r206442 - Refactor all the checking for missing 'template<>'s when a declaration has a
Nico Weber
thakis at chromium.org
Wed Jan 28 20:14:31 PST 2015
On Wed, Apr 16, 2014 at 8:29 PM, Richard Smith <richard-llvm at metafoo.co.uk>
wrote:
> 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");
>
This assert fires on some invalid inputs, for example
template <typename> struct CT2 {
template <class U> struct X;
};
template <typename T> int CT2<int>::X<>;
Is the right fix just to change this to assert(Invalid || D.getNameā¦)?
(Also attached in patch form.)
> }
>
> 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:
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150128/bcb1f7a5/attachment.html>
-------------- next part --------------
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp (revision 227416)
+++ lib/Sema/SemaDecl.cpp (working copy)
@@ -5578,8 +5578,9 @@
}
}
} else {
- assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId &&
- "should have a 'template<>' for this decl");
+ assert(
+ (Invalid || D.getName().getKind() != UnqualifiedId::IK_TemplateId) &&
+ "should have a 'template<>' for this decl");
}
if (IsVariableTemplateSpecialization) {
Index: test/SemaTemplate/dependent-names.cpp
===================================================================
--- test/SemaTemplate/dependent-names.cpp (revision 227416)
+++ test/SemaTemplate/dependent-names.cpp (working copy)
@@ -414,3 +414,8 @@
template<typename T> decltype(*T()) f() {} // expected-error {{redefinition}}
template<typename T> decltype(T() * T()) g() {} // expected-error {{redefinition}}
}
+
+template <typename> struct CT2 {
+ template <class U> struct X;
+};
+template <typename T> int CT2<int>::X<>; // expected-error {{template parameter list matching the non-templated nested type 'CT2<int>' should be empty}}
More information about the cfe-commits
mailing list