From a85cf39786fffd6860a940523be01eb02a4935c0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 5 Apr 2012 01:13:04 +0000 Subject: [PATCH] Improve diagnostics for invalid use of non-static members / this: * s/nonstatic/non-static/ in the diagnostics, since the latter form outvoted the former by 28-2 in our diagnostics. * Fix the "use of member in static member function" diagnostic to correctly detect this situation inside a block or lambda. * Produce a more specific "invalid use of non-static member" diagnostic for the case where a nested class member refers to a member of a lexically-surrounding class. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154073 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 7 ++- lib/Sema/SemaExprMember.cpp | 46 +++++++++++-------- test/CXX/class/class.nest/p1.cpp | 4 +- .../expr.prim/expr.prim.general/p12-0x.cpp | 2 +- .../expr.prim/expr.prim.general/p4-0x.cpp | 4 +- .../expr/expr.prim/expr.prim.lambda/p12.cpp | 2 +- test/CXX/special/class.free/p1.cpp | 4 +- test/CXX/special/class.free/p6.cpp | 4 +- test/Parser/cxx-typeof.cpp | 2 +- test/SemaCXX/class.cpp | 10 ++-- test/SemaCXX/default2.cpp | 10 ++-- test/SemaCXX/qual-id-test.cpp | 2 +- test/SemaCXX/this.cpp | 4 +- 13 files changed, 57 insertions(+), 44 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3ecb4a7c80..a89217c472 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3769,7 +3769,7 @@ def warn_null_in_comparison_operation : Warning< InGroup>; def err_invalid_this_use : Error< - "invalid use of 'this' outside of a nonstatic member function">; + "invalid use of 'this' outside of a non-static member function">; def err_invalid_member_use_in_static_method : Error< "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< @@ -3785,7 +3785,10 @@ def err_ref_qualifier_overload : Error< "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; def err_invalid_non_static_member_use : Error< - "invalid use of nonstatic data member %0">; + "invalid use of non-static data member %0">; +def err_nested_non_static_member_use : Error< + "%select{call to non-static member function|use of non-static data member}0 " + "%2 of %1 from nested type %3">; def warn_cxx98_compat_non_static_member_use : Warning< "use of non-static data member %0 in an unevaluated context is " "incompatible with C++98">, InGroup, DefaultIgnore; diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 4155fdb9db..26b88a2a7e 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -194,30 +194,38 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, } /// Diagnose a reference to a field with no object available. -static void DiagnoseInstanceReference(Sema &SemaRef, +static void diagnoseInstanceReference(Sema &SemaRef, const CXXScopeSpec &SS, - NamedDecl *rep, + NamedDecl *Rep, const DeclarationNameInfo &nameInfo) { SourceLocation Loc = nameInfo.getLoc(); SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - - if (isa(rep) || isa(rep)) { - if (CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) - << Range << nameInfo.getName(); - return; - } - } + DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext(); + CXXMethodDecl *Method = dyn_cast(FunctionLevelDC); + CXXRecordDecl *ContextClass = Method ? Method->getParent() : 0; + CXXRecordDecl *RepClass = dyn_cast(Rep->getDeclContext()); + + bool InStaticMethod = Method && Method->isStatic(); + bool IsField = isa(Rep) || isa(Rep); + + if (IsField && InStaticMethod) + // "invalid use of member 'x' in static member function" + SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + << Range << nameInfo.getName(); + else if (ContextClass && RepClass && SS.isEmpty() && !InStaticMethod && + !RepClass->Equals(ContextClass) && RepClass->Encloses(ContextClass)) + // Unqualified lookup in a non-static member function found a member of an + // enclosing class. + SemaRef.Diag(Loc, diag::err_nested_non_static_member_use) + << IsField << RepClass << nameInfo.getName() << ContextClass << Range; + else if (IsField) SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) - << nameInfo.getName() << Range; - return; - } - - SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; + << nameInfo.getName() << Range; + else + SemaRef.Diag(Loc, diag::err_member_call_without_object) + << Range; } /// Builds an expression which might be an implicit member expression. @@ -248,7 +256,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Error_StaticContext: case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), + diagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), R.getLookupNameInfo()); return ExprError(); } @@ -468,7 +476,7 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, // If this is an implicit member access, use a different set of // diagnostics. if (!BaseExpr) - return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); + return diagnoseInstanceReference(SemaRef, SS, rep, nameInfo); SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) << SS.getRange() << rep << BaseType; diff --git a/test/CXX/class/class.nest/p1.cpp b/test/CXX/class/class.nest/p1.cpp index 9eaeff0734..b0341da7c2 100644 --- a/test/CXX/class/class.nest/p1.cpp +++ b/test/CXX/class/class.nest/p1.cpp @@ -5,9 +5,9 @@ class Outer { static int sx; int f(); - // C++0x does relax this rule (see 5.1.1.10) in the first case, but we need to enforce it in C++03 mode. + // C++11 does relax this rule (see 5.1.1.10) in the first case, but we need to enforce it in C++03 mode. class Inner { - static char a[sizeof(x)]; // expected-error {{invalid use of nonstatic data member 'x'}} + static char a[sizeof(x)]; // expected-error {{invalid use of non-static data member 'x'}} static char b[sizeof(sx)]; // okay static char c[sizeof(f)]; // expected-error {{call to non-static member function without an object argument}} }; diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp index 606300b1b2..249c976460 100644 --- a/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp @@ -26,7 +26,7 @@ namespace std { } class Poly { virtual ~Poly(); }; const std::type_info& k = typeid(S::m); -const std::type_info& m = typeid(*(Poly*)S::m); // expected-error {{invalid use of nonstatic data member}} +const std::type_info& m = typeid(*(Poly*)S::m); // expected-error {{invalid use of non-static data member}} const std::type_info& n = typeid(*(Poly*)(0*sizeof S::m)); namespace PR11956 { diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp index b9f0414e91..4e57b74f08 100644 --- a/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp @@ -2,9 +2,9 @@ struct S { S *p = this; // ok - decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + decltype(this) q; // expected-error {{invalid use of 'this' outside of a non-static member function}} - int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a non-static member function}} int sz = sizeof(this); // ok }; diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp index 9da9fcea1f..4a2a4f3d73 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp @@ -27,7 +27,7 @@ struct ReachingThis { static void static_bar() { (void)[this](){}; // expected-error{{'this' cannot be captured in this context}} - (void)[&](){i = 7; }; // expected-error{{invalid use of nonstatic data member 'i'}} + (void)[&](){i = 7; }; // expected-error{{invalid use of member 'i' in static member function}} } }; } diff --git a/test/CXX/special/class.free/p1.cpp b/test/CXX/special/class.free/p1.cpp index e4fe127f9f..5c0240b5da 100644 --- a/test/CXX/special/class.free/p1.cpp +++ b/test/CXX/special/class.free/p1.cpp @@ -3,9 +3,9 @@ struct A { void *operator new(size_t) { - return this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + return this; // expected-error {{invalid use of 'this' outside of a non-static member function}} } void *operator new[](size_t) { - return this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + return this; // expected-error {{invalid use of 'this' outside of a non-static member function}} } }; diff --git a/test/CXX/special/class.free/p6.cpp b/test/CXX/special/class.free/p6.cpp index 555d4e9cfa..fc4b2ae1ac 100644 --- a/test/CXX/special/class.free/p6.cpp +++ b/test/CXX/special/class.free/p6.cpp @@ -3,9 +3,9 @@ struct A { void operator delete(void*) { - (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + (void)this; // expected-error {{invalid use of 'this' outside of a non-static member function}} } void operator delete[](void*) { - (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + (void)this; // expected-error {{invalid use of 'this' outside of a non-static member function}} } }; diff --git a/test/Parser/cxx-typeof.cpp b/test/Parser/cxx-typeof.cpp index 4c598e9517..1ec6e29b13 100644 --- a/test/Parser/cxx-typeof.cpp +++ b/test/Parser/cxx-typeof.cpp @@ -9,5 +9,5 @@ static void test() { // Part of rdar://problem/8347416; from the gcc test suite. struct S { int i; - __typeof(S::i) foo(); // expected-error {{invalid use of nonstatic data member 'i'}} + __typeof(S::i) foo(); // expected-error {{invalid use of non-static data member 'i'}} }; diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp index e079d0cc17..ec82925fe4 100644 --- a/test/SemaCXX/class.cpp +++ b/test/SemaCXX/class.cpp @@ -7,16 +7,18 @@ public: static void sm() { sx = 0; - this->x = 0; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + this->x = 0; // expected-error {{invalid use of 'this' outside of a non-static member function}} x = 0; // expected-error {{invalid use of member 'x' in static member function}} } class NestedC { public: NestedC(int); - void m() { + void f() { sx = 0; - x = 0; // expected-error {{invalid use of nonstatic data member 'x'}} + x = 0; // expected-error {{use of non-static data member 'x' of 'C' from nested type 'NestedC'}} + sm(); + m(); // expected-error {{call to non-static member function 'm' of 'C' from nested type 'NestedC'}} } }; @@ -186,7 +188,7 @@ struct S { }; void f() { - S::c; // expected-error {{invalid use of nonstatic data member}} + S::c; // expected-error {{invalid use of non-static data member}} } } diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp index 20763229cf..16260449d4 100644 --- a/test/SemaCXX/default2.cpp +++ b/test/SemaCXX/default2.cpp @@ -28,7 +28,7 @@ void g(int x, int y = x); // expected-error {{default argument references parame void g2(int x, int y, int z = x + y); // expected-error {{default argument references parameter 'x'}} expected-error {{default argument references parameter 'y'}} class X { - void f(X* x = this); // expected-error{{invalid use of 'this' outside of a nonstatic member function}} + void f(X* x = this); // expected-error{{invalid use of 'this' outside of a non-static member function}} void g() { int f(X* x = this); // expected-error{{default argument references 'this'}} @@ -55,7 +55,7 @@ void C::h() { // C++ [dcl.fct.default]p9 struct Y { int a; - int mem1(int i = a); // expected-error{{invalid use of nonstatic data member 'a'}} + int mem1(int i = a); // expected-error{{invalid use of non-static data member 'a'}} int mem2(int i = b); // OK; use Y::b int mem3(int i); int mem4(int i); @@ -64,8 +64,8 @@ struct Y { int mem5(int i = b, // OK; use Y::b int j = c, // OK; use Y::Nested::c int k = j, // expected-error{{default argument references parameter 'j'}} - int l = a, // expected-error{{invalid use of nonstatic data member 'a'}} - Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}} + int l = a, // expected-error{{invalid use of non-static data member 'a'}} + Nested* self = this, // expected-error{{invalid use of 'this' outside of a non-static member function}} int m); // expected-error{{missing default argument on parameter 'm'}} static int c; Nested(int i = 42); @@ -78,7 +78,7 @@ struct Y { int Y::mem3(int i = b) { return i; } // OK; use X::b -int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member 'a'}} +int Y::mem4(int i = a) // expected-error{{invalid use of non-static data member 'a'}} { return i; } diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp index e5c7306775..e43e6887c4 100644 --- a/test/SemaCXX/qual-id-test.cpp +++ b/test/SemaCXX/qual-id-test.cpp @@ -137,7 +137,7 @@ struct a { a a; -int a::sa = a.a; // expected-error {{invalid use of nonstatic data member 'a'}} +int a::sa = a.a; // expected-error {{invalid use of non-static data member 'a'}} namespace PR6645 { diff --git a/test/SemaCXX/this.cpp b/test/SemaCXX/this.cpp index 13158b93a4..27ee1e84a7 100644 --- a/test/SemaCXX/this.cpp +++ b/test/SemaCXX/this.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -int x = this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} +int x = this; // expected-error {{invalid use of 'this' outside of a non-static member function}} void f() { - int x = this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} + int x = this; // expected-error {{invalid use of 'this' outside of a non-static member function}} } -- 2.40.0