c++: Mitigate -Wuseless-cast with classes [PR85043]

-Wuseless-cast (not part of -Wall/-Wextra) warns here:

  struct S { };
  void g (S&&);
  void f (S&& arg)
  {
    g (S(arg)); // warning: useless cast to type 'struct S'
  }

which is wrong: the code will not compile without the cast because
"arg" is an lvalue which cannot bind to S&&.

This patch disables the warning when an object that isn't a prvalue
is cast to a non-reference type.  Therefore we still warn about the
useless cast in "X(X{})".

	PR c++/85043

gcc/cp/ChangeLog:

	* typeck.cc (maybe_warn_about_useless_cast): Don't warn when
	a glvalue is cast to a non-reference type.

gcc/ChangeLog:

	* doc/invoke.texi: Update documentation of -Wuseless-cast.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Wuseless-cast.C: Remove dg-warning.
	* g++.dg/warn/Wuseless-cast3.C: New test.
This commit is contained in:
Marek Polacek 2022-10-18 12:20:14 -04:00
parent 79d38dd46e
commit b3c98d6a59
4 changed files with 54 additions and 12 deletions

View file

@ -8104,11 +8104,13 @@ maybe_warn_about_useless_cast (location_t loc, tree type, tree expr,
if (warn_useless_cast
&& complain & tf_warning)
{
if ((TYPE_REF_P (type)
&& (TYPE_REF_IS_RVALUE (type)
? xvalue_p (expr) : lvalue_p (expr))
&& same_type_p (TREE_TYPE (expr), TREE_TYPE (type)))
|| same_type_p (TREE_TYPE (expr), type))
if (TYPE_REF_P (type)
? ((TYPE_REF_IS_RVALUE (type)
? xvalue_p (expr) : lvalue_p (expr))
&& same_type_p (TREE_TYPE (expr), TREE_TYPE (type)))
/* Don't warn when converting a class object to a non-reference type,
because that's a common way to create a temporary. */
: (!glvalue_p (expr) && same_type_p (TREE_TYPE (expr), type)))
warning_at (loc, OPT_Wuseless_cast,
"useless cast to type %q#T", type);
}

View file

@ -4551,7 +4551,18 @@ pointers after reallocation.
@item -Wuseless-cast @r{(C++ and Objective-C++ only)}
@opindex Wuseless-cast
@opindex Wno-useless-cast
Warn when an expression is casted to its own type.
Warn when an expression is cast to its own type. This warning does not
occur when a class object is converted to a non-reference type as that
is a way to create a temporary:
@smallexample
struct S @{ @};
void g (S&&);
void f (S&& arg)
@{
g (S(arg)); // make arg prvalue so that it can bind to S&&
@}
@end smallexample
@item -Wno-conversion-null @r{(C++ and Objective-C++ only)}
@opindex Wconversion-null

View file

@ -62,11 +62,11 @@ A prvalue();
void f()
{
int n;
int n;
(int)(n); // { dg-warning "3:useless cast" }
static_cast<int>(n); // { dg-warning "3:useless cast" }
reinterpret_cast<int>(n); // { dg-warning "3:useless cast" }
(int)(n);
static_cast<int>(n);
reinterpret_cast<int>(n);
(int*)(&n); // { dg-warning "3:useless cast" }
const_cast<int*>(&n); // { dg-warning "3:useless cast" }
@ -100,8 +100,8 @@ void f()
A a;
(A)(a); // { dg-warning "3:useless cast" }
static_cast<A>(a); // { dg-warning "3:useless cast" }
(A)(a);
static_cast<A>(a);
(A*)(&a); // { dg-warning "3:useless cast" }
const_cast<A*>(&a); // { dg-warning "3:useless cast" }

View file

@ -0,0 +1,29 @@
// PR c++/85043
// { dg-do compile { target c++11 } }
// { dg-options "-Wuseless-cast" }
struct S { int s; void bump () { s++; } };
void
foo ()
{
S s = { 1 };
s.bump ();
S (s).bump (); // { dg-bogus "useless" }
((S) s).bump (); // { dg-bogus "useless" }
static_cast<S> (s).bump (); // { dg-bogus "useless" }
}
struct X { };
void g(X&&);
void
f (X&& arg)
{
g(X(arg)); // { dg-bogus "useless" }
g(X(X{})); // { dg-warning "useless" }
g(static_cast<X&&>(arg));
int i = (int) 1; // { dg-warning "useless" }
const int &r = (int) i; // { dg-bogus "useless" }
}