r206442 - Refactor all the checking for missing 'template<>'s when a declaration has a
Richard Smith
richard-llvm at metafoo.co.uk
Wed Apr 16 20:29:34 PDT 2014
Author: rsmith
Date: Wed Apr 16 22:29:33 2014
New Revision: 206442
URL: http://llvm.org/viewvc/llvm-project?rev=206442&view=rev
Log:
Refactor all the checking for missing 'template<>'s when a declaration has a
template-id after its scope specifier into a single place.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/FixIt/fixit.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr 16 22:29:33 2014
@@ -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);
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Apr 16 22:29:33 2014
@@ -1541,18 +1541,11 @@ void Parser::ParseClassSpecifier(tok::To
}
// 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) {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Apr 16 22:29:33 2014
@@ -5228,29 +5228,13 @@ Sema::ActOnVariableDeclarator(Scope *S,
// 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,
: 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,
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,
// 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,
<< 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,
// 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
(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;
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Apr 16 22:29:33 2014
@@ -11370,7 +11370,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scop
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.
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Apr 16 22:29:33 2014
@@ -1593,6 +1593,9 @@ static SourceRange getRangeOfTypeInNeste
/// 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 getRangeOfTypeInNeste
/// 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::MatchTempla
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::MatchTempla
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(Temp
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::ActOnVarTemplateSpecial
"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(S
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(S
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(S
<< 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(S
}
// 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::ActOnExplicitInstantiat
}
// 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::ActOnExplicitInstantiat
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;
}
Modified: cfe/trunk/test/FixIt/fixit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=206442&r1=206441&r2=206442&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit.cpp (original)
+++ cfe/trunk/test/FixIt/fixit.cpp Wed Apr 16 22:29:33 2014
@@ -19,7 +19,7 @@ virtual void C1::f() { } // expected-err
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{{'te
template<> union CT<1> { }; // expected-error{{tag type}}
+struct CT<2>::Inner<int> { }; // expected-error 2{{'template<>'}}
+
// Access declarations
class A {
protected:
More information about the cfe-commits
mailing list