if (tree acs = lookup_attribute ("access", attrs))
{
+ /* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE
+ is the attribute argument's value. */
+ acs = TREE_VALUE (acs);
+ gcc_assert (TREE_CODE (acs) == TREE_LIST);
acs = TREE_VALUE (acs);
gcc_assert (TREE_CODE (acs) == STRING_CST);
return NULL_TREE;
}
+ tree access_mode = TREE_VALUE (args);
+ if (TREE_CODE (access_mode) == STRING_CST)
+ {
+ /* This must be a recursive call to handle the condensed internal
+ form of the attribute (see below). Since all validation has
+ been done simply return here, accepting the attribute as is. */
+ *no_add_attrs = false;
+ return NULL_TREE;
+ }
+
/* Set to true when the access mode has the form of a function call
as in 'attribute (read_only (1, 2))'. That's an easy mistake to
make and so worth a special diagnostic. */
bool funcall = false;
- tree access_mode = TREE_VALUE (args);
if (TREE_CODE (access_mode) == CALL_EXPR)
{
access_mode = CALL_EXPR_FN (access_mode);
/* Replace any existing access attribute specification with
the concatenation above. */
attrs = remove_attribute (IDENTIFIER_POINTER (name), attrs);
+ new_attrs = tree_cons (NULL_TREE, new_attrs, NULL_TREE);
new_attrs = tree_cons (name, new_attrs, attrs);
if (node[1])
return NULL_TREE;
attrs = remove_attribute (IDENTIFIER_POINTER (name), attrs);
+ new_attrs = tree_cons (NULL_TREE, new_attrs, NULL_TREE);
new_attrs = tree_cons (name, new_attrs, attrs);
TYPE_ATTRIBUTES (TREE_TYPE (node[1])) = new_attrs;
}
- TYPE_ATTRIBUTES (*node) = new_attrs;
+ /* Recursively call self to "replace" the documented/external form
+ of the attribute with the condensend internal form. */
+ decl_attributes (node, new_attrs, flags);
return NULL_TREE;
}
--- /dev/null
+/* PR middle-end/92721 - checking ICE on attribute access redeclaration
+ Test to verify the handling of attribute access combining multiple
+ declarations of the same function.
+ { dg-do compile }
+ { dg-options "-O0 -Wall -ftrack-macro-expansion=0" } */
+
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+
+typedef __INT32_TYPE__ int32_t;
+
+void RO (1) RO (1) rop1_ror2 (const int32_t*, const int32_t&);
+void RO (1) RO (2) rop1_ror2 (const int32_t*, const int32_t&);
+void RO (2) RO (1) rop1_ror2 (const int32_t*, const int32_t&);
+void RO (2) RO (2) rop1_ror2 (const int32_t*, const int32_t&);
+
+void RW (1) RW (1) rdwrp1_rdwrr2 (int32_t*, int32_t&);
+void RW (1) RW (2) rdwrp1_rdwrr2 (int32_t*, int32_t&);
+void RW (2) RW (1) rdwrp1_rdwrr2 (int32_t*, int32_t&);
+void RW (2) RW (2) rdwrp1_rdwrr2 (int32_t*, int32_t&);
+
+void WO (1) WO (1) wop1_wor2 (int32_t*, int32_t&);
+void WO (1) WO (2) wop1_wor2 (int32_t*, int32_t&);
+void WO (2) WO (1) wop1_wor2 (int32_t*, int32_t&);
+void WO (2) WO (2) wop1_wor2 (int32_t*, int32_t&);
+
+
+// Verify that everything works even with no optimization.
+
+void call_rop1_ror2_O0 (void)
+{
+ const int32_t x[1] = { };
+
+ rop1_ror2 (x, x[0]);
+ rop1_ror2 (x, x[1]); // { dg-warning "reading 4 bytes from a region of size 0" }
+ rop1_ror2 (x + 1, x[0]); // { dg-warning "reading 4 bytes from a region of size 0" }
+}
+
+void call_rdwrp1_rdwrr2_O0 (void)
+{
+ int32_t x[1];
+
+ rdwrp1_rdwrr2 (x, x[0]);
+ rdwrp1_rdwrr2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" }
+ rdwrp1_rdwrr2 (x + 1, x[0]); // { dg-warning "writing 4 bytes into a region of size 0" }
+}
+
+void call_wop1_wor2_O0 (void)
+{
+ int32_t x[1];
+
+ wop1_wor2 (x, x[0]);
+ wop1_wor2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" }
+ wop1_wor2 (x + 1, x[0]); // { dg-warning "writing 4 bytes into a region of size 0" }
+}
+
+
+// Verify that everything still works with -O1.
+
+#pragma GCC optimize "1"
+
+void call_rop1_ror2_O1 (void)
+{
+ const int32_t x[1] = { 1 };
+ const int32_t *p0 = x, &r0 = x[0];
+ const int32_t *p1 = (const int32_t*)((const char*)p0 + 1);
+ const int32_t &r2 = *(const int32_t*)((const char*)p1 + 1);
+
+ rop1_ror2 (x, x[0]);
+ rop1_ror2 (x, x[1]); // { dg-warning "reading 4 bytes from a region of size 0" }
+ rop1_ror2 (x + 1, x[0]); // { dg-warning "reading 4 bytes from a region of size 0" }
+
+ rop1_ror2 (p0, r0);
+ rop1_ror2 (p0, r2); // { dg-warning "reading 4 bytes from a region of size 2" }
+ rop1_ror2 (p1, r0); // { dg-warning "reading 4 bytes from a region of size 3" }
+}
+
+void call_rdwrp1_rdwrr2_O1 (void)
+{
+ int32_t x[1];
+ int32_t *p0 = x, &r0 = x[0];
+ int32_t *p1 = (int32_t*)((char*)p0 + 1);
+ int32_t &r2 = *(int32_t*)((char*)p1 + 1);
+
+ rdwrp1_rdwrr2 (x, x[0]);
+ rdwrp1_rdwrr2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" }
+ rdwrp1_rdwrr2 (x + 1, x[0]); // { dg-warning "writing 4 bytes into a region of size 0" }
+
+ rdwrp1_rdwrr2 (p0, r0);
+ rdwrp1_rdwrr2 (p0, r2); // { dg-warning "writing 4 bytes into a region of size 2" }
+ rdwrp1_rdwrr2 (p1, r0); // { dg-warning "writing 4 bytes into a region of size 3" }
+}
+
+void call_wop1_wor2_O1 (void)
+{
+ int32_t x[1];
+ int32_t *p0 = x, &r0 = x[0];
+ int32_t *p1 = (int32_t*)((char*)p0 + 1);
+ int32_t &r2 = *(int32_t*)((char*)p1 + 1);
+
+ wop1_wor2 (x, x[0]);
+ wop1_wor2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" }
+ wop1_wor2 (x + 1, x[0]); // { dg-warning "writing 4 bytes into a region of size 0" }
+
+ wop1_wor2 (p0, r0);
+ wop1_wor2 (p0, r2); // { dg-warning "writing 4 bytes into a region of size 2" }
+ wop1_wor2 (p1, r0); // { dg-warning "writing 4 bytes into a region of size 3" }
+}