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
This commit is contained in:
Jason Merrill 2011-03-02 21:49:19 -05:00 committed by Jason Merrill
parent 20532210cd
commit 262a7d6bc0
6 changed files with 100 additions and 46 deletions

View File

@ -1,3 +1,12 @@
2011-03-02 Jason Merrill <jason@redhat.com>
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 <jason@redhat.com>
PR c++/46159

View File

@ -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);

View File

@ -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:

View File

@ -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)))
if (init == void_type_node)
{
/* No actual initialization to do. */;
init = NULL_TREE;
}
else 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)
{

View File

@ -1,3 +1,7 @@
2011-03-02 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/constexpr-ctor9.C: New.
2011-03-01 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/lambda/lambda-98.C: New.

View File

@ -0,0 +1,19 @@
// PR c++/47774
// { dg-options -std=c++0x }
struct A
{
A() {}
};
template <typename T>
struct array
{
constexpr array() : mem() {}
T mem[7];
};
int main()
{
array<A> ar;
}