PR middle-end/92721 - checking ICE on attribute access redeclaration
authorMartin Sebor <msebor@redhat.com>
Mon, 2 Mar 2020 00:58:45 +0000 (17:58 -0700)
committerMartin Sebor <msebor@redhat.com>
Mon, 2 Mar 2020 00:58:45 +0000 (17:58 -0700)
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.

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/calls.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/attr-access.C [new file with mode: 0644]

index f186408e1045e2a69381ffe7822ae08394261db1..74a8b691ac9600c4e2697f6d4af5c5e7e359c4a0 100644 (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
index e47af7fb24994464e409a55e36df9862208acb90..434bac6408da27c846931b5bd3335623667bc5c6 100644 (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
index 2ea5fd5ff46802c4cb3de9faf926575ab62bd233..9abf81d02481010de0eba15eaba22d63344209ab 100644 (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;
 }
 
index d1c531711767d5ff6de336108db4a49abd8a9ebb..4c3a8f3c215d58918c07f3bd146692f946282d8b 100644 (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; )
     {
index 401c648819d40d3d5e1d1657be90968261226fdc..5c43024244558b7a59e812250e260b7142f22ef3 100644 (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
diff --git a/gcc/testsuite/g++.dg/ext/attr-access.C b/gcc/testsuite/g++.dg/ext/attr-access.C
new file mode 100644 (file)
index 0000000..fcb54cd
--- /dev/null
@@ -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" }
+}