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