From 3b1dad7cc332547721ba2f7231132aac12945d59 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 2 May 2014 02:01:07 +0000 Subject: [PATCH] Handle -fdelayed-template-parsing of out-of-line definitions of class template member classes (PR19613) Also improve this code in general by implementing suggestions from Richard. Differential Revision: http://reviews.llvm.org/D3555?id=9020 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@207822 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 +- lib/Parse/ParseTemplate.cpp | 41 ++++---------- lib/Sema/SemaDeclCXX.cpp | 74 ++++++++++++++------------ test/Parser/DelayedTemplateParsing.cpp | 58 ++++++++++++++++++++ 4 files changed, 110 insertions(+), 66 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b4278b590e..9424bc05b3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4884,8 +4884,7 @@ public: void ActOnFinishCXXMemberDecls(); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); - void ActOnReenterTemplateScope(Scope *S, Decl *Template); - void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D); + unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e81c41da67..d88f631dd3 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1239,7 +1239,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Get the list of DeclContexts to reenter. SmallVector DeclContextsToReenter; - DeclContext *DD = FunD->getLexicalParent(); + DeclContext *DD = FunD; while (DD && !DD->isTranslationUnit()) { DeclContextsToReenter.push_back(DD); DD = DD->getLexicalParent(); @@ -1249,37 +1249,16 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { SmallVectorImpl::reverse_iterator II = DeclContextsToReenter.rbegin(); for (; II != DeclContextsToReenter.rend(); ++II) { - if (ClassTemplatePartialSpecializationDecl *MD = - dyn_cast_or_null(*II)) { - TemplateParamScopeStack.push_back( - new ParseScope(this, Scope::TemplateParamScope)); - Actions.ActOnReenterTemplateScope(getCurScope(), MD); - ++CurTemplateDepthTracker; - } else if (CXXRecordDecl *MD = dyn_cast_or_null(*II)) { - bool IsClassTemplate = MD->getDescribedClassTemplate() != 0; - TemplateParamScopeStack.push_back( - new ParseScope(this, Scope::TemplateParamScope, - /*ManageScope*/IsClassTemplate)); - Actions.ActOnReenterTemplateScope(getCurScope(), - MD->getDescribedClassTemplate()); - if (IsClassTemplate) - ++CurTemplateDepthTracker; + TemplateParamScopeStack.push_back(new ParseScope(this, + Scope::TemplateParamScope)); + unsigned NumParamLists = + Actions.ActOnReenterTemplateScope(getCurScope(), cast(*II)); + CurTemplateDepthTracker.addDepth(NumParamLists); + if (*II != FunD) { + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); + Actions.PushDeclContext(Actions.getCurScope(), *II); } - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); - Actions.PushDeclContext(Actions.getCurScope(), *II); - } - TemplateParamScopeStack.push_back( - new ParseScope(this, Scope::TemplateParamScope)); - - DeclaratorDecl *Declarator = dyn_cast(FunD); - const unsigned DeclaratorNumTemplateParameterLists = - (Declarator ? Declarator->getNumTemplateParameterLists() : 0); - if (Declarator && DeclaratorNumTemplateParameterLists != 0) { - Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); - CurTemplateDepthTracker.addDepth(DeclaratorNumTemplateParameterLists); } - Actions.ActOnReenterTemplateScope(getCurScope(), LPT.D); - ++CurTemplateDepthTracker; assert(!LPT.Toks.empty() && "Empty body!"); @@ -1314,7 +1293,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { assert((!isa(LPT.D) || cast(LPT.D) ->getTemplateParameters() - ->getDepth() < TemplateParameterDepth) && + ->getDepth() == TemplateParameterDepth - 1) && "TemplateParameterDepth should be greater than the depth of " "current template being instantiated!"); ParseFunctionStatementBody(LPT.D, FnScope); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6416b6277c..1feb979f69 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5980,47 +5980,55 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) { +unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (!D) - return; + return 0; - int NumParamList = D->getNumTemplateParameterLists(); - for (int i = 0; i < NumParamList; i++) { - TemplateParameterList* Params = D->getTemplateParameterList(i); - for (TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - Param != ParamEnd; ++Param) { - NamedDecl *Named = cast(*Param); - if (Named->getDeclName()) { - S->AddDecl(Named); - IdResolver.AddDecl(Named); - } + // The order of template parameters is not important here. All names + // get added to the same scope. + SmallVector ParameterLists; + + if (TemplateDecl *TD = dyn_cast(D)) + D = TD->getTemplatedDecl(); + + if (auto *PSD = dyn_cast(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); + + if (DeclaratorDecl *DD = dyn_cast(D)) { + for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i) + ParameterLists.push_back(DD->getTemplateParameterList(i)); + + if (FunctionDecl *FD = dyn_cast(D)) { + if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) + ParameterLists.push_back(FTD->getTemplateParameters()); } } -} -void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { - if (!D) - return; - - TemplateParameterList *Params = 0; - if (TemplateDecl *Template = dyn_cast(D)) - Params = Template->getTemplateParameters(); - else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = dyn_cast(D)) - Params = PartialSpec->getTemplateParameters(); - else - return; + if (TagDecl *TD = dyn_cast(D)) { + for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i) + ParameterLists.push_back(TD->getTemplateParameterList(i)); - for (TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - Param != ParamEnd; ++Param) { - NamedDecl *Named = cast(*Param); - if (Named->getDeclName()) { - S->AddDecl(Named); - IdResolver.AddDecl(Named); + if (CXXRecordDecl *RD = dyn_cast(TD)) { + if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) + ParameterLists.push_back(CTD->getTemplateParameters()); } } + + unsigned Count = 0; + for (TemplateParameterList *Params : ParameterLists) { + if (Params->size() > 0) + // Ignore explicit specializations; they don't contribute to the template + // depth. + ++Count; + for (NamedDecl *Param : *Params) { + if (Param->getDeclName()) { + S->AddDecl(Param); + IdResolver.AddDecl(Param); + } + } + } + + return Count; } void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, Decl *RecordD) { diff --git a/test/Parser/DelayedTemplateParsing.cpp b/test/Parser/DelayedTemplateParsing.cpp index 29af6a01e9..eff31208c8 100644 --- a/test/Parser/DelayedTemplateParsing.cpp +++ b/test/Parser/DelayedTemplateParsing.cpp @@ -123,3 +123,61 @@ constexpr int Var = Fun(20); template auto invalidTrailingRetType() -> Bogus {} // expected-error {{unknown type name 'Bogus'}} + +namespace PR19613 { + +struct HeapTypeConfig { + static void from_bitset(); +}; + +template +struct TypeImpl { + struct BitsetType; + + static void Any() { + BitsetType::New(); + } +}; + +template +struct TypeImpl::BitsetType { + static void New() { + Config::from_bitset(); + } +}; + +static void f() { + TypeImpl::Any(); +} + +template struct S { + template struct T; +}; +template template struct S::T { + template struct U; + template struct U { + template static int f() { + return sizeof(A) + sizeof(B) + sizeof(C) + sizeof(E); + } + }; +}; + +static void g() { + S::T::U::f(); +} + +template struct SS { + template struct X; + template struct X; +}; +template template struct SS::X { + static int f() { + return sizeof(T) + sizeof(U); + } +}; + +static void h() { + SS::X::f(); +} + +} -- 2.40.0