c++: be stricter about constinit [CWG2543]
DR 2543 clarifies that constinit variables should follow the language, and diagnose non-constant initializers (according to [expr.const]) even if they can actually initialize the variables statically. DR 2543 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_outermost_constant_expr): Preserve TARGET_EXPR flags. (potential_constant_expression_1): Check TARGET_EXPR_ELIDING_P. * typeck2.cc (store_init_value): Diagnose constinit sooner. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2543.C: New test.
This commit is contained in:
parent
688fdde2f1
commit
8d46516a61
3 changed files with 48 additions and 24 deletions
|
@ -8448,6 +8448,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
|
|||
}
|
||||
}
|
||||
|
||||
if (TREE_CODE (t) == TARGET_EXPR
|
||||
&& TREE_CODE (r) == TARGET_EXPR)
|
||||
{
|
||||
/* Preserve this flag for potential_constant_expression, and the others
|
||||
for good measure. */
|
||||
TARGET_EXPR_ELIDING_P (r) = TARGET_EXPR_ELIDING_P (t);
|
||||
TARGET_EXPR_IMPLICIT_P (r) = TARGET_EXPR_IMPLICIT_P (t);
|
||||
TARGET_EXPR_LIST_INIT_P (r) = TARGET_EXPR_LIST_INIT_P (t);
|
||||
TARGET_EXPR_DIRECT_INIT_P (r) = TARGET_EXPR_DIRECT_INIT_P (t);
|
||||
}
|
||||
|
||||
/* Remember the original location if that wouldn't need a wrapper. */
|
||||
if (location_t loc = EXPR_LOCATION (t))
|
||||
protected_set_expr_location (r, loc);
|
||||
|
@ -9774,6 +9785,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
|
|||
|
||||
case TARGET_EXPR:
|
||||
if (!TARGET_EXPR_DIRECT_INIT_P (t)
|
||||
&& !TARGET_EXPR_ELIDING_P (t)
|
||||
&& !literal_type_p (TREE_TYPE (t)))
|
||||
{
|
||||
if (flags & tf_error)
|
||||
|
|
|
@ -843,23 +843,45 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|
|||
bool const_init;
|
||||
tree oldval = value;
|
||||
if (DECL_DECLARED_CONSTEXPR_P (decl)
|
||||
|| DECL_DECLARED_CONSTINIT_P (decl)
|
||||
|| (DECL_IN_AGGR_P (decl)
|
||||
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
|
||||
{
|
||||
value = fold_non_dependent_expr (value, tf_warning_or_error,
|
||||
/*manifestly_const_eval=*/true,
|
||||
decl);
|
||||
if (value == error_mark_node)
|
||||
;
|
||||
/* Diagnose a non-constant initializer for constexpr variable or
|
||||
non-inline in-class-initialized static data member. */
|
||||
if (!require_constant_expression (value))
|
||||
value = error_mark_node;
|
||||
else if (processing_template_decl)
|
||||
/* In a template we might not have done the necessary
|
||||
transformations to make value actually constant,
|
||||
e.g. extend_ref_init_temps. */
|
||||
value = maybe_constant_init (value, decl, true);
|
||||
else if (!is_constant_expression (value))
|
||||
{
|
||||
/* Maybe we want to give this message for constexpr variables as
|
||||
well, but that will mean a lot of testsuite adjustment. */
|
||||
if (DECL_DECLARED_CONSTINIT_P (decl))
|
||||
error_at (location_of (decl),
|
||||
"%<constinit%> variable %qD does not have a "
|
||||
"constant initializer", decl);
|
||||
require_constant_expression (value);
|
||||
value = error_mark_node;
|
||||
}
|
||||
else
|
||||
value = cxx_constant_init (value, decl);
|
||||
{
|
||||
value = maybe_constant_init (value, decl, true);
|
||||
|
||||
/* In a template we might not have done the necessary
|
||||
transformations to make value actually constant,
|
||||
e.g. extend_ref_init_temps. */
|
||||
if (!processing_template_decl
|
||||
&& !TREE_CONSTANT (value))
|
||||
{
|
||||
if (DECL_DECLARED_CONSTINIT_P (decl))
|
||||
error_at (location_of (decl),
|
||||
"%<constinit%> variable %qD does not have a "
|
||||
"constant initializer", decl);
|
||||
value = cxx_constant_init (value, decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
value = fold_non_dependent_init (value, tf_warning_or_error,
|
||||
|
@ -875,22 +897,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|
|||
if (!TYPE_REF_P (type))
|
||||
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
|
||||
if (!const_init)
|
||||
{
|
||||
/* [dcl.constinit]/2 "If a variable declared with the constinit
|
||||
specifier has dynamic initialization, the program is
|
||||
ill-formed." */
|
||||
if (DECL_DECLARED_CONSTINIT_P (decl))
|
||||
{
|
||||
error_at (location_of (decl),
|
||||
"%<constinit%> variable %qD does not have a constant "
|
||||
"initializer", decl);
|
||||
if (require_constant_expression (value))
|
||||
cxx_constant_init (value, decl);
|
||||
value = error_mark_node;
|
||||
}
|
||||
else
|
||||
value = oldval;
|
||||
}
|
||||
value = oldval;
|
||||
}
|
||||
/* Don't fold initializers of automatic variables in constexpr functions,
|
||||
that might fold away something that needs to be diagnosed at constexpr
|
||||
|
|
5
gcc/testsuite/g++.dg/DRs/dr2543.C
Normal file
5
gcc/testsuite/g++.dg/DRs/dr2543.C
Normal file
|
@ -0,0 +1,5 @@
|
|||
// CWG 2543
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
float f;
|
||||
constinit int * pi = (int*) &f; // { dg-error "constant" } reinterpret_cast, not constant-initialized
|
Loading…
Add table
Reference in a new issue