Hi!

Except for std::tuple* structured bindings, the VAR_DECLs we create for the
identifiers aren't actually variables, but placeholders with
DECL_VALUE_EXPR.  If the structured binding is not a reference, it is still
an automatic variable and so -Wreturn-local-addr should warn on those,
but if it is a reference, then it depends if it references an automatic
variable or something else.

The following patch handles it by recursing for references on the
initializer of the structured binding.  Note we don't just emit incorrect
warning without this patch, but the caller replaces return something;
with return (something, 0); if maybe_warn_about_returning_address_of_local
returns true, so it is also invalid at runtime.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and
release branches?

2018-10-11  Jakub Jelinek  <ja...@redhat.com>

        PR c++/87582
        * typeck.c (maybe_warn_about_returning_address_of_local): If
        whats_returned is a structured binding identifier and the structured
        binding is a reference, recurse on its initializer.

        * g++.dg/cpp1z/decomp48.C: New test.

--- gcc/cp/typeck.c.jj  2018-09-13 09:27:31.547765011 +0200
+++ gcc/cp/typeck.c     2018-10-11 10:06:36.820295475 +0200
@@ -9096,6 +9096,22 @@ maybe_warn_about_returning_address_of_lo
       && !(TREE_STATIC (whats_returned)
           || TREE_PUBLIC (whats_returned)))
     {
+      if (VAR_P (whats_returned)
+         && DECL_DECOMPOSITION_P (whats_returned)
+         && DECL_DECOMP_BASE (whats_returned)
+         && DECL_HAS_VALUE_EXPR_P (whats_returned))
+       {
+         /* When returning address of a structured binding, if the structured
+            binding is not a reference, continue normally, if it is a
+            reference, recurse on the initializer of the structured
+            binding.  */
+         tree base = DECL_DECOMP_BASE (whats_returned);
+         if (TYPE_REF_P (TREE_TYPE (base)))
+           {
+             tree init = DECL_INITIAL (base);
+             return maybe_warn_about_returning_address_of_local (init);
+           }
+       }
       bool w = false;
       auto_diagnostic_group d;
       if (TYPE_REF_P (valtype))
--- gcc/testsuite/g++.dg/cpp1z/decomp48.C.jj    2018-10-11 10:30:09.255651339 
+0200
+++ gcc/testsuite/g++.dg/cpp1z/decomp48.C       2018-10-11 11:00:23.210283412 
+0200
@@ -0,0 +1,134 @@
+// PR c++/87582
+// { dg-do run { target c++11 } }
+// { dg-options "-Wreturn-local-addr" }
+
+struct S { int s, t; };
+S v {1, 2};
+int a[3] = {1, 2, 3};
+
+int &
+f1 ()
+{
+  auto& [s, t] = v;    // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-bogus "reference to local variable '.' 
returned" }
+}
+
+int &
+f2 ()
+{
+  S v {1, 2};
+  auto& [s, t] = v;    // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 'v' 
returned" }
+}
+
+int &
+f3 ()
+{
+  auto& [s, t, u] = a; // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-bogus "reference to local variable '.' 
returned" }
+}
+
+int &
+f4 ()
+{
+  int a[3] = {1, 2, 3};
+  auto& [s, t, u] = a; // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 'a' 
returned" }
+}
+
+int &
+f5 ()
+{
+  auto [s, t] = v;     // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 's' 
returned" }
+}
+
+int &
+f6 ()
+{
+  S v {1, 2};
+  auto [s, t] = v;     // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 's' 
returned" }
+}
+
+int &
+f7 ()
+{
+  auto [s, t, u] = a;  // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 's' 
returned" }
+}
+
+int &
+f8 ()
+{
+  int a[3] = {1, 2, 3};
+  auto [s, t, u] = a;  // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return s;            // { dg-warning "reference to local variable 's' 
returned" }
+}
+
+int *
+f9 ()
+{
+  auto& [s, t] = v;    // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-bogus "address of local variable '.' returned" }
+}
+
+int *
+f10 ()
+{
+  S v {1, 2};
+  auto& [s, t] = v;    // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 'v' 
returned" }
+}
+
+int *
+f11 ()
+{
+  auto& [s, t, u] = a; // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-bogus "address of local variable '.' returned" }
+}
+
+int *
+f12 ()
+{
+  int a[3] = {1, 2, 3};
+  auto& [s, t, u] = a; // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 'a' 
returned" }
+}
+
+int *
+f13 ()
+{
+  auto [s, t] = v;     // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 's' 
returned" }
+}
+
+int *
+f14 ()
+{
+  S v {1, 2};
+  auto [s, t] = v;     // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 's' 
returned" }
+}
+
+int *
+f15 ()
+{
+  auto [s, t, u] = a;  // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 's' 
returned" }
+}
+
+int *
+f16 ()
+{
+  int a[3] = {1, 2, 3};
+  auto [s, t, u] = a;  // { dg-warning "structured bindings only available 
with" "" { target c++14_down } }
+  return &s;           // { dg-warning "address of local variable 's' 
returned" }
+}
+
+int
+main ()
+{
+  if (&f1 () != &v.s || &f3 () != &a[0] || f9 () != &v.s || f11 () != &a[0])
+    __builtin_abort ();
+}

        Jakub

Reply via email to