Hi!

As reported, the newly added testcase ICEs with --param ggc-min-heapsize=0.
The problem is that while the remove type is not referenced by anything
else, it is a distinct type created to hold the attributes, there is another
type with TYPE_NAME equal to the newdecl we want to tree.  That one is
created in common_handle_aligned_attribute:
    {
      if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
        /* OK, modify the type in place.  */;
      /* If we have a TYPE_DECL, then copy the type, so that we
         don't accidentally modify a builtin type.  See pushdecl.  */
      else if (decl && TREE_TYPE (decl) != error_mark_node
               && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
        {
          tree tt = TREE_TYPE (decl);
          *type = build_variant_type_copy (*type);
          DECL_ORIGINAL_TYPE (decl) = tt;
          TYPE_NAME (*type) = decl;
          TREE_USED (*type) = TREE_USED (decl);
          TREE_TYPE (decl) = *type;
        }
      else
        *type = build_variant_type_copy (*type);
where we create a variant type and set the TYPE_NAME too.  I've tried to
remove that else if ... and just do *type = build_variant_type_copy (*type);
but that regressed some DWARF DW_AT_alignment tests.

So, the following patch instead removes the remove type from the variants
list if it is not a main variant (as before), otherwise tries to find in
TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (newdecl)) variant list a type
with TYPE_NAME equal to newdecl and remove that one.

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

2019-04-18  Jakub Jelinek  <ja...@redhat.com>

        PR c++/90108
        * c-decl.c (merge_decls): If remove is main variant and
        DECL_ORIGINAL_TYPE is some other type, remove a DECL_ORIGINAL_TYPE
        variant that has newdecl as TYPE_NAME if any.

        * decl.c (duplicate_decls): If remove is main variant and
        DECL_ORIGINAL_TYPE is some other type, remove a DECL_ORIGINAL_TYPE
        variant that has newdecl as TYPE_NAME if any.

        * c-c++-common/pr90108.c: New test.

--- gcc/c/c-decl.c.jj   2019-04-17 21:21:39.936133112 +0200
+++ gcc/c/c-decl.c      2019-04-17 23:25:08.098936888 +0200
@@ -2513,7 +2513,24 @@ merge_decls (tree newdecl, tree olddecl,
        {
          tree remove = TREE_TYPE (newdecl);
          if (TYPE_MAIN_VARIANT (remove) == remove)
-           gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE);
+           {
+             gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE);
+             /* If remove is the main variant, no need to remove that
+                from the list.  One of the DECL_ORIGINAL_TYPE
+                variants, e.g. created for aligned attribute, might still
+                refer to the newdecl TYPE_DECL though, so remove that one
+                in that case.  */
+             if (DECL_ORIGINAL_TYPE (newdecl)
+                 && DECL_ORIGINAL_TYPE (newdecl) != remove)
+               for (tree t = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (newdecl));
+                    t; t = TYPE_MAIN_VARIANT (t))
+                 if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl)
+                   {
+                     TYPE_NEXT_VARIANT (t)
+                       = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t));
+                     break;
+                   }
+           }       
          else
            for (tree t = TYPE_MAIN_VARIANT (remove); ;
                 t = TYPE_NEXT_VARIANT (t))
--- gcc/cp/decl.c.jj    2019-04-17 21:21:39.753136091 +0200
+++ gcc/cp/decl.c       2019-04-17 23:27:13.995875527 +0200
@@ -2133,7 +2133,24 @@ next_arg:;
            {
              tree remove = TREE_TYPE (newdecl);
              if (TYPE_MAIN_VARIANT (remove) == remove)
-               gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE);
+               {
+                 gcc_assert (TYPE_NEXT_VARIANT (remove) == NULL_TREE);
+                 /* If remove is the main variant, no need to remove that
+                    from the list.  One of the DECL_ORIGINAL_TYPE
+                    variants, e.g. created for aligned attribute, might still
+                    refer to the newdecl TYPE_DECL though, so remove that one
+                    in that case.  */
+                 if (tree orig = DECL_ORIGINAL_TYPE (newdecl))
+                   if (orig != remove)
+                     for (tree t = TYPE_MAIN_VARIANT (orig); t;
+                          t = TYPE_MAIN_VARIANT (t))
+                       if (TYPE_NAME (TYPE_NEXT_VARIANT (t)) == newdecl)
+                         {
+                           TYPE_NEXT_VARIANT (t)
+                             = TYPE_NEXT_VARIANT (TYPE_NEXT_VARIANT (t));
+                           break;
+                         }
+               }           
              else
                for (tree t = TYPE_MAIN_VARIANT (remove); ;
                     t = TYPE_NEXT_VARIANT (t))
--- gcc/testsuite/c-c++-common/pr90108.c.jj     2019-04-17 23:18:23.466566296 
+0200
+++ gcc/testsuite/c-c++-common/pr90108.c        2019-04-17 23:18:23.466566296 
+0200
@@ -0,0 +1,6 @@
+/* PR c++/90108 */
+/* { dg-do compile } */
+/* { dg-options "--param ggc-min-heapsize=0" } */
+
+typedef unsigned int a __attribute__ ((__aligned__(8), __may_alias__));
+typedef unsigned int a __attribute__ ((__aligned__(8), __may_alias__));

        Jakub

Reply via email to