Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -668,6 +668,9 @@ def warn_missing_dependent_template_keyword : ExtWarn< "use 'template' keyword to treat '%0' as a dependent template name">; +def err_storage_class_template_parameter : Error< + "storage class specified for template parameter%select{| %1}0">; + def ext_extern_template : Extension< "extern templates are a C++11 extension">, InGroup; def warn_cxx98_compat_extern_template : Warning< Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -686,6 +686,22 @@ return nullptr; } + // C++ [temp.param]p2: + // A storage class shall not be specified in a template-parameter + // declaration. + auto ReportStorageClass = [this, &ParamDecl](SourceLocation Loc) { + if (ParamDecl.getIdentifier()) + Diag(Loc, diag::err_storage_class_template_parameter) + << 1 << ParamDecl.getIdentifier() << FixItHint::CreateRemoval(Loc); + else + Diag(Loc, diag::err_storage_class_template_parameter) + << 0 << FixItHint::CreateRemoval(Loc); + }; + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) + ReportStorageClass(DS.getStorageClassSpecLoc()); + if (DS.getThreadStorageClassSpec() != DeclSpec::TSCS_unspecified) + ReportStorageClass(DS.getThreadStorageClassSpecLoc()); + // Recover from misplaced ellipsis. SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) Index: test/CXX/temp/temp.param/p2-cpp11.cpp =================================================================== --- /dev/null +++ test/CXX/temp/temp.param/p2-cpp11.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s + +// A storage class shall not be specified in a template-parameter declaration. +template struct Z0; // expected-error {{storage class specified for template parameter 'Value'}} +template struct Z1; // expected-error {{storage class specified for template parameter}} 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,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics // There is no semantic difference between class and typename in a // template-parameter. typename followed by an unqualified-id names a @@ -13,7 +12,8 @@ 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 Z0; // expected-error {{storage class specified for template parameter 'Value'}} +template struct Z1; // expected-error {{storage class specified for template parameter}} // Make sure that we properly disambiguate non-type template parameters that // start with 'class'.