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