In this PR the issue is that we reject (valid) code such as _Alignas (long long) long long foo; with -m32, because we trip this condition:
alignas_align = 1U << declspecs->align_log; if (alignas_align < TYPE_ALIGN_UNIT (type)) { if (name) error_at (loc, "%<_Alignas%> specifiers cannot reduce " "alignment of %qE", name); and error later on, since alignas_align is 4 (correct, see PR52023 for why), but TYPE_ALIGN_UNIT of long long is 8. I think TYPE_ALIGN_UNIT is wrong here as that won't give us minimal alignment required. In c_sizeof_or_alignof_type we already have the code to compute such minimal alignment so I just moved the code to a separate function and used that instead of TYPE_ALIGN_UNIT. Note that the test is run only on i?86 and x86_64, because we can't (?) easily determine which target requires what alignment. Regtested/bootstrapped on x86_64-unknown-linux-gnu and powerpc64-unknown-linux-gnu, ok for trunk? 2014-05-05 Marek Polacek <pola...@redhat.com> PR c/61053 c-family/ * c-common.c (min_align_of_type): New function factored out from... (c_sizeof_or_alignof_type): ...here. * c-common.h (min_align_of_type): Declare. c/ * c-decl.c (grokdeclarator): Use min_align_of_type instead of TYPE_ALIGN_UNIT. testsuite/ * gcc.dg/pr61053.c: New test. diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index 0ad955d..6d4440e 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -4931,6 +4931,26 @@ c_common_get_alias_set (tree t) return -1; } +/* Return the least alignment required for type TYPE. */ + +unsigned int +min_align_of_type (tree type) +{ + unsigned int align = TYPE_ALIGN (type); + align = MIN (align, BIGGEST_ALIGNMENT); +#ifdef BIGGEST_FIELD_ALIGNMENT + align = MIN (align, BIGGEST_FIELD_ALIGNMENT); +#endif + unsigned int field_align = align; +#ifdef ADJUST_FIELD_ALIGN + tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, + type); + field_align = ADJUST_FIELD_ALIGN (field, field_align); +#endif + align = MIN (align, field_align); + return align / BITS_PER_UNIT; +} + /* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where the IS_SIZEOF parameter indicates which operator is being applied. The COMPLAIN flag controls whether we should diagnose possibly @@ -5009,21 +5029,7 @@ c_sizeof_or_alignof_type (location_t loc, size_int (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT)); else if (min_alignof) - { - unsigned int align = TYPE_ALIGN (type); - align = MIN (align, BIGGEST_ALIGNMENT); -#ifdef BIGGEST_FIELD_ALIGNMENT - align = MIN (align, BIGGEST_FIELD_ALIGNMENT); -#endif - unsigned int field_align = align; -#ifdef ADJUST_FIELD_ALIGN - tree field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, - type); - field_align = ADJUST_FIELD_ALIGN (field, field_align); -#endif - align = MIN (align, field_align); - value = size_int (align / BITS_PER_UNIT); - } + value = size_int (min_align_of_type (type)); else value = size_int (TYPE_ALIGN_UNIT (type)); } diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h index 57b7dce..d34d2bb 100644 --- gcc/c-family/c-common.h +++ gcc/c-family/c-common.h @@ -758,6 +758,7 @@ extern tree c_wrap_maybe_const (tree, bool); extern tree c_save_expr (tree); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); +extern unsigned int min_align_of_type (tree); extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. diff --git gcc/c/c-decl.c gcc/c/c-decl.c index 6e7c589..9f7419a 100644 --- gcc/c/c-decl.c +++ gcc/c/c-decl.c @@ -5931,7 +5931,7 @@ grokdeclarator (const struct c_declarator *declarator, else if (declspecs->align_log != -1) { alignas_align = 1U << declspecs->align_log; - if (alignas_align < TYPE_ALIGN_UNIT (type)) + if (alignas_align < min_align_of_type (type)) { if (name) error_at (loc, "%<_Alignas%> specifiers cannot reduce " diff --git gcc/testsuite/gcc.dg/pr61053.c gcc/testsuite/gcc.dg/pr61053.c index e69de29..e3db534 100644 --- gcc/testsuite/gcc.dg/pr61053.c +++ gcc/testsuite/gcc.dg/pr61053.c @@ -0,0 +1,75 @@ +/* PR c/61053 */ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +_Alignas (char) char cc; +_Alignas (short int) char cs; +_Alignas (int) char ci; +_Alignas (long int) char cl; +_Alignas (long long int) char cll; +_Alignas (float) char cf; +_Alignas (double) char cd; +_Alignas (long double) char cld; + +_Alignas (char) short int sc; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) short int ss; +_Alignas (int) short int si; +_Alignas (long int) short int sl; +_Alignas (long long int) short int sll; +_Alignas (float) short int sf; +_Alignas (double) short int sd; +_Alignas (long double) short int sld; + +_Alignas (char) int ic; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) int is; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) int ii; +_Alignas (long int) int il; +_Alignas (long long int) int ill; +_Alignas (float) int if_; +_Alignas (double) int id; +_Alignas (long double) int ild; + +_Alignas (char) long int lic; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) long int lis; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) long int lii; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long int) long int lil; +_Alignas (long long int) long int lill; +_Alignas (float) long int lif; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (double) long int lid; +_Alignas (long double) long int lild; + +_Alignas (char) long long int llic; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) long long int llis; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) long long int llii; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long int) long long int llil; +_Alignas (long long int) long long int llill; +_Alignas (float) long long int llif; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (double) long long int llid; +_Alignas (long double) long long int llild; + +_Alignas (char) float fc; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) float fs; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) float fi; +_Alignas (long int) float fl; +_Alignas (long long int) float fll; +_Alignas (float) float ff; +_Alignas (double) float fd; +_Alignas (long double) float fld; + +_Alignas (char) double dc; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) double ds; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) double di; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long int) double dl; +_Alignas (long long int) double dll; +_Alignas (float) double df; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (double) double dd; +_Alignas (long double) double dld; + +_Alignas (char) long double ldc; /* { dg-error "cannot reduce alignment" } */ +_Alignas (short int) long double lds; /* { dg-error "cannot reduce alignment" } */ +_Alignas (int) long double ldi; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long int) long double ldl; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long long int) long double ldll; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (float) long double ldf; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (double) long double ldd; /* { dg-error "cannot reduce alignment" "" { target { lp64 } } } */ +_Alignas (long double) long double ldld; Marek