This is yet another follow up on the discussion of the fix for the ICE in __builtin_has_attribute that started last December with PR88383.
After my last post last week I went and added more tests to make sure the built-in behaves as intended by comparing its result for non-trivial expressions with that of __alignof__. The test that does this is the new builtin-has-attribute-7.c. The test exposed one problem in the handling of attribute vector_size by the built-in (I mentioned that in my last post). It also exposed a couple of bugs in the attribute handler itself. I fixed both of these in the attached patch. This latest revision of the patch resolves the following bugs: PR 88383 - ICE calling __builtin_has_attribute on a reference PR 89288 - ICE in tree_code_size, at tree.c:865 PR 89798 - excessive vector_size silently accepted and truncated PR 89797 - ICE on a vector_size (1LU << 33) int variable Bootstrapped on x86_64-linux. The tests are still running but assuming they pass, is this last revision good to commit? Martin A link to my last comment in the archive: https://gcc.gnu.org/ml/gcc-patches/2019-03/msg01096.html
PR c/88383 - ICE calling __builtin_has_attribute on a reference PR c/89288 - ICE in tree_code_size, at tree.c:865 PR c/89798 - excessive vector_size silently accepted and truncated PR c/89797 - ICE on a vector_size (1LU << 33) int variable gcc/ChangeLog: PR c/89797 * targhooks.c (default_vector_alignment): Avoid assuming argument fits in SHWI. * tree.h (TYPE_VECTOR_SUBPARTS): Avoid sign overflow in a shift expression. gcc/c-family/ChangeLog: PR c/88383 PR c/89288 PR c/89798 PR c/89797 * c-attribs.c (type_valid_for_vector_size): Detect excessively large sizes. (validate_attribute): Handle DECLs and expressions. (has_attribute): Handle types referenced by expressions. Avoid considering array attributes in ARRAY_REF expressions . gcc/cp/ChangeLog: PR c/88383 PR c/89288 * parser.c (cp_parser_has_attribute_expression): Handle assignment expressions. gcc/testsuite/ChangeLog: PR c/88383 PR c/89288 PR c/89798 PR c/89797 * c-c++-common/attributes-1.c: Adjust. * c-c++-common/builtin-has-attribute-6.c: New test. * c-c++-common/builtin-has-attribute-7.c: New test. * c-c++-common/builtin-has-attribute-4.c: Adjust expectations. * c-c++-common/builtin-has-attribute-6.c: New test. * gcc.dg/pr25559.c: Adjust. * gcc.dg/attr-vector_size.c: New test. diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index e559d3b55d2..9ded3df278e 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -3478,19 +3478,56 @@ type_valid_for_vector_size (tree type, tree atname, tree args, return type; tree size = TREE_VALUE (args); + /* Erroneous arguments have already been diagnosed. */ + if (size == error_mark_node) + return NULL_TREE; + if (size && TREE_CODE (size) != IDENTIFIER_NODE && TREE_CODE (size) != FUNCTION_DECL) size = default_conversion (size); - if (!tree_fits_uhwi_p (size)) + if (TREE_CODE (size) != INTEGER_CST) + { + if (error_p) + error ("%qE attribute argument value %qE is not an integer constant", + atname, size); + else + warning (OPT_Wattributes, + "%qE attribute argument value %qE is not an integer constant", + atname, size); + return NULL_TREE; + } + + if (!TYPE_UNSIGNED (TREE_TYPE (size)) + && tree_int_cst_sgn (size) < 0) { - /* FIXME: make the error message more informative. */ if (error_p) - warning (OPT_Wattributes, "%qE attribute ignored", atname); + error ("%qE attribute argument value %qE is negative", + atname, size); + else + warning (OPT_Wattributes, + "%qE attribute argument value %qE is negative", + atname, size); + return NULL_TREE; + } + + /* The attribute argument value is constrained by the maximum bit + alignment representable in unsigned int on the host. */ + unsigned HOST_WIDE_INT vecsize; + unsigned HOST_WIDE_INT maxsize = tree_to_uhwi (max_object_size ()); + if (!tree_fits_uhwi_p (size) + || (vecsize = tree_to_uhwi (size)) > maxsize) + { + if (error_p) + error ("%qE attribute argument value %qE exceeds %wu", + atname, size, maxsize); + else + warning (OPT_Wattributes, + "%qE attribute argument value %qE exceeds %wu", + atname, size, maxsize); return NULL_TREE; } - unsigned HOST_WIDE_INT vecsize = tree_to_uhwi (size); if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type))) { if (error_p) @@ -4033,8 +4070,12 @@ validate_attribute (location_t atloc, tree oper, tree attr) if (TYPE_P (oper)) tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, oper); - else + else if (DECL_P (oper)) tmpdecl = build_decl (atloc, TREE_CODE (oper), tmpid, TREE_TYPE (oper)); + else if (EXPR_P (oper)) + tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, TREE_TYPE (oper)); + else + return false; /* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes believe the DECL declared above is at file scope. (See bug 87526.) */ @@ -4043,7 +4084,7 @@ validate_attribute (location_t atloc, tree oper, tree attr) if (DECL_P (tmpdecl)) { if (DECL_P (oper)) - /* An alias cannot be a defintion so declare the symbol extern. */ + /* An alias cannot be a definition so declare the symbol extern. */ DECL_EXTERNAL (tmpdecl) = true; /* Attribute visibility only applies to symbols visible from other translation units so make it "public." */ @@ -4079,11 +4120,17 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) do { /* Determine the array element/member declaration from - an ARRAY/COMPONENT_REF. */ + a COMPONENT_REF and an INDIRECT_REF involving a refeence. */ STRIP_NOPS (t); tree_code code = TREE_CODE (t); - if (code == ARRAY_REF) - t = TREE_OPERAND (t, 0); + if (code == INDIRECT_REF) + { + tree op0 = TREE_OPERAND (t, 0); + if (TREE_CODE (TREE_TYPE (op0)) == REFERENCE_TYPE) + t = op0; + else + break; + } else if (code == COMPONENT_REF) t = TREE_OPERAND (t, 1); else @@ -4134,7 +4181,8 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) } else { - atlist = TYPE_ATTRIBUTES (TREE_TYPE (expr)); + type = TREE_TYPE (expr); + atlist = TYPE_ATTRIBUTES (type); done = true; } @@ -4210,9 +4258,10 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) if (tree arg = TREE_VALUE (attr)) { arg = convert (TREE_VALUE (arg)); - if (expr && DECL_P (expr) - && DECL_USER_ALIGN (expr) - && tree_fits_uhwi_p (arg)) + if (!tree_fits_uhwi_p (arg)) + /* Invalid argument. */; + else if (expr && DECL_P (expr) + && DECL_USER_ALIGN (expr)) found_match = DECL_ALIGN_UNIT (expr) == tree_to_uhwi (arg); else if (type && TYPE_USER_ALIGN (type)) found_match = TYPE_ALIGN_UNIT (type) == tree_to_uhwi (arg); @@ -4249,13 +4298,7 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) } else if (!strcmp ("vector_size", namestr)) { - if (!type) - continue; - - /* Determine the base type from arrays, pointers, and such. - Fail if the base type is not a vector. */ - type = type_for_vector_size (type); - if (!VECTOR_TYPE_P (type)) + if (!type || !VECTOR_TYPE_P (type)) return false; if (tree arg = TREE_VALUE (attr)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c669e49214f..6c24f2ff96a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8552,9 +8552,9 @@ cp_parser_has_attribute_expression (cp_parser *parser) cp_parser_parse_definitely (parser); /* If the type-id production did not work out, then we must be - looking at the unary-expression production. */ + looking at an expression. */ if (!oper || oper == error_mark_node) - oper = cp_parser_unary_expression (parser); + oper = cp_parser_assignment_expression (parser); STRIP_ANY_LOCATION_WRAPPER (oper); diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 318f7e9784a..cfde248dd3d 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1247,14 +1247,18 @@ constant_alignment_word_strings (const_tree exp, HOST_WIDE_INT align) return align; } -/* Default to natural alignment for vector types. */ +/* Default to natural alignment for vector types, bounded by + MAX_OFILE_ALIGNMENT. */ + HOST_WIDE_INT default_vector_alignment (const_tree type) { - HOST_WIDE_INT align = tree_to_shwi (TYPE_SIZE (type)); - if (align > MAX_OFILE_ALIGNMENT) - align = MAX_OFILE_ALIGNMENT; - return align; + unsigned HOST_WIDE_INT align = MAX_OFILE_ALIGNMENT; + tree size = TYPE_SIZE (type); + if (tree_fits_uhwi_p (size)) + align = tree_to_uhwi (size); + + return align < MAX_OFILE_ALIGNMENT ? align : MAX_OFILE_ALIGNMENT; } /* The default implementation of diff --git a/gcc/testsuite/c-c++-common/attributes-1.c b/gcc/testsuite/c-c++-common/attributes-1.c index c4b232dad00..b73d31aa5e2 100644 --- a/gcc/testsuite/c-c++-common/attributes-1.c +++ b/gcc/testsuite/c-c++-common/attributes-1.c @@ -4,7 +4,7 @@ void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning ".alloc_size. attribute argument 2 is invalid" } */ void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning ".alloc_size. attribute argument is invalid" } */ -typedef char vec __attribute__((vector_size(bar))); /* { dg-warning "ignored" } */ +typedef char vec __attribute__((vector_size(bar))); void f1(char*) __attribute__((nonnull(bar))); /* { dg-warning ".nonnull. attribute argument is invalid" } */ @@ -14,7 +14,7 @@ void foo(int); void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning ".alloc_size. attribute argument 2 has type .void\\\(int\\\)." } */ void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning ".alloc_size. attribute argument has type .void ?\\\(int\\\)" } */ -typedef char vec __attribute__((vector_size(foo))); /* { dg-warning "ignored" } */ +typedef char vec __attribute__((vector_size(foo))); /* { dg-error ".vector_size. attribute argument value .foo. is not an integer constant" } */ void f1(char*) __attribute__((nonnull(foo))); /* { dg-warning ".nonnull. attribute argument has type .void ?\\\(int\\\)." } */ void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-warning ".nonnull. attribute argument 2 has type .void ?\\\(int\\\)." } */ diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c index a0681fa6980..ec3127794b5 100644 --- a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c +++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c @@ -3,7 +3,7 @@ { dg-skip-if "No section attribute" { { hppa*-*-hpux* } && { ! lp64 } } } { dg-options "-Wall -ftrack-macro-expansion=0" } { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } } - { dg-additional-options "-DSKIP_ALIAS" { target *-*-darwin* } } + { dg-additional-options "-DSKIP_ALIAS" { target *-*-darwin* } } */ #define ATTR(...) __attribute__ ((__VA_ARGS__)) @@ -155,7 +155,8 @@ void test_packed (struct PackedMember *p) A (0, gpak[0].c, packed); A (0, gpak[1].s, packed); A (1, gpak->a, packed); - A (1, (*gpak).a[0], packed); + /* It's the array that's declared packed but not its elements. */ + A (0, (*gpak).a[0], packed); /* The following fails because in C it's represented as INDIRECT_REF (POINTER_PLUS (NOP_EXPR (ADDR_EXPR (gpak)), ...)) @@ -165,7 +166,8 @@ void test_packed (struct PackedMember *p) A (0, p->c, packed); A (0, p->s, packed); A (1, p->a, packed); - A (1, p->a[0], packed); + /* It's the array that's declared packed but not its elements. */ + A (0, p->a[0], packed); /* Similar to the comment above. A (1, *p->a, packed); */ } @@ -218,13 +220,68 @@ void test_vector_size (void) A (1, iv16, vector_size (16)); A (0, iv16, vector_size (32)); + /* Verify that the attribute not detected on an array of vectors + but is detected on its elements. */ + typedef ATTR (vector_size (8)) float afv8_t[4]; + A (0, afv8_t, vector_size); + A (0, afv8_t, vector_size (1)); + A (0, afv8_t, vector_size (2)); + A (0, afv8_t, vector_size (4)); + A (0, afv8_t, vector_size (8)); + A (0, afv8_t, vector_size (16)); + + A (1, __typeof__ ((*(afv8_t*)0)[0]), vector_size); + A (0, __typeof__ ((*(afv8_t*)0)[1]), vector_size (1)); + A (0, __typeof__ ((*(afv8_t*)0)[2]), vector_size (2)); + A (0, __typeof__ ((*(afv8_t*)0)[3]), vector_size (4)); + A (1, __typeof__ ((*(afv8_t*)0)[0]), vector_size (8)); + A (0, __typeof__ ((*(afv8_t*)0)[1]), vector_size (16)); + + A (1, __typeof__ (**(afv8_t*)0), vector_size); + A (0, __typeof__ (**(afv8_t*)0), vector_size (1)); + A (0, __typeof__ (**(afv8_t*)0), vector_size (2)); + A (0, __typeof__ (**(afv8_t*)0), vector_size (4)); + A (1, __typeof__ (**(afv8_t*)0), vector_size (8)); + A (0, __typeof__ (**(afv8_t*)0), vector_size (16)); + ATTR (vector_size (8)) float afv8[4]; - A (1, afv8, vector_size); + A (0, afv8, vector_size); A (0, afv8, vector_size (1)); A (0, afv8, vector_size (2)); A (0, afv8, vector_size (4)); - A (1, afv8, vector_size (8)); + A (0, afv8, vector_size (8)); A (0, afv8, vector_size (16)); + + A (1, afv8[0], vector_size); + A (0, afv8[1], vector_size (1)); + A (0, afv8[2], vector_size (2)); + A (0, afv8[3], vector_size (4)); + A (1, afv8[0], vector_size (8)); + A (0, afv8[1], vector_size (16)); + + A (1, *afv8, vector_size); + A (0, *afv8, vector_size (1)); + A (0, *afv8, vector_size (2)); + A (0, *afv8, vector_size (4)); + A (1, *afv8, vector_size (8)); + A (0, *afv8, vector_size (16)); + + /* sizeof (long double) is 12 on i386. */ + enum { VecSize = 8 * sizeof (long double) }; + ATTR (vector_size (VecSize)) long double aldv[1][2][3]; + A (0, aldv, vector_size); + A (0, aldv[0], vector_size); + A (0, aldv[0][0], vector_size); + A (1, aldv[0][0][0], vector_size); + A (0, aldv[0][0][1], vector_size (VecSize / 2)); + A (1, aldv[0][0][2], vector_size (VecSize)); + + A (0, aldv[0][0][0][0], vector_size); + + A (0, *aldv, vector_size); + A (0, **aldv, vector_size); + A (1, ***aldv, vector_size); + A (1, ***aldv, vector_size (VecSize)); } diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c new file mode 100644 index 00000000000..89cf4f23d47 --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-6.c @@ -0,0 +1,114 @@ +/* PR c/88383 - ICE calling _builtin_has_attribute(r, aligned(N))) + on an overaligned reference r + PR c/89288 - ICE in tree_code_size, at tree.c:865 + { dg-options "-Wall -ftrack-macro-expansion=0" } + { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } } */ + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) + +#define A(expect, sym, attr) \ + typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)] + +typedef ATTR (aligned (8)) int Int8; + +/* The attribute applies to the array, not to the type of its elements. */ +extern ATTR (aligned (8)) char i8arr[]; + +/* The attribute applies to the pointer, not to the type it points to. */ +extern ATTR (aligned (8)) int *ptr; +extern Int8 *i8ptr; + +#if __cplusplus + +/* Similarly here, the attribute applies to the reference, not to its type. */ +extern ATTR (aligned (8)) int &ref; +extern Int8 &i8ref; + +#else + +/* Fake references in C. */ +extern ATTR (aligned (8)) int ref; +Int8 i8ref; + +#endif + +void test (void) +{ + /* Verify that the built-in detects the attribute on the array. */ + A (1, i8arr, aligned); + A (0, i8arr, aligned (1)); + A (0, i8arr, aligned (2)); + A (0, i8arr, aligned (4)); + A (1, i8arr, aligned (8)); + A (0, i8arr, aligned (16)); + + A (0, i8arr + 1, aligned); + A (0, i8arr + 2, aligned (1)); + A (0, i8arr + 3, aligned (8)); + + /* Verify the builtin detects the absence of the attribute on + the elements. */ + A (0, i8arr[0], aligned); + A (0, *i8arr, aligned); + + /* Verify that the built-in doesn't confuse the attribute on + the pointer type with that to the pointed to type. This + also exercises PR c/89288. */ + A (0, (Int8*)0, aligned); + A (0, (int*)0, aligned); + A (0, (void*)0, aligned); + A (0, 0, aligned); + + /* Verify that the built-in detects the attribute on the pointer + itself. */ + A (1, ptr, aligned); + A (0, ptr, aligned (1)); + A (0, ptr, aligned (2)); + A (0, ptr, aligned (4)); + A (1, ptr, aligned (8)); + A (0, ptr, aligned (16)); + + A (0, ptr + 1, aligned); + A (0, ptr + 2, aligned (1)); + A (0, ptr + 3, aligned (8)); + + /* The pointed to type is not declared with attribute aligned. */ + A (0, *ptr, aligned); + A (0, *ptr, aligned (1)); + A (0, *ptr, aligned (2)); + A (0, *ptr, aligned (4)); + A (0, *ptr, aligned (8)); + A (0, *ptr, aligned (16)); + + A (0, *ptr + 1, aligned); + A (0, *ptr + 2, aligned (1)); + A (0, *ptr + 3, aligned (8)); + + /* Verify that the built-in correctly detects the attribute on + the type of the lvalue referenced by the pointer. */ + A (0, i8ptr, aligned); + A (0, i8ptr, aligned (8)); + A (0, i8ptr + 1, aligned); + A (0, i8ptr + 3, aligned (8)); + A (1, *i8ptr, aligned); + A (0, *i8ptr, aligned (1)); + A (0, *i8ptr, aligned (2)); + A (0, *i8ptr, aligned (4)); + A (1, *i8ptr, aligned (8)); + A (0, *i8ptr, aligned (16)); + + /* The reference itself is declared aligned, even though the type + it refers to isn't. But see PR c++/88362. */ + A (1, ref, aligned); + A (0, ref, aligned (1)); + A (0, ref, aligned (2)); + A (0, ref, aligned (4)); + A (1, ref, aligned (8)); + A (0, ref, aligned (16)); + + /* Also verify that assignment expressions are accepted. */ + A (0, ref = 1, aligned); + A (0, ref += 2, aligned (1)); + A (0, ref /= 3, aligned (8)); + +} diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c new file mode 100644 index 00000000000..6ea2e9e7192 --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-has-attribute-7.c @@ -0,0 +1,396 @@ +/* Verify that __builtin_has_attribute detects attributes aligned + and packed in various forms of array dereferencing and indirection + expressions correspondingly to __alignof__. + { dg-do compile } + { dg-options "-Wall -Wno-unused -ftrack-macro-expansion=0" } */ + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define ALIGN(N) ATTR (aligned (N)) + +#define Assert(expr) typedef int _Assert [1 - 2 * !(expr)] + +/* Verify that __builtin_has_attribute (EXPR, align (ALIGN)) returns + the EXPECTed result. When EXPECT is true, verify that the EXPression + has the expected ALIGNment. */ +#define A3(expect, expr, align) do { \ + Assert (!expect || __alignof__ (expr) == align); \ + Assert (expect == __builtin_has_attribute (expr, aligned (align))); \ + } while (0) + +#define A(expect, expr) \ + Assert (expect == __builtin_has_attribute (expr, aligned)) \ + +enum { PA = __alignof__ (void*) }; + +/* Define pointer to pointer types, with different alignments + at each level of indirection. */ +typedef struct S8 { char a[8]; } S8; +typedef ALIGN (8) S8 I8; +typedef ALIGN (16) I8 *P16_I8; +typedef P16_I8 *P_P16_I8; +typedef ALIGN (32) P_P16_I8 *P32_P_P16_I8; +typedef P32_P_P16_I8 *P_P32_P_P16_I8; +typedef ALIGN (64) P_P32_P_P16_I8 *P64_P_P32_P_P16_I8; + +Assert ( 8 == __alignof__ (I8)); +Assert (16 == __alignof__ (P16_I8)); +Assert (PA == __alignof__ (P_P16_I8)); +Assert (32 == __alignof__ (P32_P_P16_I8)); +Assert (PA == __alignof__ (P_P32_P_P16_I8)); +Assert (64 == __alignof__ (P64_P_P32_P_P16_I8)); + + +/* Similar to the pointer of pointers above, define array of array + types, with different alignments at each level of indirection. */ +typedef struct S64 { char a[64]; } S64; +typedef ALIGN (64) S64 I64; +typedef ALIGN (32) I64 A32_I64[3]; +typedef A32_I64 A_A32_I64[5]; +typedef ALIGN (16) A_A32_I64 A16_A_A32_I64[7]; +typedef A16_A_A32_I64 A_A16_A_A32_I64[11]; +typedef ALIGN (8) A_A16_A_A32_I64 A8_A_A16_A_A32_I64[13]; + +Assert (64 == __alignof__ (I64)); +Assert (32 == __alignof__ (A32_I64)); +/* With no explicit alignment, an array of overaligned elements + is considered to have the alignment of its elements. */ +Assert (32 == __alignof__ (A_A32_I64)); +Assert (16 == __alignof__ (A16_A_A32_I64)); +Assert (16 == __alignof__ (A_A16_A_A32_I64)); +Assert ( 8 == __alignof__ (A8_A_A16_A_A32_I64)); + + +void test_arrays (void) +{ + /* Verify that the aligned attribute on each of the composite types + is detected corresponding to the result of __alignof__. */ + A (1, (*(A8_A_A16_A_A32_I64*)0)); + A3 (1, (*(A8_A_A16_A_A32_I64*)0), 8); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8); + /* GCC propagates the user-align bit from element types to their + arrays but it doesn't propagate the attribute itself. The built-in + considers both the bit and the attribute so it succeeds below even + though the referenced type isn't declared with the attribute. */ + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8); + A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0], 16); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 32); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 8); + A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1], 16); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 32); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 16); + A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 32); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 64); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 16); + A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 32); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 64); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 32); + A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 64); + A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 128); + + A8_A_A16_A_A32_I64 a; + A3 (0, a[0], 8); + A3 (1, a[0], 16); + A3 (0, a[0], 32); + A3 (0, a[0][1], 8); + A3 (1, a[0][1], 16); + A3 (0, a[0][1], 32); + A3 (0, a[0][1][2], 16); + A3 (1, a[0][1][2], 32); + A3 (0, a[0][1][2], 64); + A3 (0, a[0][1][2][3], 16); + A3 (1, a[0][1][2][3], 32); + A3 (0, a[0][1][2][3], 64); + A3 (0, a[0][1][2][3][4], 32); + A3 (1, a[0][1][2][3][4], 64); + A3 (0, a[0][1][2][3][4], 128); +} + +void test_pointers (void) +{ + /* Verify that the aligned attribute on each of the composite pointer + types is detected corresponding to the result of __alignof__. */ + A (1, I8); + A3 (0, I8, 4); + A3 (1, I8, 8); + + A (1, P16_I8); + A3 (0, P16_I8, 8); + A3 (1, P16_I8, 16); + + A (0, P_P16_I8); + A3 (0, P_P16_I8, 8); + A3 (0, P_P16_I8, 16); + + A (1, P32_P_P16_I8); + A3 (0, P32_P_P16_I8, 8); + A3 (0, P32_P_P16_I8, 16); + A3 (1, P32_P_P16_I8, 32); + + A (0, P_P32_P_P16_I8); + + A (1, P64_P_P32_P_P16_I8); + A3 (0, P64_P_P32_P_P16_I8, 8); + A3 (0, P64_P_P32_P_P16_I8, 16); + A3 (0, P64_P_P32_P_P16_I8, 32); + A3 (1, P64_P_P32_P_P16_I8, 64); + + + /* Verify that the attribute on each of the composite types is detected + in the type of each of the indirection expressions. */ + A (1, *(P16_I8)0); + A3 (1, *(P16_I8)0, 8); + A3 (0, *(P16_I8)0, 16); + + A (1, *(P_P16_I8)0); + A3 (0, *(P_P16_I8)0, 8); + A3 (1, *(P_P16_I8)0, 16); + + A (0, *(P32_P_P16_I8)0); + A3 (0, *(P32_P_P16_I8)0, 8); + A3 (0, *(P32_P_P16_I8)0, 16); + A3 (0, *(P32_P_P16_I8)0, 32); + + A (1, *(P_P32_P_P16_I8)0); + A3 (1, *(P_P32_P_P16_I8)0, 32); + + A (0, *(P64_P_P32_P_P16_I8)0); + + /* Verify that the attribute on each of the composite types is detected + in the type of each of the subscipting expressions. */ + A (1, ((P16_I8)0)[0]); + A3 (1, ((P16_I8)0)[1], 8); + A3 (0, ((P16_I8)0)[2], 16); + + A (1, ((P_P16_I8)0)[3]); + A3 (0, ((P_P16_I8)0)[4], 8); + A3 (1, ((P_P16_I8)0)[5], 16); + + A (0, ((P32_P_P16_I8)0)[6]); + A3 (0, ((P32_P_P16_I8)0)[7], 8); + A3 (0, ((P32_P_P16_I8)0)[8], 16); + A3 (0, ((P32_P_P16_I8)0)[9], 32); + + A (1, ((P_P32_P_P16_I8)0)[10]); + A3 (1, ((P_P32_P_P16_I8)0)[11], 32); + + A (0, ((P64_P_P32_P_P16_I8)0)[12]); + + + /* Verify that the attribute on each of the composite types is detected + in the type of each of the subscipting expression involving variables. */ + + I8 i8; + P16_I8 p16_i8 = &i8; + P_P16_I8 p_p16_i8 = &p16_i8; + P32_P_P16_I8 p32_p_p16_i8 = &p_p16_i8; + P_P32_P_P16_I8 p_p32_p_p16_i8 = &p32_p_p16_i8; + P64_P_P32_P_P16_I8 p64_p_p32_p_p16_i8 = &p_p32_p_p16_i8; + + A (1, p16_i8[0]); + A3 (1, p16_i8[1], 8); + A3 (0, p16_i8[2], 16); + + A (1, p_p16_i8[3]); + A3 (0, p_p16_i8[4], 8); + A3 (1, p_p16_i8[5], 16); + + A (0, p32_p_p16_i8[6]); + A3 (0, p32_p_p16_i8[7], 8); + A3 (0, p32_p_p16_i8[8], 16); + A3 (0, p32_p_p16_i8[9], 32); + + A (1, p_p32_p_p16_i8[10]); + A3 (1, p_p32_p_p16_i8[11], 32); + + + A (1, p_p16_i8[0][1]); + A3 (1, p_p16_i8[1][2], 8); + A3 (0, p_p16_i8[2][3], 16); + + + A (0, p64_p_p32_p_p16_i8[0]); + + A (1, p64_p_p32_p_p16_i8[0][1]); + A3 (0, p64_p_p32_p_p16_i8[0][2], 16); + A3 (1, p64_p_p32_p_p16_i8[0][3], 32); + A3 (0, p64_p_p32_p_p16_i8[0][4], 64); + + A (0, p64_p_p32_p_p16_i8[0][1][2]); + + A (1, p64_p_p32_p_p16_i8[0][1][2][3]); + A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 8); + A3 (1, p64_p_p32_p_p16_i8[0][1][2][4], 16); + A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 32); + + A (1, p64_p_p32_p_p16_i8[0][1][2][3][4]); + A3 (1, p64_p_p32_p_p16_i8[0][1][2][3][5], 8); + A3 (0, p64_p_p32_p_p16_i8[0][1][2][4][6], 16); + + + /* Same as above but using the indirection expression. */ + A (0, *p64_p_p32_p_p16_i8); + + A (1, **p64_p_p32_p_p16_i8); + A3 (0, **p64_p_p32_p_p16_i8, 16); + A3 (1, **p64_p_p32_p_p16_i8, 32); + A3 (0, **p64_p_p32_p_p16_i8, 64); + + A (0, ***p64_p_p32_p_p16_i8); + + A (1, ****p64_p_p32_p_p16_i8); + A3 (0, ****p64_p_p32_p_p16_i8, 8); + A3 (1, ****p64_p_p32_p_p16_i8, 16); + A3 (0, ****p64_p_p32_p_p16_i8, 32); + + A (1, *****p64_p_p32_p_p16_i8); + A3 (1, *****p64_p_p32_p_p16_i8, 8); + A3 (0, *****p64_p_p32_p_p16_i8, 16); +} + + +S8 f_S8 (void); +I8 f_I8 (void); +P16_I8 f_P16_I8 (void); +P_P16_I8 f_P_P16_I8 (void); +P32_P_P16_I8 f_P32_P_P16_I8 (void); +P_P32_P_P16_I8 f_P_P32_P_P16_I8 (void); +P64_P_P32_P_P16_I8 f_P64_P_P32_P_P16_I8 (void); + +void test_function_call (void) +{ + /* Verify that the aligned attribute on each of the composite pointer + types returned by the functions is detected corresponding to + the result of __alignof__. */ + + A (0, f_S8 ()); + + A (1, f_I8 ()); + A3 (1, f_I8 (), 8); + A3 (0, f_I8 (), 16); + + A (1, f_P16_I8 ()); + A3 (0, f_P16_I8 (), 8); + A3 (1, f_P16_I8 (), 16); + A3 (0, f_P16_I8 (), 32); + + A (1, *f_P16_I8 ()); + A3 (1, *f_P16_I8 (), 8); + A3 (0, *f_P16_I8 (), 16); + + A (0, f_P_P16_I8 ()); + + A (1, *f_P_P16_I8 ()); + A3 (0, *f_P_P16_I8 (), 8); + A3 (1, *f_P_P16_I8 (), 16); + A3 (0, *f_P_P16_I8 (), 32); + + A (1, **f_P_P16_I8 ()); + A3 (1, **f_P_P16_I8 (), 8); + A3 (0, **f_P_P16_I8 (), 16); + A3 (0, **f_P_P16_I8 (), 32); +} + + +void test_compound_literal (void) +{ + A (0, (S8){ }); + + A (1, (I8){ }); + A3 (1, (I8){ }, 8); + A3 (0, (I8){ }, 16); + + A (1, (I64){ }); + A3 (0, (I64){ }, 8); + A3 (0, (I64){ }, 16); + A3 (0, (I64){ }, 32); + A3 (1, (I64){ }, 64); + + A (1, (A32_I64){ 0 }); + A3 (0, (A32_I64){ 0 }, 8); + A3 (0, (A32_I64){ 0 }, 16); + A3 (1, (A32_I64){ 0 }, 32); + A3 (0, (A32_I64){ 0 }, 64); + + A (1, ((A32_I64){ 0 })[0]); + A3 (0, ((A32_I64){ 0 })[0], 8); + A3 (0, ((A32_I64){ 0 })[0], 16); + A3 (0, ((A32_I64){ 0 })[0], 32); + A3 (1, ((A32_I64){ 0 })[0], 64); +} + + +void test_ternary_expression (int i) +{ + A (0, (0 ? (S8){ } : (S8){ })); + + A (1, (1 ? (I8){ } : (I8){ })); + A3 (1, (2 ? (I8){ } : (I8){ }), 8); + A3 (0, (3 ? (I8){ } : (I8){ }), 16); + + A (1, (4 ? (I64){ } : (I64){ })); + A3 (0, (5 ? (I64){ } : (I64){ }), 8); + A3 (0, (6 ? (I64){ } : (I64){ }), 16); + A3 (0, (7 ? (I64){ } : (I64){ }), 32); + A3 (1, (8 ? (I64){ } : (I64){ }), 64); + +#if !__cplusplus + /* Suppress -Wc++-compat warning: converting an array compound literal + to a pointer is ill-formed in C++ */ +# pragma GCC diagnostic ignored "-Wc++-compat" + + A (0, (9 ? (A32_I64){ } : (A32_I64){ })); + A3 (0, (i ? (A32_I64){ } : (A32_I64){ }), 8); + A3 (0, (i++ ? (A32_I64){ } : (A32_I64){ }), 16); + A3 (0, (++i ? (A32_I64){ } : (A32_I64){ }), 32); + A3 (0, (!i ? (A32_I64){ } : (A32_I64){ }), 64); + + A (1, (0 ? (A32_I64){ } : (A32_I64){ })[0]); + A3 (0, (1 ? (A32_I64){ } : (A32_I64){ })[1], 8); + A3 (0, (2 ? (A32_I64){ } : (A32_I64){ })[2], 16); + A3 (0, (3 ? (A32_I64){ } : (A32_I64){ })[3], 32); + A3 (1, (3 ? (A32_I64){ } : (A32_I64){ })[i], 64); +#endif +} + + +void test_comma_expression (int i) +{ +#if __cplusplus + /* In C++, the type of the comma expressions whose operand is an array + is the array itself with any attributes it was defined with. */ +# define R 1 +#else + /* In C, the type of the comma expressions whose operand is an array + is a pointer type that does not include any attributes the array + was defined with. */ +# define R 0 +/* Suppress -Wc++-compat warning: converting an array compound literal + to a pointer is ill-formed in C++ + G++ accepts the conversion in unevaluated contexts without a warning. */ +# pragma GCC diagnostic ignored "-Wc++-compat" +#endif + + A (0, (0, (S8){ })); + + A (1, (0, (I8){ })); + A3 (1, (1, (I8){ }), 8); + A3 (0, (2, (I8){ }), 16); + + A (1, (3, (I64){ })); + A3 (0, (4, (I64){ }), 8); + A3 (0, (5, (I64){ }), 16); + A3 (0, (6, (I64){ }), 32); + A3 (1, (7, (I64){ }), 64); + + A (R, (8, (A32_I64){ })); + A3 (0, (9, (A32_I64){ }), 8); + A3 (0, ((void)0, (A32_I64){ }), 16); + A3 (R, ((I64){ },(A32_I64){ }), 32); + A3 (0, (0, (A32_I64){ }), 64); + + A (1, (1, ((A32_I64){ })[0])); + A3 (0, (2, ((A32_I64){ })[0]), 8); + A3 (0, (i++, ((A32_I64){ })[0]), 16); + A3 (0, (++i, ((A32_I64){ })[0]), 32); + A3 (1, (i = 0, ((A32_I64){ })[0]), 64); +} diff --git a/gcc/testsuite/gcc.dg/attr-vector_size.c b/gcc/testsuite/gcc.dg/attr-vector_size.c new file mode 100644 index 00000000000..00be26accd5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-vector_size.c @@ -0,0 +1,69 @@ +/* PR middle-end/89797 - ICE on a vector_size (1LU << 33) int variable + PR c/89798 - excessive vector_size silently accepted and truncated + { dg-do compile { target int32plus } } + { dg-options "-Wall -Wno-unused" } */ + +#define ASSERT(e) _Static_assert (e, #e) +#define VEC(N) __attribute__ ((vector_size (N))) +#define POW2(N) (1LLU << N) +#define CAT(a, b) a ## b +#define CONCAT(a, b) CAT (a, b) + +#define DEFVEC(storage, N) \ + typedef VEC (POW2 (N)) char CONCAT (Vec, N); \ + storage CONCAT (Vec, N) CONCAT (v, N); \ + ASSERT (sizeof (CONCAT (Vec, N)) == POW2 (N)); \ + ASSERT (sizeof (CONCAT (v, N)) == POW2 (N)) + +DEFVEC (extern, 27); +DEFVEC (extern, 28); +DEFVEC (extern, 29); +DEFVEC (extern, 30); + +#if __SIZEOF_SIZE_T__ > 4 + +DEFVEC (extern, 31); +DEFVEC (extern, 32); +DEFVEC (extern, 33); +DEFVEC (extern, 34); +DEFVEC (extern, 60); +DEFVEC (extern, 61); +DEFVEC (extern, 62); + +VEC (POW2 (63)) char v63; /* { dg-error "'vector_size' attribute argument value '9223372036854775808' exceeds 9223372036854775807" "LP64" { target lp64 } } */ + +#else + +VEC (POW2 (31)) char v31; /* { dg-error "'vector_size' attribute argument value '2147483648' exceeds 2147483647" "ILP32" { target ilp32 } } */ + +VEC (POW2 (32)) char v32; /* { dg-error "'vector_size' attribute argument value '4294967296' exceeds 2147483647" "ILP32" { target ilp32 } } */ + +#endif + +void test_local_scope (void) +{ + DEFVEC (auto, 27); + DEFVEC (auto, 28); + DEFVEC (auto, 29); + DEFVEC (auto, 30); + +#if __SIZEOF_SIZE_T__ > 4 + + DEFVEC (auto, 31); + DEFVEC (auto, 32); + DEFVEC (auto, 33); + DEFVEC (auto, 34); + DEFVEC (auto, 60); + DEFVEC (auto, 61); + DEFVEC (auto, 62); + + VEC (POW2 (63)) char v63; /* { dg-error "'vector_size' attribute argument value '9223372036854775808' exceeds 9223372036854775807" "LP64" { target lp64 } } */ + +#else + + VEC (POW2 (31)) char v31; /* { dg-error "'vector_size' attribute argument value '2147483648' exceeds 2147483647" "ILP32" { target ilp32 } } */ + + VEC (POW2 (32)) char v32; /* { dg-error "'vector_size' attribute argument value '4294967296' exceeds 2147483647" "ILP32" { target ilp32 } } */ + +#endif +} diff --git a/gcc/testsuite/gcc.dg/pr25559.c b/gcc/testsuite/gcc.dg/pr25559.c index 7879a1558b6..a8bce657b1c 100644 --- a/gcc/testsuite/gcc.dg/pr25559.c +++ b/gcc/testsuite/gcc.dg/pr25559.c @@ -2,7 +2,7 @@ /* { dg-do compile } */ #define vs(n) __attribute__((vector_size (n))) -int vs (-1) a; /* { dg-warning "attribute ignored" } */ +int vs (-1) a; /* { dg-error ".vector_size. attribute argument value '-1' is negative" } */ int vs (0) b; /* { dg-error "zero vector size" } */ int vs (1) c; /* { dg-error "multiple of component size" } */ int vs (sizeof (int) / 2) d; /* { dg-error "multiple of component size" } */ diff --git a/gcc/tree.h b/gcc/tree.h index 0e8e8dff876..94a810694a5 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3741,7 +3741,7 @@ TYPE_VECTOR_SUBPARTS (const_tree node) return res; } else - return 1 << precision; + return (unsigned HOST_WIDE_INT)1 << precision; } /* Set the number of elements in VECTOR_TYPE NODE to SUBPARTS, which must