r227540, thanks. I'll look through MatchTemplateParametersToScopeSpecifier() for places that need to set Invalid.
On Thu, Jan 29, 2015 at 4:24 PM, Richard Smith <[email protected]> wrote: > It looks like there are paths through > MatchTemplateParametersToScopeSpecifier that return nullptr on invalid > inputs but don't set Invalid to true; I don't think this patch is > sufficient, though it does seem correct as far as it goes. > > On Wed, Jan 28, 2015 at 8:14 PM, Nico Weber <[email protected]> wrote: > >> On Wed, Apr 16, 2014 at 8:29 PM, Richard Smith < >> [email protected]> 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 >>> [email protected] >>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >>> >> >> >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
