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 <ppa...@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 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" } base-commit: 0fd824d717ca901319864a5eeba4e62b278f8329 -- 2.44.0