This is a repost of a patch for PR 88383 updated to also fix the just reported PR 89288 (the original patch only partially handles this case). The review of the first patch was derailed by questions about the design of the built-in so the fix for the ICE was never approved. I think the ICEs should be fixed for GCC 9 and any open design questions should be dealt with independently.
Martin The patch for PR 88383 was originally posted last December: https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00337.html
PR c/88383 - ICE calling __builtin_has_attribute on a reference PR c/89288 - ICE in tree_code_size, at tree.c:865 gcc/c-family/ChangeLog: PR c/88383 PR c/89288 * 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 PR c/89288 * parser.c (cp_parser_has_attribute_expression): Handle assignment expressions. gcc/testsuite/ChangeLog: PR c/88383 PR c/89288 * 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 268774) +++ gcc/c-family/c-attribs.c (working copy) @@ -4032,8 +4032,12 @@ validate_attribute (location_t atloc, tree oper, t if (TYPE_P (oper)) tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, oper); + 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 - tmpdecl = build_decl (atloc, TREE_CODE (oper), tmpid, TREE_TYPE (oper)); + return false; /* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes believe the DECL declared above is at file scope. (See bug 87526.) */ @@ -4042,7 +4046,7 @@ validate_attribute (location_t atloc, tree oper, t 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." */ @@ -4078,11 +4082,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 @@ -4133,7 +4143,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 268774) +++ gcc/cp/parser.c (working copy) @@ -8542,9 +8542,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); STRIP_ANY_LOCATION_WRAPPER (oper); Index: gcc/testsuite/c-c++-common/builtin-has-attribute-4.c =================================================================== --- gcc/testsuite/c-c++-common/builtin-has-attribute-4.c (revision 268774) +++ gcc/testsuite/c-c++-common/builtin-has-attribute-4.c (working copy) @@ -154,7 +154,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)), ...)) @@ -164,7 +165,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,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)); + +}