Skip to content

Commit 3120ebf

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 #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. (cherry picked from commit f23b5df)
1 parent f65c604 commit 3120ebf

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

gcc/cp/constexpr.cc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,10 +3337,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
33373337
&& TREE_CODE (new_obj) == COMPONENT_REF
33383338
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == UNION_TYPE)
33393339
{
3340+
tree ctor = build_constructor (TREE_TYPE (new_obj), NULL);
3341+
CONSTRUCTOR_NO_CLEARING (ctor) = true;
33403342
tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
3341-
new_obj,
3342-
build_constructor (TREE_TYPE (new_obj),
3343-
NULL));
3343+
new_obj, ctor);
33443344
cxx_eval_constant_expression (ctx, activate,
33453345
lval, non_constant_p, overflow_p);
33463346
ggc_free (activate);
@@ -4731,6 +4731,16 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
47314731
}
47324732

47334733
/* If there's no explicit init for this field, it's value-initialized. */
4734+
4735+
if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
4736+
{
4737+
/* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR
4738+
and copy the flags. */
4739+
constructor_elt *e = get_or_insert_ctor_field (whole, part);
4740+
e->value = value = build_constructor (TREE_TYPE (part), NULL);
4741+
return value;
4742+
}
4743+
47344744
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
47354745
return cxx_eval_constant_expression (ctx, value,
47364746
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)