]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: allow stores to anon union vars to change current union member in constexpr...
authorJakub Jelinek <jakub@redhat.com>
Wed, 11 Dec 2024 16:28:47 +0000 (17:28 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 11 Dec 2024 16:28:47 +0000 (17:28 +0100)
Since r14-4771 the FE tries to differentiate between cases where the lhs
of a store allows changing the current union member and cases where it
doesn't, and cases where it doesn't includes everything that has gone
through the cxx_eval_constant_expression path on the lhs.
As the testcase shows, DECL_ANON_UNION_VAR_P vars were handled like that
too, even when stores to them are the only way how to change the current
union member in the sources.

So, the following patch just handles that case manually without calling
cxx_eval_constant_expression and without setting evaluated to true.

2024-12-11  Jakub Jelinek  <jakub@redhat.com>

PR c++/117614
* constexpr.cc (cxx_eval_store_expression): For stores to
DECL_ANON_UNION_VAR_P vars just continue with DECL_VALUE_EXPR
of it, without setting evaluated to true or full
cxx_eval_constant_expression.

* g++.dg/cpp2a/constexpr-union8.C: New test.

gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/cpp2a/constexpr-union8.C [new file with mode: 0644]

index 08765c9caa6134823733c45115f95f17bfe7a996..c16597dfaecea1aee5f74b0de33dbce133b6f05d 100644 (file)
@@ -6418,6 +6418,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
            object = probe;
          else
            {
+             tree pvar = tree_strip_any_location_wrapper (probe);
+             if (VAR_P (pvar) && DECL_ANON_UNION_VAR_P (pvar))
+               {
+                 /* Stores to DECL_ANON_UNION_VAR_P var are allowed to change
+                    active union member.  */
+                 probe = DECL_VALUE_EXPR (pvar);
+                 break;
+               }
              probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue,
                                                    non_constant_p, overflow_p);
              evaluated = true;
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-union8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-union8.C
new file mode 100644 (file)
index 0000000..1e51857
--- /dev/null
@@ -0,0 +1,31 @@
+// PR c++/117614
+// { dg-do compile { target c++20 } }
+
+constexpr int
+foo ()
+{
+  union {
+    int x{0};
+    char y;
+  };
+  y = 1;
+  return y;
+}
+
+constexpr int
+bar ()
+{
+  union {
+    union {
+      int x{0};
+      char y;
+    };
+    long long z;
+  };
+  y = 1;
+  z = 2;
+  return z;
+}
+
+static_assert (foo () == 1);
+static_assert (bar () == 2);