mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-11 13:01:20 +08:00
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:
parent
726e292d41
commit
649e174102
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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; )
|
||||
{
|
||||
|
@ -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
|
||||
|
109
gcc/testsuite/g++.dg/ext/attr-access.C
Normal file
109
gcc/testsuite/g++.dg/ext/attr-access.C
Normal 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" }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user