aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-06-04 16:06:10 -0600
committerMartin Sebor <msebor@redhat.com>2020-06-04 16:08:32 -0600
commitb825a22890740f341eae566af27e18e528cd29a7 (patch)
treeb614b6b24e6395784b9eb80af79352ce9bca555f /gcc
parent2cbc99d18dc411ac3fdef94e22ce86859806e63c (diff)
downloadgcc-b825a22890740f341eae566af27e18e528cd29a7.zip
gcc-b825a22890740f341eae566af27e18e528cd29a7.tar.gz
gcc-b825a22890740f341eae566af27e18e528cd29a7.tar.bz2
Implement a solution for PR middle-end/10138 and PR middle-end/95136.
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/attribs.c59
-rw-r--r--gcc/attribs.h12
-rw-r--r--gcc/builtins.c126
-rw-r--r--gcc/builtins.h3
-rw-r--r--gcc/c-family/c-attribs.c29
-rw-r--r--gcc/calls.c83
-rw-r--r--gcc/doc/extend.texi12
-rw-r--r--gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c2
-rw-r--r--gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c12
-rw-r--r--gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c2
-rw-r--r--gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c16
-rw-r--r--gcc/testsuite/c-c++-common/gomp/pr70550-1.c16
-rw-r--r--gcc/testsuite/c-c++-common/gomp/pr70550-2.c16
-rw-r--r--gcc/testsuite/c-c++-common/uninit-pr51010.c4
-rw-r--r--gcc/testsuite/g++.dg/20090107-1.C2
-rw-r--r--gcc/testsuite/g++.dg/20090121-1.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-access.C4
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-52.c3
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-53.c3
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-54.c6
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-33.c40
-rw-r--r--gcc/testsuite/gcc.dg/attr-access-none.c38
-rw-r--r--gcc/testsuite/gcc.dg/attr-access-read-only.c2
-rw-r--r--gcc/testsuite/gcc.dg/attr-access-read-write.c2
-rw-r--r--gcc/testsuite/gcc.dg/attr-access-write-only.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr71581.c6
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c3
-rw-r--r--gcc/testsuite/gcc.dg/uninit-15.c2
-rw-r--r--gcc/testsuite/gcc.dg/uninit-32.c312
-rw-r--r--gcc/testsuite/gcc.dg/uninit-33.c145
-rw-r--r--gcc/testsuite/gcc.dg/uninit-34.c58
-rw-r--r--gcc/testsuite/gcc.dg/uninit-36.c237
-rw-r--r--gcc/testsuite/gcc.dg/uninit-B-O0.c2
-rw-r--r--gcc/testsuite/gcc.dg/uninit-I-O0.c2
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr19430-O0.c16
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr19430.c18
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr95136.c63
-rw-r--r--gcc/testsuite/gfortran.dg/assignment_4.f902
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f9512
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f952
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f958
-rw-r--r--gcc/testsuite/gfortran.dg/pr66545_2.f908
-rw-r--r--gcc/tree-ssa-uninit.c490
43 files changed, 1566 insertions, 316 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 7d0f4b5..71dae12 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -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
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 8d79464..dea0b6c 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index f7bb87e..667d36c 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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;
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 7d8b9cd..73e85d6 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -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 */
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 7a6fb9a..193c4cd 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -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;
diff --git a/gcc/calls.c b/gcc/calls.c
index 8041388..d1c9c0b 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -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);
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index cced19d..e656e66 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c
index 4281e3b..c4127b8 100644
--- a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c
+++ b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c
@@ -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" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c
index 9f11196..827dac7 100644
--- a/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c
+++ b/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c
@@ -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" } */
;
}
diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c
index 2584033..334567d 100644
--- a/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c
+++ b/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c
@@ -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;
}
diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c
index 55caa4c..7f78d72 100644
--- a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c
+++ b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c
@@ -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++ } } */
;
}
diff --git a/gcc/testsuite/c-c++-common/gomp/pr70550-1.c b/gcc/testsuite/c-c++-common/gomp/pr70550-1.c
index 493d417..d0d2fa5 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr70550-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr70550-1.c
@@ -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);
diff --git a/gcc/testsuite/c-c++-common/gomp/pr70550-2.c b/gcc/testsuite/c-c++-common/gomp/pr70550-2.c
index 31c34da..936d907 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr70550-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr70550-2.c
@@ -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;
diff --git a/gcc/testsuite/c-c++-common/uninit-pr51010.c b/gcc/testsuite/c-c++-common/uninit-pr51010.c
index f28da46..9fd1ea3 100644
--- a/gcc/testsuite/c-c++-common/uninit-pr51010.c
+++ b/gcc/testsuite/c-c++-common/uninit-pr51010.c
@@ -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" } */
}
diff --git a/gcc/testsuite/g++.dg/20090107-1.C b/gcc/testsuite/g++.dg/20090107-1.C
index ff586e8..80b88f0 100644
--- a/gcc/testsuite/g++.dg/20090107-1.C
+++ b/gcc/testsuite/g++.dg/20090107-1.C
@@ -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(); }
diff --git a/gcc/testsuite/g++.dg/20090121-1.C b/gcc/testsuite/g++.dg/20090121-1.C
index ddfa3ad..9d70fb3 100644
--- a/gcc/testsuite/g++.dg/20090121-1.C
+++ b/gcc/testsuite/g++.dg/20090121-1.C
@@ -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; }
};
diff --git a/gcc/testsuite/g++.dg/ext/attr-access.C b/gcc/testsuite/g++.dg/ext/attr-access.C
index fcb54cd..3b9c1a3 100644
--- a/gcc/testsuite/g++.dg/ext/attr-access.C
+++ b/gcc/testsuite/g++.dg/ext/attr-access.C
@@ -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);
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-52.c b/gcc/testsuite/gcc.dg/Warray-bounds-52.c
index 1a7d76f..729ad45 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-52.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-52.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-53.c b/gcc/testsuite/gcc.dg/Warray-bounds-53.c
index 0f06222..80db314 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-53.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-53.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-54.c b/gcc/testsuite/gcc.dg/Warray-bounds-54.c
index 644fcd0..5df5710 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-54.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-54.c
@@ -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
index 0000000..cb8aeb9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c
@@ -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
index 0000000..d983f2f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-access-none.c
@@ -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" }
+}
diff --git a/gcc/testsuite/gcc.dg/attr-access-read-only.c b/gcc/testsuite/gcc.dg/attr-access-read-only.c
index 9acd769..71175d0 100644
--- a/gcc/testsuite/gcc.dg/attr-access-read-only.c
+++ b/gcc/testsuite/gcc.dg/attr-access-read-only.c
@@ -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" }
diff --git a/gcc/testsuite/gcc.dg/attr-access-read-write.c b/gcc/testsuite/gcc.dg/attr-access-read-write.c
index c97e54b..849d9f1 100644
--- a/gcc/testsuite/gcc.dg/attr-access-read-write.c
+++ b/gcc/testsuite/gcc.dg/attr-access-read-write.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/attr-access-write-only.c b/gcc/testsuite/gcc.dg/attr-access-write-only.c
index 008f5a3..2718b0d 100644
--- a/gcc/testsuite/gcc.dg/attr-access-write-only.c
+++ b/gcc/testsuite/gcc.dg/attr-access-write-only.c
@@ -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" }
diff --git a/gcc/testsuite/gcc.dg/pr71581.c b/gcc/testsuite/gcc.dg/pr71581.c
index d82eb1e..dd71dde 100644
--- a/gcc/testsuite/gcc.dg/pr71581.c
+++ b/gcc/testsuite/gcc.dg/pr71581.c
@@ -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" } */
}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c
index 3f50243..24b1767 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/uninit-15.c b/gcc/testsuite/gcc.dg/uninit-15.c
index 67aac41..8ee10c2 100644
--- a/gcc/testsuite/gcc.dg/uninit-15.c
+++ b/gcc/testsuite/gcc.dg/uninit-15.c
@@ -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
index 0000000..cdc0512
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-32.c
@@ -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
index 0000000..a45f18d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-33.c
@@ -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
index 0000000..9de6183
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-34.c
@@ -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
index 0000000..9524e7a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-36.c
@@ -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" }
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-B-O0.c b/gcc/testsuite/gcc.dg/uninit-B-O0.c
index 5557ace..b01e4fa 100644
--- a/gcc/testsuite/gcc.dg/uninit-B-O0.c
+++ b/gcc/testsuite/gcc.dg/uninit-B-O0.c
@@ -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);
}
diff --git a/gcc/testsuite/gcc.dg/uninit-I-O0.c b/gcc/testsuite/gcc.dg/uninit-I-O0.c
index 761f65b..e4b68ba 100644
--- a/gcc/testsuite/gcc.dg/uninit-I-O0.c
+++ b/gcc/testsuite/gcc.dg/uninit-I-O0.c
@@ -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" } */
}
diff --git a/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c b/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c
index 832aeb3..e9e264d 100644
--- a/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c
+++ b/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c
@@ -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);
}
diff --git a/gcc/testsuite/gcc.dg/uninit-pr19430.c b/gcc/testsuite/gcc.dg/uninit-pr19430.c
index e00f313..417cdc6 100644
--- a/gcc/testsuite/gcc.dg/uninit-pr19430.c
+++ b/gcc/testsuite/gcc.dg/uninit-pr19430.c
@@ -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
index 0000000..47d16c5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr95136.c
@@ -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" }
+}
diff --git a/gcc/testsuite/gfortran.dg/assignment_4.f90 b/gcc/testsuite/gfortran.dg/assignment_4.f90
index 77181a2..37fdbca 100644
--- a/gcc/testsuite/gfortran.dg/assignment_4.f90
+++ b/gcc/testsuite/gfortran.dg/assignment_4.f90
@@ -12,5 +12,5 @@
logical :: r
type(event), pointer :: myEvent
allocate(myEvent)
- r=myEvent%task()
+ r=myEvent%task() ! { dg-warning "uninitialized" }
end
diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95
index 5dea42b..c77d47a 100644
--- a/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95
+++ b/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95
@@ -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
diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95
index 14d960a..cd5d189 100644
--- a/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95
+++ b/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95
@@ -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
diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
index 60dc53e..73eb4ee 100644
--- a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
+++ b/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95
@@ -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
diff --git a/gcc/testsuite/gfortran.dg/pr66545_2.f90 b/gcc/testsuite/gfortran.dg/pr66545_2.f90
index e15d8ba..c15a2b3 100644
--- a/gcc/testsuite/gfortran.dg/pr66545_2.f90
+++ b/gcc/testsuite/gfortran.dg/pr66545_2.f90
@@ -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
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index cc785bd..2f0ff72 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -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. */