From 8690cee218a59d3f6eaca17b9c25d03a52ebacaa Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 15 Oct 2013 18:38:02 +0000 Subject: [PATCH] ms-compat: Fix taking the address of a member of a dependent base If unqualified id lookup fails while parsing a class template with a dependent base, clang with -fms-compatibility will pretend the user prefixed the name with 'this->' in order to delay the lookup. However, if there was a unary ampersand, Sema::ActOnDependentIdExpression() will create a DependentDeclRefExpr, which is not what we wanted at all. Fix this by building the CXXDependentScopeMemberExpr directly instead. In order to be fully MSVC compatible, we would have to defer all attempts at name lookup to instantiation time. However, until we have real problems with system headers that can't be parsed, we'll put off implementing that. Fixes PR16014. Reviewers: rsmith Differential Revision: http://llvm-reviews.chandlerc.com/D1892 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192727 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprCXX.cpp | 1 + lib/Sema/SemaExpr.cpp | 24 ++++++++--- lib/Sema/TreeTransform.h | 1 + .../ms-lookup-template-base-classes.cpp | 40 +++++++++++++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 069404aa7c..3738c0e4f2 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -456,6 +456,7 @@ DependentScopeDeclRefExpr::Create(const ASTContext &C, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { + assert(QualifierLoc && "should be created for dependent qualifiers"); std::size_t size = sizeof(DependentScopeDeclRefExpr); if (Args) size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size()); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 04e01f6ccb..14059035e7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2020,14 +2020,26 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (R.empty()) { // In Microsoft mode, if we are inside a template class member function // whose parent class has dependent base classes, and we can't resolve - // an identifier, then assume the identifier is type dependent. The - // goal is to postpone name lookup to instantiation time to be able to - // search into the type dependent base classes. + // an identifier, then assume the identifier is a member of a dependent + // base class. The goal is to postpone name lookup to instantiation time + // to be able to search into the type dependent base classes. + // FIXME: If we want 100% compatibility with MSVC, we will have delay all + // unqualified name lookup. Any name lookup during template parsing means + // clang might find something that MSVC doesn't. For now, we only handle + // the common case of members of a dependent base class. if (getLangOpts().MicrosoftMode) { CXXMethodDecl *MD = dyn_cast(CurContext); - if (MD && MD->getParent()->hasAnyDependentBases()) - return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, - IsAddressOfOperand, TemplateArgs); + if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) { + assert(SS.isEmpty() && "qualifiers should be already handled"); + QualType ThisType = MD->getThisType(Context); + // Since the 'this' expression is synthesized, we don't need to + // perform the double-lookup check. + NamedDecl *FirstQualifierInScope = 0; + return Owned(CXXDependentScopeMemberExpr::Create( + Context, /*This=*/0, ThisType, /*IsArrow=*/true, + /*Op=*/SourceLocation(), SS.getWithLocInContext(Context), + TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs)); + } } // Don't diagnose an empty lookup for inline assmebly. diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 6f5f72ecf6..97e12d77a1 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8109,6 +8109,7 @@ ExprResult TreeTransform::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E, bool IsAddressOfOperand) { + assert(E->getQualifierLoc()); NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp index cb1a7f50b7..72ce056063 100644 --- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -196,3 +196,43 @@ void f() { } } // namespace PR12701 + +namespace PR16014 { + +struct A { + int a; + static int sa; +}; +template struct B : T { + int foo() { return a; } + int *bar() { return &a; } + int baz() { return T::a; } + int T::*qux() { return &T::a; } + static int T::*stuff() { return &T::a; } + static int stuff1() { return T::sa; } + static int *stuff2() { return &T::sa; } +}; + +template struct C : T { + int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C'}} + int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C'}} + int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} + int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} + int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} +}; + +template struct B; +template struct C; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C::.*' requested here}} + +template struct D : T { + struct Inner { + int foo() { + // FIXME: MSVC can find this in D's base T! Even worse, if ::sa exists, + // clang will use it instead. + return sa; // expected-error {{use of undeclared identifier 'sa'}} + } + }; +}; +template struct D; + +} -- 2.40.0