Make use of new attribute access infrastructure in -Wuninitialized (PR 50584).
authorMartin Sebor <msebor@redhat.com>
Sat, 19 Sep 2020 23:30:32 +0000 (17:30 -0600)
committerMartin Sebor <msebor@redhat.com>
Sat, 19 Sep 2020 23:34:31 +0000 (17:34 -0600)
gcc/ChangeLog:

* tree-ssa-uninit.c (maybe_warn_pass_by_reference): Handle attribute
access internal representation of arrays.

gcc/testsuite/ChangeLog:

* gcc.dg/uninit-37.c: New test.

gcc/testsuite/gcc.dg/uninit-37.c [new file with mode: 0644]
gcc/tree-ssa-uninit.c

diff --git a/gcc/testsuite/gcc.dg/uninit-37.c b/gcc/testsuite/gcc.dg/uninit-37.c
new file mode 100644 (file)
index 0000000..b8c49ad
--- /dev/null
@@ -0,0 +1,154 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
+   Verify that -Wuninitialized and -Wmaybe-uninitialized trigger (or don't)
+   when passing uninitialized variables by reference to functions declared
+   with or without attribute access and with (or without) const qualified
+   arguments of array, VLA, or pointer types.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NONE    /* none */
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+#define X(...)  __attribute__ ((access (none, __VA_ARGS__)))
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y)    CONCAT (x, y)
+#define UNIQ(pfx)    CAT (pfx, __LINE__)
+
+extern void sink (void*);
+
+
+#define T1(attr, name, type)                   \
+  void UNIQ (CAT (test_, name))(void) {                \
+    extern attr void UNIQ (name)(type);                \
+    int x;                                     \
+    UNIQ (name)(&x);                           \
+    sink (&x);                                 \
+  }
+
+#define T2(attr, name, types)                  \
+  void UNIQ (CAT (test_, name))(void) {                \
+    extern attr void UNIQ (name)(types);       \
+    int x;                                     \
+    UNIQ (name)(1, &x);                                \
+    sink (&x);                                 \
+  }
+
+
+typedef int IA_[];
+typedef const int CIA_[];
+
+T1 (NONE,   fia_,   IA_);
+T1 (NONE,   fcia_,  CIA_);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia_, IA_);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia_, IA_);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia_, IA_);
+T1 (X (1),  fxia_,  IA_);
+
+
+typedef int IA1[1];
+typedef const int CIA1[1];
+
+T1 (NONE,   fia1,   IA1);
+T1 (NONE,   fcia1,  CIA1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia1, IA1);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia1, IA1);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia1, IA1);
+T1 (X (1),  fxia1,  IA1);
+
+
+#define IARS1  int[restrict static 1]
+#define CIARS1 const int[restrict static 1]
+
+T1 (NONE,   fiars1,   IARS1);
+T1 (NONE,   fciars1,  CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiars1, IARS1);
+T1 (X (1),  fxiars1,  IARS1);
+
+
+#define IAS1  int[static 1]
+#define CIAS1 const int[static 1]
+
+T1 (NONE,   fias1,   IAS1);
+T1 (NONE,   fcias1,  CIAS1);   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froias1, IAS1);    // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwias1, IAS1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoias1, IAS1);
+T1 (X (1),  fxias1,  IAS1);
+
+
+#define IAX  int[*]
+#define CIAX const int[*]
+
+T1 (NONE,   fiax,   IAX);
+T1 (NONE,   fciax,  CIAX);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiax, IAX);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiax, IAX);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiax, IAX);
+T1 (X (1),  fxiax,  IAX);
+
+
+#define IAN  int n, int[n]
+#define CIAN int n, const int[n]
+
+T2 (NONE,      fian,   IAN);
+T2 (NONE,      fcian,  CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (RO (2, 1), froian, IAN);  // { dg-warning "\\\[-Wuninitialized" }
+T2 (RW (2, 1), frwian, IAN);  // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (WO (2, 1), fwoian, IAN);
+T2 (X (2, 1),  fxian,  IAN);
+
+
+typedef int* IP;
+typedef const int* CIP;
+
+T1 (NONE,   fip,   IP);
+T1 (NONE,   fcip,  CIP);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froip, IP);      // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwip, IP);      // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoip, IP);
+T1 (X (1),  fxip,  IP);
+
+
+/* Verify that the notes printed after the warning mention attribute
+   access only when the attribute is explicitly used in the declaration
+   and not otherwise.  */
+
+void test_note_cst_restrict (void)
+{
+  extern void
+    fccar (const char[restrict]);   // { dg-message "by argument 1 of type 'const char\\\[restrict]' to 'fccar'" "note" }
+
+  char a[1];                  // { dg-message "'a' declared here" "note" }
+  fccar (a);                  // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_vla (int n)
+{
+  extern void
+    fccvla (const char[n]);   // { dg-message "by argument 1 of type 'const char\\\[n]' to 'fccvla'" "note" }
+
+  char a[2];                  // { dg-message "'a' declared here" "note" }
+  fccvla (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_ro (void)
+{
+  extern RO (1) void
+    frocar (char[restrict]);  // { dg-message "in a call to 'frocar' declared with attribute 'access \\\(read_only, 1\\\)'" "note" }
+
+  char a[3];                  // { dg-message "'a' declared here" "note" }
+  frocar (a);                 // { dg-warning "'a' is used uninitialized" }
+}
+
+void test_note_rw (void)
+{
+  extern RW (1) void
+    frwcar (char[restrict]);  // { dg-message "in a call to 'frwcar' declared with attribute 'access \\\(read_write, 1\\\)'" "note" }
+
+  char a[4];                  // { dg-message "'a' declared here" "note" }
+  frwcar (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
index 2cef5f3..0447bb2 100644 (file)
@@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define INCLUDE_STRING
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -472,7 +473,8 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
      read_only.  */
   const bool save_always_executed = wlims.always_executed;
 
-  /* Map of attribute access specifications for function arguments.  */
+  /* Initialize a map of attribute access specifications for arguments
+     to the function function call.  */
   rdwr_map rdwr_idx;
   init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
 
@@ -488,12 +490,17 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
        continue;
 
       tree access_size = NULL_TREE;
-      attr_access *access = rdwr_idx.get (argno - 1);
+      const attr_access* access = rdwr_idx.get (argno - 1);
       if (access)
        {
          if (access->mode == access_none
              || access->mode == access_write_only)
            continue;
+
+         if (access->mode == access_deferred
+             && !TYPE_READONLY (TREE_TYPE (argtype)))
+           continue;
+
          if (save_always_executed && access->mode == access_read_only)
            /* Attribute read_only arguments imply read access.  */
            wlims.always_executed = true;
@@ -524,45 +531,48 @@ maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
       if (!argbase)
        continue;
 
-      if (access)
+      if (access && access->mode != access_deferred)
        {
-         const char* const mode = (access->mode == access_read_only
-                                   ? "read_only" : "read_write");
-         char attrstr[80];
-         int n = sprintf (attrstr, "access (%s, %u", mode, argno);
-         if (access->sizarg < UINT_MAX)
-           sprintf (attrstr + n, ", %u)", access->sizarg);
-         else
-           strcpy (attrstr + n, ")");
+         const char* const access_str =
+           TREE_STRING_POINTER (access->to_external_string ());
 
          if (fndecl)
            {
              location_t loc = DECL_SOURCE_LOCATION (fndecl);
-             inform (loc, "in a call to %qD declared "
-                     "with attribute %<access (%s, %u)%> here",
-                     fndecl, mode, argno);
+             inform (loc, "in a call to %qD declared with "
+                     "attribute %<%s%> here", fndecl, access_str);
            }
          else
            {
              /* Handle calls through function pointers.  */
              location_t loc = gimple_location (stmt);
              inform (loc, "in a call to %qT declared with "
-                     "attribute %<access (%s, %u)%>",
-                     fntype, mode, argno);
+                     "attribute %<%s%>", fntype, access_str);
            }
        }
-      else if (fndecl)
-       {
-         location_t loc = DECL_SOURCE_LOCATION (fndecl);
-         inform (loc, "by argument %u of type %qT to %qD declared here",
-                 argno, argtype, fndecl);
-       }
       else
        {
-         /* Handle calls through function pointers.  */
-         location_t loc = gimple_location (stmt);
-         inform (loc, "by argument %u of type %qT to %qT",
-                 argno, argtype, fntype);
+         /* For a declaration with no relevant attribute access create
+            a dummy object and use the formatting function to avoid
+            having to complicate things here.  */
+         attr_access ptr_access = { };
+         if (!access)
+           access = &ptr_access;
+         const std::string argtypestr = access->array_as_string (argtype);
+         if (fndecl)
+           {
+             location_t loc (DECL_SOURCE_LOCATION (fndecl));
+             inform (loc, "by argument %u of type %<%s%> to %qD "
+                     "declared here",
+                     argno, argtypestr.c_str (), fndecl);
+           }
+         else
+           {
+             /* Handle calls through function pointers.  */
+             location_t loc (gimple_location (stmt));
+             inform (loc, "by argument %u of type %<%s%> to %qT",
+                     argno, argtypestr.c_str (), fntype);
+           }
        }
 
       if (DECL_P (argbase))