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)
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
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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);
+}