Google ref: b/11479502 /// --- cut --- template <const char name[]> class BaseObject { virtual const char* GetName() const { return name; } }; const char kName[] = "name"; class Object : public BaseObject<kName> { }; int main() { return 0; } /// --- cut --- Using g++ (GCC) 4.9.0 20131028 (experimental) g++ -c t.cc t.cc:9:34: error: 'kName' cannot appear in a constant-expression class Object : public BaseObject<kName> { ^ t.cc:9:39: error: template argument 1 is invalid class Object : public BaseObject<kName> { ^ g++ -c t.cc -std=c++11 t.cc:9:34: error: the value of 'kName' is not usable in a constant expression class Object : public BaseObject<kName> { ^ t.cc:8:12: note: 'kName' was not declared 'constexpr' const char kName[] = "name"; ^ Compiles with Clang. Analysis by Richard Smith: This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type. You can also get GCC to accept the code by marking kName as 'extern'. Obligatory standards references (relative to N3797): [temp.param](14.1)/8: "A non-type template-parameter of type "array of T" [...] is adjusted to be of type "pointer to T". [temp.arg.nontype](14.3.2)/1: "A template-argument for a non-type, non-template template-parameter shall be [...] a constant expression that designates the address of a complete object with static storage duration and external or internal linkage [...] expressed [...] as & id-expression, where the id-expression is the name of an object [...], except that the & may be omitted if the name refers to a[n] [...] array" Note that "kName" is a constant expression, because it is a glvalue core constant expression whose value refers to an object with static storage duration (see [expr.const](5.19)/4). [temp.arg.nontype](14.3.2)/5: "The following conversions are performed on each expression used as a non-type template-argument. [...] For a non-type template-parameter of type pointer to object, [...] the array-to-pointer conversion [is] applied." So BaseObject has a template parameter of type 'const char*', and that parameter can bind to the template argument kName (after array-to-pointer decay). There's no requirement that kName be declared 'constexpr'; its value is not used here, only its address is used.
Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function. We could allow here additional ARRAY_TYPEs with constant, non-vla, and trivial destructors. Maybe even non-trivial destructors could be ok. Not sure Suggested patch, which allows provided testcase to run is: Index: decl2.c =================================================================== --- decl2.c (Revision 218570) +++ decl2.c (Arbeitskopie) @@ -4157,8 +4157,12 @@ decl_maybe_constant_var_p (tree decl) return false; if (DECL_DECLARED_CONSTEXPR_P (decl)) return true; - return (CP_TYPE_CONST_NON_VOLATILE_P (type) - && INTEGRAL_OR_ENUMERATION_TYPE_P (type)); + if (!CP_TYPE_CONST_NON_VOLATILE_P (type)) + return false; + return ((TREE_CODE (type) == ARRAY_TYPE + && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)) + && !array_of_runtime_bound_p (type)) + || INTEGRAL_OR_ENUMERATION_TYPE_P (type)); } /* Complain that DECL uses a type with no linkage. In C++98 mode this is
(In reply to Kai Tietz from comment #1) > Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function. I don't know how the GCC code is structured, but I don't think that's right; that function appears to be checking whether the value of the variable can be used in a constant expression. The relevant condition here is whether the address of the variable can be used.
(In reply to Richard Smith from comment #2) > (In reply to Kai Tietz from comment #1) > > Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function. > > I don't know how the GCC code is structured, but I don't think that's right; > that function appears to be checking whether the value of the variable can > be used in a constant expression. The relevant condition here is whether the > address of the variable can be used. hmm, this function has nothing to do with its value. AFAIU the comment (and its use) it just checks that a VAR-decl might be a constant. In general it checks for const and volatile attributes, and assumes for integral/enumeral typed variables that variable is constant. So a 'const char *' isn't constant - as just the destination the variable is pointing to is constant, but not the variable itself. For a constant array with trivial destructor, and non-vla size this is different. The array's name is indeed a constant address, and its content is constant too. Of course the a variable pointing to into an array isn't constant, but the array itself is. Anyway I might be wrong here
This was fixed by r249079 on trunk and r249325 for 7.2 Fix array decay handling in constant expressions. * parser.c (cp_parser_constant_expression): Check potential_rvalue_constant_expression after decay_conversion. * pt.c (convert_nontype_argument): Don't require linkage in C++17.