<div dir="ltr">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.</div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 28, 2015 at 8:14 PM, Nico Weber <span dir="ltr"><<a href="mailto:thakis@chromium.org" target="_blank">thakis@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On Wed, Apr 16, 2014 at 8:29 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: rsmith<br>
Date: Wed Apr 16 22:29:33 2014<br>
New Revision: 206442<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=206442&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=206442&view=rev</a><br>
Log:<br>
Refactor all the checking for missing 'template<>'s when a declaration has a<br>
template-id after its scope specifier into a single place.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaDecl.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
    cfe/trunk/test/FixIt/fixit.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr 16 22:29:33 2014<br>
@@ -5197,7 +5197,8 @@ public:<br>
                                   TemplateParamListContext TPC);<br>
   TemplateParameterList *MatchTemplateParametersToScopeSpecifier(<br>
       SourceLocation DeclStartLoc, SourceLocation DeclLoc,<br>
-      const CXXScopeSpec &SS, ArrayRef<TemplateParameterList *> ParamLists,<br>
+      const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,<br>
+      ArrayRef<TemplateParameterList *> ParamLists,<br>
       bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid);<br>
<br>
   DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,<br>
@@ -5279,12 +5280,7 @@ public:<br>
   ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,<br>
                                    SourceLocation KWLoc,<br>
                                    SourceLocation ModulePrivateLoc,<br>
-                                   CXXScopeSpec &SS,<br>
-                                   TemplateTy Template,<br>
-                                   SourceLocation TemplateNameLoc,<br>
-                                   SourceLocation LAngleLoc,<br>
-                                   ASTTemplateArgsPtr TemplateArgs,<br>
-                                   SourceLocation RAngleLoc,<br>
+                                   TemplateIdAnnotation &TemplateId,<br>
                                    AttributeList *Attr,<br>
                                  MultiTemplateParamsArg TemplateParameterLists);<br>
<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Apr 16 22:29:33 2014<br>
@@ -1541,18 +1541,11 @@ void Parser::ParseClassSpecifier(tok::To<br>
       }<br>
<br>
       // Build the class template specialization.<br>
-      TagOrTempResult<br>
-        = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK,<br>
-                       StartLoc, DS.getModulePrivateSpecLoc(), SS,<br>
-                       TemplateId->Template,<br>
-                       TemplateId->TemplateNameLoc,<br>
-                       TemplateId->LAngleLoc,<br>
-                       TemplateArgsPtr,<br>
-                       TemplateId->RAngleLoc,<br>
-                       attrs.getList(),<br>
-                       MultiTemplateParamsArg(<br>
-                                    TemplateParams? &(*TemplateParams)[0] : 0,<br>
-                                 TemplateParams? TemplateParams->size() : 0));<br>
+      TagOrTempResult = Actions.ActOnClassTemplateSpecialization(<br>
+          getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),<br>
+          *TemplateId, attrs.getList(),<br>
+          MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : 0,<br>
+                                 TemplateParams ? TemplateParams->size() : 0));<br>
     }<br>
   } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&<br>
              TUK == Sema::TUK_Declaration) {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Apr 16 22:29:33 2014<br>
@@ -5228,29 +5228,13 @@ Sema::ActOnVariableDeclarator(Scope *S,<br>
     // determine whether we have a template or a template specialization.<br>
     TemplateParams = MatchTemplateParametersToScopeSpecifier(<br>
         D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),<br>
-        D.getCXXScopeSpec(), TemplateParamLists,<br>
+        D.getCXXScopeSpec(),<br>
+        D.getName().getKind() == UnqualifiedId::IK_TemplateId<br>
+            ? D.getName().TemplateId<br>
+            : 0,<br>
+        TemplateParamLists,<br>
         /*never a friend*/ false, IsExplicitSpecialization, Invalid);<br>
<br>
-    if (D.getName().getKind() == UnqualifiedId::IK_TemplateId &&<br>
-        !TemplateParams) {<br>
-      TemplateIdAnnotation *TemplateId = D.getName().TemplateId;<br>
-<br>
-      // We have encountered something that the user meant to be a<br>
-      // specialization (because it has explicitly-specified template<br>
-      // arguments) but that was not introduced with a "template<>" (or had<br>
-      // too few of them).<br>
-      // FIXME: Differentiate between attempts for explicit instantiations<br>
-      // (starting with "template") and the rest.<br>
-      Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)<br>
-          << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)<br>
-          << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(),<br>
-                                        "template<> ");<br>
-      IsExplicitSpecialization = true;<br>
-      TemplateParams = TemplateParameterList::Create(Context, SourceLocation(),<br>
-                                                     SourceLocation(), 0, 0,<br>
-                                                     SourceLocation());<br>
-    }<br>
-<br>
     if (TemplateParams) {<br>
       if (!TemplateParams->size() &&<br>
           D.getName().getKind() != UnqualifiedId::IK_TemplateId) {<br>
@@ -5283,6 +5267,9 @@ Sema::ActOnVariableDeclarator(Scope *S,<br>
                    : diag::ext_variable_template);<br>
         }<br>
       }<br>
+    } else {<br>
+      assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId &&<br>
+             "should have a 'template<>' for this decl");<br></blockquote><div><br></div></div></div><div>This assert fires on some invalid inputs, for example</div><div><br></div><div><div>  template <typename> struct CT2 {</div><div>    template <class U> struct X;</div><div>  };</div><div>  template <typename T> int CT2<int>::X<>;</div></div><div><br></div><div>Is the right fix just to change this to assert(Invalid || D.getName…)? (Also attached in patch form.)</div><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
     }<br>
<br>
     if (IsVariableTemplateSpecialization) {<br>
@@ -6709,8 +6696,12 @@ Sema::ActOnFunctionDeclarator(Scope *S,<br>
     if (TemplateParameterList *TemplateParams =<br>
             MatchTemplateParametersToScopeSpecifier(<br>
                 D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),<br>
-                D.getCXXScopeSpec(), TemplateParamLists, isFriend,<br>
-                isExplicitSpecialization, Invalid)) {<br>
+                D.getCXXScopeSpec(),<br>
+                D.getName().getKind() == UnqualifiedId::IK_TemplateId<br>
+                    ? D.getName().TemplateId<br>
+                    : 0,<br>
+                TemplateParamLists, isFriend, isExplicitSpecialization,<br>
+                Invalid)) {<br>
       if (TemplateParams->size() > 0) {<br>
         // This is a function template<br>
<br>
@@ -6751,9 +6742,10 @@ Sema::ActOnFunctionDeclarator(Scope *S,<br>
         // This is a function template specialization.<br>
         isFunctionTemplateSpecialization = true;<br>
         // For source fidelity, store all the template param lists.<br>
-        NewFD->setTemplateParameterListsInfo(Context,<br>
-                                             TemplateParamLists.size(),<br>
-                                             TemplateParamLists.data());<br>
+        if (TemplateParamLists.size() > 0)<br>
+          NewFD->setTemplateParameterListsInfo(Context,<br>
+                                               TemplateParamLists.size(),<br>
+                                               TemplateParamLists.data());<br>
<br>
         // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".<br>
         if (isFriend) {<br>
@@ -7152,21 +7144,10 @@ Sema::ActOnFunctionDeclarator(Scope *S,<br>
           << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);<br>
<br>
         HasExplicitTemplateArgs = false;<br>
-      } else if (!isFunctionTemplateSpecialization &&<br>
-                 !D.getDeclSpec().isFriendSpecified()) {<br>
-        // We have encountered something that the user meant to be a<br>
-        // specialization (because it has explicitly-specified template<br>
-        // arguments) but that was not introduced with a "template<>" (or had<br>
-        // too few of them).<br>
-        // FIXME: Differentiate between attempts for explicit instantiations<br>
-        // (starting with "template") and the rest.<br>
-        Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)<br>
-          << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)<br>
-          << FixItHint::CreateInsertion(<br>
-                                    D.getDeclSpec().getLocStart(),<br>
-                                        "template<> ");<br>
-        isFunctionTemplateSpecialization = true;<br>
       } else {<br>
+        assert((isFunctionTemplateSpecialization ||<br>
+                D.getDeclSpec().isFriendSpecified()) &&<br>
+               "should have a 'template<>' for this decl");<br>
         // "friend void foo<>(int);" is an implicit specialization decl.<br>
         isFunctionTemplateSpecialization = true;<br>
       }<br>
@@ -7178,7 +7159,7 @@ Sema::ActOnFunctionDeclarator(Scope *S,<br>
       //   friend void foo<>(int);<br>
       // Go ahead and fake up a template id.<br>
       HasExplicitTemplateArgs = true;<br>
-        TemplateArgs.setLAngleLoc(D.getIdentifierLoc());<br>
+      TemplateArgs.setLAngleLoc(D.getIdentifierLoc());<br>
       TemplateArgs.setRAngleLoc(D.getIdentifierLoc());<br>
     }<br>
<br>
@@ -10569,8 +10550,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned<br>
       (SS.isNotEmpty() && TUK != TUK_Reference)) {<br>
     if (TemplateParameterList *TemplateParams =<br>
             MatchTemplateParametersToScopeSpecifier(<br>
-                KWLoc, NameLoc, SS, TemplateParameterLists, TUK == TUK_Friend,<br>
-                isExplicitSpecialization, Invalid)) {<br>
+                KWLoc, NameLoc, SS, 0, TemplateParameterLists,<br>
+                TUK == TUK_Friend, isExplicitSpecialization, Invalid)) {<br>
       if (Kind == TTK_Enum) {<br>
         Diag(KWLoc, diag::err_enum_template);<br>
         return 0;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Apr 16 22:29:33 2014<br>
@@ -11370,7 +11370,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scop<br>
<br>
   if (TemplateParameterList *TemplateParams =<br>
           MatchTemplateParametersToScopeSpecifier(<br>
-              TagLoc, NameLoc, SS, TempParamLists, /*friend*/ true,<br>
+              TagLoc, NameLoc, SS, 0, TempParamLists, /*friend*/ true,<br>
               isExplicitSpecialization, Invalid)) {<br>
     if (TemplateParams->size() > 0) {<br>
       // This is a declaration of a class template.<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Apr 16 22:29:33 2014<br>
@@ -1593,6 +1593,9 @@ static SourceRange getRangeOfTypeInNeste<br>
 /// parameter lists. This scope specifier precedes a qualified name that is<br>
 /// being declared.<br>
 ///<br>
+/// \param TemplateId The template-id following the scope specifier, if there<br>
+/// is one. Used to check for a missing 'template<>'.<br>
+///<br>
 /// \param ParamLists the template parameter lists, from the outermost to the<br>
 /// innermost template parameter lists.<br>
 ///<br>
@@ -1611,6 +1614,7 @@ static SourceRange getRangeOfTypeInNeste<br>
 /// itself a template).<br>
 TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(<br>
     SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,<br>
+    TemplateIdAnnotation *TemplateId,<br>
     ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,<br>
     bool &IsExplicitSpecialization, bool &Invalid) {<br>
   IsExplicitSpecialization = false;<br>
@@ -1830,6 +1834,7 @@ TemplateParameterList *Sema::MatchTempla<br>
         else<br>
           ExpectedTemplateLoc = DeclStartLoc;<br>
<br>
+        // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.<br>
         Diag(DeclLoc, diag::err_template_spec_needs_header)<br>
           << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)<br>
           << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");<br>
@@ -1875,12 +1880,33 @@ TemplateParameterList *Sema::MatchTempla<br>
       continue;<br>
     }<br>
   }<br>
-<br>
+<br>
   // If there were at least as many template-ids as there were template<br>
   // parameter lists, then there are no template parameter lists remaining for<br>
   // the declaration itself.<br>
-  if (ParamIdx >= ParamLists.size())<br>
+  if (ParamIdx >= ParamLists.size()) {<br>
+    if (TemplateId && !IsFriend) {<br>
+      // FIXME: Don't recover this way if we SawNonEmptyTemplateParameterList.<br>
+      // We don't have a template header for the declaration itself, but we<br>
+      // should.<br>
+      SourceLocation ExpectedTemplateLoc;<br>
+      if (!ParamLists.empty())<br>
+        ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();<br>
+      else<br>
+        ExpectedTemplateLoc = DeclStartLoc;<br>
+      Diag(DeclLoc, diag::err_template_spec_needs_header)<br>
+          << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)<br>
+          << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");<br>
+      IsExplicitSpecialization = true;<br>
+<br>
+      // Fabricate an empty template parameter list for the invented header.<br>
+      return TemplateParameterList::Create(Context, SourceLocation(),<br>
+                                           SourceLocation(), 0, 0,<br>
+                                           SourceLocation());<br>
+    }<br>
+<br>
     return 0;<br>
+  }<br>
<br>
   // If there were too many template parameter lists, complain about that now.<br>
   if (ParamIdx < ParamLists.size() - 1) {<br>
@@ -2355,6 +2381,17 @@ static bool isSameAsPrimaryTemplate(Temp<br>
   return true;<br>
 }<br>
<br>
+/// Convert the parser's template argument list representation into our form.<br>
+static TemplateArgumentListInfo<br>
+makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {<br>
+  TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,<br>
+                                        TemplateId.RAngleLoc);<br>
+  ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),<br>
+                                     TemplateId.NumArgs);<br>
+  S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);<br>
+  return TemplateArgs;<br>
+}<br>
+<br>
 DeclResult Sema::ActOnVarTemplateSpecialization(<br>
     Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,<br>
     TemplateParameterList *TemplateParams, VarDecl::StorageClass SC,<br>
@@ -2364,13 +2401,12 @@ DeclResult Sema::ActOnVarTemplateSpecial<br>
          "Variable template specialization is declared with a template it.");<br>
<br>
   TemplateIdAnnotation *TemplateId = D.getName().TemplateId;<br>
+  TemplateArgumentListInfo TemplateArgs =<br>
+      makeTemplateArgumentListInfo(*this, *TemplateId);<br>
   SourceLocation TemplateNameLoc = D.getIdentifierLoc();<br>
   SourceLocation LAngleLoc = TemplateId->LAngleLoc;<br>
   SourceLocation RAngleLoc = TemplateId->RAngleLoc;<br>
-  ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>
-                                     TemplateId->NumArgs);<br>
-  TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);<br>
-  translateTemplateArguments(TemplateArgsPtr, TemplateArgs);<br>
+<br>
   TemplateName Name = TemplateId->Template.get();<br>
<br>
   // The template-id must name a variable template.<br>
@@ -5840,23 +5876,23 @@ Sema::ActOnClassTemplateSpecialization(S<br>
                                        TagUseKind TUK,<br>
                                        SourceLocation KWLoc,<br>
                                        SourceLocation ModulePrivateLoc,<br>
-                                       CXXScopeSpec &SS,<br>
-                                       TemplateTy TemplateD,<br>
-                                       SourceLocation TemplateNameLoc,<br>
-                                       SourceLocation LAngleLoc,<br>
-                                       ASTTemplateArgsPtr TemplateArgsIn,<br>
-                                       SourceLocation RAngleLoc,<br>
+                                       TemplateIdAnnotation &TemplateId,<br>
                                        AttributeList *Attr,<br>
                                MultiTemplateParamsArg TemplateParameterLists) {<br>
   assert(TUK != TUK_Reference && "References are not specializations");<br>
<br>
+  CXXScopeSpec &SS = TemplateId.SS;<br>
+<br>
   // NOTE: KWLoc is the location of the tag keyword. This will instead<br>
   // store the location of the outermost template keyword in the declaration.<br>
   SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0<br>
-    ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();<br>
+    ? TemplateParameterLists[0]->getTemplateLoc() : KWLoc;<br>
+  SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;<br>
+  SourceLocation LAngleLoc = TemplateId.LAngleLoc;<br>
+  SourceLocation RAngleLoc = TemplateId.RAngleLoc;<br>
<br>
   // Find the class template we're specializing<br>
-  TemplateName Name = TemplateD.get();<br>
+  TemplateName Name = TemplateId.Template.get();<br>
   ClassTemplateDecl *ClassTemplate<br>
     = dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl());<br>
<br>
@@ -5877,8 +5913,9 @@ Sema::ActOnClassTemplateSpecialization(S<br>
   bool Invalid = false;<br>
   TemplateParameterList *TemplateParams =<br>
       MatchTemplateParametersToScopeSpecifier(<br>
-          TemplateNameLoc, TemplateNameLoc, SS, TemplateParameterLists,<br>
-          TUK == TUK_Friend, isExplicitSpecialization, Invalid);<br>
+          KWLoc, TemplateNameLoc, SS, &TemplateId,<br>
+          TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization,<br>
+          Invalid);<br>
   if (Invalid)<br>
     return true;<br>
<br>
@@ -5929,11 +5966,8 @@ Sema::ActOnClassTemplateSpecialization(S<br>
         << SourceRange(LAngleLoc, RAngleLoc);<br>
     else<br>
       isExplicitSpecialization = true;<br>
-  } else if (TUK != TUK_Friend) {<br>
-    Diag(KWLoc, diag::err_template_spec_needs_header)<br>
-      << FixItHint::CreateInsertion(KWLoc, "template<> ");<br>
-    TemplateKWLoc = KWLoc;<br>
-    isExplicitSpecialization = true;<br>
+  } else {<br>
+    assert(TUK == TUK_Friend && "should have a 'template<>' for this decl");<br>
   }<br>
<br>
   // Check that the specialization uses the same tag kind as the<br>
@@ -5953,10 +5987,8 @@ Sema::ActOnClassTemplateSpecialization(S<br>
   }<br>
<br>
   // Translate the parser's template argument list in our AST format.<br>
-  TemplateArgumentListInfo TemplateArgs;<br>
-  TemplateArgs.setLAngleLoc(LAngleLoc);<br>
-  TemplateArgs.setRAngleLoc(RAngleLoc);<br>
-  translateTemplateArguments(TemplateArgsIn, TemplateArgs);<br>
+  TemplateArgumentListInfo TemplateArgs =<br>
+      makeTemplateArgumentListInfo(*this, TemplateId);<br>
<br>
   // Check for unexpanded parameter packs in any of the template arguments.<br>
   for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)<br>
@@ -7416,13 +7448,8 @@ DeclResult Sema::ActOnExplicitInstantiat<br>
       }<br>
<br>
       // Translate the parser's template argument list into our AST format.<br>
-      TemplateArgumentListInfo TemplateArgs;<br>
-      TemplateIdAnnotation *TemplateId = D.getName().TemplateId;<br>
-      TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);<br>
-      TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);<br>
-      ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>
-                                         TemplateId->NumArgs);<br>
-      translateTemplateArguments(TemplateArgsPtr, TemplateArgs);<br>
+      TemplateArgumentListInfo TemplateArgs =<br>
+          makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);<br>
<br>
       DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,<br>
                                           D.getIdentifierLoc(), TemplateArgs);<br>
@@ -7492,12 +7519,7 @@ DeclResult Sema::ActOnExplicitInstantiat<br>
   bool HasExplicitTemplateArgs = false;<br>
   TemplateArgumentListInfo TemplateArgs;<br>
   if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {<br>
-    TemplateIdAnnotation *TemplateId = D.getName().TemplateId;<br>
-    TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);<br>
-    TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);<br>
-    ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>
-                                       TemplateId->NumArgs);<br>
-    translateTemplateArguments(TemplateArgsPtr, TemplateArgs);<br>
+    TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);<br>
     HasExplicitTemplateArgs = true;<br>
   }<br>
<br>
<br>
Modified: cfe/trunk/test/FixIt/fixit.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=206442&r1=206441&r2=206442&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=206442&r1=206441&r2=206442&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/FixIt/fixit.cpp (original)<br>
+++ cfe/trunk/test/FixIt/fixit.cpp Wed Apr 16 22:29:33 2014<br>
@@ -19,7 +19,7 @@ virtual void C1::f() { } // expected-err<br>
<br>
 static void C1::g() { } // expected-error{{'static' can only be specified inside the class definition}}<br>
<br>
-template<int Value> struct CT { }; // expected-note{{previous use is here}}<br>
+template<int Value> struct CT { template<typename> struct Inner; }; // expected-note{{previous use is here}}<br>
<br>
 CT<10 >> 2> ct; // expected-warning{{require parentheses}}<br>
<br>
@@ -32,6 +32,8 @@ struct CT<0> { }; // expected-error{{'te<br>
<br>
 template<> union CT<1> { }; // expected-error{{tag type}}<br>
<br>
+struct CT<2>::Inner<int> { }; // expected-error 2{{'template<>'}}<br>
+<br>
 // Access declarations<br>
 class A {<br>
 protected:<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div>