Implement a solution for PR middle-end/10138 and PR middle-end/95136.
authorMartin Sebor <msebor@redhat.com>
Thu, 4 Jun 2020 22:06:10 +0000 (16:06 -0600)
committerMartin Sebor <msebor@redhat.com>
Thu, 4 Jun 2020 22:08:32 +0000 (16:08 -0600)
PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
PR middle-end/95136 - missing -Wuninitialized on an array access with a variable offset

gcc/c-family/ChangeLog:

PR middle-end/10138
PR middle-end/95136
* c-attribs.c (append_access_attrs): Handle attr_access::none.
(handle_access_attribute): Same.

gcc/ChangeLog:

PR middle-end/10138
PR middle-end/95136
* attribs.c (init_attr_rdwr_indices): Move function here.
* attribs.h (rdwr_access_hash, rdwr_map): Define.
(attr_access): Add 'none'.
(init_attr_rdwr_indices): Declared function.
* builtins.c (warn_for_access)): New function.
(check_access): Call it.
* builtins.h (checK-access): Add an optional argument.
* calls.c (rdwr_access_hash, rdwr_map): Move to attribs.h.
(init_attr_rdwr_indices): Declare extern.
(append_attrname): Handle attr_access::none.
(maybe_warn_rdwr_sizes): Same.
(initialize_argument_information): Update comments.
* doc/extend.texi (attribute access): Document 'none'.
* tree-ssa-uninit.c (struct wlimits): New.
(maybe_warn_operand): New function.
(maybe_warn_pass_by_reference): Same.
(warn_uninitialized_vars): Refactor code into maybe_warn_operand.
Also call for function calls.
(pass_late_warn_uninitialized::execute): Adjust comments.
(execute_early_warn_uninitialized): Same.

gcc/testsuite/ChangeLog:

PR middle-end/10138
PR middle-end/95136
* c-c++-common/Wsizeof-pointer-memaccess1.c: Prune out valid
Wuninitialized.
* c-c++-common/uninit-pr51010.c: Adjust expected warning format.
* c-c++-common/goacc/uninit-dim-clause.c: Same.
* c-c++-common/goacc/uninit-firstprivate-clause.c: Same.
* c-c++-common/goacc/uninit-if-clause.c: Same.
* c-c++-common/gomp/pr70550-1.c: Same.
* c-c++-common/gomp/pr70550-2.c: Adjust.
* g++.dg/20090107-1.C: Same.
* g++.dg/20090121-1.C: Same.
* g++.dg/ext/attr-access.C: Avoid -Wuninitialized.
* gcc.dg/tree-ssa/forwprop-6.c: Prune out -Wuninitialized.
* gcc.dg/Warray-bounds-52.c: Prune out valid -Wuninitialized.
* gcc.dg/Warray-bounds-53.c: Same.
* gcc.dg/Warray-bounds-54.c: Same.
* gcc.dg/Wstringop-overflow-33.c: New test.
* gcc.dg/attr-access-none.c: New test.
* gcc.dg/attr-access-read-only.c: Adjust.
* gcc.dg/attr-access-read-write.c: Same.
* gcc.dg/attr-access-write-only.c: Same.
* gcc.dg/pr71581.c: Adjust text of expected warning.
* gcc.dg/uninit-15.c: Same.
* gcc.dg/uninit-32.c: New test.
* gcc.dg/uninit-33.c: New test.
* gcc.dg/uninit-34.c: New test.
* gcc.dg/uninit-36.c: New test.
* gcc.dg/uninit-B-O0.c: Adjust text of expected warning.
* gcc.dg/uninit-I-O0.c: Same.
* gcc.dg/uninit-pr19430-O0.c: Same.
* gcc.dg/uninit-pr19430.c: Same.
* gcc.dg/uninit-pr95136.c: New test.
* gfortran.dg/assignment_4.f90: Expect -Wuninitialized.
* gfortran.dg/goacc/uninit-dim-clause.f95: Adjust text of expected
warning.
* gfortran.dg/goacc/uninit-firstprivate-clause.f95
* gfortran.dg/goacc/uninit-if-clause.f95
* gfortran.dg/pr66545_2.f90

43 files changed:
gcc/attribs.c
gcc/attribs.h
gcc/builtins.c
gcc/builtins.h
gcc/c-family/c-attribs.c
gcc/calls.c
gcc/doc/extend.texi
gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c
gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c
gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c
gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c
gcc/testsuite/c-c++-common/gomp/pr70550-1.c
gcc/testsuite/c-c++-common/gomp/pr70550-2.c
gcc/testsuite/c-c++-common/uninit-pr51010.c
gcc/testsuite/g++.dg/20090107-1.C
gcc/testsuite/g++.dg/20090121-1.C
gcc/testsuite/g++.dg/ext/attr-access.C
gcc/testsuite/gcc.dg/Warray-bounds-52.c
gcc/testsuite/gcc.dg/Warray-bounds-53.c
gcc/testsuite/gcc.dg/Warray-bounds-54.c
gcc/testsuite/gcc.dg/Wstringop-overflow-33.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-access-none.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-access-read-only.c
gcc/testsuite/gcc.dg/attr-access-read-write.c
gcc/testsuite/gcc.dg/attr-access-write-only.c
gcc/testsuite/gcc.dg/pr71581.c
gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c
gcc/testsuite/gcc.dg/uninit-15.c
gcc/testsuite/gcc.dg/uninit-32.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/uninit-33.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/uninit-34.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/uninit-36.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/uninit-B-O0.c
gcc/testsuite/gcc.dg/uninit-I-O0.c
gcc/testsuite/gcc.dg/uninit-pr19430-O0.c
gcc/testsuite/gcc.dg/uninit-pr19430.c
gcc/testsuite/gcc.dg/uninit-pr95136.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/assignment_4.f90
gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95
gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95
gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
gcc/testsuite/gfortran.dg/pr66545_2.f90
gcc/tree-ssa-uninit.c

index 7d0f4b5..71dae12 100644 (file)
@@ -2017,6 +2017,65 @@ maybe_diag_alias_attributes (tree alias, tree target)
     }
 }
 
+/* Initialize a mapping for a call to function FNDECL declared with
+   attribute access.  Each attribute positional operand inserts one
+   entry into the mapping with the operand number as the key.  */
+
+void
+init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
+{
+  if (!fntype)
+    return;
+
+  for (tree access = TYPE_ATTRIBUTES (fntype);
+       (access = lookup_attribute ("access", access));
+       access = TREE_CHAIN (access))
+    {
+      /* 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; )
+       {
+         attr_access acc = { };
+
+         switch (*m)
+           {
+           case 'r': acc.mode = acc.read_only; break;
+           case 'w': acc.mode = acc.write_only; break;
+           case 'x': acc.mode = acc.read_write; break;
+           case '-': acc.mode = acc.none; break;
+           default: gcc_unreachable ();
+           }
+
+         char *end;
+         acc.ptrarg = strtoul (++m, &end, 10);
+         m = end;
+         if (*m == ',')
+           {
+             acc.sizarg = strtoul (++m, &end, 10);
+             m = end;
+           }
+         else
+           acc.sizarg = UINT_MAX;
+
+         acc.ptr = NULL_TREE;
+         acc.size = NULL_TREE;
+
+         /* Unconditionally add an entry for the required pointer
+            operand of the attribute, and one for the optional size
+            operand when it's specified.  */
+         rwm->put (acc.ptrarg, acc);
+         if (acc.sizarg != UINT_MAX)
+           rwm->put (acc.sizarg, acc);
+       }
+    }
+}
+
 
 #if CHECKING_P
 
index 8d79464..dea0b6c 100644 (file)
@@ -234,8 +234,18 @@ struct attr_access
   unsigned sizarg;
 
   /* The access mode.  */
-  enum access_mode { read_only, write_only, read_write };
+  enum access_mode { none, read_only, write_only, read_write };
   access_mode mode;
 };
 
+/* Used to define rdwr_map below.  */
+struct rdwr_access_hash: int_hash<int, -1> { };
+
+/* A mapping between argument number corresponding to attribute access
+   mode (read_only, write_only, or read_write) and operands.  */
+struct attr_access;
+typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
+
+extern void init_attr_rdwr_indices (rdwr_map *, tree);
+
 #endif // GCC_ATTRIBS_H
index f7bb87e..667d36c 100644 (file)
@@ -3310,6 +3310,90 @@ determine_block_size (tree len, rtx len_rtx,
                          GET_MODE_MASK (GET_MODE (len_rtx)));
 }
 
+/* For an expression EXP issue an access warning controlled by option OPT
+   with access to a region SLEN bytes in size in the RANGE of sizes.  */
+
+static bool
+warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
+                tree slen, bool access)
+{
+  bool warned = false;
+
+  if (access)
+    {
+      if (tree_int_cst_equal (range[0], range[1]))
+       warned = (func
+                 ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+                              "%K%qD reading %E byte from a region of size %E",
+                              "%K%qD reading %E bytes from a region of size %E",
+                              exp, func, range[0], slen)
+                 : warning_n (loc, opt, tree_to_uhwi (range[0]),
+                              "%Kreading %E byte from a region of size %E",
+                              "%Kreading %E bytes from a region of size %E",
+                              exp, range[0], slen));
+      else if (tree_int_cst_sign_bit (range[1]))
+       {
+         /* Avoid printing the upper bound if it's invalid.  */
+         warned = (func
+                   ? warning_at (loc, opt,
+                                 "%K%qD reading %E or more bytes from a region "
+                                 "of size %E",
+                                 exp, func, range[0], slen)
+                   : warning_at (loc, opt,
+                                 "%Kreading %E or more bytes from a region "
+                                 "of size %E",
+                                 exp, range[0], slen));
+       }
+      else
+       warned = (func
+                 ? warning_at (loc, opt,
+                               "%K%qD reading between %E and %E bytes from "
+                               "a region of size %E",
+                               exp, func, range[0], range[1], slen)
+                 : warning_at (loc, opt,
+                               "%Kreading between %E and %E bytes from "
+                               "a region of size %E",
+                               exp, range[0], range[1], slen));
+
+      return warned;
+    }
+
+  if (tree_int_cst_equal (range[0], range[1]))
+    warned = (func
+             ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+                          "%K%qD epecting %E byte in a region of size %E",
+                          "%K%qD expecting %E bytes in a region of size %E",
+                          exp, func, range[0], slen)
+             : warning_n (loc, opt, tree_to_uhwi (range[0]),
+                          "%Kexpecting %E byte in a region of size %E",
+                          "%Kexpecting %E bytes in a region of size %E",
+                          exp, range[0], slen));
+  else if (tree_int_cst_sign_bit (range[1]))
+    {
+      /* Avoid printing the upper bound if it's invalid.  */
+      warned = (func
+               ? warning_at (loc, opt,
+                             "%K%qD expecting %E or more bytes in a region "
+                             "of size %E",
+                             exp, func, range[0], slen)
+               : warning_at (loc, opt,
+                             "%Kexpecting %E or more bytes in a region "
+                             "of size %E",
+                             exp, range[0], slen));
+    }
+  else
+    warned = (func
+             ? warning_at (loc, opt,
+                           "%K%qD expecting between %E and %E bytes in "
+                           "a region of size %E",
+                           exp, func, range[0], range[1], slen)
+             : warning_at (loc, opt,
+                           "%Kexpectting between %E and %E bytes in "
+                           "a region of size %E",
+                           exp, range[0], range[1], slen));
+  return warned;
+}
+
 /* Try to verify that the sizes and lengths of the arguments to a string
    manipulation function given by EXP are within valid bounds and that
    the operation does not lead to buffer overflow or read past the end.
@@ -3336,12 +3420,16 @@ determine_block_size (tree len, rtx len_rtx,
    When DSTWRITE is null LEN is checked to verify that it doesn't exceed
    SIZE_MAX.
 
+   ACCESS is true for accesses, false for simple size checks in calls
+   to functions that neither read from nor write to the region.
+
    If the call is successfully verified as safe return true, otherwise
    return false.  */
 
 bool
 check_access (tree exp, tree, tree, tree dstwrite,
-             tree maxread, tree srcstr, tree dstsize)
+             tree maxread, tree srcstr, tree dstsize,
+             bool access /* = true */)
 {
   int opt = OPT_Wstringop_overflow_;
 
@@ -3649,44 +3737,10 @@ check_access (tree exp, tree, tree, tree dstwrite,
       if (TREE_NO_WARNING (exp))
        return false;
 
-      bool warned = false;
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
-      if (tree_int_cst_equal (range[0], range[1]))
-       warned = (func
-                 ? warning_n (loc, opt, tree_to_uhwi (range[0]),
-                              "%K%qD reading %E byte from a region of size %E",
-                              "%K%qD reading %E bytes from a region of size %E",
-                              exp, func, range[0], slen)
-                 : warning_n (loc, opt, tree_to_uhwi (range[0]),
-                              "%Kreading %E byte from a region of size %E",
-                              "%Kreading %E bytes from a region of size %E",
-                              exp, range[0], slen));
-      else if (tree_int_cst_sign_bit (range[1]))
-       {
-         /* Avoid printing the upper bound if it's invalid.  */
-         warned = (func
-                   ? warning_at (loc, opt,
-                                 "%K%qD reading %E or more bytes from a region "
-                                 "of size %E",
-                                 exp, func, range[0], slen)
-                   : warning_at (loc, opt,
-                                 "%Kreading %E or more bytes from a region "
-                                 "of size %E",
-                                 exp, range[0], slen));
-       }
-      else
-       warned = (func
-                 ? warning_at (loc, opt,
-                               "%K%qD reading between %E and %E bytes from "
-                               "a region of size %E",
-                               exp, func, range[0], range[1], slen)
-                 : warning_at (loc, opt,
-                               "%Kreading between %E and %E bytes from "
-                               "a region of size %E",
-                               exp, range[0], range[1], slen));
-      if (warned)
+      if (warn_for_access (loc, func, exp, opt, range, slen, access))
        TREE_NO_WARNING (exp) = true;
 
       return false;
index 7d8b9cd..73e85d6 100644 (file)
@@ -156,7 +156,8 @@ bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
 extern void warn_string_no_nul (location_t, const char *, tree, tree);
 extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
 extern bool builtin_with_linkage_p (tree);
-extern bool check_access (tree, tree, tree, tree, tree, tree, tree);
+extern bool check_access (tree, tree, tree, tree, tree, tree, tree,
+                         bool = true);
 
 
 #endif /* GCC_BUILTINS_H */
index 7a6fb9a..193c4cd 100644 (file)
@@ -3875,14 +3875,17 @@ append_access_attrs (tree t, tree attrs, const char *attrstr,
          /* Found a matching positional argument.  */
          if (*attrspec != pos[-1])
            {
+             const char* const modestr
+               = (pos[-1] == 'r'
+                  ? "read_only"
+                  : (pos[-1] == 'w'
+                     ? "write_only"
+                     : (pos[-1] == 'x' ? "read_write" : "none")));
              /* Mismatch in access mode.  */
              auto_diagnostic_group d;
              if (warning (OPT_Wattributes,
                           "attribute %qs mismatch with mode %qs",
-                          attrstr,
-                          (pos[-1] == 'r'
-                           ? "read_only"
-                           : (pos[-1] == 'w' ? "write_only" : "read_write")))
+                          attrstr, modestr)
                  && DECL_P (t))
                inform (DECL_SOURCE_LOCATION (t),
                        "previous declaration here");
@@ -4014,13 +4017,14 @@ handle_access_attribute (tree *node, tree name, tree args,
        ps += 2;
     }
 
-  const bool read_only = strncmp (ps, "read_only", 9) == 0;
-  const bool write_only = strncmp (ps, "write_only", 10) == 0;
-  if (!read_only && !write_only && strncmp (ps, "read_write", 10))
+  const bool read_only = !strncmp (ps, "read_only", 9);
+  const bool write_only = !strncmp (ps, "write_only", 10);
+  const bool read_write = !strncmp (ps, "read_write", 10);
+  if (!read_only && !write_only && !read_write && strncmp (ps, "none", 4))
     {
       error ("attribute %qE invalid mode %qs; expected one of "
-            "%qs, %qs, or %qs", name, access_str,
-            "read_only", "read_write", "write_only");
+            "%qs, %qs, %qs, or %qs", name, access_str,
+            "read_only", "read_write", "write_only", "none");
       return NULL_TREE;
     }
 
@@ -4145,9 +4149,9 @@ handle_access_attribute (tree *node, tree name, tree args,
       }
   }
 
-  if (!read_only)
+  if (read_write || write_only)
     {
-      /* A read_write and write_only modes must reference non-const
+      /* Read_write and write_only modes must reference non-const
         arguments.  */
       if (TYPE_READONLY (TREE_TYPE (argtypes[0])))
        {
@@ -4178,7 +4182,8 @@ handle_access_attribute (tree *node, tree name, tree args,
   /* Verify that the new attribute doesn't conflict with any existing
      attributes specified on previous declarations of the same type
      and if not, concatenate the two.  */
-  const char code = read_only ? 'r' : write_only ? 'w' : 'x';
+  const char code
+    = read_only ? 'r' : write_only ? 'w' : read_write ? 'x' : '-';
   tree new_attrs = append_access_attrs (node[0], attrs, attrstr, code, idxs);
   if (!new_attrs)
     return NULL_TREE;
index 8041388..d1c9c0b 100644 (file)
@@ -1865,70 +1865,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
   error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason);
 }
 
-/* Used to define rdwr_map below.  */
-struct rdwr_access_hash: int_hash<int, -1> { };
-
-/* A mapping between argument number corresponding to attribute access
-   mode (read_only, write_only, or read_write) and operands.  */
-typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
-
-/* Initialize a mapping for a call to function FNDECL declared with
-   attribute access.  Each attribute positional operand inserts one
-   entry into the mapping with the operand number as the key.  */
-
-static void
-init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
-{
-  if (!fntype)
-    return;
-
-  for (tree access = TYPE_ATTRIBUTES (fntype);
-       (access = lookup_attribute ("access", access));
-       access = TREE_CHAIN (access))
-    {
-      /* 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; )
-       {
-         attr_access acc = { };
-
-         switch (*m)
-           {
-           case 'r': acc.mode = acc.read_only; break;
-           case 'w': acc.mode = acc.write_only; break;
-           default: acc.mode = acc.read_write; break;
-           }
-
-         char *end;
-         acc.ptrarg = strtoul (++m, &end, 10);
-         m = end;
-         if (*m == ',')
-           {
-             acc.sizarg = strtoul (++m, &end, 10);
-             m = end;
-           }
-         else
-           acc.sizarg = UINT_MAX;
-
-         acc.ptr = NULL_TREE;
-         acc.size = NULL_TREE;
-
-         /* Unconditionally add an entry for the required pointer
-            operand of the attribute, and one for the optional size
-            operand when it's specified.  */
-         rwm->put (acc.ptrarg, acc);
-         if (acc.sizarg != UINT_MAX)
-           rwm->put (acc.sizarg, acc);
-       }
-    }
-}
-
 /* Returns the type of the argument ARGNO to function with type FNTYPE
    or null when the typoe cannot be determined or no such argument exists.  */
 
@@ -1959,11 +1895,13 @@ append_attrname (const std::pair<int, attr_access> &access,
      appends the attribute pointer operand even when none was specified.  */
   size_t len = strlen (attrstr);
 
-  const char *atname
+  const char* const atname
     = (access.second.mode == attr_access::read_only
        ? "read_only"
        : (access.second.mode == attr_access::write_only
-         ? "write_only" : "read_write"));
+         ? "write_only"
+         : (access.second.mode == attr_access::read_write
+            ? "read_write" : "none")));
 
   const char *sep = len ? ", " : "";
 
@@ -2131,11 +2069,13 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp)
          /* For read-only and read-write attributes also set the source
             size.  */
          srcsize = objsize;
-         if (access.second.mode == attr_access::read_only)
+         if (access.second.mode == attr_access::read_only
+             || access.second.mode == attr_access::none)
            {
              /* For a read-only attribute there is no destination so
                 clear OBJSIZE.  This emits "reading N bytes" kind of
-                diagnostics instead of the "writing N bytes" kind.  */
+                diagnostics instead of the "writing N bytes" kind,
+                unless MODE is none.  */
              objsize = NULL_TREE;
            }
        }
@@ -2145,7 +2085,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp)
         diagnosed.  */
       TREE_NO_WARNING (exp) = false;
       check_access (exp, NULL_TREE, NULL_TREE, size, /*maxread=*/ NULL_TREE,
-                   srcsize, objsize);
+                   srcsize, objsize, access.second.mode != attr_access::none);
 
       if (TREE_NO_WARNING (exp))
        /* If check_access issued a warning above, append the relevant
@@ -2285,8 +2225,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
   /* Array for up to the two attribute alloc_size arguments.  */
   tree alloc_args[] = { NULL_TREE, NULL_TREE };
 
-  /* Map of attribute read_only, write_only, or read_write specifications
-     for function arguments.  */
+  /* Map of attribute accewss specifications for function arguments.  */
   rdwr_map rdwr_idx;
   init_attr_rdwr_indices (&rdwr_idx, fntype);
 
@@ -2559,7 +2498,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
      nul-terminated strings.  */
   maybe_warn_nonstring_arg (fndecl, exp);
 
-  /* Check read_only, write_only, and read_write arguments.  */
+  /* Check attribute access arguments.  */
   maybe_warn_rdwr_sizes (&rdwr_idx, exp);
 }
 
index cced19d..e656e66 100644 (file)
@@ -2497,8 +2497,8 @@ may be diagnosed by warnings such as @option{-Wstringop-overflow},
 The @code{access} attribute specifies that a function to whose by-reference
 arguments the attribute applies accesses the referenced object according to
 @var{access-mode}.  The @var{access-mode} argument is required and must be
-one of three names: @code{read_only}, @code{read_write}, or @code{write_only}.
-The remaining two are positional arguments.
+one of four names: @code{read_only}, @code{read_write}, @code{write_only},
+or @code{none}.  The remaining two are positional arguments.
 
 The required @var{ref-index} positional argument  denotes a function
 argument of pointer (or in C++, reference) type that is subject to
@@ -2555,6 +2555,14 @@ __attribute__ ((access (write_only, 1), access (read_only, 2))) char* strcpy (ch
 __attribute__ ((access (write_only, 1, 2), access (read_write, 3))) int fgets (char*, int, FILE*);
 @end smallexample
 
+The access mode @code{none} specifies that the pointer to which it applies
+is not used to access the referenced object at all.  Unless the pointer is
+null the pointed-to object must exist and have at least the size as denoted
+by the @var{size-index} argument.  The object need not be initialized.
+The mode is intended to be used as a means to help validate the expected
+object size, for example in functions that call @code{__builtin_object_size}.
+@xref{Object Size Checking}.
+
 @item alias ("@var{target}")
 @cindex @code{alias} function attribute
 The @code{alias} attribute causes the declaration to be emitted as an alias
index 4281e3b..c4127b8 100644 (file)
@@ -161,3 +161,5 @@ f4 (char x[64], char *y, __builtin_va_list ap)
   snprintf (p, sizeof (buf), "%s", y);
   vsnprintf (p, sizeof (buf), "%s", ap);
 }
+
+/* { dg-prune-output "-Wuninitialized" } */
index 9f11196..827dac7 100644 (file)
@@ -4,13 +4,13 @@ void acc_parallel()
 {
   int i, j, k;
 
-  #pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized" } */
   ;
 }
 
@@ -18,12 +18,12 @@ void acc_kernels()
 {
   int i, j, k;
 
-  #pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized" } */
   ;
 }
index 2584033..334567d 100644 (file)
@@ -18,7 +18,7 @@ foo2 (void)
 {
   int i;
 
-#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized in this function" } */
+#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized" } */
   {
     i = 1;
   }
index 55caa4c..7f78d72 100644 (file)
@@ -11,28 +11,28 @@ main (void)
   bool b, b2, b3, b4;
   int i, i2;
 
-  #pragma acc parallel if(l) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
+  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
   ;
 
-  #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
+  #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
   ;
 
-  #pragma acc data if(l3) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc data if(b3) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
+  #pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
   ;
 
-  #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized in this function" } */
+  #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
+  #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
   ;
 
 }
index 493d417..d0d2fa5 100644 (file)
@@ -16,7 +16,7 @@ foo (void)
 {
   {
     int i;
-    #pragma omp target defaultmap(tofrom:scalar)       /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target defaultmap(tofrom:scalar)       /* { dg-bogus "is used uninitialized" } */
     {
       i = 26;
       bar (i);
@@ -24,7 +24,7 @@ foo (void)
   }
   {
     T j;
-    #pragma omp target defaultmap(tofrom:scalar)       /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target defaultmap(tofrom:scalar)       /* { dg-bogus "is used uninitialized" } */
     {
       j = 37;
       bar (j);
@@ -32,7 +32,7 @@ foo (void)
   }
   {
     int i;
-    #pragma omp target                                 /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target                                 /* { dg-bogus "is used uninitialized" } */
     {
       i = 26;
       bar (i);
@@ -40,7 +40,7 @@ foo (void)
   }
   {
     T j;
-    #pragma omp target                                 /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target                                 /* { dg-bogus "is used uninitialized" } */
     {
       j = 37;
       bar (j);
@@ -48,7 +48,7 @@ foo (void)
   }
   {
     int i;
-    #pragma omp target firstprivate (i)                        /* { dg-warning "is used uninitialized in this function" } */
+    #pragma omp target firstprivate (i)                        /* { dg-warning "is used uninitialized" } */
     {
       i = 26;
       bar (i);
@@ -56,7 +56,7 @@ foo (void)
   }
   {
     T j;
-    #pragma omp target firstprivate (j)                        /* { dg-warning "is used uninitialized in this function" } */
+    #pragma omp target firstprivate (j)                        /* { dg-warning "is used uninitialized" } */
     {
       j = 37;
       bar (j);
@@ -64,7 +64,7 @@ foo (void)
   }
   {
     int i;
-    #pragma omp target private (i)                     /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target private (i)                     /* { dg-bogus "is used uninitialized" } */
     {
       i = 26;
       bar (i);
@@ -72,7 +72,7 @@ foo (void)
   }
   {
     T j;
-    #pragma omp target private (j)                     /* { dg-bogus "is used uninitialized in this function" } */
+    #pragma omp target private (j)                     /* { dg-bogus "is used uninitialized" } */
     {
       j = 37;
       bar (j);
index 31c34da..936d907 100644 (file)
@@ -8,45 +8,45 @@ void
 foo (void)
 {
   int i, j, k, l, m, n, o, p, q;
-  #pragma omp task                             /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp task                             /* { dg-bogus "is used uninitialized" } */
   {
     i = 2;
     bar (i);
   }
-  #pragma omp taskloop                         /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp taskloop                         /* { dg-bogus "is used uninitialized" } */
   for (j = 0; j < 10; j++)
     {
       k = 7;
       bar (k);
     }
-  #pragma omp task firstprivate (l)            /* { dg-warning "is used uninitialized in this function" } */
+  #pragma omp task firstprivate (l)            /* { dg-warning "is used uninitialized" } */
   {
     l = 2;
     bar (l);
   }
-  #pragma omp taskloop firstprivate (m)                /* { dg-warning "is used uninitialized in this function" } */
+  #pragma omp taskloop firstprivate (m)                /* { dg-warning "is used uninitialized" } */
   for (j = 0; j < 10; j++)
     {
       m = 7;
       bar (m);
     }
-  #pragma omp task shared (n)                  /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp task shared (n)                  /* { dg-bogus "is used uninitialized" } */
   {
     n = 2;
     bar (n);
   }
-  #pragma omp taskloop shared (o)              /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp taskloop shared (o)              /* { dg-bogus "is used uninitialized" } */
   for (j = 0; j < 10; j++)
     {
       o = 7;
       bar (o);
     }
-  #pragma omp task private (p)                 /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp task private (p)                 /* { dg-bogus "is used uninitialized" } */
   {
     p = 2;
     bar (p);
   }
-  #pragma omp taskloop shared (q)              /* { dg-bogus "is used uninitialized in this function" } */
+  #pragma omp taskloop shared (q)              /* { dg-bogus "is used uninitialized" } */
   for (j = 0; j < 10; j++)
     {
       q = 7;
index f28da46..9fd1ea3 100644 (file)
@@ -4,10 +4,10 @@
 int f (int j)
 {
   int a [10];
-  return a [j]; /* { dg-warning "a\\\[j\\\]. is used uninitialized" } */
+  return a [j]; /* { dg-warning "a|a\\\[j\\\]. is used uninitialized" } */
 }
 int g (int j)
 {
   int a [10];
-  return a [j+1]; /* { dg-warning "a\\\[<unknown>\\\]. is used uninitialized" } */
+  return a [j+1]; /* { dg-warning "a|a\\\[<unknown>\\\]. is used uninitialized" } */
 }
index ff586e8..80b88f0 100644 (file)
@@ -6,7 +6,7 @@ template <typename T> struct Q1 { typedef int x; };
 template <typename T> struct Q2 {
   typename Q1<T>::x f() {
     int k;
-    return k; /* { dg-warning "'k' is used uninitialized in this function" }  */
+    return k; /* { dg-warning "'k' is used uninitialized" }  */
   }
 };
 int foo() { return Q2<int>().f(); }
index ddfa3ad..9d70fb3 100644 (file)
@@ -7,7 +7,7 @@ private:
   int y;
 
 public:
-  A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized in this function" }  */
+  A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized" }  */
   int get_y () { return y; }
 };
 
index fcb54cd..3b9c1a3 100644 (file)
@@ -39,7 +39,7 @@ void call_rop1_ror2_O0 (void)
 
 void call_rdwrp1_rdwrr2_O0 (void)
 {
-  int32_t x[1];
+  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" }
@@ -78,7 +78,7 @@ void call_rop1_ror2_O1 (void)
 
 void call_rdwrp1_rdwrr2_O1 (void)
 {
-  int32_t x[1];
+  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);
index 1a7d76f..729ad45 100644 (file)
@@ -95,3 +95,6 @@ void ptr_idx_range (void)
   i = SR (3, 4);
   T (i, (int[]){ 2, 3, 4 });          // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" }
 }
+
+/* Some of the invalid accesses above also trigger -Wuninitialized.
+   { dg-prune-output "\\\[-Wuninitialized" }  */
index 0f06222..80db314 100644 (file)
@@ -95,3 +95,6 @@ void ptr_idx_range (void)
   i = SR (3, 4);
   T (i, (int[]){ 2, 3, 4 });          // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" }
 }
+
+/* Some of the invalid accesses above also trigger -Wuninitialized.
+   { dg-prune-output "\\\[-Wuninitialized" }  */
index 644fcd0..5df5710 100644 (file)
@@ -10,9 +10,9 @@ int f0 (void)
   return p[2];      // { dg-warning "-Warray-bounds" }
 }
 
-int f1 (void)
+int f1 (int j)
 {
-  int i;
+  int i = j;
   int *p = &i;
   return p[2];      // { dg-warning "-Warray-bounds" }
 }
@@ -22,3 +22,5 @@ int f2 (int i)
   int *p = &i;
   return p[2];      // { dg-warning "-Warray-bounds" }
 }
+
+/* { dg-prune-output "-Wuninitialized" } */
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c
new file mode 100644 (file)
index 0000000..cb8aeb9
--- /dev/null
@@ -0,0 +1,40 @@
+/* PR middle-end/82456 - missing -Wstringop-overflow on strcpy reading past
+   the end of an array
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+void fcst (char *d)
+{
+  char a[2] = "0";
+
+  __builtin_strcpy (d, a + 3);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+}
+
+void frng (char *d, int i)
+{
+  char a[2] = "0";
+
+  if (i < 3)
+    i = 3;
+
+  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+}
+
+void gcst (char *d)
+{
+  char a[2] = "0";
+
+  __builtin_strcpy (d, a + 2);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+}
+
+void grng (char *d, int i)
+{
+  char a[2] = "0";
+
+  if (i < 2)
+    i = 2;
+
+  __builtin_strcpy (d, a + i);    // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
+}
+
+/* { dg-prune-output "-Wuninitialized" } */
diff --git a/gcc/testsuite/gcc.dg/attr-access-none.c b/gcc/testsuite/gcc.dg/attr-access-none.c
new file mode 100644 (file)
index 0000000..d983f2f
--- /dev/null
@@ -0,0 +1,38 @@
+/* Test to verify the handling of attribute access (none).
+   { dg-do compile }
+   { dg-options "-O -Wall -ftrack-macro-expansion=0" } */
+
+int __attribute__ ((access (none, 1)))
+fnone_pv1 (void*);
+
+void nowarn_fnone_pv1 (void)
+{
+  int x;
+  fnone_pv1 (&x);
+}
+
+
+int __attribute__ ((access (none, 1)))
+fnone_pcv1 (const void*);
+
+void nowarn_fnone_pcv1 (void)
+{
+  char a[2];
+  fnone_pcv1 (a);
+}
+
+
+int __attribute__ ((access (none, 1, 2)))
+fnone_pcv1_2 (const void*, int);  // { dg-message "in a call to function 'fnone_pcv1_2' declared with attribute 'none \\\(1, 2\\\)'" }
+
+void nowarn_fnone_pcv1_2 (void)
+{
+  char a[2];
+  fnone_pcv1_2 (a, 2);
+}
+
+void warn_fnone_pcv1_2 (void)
+{
+  char a[3];
+  fnone_pcv1_2 (a, 4);        // { dg-warning "expecting 4 bytes in a region of size 3" }
+}
index 9acd769..71175d0 100644 (file)
@@ -11,7 +11,7 @@ int  __attribute__ ((access ()))
 access___v (void);     // { dg-error "wrong number of arguments specified for 'access' attribute" }
 
 int  __attribute__ ((access (rdonly)))
-rdonly_spelling (void);   // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', or 'write_only'" }
+rdonly_spelling (void);   // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" }
 
 int  __attribute__ ((access (read_only)))
 rdonly_v_all (void);   // { dg-error "attribute .access\\(read_only\\). missing an argument" }
index c97e54b..849d9f1 100644 (file)
@@ -10,7 +10,7 @@ int  __attribute__ ((access ()))
 access___v (void);     /* { dg-error "wrong number of arguments specified for 'access' attribute" } */
 
 int  __attribute__ ((access (rdwr)))
-rdwr_spelling (void);   /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', or 'write_only'" } */
+rdwr_spelling (void);   /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } */
 
 int  __attribute__ ((access (read_write)))
 rdwr_v_all (void);   /* { dg-error "attribute .access\\(read_write\\). missing an argument" } */
index 008f5a3..2718b0d 100644 (file)
@@ -11,7 +11,7 @@ int  __attribute__ ((access ()))
 access___v (void);     // { dg-error "wrong number of arguments specified for 'access' attribute" }
 
 int  __attribute__ ((access (wronly)))
-wronly_spelling (void);   // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', or 'write_only'" }
+wronly_spelling (void);   // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" }
 
 int  __attribute__ ((access (read_only)))
 wronly_v_all (void);   // { dg-error "attribute .access\\(read_only\\). missing an argument" }
index d82eb1e..dd71dde 100644 (file)
@@ -6,19 +6,19 @@ _Complex float
 f1 (void)
 {
   float x;
-  return x;    /* { dg-warning "is used uninitialized in this function" } */
+  return x;    /* { dg-warning "is used uninitialized" } */
 }
 
 _Complex double
 f2 (void)
 {
   double x;
-  return x;    /* { dg-warning "is used uninitialized in this function" } */
+  return x;    /* { dg-warning "is used uninitialized" } */
 }
 
 _Complex int
 f3 (void)
 {
   int x;
-  return x;    /* { dg-warning "is used uninitialized in this function" } */
+  return x;    /* { dg-warning "is used uninitialized" } */
 }
index 3f50243..24b1767 100644 (file)
@@ -25,3 +25,6 @@ void f(void)
    value-numbering, removing the load altogether.
    ???  We now do this after CPP re-writes a into SSA form.  */
 /* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "ccp1" } } */
+
+/* The invalid access above may also trigger -Wuninitialized.
+   { dg-prune-output "-Wuninitialized" } */
index 67aac41..8ee10c2 100644 (file)
@@ -10,7 +10,7 @@
 inline int
 foo (int i)
 {
-  if (i) /* { dg-warning "used uninitialized in this function" "" } */
+  if (i) /* { dg-warning "used uninitialized" } */
     return 1;
   return 0;
 }
diff --git a/gcc/testsuite/gcc.dg/uninit-32.c b/gcc/testsuite/gcc.dg/uninit-32.c
new file mode 100644 (file)
index 0000000..cdc0512
--- /dev/null
@@ -0,0 +1,312 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* alloca (size_t);
+void* malloc (size_t);
+void* realloc (void*, size_t);
+
+void fpi (int*);
+void fpci (const int*);
+void fpcv (const void*);
+
+
+void nowarn_scalar_fpi (void)
+{
+  int x;
+  fpi (&x);
+}
+
+void nowarn_scalar_plus_cst_fpi (void)
+{
+  int x;
+  // This deserves a warning other than -Wuninitialized.
+  fpi (&x + 1);
+}
+
+void nowarn_scalar_plus_var_fpi (int i)
+{
+  int x;
+  // Same as above, this deserves a warning other than -Wuninitialized.
+  fpi (&x + i);
+}
+
+void nowarn_array_assign_fpci (void)
+{
+  int a[2];
+  a[0] = 0;
+  fpci (a);
+}
+
+void nowarn_array_assign_plus_cst_fpci (void)
+{
+  int a[4];
+  a[1] = 0;
+  a[2] = 1;
+  fpci (a + 1);
+}
+
+void nowarn_array_init_fpci (void)
+{
+  int a[4] = { 0 };
+  fpci (a);
+}
+
+void nowarn_array_compound_fpi (void)
+{
+  fpi ((int[2]){ 1 });
+}
+
+void nowarn_array_compound_fpci (void)
+{
+  fpci ((int[3]){ 1 });
+}
+
+void warn_array_fpci (void)
+{
+  int a[4];                   // { dg-message "declared here" }"
+  fpci (a);                   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_array_plus_cst_fpci (void)
+{
+  int a[4];
+  fpci (a + 1);               // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_array_plus_var_fpci (int i)
+{
+  int a[4];
+  fpci (a + i);               // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void nowarn_array_end_fpci (void)
+{
+  int a[4];
+  /* This should be diagnosed by a warning other than -Wuninitialized
+     because the just-past-the-end pointer cannot be dereferenced and
+     the function doesn't take any other pointer to tell where the start
+     of the array is.  -Wuninitialized isn't appropriate because there
+     is nothing to initialize at that offset.  */
+  fpci (a + 4);
+}
+
+void warn_matrix_fpcv (void)
+{
+  int a[2][2];
+  fpci (a[1]);                // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_scalar_fpcv (void)
+{
+  int i;
+  fpci (&i);                  // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_scalar_plus_cst_fpcv (void)
+{
+  int x;
+  /* Same as above, this deserves a warning other than -Wuninitialized
+     for passing the function a past-the-end pointer with no other
+     argument.  */
+  fpci (&x + 1);
+}
+
+void warn_scalar_plus_var_fpcv (int i)
+{
+  int x;
+  fpci (&x + i);              // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void nowarn_struct_assign_fpci (void)
+{
+  struct { int a, b; } s;
+  s.a = 0;
+  fpci (&s.a);
+}
+
+void warn_struct_assign_fpci (void)
+{
+  struct { int a, b; } s;
+  s.a = 0;
+  fpci (&s.b);                // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void nowarn_struct_init_fpci (void)
+{
+  struct { int a, b; } s = { 0 };
+  fpci (&s.a);
+  fpci (&s.b);
+}
+
+void nowarn_struct_compound_fpci (void)
+{
+  struct S { int a, b; };
+  fpci (&(struct S){ }.a);
+  fpci (&(struct S){ }.b);
+}
+
+/* Verify that passing a just-past-the-end pointer to a const pointer
+   argument to a function that takes another argument is not diagnosed
+   since the two arguments together could outline a range.  */
+void nowarn_fp_p (void)
+{
+  extern void fpi_pci (int*, const int*);
+
+  {
+    int i;
+    fpi_pci (&i, &i + 1);
+  }
+  {
+    int j;
+    fpi_pci (&j + 1, &j + 1);
+  }
+
+  extern void fpc_pcc (char*, const char*);
+
+  {
+    char a[2];
+    fpc_pcc (a, a + 2);
+  }
+  {
+    char a[3];
+    fpc_pcc (a, a + 3);
+  }
+
+  extern void fpcc_pcc (const char*, const char*);
+
+  {
+    char a[4];
+    fpcc_pcc (a + 4, a + 4);
+  }
+}
+
+
+/* Verify passing addresses of empty uninitialized objects doesn't
+   trigger a warning.  */
+void nowarn_fpcEmpty (void)
+{
+  struct Empty { };
+  extern void fpcEmpty (const struct Empty*);
+
+  /* Since Empty has no members warning for it isn't really necessary.
+     See also PR 38908.  */
+  struct Empty s;
+  fpcEmpty (&s);
+}
+
+
+/* Verify passing addresses of uninitialized objects to functions
+   declared without a proptotype doesn't trigger a warning.  */
+void nowarn_noproto (void)
+{
+  extern void fnoproto ();
+  int i, a[2];
+
+  fnoproto (&i, a, a + 2);
+}
+
+
+/* Verify passing addresses of uninitialized objects to variadic
+   functions doesn't trigger a warning.  */
+void nowarn_vararg (void)
+{
+  extern void fvararg (int, ...);
+
+  int i, a[2];
+
+  fvararg (0, &i, a, a + 2);
+}
+
+
+void nowarn_alloca_assign_fpci (unsigned n)
+{
+  int *p = (int*)alloca (n);
+  p[0] = 0;
+  fpci (p);
+}
+
+void nowarn_alloca_assign_plus_cst_fpci (unsigned n)
+{
+  int *p = (int*)alloca (n);
+  p[1] = 0;
+  p[2] = 1;
+  fpci (p + 1);
+}
+
+void warn_alloca_fpci (unsigned n)
+{
+  int *p = (int*)alloca (n);
+  fpci (p);                   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_alloca_assign_plus_cst_fpci (unsigned n)
+{
+  int *p = (int*)alloca (n);
+  p[1] = 0;
+  p[2] = 1;
+  fpci (p + 3);               // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+
+void nowarn_vla_assign_fpci (unsigned n)
+{
+  int a[n];
+  a[0] = 0;
+  fpci (a);
+}
+
+void nowarn_vla_assign_plus_cst_fpci (unsigned n)
+{
+  int vla[n];
+  vla[1] = 0;
+  vla[2] = 1;
+  fpci (vla + 1);
+}
+
+void warn_vla_fpci (unsigned n)
+{
+  int vla[n];                 // { dg-message "declared here" "pr?????" { xfail *-*-* } }"
+  fpci (vla);                 // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_vla_assign_plus_cst_fpci (unsigned n)
+{
+  int vla[n];                 // { dg-message "declared here" "pr?????" { xfail *-*-* } }"
+  vla[1] = 0;
+  vla[2] = 1;
+  fpci (vla + 3);             // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+
+void nowarn_malloc_assign_fpci (unsigned n)
+{
+  int *p = (int*)malloc (n);
+  p[0] = 0;
+  fpci (p);
+}
+
+void nowarn_malloc_assign_plus_cst_fpci (unsigned n)
+{
+  int *p = (int*)malloc (n);
+  p[1] = 0;
+  p[2] = 1;
+  fpci (p + 1);
+}
+
+void warn_malloc_fpci (unsigned n)
+{
+  int *p = (int*)malloc (n);
+  fpci (p);                   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
+
+void warn_malloc_assign_plus_cst_fpci (unsigned n)
+{
+  int *p = (int*)malloc (n);  // { dg-message "allocated here" "pr?????" { xfail *-*-* } }"
+  p[1] = 0;
+  p[2] = 1;
+  fpci (p + 3);               // { dg-warning "\\\[-Wmaybe-uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-33.c b/gcc/testsuite/gcc.dg/uninit-33.c
new file mode 100644 (file)
index 0000000..a45f18d
--- /dev/null
@@ -0,0 +1,145 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to arguments
+   to functions declared with attribute access is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+
+RO (1) void fpri (int*);      // { dg-message "in a call to 'fpri' declared with attribute 'access \\\(read_only, 1\\\)' here" }
+
+RO (1) void fpcri (const int*);
+
+RO (1, 2) void fpcri1_2 (const int*, int);
+
+
+void warn_scalar_fpri (void)
+{
+  int i;                      // { dg-message "declared here" }
+  fpri (&i);                  // { dg-warning "'i' is used uninitialized" }
+}
+
+void nowarn_scalar_plus_fpri (void)
+{
+  int i;
+  /* This gets a -Wstringop-overflow for reading past the end but not
+     -Wuninitialized because there's nothing to initialize there.  */
+  fpri (&i + 1);              // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+void nowarn_array_assign_fpcri (void)
+{
+  int a[2];
+  a[0] = 0;
+  fpcri (a);
+}
+
+void nowarn_array_init_fpcri (void)
+{
+  int a[4] = { 0 };
+  fpcri (a);
+}
+
+void nowarn_array_compound_fpri (void)
+{
+  fpri ((int[2]){ 0 });
+}
+
+void nowarn_array_compound_fpcri (void)
+{
+  fpcri ((int[3]){ 1 });
+}
+
+void warn_scalar_fpcri (void)
+{
+  int i;
+  fpcri (&i);                 // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void warn_array_fpcri (void)
+{
+  int a[4];
+  fpcri (a);                  // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void warn_array_plus_cst_fpcri (void)
+{
+  int a[4];
+  fpcri (a + 1);              // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void warn_array_plus_var_fpcri (int i)
+{
+  int a[4];
+  fpcri (a + i);              // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void nowarn_struct_assign_fpcri (void)
+{
+  struct { int a, b; } s;
+  s.a = 0;
+  fpcri (&s.a);
+}
+
+void warn_struct_assign_fpcri (void)
+{
+  struct { int a, b; } s;
+  s.a = 0;
+  fpcri (&s.b);               // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void nowarn_struct_init_fpcri (void)
+{
+  struct { int a, b; } s = { 0 };
+  fpcri (&s.a);
+  fpcri (&s.b);
+}
+
+void nowarn_struct_compound_fpcri (void)
+{
+  struct S { int a, b; };
+  fpcri (&(struct S){ }.a);
+  fpcri (&(struct S){ }.b);
+}
+
+
+void nowarn_scalar_fpcri1_2 (void)
+{
+  int i;
+  fpcri1_2 (&i, 0);
+}
+
+void nowarn_array_assign_fpcri1_2 (void)
+{
+  int a[2];
+  a[0] = 0;
+  fpcri1_2 (a, 1);
+}
+
+void nowarn_array_assign_fpcri1_2_plus_cst (void)
+{
+  int a[3];
+  a[1] = 0;
+  fpcri1_2 (a + 1, 1);
+}
+
+void nowarn_array_init_fpcri1_2 (void)
+{
+  int a[4] = { 0 };
+  fpcri1_2 (a, 2);
+}
+
+void warn_array_fpcri1_2_rd1 (void)
+{
+  int a[4];
+  fpcri1_2 (a, 1);            // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void warn_array_fpcri1_2_rd2 (void)
+{
+  int a[4];
+  fpcri1_2 (a, 2);            // { dg-warning "\\\[-Wuninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-34.c b/gcc/testsuite/gcc.dg/uninit-34.c
new file mode 100644 (file)
index 0000000..9de6183
--- /dev/null
@@ -0,0 +1,58 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to arguments
+   to functions declared with attribute access is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+
+RW (1) RW (3) void
+f4pi (int*, int*, int*, int*);    // { dg-message "in a call to 'f4pi' declared with attribute 'access \\\(read_write, \[13\]\\\)'" }
+
+
+void nowarn_scalar (void)
+{
+  int i1 = 0, i2, i3 = 1, i4;
+  f4pi (&i1, &i2, &i3, &i4);
+}
+
+void warn_scalar_1 (void)
+{
+  int i1;                         // { dg-message "declared here" }
+  int i2, i3 = 1, i4;
+
+  f4pi (&i1, &i2, &i3, &i4);      // { dg-warning "'i1' may be used uninitialized" }
+}
+
+void warn_scalar_2 (void)
+{
+  int j1 = 0, j2, j4;
+  int j3;
+
+  f4pi (&j1, &j2, &j3, &j4);      // { dg-warning "'j3' may be used uninitialized" }
+}
+
+
+void nowarn_array_init (void)
+{
+  int a1[4] = { 0 }, a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);
+}
+
+void warn_array_1 (void)
+{
+  int a1[4];                  // { dg-message "'a1' declared here" }
+  int a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a1' may be used uninitialized" }
+}
+
+void warn_array_2 (void)
+{
+  int a1[4] = { 0 }, a2[5], a4[7];
+  int a3[6];                  // { dg-message "'a3' declared here" }
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a3' may be used uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-36.c b/gcc/testsuite/gcc.dg/uninit-36.c
new file mode 100644 (file)
index 0000000..9524e7a
--- /dev/null
@@ -0,0 +1,237 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to const
+   arguments to built-ins is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* alloca (size_t);
+void* malloc (size_t);
+void* realloc (void*, size_t);
+
+void* memcpy (void*, const void*, size_t);
+char* strcpy (char*, const char*);
+size_t strlen (const char*);
+
+void sink (void*);
+
+void nowarn_array_memcpy (void *d, unsigned n)
+{
+  int a[2];
+  /* Diagnose this?  */
+  memcpy (d, a, n /* Non-constant to avoid folding into MEM_REF.  */);
+}
+
+void nowarn_array_plus_cst_memcpy (void *d, unsigned n)
+{
+  int a[3];
+  /* Diagnose this?  */
+  memcpy (d, a + 1, n);
+}
+
+void nowarn_array_plus_var_memcpy (void *d, unsigned n, int i)
+{
+  int a[4];
+  /* Diagnose this?  */
+  memcpy (d, a + i, n);
+}
+
+void nowarn_array_assign_memcpy (char *d, unsigned n)
+{
+  int a[3];
+  a[1] = 3;
+  memcpy (d, a, n);
+}
+
+void nowarn_array_init_memcpy (char *d, unsigned n)
+{
+  int a[4] = { 0 };
+  memcpy (d, a, n);
+}
+
+void nowarn_array_compound_memcpy (void *d, unsigned n)
+{
+  memcpy (d, (int[2]){ 0 }, n);
+}
+
+void nowarn_struct_assign_memcpy (void *d, unsigned n)
+{
+  struct S { int a, b, c, d; } s;
+  s.b = 1;
+  s.d = 2;
+  memcpy (d, &s, n);
+}
+
+
+void nowarn_array_init_strcpy (char *d[], unsigned n)
+{
+  char a[8] = "012";
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+  strcpy (d[1], a + 4);
+  strcpy (d[1], a + 5);
+  strcpy (d[1], a + 6);
+  strcpy (d[1], a + 7);
+}
+
+
+void nowarn_array_assign_strcpy (char *d[], unsigned n)
+{
+  char a[8];
+  a[0] = '0';
+  a[1] = '1';
+  a[2] = '2';
+  a[3] = '\0';
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+}
+
+void warn_array_plus_cst_strcpy (char *d, unsigned n)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + 4);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 5);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 6);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 7);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void nowarn_array_plus_var_strcpy (char *d, int i)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + i);
+}
+
+
+size_t nowarn_array_assign_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  size_t n = 0;
+
+  n += strlen (a);
+  n += strlen (a + 1);
+  n += strlen (a + 2);
+  n += strlen (a + 3);
+  return n;
+}
+
+size_t warn_array_plus_cst_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + 4);      // { dg-warning "\\\[-Wuninitialized" }
+}
+
+size_t nowarn_array_plus_var_strlen (const char *s, int i)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + i);
+}
+
+
+size_t nowarn_alloca_assign_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_alloca_escape_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_alloca_strlen (void)
+{
+  char *p = (char*)alloca (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_malloc_assign_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_malloc_escape_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_malloc_strlen (void)
+{
+  char *p = (char*)malloc (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_realloc_strlen (void *p)
+{
+  char *q = (char*)realloc (p, 8);
+  return strlen (q);
+}
+
+
+size_t nowarn_vla_assign_strlen (int n, int i)
+{
+  char vla[n];
+  vla[i] = '\0';
+  return strlen (vla);
+}
+
+size_t nowarn_vla_strcpy_strlen (int n, const char *s, int i)
+{
+  char vla[n];
+  strcpy (vla, s);
+  return strlen (vla + i);
+}
+
+size_t nowarn_vla_escape_strlen (int n, int i)
+{
+  char vla[n];
+  sink (vla);
+  return strlen (vla);
+}
+
+size_t warn_vla_strlen (unsigned n)
+{
+  char vla[n];
+  return strlen (vla);        // { dg-warning "\\\[-Wuninitialized" }
+}
index 5557ace..b01e4fa 100644 (file)
@@ -9,7 +9,7 @@ void
 baz (void)
 {
   int i;
-  if (i) /* { dg-warning "'i' is used uninitialized in this function" } */
+  if (i) /* { dg-warning "'i' is used uninitialized" } */
     bar (i);
   foo (&i);
 }
index 761f65b..e4b68ba 100644 (file)
@@ -4,5 +4,5 @@
 int sys_msgctl (void)
 {
   struct { int mode; } setbuf;
-  return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized in this function" } */
+  return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized" } */
 }
index 832aeb3..e9e264d 100644 (file)
@@ -6,7 +6,7 @@ extern void baz (int *);
 int
 foo (int i)
 {
-  int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */
+  int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */
 
   if (bar (i)) {
     baz (&j);
@@ -18,7 +18,7 @@ foo (int i)
 
 int foo2( void ) {
   int rc;
-  return rc; /* { dg-warning "'rc' is used uninitialized in this function" } */
+  return rc; /* { dg-warning "'rc' is used uninitialized" } */
   *&rc = 0;
 }
 
@@ -27,16 +27,16 @@ void frob(int *pi);
 
 int main(void)
 {
-  int i; 
-  printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */
+  int i;
+  printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */
   frob(&i);
 
   return 0;
 }
 
 void foo3(int*);
-void bar3(void) { 
-  int x; 
-  if(x) /* { dg-warning "'x' is used uninitialized in this function" } */
-    foo3(&x); 
+void bar3(void) {
+  int x;
+  if(x) /* { dg-warning "'x' is used uninitialized" } */
+    foo3(&x);
 }
index e00f313..417cdc6 100644 (file)
@@ -5,9 +5,9 @@ extern void baz (int *);
 int
 foo (int i)
 {
-  int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */
+  int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */
 
-  if (bar (i)) { 
+  if (bar (i)) {
     baz (&j);
   } else {
   }
@@ -19,7 +19,7 @@ foo (int i)
 
 int foo2( void ) {
   int rc;
-  return rc;  /* { dg-warning "'rc' is used uninitialized in this function" } */
+  return rc;  /* { dg-warning "'rc' is used uninitialized" } */
   *&rc = 0;
 }
 
@@ -28,16 +28,16 @@ void frob(int *pi);
 
 int main(void)
 {
-  int i; 
-  printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */
+  int i;
+  printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */
   frob(&i);
 
   return 0;
 }
 
 void foo3(int*);
-void bar3(void) { 
-  int x; 
-  if(x) /* { dg-warning "'x' is used uninitialized in this function" "uninitialized" } */
-    foo3(&x); 
+void bar3(void) {
+  int x;
+  if(x) /* { dg-warning "'x' is used uninitialized" "uninitialized" } */
+    foo3(&x);
 }
diff --git a/gcc/testsuite/gcc.dg/uninit-pr95136.c b/gcc/testsuite/gcc.dg/uninit-pr95136.c
new file mode 100644 (file)
index 0000000..47d16c5
--- /dev/null
@@ -0,0 +1,63 @@
+/* PR middle-end/95136 - missing -Wuninitialized on an array access with
+   a variable offset
+   { dg-do compile }
+   { dg-options "-O -Wall" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+NOIPA int a1_addr_varidx_plus_cst (int i)
+{
+  int a[4];              // { dg-message "'a' declared here" }
+  int *p = &a[i + 1];
+  return *p;             // { dg-warning "'a|a\\\[<unknown>]' is used uninitialized" }
+}
+
+NOIPA int a1_plus_addr_varidx_cst (int i)
+{
+  int a[4];              // { dg-message "'a' declared here" }
+  int *p = &a[i] + 1;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
+
+NOIPA int a1_plus_addr_cstidx_var (int i)
+{
+  int a[4];              // { dg-message "'a' declared here" }
+  int *p = &a[1] + i;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
+
+NOIPA int a1_plus_addr_varidx_var (int i, int j)
+{
+  int a[4];              // { dg-message "'a' declared here" }
+  int *p = &a[i] + j;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
+
+
+NOIPA int a2_addr_varidx_plus_cst (int i, int j)
+{
+  int a[4][4];           // { dg-message "'a' declared here" }
+  int *p = &a[i + 1][j + 1];
+  return *p;             // { dg-warning "'a|a\\\[<unknown>]\\\[<unknown>]' is used uninitialized" }
+}
+
+NOIPA int a2_plus_addr_varidx_cst (int i, int j)
+{
+  int a[4][4];           // { dg-message "'a' declared here" }
+  int *p = &a[i][j] + 1;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
+
+NOIPA int a2_plus_addr_cstidx_var (int i)
+{
+  int a[4][4];           // { dg-message "'a' declared here" }
+  int *p = &a[1][1] + i;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
+
+NOIPA int a2_plus_addr_varidx_var (int i, int j, int k)
+{
+  int a[4][4];           // { dg-message "'a' declared here" }
+  int *p = &a[i][j] + k;
+  return *p;             // { dg-warning "'a' is used uninitialized" }
+}
index 77181a2..37fdbca 100644 (file)
@@ -12,5 +12,5 @@
   logical :: r
   type(event), pointer :: myEvent
   allocate(myEvent)
-  r=myEvent%task()
+  r=myEvent%task()  ! { dg-warning "uninitialized" }
 end 
index 5dea42b..c77d47a 100644 (file)
@@ -4,13 +4,13 @@ subroutine acc_parallel
   implicit none
   integer :: i, j, k
 
-  !$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized in this function" }
+  !$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized" }
   !$acc end parallel
 
-  !$acc parallel num_workers(j) ! { dg-warning "is used uninitialized in this function" }
+  !$acc parallel num_workers(j) ! { dg-warning "is used uninitialized" }
   !$acc end parallel
 
-  !$acc parallel vector_length(k) ! { dg-warning "is used uninitialized in this function" }
+  !$acc parallel vector_length(k) ! { dg-warning "is used uninitialized" }
   !$acc end parallel
 end subroutine acc_parallel
 
@@ -18,12 +18,12 @@ subroutine acc_kernels
   implicit none
   integer :: i, j, k
 
-  !$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized in this function" }
+  !$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized" }
   !$acc end kernels
 
-  !$acc kernels num_workers(j) ! { dg-warning "is used uninitialized in this function" }
+  !$acc kernels num_workers(j) ! { dg-warning "is used uninitialized" }
   !$acc end kernels
 
-  !$acc kernels vector_length(k) ! { dg-warning "is used uninitialized in this function" }
+  !$acc kernels vector_length(k) ! { dg-warning "is used uninitialized" }
   !$acc end kernels
 end subroutine acc_kernels
index 14d960a..cd5d189 100644 (file)
@@ -12,7 +12,7 @@ end subroutine test
 subroutine test2
   INTEGER :: i
 
-  !$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized in this function" }
+  !$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized" }
   i = 1
   !$acc end parallel
 end subroutine test2
index 60dc53e..73eb4ee 100644 (file)
@@ -6,15 +6,15 @@ program test
   logical :: b, b2, b3, b4
   integer :: data, data2
 
-  !$acc parallel if(b) ! { dg-warning "is used uninitialized in this function" }
+  !$acc parallel if(b) ! { dg-warning "is used uninitialized" }
   !$acc end parallel
 
-  !$acc kernels if(b2) ! { dg-warning "is used uninitialized in this function" }
+  !$acc kernels if(b2) ! { dg-warning "is used uninitialized" }
   !$acc end kernels
 
-  !$acc data if(b3) ! { dg-warning "is used uninitialized in this function" }
+  !$acc data if(b3) ! { dg-warning "is used uninitialized" }
   !$acc end data
 
-  !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized in this function" }
+  !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized" }
 
 end program test
index e15d8ba..c15a2b3 100644 (file)
@@ -11,13 +11,13 @@ end program foo
 subroutine p1
    complex :: c5
    complex :: c6
-   c5 = (c5)      ! { dg-warning "used uninitialized in this" }
-   c6 = c6        ! { dg-warning "used uninitialized in this" }
+   c5 = (c5)      ! { dg-warning "used uninitialized" }
+   c6 = c6        ! { dg-warning "used uninitialized" }
 end subroutine p1
 
 subroutine q1
    real :: r5
    real :: r6
-   r5 = (r5)   ! { dg-warning "used uninitialized in this" }
-   r6 = r6     ! { dg-warning "used uninitialized in this" }
+   r5 = (r5)   ! { dg-warning "used uninitialized" }
+   r6 = r6     ! { dg-warning "used uninitialized" }
 end subroutine q1
index cc785bd..2f0ff72 100644 (file)
@@ -33,6 +33,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "tree-cfg.h"
 #include "cfghooks.h"
+#include "attribs.h"
+#include "builtins.h"
+#include "calls.h"
 
 /* This implements the pass that does predicate aware warning on uses of
    possibly uninitialized variables.  The pass first collects the set of
@@ -217,19 +220,373 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
   return true;
 }
 
+/* Counters and limits controlling the the depth of analysis and
+   strictness of the warning.  */
+struct wlimits
+{
+  /* Number of VDEFs encountered.  */
+  unsigned int vdef_cnt;
+  /* Number of statements examined by walk_aliased_vdefs.  */
+  unsigned int oracle_cnt;
+  /* Limit on the number of statements visited by walk_aliased_vdefs.  */
+  unsigned limit;
+  /* Set when basic block with statement is executed unconditionally.  */
+  bool always_executed;
+  /* Set to issue -Wmaybe-uninitialized.  */
+  bool wmaybe_uninit;
+};
+
+/* Determine if REF references an uninitialized operand and diagnose
+   it if so.  */
+
+static tree
+maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
+                   wlimits &wlims)
+{
+  bool has_bit_insert = false;
+  use_operand_p luse_p;
+  imm_use_iterator liter;
+
+  if (TREE_NO_WARNING (rhs))
+    return NULL_TREE;
+
+  /* Do not warn if the base was marked so or this is a
+     hard register var.  */
+  tree base = ao_ref_base (&ref);
+  if ((VAR_P (base)
+       && DECL_HARD_REGISTER (base))
+      || TREE_NO_WARNING (base))
+    return NULL_TREE;
+
+  /* Do not warn if the access is fully outside of the variable.  */
+  poly_int64 decl_size;
+  if (DECL_P (base)
+      && ((known_size_p (ref.size)
+          && known_eq (ref.max_size, ref.size)
+          && known_le (ref.offset + ref.size, 0))
+         || (known_ge (ref.offset, 0)
+             && DECL_SIZE (base)
+             && poly_int_tree_p (DECL_SIZE (base), &decl_size)
+             && known_le (decl_size, ref.offset))))
+    return NULL_TREE;
+
+  /* Do not warn if the result of the access is then used for
+     a BIT_INSERT_EXPR. */
+  if (lhs && TREE_CODE (lhs) == SSA_NAME)
+    FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs)
+      {
+       gimple *use_stmt = USE_STMT (luse_p);
+       /* BIT_INSERT_EXPR first operand should not be considered
+          a use for the purpose of uninit warnings.  */
+       if (gassign *ass = dyn_cast <gassign *> (use_stmt))
+         {
+           if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
+               && luse_p->use == gimple_assign_rhs1_ptr (ass))
+             {
+               has_bit_insert = true;
+               break;
+             }
+         }
+      }
+
+  if (has_bit_insert)
+    return NULL_TREE;
+
+  /* Limit the walking to a constant number of stmts after
+     we overcommit quadratic behavior for small functions
+     and O(n) behavior.  */
+  if (wlims.oracle_cnt > 128 * 128
+      && wlims.oracle_cnt > wlims.vdef_cnt * 2)
+    wlims.limit = 32;
+
+  check_defs_data data;
+  bool fentry_reached = false;
+  data.found_may_defs = false;
+  tree use = gimple_vuse (stmt);
+  if (!use)
+    return NULL_TREE;
+  int res = walk_aliased_vdefs (&ref, use,
+                               check_defs, &data, NULL,
+                               &fentry_reached, wlims.limit);
+  if (res == -1)
+    {
+      wlims.oracle_cnt += wlims.limit;
+      return NULL_TREE;
+    }
+
+  wlims.oracle_cnt += res;
+  if (data.found_may_defs)
+    return NULL_TREE;
+
+  bool found_alloc = false;
+
+  if (fentry_reached)
+    {
+      if (TREE_CODE (base) == MEM_REF)
+       base = TREE_OPERAND (base, 0);
+
+      /* Follow the chain of SSA_NAME assignments looking for an alloca
+        call (or VLA) or malloc/realloc, or for decls.  If any is found
+        (and in the latter case, the operand is a local variable) issue
+        a warning.  */
+      while (TREE_CODE (base) == SSA_NAME)
+       {
+         gimple *def_stmt = SSA_NAME_DEF_STMT (base);
+
+         if (is_gimple_call (def_stmt)
+             && gimple_call_builtin_p (def_stmt))
+           {
+             /* Detect uses of uninitialized alloca/VLAs.  */
+             tree fndecl = gimple_call_fndecl (def_stmt);
+             const built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
+             if (fncode == BUILT_IN_ALLOCA
+                 || fncode  == BUILT_IN_ALLOCA_WITH_ALIGN
+                 || fncode  == BUILT_IN_MALLOC)
+               found_alloc = true;
+             break;
+           }
+
+         if (!is_gimple_assign (def_stmt))
+           break;
+
+         tree_code code = gimple_assign_rhs_code (def_stmt);
+         if (code != ADDR_EXPR && code != POINTER_PLUS_EXPR)
+           break;
+
+         base = gimple_assign_rhs1 (def_stmt);
+         if (TREE_CODE (base) == ADDR_EXPR)
+           base = TREE_OPERAND (base, 0);
+
+         if (DECL_P (base)
+             || TREE_CODE (base) == COMPONENT_REF)
+           rhs = base;
+
+         if (TREE_CODE (base) == MEM_REF)
+           base = TREE_OPERAND (base, 0);
+
+         if (tree ba = get_base_address (base))
+           base = ba;
+       }
+
+      /* Replace the RHS expression with BASE so that it
+        refers to it in the diagnostic (instead of to
+        '<unknown>').  */
+      if (DECL_P (base)
+         && EXPR_P (rhs)
+         && TREE_CODE (rhs) != COMPONENT_REF)
+       rhs = base;
+    }
+
+  /* Do not warn if it can be initialized outside this function.
+     If we did not reach function entry then we found killing
+     clobbers on all paths to entry.  */
+  if (!found_alloc
+      && fentry_reached
+      /* ???  We'd like to use ref_may_alias_global_p but that
+        excludes global readonly memory and thus we get bogus
+        warnings from p = cond ? "a" : "b" for example.  */
+      && (!VAR_P (base)
+         || is_global_var (base)))
+    return NULL_TREE;
+
+  /* Strip the address-of expression from arrays passed to functions. */
+  if (TREE_CODE (rhs) == ADDR_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
+
+  /* Check again since RHS may have changed above.  */
+  if (TREE_NO_WARNING (rhs))
+    return NULL_TREE;
+
+  /* Avoid warning about empty types such as structs with no members.
+     The first_field() test is important for C++ where the predicate
+     alone isn't always sufficient.  */
+  tree rhstype = TREE_TYPE (rhs);
+  if (TYPE_EMPTY_P (rhstype)
+      || (RECORD_OR_UNION_TYPE_P (rhstype)
+         && (!first_field (rhstype)
+             || default_is_empty_record (rhstype))))
+    return NULL_TREE;
+
+  bool warned = false;
+  /* We didn't find any may-defs so on all paths either
+     reached function entry or a killing clobber.  */
+  location_t location
+    = linemap_resolve_location (line_table, gimple_location (stmt),
+                               LRK_SPELLING_LOCATION, NULL);
+  if (wlims.always_executed)
+    {
+      if (warning_at (location, OPT_Wuninitialized,
+                     "%G%qE is used uninitialized", stmt, rhs))
+       {
+         /* ???  This is only effective for decls as in
+            gcc.dg/uninit-B-O0.c.  Avoid doing this for maybe-uninit
+            uses or accesses by functions as it may hide important
+            locations.  */
+         if (lhs)
+           TREE_NO_WARNING (rhs) = 1;
+         warned = true;
+       }
+    }
+  else if (wlims.wmaybe_uninit)
+    warned = warning_at (location, OPT_Wmaybe_uninitialized,
+                        "%G%qE may be used uninitialized", stmt, rhs);
+
+  return warned ? base : NULL_TREE;
+}
+
+
+/* Diagnose passing addresses of uninitialized objects to either const
+   pointer arguments to functions, or to functions declared with attribute
+   access implying read access to those objects.  */
+
+static void
+maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
+{
+  if (!wlims.wmaybe_uninit)
+    return;
+
+  unsigned nargs = gimple_call_num_args (stmt);
+  if (!nargs)
+    return;
+
+  tree fndecl = gimple_call_fndecl (stmt);
+  tree fntype = gimple_call_fntype (stmt);
+  if (!fntype)
+    return;
+
+  const built_in_function fncode
+    = (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
+       ? DECL_FUNCTION_CODE (fndecl) : (built_in_function)BUILT_IN_LAST);
+
+  if (fncode == BUILT_IN_MEMCPY || fncode == BUILT_IN_MEMMOVE)
+    /* Avoid diagnosing calls to raw memory functions (this is overly
+       permissive; consider tightening it up).  */
+    return;
+
+  /* Save the current warning setting and replace it either a "maybe"
+     when passing addresses of uninitialized variables to const-qualified
+     pointers or arguments declared with attribute read_write, or with
+     a "certain" when passing them to arguments declared with attribute
+     read_only.  */
+  const bool save_always_executed = wlims.always_executed;
+
+  /* Map of attribute access specifications for function arguments.  */
+  rdwr_map rdwr_idx;
+  init_attr_rdwr_indices (&rdwr_idx, fntype);
+
+  tree argtype;
+  unsigned argno = 0;
+  function_args_iterator it;
+
+  FOREACH_FUNCTION_ARGS (fntype, argtype, it)
+    {
+      ++argno;
+
+      if (!POINTER_TYPE_P (argtype))
+       continue;
+
+      tree access_size = NULL_TREE;
+      attr_access *access = rdwr_idx.get (argno - 1);
+      if (access)
+       {
+         if (access->mode == attr_access::none
+             || access->mode == attr_access::write_only)
+           continue;
+         if (save_always_executed && access->mode == attr_access::read_only)
+           /* Attribute read_only arguments imply read access.  */
+           wlims.always_executed = true;
+         else
+           /* Attribute read_write arguments are documented as requiring
+              initialized objects but it's expected that aggregates may
+              be only partially initialized regardless.  */
+           wlims.always_executed = false;
+
+         if (access->sizarg < nargs)
+           access_size = gimple_call_arg (stmt, access->sizarg);
+       }
+      else if (!TYPE_READONLY (TREE_TYPE (argtype)))
+       continue;
+      else if (save_always_executed && fncode != BUILT_IN_LAST)
+       /* Const-qualified arguments to built-ins imply read access.  */
+       wlims.always_executed = true;
+      else
+       /* Const-qualified arguments to ordinary functions imply a likely
+          (but not definitive) read access.  */
+       wlims.always_executed = false;
+
+      tree arg = gimple_call_arg (stmt, argno - 1);
+
+      ao_ref ref;
+      ao_ref_init_from_ptr_and_size (&ref, arg, access_size);
+      tree argbase = maybe_warn_operand (ref, stmt, NULL_TREE, arg, wlims);
+      if (!argbase)
+       continue;
+
+      if (access)
+       {
+         const char* const mode = (access->mode == attr_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, ")");
+
+         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);
+           }
+         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);
+           }
+       }
+      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);
+       }
+
+      if (DECL_P (argbase))
+       {
+         location_t loc = DECL_SOURCE_LOCATION (argbase);
+         inform (loc, "%qD declared here", argbase);
+       }
+    }
+
+  wlims.always_executed = save_always_executed;
+}
+
+
 static unsigned int
-warn_uninitialized_vars (bool warn_possibly_uninitialized)
+warn_uninitialized_vars (bool wmaybe_uninit)
 {
+  /* Counters and limits controlling the the depth of the warning.  */
+  wlimits wlims = { };
+  wlims.wmaybe_uninit = wmaybe_uninit;
+
   gimple_stmt_iterator gsi;
   basic_block bb;
-  unsigned int vdef_cnt = 0;
-  unsigned int oracle_cnt = 0;
-  unsigned limit = 0;
-
   FOR_EACH_BB_FN (bb, cfun)
     {
       basic_block succ = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-      bool always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb);
+      wlims.always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb);
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
          gimple *stmt = gsi_stmt (gsi);
@@ -253,131 +610,42 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
                    continue;
                }
              use = USE_FROM_PTR (use_p);
-             if (always_executed)
+             if (wlims.always_executed)
                warn_uninit (OPT_Wuninitialized, use, SSA_NAME_VAR (use),
                             SSA_NAME_VAR (use),
-                            "%qD is used uninitialized in this function", stmt,
+                            "%qD is used uninitialized", stmt,
                             UNKNOWN_LOCATION);
-             else if (warn_possibly_uninitialized)
+             else if (wmaybe_uninit)
                warn_uninit (OPT_Wmaybe_uninitialized, use, SSA_NAME_VAR (use),
                             SSA_NAME_VAR (use),
-                            "%qD may be used uninitialized in this function",
+                            "%qD may be used uninitialized",
                             stmt, UNKNOWN_LOCATION);
            }
 
          /* For limiting the alias walk below we count all
             vdefs in the function.  */
          if (gimple_vdef (stmt))
-           vdef_cnt++;
+           wlims.vdef_cnt++;
 
-         if (gimple_assign_load_p (stmt)
-             && gimple_has_location (stmt))
+         if (is_gimple_call (stmt))
+           maybe_warn_pass_by_reference (stmt, wlims);
+         else if (gimple_assign_load_p (stmt)
+                  && gimple_has_location (stmt))
            {
              tree rhs = gimple_assign_rhs1 (stmt);
              tree lhs = gimple_assign_lhs (stmt);
-             bool has_bit_insert = false;
-             use_operand_p luse_p;
-             imm_use_iterator liter;
-
-             if (TREE_NO_WARNING (rhs))
-               continue;
 
              ao_ref ref;
              ao_ref_init (&ref, rhs);
-
-             /* Do not warn if the base was marked so or this is a
-                hard register var.  */
-             tree base = ao_ref_base (&ref);
-             if ((VAR_P (base)
-                  && DECL_HARD_REGISTER (base))
-                 || TREE_NO_WARNING (base))
-               continue;
-
-             /* Do not warn if the access is fully outside of the
-                variable.  */
-             poly_int64 decl_size;
-             if (DECL_P (base)
-                 && known_size_p (ref.size)
-                 && ((known_eq (ref.max_size, ref.size)
-                      && known_le (ref.offset + ref.size, 0))
-                     || (known_ge (ref.offset, 0)
-                         && DECL_SIZE (base)
-                         && poly_int_tree_p (DECL_SIZE (base), &decl_size)
-                         && known_le (decl_size, ref.offset))))
-               continue;
-
-             /* Do not warn if the access is then used for a BIT_INSERT_EXPR. */
-             if (TREE_CODE (lhs) == SSA_NAME)
-               FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs)
-                 {
-                   gimple *use_stmt = USE_STMT (luse_p);
-                    /* BIT_INSERT_EXPR first operand should not be considered
-                      a use for the purpose of uninit warnings.  */
-                   if (gassign *ass = dyn_cast <gassign *> (use_stmt))
-                     {
-                       if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
-                           && luse_p->use == gimple_assign_rhs1_ptr (ass))
-                         {
-                           has_bit_insert = true;
-                           break;
-                         }
-                     }
-                 }
-             if (has_bit_insert)
-               continue;
-
-             /* Limit the walking to a constant number of stmts after
-                we overcommit quadratic behavior for small functions
-                and O(n) behavior.  */
-             if (oracle_cnt > 128 * 128
-                 && oracle_cnt > vdef_cnt * 2)
-               limit = 32;
-             check_defs_data data;
-             bool fentry_reached = false;
-             data.found_may_defs = false;
-             use = gimple_vuse (stmt);
-             int res = walk_aliased_vdefs (&ref, use,
-                                           check_defs, &data, NULL,
-                                           &fentry_reached, limit);
-             if (res == -1)
-               {
-                 oracle_cnt += limit;
-                 continue;
-               }
-             oracle_cnt += res;
-             if (data.found_may_defs)
-               continue;
-             /* Do not warn if it can be initialized outside this function.
-                If we did not reach function entry then we found killing
-                clobbers on all paths to entry.  */
-             if (fentry_reached
-                 /* ???  We'd like to use ref_may_alias_global_p but that
-                    excludes global readonly memory and thus we get bougs
-                    warnings from p = cond ? "a" : "b" for example.  */
-                 && (!VAR_P (base)
-                     || is_global_var (base)))
+             tree var = maybe_warn_operand (ref, stmt, lhs, rhs, wlims);
+             if (!var)
                continue;
 
-             /* We didn't find any may-defs so on all paths either
-                reached function entry or a killing clobber.  */
-             location_t location
-               = linemap_resolve_location (line_table, gimple_location (stmt),
-                                           LRK_SPELLING_LOCATION, NULL);
-             if (always_executed)
+             if (DECL_P (var))
                {
-                 if (warning_at (location, OPT_Wuninitialized,
-                                 "%qE is used uninitialized in this function",
-                                 rhs))
-                   /* ???  This is only effective for decls as in
-                      gcc.dg/uninit-B-O0.c.  Avoid doing this for
-                      maybe-uninit uses as it may hide important
-                      locations.  */
-                   TREE_NO_WARNING (rhs) = 1;
+                 location_t loc = DECL_SOURCE_LOCATION (var);
+                 inform (loc, "%qD declared here", var);
                }
-             else if (warn_possibly_uninitialized)
-               warning_at (location, OPT_Wmaybe_uninitialized,
-                           "%qE may be used uninitialized in this function",
-                           rhs);
            }
        }
     }
@@ -2665,7 +2933,7 @@ pass_late_warn_uninitialized::execute (function *fun)
   /* Re-do the plain uninitialized variable check, as optimization may have
      straightened control flow.  Do this first so that we don't accidentally
      get a "may be" warning when we'd have seen an "is" warning later.  */
-  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1);
+  warn_uninitialized_vars (/*warn_maybe_uninitialized=*/1);
 
   timevar_push (TV_TREE_UNINIT);
 
@@ -2735,7 +3003,7 @@ execute_early_warn_uninitialized (void)
      optimization we need to warn here about "may be uninitialized".  */
   calculate_dominance_info (CDI_POST_DOMINATORS);
 
-  warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
+  warn_uninitialized_vars (/*warn_maybe_uninitialized=*/!optimize);
 
   /* Post-dominator information cannot be reliably updated.  Free it
      after the use.  */