diff options
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 1 | ||||
-rw-r--r-- | clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp | 40 |
4 files changed, 60 insertions, 6 deletions
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 069404aa7cb..3738c0e4f2c 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 04e01f6ccb7..14059035e70 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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<CXXMethodDecl>(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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6f5f72ecf61..97e12d77a19 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -8109,6 +8109,7 @@ ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E, bool IsAddressOfOperand) { + assert(E->getQualifierLoc()); NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) diff --git a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp index cb1a7f50b71..72ce056063e 100644 --- a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ b/clang/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 <typename T> 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 <typename T> struct C : T { + int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} + int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C<PR16014::A>'}} + 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<A>; +template struct C<A>; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C<PR16014::A>::.*' requested here}} + +template <typename T> 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<A>; + +} |