]> granicus.if.org Git - clang/commitdiff
Look through using decls when classifying implicit member access
authorReid Kleckner <rnk@google.com>
Tue, 20 Oct 2015 18:12:08 +0000 (18:12 +0000)
committerReid Kleckner <rnk@google.com>
Tue, 20 Oct 2015 18:12:08 +0000 (18:12 +0000)
Clang will now accept this valid C++11 code:
  struct A { int field; };
  struct B : A {
    using A::field;
    enum { TheSize = sizeof(field) };
  };

Previously we would classify the 'field' reference as something other
than a field, and then forget to apply the C++11 rule to allow
non-static data member references in unevaluated contexts.

This usually arises in class templates that want to reference fields of
a dependent base in an unevaluated context outside of an instance
method. Such contexts do not allow references to 'this', so the only way
to access the field is with a using decl and an implicit member
reference.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@250839 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExprMember.cpp
test/SemaCXX/using-decl-1.cpp

index 52dfceccb94eff8fd8233b679c100e60478823c8..9c345f8a69a3d9e0b130d38c618a2bbffcf63390 100644 (file)
@@ -102,8 +102,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
   bool hasNonInstance = false;
   bool isField = false;
   BaseSet Classes;
-  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
-    NamedDecl *D = *I;
+  for (NamedDecl *D : R) {
+    // Look through any using decls.
+    D = D->getUnderlyingDecl();
 
     if (D->isCXXInstanceMember()) {
       isField |= isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) ||
@@ -111,8 +112,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
 
       CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
       Classes.insert(R->getCanonicalDecl());
-    }
-    else
+    } else
       hasNonInstance = true;
   }
 
index ca532692c1cb0ee6d053d7013ae1fa6a8cc5a5d2..5afd15f8b50e7a3a114430cb390309eb30734d61 100644 (file)
@@ -327,3 +327,16 @@ namespace PR24033 {
     using PR24033::st; // expected-error {{target of using declaration conflicts with declaration already in scope}}
   }
 }
+
+namespace field_use {
+struct A { int field; };
+struct B : A {
+  // Previously Clang rejected this valid C++11 code because it didn't look
+  // through the UsingShadowDecl.
+  using A::field;
+#if __cplusplus < 201103L
+  // expected-error@+2 {{invalid use of non-static data member 'field'}}
+#endif
+  enum { X = sizeof(field) };
+};
+}