From 262a7d6bc0820d7aed46a05b2b8b6ef7824bb08f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 2 Mar 2011 21:49:19 -0500 Subject: [PATCH] re PR c++/47774 ([C++0x] constexpr specifier on ctor not ignored when template instantiation causes ctor to not satify constexpr requirements) PR c++/47774 * tree.c (build_vec_init_elt): Split out from... (build_vec_init_expr): ...here. (diagnose_non_constexpr_vec_init): New fn. * semantics.c (potential_constant_expression_1): Use it. * cp-tree.h: Declare it. From-SVN: r170638 --- gcc/cp/ChangeLog | 9 ++ gcc/cp/cp-tree.h | 1 + gcc/cp/semantics.c | 5 +- gcc/cp/tree.c | 108 +++++++++++-------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/cpp0x/constexpr-ctor9.C | 19 ++++ 6 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a080431ff87..b9ad026d3c2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2011-03-02 Jason Merrill + + PR c++/47774 + * tree.c (build_vec_init_elt): Split out from... + (build_vec_init_expr): ...here. + (diagnose_non_constexpr_vec_init): New fn. + * semantics.c (potential_constant_expression_1): Use it. + * cp-tree.h: Declare it. + 2011-03-01 Jason Merrill PR c++/46159 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d5a6d5c0763..4b49046105f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5400,6 +5400,7 @@ extern tree build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); extern tree build_array_copy (tree); extern tree build_vec_init_expr (tree, tree); +extern void diagnose_non_constexpr_vec_init (tree); extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); extern tree build_qualified_name (tree, tree, tree, bool); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6b3e9149a80..52a962dce09 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7722,7 +7722,10 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) if (VEC_INIT_EXPR_IS_CONSTEXPR (t)) return true; if (flags & tf_error) - error ("non-constant array initialization"); + { + error ("non-constant array initialization"); + diagnose_non_constexpr_vec_init (t); + } return false; default: diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index ed4f67bbb0f..56639ffe836 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -456,6 +456,47 @@ build_cplus_new (tree type, tree init) return rval; } +/* Subroutine of build_vec_init_expr: Build up a single element + intialization as a proxy for the full array initialization to get things + marked as used and any appropriate diagnostics. + + Since we're deferring building the actual constructor calls until + gimplification time, we need to build one now and throw it away so + that the relevant constructor gets mark_used before cgraph decides + what functions are needed. Here we assume that init is either + NULL_TREE, void_type_node (indicating value-initialization), or + another array to copy. */ + +static tree +build_vec_init_elt (tree type, tree init) +{ + tree inner_type = strip_array_types (type); + VEC(tree,gc) *argvec; + + if (integer_zerop (array_type_nelts_total (type)) + || !CLASS_TYPE_P (inner_type)) + /* No interesting initialization to do. */ + return integer_zero_node; + else if (init == void_type_node) + return build_value_init (inner_type, tf_warning_or_error); + + gcc_assert (init == NULL_TREE + || (same_type_ignoring_top_level_qualifiers_p + (type, TREE_TYPE (init)))); + + argvec = make_tree_vector (); + if (init) + { + tree dummy = build_dummy_object (inner_type); + if (!real_lvalue_p (init)) + dummy = move (dummy); + VEC_quick_push (tree, argvec, dummy); + } + return build_special_member_call (NULL_TREE, complete_ctor_identifier, + &argvec, inner_type, LOOKUP_NORMAL, + tf_warning_or_error); +} + /* Return a TARGET_EXPR which expresses the initialization of an array to be named later, either default-initialization or copy-initialization from another array of the same type. */ @@ -464,62 +505,22 @@ tree build_vec_init_expr (tree type, tree init) { tree slot; - tree inner_type = strip_array_types (type); - tree elt_init = integer_zero_node; bool value_init = false; + tree elt_init = build_vec_init_elt (type, init); - /* Since we're deferring building the actual constructor calls until - gimplification time, we need to build one now and throw it away so - that the relevant constructor gets mark_used before cgraph decides - what functions are needed. Here we assume that init is either - NULL_TREE, void_type_node (indicating value-initialization), or - another array to copy. */ - if (integer_zerop (array_type_nelts_total (type))) - { - /* No actual initialization to do. */; - init = NULL_TREE; - } - else if (init == void_type_node) + if (init == void_type_node) { - elt_init = build_value_init (inner_type, tf_warning_or_error); value_init = true; init = NULL_TREE; } - else - { - gcc_assert (init == NULL_TREE - || (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (init)))); - - if (CLASS_TYPE_P (inner_type)) - { - VEC(tree,gc) *argvec = make_tree_vector (); - if (init) - { - tree dummy = build_dummy_object (inner_type); - if (!real_lvalue_p (init)) - dummy = move (dummy); - VEC_quick_push (tree, argvec, dummy); - } - elt_init - = build_special_member_call (NULL_TREE, complete_ctor_identifier, - &argvec, inner_type, LOOKUP_NORMAL, - tf_warning_or_error); - } - } slot = build_local_temp (type); init = build2 (VEC_INIT_EXPR, type, slot, init); SET_EXPR_LOCATION (init, input_location); - if (current_function_decl - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) - { - if (potential_constant_expression (elt_init)) - VEC_INIT_EXPR_IS_CONSTEXPR (init) = true; - else if (!processing_template_decl) - require_potential_constant_expression (elt_init); - } + if (cxx_dialect >= cxx0x + && potential_constant_expression (elt_init)) + VEC_INIT_EXPR_IS_CONSTEXPR (init) = true; VEC_INIT_EXPR_VALUE_INIT (init) = value_init; init = build_target_expr (slot, init); @@ -528,6 +529,23 @@ build_vec_init_expr (tree type, tree init) return init; } +/* Give a helpful diagnostic for a non-constexpr VEC_INIT_EXPR in a context + that requires a constant expression. */ + +void +diagnose_non_constexpr_vec_init (tree expr) +{ + tree type = TREE_TYPE (VEC_INIT_EXPR_SLOT (expr)); + tree init, elt_init; + if (VEC_INIT_EXPR_VALUE_INIT (expr)) + init = void_zero_node; + else + init = VEC_INIT_EXPR_INIT (expr); + + elt_init = build_vec_init_elt (type, init); + require_potential_constant_expression (elt_init); +} + tree build_array_copy (tree init) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c4f8ceeacfb..328ed9e468e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-03-02 Jason Merrill + + * g++.dg/cpp0x/constexpr-ctor9.C: New. + 2011-03-01 Jason Merrill * g++.dg/cpp0x/lambda/lambda-98.C: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor9.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor9.C new file mode 100644 index 00000000000..b7693f1e637 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor9.C @@ -0,0 +1,19 @@ +// PR c++/47774 +// { dg-options -std=c++0x } + +struct A +{ + A() {} +}; + +template +struct array +{ + constexpr array() : mem() {} + T mem[7]; +}; + +int main() +{ + array ar; +} -- 2.34.1