"%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 "
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:\r
+ // ...\r
+ // parameter-declaration\r
+ // 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)
-// 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
template<typename T, typename X<T>::type Value> struct Y1;
// A storage class shall not be specified in a template-parameter declaration.
-template<static int Value> struct Z; // FIXME: expect an error
+template<static int Value> struct Z; //expected-error{{invalid declaration specifier}}
+template<typedef int Value> struct Z0; //expected-error{{invalid declaration specifier}}
+template<extern inline int Value> struct Z0; //expected-error2{{invalid declaration specifier}}
+template<virtual int Value> struct Z0; //expected-error{{invalid declaration specifier}}
+template<explicit int Value> struct Z0; //expected-error{{invalid declaration specifier}}
+template<inline int Value> struct Z0; //expected-error{{invalid declaration specifier}}
+template<extern int> struct Z0; //expected-error{{invalid declaration specifier}}
+template<static int> struct Z0; //expected-error{{invalid declaration specifier}}
+template<explicit int Value> struct Z0; //expected-error{{invalid declaration specifier}}
+template<mutable int> struct Z0; //expected-error{{invalid declaration specifier}}
+
+template<const int> struct Z0; // OK
+template<volatile int> struct Z0; // OK
+
+
+
+#ifdef CPP11
+template<thread_local int> struct Z0; //expected-error{{invalid declaration specifier}}
+template<constexpr int> struct Z0; //expected-error{{invalid declaration specifier}}
+
+#endif
+
+#ifdef CPP17
+template<auto> struct Z1; // OK
+#endif
// Make sure that we properly disambiguate non-type template parameters that
// start with 'class'.