r321339 - Diagnose the various invalid decl-specifiers on nontype template parameters.

Faisal Vali via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 21 19:50:55 PST 2017


Author: faisalv
Date: Thu Dec 21 19:50:55 2017
New Revision: 321339

URL: http://llvm.org/viewvc/llvm-project?rev=321339&view=rev
Log:
Diagnose the various invalid decl-specifiers on nontype template parameters.

The standard correctly forbids various decl-specifiers that dont make sense on non-type template parameters - such as the extern in:
    template<extern int> struct X;

This patch implements those restrictions (in a fashion similar to the corresponding checks on function parameters within ActOnParamDeclarator).

Credit goes to miyuki (Mikhail Maltsev) for drawing attention to this issue,  authoring the initial versions of this patch, and supporting the effort to re-engineer it slightly.  Thank you!

For details of how this patch evolved please see: https://reviews.llvm.org/D40705



Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.param/p2.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=321339&r1=321338&r2=321339&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 21 19:50:55 2017
@@ -3911,6 +3911,9 @@ def err_template_param_different_kind :
   "%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 "

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=321339&r1=321338&r2=321339&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Dec 21 19:50:55 2017
@@ -929,6 +929,60 @@ Decl *Sema::ActOnNonTypeTemplateParamete
                                           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)

Modified: cfe/trunk/test/CXX/temp/temp.param/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p2.cpp?rev=321339&r1=321338&r2=321339&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.param/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.param/p2.cpp Thu Dec 21 19:50:55 2017
@@ -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,7 +14,31 @@ template<typename T, typename T::type Va
 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'.




More information about the cfe-commits mailing list