Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3911,6 +3911,9 @@ "%select{|template parameter }0redeclaration">; def note_template_param_different_kind : Note< "template parameter has a different kind in template argument">; + +def err_invalid_decl_specifier_in_nontype_parm : Error< + "invalid declaration specifier in template non-type parameter">; def err_template_nontype_parm_different_type : Error< "template non-type parameter has a different type %0 in template " Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -929,6 +929,60 @@ Expr *Default) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + // Check that we have valid decl-specifiers specified. + auto CheckValidDeclSpecifiers = [this, &D] { + // C++ [temp.param] + // p1 + // template-parameter: + // ... + // parameter-declaration + // p2 + // ... A storage class shall not be specified in a template-parameter + // declaration. + // [dcl.typedef]p1: + // The typedef specifier [...] shall not be used in the decl-specifier-seq + // of a parameter-declaration + const DeclSpec &DS = D.getDeclSpec(); + auto EmitDiag = [this](SourceLocation Loc) { + Diag(Loc, diag::err_invalid_decl_specifier_in_nontype_parm) + << FixItHint::CreateRemoval(Loc); + }; + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) + EmitDiag(DS.getStorageClassSpecLoc()); + + if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) + EmitDiag(DS.getThreadStorageClassSpecLoc()); + + // [dcl.inline]p1: + // The inline specifier can be applied only to the declaration or + // definition of a variable or function. + + if (DS.isInlineSpecified()) + EmitDiag(DS.getInlineSpecLoc()); + + // [dcl.constexpr]p1: + // The constexpr specifier shall be applied only to the definition of a + // variable or variable template or the declaration of a function or + // function template. + + if (DS.isConstexprSpecified()) + EmitDiag(DS.getConstexprSpecLoc()); + + // [dcl.fct.spec]p1: + // Function-specifiers can be used only in function declarations. + + if (DS.isVirtualSpecified()) + EmitDiag(DS.getVirtualSpecLoc()); + + if (DS.isExplicitSpecified()) + EmitDiag(DS.getExplicitSpecLoc()); + + if (DS.isNoreturnSpecified()) + EmitDiag(DS.getNoreturnSpecLoc()); + }; + + CheckValidDeclSpecifiers(); + if (TInfo->getType()->isUndeducedType()) { Diag(D.getIdentifierLoc(), diag::warn_cxx14_compat_template_nontype_parm_auto_type) Index: test/CXX/temp/temp.param/p2.cpp =================================================================== --- test/CXX/temp/temp.param/p2.cpp +++ test/CXX/temp/temp.param/p2.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -DCPP11 +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -DCPP17 // There is no semantic difference between class and typename in a // template-parameter. typename followed by an unqualified-id names a @@ -13,8 +14,32 @@ template::type Value> struct Y1; // A storage class shall not be specified in a template-parameter declaration. -template struct Z; // FIXME: expect an error +template struct Z; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error2{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; // OK +template struct Z0; // OK + + + +#ifdef CPP11 +template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z0; //expected-error{{invalid declaration specifier}} + +#endif + +#ifdef CPP17 +template struct Z1; // OK +#endif + // Make sure that we properly disambiguate non-type template parameters that // start with 'class'. class X1 { };