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);
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)
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);
}
/* 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) {
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. */
--- /dev/null
+// 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" }
+};
+