PR middle-end/92721 - checking ICE on attribute access redeclaration

gcc/c-family/ChangeLog:

	PR c++/92721
	* c-attribs.c (append_access_attrs): Correctly handle attribute.
	(handle_access_attribute): Same.

gcc/ChangeLog:

	PR c++/92721
	* calls.c (init_attr_rdwr_indices): Correctly handle attribute.

gcc/testsuite/ChangeLog:

	PR c++/92721
	g++.dg/ext/attr-access.C: New test.
This commit is contained in:
Martin Sebor 2020-03-01 17:58:45 -07:00
parent 726e292d41
commit 649e174102
6 changed files with 149 additions and 2 deletions

View File

@ -1,3 +1,8 @@
2020-03-01 Martin Sebor <msebor@redhat.com>
PR c++/92721
* calls.c (init_attr_rdwr_indices): Correctly handle attribute.
2020-03-01 Martin Sebor <msebor@redhat.com>
PR middle-end/93829

View File

@ -1,3 +1,9 @@
2020-03-01 Martin Sebor <msebor@redhat.com>
PR c++/92721
* c-attribs.c (append_access_attrs): Correctly handle attribute.
(handle_access_attribute): Same.
2020-02-25 Jakub Jelinek <jakub@redhat.com>
PR c/93858

View File

@ -3845,6 +3845,10 @@ append_access_attrs (tree t, tree attrs, const char *attrstr,
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);
@ -3971,11 +3975,20 @@ handle_access_attribute (tree *node, tree name, tree args,
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);
@ -4170,6 +4183,7 @@ handle_access_attribute (tree *node, tree name, tree args,
/* 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])
@ -4182,11 +4196,14 @@ handle_access_attribute (tree *node, tree name, tree args,
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;
}

View File

@ -1891,8 +1891,13 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
if (!access)
return;
/* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE
is the attribute argument's value. */
tree mode = TREE_VALUE (access);
gcc_assert (TREE_CODE (mode) == TREE_LIST);
mode = TREE_VALUE (mode);
gcc_assert (TREE_CODE (mode) == STRING_CST);
const char *modestr = TREE_STRING_POINTER (mode);
for (const char *m = modestr; *m; )
{

View File

@ -1,3 +1,8 @@
2020-03-01 Martin Sebor <msebor@redhat.com>
PR c++/92721
g++.dg/ext/attr-access.C: New test.
2020-03-01 Martin Sebor <msebor@redhat.com>
PR middle-end/93926

View File

@ -0,0 +1,109 @@
/* 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" }
}