PR c/88383 - ICE calling __builtin_has_attribute on a reference gcc/c-family/ChangeLog: PR c/88383 * c-attribs.c (validate_attribute): Handle expressions. (has_attribute): Handle types referenced by expressions. Avoid considering array attributes in ARRAY_REF expressions . gcc/cp/ChangeLog: PR c/88383 * parser.c (cp_parser_has_attribute_expression): Handle assignment expressions. gcc/testsuite/ChangeLog: PR c/88383 * c-c++-common/builtin-has-attribute-4.c: Adjust expectations. * c-c++-common/builtin-has-attribute-6.c: New test. Index: gcc/c-family/c-attribs.c =================================================================== --- gcc/c-family/c-attribs.c (revision 266799) +++ gcc/c-family/c-attribs.c (working copy) @@ -3994,8 +3994,10 @@ validate_attribute (location_t atloc, tree oper, t 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)); /* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes believe the DECL declared above is at file scope. (See bug 87526.) */ @@ -4040,11 +4042,17 @@ has_attribute (location_t atloc, tree t, tree attr 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 @@ -4095,7 +4103,8 @@ has_attribute (location_t atloc, tree t, tree attr } else { - atlist = TYPE_ATTRIBUTES (TREE_TYPE (expr)); + type = TREE_TYPE (expr); + atlist = TYPE_ATTRIBUTES (type); done = true; } Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 266799) +++ gcc/cp/parser.c (working copy) @@ -8480,9 +8480,9 @@ cp_parser_has_attribute_expression (cp_parser *par 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); /* Go back to evaluating expressions. */ --cp_unevaluated_operand; Index: gcc/testsuite/c-c++-common/builtin-has-attribute-4.c =================================================================== --- gcc/testsuite/c-c++-common/builtin-has-attribute-4.c (revision 266799) +++ gcc/testsuite/c-c++-common/builtin-has-attribute-4.c (working copy) @@ -151,7 +151,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)), ...)) @@ -161,7 +162,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); */ } Index: gcc/testsuite/c-c++-common/builtin-has-attribute-6.c =================================================================== --- gcc/testsuite/c-c++-common/builtin-has-attribute-6.c (nonexistent) +++ gcc/testsuite/c-c++-common/builtin-has-attribute-6.c (working copy) @@ -0,0 +1,105 @@ +/* PR c/88383 - ICE calling _builtin_has_attribute(r, aligned(N))) + on an overaligned reference r + { 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 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)); + +}