On 04/20/2015 10:35 AM, Jakub Jelinek wrote:
Wonder what will happen if finalize_type_size or fixup_attribute_variants is called on a type variant with TYPE_USER_ALIGN before it is called on the TYPE_MAIN_VARIANT; I'd guess that in that case all the variants including the main variant would be marked as TYPE_USER_ALIGN and might have incorrect TYPE_ALIGN.
Good point. Changing layout_type to always work on the TYPE_MAIN_VARIANT passes testing:
commit 0f520c7c862aa3c8850c3d3c024d19e4b8f1a757 Author: Jason Merrill <ja...@redhat.com> Date: Fri Apr 10 18:13:56 2015 -0400 PR c++/65734 gcc/ * stor-layout.c (layout_type): Layout the TYPE_MAIN_VARIANT. (finalize_type_size): Respect TYPE_USER_ALIGN. (layout_type) [ARRAY_TYPE]: Likewise. gcc/cp/ * class.c (fixup_attribute_variants): Respect TYPE_USER_ALIGN. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d80d312e..8103e60 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1989,14 +1989,23 @@ fixup_attribute_variants (tree t) if (!t) return; + tree attrs = TYPE_ATTRIBUTES (t); + unsigned align = TYPE_ALIGN (t); + bool user_align = TYPE_USER_ALIGN (t); + for (variants = TYPE_NEXT_VARIANT (t); variants; variants = TYPE_NEXT_VARIANT (variants)) { /* These are the two fields that check_qualified_type looks at and are affected by attributes. */ - TYPE_ATTRIBUTES (variants) = TYPE_ATTRIBUTES (t); - TYPE_ALIGN (variants) = TYPE_ALIGN (t); + TYPE_ATTRIBUTES (variants) = attrs; + unsigned valign = align; + if (TYPE_USER_ALIGN (variants)) + valign = MAX (valign, TYPE_ALIGN (variants)); + else + TYPE_USER_ALIGN (variants) = user_align; + TYPE_ALIGN (variants) = valign; } } diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index f18f1ac..5bc8a29 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -1831,9 +1831,13 @@ finalize_type_size (tree type) { TYPE_SIZE (variant) = size; TYPE_SIZE_UNIT (variant) = size_unit; - TYPE_ALIGN (variant) = align; + unsigned valign = align; + if (TYPE_USER_ALIGN (variant)) + valign = MAX (valign, TYPE_ALIGN (variant)); + else + TYPE_USER_ALIGN (variant) = user_align; + TYPE_ALIGN (variant) = valign; TYPE_PRECISION (variant) = precision; - TYPE_USER_ALIGN (variant) = user_align; SET_TYPE_MODE (variant, mode); } } @@ -2154,6 +2158,10 @@ layout_type (tree type) if (type == error_mark_node) return; + /* We don't want finalize_type_size to copy an alignment attribute to + variants that don't have it. */ + type = TYPE_MAIN_VARIANT (type); + /* Do nothing if type has been laid out before. */ if (TYPE_SIZE (type)) return; @@ -2350,13 +2358,17 @@ layout_type (tree type) /* Now round the alignment and size, using machine-dependent criteria if any. */ + unsigned align = TYPE_ALIGN (element); + if (TYPE_USER_ALIGN (type)) + align = MAX (align, TYPE_ALIGN (type)); + else + TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element); #ifdef ROUND_TYPE_ALIGN - TYPE_ALIGN (type) - = ROUND_TYPE_ALIGN (type, TYPE_ALIGN (element), BITS_PER_UNIT); + align = ROUND_TYPE_ALIGN (type, align, BITS_PER_UNIT); #else - TYPE_ALIGN (type) = MAX (TYPE_ALIGN (element), BITS_PER_UNIT); + align = MAX (align, BITS_PER_UNIT); #endif - TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element); + TYPE_ALIGN (type) = align; SET_TYPE_MODE (type, BLKmode); if (TYPE_SIZE (type) != 0 && ! targetm.member_type_forces_blk (type, VOIDmode) diff --git a/gcc/testsuite/g++.dg/cpp0x/alignas1.C b/gcc/testsuite/g++.dg/cpp0x/alignas1.C new file mode 100644 index 0000000..d73c875 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alignas1.C @@ -0,0 +1,16 @@ +// PR c++/65734 +// { dg-do compile { target c++11 } } + +template <class T> struct A +{ + T t; +}; + +typedef A<int> T[4] alignas (2 * alignof (int)); +A<int> a[4]; + +typedef A<char> T2[4] alignas (2 * alignof (int)); + +#define SA(X) static_assert((X),#X) +SA(alignof (T) == 2 * alignof(int)); +SA(alignof (T2) == 2 * alignof(int)); diff --git a/gcc/testsuite/g++.dg/cpp0x/alignas2.C b/gcc/testsuite/g++.dg/cpp0x/alignas2.C new file mode 100644 index 0000000..2e7d051 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alignas2.C @@ -0,0 +1,20 @@ +// PR c++/65734 +// { dg-do compile { target c++11 } } + +template <typename T> +struct BVector +{ + T t; +}; +BVector<int> m; + +template <template <class> class T> +struct BV2 +{ + typedef T<float> value_type alignas (16); + value_type v; +}; +BV2<BVector> m2; + +#define SA(X) static_assert((X),#X) +SA(alignof (BV2<BVector>::value_type) == 16);