Skip to content

Commit f23b5df

Browse files
committed
c++: constexpr uninitialized union [PR120577]
This was failing for two reasons: 1) We were wrongly treating the basic_string constructor as zero-initializing the object, which it doesn't. 2) Given that, when we went to look for a value for the anonymous union, we concluded that it was value-initialized, and trying to evaluate that broke because we weren't setting ctx->ctor for it. This patch fixes both issues, #1 by setting CONSTRUCTOR_NO_CLEARING and gcc-mirror#2 by inserting a new CONSTRUCTOR for the member rather than evaluate it out of context, which is consistent with cxx_eval_store_expression. PR c++/120577 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_call_expression): Set CONSTRUCTOR_NO_CLEARING on initial value for ctor. (cxx_eval_component_reference): Make value-initialization of an aggregate member explicit. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-union9.C: New test.
1 parent 9956dc3 commit f23b5df

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

gcc/cp/constexpr.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,10 +4201,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
42014201
&& TREE_CODE (new_obj) == COMPONENT_REF
42024202
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == UNION_TYPE)
42034203
{
4204+
tree ctor = build_constructor (TREE_TYPE (new_obj), NULL);
4205+
CONSTRUCTOR_NO_CLEARING (ctor) = true;
42044206
tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
4205-
new_obj,
4206-
build_constructor (TREE_TYPE (new_obj),
4207-
NULL));
4207+
new_obj, ctor);
42084208
cxx_eval_constant_expression (ctx, activate,
42094209
lval, non_constant_p, overflow_p,
42104210
jump_target);
@@ -5793,6 +5793,18 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
57935793
}
57945794

57955795
/* If there's no explicit init for this field, it's value-initialized. */
5796+
5797+
if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
5798+
{
5799+
/* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR
5800+
and copy the flags. */
5801+
constructor_elt *e = get_or_insert_ctor_field (whole, part);
5802+
e->value = value = build_constructor (TREE_TYPE (part), NULL);
5803+
CONSTRUCTOR_ZERO_PADDING_BITS (value)
5804+
= CONSTRUCTOR_ZERO_PADDING_BITS (whole);
5805+
return value;
5806+
}
5807+
57965808
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
57975809
return cxx_eval_constant_expression (ctx, value,
57985810
lval,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// PR c++/120577
2+
// { dg-do compile { target c++20 } }
3+
4+
template <class _Tp> struct optional {
5+
union {
6+
_Tp __val_;
7+
};
8+
template <class... _Args>
9+
constexpr optional(_Args... __args)
10+
: __val_(__args...) {}
11+
};
12+
template <class _Tp, class... _Args>
13+
constexpr optional<_Tp> make_optional(_Args... __args) {
14+
return optional<_Tp>(__args...);
15+
}
16+
17+
struct __non_trivial_if {
18+
constexpr __non_trivial_if() {}
19+
};
20+
struct allocator : __non_trivial_if {};
21+
struct __padding {};
22+
struct __short {
23+
[[__no_unique_address__]] __padding __padding_;
24+
int __data_;
25+
};
26+
struct basic_string {
27+
union {
28+
__short __s;
29+
};
30+
[[__no_unique_address__]] allocator __alloc_;
31+
constexpr basic_string(int, int) {}
32+
};
33+
auto opt = make_optional<basic_string>(4, 'X');

0 commit comments

Comments
 (0)