aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-05-20 16:16:25 -0400
committerJason Merrill <jason@redhat.com>2022-05-24 15:49:27 -0400
commit2540e2c604142889308857657d3510874955336a (patch)
tree789bb80c29cf6b4eb7eec0ccd86c2eb840f945b9
parentae8decf1d2b8329af59592b4fa78ee8dfab3ba5e (diff)
downloadgcc-2540e2c604142889308857657d3510874955336a.zip
gcc-2540e2c604142889308857657d3510874955336a.tar.gz
gcc-2540e2c604142889308857657d3510874955336a.tar.bz2
c++: constexpr empty base redux [PR105622]
Here calling the constructor for s.__size_ had ctx->ctor for s itself because cxx_eval_store_expression doesn't create a ctor for the empty field. Then cxx_eval_call_expression returned the s initializer, and my empty base overhaul in r13-160 got confused because the type of init is not an empty class. But that's OK, we should be checking the type of the original LHS instead. We also want to use initialized_type in the condition, in case init is an AGGR_INIT_EXPR. I spent quite a while working on more complex solutions before coming back to this simple one. PR c++/105622 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_store_expression): Adjust assert. Use initialized_type. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/no_unique_address14.C: New test.
-rw-r--r--gcc/cp/constexpr.cc4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C19
2 files changed, 21 insertions, 2 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 433fa76..0f1a439 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5916,15 +5916,15 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (*valp), type)));
if (empty_base || !(same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (init), type)))
+ (initialized_type (init), type)))
{
/* For initialization of an empty base, the original target will be
*(base*)this, evaluation of which resolves to the object
argument, which has the derived type rather than the base type. In
this situation, just evaluate the initializer and return, since
there's no actual data to store, and we didn't build a CONSTRUCTOR. */
+ gcc_assert (is_empty_class (TREE_TYPE (target)));
empty_base = true;
- gcc_assert (is_empty_class (TREE_TYPE (init)));
if (!*valp)
{
/* But do make sure we have something in *valp. */
diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C
new file mode 100644
index 0000000..d3fcd4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C
@@ -0,0 +1,19 @@
+// PR c++/105622
+// { dg-do compile { target c++20 } }
+
+struct empty {
+ empty() = default;
+ constexpr empty(int) { }
+};
+
+struct container {
+ empty __begin_ = {};
+ [[no_unique_address]] empty __size_ = 0;
+};
+
+constexpr bool test() {
+ container s;
+ return true;
+}
+static_assert(test());
+