From: John McCall Date: Sun, 20 Dec 2009 07:58:13 +0000 (+0000) Subject: Don't inject the class name until that magical lbrace. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9368159334ff86ea5fa367225c1a580977f3b03;p=clang Don't inject the class name until that magical lbrace. 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 A : B { ... }; instead of template class A : B > { ... }; 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 --- diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 50f4302019..4cbc21ad01 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index fcbbce1062..265d0f3e84 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 41081f2f13..f83e9a70bb 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e408000fab..c873f39579 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4962,31 +4962,36 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { // Enter the tag context. PushDeclContext(S, Tag); +} - if (CXXRecordDecl *Record = dyn_cast(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(TagD.getAs()); + + 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, diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp index 5f63392469..e579546099 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp @@ -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 struct bar {}; // expected-note {{template parameter is declared here}} + template struct foo : bar {}; // expected-error {{template argument for template type parameter must be a type}} +}