re PR c++/81197 (ICE with structured binding and lifetime-extended temporaries)
authorJakub Jelinek <jakub@redhat.com>
Fri, 15 Dec 2017 21:39:20 +0000 (22:39 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 15 Dec 2017 21:39:20 +0000 (22:39 +0100)
PR c++/81197
* cp-tree.h (cp_maybe_mangle_decomp): Declare.
* decl.c (cp_maybe_mangle_decomp): New function.
(cp_finish_decomp): Don't SET_DECL_ASSEMBLER_NAME here.
* parser.c (cp_convert_range_for,
cp_parser_decomposition_declaration): Call cp_maybe_mangle_decomp.
* pt.c (tsubst_expr): Likewise.
* mangle.c (find_decomp_unqualified_name): New function.
(write_unqualified_name): Handle DECL_DECOMPOSITION_P
where DECL_ASSEMBLER_NAME is already set.

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

From-SVN: r255705

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1z/decomp34.C [new file with mode: 0644]

index 488b9f3f59970472b40d3b72d12fa0c22e667593..d96b679de630687f0c7065b667c4d317d07c0300 100644 (file)
@@ -1,5 +1,16 @@
 2017-12-15  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/81197
+       * cp-tree.h (cp_maybe_mangle_decomp): Declare.
+       * decl.c (cp_maybe_mangle_decomp): New function.
+       (cp_finish_decomp): Don't SET_DECL_ASSEMBLER_NAME here.
+       * parser.c (cp_convert_range_for,
+       cp_parser_decomposition_declaration): Call cp_maybe_mangle_decomp.
+       * pt.c (tsubst_expr): Likewise.
+       * mangle.c (find_decomp_unqualified_name): New function.
+       (write_unqualified_name): Handle DECL_DECOMPOSITION_P
+       where DECL_ASSEMBLER_NAME is already set.
+
        PR c++/80135
        PR c++/81922
        * typeck2.c (digest_init_r): Change nested argument type from bool to
index 05551dfdf29d4e5284af6c5b00e9958d937ceaf8..f5f974da72857424c2deb53e2544718bcc903ea2 100644 (file)
@@ -6149,6 +6149,7 @@ extern void start_decl_1                  (tree, bool);
 extern bool check_array_initializer            (tree, tree, tree);
 extern void cp_finish_decl                     (tree, tree, bool, tree, int);
 extern tree lookup_decomp_type                 (tree);
+extern void cp_maybe_mangle_decomp             (tree, tree, unsigned int);
 extern void cp_finish_decomp                   (tree, tree, unsigned int);
 extern int cp_complete_array_type              (tree *, tree, bool);
 extern int cp_complete_array_type_or_error     (tree *, tree, bool, tsubst_flags_t);
index 5df16bb21bfc8b63c275071a004e69df116fe217..0e6ee059e230474faa133d0ee9b3183e74d76e87 100644 (file)
@@ -7339,6 +7339,25 @@ lookup_decomp_type (tree v)
   return *decomp_type_table->get (v);
 }
 
+/* Mangle a decomposition declaration if needed.  Arguments like
+   in cp_finish_decomp.  */
+
+void
+cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count)
+{
+  if (!processing_template_decl
+      && !error_operand_p (decl)
+      && DECL_NAMESPACE_SCOPE_P (decl))
+    {
+      auto_vec<tree, 16> v;
+      v.safe_grow (count);
+      tree d = first;
+      for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
+       v[count - i - 1] = d;
+      SET_DECL_ASSEMBLER_NAME (decl, mangle_decomp (decl, v));
+    }
+}
+
 /* Finish a decomposition declaration.  DECL is the underlying declaration
    "e", FIRST is the head of a chain of decls for the individual identifiers
    chained through DECL_CHAIN in reverse order and COUNT is the number of
@@ -7612,8 +7631,6 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
            DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
          }
     }
-  else if (DECL_NAMESPACE_SCOPE_P (decl))
-    SET_DECL_ASSEMBLER_NAME (decl, mangle_decomp (decl, v));
 }
 
 /* Returns a declaration for a VAR_DECL as if:
index 6d4e59101ee3bdb26bd17c787140ff99b2d59cff..ffd2b4c5844e374aa52c186873ca77355fb755d7 100644 (file)
@@ -1247,6 +1247,51 @@ write_template_prefix (const tree node)
   add_substitution (substitution);
 }
 
+/* As the list of identifiers for the structured binding declaration
+   DECL is likely gone, try to recover the DC <source-name>+ E portion
+   from its mangled name.  Return pointer to the DC and set len to
+   the length up to and including the terminating E.  On failure
+   return NULL.  */
+
+static const char *
+find_decomp_unqualified_name (tree decl, size_t *len)
+{
+  const char *p = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  const char *end = p + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl));
+  bool nested = false;
+  if (strncmp (p, "_Z", 2))
+    return NULL;
+  p += 2;
+  if (!strncmp (p, "St", 2))
+    p += 2;
+  else if (*p == 'N')
+    {
+      nested = true;
+      ++p;
+      while (ISDIGIT (p[0]))
+       {
+         char *e;
+         long num = strtol (p, &e, 10);
+         if (num >= 1 && num < end - e)
+           p = e + num;
+         else
+           break;
+       }
+    }
+  if (strncmp (p, "DC", 2))
+    return NULL;
+  if (nested)
+    {
+      if (end[-1] != 'E')
+       return NULL;
+      --end;
+    }
+  if (end[-1] != 'E')
+    return NULL;
+  *len = end - p;
+  return p;
+}
+
 /* We don't need to handle thunks, vtables, or VTTs here.  Those are
    mangled through special entry points.
 
@@ -1291,7 +1336,17 @@ write_unqualified_name (tree decl)
     {
       found = true;
       gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
-      write_source_name (DECL_ASSEMBLER_NAME (decl));
+      const char *decomp_str = NULL;
+      size_t decomp_len = 0;
+      if (VAR_P (decl)
+         && DECL_DECOMPOSITION_P (decl)
+         && DECL_NAME (decl) == NULL_TREE
+         && DECL_NAMESPACE_SCOPE_P (decl))
+       decomp_str = find_decomp_unqualified_name (decl, &decomp_len);
+      if (decomp_str)
+       write_chars (decomp_str, decomp_len);
+      else
+       write_source_name (DECL_ASSEMBLER_NAME (decl));
     }
   else if (DECL_DECLARES_FUNCTION_P (decl))
     {
index 94e87c235f1bfec09f01a072bf6cda24c4e32f13..e13e127d45fefe30874305c2f91b0d39f1a61bdd 100644 (file)
@@ -11940,6 +11940,9 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
                                     tf_warning_or_error);
   finish_for_expr (expression, statement);
 
+  if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl))
+    cp_maybe_mangle_decomp (range_decl, decomp_first_name, decomp_cnt);
+
   /* The declaration is initialized with *__begin inside the loop body.  */
   cp_finish_decl (range_decl,
                  build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
@@ -13283,6 +13286,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
 
       if (decl != error_mark_node)
        {
+         cp_maybe_mangle_decomp (decl, prev, v.length ());
          cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
                          is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
          cp_finish_decomp (decl, prev, v.length ());
index 5a6a7cff939496a29caa2b315bdd24be9addb208..dc50f31034b3015ebc1941612b8f632fad54e5af 100644 (file)
@@ -16135,19 +16135,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
                    if (VAR_P (decl))
                      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
                                    (pattern_decl));
-                   cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
                    if (VAR_P (decl)
                        && DECL_DECOMPOSITION_P (decl)
                        && TREE_TYPE (pattern_decl) != error_mark_node)
                      {
                        unsigned int cnt;
                        tree first;
-                       decl = tsubst_decomp_names (decl, pattern_decl, args,
-                                                   complain, in_decl, &first,
-                                                   &cnt);
-                       if (decl != error_mark_node)
-                         cp_finish_decomp (decl, first, cnt);
+                       tree ndecl
+                         = tsubst_decomp_names (decl, pattern_decl, args,
+                                                complain, in_decl, &first, &cnt);
+                       if (ndecl != error_mark_node)
+                         cp_maybe_mangle_decomp (ndecl, first, cnt);
+                       cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
+                       if (ndecl != error_mark_node)
+                         cp_finish_decomp (ndecl, first, cnt);
                      }
+                   else
+                     cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
                  }
              }
          }
index e1e29f195fd3ea25cc3fcf0a20bfe5e02660bf59..ba86d2f938091f015acbe40638b749b3576f779d 100644 (file)
@@ -1,5 +1,8 @@
 2017-12-15  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/81197
+       * g++.dg/cpp1z/decomp34.C: New test.
+
        PR c++/80135
        PR c++/81922
        * g++.dg/warn/Wplacement-new-size-1.C (fBx1): Initialize nested
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp34.C b/gcc/testsuite/g++.dg/cpp1z/decomp34.C
new file mode 100644 (file)
index 0000000..c7f0b8a
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/81197
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct X { int a; };
+struct Y { int b, c, d; };
+auto&& [t] = X{};      // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+namespace A { namespace B { auto&& [u, v, ww] = Y{}; } }       // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+
+// { dg-final { scan-assembler "_ZGRDC1tE0" } }
+// { dg-final { scan-assembler "_ZGRN1A1BDC1u1v2wwEE1" } }