From 61b6999daba57e7417369a9dee1610d7c20e1967 Mon Sep 17 00:00:00 2001
From: Ed Catmur <ed@catmur.uk>
Date: Sun, 19 Dec 2021 23:59:50 +0000
Subject: [PATCH 2/3] Add const qualification to static_cast stage of C-style
 cast

when reference binding to temporary

https://stackoverflow.com/q/66816741/567292
---
 gcc/cp/call.c                                  | 17 ++++++++++++++++-
 gcc/testsuite/g++.dg/conversion/explicit1.C    | 13 +++++++++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-union.C   |  4 +++-
 gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C |  3 ++-
 gcc/testsuite/g++.old-deja/g++.jason/rvalue3.C |  3 ++-
 5 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/explicit1.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f7aad03d4d0..de3c43d75c7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1967,13 +1967,28 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   conv->need_temporary_p = true;
   conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
 
+  if (c_cast_p && (complain & tf_warning)
+    && warning (OPT_Wconversion, "reference binding temporary for C-style "
+		"cast"))
+      inform (input_location, " use %<reinterpret_cast%> for type-punning");
+
   /* [dcl.init.ref]
 
      Otherwise, the reference shall be an lvalue reference to a
      non-volatile const type, or the reference shall be an rvalue
      reference.  */
   if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
-    conv->bad_p = true;
+    {
+      /* If this is a C-style cast, we can cast away const later.  */
+      if (c_cast_p)
+	{
+	  int cflags = (cp_type_quals (to)|TYPE_QUAL_CONST)&~TYPE_QUAL_VOLATILE;
+	  to = cp_build_qualified_type (to, cflags);
+	  conv->type = cp_build_reference_type (to, false);
+	}
+      else
+	conv->bad_p = true;
+    }
 
   /* [dcl.init.ref]
 
diff --git a/gcc/testsuite/g++.dg/conversion/explicit1.C b/gcc/testsuite/g++.dg/conversion/explicit1.C
new file mode 100644
index 00000000000..b93d9419696
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/explicit1.C
@@ -0,0 +1,13 @@
+// { dg-do run }
+// { dg-options "-Wconversion" }
+// Similarly, we should be able to simultaneously reference bind to a temporary
+// and cast away const in a single C-style cast.
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+int main() {
+  float f = 5.99f;
+  int i = (int&) f; // { dg-warning "reference binding temporary" }
+  // { dg-message "reinterpret_cast" "" { target *-*-* } .-1 }
+  assert(i == 5);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C
index 0c3548c0ac4..6bed16e3da5 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C
@@ -13,4 +13,6 @@ constexpr float f = u.f;
 constexpr unsigned char c = u.ca[0]; // { dg-error "U::ca" }
 
 constexpr double d = 1.0;
-constexpr unsigned char c2 = (unsigned char&)d; // { dg-error "char. glvalue" }
+constexpr unsigned char c2 = reinterpret_cast<unsigned char const&>(d); // { dg-error "char. glvalue" }
+constexpr unsigned char c3 = (unsigned char const&)d; // OK, same as:
+constexpr unsigned char c4 = static_cast<unsigned char const&>(d);
diff --git a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
index 84c493c435f..caa489e3509 100644
--- a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
+++ b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
@@ -6,6 +6,7 @@ typedef unsigned uint32_t __attribute__((mode (__SI__)));
 float foo ()
 {
   uint32_t MASK = 0x80000000;
-  return (float &) MASK; /* { dg-warning "strict-aliasing" } */
+  float f1 = (float &)MASK; // OK, same as const_cast<float &>(static_cast<float const &>(MASK))
+  return reinterpret_cast<float &>(MASK); /* { dg-warning "strict-aliasing" } */
 }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/rvalue3.C b/gcc/testsuite/g++.old-deja/g++.jason/rvalue3.C
index 77969bc60ee..367ac7d8909 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/rvalue3.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/rvalue3.C
@@ -2,5 +2,6 @@
 int main ()
 {
    int i;
-   int &ir = (int&)(int)i;	// { dg-error "14:invalid cast of a prvalue expression" } casting rvalue to reference type
+   int &ir = reinterpret_cast<int&>((int)i); // { dg-error "14:invalid cast of a prvalue expression" } casting rvalue to reference type
+   int &ir2 = (int&)(int)i; // OK, const_cast<int&>(static_cast<int const&>(...))
 }
-- 
2.30.2

