}
}
+/* 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
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
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.
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_;
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;
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 */
/* 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");
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;
}
}
}
- 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])))
{
/* 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;
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. */
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 ? ", " : "";
/* 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;
}
}
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
/* 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);
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);
}
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
__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
snprintf (p, sizeof (buf), "%s", y);
vsnprintf (p, sizeof (buf), "%s", ap);
}
+
+/* { dg-prune-output "-Wuninitialized" } */
{
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" } */
;
}
{
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" } */
;
}
{
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;
}
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++ } } */
;
}
{
{
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);
}
{
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);
}
{
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);
}
{
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);
}
{
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);
}
{
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);
}
{
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);
}
{
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);
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;
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" } */
}
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(); }
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; }
};
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" }
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);
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" } */
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" } */
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" }
}
int *p = &i;
return p[2]; // { dg-warning "-Warray-bounds" }
}
+
+/* { dg-prune-output "-Wuninitialized" } */
--- /dev/null
+/* 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" } */
--- /dev/null
+/* 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" }
+}
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" }
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" } */
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" }
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" } */
}
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" } */
inline int
foo (int i)
{
- if (i) /* { dg-warning "used uninitialized in this function" "" } */
+ if (i) /* { dg-warning "used uninitialized" } */
return 1;
return 0;
}
--- /dev/null
+/* 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" }
+}
--- /dev/null
+/* 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" }
+}
--- /dev/null
+/* 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" }
+}
--- /dev/null
+/* 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" }
+}
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);
}
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" } */
}
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);
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;
}
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);
}
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 {
}
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;
}
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);
}
--- /dev/null
+/* 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" }
+}
logical :: r
type(event), pointer :: myEvent
allocate(myEvent)
- r=myEvent%task()
+ r=myEvent%task() ! { dg-warning "uninitialized" }
end
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
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
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
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
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
#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
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);
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);
}
}
}
/* 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);
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. */