This PR points out to a GC problem: when we freed a duplicate typedef, we were
leaving its type in the variants list, with its TYPE_NAME still pointing to the
now-freed TYPE_DECL, leading to a crash.   I was lucky to discover that the
exact same problem was fixed in November for the C++ FE, so I could just follow
suit here.  And because that change didn't add a new testcase, I'm putting the
new test into c-c++-common/.

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

2016-03-21  Marek Polacek  <pola...@redhat.com>

        PR c/70297
        * c-decl.c (merge_decls): When combining typedefs, remove the new
        type from the variants list.

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

diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index bab4715..98d7f2a 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -2358,6 +2358,26 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, 
tree oldtype)
   DECL_ATTRIBUTES (newdecl)
     = targetm.merge_decl_attributes (olddecl, newdecl);
 
+  /* For typedefs use the old type, as the new type's DECL_NAME points
+     at newdecl, which will be ggc_freed.  */
+  if (TREE_CODE (newdecl) == TYPE_DECL)
+    {
+      newtype = oldtype;
+
+      /* And remove the new type from the variants list.  */
+      if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl)
+       {
+         tree remove = TREE_TYPE (newdecl);
+         for (tree t = TYPE_MAIN_VARIANT (remove); ;
+              t = TYPE_NEXT_VARIANT (t))
+           if (TYPE_NEXT_VARIANT (t) == remove)
+             {
+               TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (remove);
+               break;
+             }
+       }
+    }
+
   /* Merge the data types specified in the two decls.  */
   TREE_TYPE (newdecl)
     = TREE_TYPE (olddecl)
diff --git gcc/testsuite/c-c++-common/pr70297.c 
gcc/testsuite/c-c++-common/pr70297.c
index e69de29..bc078c8 100644
--- gcc/testsuite/c-c++-common/pr70297.c
+++ gcc/testsuite/c-c++-common/pr70297.c
@@ -0,0 +1,10 @@
+/* PR c/70297 */
+/* { dg-do compile } */
+/* { dg-options "-g" } */
+
+typedef unsigned int uint32_t;
+typedef uint32_t T;
+typedef uint32_t T __attribute__((aligned(4)));
+struct S {
+  T *t;
+};

        Marek

Reply via email to