From 4b55a9c841c9118c92e059716c0f2b7d152c6be9 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 17 Apr 2014 03:29:33 +0000 Subject: [PATCH] Refactor all the checking for missing 'template<>'s when a declaration has a template-id after its scope specifier into a single place. llvm-svn: 206442 --- clang/include/clang/Sema/Sema.h | 10 +--- clang/lib/Parse/ParseDeclCXX.cpp | 17 ++---- clang/lib/Sema/SemaDecl.cpp | 67 ++++++++-------------- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 98 +++++++++++++++++++------------- clang/test/FixIt/fixit.cpp | 4 +- 6 files changed, 96 insertions(+), 102 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7ed7e8b895fa..0b1cae187799 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5197,7 +5197,8 @@ public: TemplateParamListContext TPC); TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, - const CXXScopeSpec &SS, ArrayRef ParamLists, + const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, + ArrayRef ParamLists, bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, @@ -5279,12 +5280,7 @@ public: ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, - CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc, + TemplateIdAnnotation &TemplateId, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 56e116ef3969..7ef04730ac95 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1541,18 +1541,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Build the class template specialization. - TagOrTempResult - = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK, - StartLoc, DS.getModulePrivateSpecLoc(), SS, - TemplateId->Template, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc, - attrs.getList(), - MultiTemplateParamsArg( - TemplateParams? &(*TemplateParams)[0] : 0, - TemplateParams? TemplateParams->size() : 0)); + TagOrTempResult = Actions.ActOnClassTemplateSpecialization( + getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(), + *TemplateId, attrs.getList(), + MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : 0, + TemplateParams ? TemplateParams->size() : 0)); } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fb2049f6eae1..6627e0792001 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5228,29 +5228,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // determine whether we have a template or a template specialization. TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), TemplateParamLists, + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedId::IK_TemplateId + ? D.getName().TemplateId + : 0, + TemplateParamLists, /*never a friend*/ false, IsExplicitSpecialization, Invalid); - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId && - !TemplateParams) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - - // We have encountered something that the user meant to be a - // specialization (because it has explicitly-specified template - // arguments) but that was not introduced with a "template<>" (or had - // too few of them). - // FIXME: Differentiate between attempts for explicit instantiations - // (starting with "template") and the rest. - Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(), - "template<> "); - IsExplicitSpecialization = true; - TemplateParams = TemplateParameterList::Create(Context, SourceLocation(), - SourceLocation(), 0, 0, - SourceLocation()); - } - if (TemplateParams) { if (!TemplateParams->size() && D.getName().getKind() != UnqualifiedId::IK_TemplateId) { @@ -5283,6 +5267,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, : diag::ext_variable_template); } } + } else { + assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId && + "should have a 'template<>' for this decl"); } if (IsVariableTemplateSpecialization) { @@ -6709,8 +6696,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), TemplateParamLists, isFriend, - isExplicitSpecialization, Invalid)) { + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedId::IK_TemplateId + ? D.getName().TemplateId + : 0, + TemplateParamLists, isFriend, isExplicitSpecialization, + Invalid)) { if (TemplateParams->size() > 0) { // This is a function template @@ -6751,9 +6742,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // This is a function template specialization. isFunctionTemplateSpecialization = true; // For source fidelity, store all the template param lists. - NewFD->setTemplateParameterListsInfo(Context, - TemplateParamLists.size(), - TemplateParamLists.data()); + if (TemplateParamLists.size() > 0) + NewFD->setTemplateParameterListsInfo(Context, + TemplateParamLists.size(), + TemplateParamLists.data()); // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend) { @@ -7152,21 +7144,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); HasExplicitTemplateArgs = false; - } else if (!isFunctionTemplateSpecialization && - !D.getDeclSpec().isFriendSpecified()) { - // We have encountered something that the user meant to be a - // specialization (because it has explicitly-specified template - // arguments) but that was not introduced with a "template<>" (or had - // too few of them). - // FIXME: Differentiate between attempts for explicit instantiations - // (starting with "template") and the rest. - Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << FixItHint::CreateInsertion( - D.getDeclSpec().getLocStart(), - "template<> "); - isFunctionTemplateSpecialization = true; } else { + assert((isFunctionTemplateSpecialization || + D.getDeclSpec().isFriendSpecified()) && + "should have a 'template<>' for this decl"); // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } @@ -7178,7 +7159,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // friend void foo<>(int); // Go ahead and fake up a template id. HasExplicitTemplateArgs = true; - TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); } @@ -10569,8 +10550,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - KWLoc, NameLoc, SS, TemplateParameterLists, TUK == TUK_Friend, - isExplicitSpecialization, Invalid)) { + KWLoc, NameLoc, SS, 0, TemplateParameterLists, + TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { if (Kind == TTK_Enum) { Diag(KWLoc, diag::err_enum_template); return 0; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 65705f5a559d..8f00f9221108 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11370,7 +11370,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - TagLoc, NameLoc, SS, TempParamLists, /*friend*/ true, + TagLoc, NameLoc, SS, 0, TempParamLists, /*friend*/ true, isExplicitSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a declaration of a class template. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9be7189ba90f..58742fc055e4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1593,6 +1593,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, /// parameter lists. This scope specifier precedes a qualified name that is /// being declared. /// +/// \param TemplateId The template-id following the scope specifier, if there +/// is one. Used to check for a missing 'template<>'. +/// /// \param ParamLists the template parameter lists, from the outermost to the /// innermost template parameter lists. /// @@ -1611,6 +1614,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, /// itself a template). TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, + TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; @@ -1830,6 +1834,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( else ExpectedTemplateLoc = DeclStartLoc; + // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList. Diag(DeclLoc, diag::err_template_spec_needs_header) << getRangeOfTypeInNestedNameSpecifier(Context, T, SS) << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); @@ -1875,12 +1880,33 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } } - + // If there were at least as many template-ids as there were template // parameter lists, then there are no template parameter lists remaining for // the declaration itself. - if (ParamIdx >= ParamLists.size()) + if (ParamIdx >= ParamLists.size()) { + if (TemplateId && !IsFriend) { + // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList. + // We don't have a template header for the declaration itself, but we + // should. + SourceLocation ExpectedTemplateLoc; + if (!ParamLists.empty()) + ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc(); + else + ExpectedTemplateLoc = DeclStartLoc; + Diag(DeclLoc, diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + IsExplicitSpecialization = true; + + // Fabricate an empty template parameter list for the invented header. + return TemplateParameterList::Create(Context, SourceLocation(), + SourceLocation(), 0, 0, + SourceLocation()); + } + return 0; + } // If there were too many template parameter lists, complain about that now. if (ParamIdx < ParamLists.size() - 1) { @@ -2355,6 +2381,17 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, return true; } +/// Convert the parser's template argument list representation into our form. +static TemplateArgumentListInfo +makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { + TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, + TemplateId.RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), + TemplateId.NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + return TemplateArgs; +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, VarDecl::StorageClass SC, @@ -2364,13 +2401,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization( "Variable template specialization is declared with a template it."); TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgumentListInfo TemplateArgs = + makeTemplateArgumentListInfo(*this, *TemplateId); SourceLocation TemplateNameLoc = D.getIdentifierLoc(); SourceLocation LAngleLoc = TemplateId->LAngleLoc; SourceLocation RAngleLoc = TemplateId->RAngleLoc; - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); - translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + TemplateName Name = TemplateId->Template.get(); // The template-id must name a variable template. @@ -5840,23 +5876,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, - CXXScopeSpec &SS, - TemplateTy TemplateD, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation RAngleLoc, + TemplateIdAnnotation &TemplateId, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists) { assert(TUK != TUK_Reference && "References are not specializations"); + CXXScopeSpec &SS = TemplateId.SS; + // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 - ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation(); + ? TemplateParameterLists[0]->getTemplateLoc() : KWLoc; + SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc; + SourceLocation LAngleLoc = TemplateId.LAngleLoc; + SourceLocation RAngleLoc = TemplateId.RAngleLoc; // Find the class template we're specializing - TemplateName Name = TemplateD.get(); + TemplateName Name = TemplateId.Template.get(); ClassTemplateDecl *ClassTemplate = dyn_cast_or_null(Name.getAsTemplateDecl()); @@ -5877,8 +5913,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, bool Invalid = false; TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( - TemplateNameLoc, TemplateNameLoc, SS, TemplateParameterLists, - TUK == TUK_Friend, isExplicitSpecialization, Invalid); + KWLoc, TemplateNameLoc, SS, &TemplateId, + TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization, + Invalid); if (Invalid) return true; @@ -5929,11 +5966,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, << SourceRange(LAngleLoc, RAngleLoc); else isExplicitSpecialization = true; - } else if (TUK != TUK_Friend) { - Diag(KWLoc, diag::err_template_spec_needs_header) - << FixItHint::CreateInsertion(KWLoc, "template<> "); - TemplateKWLoc = KWLoc; - isExplicitSpecialization = true; + } else { + assert(TUK == TUK_Friend && "should have a 'template<>' for this decl"); } // Check that the specialization uses the same tag kind as the @@ -5953,10 +5987,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } // Translate the parser's template argument list in our AST format. - TemplateArgumentListInfo TemplateArgs; - TemplateArgs.setLAngleLoc(LAngleLoc); - TemplateArgs.setRAngleLoc(RAngleLoc); - translateTemplateArguments(TemplateArgsIn, TemplateArgs); + TemplateArgumentListInfo TemplateArgs = + makeTemplateArgumentListInfo(*this, TemplateId); // Check for unexpanded parameter packs in any of the template arguments. for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -7416,13 +7448,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, } // Translate the parser's template argument list into our AST format. - TemplateArgumentListInfo TemplateArgs; - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + TemplateArgumentListInfo TemplateArgs = + makeTemplateArgumentListInfo(*this, *D.getName().TemplateId); DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(), TemplateArgs); @@ -7492,12 +7519,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId); HasExplicitTemplateArgs = true; } diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index 52bbb3849a8f..6a8e7d1e8494 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -19,7 +19,7 @@ virtual void C1::f() { } // expected-error{{'virtual' can only be specified insi static void C1::g() { } // expected-error{{'static' can only be specified inside the class definition}} -template struct CT { }; // expected-note{{previous use is here}} +template struct CT { template struct Inner; }; // expected-note{{previous use is here}} CT<10 >> 2> ct; // expected-warning{{require parentheses}} @@ -32,6 +32,8 @@ struct CT<0> { }; // expected-error{{'template<>'}} template<> union CT<1> { }; // expected-error{{tag type}} +struct CT<2>::Inner { }; // expected-error 2{{'template<>'}} + // Access declarations class A { protected: