]> granicus.if.org Git - clang/commitdiff
ms-compat: Fix taking the address of a member of a dependent base
authorReid Kleckner <reid@kleckner.net>
Tue, 15 Oct 2013 18:38:02 +0000 (18:38 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 15 Oct 2013 18:38:02 +0000 (18:38 +0000)
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
lib/Sema/SemaExpr.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/ms-lookup-template-base-classes.cpp

index 069404aa7cba82ca9f4266e435cd3beefb66e4a1..3738c0e4f2c9a59c686ad0682b350db6a0e5ccef 100644 (file)
@@ -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());
index 04e01f6ccb7e1d7a8298290871e0b27a2d576465..14059035e704dac9ce233963c35158239adc4720 100644 (file)
@@ -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.
index 6f5f72ecf61b83858e6b753fd8091c7c12e4f266..97e12d77a194258b6a84a996df755e5a7a6ffddf 100644 (file)
@@ -8109,6 +8109,7 @@ ExprResult
 TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
                                                DependentScopeDeclRefExpr *E,
                                                bool IsAddressOfOperand) {
+  assert(E->getQualifierLoc());
   NestedNameSpecifierLoc QualifierLoc
   = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
   if (!QualifierLoc)
index cb1a7f50b719d2ae60b0233bb7c25166f5053fa2..72ce056063ea5bc7f2668a2ac9fa57b8329ea0cf 100644 (file)
@@ -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>;
+
+}