This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] handle expressions in __builtin_has_attribute (PR 88383)
- From: Martin Sebor <msebor at gmail dot com>
- To: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 5 Dec 2018 20:55:56 -0700
- Subject: [PATCH] handle expressions in __builtin_has_attribute (PR 88383)
The __builtin_has_attribute function fails with an ICE when
its first argument is an expression such as INDIRECT_REF, or
many others. The code simply assumes it's either a type or
a decl. The attached patch corrects this oversight.
While testing the fix I also noticed the C++ front end expects
the first operand to be a unary expression, which causes most
other kinds of expressions to be rejected. The patch fixes
that as well.
Finally, while testing the fix even more I realized that
the built-in considers the underlying array itself in ARRAY_REF
expressions rather than its type, which leads to inconsistent
results for overaligned arrays (it's the array itself that's
overaligned, not its elements). So I fixed that too and
adjusted the one test designed to verify this.
Tested on x86_64-linux.
Martin
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));
+
+}