To finally resolve this PR, I'm backporting the two attached patches to gcc-5-branch.
Regtested/bootstrapped on x86_64-linux, applying. Marek
2015-11-11 Jason Merrill <ja...@redhat.com> * decl.c (duplicate_decls): When combining typedefs, remove the new type from the variants list. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 76cc1d1..383b47d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2014,7 +2014,22 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* 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; + { + 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; + } + } + } else /* Merge the data types specified in the two decls. */ newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
2016-03-31 Marek Polacek <pola...@redhat.com> PR c/70297 * c-decl.c (merge_decls): Also set TYPE_ALIGN and TYPE_USER_ALIGN. * decl.c (duplicate_decls): Also set TYPE_ALIGN and TYPE_USER_ALIGN. * c-c++-common/pr70297.c: New test. * g++.dg/cpp0x/typedef-redecl.C: New test. * gcc.dg/typedef-redecl2.c: New test. diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index bab4715..0dd2121 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2358,6 +2358,35 @@ 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) + { + /* But NEWTYPE might have an attribute, honor that. */ + tree tem = newtype; + newtype = oldtype; + + if (TYPE_USER_ALIGN (tem)) + { + if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) + TYPE_ALIGN (newtype) = TYPE_ALIGN (tem); + TYPE_USER_ALIGN (newtype) = true; + } + + /* 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 a/gcc/cp/decl.c b/gcc/cp/decl.c index cfae210..4730093 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2028,8 +2028,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) at newdecl, which will be ggc_freed. */ if (TREE_CODE (newdecl) == TYPE_DECL) { + /* But NEWTYPE might have an attribute, honor that. */ + tree tem = TREE_TYPE (newdecl); newtype = oldtype; + if (TYPE_USER_ALIGN (tem)) + { + if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) + TYPE_ALIGN (newtype) = TYPE_ALIGN (tem); + TYPE_USER_ALIGN (newtype) = true; + } + /* And remove the new type from the variants list. */ if (TYPE_NAME (TREE_TYPE (newdecl)) == newdecl) { diff --git a/gcc/testsuite/c-c++-common/pr70297.c b/gcc/testsuite/c-c++-common/pr70297.c new file mode 100644 index 0000000..70a4f15 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr70297.c @@ -0,0 +1,9 @@ +/* PR c/70297 */ +/* { dg-do compile } */ +/* { dg-options "-g" } */ + +typedef int T; +typedef int T __attribute__((aligned (4))); +struct S { + T *t; +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/typedef-redecl.C b/gcc/testsuite/g++.dg/cpp0x/typedef-redecl.C new file mode 100644 index 0000000..576c7ce --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/typedef-redecl.C @@ -0,0 +1,12 @@ +// PR c/70297 +// { dg-do compile { target c++11 } } + +#define N 64 + +typedef int T; +typedef int T __attribute__((aligned (N))); +typedef int T __attribute__((aligned (N * 2))); +typedef int T __attribute__((aligned (N))); +typedef int T; + +static_assert (alignof (T) == N * 2, "N * 2"); diff --git a/gcc/testsuite/gcc.dg/typedef-redecl2.c b/gcc/testsuite/gcc.dg/typedef-redecl2.c new file mode 100644 index 0000000..c2314c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/typedef-redecl2.c @@ -0,0 +1,13 @@ +/* PR c/70297 */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +#define N 64 + +typedef int T; +typedef int T __attribute__((aligned (N))); +typedef int T __attribute__((aligned (N * 2))); +typedef int T __attribute__((aligned (N))); +typedef int T; + +_Static_assert (_Alignof (T) == N * 2, "N * 2");