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");
+         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: 66d2a76dcf625f8dbe43d3c512e9c43f588fdc25
-- 
2.45.1

Reply via email to