summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ExprCXX.cpp1
-rw-r--r--clang/lib/Sema/SemaExpr.cpp24
-rw-r--r--clang/lib/Sema/TreeTransform.h1
-rw-r--r--clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp40
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>;
+
+}
OpenPOWER on IntegriCloud