On Fri, May 24, 2024 at 10:15:56AM -0400, Jason Merrill wrote:
> On 5/23/24 19:57, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> >
> > -- >8 --
> > We already warn for:
> >
> > x = std::move (x);
> >
> > which triggers:
> >
> > warning: moving 'x' of type 'int' to itself [-Wself-move]
> >
> > but bug 109396 reports that this doesn't work for a member-initializer-list:
> >
> > X() : x(std::move (x))
> >
> > so this patch amends that.
> >
> > PR c++/109396
> >
> > gcc/cp/ChangeLog:
> >
> > * cp-tree.h (maybe_warn_self_move): Declare.
> > * init.cc (perform_member_init): Call maybe_warn_self_move.
> > * typeck.cc (maybe_warn_self_move): No longer static. Change the
> > return type to bool. Also warn when called from
> > a member-initializer-list.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/warn/Wself-move2.C: New test.
> > ---
> > gcc/cp/cp-tree.h | 1 +
> > gcc/cp/init.cc | 5 ++--
> > gcc/cp/typeck.cc | 28 +++++++++++++------
> > gcc/testsuite/g++.dg/warn/Wself-move2.C | 37 +++++++++++++++++++++++++
> > 4 files changed, 60 insertions(+), 11 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/warn/Wself-move2.C
> >
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index ba9e848c177..ea3fa6f4aac 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -8263,6 +8263,7 @@ extern cp_expr build_c_cast
> > (location_t loc, tree type,
> > cp_expr expr);
> > extern tree cp_build_c_cast (location_t, tree, tree,
> > tsubst_flags_t);
> > +extern bool maybe_warn_self_move (location_t, tree, tree);
> > extern cp_expr build_x_modify_expr (location_t, tree,
> > enum tree_code, tree,
> > tree, tsubst_flags_t);
> > diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> > index 52396d87a8c..4a7ed7f5302 100644
> > --- a/gcc/cp/init.cc
> > +++ b/gcc/cp/init.cc
> > @@ -999,7 +999,7 @@ perform_member_init (tree member, tree init,
> > hash_set<tree> &uninitialized)
> > if (decl == error_mark_node)
> > return;
> > - if ((warn_init_self || warn_uninitialized)
> > + if ((warn_init_self || warn_uninitialized || warn_self_move)
> > && init
> > && TREE_CODE (init) == TREE_LIST
> > && TREE_CHAIN (init) == NULL_TREE)
> > @@ -1013,7 +1013,8 @@ perform_member_init (tree member, tree init,
> > hash_set<tree> &uninitialized)
> > warning_at (DECL_SOURCE_LOCATION (current_function_decl),
> > OPT_Winit_self, "%qD is initialized with itself",
> > member);
> > - else
> > + else if (!maybe_warn_self_move (input_location, member,
> > + TREE_VALUE (init)))
> > find_uninit_fields (&val, &uninitialized, decl);
> > }
> > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> > index d7fa6e0dd96..e058ce18276 100644
> > --- a/gcc/cp/typeck.cc
> > +++ b/gcc/cp/typeck.cc
> > @@ -9355,27 +9355,27 @@ cp_build_c_cast (location_t loc, tree type, tree
> > expr,
> > /* Warn when a value is moved to itself with std::move. LHS is the
> > target,
> > RHS may be the std::move call, and LOC is the location of the whole
> > - assignment. */
> > + assignment. Return true if we warned. */
> > -static void
> > +bool
> > maybe_warn_self_move (location_t loc, tree lhs, tree rhs)
> > {
> > if (!warn_self_move)
> > - return;
> > + return false;
> > /* C++98 doesn't know move. */
> > if (cxx_dialect < cxx11)
> > - return;
> > + return false;
> > if (processing_template_decl)
> > - return;
> > + return false;
> > if (!REFERENCE_REF_P (rhs)
> > || TREE_CODE (TREE_OPERAND (rhs, 0)) != CALL_EXPR)
> > - return;
> > + return false;
> > tree fn = TREE_OPERAND (rhs, 0);
> > if (!is_std_move_p (fn))
> > - return;
> > + return false;
> > /* Just a little helper to strip * and various NOPs. */
> > auto extract_op = [] (tree &op) {
> > @@ -9393,13 +9393,23 @@ maybe_warn_self_move (location_t loc, tree lhs,
> > tree rhs)
> > tree type = TREE_TYPE (lhs);
> > tree orig_lhs = lhs;
> > extract_op (lhs);
> > - if (cp_tree_equal (lhs, arg))
> > + if (cp_tree_equal (lhs, arg)
> > + /* Also warn in a member-initializer-list, as in : i(std::move(i)).
> > */
> > + || (TREE_CODE (lhs) == FIELD_DECL
> > + && TREE_CODE (arg) == COMPONENT_REF
> > + && cp_tree_equal (TREE_OPERAND (arg, 0), current_class_ref)
> > + && TREE_OPERAND (arg, 1) == lhs))
> > {
> > auto_diagnostic_group d;
> > if (warning_at (loc, OPT_Wself_move,
> > "moving %qE of type %qT to itself", orig_lhs, type))
> > - inform (loc, "remove %<std::move%> call");
> > + {
> > + inform (loc, "remove %<std::move%> call");
>
> The patch is OK, but why do we suggest removing std::move? That just
> changes the warning to self-init. Maybe drop the inform?
Thanks. Yes, I don't know why I added the inform in the first place;
there's no point in suggesting changing
x = std::move(x);
into
x = x;
I dropped the inform and pushed the following:
-- >8 --
We already warn for:
x = std::move (x);
which triggers:
warning: moving 'x' of type 'int' to itself [-Wself-move]
but bug 109396 reports that this doesn't work for a member-initializer-list:
X() : x(std::move (x))
so this patch amends that.
PR c++/109396
gcc/cp/ChangeLog:
* cp-tree.h (maybe_warn_self_move): Declare.
* init.cc (perform_member_init): Call maybe_warn_self_move.
* typeck.cc (maybe_warn_self_move): No longer static. Change the
return type to bool. Also warn when called from
a member-initializer-list. Drop the inform call.
gcc/testsuite/ChangeLog:
* g++.dg/warn/Wself-move2.C: New test.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/init.cc | 5 ++--
gcc/cp/typeck.cc | 32 +++++++++++----------
gcc/testsuite/g++.dg/warn/Wself-move2.C | 37 +++++++++++++++++++++++++
4 files changed, 59 insertions(+), 16 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/warn/Wself-move2.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 655850a9ab6..6206482c602 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8263,6 +8263,7 @@ extern cp_expr build_c_cast
(location_t loc, tree type,
cp_expr expr);
extern tree cp_build_c_cast (location_t, tree, tree,
tsubst_flags_t);
+extern bool maybe_warn_self_move (location_t, tree, tree);
extern cp_expr build_x_modify_expr (location_t, tree,
enum tree_code, tree,
tree, tsubst_flags_t);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 52396d87a8c..4a7ed7f5302 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -999,7 +999,7 @@ perform_member_init (tree member, tree init, hash_set<tree>
&uninitialized)
if (decl == error_mark_node)
return;
- if ((warn_init_self || warn_uninitialized)
+ if ((warn_init_self || warn_uninitialized || warn_self_move)
&& init
&& TREE_CODE (init) == TREE_LIST
&& TREE_CHAIN (init) == NULL_TREE)
@@ -1013,7 +1013,8 @@ perform_member_init (tree member, tree init,
hash_set<tree> &uninitialized)
warning_at (DECL_SOURCE_LOCATION (current_function_decl),
OPT_Winit_self, "%qD is initialized with itself",
member);
- else
+ else if (!maybe_warn_self_move (input_location, member,
+ TREE_VALUE (init)))
find_uninit_fields (&val, &uninitialized, decl);
}
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 4a153a8baf9..1b7a31d32f3 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -9355,27 +9355,27 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
/* Warn when a value is moved to itself with std::move. LHS is the target,
RHS may be the std::move call, and LOC is the location of the whole
- assignment. */
+ assignment. Return true if we warned. */
-static void
+bool
maybe_warn_self_move (location_t loc, tree lhs, tree rhs)
{
if (!warn_self_move)
- return;
+ return false;
/* C++98 doesn't know move. */
if (cxx_dialect < cxx11)
- return;
+ return false;
if (processing_template_decl)
- return;
+ return false;
if (!REFERENCE_REF_P (rhs)
|| TREE_CODE (TREE_OPERAND (rhs, 0)) != CALL_EXPR)
- return;
+ return false;
tree fn = TREE_OPERAND (rhs, 0);
if (!is_std_move_p (fn))
- return;
+ return false;
/* Just a little helper to strip * and various NOPs. */
auto extract_op = [] (tree &op) {
@@ -9393,13 +9393,17 @@ maybe_warn_self_move (location_t loc, tree lhs, tree
rhs)
tree type = TREE_TYPE (lhs);
tree orig_lhs = lhs;
extract_op (lhs);
- if (cp_tree_equal (lhs, arg))
- {
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wself_move,
- "moving %qE of type %qT to itself", orig_lhs, type))
- inform (loc, "remove %<std::move%> call");
- }
+ if (cp_tree_equal (lhs, arg)
+ /* Also warn in a member-initializer-list, as in : i(std::move(i)). */
+ || (TREE_CODE (lhs) == FIELD_DECL
+ && TREE_CODE (arg) == COMPONENT_REF
+ && cp_tree_equal (TREE_OPERAND (arg, 0), current_class_ref)
+ && TREE_OPERAND (arg, 1) == lhs))
+ if (warning_at (loc, OPT_Wself_move,
+ "moving %qE of type %qT to itself", orig_lhs, type))
+ return true;
+
+ return false;
}
/* For use from the C common bits. */
diff --git a/gcc/testsuite/g++.dg/warn/Wself-move2.C
b/gcc/testsuite/g++.dg/warn/Wself-move2.C
new file mode 100644
index 00000000000..0c0e1b9d5f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wself-move2.C
@@ -0,0 +1,37 @@
+// PR c++/109396
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wall" }
+
+// Define std::move.
+namespace std {
+ template<typename _Tp>
+ struct remove_reference
+ { typedef _Tp type; };
+
+ template<typename _Tp>
+ struct remove_reference<_Tp&>
+ { typedef _Tp type; };
+
+ template<typename _Tp>
+ struct remove_reference<_Tp&&>
+ { typedef _Tp type; };
+
+ template<typename _Tp>
+ constexpr typename std::remove_reference<_Tp>::type&&
+ move(_Tp&& __t) noexcept
+ { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
+}
+struct A {
+ int i_;
+
+ A(int) : i_(i_) { } // { dg-warning "itself" }
+ A(int, int) : i_(this->i_) { } // { dg-warning "itself" }
+};
+
+struct B {
+ int i_;
+
+ B(int) : i_(std::move(i_)) { } // { dg-warning "itself" }
+ B(int, int) : i_(std::move(this->i_)) { } // { dg-warning "itself" }
+};
+
base-commit: 5bc731b83b51910dc7f7cacddb4257a16d62ee38
--
2.45.1