Author: rnk Date: Fri Oct 16 19:19:04 2015 New Revision: 250592 URL: http://llvm.org/viewvc/llvm-project?rev=250592&view=rev Log: Diagnose UnresolvedLookupExprs that resolve to instance members in static methods
During the initial template parse for this code, 'member' is unresolved and we don't know anything about it: struct A { int member }; template <typename T> struct B : public T { using T::member; static void f() { (void)member; // Could be static or non-static. } }; template class B<A>; The pattern declaration contains an UnresolvedLookupExpr rather than an UnresolvedMemberExpr because `f` is static, and `member` should never be a field. However, if the code is invalid, it may become a field, in which case we should diagnose it. Reviewers: rjmccall, rsmith Differential Revision: http://reviews.llvm.org/D6700 Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaExprMember.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/test/SemaCXX/using-decl-1.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=250592&r1=250591&r2=250592&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 16 19:19:04 2015 @@ -3692,6 +3692,9 @@ public: Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); + void DiagnoseInstanceReference(const CXXScopeSpec &SS, NamedDecl *Rep, + const DeclarationNameInfo &nameInfo); + ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=250592&r1=250591&r2=250592&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Fri Oct 16 19:19:04 2015 @@ -192,10 +192,8 @@ static IMAKind ClassifyImplicitMemberAcc } /// Diagnose a reference to a field with no object available. -static void diagnoseInstanceReference(Sema &SemaRef, - const CXXScopeSpec &SS, - NamedDecl *Rep, - const DeclarationNameInfo &nameInfo) { +void Sema::DiagnoseInstanceReference(const CXXScopeSpec &SS, NamedDecl *Rep, + const DeclarationNameInfo &nameInfo) { SourceLocation Loc = nameInfo.getLoc(); SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); @@ -203,7 +201,7 @@ static void diagnoseInstanceReference(Se // Look through using shadow decls and aliases. Rep = Rep->getUnderlyingDecl(); - DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext(); + DeclContext *FunctionLevelDC = getFunctionLevelDeclContext(); CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC); CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr; CXXRecordDecl *RepClass = dyn_cast<CXXRecordDecl>(Rep->getDeclContext()); @@ -213,20 +211,19 @@ static void diagnoseInstanceReference(Se if (IsField && InStaticMethod) // "invalid use of member 'x' in static member function" - SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + 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; + 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; + Diag(Loc, diag::err_invalid_non_static_member_use) << nameInfo.getName() + << Range; else - SemaRef.Diag(Loc, diag::err_member_call_without_object) - << Range; + Diag(Loc, diag::err_member_call_without_object) << Range; } /// Builds an expression which might be an implicit member expression. @@ -260,7 +257,7 @@ Sema::BuildPossibleImplicitMemberExpr(co case IMA_Error_StaticContext: case IMA_Error_Unrelated: - diagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), + DiagnoseInstanceReference(SS, R.getRepresentativeDecl(), R.getLookupNameInfo()); return ExprError(); } @@ -474,7 +471,7 @@ static void DiagnoseQualifiedMemberRefer // If this is an implicit member access, use a different set of // diagnostics. if (!BaseExpr) - return diagnoseInstanceReference(SemaRef, SS, rep, nameInfo); + return SemaRef.DiagnoseInstanceReference(SS, rep, nameInfo); SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) << SS.getRange() << rep << BaseType; Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=250592&r1=250591&r2=250592&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Fri Oct 16 19:19:04 2015 @@ -9128,8 +9128,18 @@ TreeTransform<Derived>::TransformUnresol // If we have neither explicit template arguments, nor the template keyword, // it's a normal declaration name. - if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) + if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) { + // If an UnresolvedLookupExpr resolved to an instance member, that's an + // error. + NamedDecl *D = R.getAsSingle<NamedDecl>(); + if (D && D->isCXXInstanceMember()) { + SemaRef.DiagnoseInstanceReference(SS, D, Old->getNameInfo()); + R.clear(); + return ExprError(); + } + return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL()); + } // If we have template arguments, rebuild them, then rebuild the // templateid expression. Modified: cfe/trunk/test/SemaCXX/using-decl-1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-decl-1.cpp?rev=250592&r1=250591&r2=250592&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/using-decl-1.cpp (original) +++ cfe/trunk/test/SemaCXX/using-decl-1.cpp Fri Oct 16 19:19:04 2015 @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -DCXX11 -fsyntax-only -verify -std=c++11 %s extern "C" { void f(bool); } @@ -327,3 +327,52 @@ namespace PR24033 { using PR24033::st; // expected-error {{target of using declaration conflicts with declaration already in scope}} } } + +namespace pr21923 { +template <typename> struct Base { + int field; + void method(); +}; +template <typename Scalar> struct Derived : Base<Scalar> { + using Base<Scalar>::field; + using Base<Scalar>::method; + static void m_fn1() { + // expected-error@+1 {{invalid use of member 'field' in static member function}} + (void)field; + // expected-error@+1 {{invalid use of member 'field' in static member function}} + (void)&field; + // expected-error@+1 {{call to non-static member function without an object argument}} + (void)method; + // expected-error@+1 {{call to non-static member function without an object argument}} + (void)&method; + // expected-error@+1 {{call to non-static member function without an object argument}} + method(); + (void)&Base<Scalar>::field; + (void)&Base<Scalar>::method; + } +}; +// expected-note@+1 {{in instantiation of member function 'pr21923::Derived<int>::m_fn1' requested here}} +template class Derived<int>; + +#ifdef CXX11 +// This is interesting because we form an UnresolvedLookupExpr in the static +// function template and an UnresolvedMemberExpr in the instance function +// template. As a result, we get slightly different behavior. +struct UnresolvedTemplateNames { + template <typename> void maybe_static(); + template <typename T, typename T::type = 0> static void maybe_static(); + + template <typename T> + void instance_method() { (void)maybe_static<T>(); } + template <typename T> + static void static_method() { + // expected-error@+1 {{call to non-static member function without an object argument}} + (void)maybe_static<T>(); + } +}; +void force_instantiation(UnresolvedTemplateNames x) { + x.instance_method<int>(); + UnresolvedTemplateNames::static_method<int>(); // expected-note {{requested here}} +} +#endif // CXX11 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits