r192727 - ms-compat: Fix taking the address of a member of a dependent base

Reid Kleckner reid at kleckner.net
Tue Oct 15 11:38:02 PDT 2013


Author: rnk
Date: Tue Oct 15 13:38:02 2013
New Revision: 192727

URL: http://llvm.org/viewvc/llvm-project?rev=192727&view=rev
Log:
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

Modified:
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=192727&r1=192726&r2=192727&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Oct 15 13:38:02 2013
@@ -456,6 +456,7 @@ DependentScopeDeclRefExpr::Create(const
                                   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());

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=192727&r1=192726&r2=192727&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 15 13:38:02 2013
@@ -2020,14 +2020,26 @@ ExprResult Sema::ActOnIdExpression(Scope
     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.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=192727&r1=192726&r2=192727&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 15 13:38:02 2013
@@ -8109,6 +8109,7 @@ ExprResult
 TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
                                                DependentScopeDeclRefExpr *E,
                                                bool IsAddressOfOperand) {
+  assert(E->getQualifierLoc());
   NestedNameSpecifierLoc QualifierLoc
   = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
   if (!QualifierLoc)

Modified: cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp?rev=192727&r1=192726&r2=192727&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp (original)
+++ cfe/trunk/test/SemaTemplate/ms-lookup-template-base-classes.cpp Tue Oct 15 13:38:02 2013
@@ -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>;
+
+}





More information about the cfe-commits mailing list