]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: ICE with reinterpret_cast and switch [PR113545]
authorMarek Polacek <polacek@redhat.com>
Fri, 16 Feb 2024 17:25:26 +0000 (12:25 -0500)
committerMarek Polacek <polacek@redhat.com>
Fri, 16 Feb 2024 17:25:26 +0000 (12:25 -0500)
Jason, this is the patch you proposed for PR113545.  It looks very safe
so I'm posting it here so that it's not forgotten.

PR c++/113545

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_switch_expr): If the condition doesn't reduce
to an INTEGER_CST, consider it non-constant.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1y/constexpr-reinterpret3.C: New test.
* g++.dg/cpp1y/constexpr-reinterpret4.C: New test.

(cherry picked from commit 39d989022dd0eacf1a7b95b7b20621acbe717d70)

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

index ab129c087555a4d61e9b3a96b8de5c98133cc115..a3c21e88e7bae83f692e6b85873b45408fef88df 100644 (file)
@@ -6722,6 +6722,16 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
   cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue,
                                       non_constant_p, overflow_p);
   VERIFY_CONSTANT (cond);
+  if (TREE_CODE (cond) != INTEGER_CST)
+    {
+      /* If the condition doesn't reduce to an INTEGER_CST it isn't a usable
+        switch condition even if it's constant enough for other things
+        (c++/113545).  */
+      gcc_checking_assert (ctx->quiet);
+      *non_constant_p = true;
+      return t;
+    }
+
   *jump_target = cond;
 
   tree body
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-reinterpret3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-reinterpret3.C
new file mode 100644 (file)
index 0000000..adc0b41
--- /dev/null
@@ -0,0 +1,54 @@
+// PR c++/113545
+// { dg-do run { target c++14 } }
+
+char foo;
+
+// This one caught a call to gcc_unreachable in
+// cp/constexpr.cc:label_matches, when passed a convert_expr from the
+// cast in the call.
+constexpr unsigned char swbar(__UINTPTR_TYPE__ baz)
+{
+  switch (baz)
+    {
+    case 13:
+      return 11;
+    case 14:
+      return 78;
+    case 2048:
+      return 13;
+    default:
+      return 42;
+    }
+}
+
+// For reference, the equivalent* if-statements.
+constexpr unsigned char ifbar(__UINTPTR_TYPE__ baz)
+{
+  if (baz == 13)
+    return 11;
+  else if (baz == 14)
+    return 78;
+  else if (baz == 2048)
+    return 13;
+  else
+    return 42;
+}
+
+__attribute__ ((__noipa__))
+void xyzzy(int x)
+{
+  if (x != 42)
+    __builtin_abort ();
+}
+
+int main()
+{
+  unsigned const char c = swbar(reinterpret_cast<__UINTPTR_TYPE__>(&foo));
+  xyzzy(c);
+  unsigned const char d = ifbar(reinterpret_cast<__UINTPTR_TYPE__>(&foo));
+  xyzzy(d);
+  unsigned const char e = swbar((__UINTPTR_TYPE__) &foo);
+  xyzzy(e);
+  unsigned const char f = ifbar((__UINTPTR_TYPE__) &foo);
+  xyzzy(f);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-reinterpret4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-reinterpret4.C
new file mode 100644 (file)
index 0000000..9aaa6e4
--- /dev/null
@@ -0,0 +1,54 @@
+// PR c++/113545
+// { dg-do compile { target c++14 } }
+
+char foo;
+
+// This one caught a call to gcc_unreachable in
+// cp/constexpr.cc:label_matches, when passed a convert_expr from the
+// cast in the call.
+constexpr unsigned char swbar(__UINTPTR_TYPE__ baz)
+{
+  switch (baz)
+    {
+    case 13:
+      return 11;
+    case 14:
+      return 78;
+    case 2048:
+      return 13;
+    default:
+      return 42;
+    }
+}
+
+// For reference, the equivalent* if-statements.
+constexpr unsigned char ifbar(__UINTPTR_TYPE__ baz)
+{
+  if (baz == 13)
+    return 11;
+  else if (baz == 14)
+    return 78;
+  else if (baz == 2048)
+    return 13;
+  else
+    return 42;
+}
+
+__attribute__ ((__noipa__))
+void xyzzy(int x)
+{
+  if (x != 42)
+    __builtin_abort ();
+}
+
+int main()
+{
+  unsigned constexpr char c = swbar(reinterpret_cast<__UINTPTR_TYPE__>(&foo)); // { dg-error "conversion from pointer type" }
+  xyzzy(c);
+  unsigned constexpr char d = ifbar(reinterpret_cast<__UINTPTR_TYPE__>(&foo)); // { dg-error "conversion from pointer type" }
+  xyzzy(d);
+  unsigned constexpr char e = swbar((__UINTPTR_TYPE__) &foo); // { dg-error "conversion from pointer type" }
+  xyzzy(e);
+  unsigned constexpr char f = ifbar((__UINTPTR_TYPE__) &foo); // { dg-error "conversion from pointer type" }
+  xyzzy(f);
+}