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
This commit is contained in:
Richard Smith 2014-04-17 03:29:33 +00:00
parent 0d963d6c49
commit 4b55a9c841
6 changed files with 96 additions and 102 deletions

View File

@ -5197,7 +5197,8 @@ public:
TemplateParamListContext TPC);
TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, ArrayRef<TemplateParameterList *> ParamLists,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> 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);

View File

@ -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) {

View File

@ -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;

View File

@ -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.

View File

@ -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<TemplateParameterList *> 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<ClassTemplateDecl>(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;
}

View File

@ -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<int Value> struct CT { }; // expected-note{{previous use is here}}
template<int Value> struct CT { template<typename> 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<int> { }; // expected-error 2{{'template<>'}}
// Access declarations
class A {
protected: