From c9068d7dd94d439cec66c421115d15303e481025 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 16 Jul 2010 08:13:16 +0000 Subject: [PATCH] Treat template parameters as part of the declaration-specifiers for the purpose of access control. Fixes PR7644. I can't actually find anything directly justifying this, but it seems obvious. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108521 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 31 +++++++++++++++++++++++++++---- lib/Parse/ParseDeclCXX.cpp | 11 +++++++---- lib/Parse/ParseTemplate.cpp | 17 ++++++++++++++--- lib/Sema/SemaDecl.cpp | 2 +- test/CXX/class.access/p6.cpp | 20 ++++++++++++++++++++ 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index b8c294ada6..90a1cab5cf 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -654,12 +654,25 @@ private: Action &Actions; Action::ParsingDeclStackState State; bool Popped; - + public: ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { push(); } + ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *Other) + : Actions(P.Actions) { + if (Other) steal(*Other); + else push(); + } + + /// Creates a RAII object which steals the state from a different + /// object instead of pushing. + ParsingDeclRAIIObject(ParsingDeclRAIIObject &Other) + : Actions(Other.Actions) { + steal(Other); + } + ~ParsingDeclRAIIObject() { abort(); } @@ -682,6 +695,12 @@ private: } private: + void steal(ParsingDeclRAIIObject &Other) { + State = Other.State; + Popped = Other.Popped; + Other.Popped = true; + } + void push() { State = Actions.PushParsingDeclaration(); Popped = false; @@ -700,8 +719,10 @@ private: ParsingDeclRAIIObject ParsingRAII; public: - ParsingDeclSpec(Parser &P) : ParsingRAII(P) { - } + ParsingDeclSpec(Parser &P) : ParsingRAII(P) {} + ParsingDeclSpec(ParsingDeclRAIIObject &RAII) : ParsingRAII(RAII) {} + ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) + : ParsingRAII(P, RAII) {} void complete(DeclPtrTy D) { ParsingRAII.complete(D); @@ -1414,7 +1435,8 @@ private: void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, - const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ParsingDeclRAIIObject *DiagsFromTParams = 0); void ParseConstructorInitializer(DeclPtrTy ConstructorDecl); MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl); void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, @@ -1457,6 +1479,7 @@ private: DeclPtrTy ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, AccessSpecifier AS=AS_none); bool ParseTemplateParameters(unsigned Depth, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 590ba6c6f8..1d81258367 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1218,7 +1218,8 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// '=' constant-expression /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject *TemplateDiags) { // Access declarations. if (!TemplateInfo.Kind && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && @@ -1281,7 +1282,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS, TemplateInfo); + return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags); } // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it @@ -1317,7 +1318,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. - ParsingDeclSpec DS(*this); + ParsingDeclSpec DS(*this, TemplateDiags); DS.AddAttributes(AttrList.AttrList); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); @@ -1327,7 +1328,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + DeclPtrTy TheDecl = + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + DS.complete(TheDecl); return; } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e1aaf91bd6..dfb1c86409 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -80,6 +80,10 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Enter template-parameter scope. ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + // Tell the action that names should be checked in the context of + // the declaration to come. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + // Parse multiple levels of template headers within this template // parameter scope, e.g., // @@ -152,6 +156,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), + ParsingTemplateParams, DeclEnd, AS); } @@ -179,6 +184,7 @@ Parser::DeclPtrTy Parser::ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, AccessSpecifier AS) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && @@ -186,12 +192,13 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Context == Declarator::MemberContext) { // We are parsing a member template. - ParseCXXClassMemberDeclaration(AS, TemplateInfo); + ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams); return DeclPtrTy::make((void*)0); } - // Parse the declaration specifiers. - ParsingDeclSpec DS(*this); + // Parse the declaration specifiers, stealing the accumulated + // diagnostics from the template parameters. + ParsingDeclSpec DS(DiagsFromTParams); if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) DS.AddAttributes(ParseCXX0XAttributes().AttrList); @@ -1057,8 +1064,12 @@ Parser::DeclPtrTy Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, SourceLocation TemplateLoc, SourceLocation &DeclEnd) { + // This isn't really required here. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, ParsedTemplateInfo(ExternLoc, TemplateLoc), + ParsingTemplateParams, DeclEnd, AS_none); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 538d56470f..29ecdbc680 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1562,7 +1562,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << DS.getSourceRange(); } - return DeclPtrTy::make(Tag); + return DeclPtrTy::make(TagD); } /// We are trying to inject an anonymous member into the given scope; diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp index 734a4d8c48..8795708474 100644 --- a/test/CXX/class.access/p6.cpp +++ b/test/CXX/class.access/p6.cpp @@ -119,3 +119,23 @@ namespace test4 { foo(a, 0); } } + +// PR7644 +namespace test5 { + class A { + enum Enum { E0, E1, E2 }; // expected-note 4 {{declared private here}} + template void foo(); + template class bar; + }; + + template void A::foo() {} + template class A::bar {}; + + template void foo() {} // expected-error {{'Enum' is a private member of 'test5::A'}} + template class bar {}; // expected-error {{'Enum' is a private member of 'test5::A'}} + + class B { + template void foo() {} // expected-error {{'Enum' is a private member of 'test5::A'}} + template class bar {}; // expected-error {{'Enum' is a private member of 'test5::A'}} + }; +} -- 2.40.0