]> granicus.if.org Git - clang/commitdiff
Don't inject the class name until that magical lbrace.
authorJohn McCall <rjmccall@apple.com>
Sun, 20 Dec 2009 07:58:13 +0000 (07:58 +0000)
committerJohn McCall <rjmccall@apple.com>
Sun, 20 Dec 2009 07:58:13 +0000 (07:58 +0000)
Because of the rules of base-class lookup* and the restrictions on typedefs, it
was actually impossible for this to cause any problems more serious than the
spurious acceptance of
  template <class T> class A : B<A> { ... };
instead of
  template <class T> class A : B<A<T> > { ... };
but I'm sure we can all agree that that is a very important restriction which
is well worth making another Parser->Sema call for.

(*) n.b. clang++ does not implement these rules correctly;  we are not ignoring
    non-type names

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

include/clang/Parse/Action.h
lib/Parse/ParseDeclCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp

index 50f4302019ad992ba795fdafd091046098cabc4d..4cbc21ad014ae36d723f1953ffc31b4a8bb732c7 100644 (file)
@@ -662,6 +662,12 @@ public:
   /// struct, or union).
   virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl) { }
 
+  /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
+  /// C++ record definition's base-specifiers clause and are starting its
+  /// member declarations.
+  virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl,
+                                               SourceLocation LBraceLoc) { }
+
   /// ActOnTagFinishDefinition - Invoked once we have finished parsing
   /// the definition of a tag (enumeration, class, struct, or union).
   virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
index fcbbce1062dfb6c71e76befd5ee78ead31e0e778..265d0f3e849fe13079d82f41effccd903491eb66 100644 (file)
@@ -1389,6 +1389,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
     return;
   }
 
+  Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc);
+
   // C++ 11p3: Members of a class defined with the keyword class are private
   // by default. Members of a class defined with the keywords struct or union
   // are public by default.
index 41081f2f13b7e3d94f48af8af1b0a2364a88bec8..f83e9a70bb0664f6c634270c3999aa5e374817d3 100644 (file)
@@ -757,6 +757,12 @@ public:
   /// struct, or union).
   virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl);
 
+  /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
+  /// C++ record definition's base-specifiers clause and are starting its
+  /// member declarations.
+  virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl,
+                                               SourceLocation LBraceLoc);
+
   /// ActOnTagFinishDefinition - Invoked once we have finished parsing
   /// the definition of a tag (enumeration, class, struct, or union).
   virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
index e408000fab591d0055d7933a6ca3188098c65d5c..c873f3957979452bc28285c99de129e942f16c81 100644 (file)
@@ -4962,31 +4962,36 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
 
   // Enter the tag context.
   PushDeclContext(S, Tag);
+}
 
-  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
-    FieldCollector->StartClass();
-
-    if (Record->getIdentifier()) {
-      // C++ [class]p2:
-      //   [...] The class-name is also inserted into the scope of the
-      //   class itself; this is known as the injected-class-name. For
-      //   purposes of access checking, the injected-class-name is treated
-      //   as if it were a public member name.
-      CXXRecordDecl *InjectedClassName
-        = CXXRecordDecl::Create(Context, Record->getTagKind(),
-                                CurContext, Record->getLocation(),
-                                Record->getIdentifier(),
-                                Record->getTagKeywordLoc(),
-                                Record);
-      InjectedClassName->setImplicit();
-      InjectedClassName->setAccess(AS_public);
-      if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
-        InjectedClassName->setDescribedClassTemplate(Template);
-      PushOnScopeChains(InjectedClassName, S);
-      assert(InjectedClassName->isInjectedClassName() &&
-             "Broken injected-class-name");
-    }
-  }
+void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
+                                           SourceLocation LBraceLoc) {
+  AdjustDeclIfTemplate(TagD);
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD.getAs<Decl>());
+
+  FieldCollector->StartClass();
+
+  if (!Record->getIdentifier())
+    return;
+
+  // C++ [class]p2:
+  //   [...] The class-name is also inserted into the scope of the
+  //   class itself; this is known as the injected-class-name. For
+  //   purposes of access checking, the injected-class-name is treated
+  //   as if it were a public member name.
+  CXXRecordDecl *InjectedClassName
+    = CXXRecordDecl::Create(Context, Record->getTagKind(),
+                            CurContext, Record->getLocation(),
+                            Record->getIdentifier(),
+                            Record->getTagKeywordLoc(),
+                            Record);
+  InjectedClassName->setImplicit();
+  InjectedClassName->setAccess(AS_public);
+  if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
+      InjectedClassName->setDescribedClassTemplate(Template);
+  PushOnScopeChains(InjectedClassName, S);
+  assert(InjectedClassName->isInjectedClassName() &&
+         "Broken injected-class-name");
 }
 
 void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
index 5f63392469cdc66320a071e7a69e5d048f8c66f6..e57954609907e548c9d6ed3fdd411003cc6ba43d 100644 (file)
@@ -10,6 +10,7 @@ namespace test0 {
   struct A::C : B { };
 }
 
+// Test that successive base specifiers don't screw with each other.
 namespace test1 {
   struct Opaque1 {};
   struct Opaque2 {};
@@ -27,3 +28,10 @@ namespace test1 {
     C() : A(), test1::B(Opaque2()) {}
   };
 }
+
+// Test that we don't find the injected class name when parsing base
+// specifiers.
+namespace test2 {
+  template <class T> struct bar {}; // expected-note {{template parameter is declared here}}
+  template <class T> struct foo : bar<foo> {}; // expected-error {{template argument for template type parameter must be a type}}
+}