Skip to content

Commit 6f0c684

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. (cherry picked from commit f23b5df)
1 parent 2fb7db8 commit 6f0c684

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
@@ -3363,10 +3363,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
33633363
&& TREE_CODE (new_obj) == COMPONENT_REF
33643364
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == UNION_TYPE)
33653365
{
3366+
tree ctor = build_constructor (TREE_TYPE (new_obj), NULL);
3367+
CONSTRUCTOR_NO_CLEARING (ctor) = true;
33663368
tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
3367-
new_obj,
3368-
build_constructor (TREE_TYPE (new_obj),
3369-
NULL));
3369+
new_obj, ctor);
33703370
cxx_eval_constant_expression (ctx, activate,
33713371
lval, non_constant_p, overflow_p);
33723372
ggc_free (activate);
@@ -4876,6 +4876,18 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
48764876
}
48774877

48784878
/* If there's no explicit init for this field, it's value-initialized. */
4879+
4880+
if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
4881+
{
4882+
/* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR
4883+
and copy the flags. */
4884+
constructor_elt *e = get_or_insert_ctor_field (whole, part);
4885+
e->value = value = build_constructor (TREE_TYPE (part), NULL);
4886+
CONSTRUCTOR_ZERO_PADDING_BITS (value)
4887+
= CONSTRUCTOR_ZERO_PADDING_BITS (whole);
4888+
return value;
4889+
}
4890+
48794891
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
48804892
return cxx_eval_constant_expression (ctx, value,
48814893
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)