mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
c++: constexpr union placement new [PR121068]
The note and example in [class.union] p6 think that placement new can be used to change the active member of a union, but we didn't support that for array members in constant-evaluation even after implementing P1330 and P2747. First I tried to address this by introducing a CLOBBER_BEGIN_OBJECT for the entire array, but that broke the resolution of LWG3436, which invokes 'new T[1]' for an array T, and trying to clobber a multidimensional array when the actual object is single-dimensional breaks. So I've raised that issue with the committee. Until that is resolved, this patch takes a simpler approach: allow initialization of an element of an array to make the array the active member of a union. PR c++/121068 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs when activating an array member of a union. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-union6.C: Expect x5 to work. * g++.dg/cpp26/constexpr-new4.C: New test.
This commit is contained in:
@@ -7736,13 +7736,24 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
|
||||
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (*valp), first, NULL_TREE);
|
||||
|
||||
/* Check for implicit change of active member for a union. */
|
||||
|
||||
/* LWG3436, CWG2675, c++/121068: The array object model is confused. For
|
||||
now allow initializing an array element to activate the array. */
|
||||
auto only_array_refs = [](const releasing_vec &refs)
|
||||
{
|
||||
for (unsigned i = 1; i < refs->length(); i += 3)
|
||||
if (TREE_CODE ((*refs)[i]) != INTEGER_CST)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (code == UNION_TYPE
|
||||
&& (CONSTRUCTOR_NELTS (*valp) == 0
|
||||
|| CONSTRUCTOR_ELT (*valp, 0)->index != index)
|
||||
/* An INIT_EXPR of the last member in an access chain is always OK,
|
||||
but still check implicit change of members earlier on; see
|
||||
cpp2a/constexpr-union6.C. */
|
||||
&& !(TREE_CODE (t) == INIT_EXPR && refs->is_empty ()))
|
||||
&& !(TREE_CODE (t) == INIT_EXPR && only_array_refs (refs)))
|
||||
{
|
||||
bool has_active_member = CONSTRUCTOR_NELTS (*valp) != 0;
|
||||
tree inner = strip_array_types (reftype);
|
||||
|
||||
21
gcc/testsuite/g++.dg/cpp26/constexpr-new4.C
Normal file
21
gcc/testsuite/g++.dg/cpp26/constexpr-new4.C
Normal file
@@ -0,0 +1,21 @@
|
||||
// PR c++/121068
|
||||
// { dg-do compile { target c++26 } }
|
||||
|
||||
constexpr void *operator new (__SIZE_TYPE__, void *p) { return p; }
|
||||
constexpr void *operator new[] (__SIZE_TYPE__, void *p) { return p; }
|
||||
|
||||
consteval int
|
||||
foo()
|
||||
{
|
||||
using T = int;
|
||||
union { T arr[3]; };
|
||||
new(arr) T[3]; // makes arr active
|
||||
for (int i = 0; i < 3; ++i)
|
||||
arr[i].~T();
|
||||
|
||||
new (arr + 2) T{10}; // A
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
constexpr int g = foo();
|
||||
@@ -45,9 +45,9 @@ constexpr int test5() {
|
||||
union {
|
||||
int data[1];
|
||||
} u;
|
||||
std::construct_at(u.data, 0); // { dg-message "in .constexpr. expansion" }
|
||||
std::construct_at(u.data, 0); // { dg-bogus "in .constexpr. expansion" }
|
||||
return 0;
|
||||
}
|
||||
constexpr int x5 = test5(); // { dg-message "in .constexpr. expansion" }
|
||||
constexpr int x5 = test5(); // { dg-bogus "in .constexpr. expansion" }
|
||||
|
||||
// { dg-error "accessing (uninitialized member|.* member instead of)" "" { target *-*-* } 0 }
|
||||
|
||||
Reference in New Issue
Block a user