From 3d2e25a240c7115c3deaaa9dea856588300dd05b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 9 Jun 2017 16:13:44 -0400 Subject: [PATCH] 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. From-SVN: r249079 --- gcc/cp/ChangeLog | 4 +++ gcc/cp/parser.c | 8 +++-- gcc/cp/pt.c | 35 ++++++++++++++++++- gcc/testsuite/g++.dg/template/function1.C | 4 +-- .../g++.dg/template/nontype-array1.C | 27 ++++++++++++++ 5 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/nontype-array1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 944b69596fe..7bc9c204a29 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2017-06-09 Jason Merrill + * 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. + PR c++/80384 - ICE with dependent noexcept-specifier * pt.c (dependent_type_p_r) [FUNCTION_TYPE]: Check for dependent noexcept-specifier. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 891341d1e81..78f7d66f3bb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9462,10 +9462,14 @@ cp_parser_constant_expression (cp_parser* parser, /* Require an rvalue constant expression here; that's what our callers expect. Reference constant expressions are handled separately in e.g. cp_parser_template_argument. */ - bool is_const = potential_rvalue_constant_expression (expression); + tree decay = expression; + if (TREE_TYPE (expression) + && TREE_CODE (TREE_TYPE (expression)) == ARRAY_TYPE) + decay = build_address (expression); + bool is_const = potential_rvalue_constant_expression (decay); parser->non_integral_constant_expression_p = !is_const; if (!is_const && !allow_non_constant_p) - require_potential_rvalue_constant_expression (expression); + require_potential_rvalue_constant_expression (decay); } if (allow_non_constant_p) *non_constant_p = parser->non_integral_constant_expression_p; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 99f5b123a84..d8f8d467200 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6683,13 +6683,46 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) expr, type, decl); return NULL_TREE; } - else if (cxx_dialect >= cxx11 && decl_linkage (decl) == lk_none) + else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx1z) + && decl_linkage (decl) == lk_none) { if (complain & tf_error) error ("%qE is not a valid template argument of type %qT " "because %qD has no linkage", expr, type, decl); return NULL_TREE; } + /* C++17: For a non-type template-parameter of reference or pointer + type, the value of the constant expression shall not refer to (or + for a pointer type, shall not be the address of): + * a subobject (4.5), + * a temporary object (15.2), + * a string literal (5.13.5), + * the result of a typeid expression (8.2.8), or + * a predefined __func__ variable (11.4.1). */ + else if (DECL_ARTIFICIAL (decl)) + { + if (complain & tf_error) + error ("the address of %qD is not a valid template argument", + decl); + return NULL_TREE; + } + else if (!same_type_ignoring_top_level_qualifiers_p + (strip_array_types (TREE_TYPE (type)), + strip_array_types (TREE_TYPE (decl)))) + { + if (complain & tf_error) + error ("the address of the %qT subobject of %qD is not a " + "valid template argument", TREE_TYPE (type), decl); + return NULL_TREE; + } + else if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + { + if (complain & tf_error) + error ("the address of %qD is not a valid template argument " + "because it does not have static storage duration", + decl); + return NULL_TREE; + } } expr = decay_conversion (expr, complain); diff --git a/gcc/testsuite/g++.dg/template/function1.C b/gcc/testsuite/g++.dg/template/function1.C index f2345855ed9..4bab2e4e9bf 100644 --- a/gcc/testsuite/g++.dg/template/function1.C +++ b/gcc/testsuite/g++.dg/template/function1.C @@ -1,10 +1,8 @@ // PR c++/38647 -// { dg-do compile { target { ! c++1z } } } -// { dg-prune-output "note" } template struct A {}; const char func[] = "abc"; -template struct A {}; // { dg-error "cannot appear|is invalid|not a valid|constant expression" } +template struct A {}; // { dg-error "cannot appear|is invalid|not a valid|constant expression" "" { target c++98_only } } char a1[1]; A a; diff --git a/gcc/testsuite/g++.dg/template/nontype-array1.C b/gcc/testsuite/g++.dg/template/nontype-array1.C new file mode 100644 index 00000000000..cf21908481b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/nontype-array1.C @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } + +template +class Message { +}; + +extern char const s1[] = "hi"; +char const s2[] = "hi"; +constexpr char const s3[] = "hi"; // OK since C++11 + +constexpr char const * f() { return s3; } + +int main() +{ + Message m1; // OK (all versions) + Message m2; // OK for clang since C++14, for gcc since C++17 + Message m3; // OK for clang/gcc since C++11 + + static char const s4[] = "hi"; + static constexpr char const s5[] = "hi"; // OK since C++11 + Message m4; // { dg-error "no linkage" "" { target c++14_down } } + Message m5; // { dg-error "no linkage" "" { target c++14_down } } + Message m6; // { dg-error "" "" { target c++14_down } } + + char const s8[] = "hi"; + Message m8; // { dg-error "" } +} -- 2.30.2