PR c++/86982, -Wreturn-local-addr and std::move and std::forward.
authorMarek Polacek <polacek@redhat.com>
Thu, 6 Sep 2018 00:38:13 +0000 (00:38 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Thu, 6 Sep 2018 00:38:13 +0000 (00:38 +0000)
* typeck.c (maybe_warn_about_returning_address_of_local): Handle calls
to std::move or std::forward.
(is_std_forward_p): New function.

* g++.dg/warn/Wreturn-local-addr-5.C: New test.

From-SVN: r264139

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wreturn-local-addr-5.C [new file with mode: 0644]

index b4ec9f4..d5879f8 100644 (file)
@@ -5,6 +5,11 @@
        out if performing the maybe-rvalue overload resolution and a conversion
        function is getting called.
 
+       PR c++/86982, -Wreturn-local-addr and std::move and std::forward.
+       * typeck.c (maybe_warn_about_returning_address_of_local): Handle calls
+       to std::move or std::forward.
+       (is_std_forward_p): New function.
+
 2018-09-05  Pádraig Brady  <p@draigbrady.com>
 
        PR c++/87185
index 84cf4c4..9fa4c16 100644 (file)
@@ -63,6 +63,8 @@ static tree lookup_destructor (tree, tree, tree, tsubst_flags_t);
 static void error_args_num (location_t, tree, bool);
 static int convert_arguments (tree, vec<tree, va_gc> **, tree, int,
                               tsubst_flags_t);
+static bool is_std_move_p (tree);
+static bool is_std_forward_p (tree);
 
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)
@@ -9071,6 +9073,15 @@ maybe_warn_about_returning_address_of_local (tree retval)
       STRIP_NOPS (whats_returned);
     }
 
+  /* As a special case, we handle a call to std::move or std::forward.  */
+  if (TREE_CODE (whats_returned) == CALL_EXPR
+      && (is_std_move_p (whats_returned)
+         || is_std_forward_p (whats_returned)))
+    {
+      tree arg = CALL_EXPR_ARG (whats_returned, 0);
+      return maybe_warn_about_returning_address_of_local (arg);
+    }
+
   if (TREE_CODE (whats_returned) != ADDR_EXPR)
     return false;
   whats_returned = TREE_OPERAND (whats_returned, 0);
@@ -9136,6 +9147,23 @@ decl_in_std_namespace_p (tree decl)
          && DECL_NAMESPACE_STD_P (decl_namespace_context (decl)));
 }
 
+/* Returns true if FN, a CALL_EXPR, is a call to std::forward.  */
+
+static bool
+is_std_forward_p (tree fn)
+{
+  /* std::forward only takes one argument.  */
+  if (call_expr_nargs (fn) != 1)
+    return false;
+
+  tree fndecl = cp_get_callee_fndecl_nofold (fn);
+  if (!decl_in_std_namespace_p (fndecl))
+    return false;
+
+  tree name = DECL_NAME (fndecl);
+  return name && id_equal (name, "forward");
+}
+
 /* Returns true if FN, a CALL_EXPR, is a call to std::move.  */
 
 static bool
index 5ccc244..e22ede0 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-05  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/86982, -Wreturn-local-addr and std::move and std::forward.
+       * g++.dg/warn/Wreturn-local-addr-5.C: New test.
+
 2018-09-05  Cesar Philippidis  <cesar@codesourcery.com>
            Bernd Schmidt  <bernds_cb1@t-online.de>
 
diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-5.C b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-5.C
new file mode 100644 (file)
index 0000000..7609627
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/86982
+// { dg-do compile { target c++11 } }
+
+#include <utility>
+
+int&& f() { int i = 0; return std::move(i); } // { dg-warning "reference to local variable" }
+int&& g() { int i = 0; return std::forward<int>(i); } // { dg-warning "reference to local variable" }
+int&& h() { long l = 0; return std::forward<int>(l); } // { dg-warning "reference to temporary" }