diff mbox series

[pushed] c++: reference cast, conversion fn [PR113141]

Message ID 20240412193424.2467514-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: reference cast, conversion fn [PR113141] | expand

Commit Message

Jason Merrill April 12, 2024, 7:33 p.m. UTC
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

The second testcase in 113141 is a separate issue: we first decide that the
conversion is ill-formed, but then when recalculating the special c_cast_p
handling makes us think it's OK.  We don't want that, it should continue to
fall back to the reinterpret_cast interpretation.  And while we're here,
let's warn that we're not using the conversion function.

Note that the standard seems to say that in this case we should
treat (Matrix &) as const_cast<Matrix &>(static_cast<const Matrix &>(X)),
which would use the conversion operator, but that doesn't match existing
practice, so let's resolve that another day.  I've raised this issue with
CWG; at the moment I lean toward never binding a temporary in a C-style cast
to reference type, which would also be a change from existing practice.

	PR c++/113141

gcc/c-family/ChangeLog:

	* c.opt: Add -Wcast-user-defined.

gcc/ChangeLog:

	* doc/invoke.texi: Document -Wcast-user-defined.

gcc/cp/ChangeLog:

	* call.cc (reference_binding): For an invalid cast, warn and don't
	recalculate.

gcc/testsuite/ChangeLog:

	* g++.dg/conversion/ref12.C: New test.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
---
 gcc/doc/invoke.texi                     | 13 +++++++++++++
 gcc/c-family/c.opt                      |  4 ++++
 gcc/cp/call.cc                          | 12 +++++++++++-
 gcc/testsuite/g++.dg/conversion/ref12.C | 20 ++++++++++++++++++++
 4 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/conversion/ref12.C


base-commit: 0fd824d717ca901319864a5eeba4e62b278f8329
diff mbox series

Patch

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5d5e70c3033..e3285587e4e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -9391,6 +9391,19 @@  In a cast involving pointer to member types this warning warns whenever
 the type cast is changing the pointer to member type.
 This warning is enabled by @option{-Wextra}.
 
+@opindex Wcast-user-defined
+@opindex Wno-cast-user-defined
+@item -Wcast-user-defined
+Warn when a cast to reference type does not involve a user-defined
+conversion that the programmer might expect to be called.
+
+@smallexample
+struct A @{ operator const int&(); @} a;
+auto r = (int&)a; // warning
+@end smallexample
+
+This warning is enabled by default.
+
 @opindex Wwrite-strings
 @opindex Wno-write-strings
 @item -Wwrite-strings
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 56cccf2a67b..848c2fda203 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -514,6 +514,10 @@  Wcast-qual
 C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
 Warn about casts which discard qualifiers.
 
+Wcast-user-defined
+C++ ObjC++ Var(warn_cast_user_defined) Warning Init(1)
+Warn about a cast to reference type that does not use a related user-defined conversion function.
+
 Wcatch-value
 C++ ObjC++ Warning Alias(Wcatch-value=, 1, 0)
 Warn about catch handlers of non-reference type.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 15b5647298e..dbdd7c29fe8 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -2034,7 +2034,17 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
 	 recalculate the second conversion sequence.  */
       for (conversion *t = conv; t; t = next_conversion (t))
 	if (t->kind == ck_user
-	    && DECL_CONV_FN_P (t->cand->fn))
+	    && c_cast_p && !maybe_valid_p)
+	  {
+	    if (complain & tf_warning)
+	      warning (OPT_Wcast_user_defined,
+		       "casting %qT to %qT does not use %qD",
+		       from, rto, t->cand->fn);
+	    /* Don't let recalculation try to make this valid.  */
+	    break;
+	  }
+	else if (t->kind == ck_user
+		 && DECL_CONV_FN_P (t->cand->fn))
 	  {
 	    tree ftype = TREE_TYPE (TREE_TYPE (t->cand->fn));
 	    /* A prvalue of non-class type is cv-unqualified.  */
diff --git a/gcc/testsuite/g++.dg/conversion/ref12.C b/gcc/testsuite/g++.dg/conversion/ref12.C
new file mode 100644
index 00000000000..27ed9122769
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ref12.C
@@ -0,0 +1,20 @@ 
+// PR c++/113141
+
+struct Matrix { };
+
+struct TPoint3 { private: operator const Matrix(); };
+
+void f(Matrix&);
+
+int main() {
+  TPoint3 X;
+  Matrix& m = (Matrix &)X;	// { dg-warning "does not use" }
+  f((Matrix &)X);		// { dg-warning "does not use" }
+}
+
+struct A { private: operator const int&(); } a;
+int &r = (int&)a;		// { dg-warning "does not use" }
+
+struct B { B(int); };
+int i;
+B &br = (B&)i;			// { dg-warning "does not use" }