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
This commit is contained in:
Martin Sebor
2020-06-04 16:06:10 -06:00
parent 2cbc99d18d
commit b825a22890
43 changed files with 1567 additions and 317 deletions

View 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

View 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

View 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;

View 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 */

View 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;

View 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);
}

View 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

View 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" } */

View 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" } */
;
}

View 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;
}

View 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++ } } */
;
}

View 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);

View 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;

View 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" } */
}

View 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(); }

View 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; }
};

View 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);

View 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" } */

View 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" } */

View 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" } */

View File

@@ -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" } */

View File

@@ -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" }
}

View 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" }

View 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" } */

View 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" }

View 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" } */
}

View 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" } */

View 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;
}

View File

@@ -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" }
}

View File

@@ -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" }
}

View File

@@ -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" }
}

View File

@@ -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" }
}

View 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);
}

View 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" } */
}

View 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);
}

View 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);
}

View File

@@ -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" }
}

View File

@@ -12,5 +12,5 @@
logical :: r
type(event), pointer :: myEvent
allocate(myEvent)
r=myEvent%task()
r=myEvent%task() ! { dg-warning "uninitialized" }
end

View 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

View 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

View 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

View 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

View 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;
}
static unsigned int
warn_uninitialized_vars (bool warn_possibly_uninitialized)
/* 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 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))
tree var = maybe_warn_operand (ref, stmt, lhs, rhs, wlims);
if (!var)
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)
if (DECL_P (var))
{
oracle_cnt += limit;
continue;
location_t loc = DECL_SOURCE_LOCATION (var);
inform (loc, "%qD declared here", var);
}
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)))
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 (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;
}
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. */