From: Martin Sebor Date: Thu, 4 Jun 2020 22:06:10 +0000 (-0600) Subject: Implement a solution for PR middle-end/10138 and PR middle-end/95136. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b825a22890740f341eae566af27e18e528cd29a7;p=gcc.git 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 --- diff --git a/gcc/attribs.c b/gcc/attribs.c index 7d0f4b5b7b4..71dae123af8 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -2017,6 +2017,65 @@ maybe_diag_alias_attributes (tree alias, tree target) } } +/* Initialize a mapping for a call to function FNDECL declared with + attribute access. Each attribute positional operand inserts one + entry into the mapping with the operand number as the key. */ + +void +init_attr_rdwr_indices (rdwr_map *rwm, tree fntype) +{ + if (!fntype) + return; + + for (tree access = TYPE_ATTRIBUTES (fntype); + (access = lookup_attribute ("access", access)); + access = TREE_CHAIN (access)) + { + /* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE + is the attribute argument's value. */ + tree mode = TREE_VALUE (access); + gcc_assert (TREE_CODE (mode) == TREE_LIST); + mode = TREE_VALUE (mode); + gcc_assert (TREE_CODE (mode) == STRING_CST); + + const char *modestr = TREE_STRING_POINTER (mode); + for (const char *m = modestr; *m; ) + { + attr_access acc = { }; + + switch (*m) + { + case 'r': acc.mode = acc.read_only; break; + case 'w': acc.mode = acc.write_only; break; + case 'x': acc.mode = acc.read_write; break; + case '-': acc.mode = acc.none; break; + default: gcc_unreachable (); + } + + char *end; + acc.ptrarg = strtoul (++m, &end, 10); + m = end; + if (*m == ',') + { + acc.sizarg = strtoul (++m, &end, 10); + m = end; + } + else + acc.sizarg = UINT_MAX; + + acc.ptr = NULL_TREE; + acc.size = NULL_TREE; + + /* Unconditionally add an entry for the required pointer + operand of the attribute, and one for the optional size + operand when it's specified. */ + rwm->put (acc.ptrarg, acc); + if (acc.sizarg != UINT_MAX) + rwm->put (acc.sizarg, acc); + } + } +} + #if CHECKING_P diff --git a/gcc/attribs.h b/gcc/attribs.h index 8d794649b3e..dea0b6c44e6 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -234,8 +234,18 @@ struct attr_access unsigned sizarg; /* The access mode. */ - enum access_mode { read_only, write_only, read_write }; + enum access_mode { none, read_only, write_only, read_write }; access_mode mode; }; +/* Used to define rdwr_map below. */ +struct rdwr_access_hash: int_hash { }; + +/* 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_map; + +extern void init_attr_rdwr_indices (rdwr_map *, tree); + #endif // GCC_ATTRIBS_H diff --git a/gcc/builtins.c b/gcc/builtins.c index f7bb87e4690..667d36c940b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3310,6 +3310,90 @@ determine_block_size (tree len, rtx len_rtx, GET_MODE_MASK (GET_MODE (len_rtx))); } +/* For an expression EXP issue an access warning controlled by option OPT + with access to a region SLEN bytes in size in the RANGE of sizes. */ + +static bool +warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2], + tree slen, bool access) +{ + bool warned = false; + + if (access) + { + if (tree_int_cst_equal (range[0], range[1])) + warned = (func + ? warning_n (loc, opt, tree_to_uhwi (range[0]), + "%K%qD reading %E byte from a region of size %E", + "%K%qD reading %E bytes from a region of size %E", + exp, func, range[0], slen) + : warning_n (loc, opt, tree_to_uhwi (range[0]), + "%Kreading %E byte from a region of size %E", + "%Kreading %E bytes from a region of size %E", + exp, range[0], slen)); + else if (tree_int_cst_sign_bit (range[1])) + { + /* Avoid printing the upper bound if it's invalid. */ + warned = (func + ? warning_at (loc, opt, + "%K%qD reading %E or more bytes from a region " + "of size %E", + exp, func, range[0], slen) + : warning_at (loc, opt, + "%Kreading %E or more bytes from a region " + "of size %E", + exp, range[0], slen)); + } + else + warned = (func + ? warning_at (loc, opt, + "%K%qD reading between %E and %E bytes from " + "a region of size %E", + exp, func, range[0], range[1], slen) + : warning_at (loc, opt, + "%Kreading between %E and %E bytes from " + "a region of size %E", + exp, range[0], range[1], slen)); + + return warned; + } + + if (tree_int_cst_equal (range[0], range[1])) + warned = (func + ? warning_n (loc, opt, tree_to_uhwi (range[0]), + "%K%qD epecting %E byte in a region of size %E", + "%K%qD expecting %E bytes in a region of size %E", + exp, func, range[0], slen) + : warning_n (loc, opt, tree_to_uhwi (range[0]), + "%Kexpecting %E byte in a region of size %E", + "%Kexpecting %E bytes in a region of size %E", + exp, range[0], slen)); + else if (tree_int_cst_sign_bit (range[1])) + { + /* Avoid printing the upper bound if it's invalid. */ + warned = (func + ? warning_at (loc, opt, + "%K%qD expecting %E or more bytes in a region " + "of size %E", + exp, func, range[0], slen) + : warning_at (loc, opt, + "%Kexpecting %E or more bytes in a region " + "of size %E", + exp, range[0], slen)); + } + else + warned = (func + ? warning_at (loc, opt, + "%K%qD expecting between %E and %E bytes in " + "a region of size %E", + exp, func, range[0], range[1], slen) + : warning_at (loc, opt, + "%Kexpectting between %E and %E bytes in " + "a region of size %E", + exp, range[0], range[1], slen)); + return warned; +} + /* Try to verify that the sizes and lengths of the arguments to a string manipulation function given by EXP are within valid bounds and that the operation does not lead to buffer overflow or read past the end. @@ -3336,12 +3420,16 @@ determine_block_size (tree len, rtx len_rtx, When DSTWRITE is null LEN is checked to verify that it doesn't exceed SIZE_MAX. + ACCESS is true for accesses, false for simple size checks in calls + to functions that neither read from nor write to the region. + If the call is successfully verified as safe return true, otherwise return false. */ bool check_access (tree exp, tree, tree, tree dstwrite, - tree maxread, tree srcstr, tree dstsize) + tree maxread, tree srcstr, tree dstsize, + bool access /* = true */) { int opt = OPT_Wstringop_overflow_; @@ -3649,44 +3737,10 @@ check_access (tree exp, tree, tree, tree dstwrite, if (TREE_NO_WARNING (exp)) return false; - bool warned = false; location_t loc = tree_nonartificial_location (exp); loc = expansion_point_location_if_in_system_header (loc); - if (tree_int_cst_equal (range[0], range[1])) - warned = (func - ? warning_n (loc, opt, tree_to_uhwi (range[0]), - "%K%qD reading %E byte from a region of size %E", - "%K%qD reading %E bytes from a region of size %E", - exp, func, range[0], slen) - : warning_n (loc, opt, tree_to_uhwi (range[0]), - "%Kreading %E byte from a region of size %E", - "%Kreading %E bytes from a region of size %E", - exp, range[0], slen)); - else if (tree_int_cst_sign_bit (range[1])) - { - /* Avoid printing the upper bound if it's invalid. */ - warned = (func - ? warning_at (loc, opt, - "%K%qD reading %E or more bytes from a region " - "of size %E", - exp, func, range[0], slen) - : warning_at (loc, opt, - "%Kreading %E or more bytes from a region " - "of size %E", - exp, range[0], slen)); - } - else - warned = (func - ? warning_at (loc, opt, - "%K%qD reading between %E and %E bytes from " - "a region of size %E", - exp, func, range[0], range[1], slen) - : warning_at (loc, opt, - "%Kreading between %E and %E bytes from " - "a region of size %E", - exp, range[0], range[1], slen)); - if (warned) + if (warn_for_access (loc, func, exp, opt, range, slen, access)) TREE_NO_WARNING (exp) = true; return false; diff --git a/gcc/builtins.h b/gcc/builtins.h index 7d8b9cddf73..73e85d66e9b 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -156,7 +156,8 @@ bool check_nul_terminated_array (tree, tree, tree = NULL_TREE); extern void warn_string_no_nul (location_t, const char *, tree, tree); extern tree unterminated_array (tree, tree * = NULL, bool * = NULL); extern bool builtin_with_linkage_p (tree); -extern bool check_access (tree, tree, tree, tree, tree, tree, tree); +extern bool check_access (tree, tree, tree, tree, tree, tree, tree, + bool = true); #endif /* GCC_BUILTINS_H */ diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 7a6fb9af6da..193c4cd7cd0 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -3875,14 +3875,17 @@ append_access_attrs (tree t, tree attrs, const char *attrstr, /* Found a matching positional argument. */ if (*attrspec != pos[-1]) { + const char* const modestr + = (pos[-1] == 'r' + ? "read_only" + : (pos[-1] == 'w' + ? "write_only" + : (pos[-1] == 'x' ? "read_write" : "none"))); /* Mismatch in access mode. */ auto_diagnostic_group d; if (warning (OPT_Wattributes, "attribute %qs mismatch with mode %qs", - attrstr, - (pos[-1] == 'r' - ? "read_only" - : (pos[-1] == 'w' ? "write_only" : "read_write"))) + attrstr, modestr) && DECL_P (t)) inform (DECL_SOURCE_LOCATION (t), "previous declaration here"); @@ -4014,13 +4017,14 @@ handle_access_attribute (tree *node, tree name, tree args, ps += 2; } - const bool read_only = strncmp (ps, "read_only", 9) == 0; - const bool write_only = strncmp (ps, "write_only", 10) == 0; - if (!read_only && !write_only && strncmp (ps, "read_write", 10)) + const bool read_only = !strncmp (ps, "read_only", 9); + const bool write_only = !strncmp (ps, "write_only", 10); + const bool read_write = !strncmp (ps, "read_write", 10); + if (!read_only && !write_only && !read_write && strncmp (ps, "none", 4)) { error ("attribute %qE invalid mode %qs; expected one of " - "%qs, %qs, or %qs", name, access_str, - "read_only", "read_write", "write_only"); + "%qs, %qs, %qs, or %qs", name, access_str, + "read_only", "read_write", "write_only", "none"); return NULL_TREE; } @@ -4145,9 +4149,9 @@ handle_access_attribute (tree *node, tree name, tree args, } } - if (!read_only) + if (read_write || write_only) { - /* A read_write and write_only modes must reference non-const + /* Read_write and write_only modes must reference non-const arguments. */ if (TYPE_READONLY (TREE_TYPE (argtypes[0]))) { @@ -4178,7 +4182,8 @@ handle_access_attribute (tree *node, tree name, tree args, /* Verify that the new attribute doesn't conflict with any existing attributes specified on previous declarations of the same type and if not, concatenate the two. */ - const char code = read_only ? 'r' : write_only ? 'w' : 'x'; + const char code + = read_only ? 'r' : write_only ? 'w' : read_write ? 'x' : '-'; tree new_attrs = append_access_attrs (node[0], attrs, attrstr, code, idxs); if (!new_attrs) return NULL_TREE; diff --git a/gcc/calls.c b/gcc/calls.c index 8041388c1d2..d1c9c0b159a 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1865,70 +1865,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason) error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); } -/* Used to define rdwr_map below. */ -struct rdwr_access_hash: int_hash { }; - -/* A mapping between argument number corresponding to attribute access - mode (read_only, write_only, or read_write) and operands. */ -typedef hash_map 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 &access, appends the attribute pointer operand even when none was specified. */ size_t len = strlen (attrstr); - const char *atname + const char* const atname = (access.second.mode == attr_access::read_only ? "read_only" : (access.second.mode == attr_access::write_only - ? "write_only" : "read_write")); + ? "write_only" + : (access.second.mode == attr_access::read_write + ? "read_write" : "none"))); const char *sep = len ? ", " : ""; @@ -2131,11 +2069,13 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp) /* For read-only and read-write attributes also set the source size. */ srcsize = objsize; - if (access.second.mode == attr_access::read_only) + if (access.second.mode == attr_access::read_only + || access.second.mode == attr_access::none) { /* For a read-only attribute there is no destination so clear OBJSIZE. This emits "reading N bytes" kind of - diagnostics instead of the "writing N bytes" kind. */ + diagnostics instead of the "writing N bytes" kind, + unless MODE is none. */ objsize = NULL_TREE; } } @@ -2145,7 +2085,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp) diagnosed. */ TREE_NO_WARNING (exp) = false; check_access (exp, NULL_TREE, NULL_TREE, size, /*maxread=*/ NULL_TREE, - srcsize, objsize); + srcsize, objsize, access.second.mode != attr_access::none); if (TREE_NO_WARNING (exp)) /* If check_access issued a warning above, append the relevant @@ -2285,8 +2225,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, /* Array for up to the two attribute alloc_size arguments. */ tree alloc_args[] = { NULL_TREE, NULL_TREE }; - /* Map of attribute read_only, write_only, or read_write specifications - for function arguments. */ + /* Map of attribute accewss specifications for function arguments. */ rdwr_map rdwr_idx; init_attr_rdwr_indices (&rdwr_idx, fntype); @@ -2559,7 +2498,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, nul-terminated strings. */ maybe_warn_nonstring_arg (fndecl, exp); - /* Check read_only, write_only, and read_write arguments. */ + /* Check attribute access arguments. */ maybe_warn_rdwr_sizes (&rdwr_idx, exp); } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index cced19d2018..e656e66a80c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2497,8 +2497,8 @@ may be diagnosed by warnings such as @option{-Wstringop-overflow}, The @code{access} attribute specifies that a function to whose by-reference arguments the attribute applies accesses the referenced object according to @var{access-mode}. The @var{access-mode} argument is required and must be -one of three names: @code{read_only}, @code{read_write}, or @code{write_only}. -The remaining two are positional arguments. +one of four names: @code{read_only}, @code{read_write}, @code{write_only}, +or @code{none}. The remaining two are positional arguments. The required @var{ref-index} positional argument denotes a function argument of pointer (or in C++, reference) type that is subject to @@ -2555,6 +2555,14 @@ __attribute__ ((access (write_only, 1), access (read_only, 2))) char* strcpy (ch __attribute__ ((access (write_only, 1, 2), access (read_write, 3))) int fgets (char*, int, FILE*); @end smallexample +The access mode @code{none} specifies that the pointer to which it applies +is not used to access the referenced object at all. Unless the pointer is +null the pointed-to object must exist and have at least the size as denoted +by the @var{size-index} argument. The object need not be initialized. +The mode is intended to be used as a means to help validate the expected +object size, for example in functions that call @code{__builtin_object_size}. +@xref{Object Size Checking}. + @item alias ("@var{target}") @cindex @code{alias} function attribute The @code{alias} attribute causes the declaration to be emitted as an alias diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c index 4281e3b5a8e..c4127b805ab 100644 --- a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c +++ b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c @@ -161,3 +161,5 @@ f4 (char x[64], char *y, __builtin_va_list ap) snprintf (p, sizeof (buf), "%s", y); vsnprintf (p, sizeof (buf), "%s", ap); } + +/* { dg-prune-output "-Wuninitialized" } */ diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c index 9f11196bdbe..827dac71519 100644 --- a/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c +++ b/gcc/testsuite/c-c++-common/goacc/uninit-dim-clause.c @@ -4,13 +4,13 @@ void acc_parallel() { int i, j, k; - #pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized" } */ ; } @@ -18,12 +18,12 @@ void acc_kernels() { int i, j, k; - #pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized" } */ ; } diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c index 2584033a8c5..334567d3337 100644 --- a/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c +++ b/gcc/testsuite/c-c++-common/goacc/uninit-firstprivate-clause.c @@ -18,7 +18,7 @@ foo2 (void) { int i; -#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized in this function" } */ +#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized" } */ { i = 1; } diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c index 55caa4c2c7f..7f78d729681 100644 --- a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c +++ b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c @@ -11,28 +11,28 @@ main (void) bool b, b2, b3, b4; int i, i2; - #pragma acc parallel if(l) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc parallel if(b) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */ + #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ ; - #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */ + #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ ; - #pragma acc data if(l3) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc data if(b3) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */ + #pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ ; - #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized in this function" } */ + #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */ + #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ ; } diff --git a/gcc/testsuite/c-c++-common/gomp/pr70550-1.c b/gcc/testsuite/c-c++-common/gomp/pr70550-1.c index 493d4175993..d0d2fa53e03 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr70550-1.c +++ b/gcc/testsuite/c-c++-common/gomp/pr70550-1.c @@ -16,7 +16,7 @@ foo (void) { { int i; - #pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized" } */ { i = 26; bar (i); @@ -24,7 +24,7 @@ foo (void) } { T j; - #pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized" } */ { j = 37; bar (j); @@ -32,7 +32,7 @@ foo (void) } { int i; - #pragma omp target /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target /* { dg-bogus "is used uninitialized" } */ { i = 26; bar (i); @@ -40,7 +40,7 @@ foo (void) } { T j; - #pragma omp target /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target /* { dg-bogus "is used uninitialized" } */ { j = 37; bar (j); @@ -48,7 +48,7 @@ foo (void) } { int i; - #pragma omp target firstprivate (i) /* { dg-warning "is used uninitialized in this function" } */ + #pragma omp target firstprivate (i) /* { dg-warning "is used uninitialized" } */ { i = 26; bar (i); @@ -56,7 +56,7 @@ foo (void) } { T j; - #pragma omp target firstprivate (j) /* { dg-warning "is used uninitialized in this function" } */ + #pragma omp target firstprivate (j) /* { dg-warning "is used uninitialized" } */ { j = 37; bar (j); @@ -64,7 +64,7 @@ foo (void) } { int i; - #pragma omp target private (i) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target private (i) /* { dg-bogus "is used uninitialized" } */ { i = 26; bar (i); @@ -72,7 +72,7 @@ foo (void) } { T j; - #pragma omp target private (j) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp target private (j) /* { dg-bogus "is used uninitialized" } */ { j = 37; bar (j); diff --git a/gcc/testsuite/c-c++-common/gomp/pr70550-2.c b/gcc/testsuite/c-c++-common/gomp/pr70550-2.c index 31c34da4711..936d907deb8 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr70550-2.c +++ b/gcc/testsuite/c-c++-common/gomp/pr70550-2.c @@ -8,45 +8,45 @@ void foo (void) { int i, j, k, l, m, n, o, p, q; - #pragma omp task /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp task /* { dg-bogus "is used uninitialized" } */ { i = 2; bar (i); } - #pragma omp taskloop /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp taskloop /* { dg-bogus "is used uninitialized" } */ for (j = 0; j < 10; j++) { k = 7; bar (k); } - #pragma omp task firstprivate (l) /* { dg-warning "is used uninitialized in this function" } */ + #pragma omp task firstprivate (l) /* { dg-warning "is used uninitialized" } */ { l = 2; bar (l); } - #pragma omp taskloop firstprivate (m) /* { dg-warning "is used uninitialized in this function" } */ + #pragma omp taskloop firstprivate (m) /* { dg-warning "is used uninitialized" } */ for (j = 0; j < 10; j++) { m = 7; bar (m); } - #pragma omp task shared (n) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp task shared (n) /* { dg-bogus "is used uninitialized" } */ { n = 2; bar (n); } - #pragma omp taskloop shared (o) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp taskloop shared (o) /* { dg-bogus "is used uninitialized" } */ for (j = 0; j < 10; j++) { o = 7; bar (o); } - #pragma omp task private (p) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp task private (p) /* { dg-bogus "is used uninitialized" } */ { p = 2; bar (p); } - #pragma omp taskloop shared (q) /* { dg-bogus "is used uninitialized in this function" } */ + #pragma omp taskloop shared (q) /* { dg-bogus "is used uninitialized" } */ for (j = 0; j < 10; j++) { q = 7; diff --git a/gcc/testsuite/c-c++-common/uninit-pr51010.c b/gcc/testsuite/c-c++-common/uninit-pr51010.c index f28da46562c..9fd1ea3a262 100644 --- a/gcc/testsuite/c-c++-common/uninit-pr51010.c +++ b/gcc/testsuite/c-c++-common/uninit-pr51010.c @@ -4,10 +4,10 @@ int f (int j) { int a [10]; - return a [j]; /* { dg-warning "a\\\[j\\\]. is used uninitialized" } */ + return a [j]; /* { dg-warning "a|a\\\[j\\\]. is used uninitialized" } */ } int g (int j) { int a [10]; - return a [j+1]; /* { dg-warning "a\\\[\\\]. is used uninitialized" } */ + return a [j+1]; /* { dg-warning "a|a\\\[\\\]. is used uninitialized" } */ } diff --git a/gcc/testsuite/g++.dg/20090107-1.C b/gcc/testsuite/g++.dg/20090107-1.C index ff586e81767..80b88f02dcc 100644 --- a/gcc/testsuite/g++.dg/20090107-1.C +++ b/gcc/testsuite/g++.dg/20090107-1.C @@ -6,7 +6,7 @@ template struct Q1 { typedef int x; }; template struct Q2 { typename Q1::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().f(); } diff --git a/gcc/testsuite/g++.dg/20090121-1.C b/gcc/testsuite/g++.dg/20090121-1.C index ddfa3ad057f..9d70fb3601b 100644 --- a/gcc/testsuite/g++.dg/20090121-1.C +++ b/gcc/testsuite/g++.dg/20090121-1.C @@ -7,7 +7,7 @@ private: int y; public: - A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized in this function" } */ + A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized" } */ int get_y () { return y; } }; diff --git a/gcc/testsuite/g++.dg/ext/attr-access.C b/gcc/testsuite/g++.dg/ext/attr-access.C index fcb54cd8861..3b9c1a36e30 100644 --- a/gcc/testsuite/g++.dg/ext/attr-access.C +++ b/gcc/testsuite/g++.dg/ext/attr-access.C @@ -39,7 +39,7 @@ void call_rop1_ror2_O0 (void) void call_rdwrp1_rdwrr2_O0 (void) { - int32_t x[1]; + int32_t x[1] = { }; rdwrp1_rdwrr2 (x, x[0]); rdwrp1_rdwrr2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" } @@ -78,7 +78,7 @@ void call_rop1_ror2_O1 (void) void call_rdwrp1_rdwrr2_O1 (void) { - int32_t x[1]; + int32_t x[1] = { }; int32_t *p0 = x, &r0 = x[0]; int32_t *p1 = (int32_t*)((char*)p0 + 1); int32_t &r2 = *(int32_t*)((char*)p1 + 1); diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-52.c b/gcc/testsuite/gcc.dg/Warray-bounds-52.c index 1a7d76fcc2a..729ad45d6ac 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-52.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-52.c @@ -95,3 +95,6 @@ void ptr_idx_range (void) i = SR (3, 4); T (i, (int[]){ 2, 3, 4 }); // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" } } + +/* Some of the invalid accesses above also trigger -Wuninitialized. + { dg-prune-output "\\\[-Wuninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-53.c b/gcc/testsuite/gcc.dg/Warray-bounds-53.c index 0f062225b29..80db314b393 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-53.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-53.c @@ -95,3 +95,6 @@ void ptr_idx_range (void) i = SR (3, 4); T (i, (int[]){ 2, 3, 4 }); // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" } } + +/* Some of the invalid accesses above also trigger -Wuninitialized. + { dg-prune-output "\\\[-Wuninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-54.c b/gcc/testsuite/gcc.dg/Warray-bounds-54.c index 644fcd02cb6..5df5710c1d9 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-54.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-54.c @@ -10,9 +10,9 @@ int f0 (void) return p[2]; // { dg-warning "-Warray-bounds" } } -int f1 (void) +int f1 (int j) { - int i; + int i = j; int *p = &i; return p[2]; // { dg-warning "-Warray-bounds" } } @@ -22,3 +22,5 @@ int f2 (int i) int *p = &i; return p[2]; // { dg-warning "-Warray-bounds" } } + +/* { dg-prune-output "-Wuninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c new file mode 100644 index 00000000000..cb8aeb9b5d9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-33.c @@ -0,0 +1,40 @@ +/* PR middle-end/82456 - missing -Wstringop-overflow on strcpy reading past + the end of an array + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +void fcst (char *d) +{ + char a[2] = "0"; + + __builtin_strcpy (d, a + 3); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" } +} + +void frng (char *d, int i) +{ + char a[2] = "0"; + + if (i < 3) + i = 3; + + __builtin_strcpy (d, a + i); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" } +} + +void gcst (char *d) +{ + char a[2] = "0"; + + __builtin_strcpy (d, a + 2); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" } +} + +void grng (char *d, int i) +{ + char a[2] = "0"; + + if (i < 2) + i = 2; + + __builtin_strcpy (d, a + i); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" } +} + +/* { dg-prune-output "-Wuninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/attr-access-none.c b/gcc/testsuite/gcc.dg/attr-access-none.c new file mode 100644 index 00000000000..d983f2fac06 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-access-none.c @@ -0,0 +1,38 @@ +/* Test to verify the handling of attribute access (none). + { dg-do compile } + { dg-options "-O -Wall -ftrack-macro-expansion=0" } */ + +int __attribute__ ((access (none, 1))) +fnone_pv1 (void*); + +void nowarn_fnone_pv1 (void) +{ + int x; + fnone_pv1 (&x); +} + + +int __attribute__ ((access (none, 1))) +fnone_pcv1 (const void*); + +void nowarn_fnone_pcv1 (void) +{ + char a[2]; + fnone_pcv1 (a); +} + + +int __attribute__ ((access (none, 1, 2))) +fnone_pcv1_2 (const void*, int); // { dg-message "in a call to function 'fnone_pcv1_2' declared with attribute 'none \\\(1, 2\\\)'" } + +void nowarn_fnone_pcv1_2 (void) +{ + char a[2]; + fnone_pcv1_2 (a, 2); +} + +void warn_fnone_pcv1_2 (void) +{ + char a[3]; + fnone_pcv1_2 (a, 4); // { dg-warning "expecting 4 bytes in a region of size 3" } +} diff --git a/gcc/testsuite/gcc.dg/attr-access-read-only.c b/gcc/testsuite/gcc.dg/attr-access-read-only.c index 9acd769621e..71175d05ca5 100644 --- a/gcc/testsuite/gcc.dg/attr-access-read-only.c +++ b/gcc/testsuite/gcc.dg/attr-access-read-only.c @@ -11,7 +11,7 @@ int __attribute__ ((access ())) access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" } int __attribute__ ((access (rdonly))) -rdonly_spelling (void); // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', or 'write_only'" } +rdonly_spelling (void); // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } int __attribute__ ((access (read_only))) rdonly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" } diff --git a/gcc/testsuite/gcc.dg/attr-access-read-write.c b/gcc/testsuite/gcc.dg/attr-access-read-write.c index c97e54bbd60..849d9f1cf67 100644 --- a/gcc/testsuite/gcc.dg/attr-access-read-write.c +++ b/gcc/testsuite/gcc.dg/attr-access-read-write.c @@ -10,7 +10,7 @@ int __attribute__ ((access ())) access___v (void); /* { dg-error "wrong number of arguments specified for 'access' attribute" } */ int __attribute__ ((access (rdwr))) -rdwr_spelling (void); /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', or 'write_only'" } */ +rdwr_spelling (void); /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } */ int __attribute__ ((access (read_write))) rdwr_v_all (void); /* { dg-error "attribute .access\\(read_write\\). missing an argument" } */ diff --git a/gcc/testsuite/gcc.dg/attr-access-write-only.c b/gcc/testsuite/gcc.dg/attr-access-write-only.c index 008f5a36ff4..2718b0db456 100644 --- a/gcc/testsuite/gcc.dg/attr-access-write-only.c +++ b/gcc/testsuite/gcc.dg/attr-access-write-only.c @@ -11,7 +11,7 @@ int __attribute__ ((access ())) access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" } int __attribute__ ((access (wronly))) -wronly_spelling (void); // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', or 'write_only'" } +wronly_spelling (void); // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } int __attribute__ ((access (read_only))) wronly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" } diff --git a/gcc/testsuite/gcc.dg/pr71581.c b/gcc/testsuite/gcc.dg/pr71581.c index d82eb1ed5c9..dd71dde9eac 100644 --- a/gcc/testsuite/gcc.dg/pr71581.c +++ b/gcc/testsuite/gcc.dg/pr71581.c @@ -6,19 +6,19 @@ _Complex float f1 (void) { float x; - return x; /* { dg-warning "is used uninitialized in this function" } */ + return x; /* { dg-warning "is used uninitialized" } */ } _Complex double f2 (void) { double x; - return x; /* { dg-warning "is used uninitialized in this function" } */ + return x; /* { dg-warning "is used uninitialized" } */ } _Complex int f3 (void) { int x; - return x; /* { dg-warning "is used uninitialized in this function" } */ + return x; /* { dg-warning "is used uninitialized" } */ } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c index 3f502430333..24b1767975b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-6.c @@ -25,3 +25,6 @@ void f(void) value-numbering, removing the load altogether. ??? We now do this after CPP re-writes a into SSA form. */ /* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "ccp1" } } */ + +/* The invalid access above may also trigger -Wuninitialized. + { dg-prune-output "-Wuninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/uninit-15.c b/gcc/testsuite/gcc.dg/uninit-15.c index 67aac41d49e..8ee10c27aba 100644 --- a/gcc/testsuite/gcc.dg/uninit-15.c +++ b/gcc/testsuite/gcc.dg/uninit-15.c @@ -10,7 +10,7 @@ inline int foo (int i) { - if (i) /* { dg-warning "used uninitialized in this function" "" } */ + if (i) /* { dg-warning "used uninitialized" } */ return 1; return 0; } diff --git a/gcc/testsuite/gcc.dg/uninit-32.c b/gcc/testsuite/gcc.dg/uninit-32.c new file mode 100644 index 00000000000..cdc05128dfd --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-32.c @@ -0,0 +1,312 @@ +/* PR middle-end/10138 - warn for uninitialized arrays passed as const* + arguments + { dg-do compile } + { dg-options "-O -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +void* alloca (size_t); +void* malloc (size_t); +void* realloc (void*, size_t); + +void fpi (int*); +void fpci (const int*); +void fpcv (const void*); + + +void nowarn_scalar_fpi (void) +{ + int x; + fpi (&x); +} + +void nowarn_scalar_plus_cst_fpi (void) +{ + int x; + // This deserves a warning other than -Wuninitialized. + fpi (&x + 1); +} + +void nowarn_scalar_plus_var_fpi (int i) +{ + int x; + // Same as above, this deserves a warning other than -Wuninitialized. + fpi (&x + i); +} + +void nowarn_array_assign_fpci (void) +{ + int a[2]; + a[0] = 0; + fpci (a); +} + +void nowarn_array_assign_plus_cst_fpci (void) +{ + int a[4]; + a[1] = 0; + a[2] = 1; + fpci (a + 1); +} + +void nowarn_array_init_fpci (void) +{ + int a[4] = { 0 }; + fpci (a); +} + +void nowarn_array_compound_fpi (void) +{ + fpi ((int[2]){ 1 }); +} + +void nowarn_array_compound_fpci (void) +{ + fpci ((int[3]){ 1 }); +} + +void warn_array_fpci (void) +{ + int a[4]; // { dg-message "declared here" }" + fpci (a); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_array_plus_cst_fpci (void) +{ + int a[4]; + fpci (a + 1); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_array_plus_var_fpci (int i) +{ + int a[4]; + fpci (a + i); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void nowarn_array_end_fpci (void) +{ + int a[4]; + /* This should be diagnosed by a warning other than -Wuninitialized + because the just-past-the-end pointer cannot be dereferenced and + the function doesn't take any other pointer to tell where the start + of the array is. -Wuninitialized isn't appropriate because there + is nothing to initialize at that offset. */ + fpci (a + 4); +} + +void warn_matrix_fpcv (void) +{ + int a[2][2]; + fpci (a[1]); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_scalar_fpcv (void) +{ + int i; + fpci (&i); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_scalar_plus_cst_fpcv (void) +{ + int x; + /* Same as above, this deserves a warning other than -Wuninitialized + for passing the function a past-the-end pointer with no other + argument. */ + fpci (&x + 1); +} + +void warn_scalar_plus_var_fpcv (int i) +{ + int x; + fpci (&x + i); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void nowarn_struct_assign_fpci (void) +{ + struct { int a, b; } s; + s.a = 0; + fpci (&s.a); +} + +void warn_struct_assign_fpci (void) +{ + struct { int a, b; } s; + s.a = 0; + fpci (&s.b); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void nowarn_struct_init_fpci (void) +{ + struct { int a, b; } s = { 0 }; + fpci (&s.a); + fpci (&s.b); +} + +void nowarn_struct_compound_fpci (void) +{ + struct S { int a, b; }; + fpci (&(struct S){ }.a); + fpci (&(struct S){ }.b); +} + +/* Verify that passing a just-past-the-end pointer to a const pointer + argument to a function that takes another argument is not diagnosed + since the two arguments together could outline a range. */ +void nowarn_fp_p (void) +{ + extern void fpi_pci (int*, const int*); + + { + int i; + fpi_pci (&i, &i + 1); + } + { + int j; + fpi_pci (&j + 1, &j + 1); + } + + extern void fpc_pcc (char*, const char*); + + { + char a[2]; + fpc_pcc (a, a + 2); + } + { + char a[3]; + fpc_pcc (a, a + 3); + } + + extern void fpcc_pcc (const char*, const char*); + + { + char a[4]; + fpcc_pcc (a + 4, a + 4); + } +} + + +/* Verify passing addresses of empty uninitialized objects doesn't + trigger a warning. */ +void nowarn_fpcEmpty (void) +{ + struct Empty { }; + extern void fpcEmpty (const struct Empty*); + + /* Since Empty has no members warning for it isn't really necessary. + See also PR 38908. */ + struct Empty s; + fpcEmpty (&s); +} + + +/* Verify passing addresses of uninitialized objects to functions + declared without a proptotype doesn't trigger a warning. */ +void nowarn_noproto (void) +{ + extern void fnoproto (); + int i, a[2]; + + fnoproto (&i, a, a + 2); +} + + +/* Verify passing addresses of uninitialized objects to variadic + functions doesn't trigger a warning. */ +void nowarn_vararg (void) +{ + extern void fvararg (int, ...); + + int i, a[2]; + + fvararg (0, &i, a, a + 2); +} + + +void nowarn_alloca_assign_fpci (unsigned n) +{ + int *p = (int*)alloca (n); + p[0] = 0; + fpci (p); +} + +void nowarn_alloca_assign_plus_cst_fpci (unsigned n) +{ + int *p = (int*)alloca (n); + p[1] = 0; + p[2] = 1; + fpci (p + 1); +} + +void warn_alloca_fpci (unsigned n) +{ + int *p = (int*)alloca (n); + fpci (p); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_alloca_assign_plus_cst_fpci (unsigned n) +{ + int *p = (int*)alloca (n); + p[1] = 0; + p[2] = 1; + fpci (p + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + + +void nowarn_vla_assign_fpci (unsigned n) +{ + int a[n]; + a[0] = 0; + fpci (a); +} + +void nowarn_vla_assign_plus_cst_fpci (unsigned n) +{ + int vla[n]; + vla[1] = 0; + vla[2] = 1; + fpci (vla + 1); +} + +void warn_vla_fpci (unsigned n) +{ + int vla[n]; // { dg-message "declared here" "pr?????" { xfail *-*-* } }" + fpci (vla); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_vla_assign_plus_cst_fpci (unsigned n) +{ + int vla[n]; // { dg-message "declared here" "pr?????" { xfail *-*-* } }" + vla[1] = 0; + vla[2] = 1; + fpci (vla + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + + +void nowarn_malloc_assign_fpci (unsigned n) +{ + int *p = (int*)malloc (n); + p[0] = 0; + fpci (p); +} + +void nowarn_malloc_assign_plus_cst_fpci (unsigned n) +{ + int *p = (int*)malloc (n); + p[1] = 0; + p[2] = 1; + fpci (p + 1); +} + +void warn_malloc_fpci (unsigned n) +{ + int *p = (int*)malloc (n); + fpci (p); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} + +void warn_malloc_assign_plus_cst_fpci (unsigned n) +{ + int *p = (int*)malloc (n); // { dg-message "allocated here" "pr?????" { xfail *-*-* } }" + p[1] = 0; + p[2] = 1; + fpci (p + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" } +} diff --git a/gcc/testsuite/gcc.dg/uninit-33.c b/gcc/testsuite/gcc.dg/uninit-33.c new file mode 100644 index 00000000000..a45f18dd6ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-33.c @@ -0,0 +1,145 @@ +/* PR middle-end/10138 - warn for uninitialized arrays passed as const* + arguments + Verify that passing pointers to uninitialized objects to arguments + to functions declared with attribute access is diagnosed where expected. + { dg-do compile } + { dg-options "-O -Wall" } */ + +#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__))) +#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__))) +#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__))) + +RO (1) void fpri (int*); // { dg-message "in a call to 'fpri' declared with attribute 'access \\\(read_only, 1\\\)' here" } + +RO (1) void fpcri (const int*); + +RO (1, 2) void fpcri1_2 (const int*, int); + + +void warn_scalar_fpri (void) +{ + int i; // { dg-message "declared here" } + fpri (&i); // { dg-warning "'i' is used uninitialized" } +} + +void nowarn_scalar_plus_fpri (void) +{ + int i; + /* This gets a -Wstringop-overflow for reading past the end but not + -Wuninitialized because there's nothing to initialize there. */ + fpri (&i + 1); // { dg-warning "\\\[-Wstringop-overflow" } +} + +void nowarn_array_assign_fpcri (void) +{ + int a[2]; + a[0] = 0; + fpcri (a); +} + +void nowarn_array_init_fpcri (void) +{ + int a[4] = { 0 }; + fpcri (a); +} + +void nowarn_array_compound_fpri (void) +{ + fpri ((int[2]){ 0 }); +} + +void nowarn_array_compound_fpcri (void) +{ + fpcri ((int[3]){ 1 }); +} + +void warn_scalar_fpcri (void) +{ + int i; + fpcri (&i); // { dg-warning "\\\[-Wuninitialized" } +} + +void warn_array_fpcri (void) +{ + int a[4]; + fpcri (a); // { dg-warning "\\\[-Wuninitialized" } +} + +void warn_array_plus_cst_fpcri (void) +{ + int a[4]; + fpcri (a + 1); // { dg-warning "\\\[-Wuninitialized" } +} + +void warn_array_plus_var_fpcri (int i) +{ + int a[4]; + fpcri (a + i); // { dg-warning "\\\[-Wuninitialized" } +} + +void nowarn_struct_assign_fpcri (void) +{ + struct { int a, b; } s; + s.a = 0; + fpcri (&s.a); +} + +void warn_struct_assign_fpcri (void) +{ + struct { int a, b; } s; + s.a = 0; + fpcri (&s.b); // { dg-warning "\\\[-Wuninitialized" } +} + +void nowarn_struct_init_fpcri (void) +{ + struct { int a, b; } s = { 0 }; + fpcri (&s.a); + fpcri (&s.b); +} + +void nowarn_struct_compound_fpcri (void) +{ + struct S { int a, b; }; + fpcri (&(struct S){ }.a); + fpcri (&(struct S){ }.b); +} + + +void nowarn_scalar_fpcri1_2 (void) +{ + int i; + fpcri1_2 (&i, 0); +} + +void nowarn_array_assign_fpcri1_2 (void) +{ + int a[2]; + a[0] = 0; + fpcri1_2 (a, 1); +} + +void nowarn_array_assign_fpcri1_2_plus_cst (void) +{ + int a[3]; + a[1] = 0; + fpcri1_2 (a + 1, 1); +} + +void nowarn_array_init_fpcri1_2 (void) +{ + int a[4] = { 0 }; + fpcri1_2 (a, 2); +} + +void warn_array_fpcri1_2_rd1 (void) +{ + int a[4]; + fpcri1_2 (a, 1); // { dg-warning "\\\[-Wuninitialized" } +} + +void warn_array_fpcri1_2_rd2 (void) +{ + int a[4]; + fpcri1_2 (a, 2); // { dg-warning "\\\[-Wuninitialized" } +} diff --git a/gcc/testsuite/gcc.dg/uninit-34.c b/gcc/testsuite/gcc.dg/uninit-34.c new file mode 100644 index 00000000000..9de618347eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-34.c @@ -0,0 +1,58 @@ +/* PR middle-end/10138 - warn for uninitialized arrays passed as const* + arguments + Verify that passing pointers to uninitialized objects to arguments + to functions declared with attribute access is diagnosed where expected. + { dg-do compile } + { dg-options "-O -Wall" } */ + +#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__))) + +RW (1) RW (3) void +f4pi (int*, int*, int*, int*); // { dg-message "in a call to 'f4pi' declared with attribute 'access \\\(read_write, \[13\]\\\)'" } + + +void nowarn_scalar (void) +{ + int i1 = 0, i2, i3 = 1, i4; + f4pi (&i1, &i2, &i3, &i4); +} + +void warn_scalar_1 (void) +{ + int i1; // { dg-message "declared here" } + int i2, i3 = 1, i4; + + f4pi (&i1, &i2, &i3, &i4); // { dg-warning "'i1' may be used uninitialized" } +} + +void warn_scalar_2 (void) +{ + int j1 = 0, j2, j4; + int j3; + + f4pi (&j1, &j2, &j3, &j4); // { dg-warning "'j3' may be used uninitialized" } +} + + +void nowarn_array_init (void) +{ + int a1[4] = { 0 }, a2[5], a3[6] = { 0 }, a4[7]; + + f4pi (a1, a2, a3, a4); +} + +void warn_array_1 (void) +{ + int a1[4]; // { dg-message "'a1' declared here" } + int a2[5], a3[6] = { 0 }, a4[7]; + + f4pi (a1, a2, a3, a4); // { dg-warning "'a1' may be used uninitialized" } +} + +void warn_array_2 (void) +{ + int a1[4] = { 0 }, a2[5], a4[7]; + int a3[6]; // { dg-message "'a3' declared here" } + + f4pi (a1, a2, a3, a4); // { dg-warning "'a3' may be used uninitialized" } +} diff --git a/gcc/testsuite/gcc.dg/uninit-36.c b/gcc/testsuite/gcc.dg/uninit-36.c new file mode 100644 index 00000000000..9524e7ad1b9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-36.c @@ -0,0 +1,237 @@ +/* PR middle-end/10138 - warn for uninitialized arrays passed as const* + arguments + Verify that passing pointers to uninitialized objects to const + arguments to built-ins is diagnosed where expected. + { dg-do compile } + { dg-options "-O -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +void* alloca (size_t); +void* malloc (size_t); +void* realloc (void*, size_t); + +void* memcpy (void*, const void*, size_t); +char* strcpy (char*, const char*); +size_t strlen (const char*); + +void sink (void*); + +void nowarn_array_memcpy (void *d, unsigned n) +{ + int a[2]; + /* Diagnose this? */ + memcpy (d, a, n /* Non-constant to avoid folding into MEM_REF. */); +} + +void nowarn_array_plus_cst_memcpy (void *d, unsigned n) +{ + int a[3]; + /* Diagnose this? */ + memcpy (d, a + 1, n); +} + +void nowarn_array_plus_var_memcpy (void *d, unsigned n, int i) +{ + int a[4]; + /* Diagnose this? */ + memcpy (d, a + i, n); +} + +void nowarn_array_assign_memcpy (char *d, unsigned n) +{ + int a[3]; + a[1] = 3; + memcpy (d, a, n); +} + +void nowarn_array_init_memcpy (char *d, unsigned n) +{ + int a[4] = { 0 }; + memcpy (d, a, n); +} + +void nowarn_array_compound_memcpy (void *d, unsigned n) +{ + memcpy (d, (int[2]){ 0 }, n); +} + +void nowarn_struct_assign_memcpy (void *d, unsigned n) +{ + struct S { int a, b, c, d; } s; + s.b = 1; + s.d = 2; + memcpy (d, &s, n); +} + + +void nowarn_array_init_strcpy (char *d[], unsigned n) +{ + char a[8] = "012"; + + strcpy (d[0], a); + strcpy (d[1], a + 1); + strcpy (d[1], a + 2); + strcpy (d[1], a + 3); + strcpy (d[1], a + 4); + strcpy (d[1], a + 5); + strcpy (d[1], a + 6); + strcpy (d[1], a + 7); +} + + +void nowarn_array_assign_strcpy (char *d[], unsigned n) +{ + char a[8]; + a[0] = '0'; + a[1] = '1'; + a[2] = '2'; + a[3] = '\0'; + + strcpy (d[0], a); + strcpy (d[1], a + 1); + strcpy (d[1], a + 2); + strcpy (d[1], a + 3); +} + +void warn_array_plus_cst_strcpy (char *d, unsigned n) +{ + char a[8]; + a[0] = '1'; + a[1] = '2'; + a[2] = '3'; + a[3] = '\0'; + + strcpy (d, a + 4); // { dg-warning "\\\[-Wuninitialized" } + strcpy (d, a + 5); // { dg-warning "\\\[-Wuninitialized" } + strcpy (d, a + 6); // { dg-warning "\\\[-Wuninitialized" } + strcpy (d, a + 7); // { dg-warning "\\\[-Wuninitialized" } +} + +void nowarn_array_plus_var_strcpy (char *d, int i) +{ + char a[8]; + a[0] = '1'; + a[1] = '2'; + a[2] = '3'; + a[3] = '\0'; + + strcpy (d, a + i); +} + + +size_t nowarn_array_assign_strlen (const char *s) +{ + char a[8]; + a[0] = s[0]; + a[1] = s[1]; + a[2] = s[2]; + a[3] = s[3]; + + size_t n = 0; + + n += strlen (a); + n += strlen (a + 1); + n += strlen (a + 2); + n += strlen (a + 3); + return n; +} + +size_t warn_array_plus_cst_strlen (const char *s) +{ + char a[8]; + a[0] = s[0]; + a[1] = s[1]; + a[2] = s[2]; + a[3] = s[3]; + + return strlen (a + 4); // { dg-warning "\\\[-Wuninitialized" } +} + +size_t nowarn_array_plus_var_strlen (const char *s, int i) +{ + char a[8]; + a[0] = s[0]; + a[1] = s[1]; + a[2] = s[2]; + a[3] = s[3]; + + return strlen (a + i); +} + + +size_t nowarn_alloca_assign_strlen (int i) +{ + char *p = (char*)alloca (8); + p[i] = '\0'; + return strlen (p); +} + +size_t nowarn_alloca_escape_strlen (int i) +{ + char *p = (char*)alloca (8); + sink (p); + return strlen (p); +} + +size_t warn_alloca_strlen (void) +{ + char *p = (char*)alloca (8); + return strlen (p); // { dg-warning "\\\[-Wuninitialized" } +} + + +size_t nowarn_malloc_assign_strlen (int i) +{ + char *p = (char*)malloc (8); + p[i] = '\0'; + return strlen (p); +} + +size_t nowarn_malloc_escape_strlen (int i) +{ + char *p = (char*)malloc (8); + sink (p); + return strlen (p); +} + +size_t warn_malloc_strlen (void) +{ + char *p = (char*)malloc (8); + return strlen (p); // { dg-warning "\\\[-Wuninitialized" } +} + + +size_t nowarn_realloc_strlen (void *p) +{ + char *q = (char*)realloc (p, 8); + return strlen (q); +} + + +size_t nowarn_vla_assign_strlen (int n, int i) +{ + char vla[n]; + vla[i] = '\0'; + return strlen (vla); +} + +size_t nowarn_vla_strcpy_strlen (int n, const char *s, int i) +{ + char vla[n]; + strcpy (vla, s); + return strlen (vla + i); +} + +size_t nowarn_vla_escape_strlen (int n, int i) +{ + char vla[n]; + sink (vla); + return strlen (vla); +} + +size_t warn_vla_strlen (unsigned n) +{ + char vla[n]; + return strlen (vla); // { dg-warning "\\\[-Wuninitialized" } +} diff --git a/gcc/testsuite/gcc.dg/uninit-B-O0.c b/gcc/testsuite/gcc.dg/uninit-B-O0.c index 5557ace6f8d..b01e4fa945a 100644 --- a/gcc/testsuite/gcc.dg/uninit-B-O0.c +++ b/gcc/testsuite/gcc.dg/uninit-B-O0.c @@ -9,7 +9,7 @@ void baz (void) { int i; - if (i) /* { dg-warning "'i' is used uninitialized in this function" } */ + if (i) /* { dg-warning "'i' is used uninitialized" } */ bar (i); foo (&i); } diff --git a/gcc/testsuite/gcc.dg/uninit-I-O0.c b/gcc/testsuite/gcc.dg/uninit-I-O0.c index 761f65b485b..e4b68ba47b1 100644 --- a/gcc/testsuite/gcc.dg/uninit-I-O0.c +++ b/gcc/testsuite/gcc.dg/uninit-I-O0.c @@ -4,5 +4,5 @@ int sys_msgctl (void) { struct { int mode; } setbuf; - return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized in this function" } */ + return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized" } */ } diff --git a/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c b/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c index 832aeb30bec..e9e264deb5a 100644 --- a/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c +++ b/gcc/testsuite/gcc.dg/uninit-pr19430-O0.c @@ -6,7 +6,7 @@ extern void baz (int *); int foo (int i) { - int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */ + int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */ if (bar (i)) { baz (&j); @@ -18,7 +18,7 @@ foo (int i) int foo2( void ) { int rc; - return rc; /* { dg-warning "'rc' is used uninitialized in this function" } */ + return rc; /* { dg-warning "'rc' is used uninitialized" } */ *&rc = 0; } @@ -27,16 +27,16 @@ void frob(int *pi); int main(void) { - int i; - printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */ + int i; + printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */ frob(&i); return 0; } void foo3(int*); -void bar3(void) { - int x; - if(x) /* { dg-warning "'x' is used uninitialized in this function" } */ - foo3(&x); +void bar3(void) { + int x; + if(x) /* { dg-warning "'x' is used uninitialized" } */ + foo3(&x); } diff --git a/gcc/testsuite/gcc.dg/uninit-pr19430.c b/gcc/testsuite/gcc.dg/uninit-pr19430.c index e00f3138045..417cdc63314 100644 --- a/gcc/testsuite/gcc.dg/uninit-pr19430.c +++ b/gcc/testsuite/gcc.dg/uninit-pr19430.c @@ -5,9 +5,9 @@ extern void baz (int *); int foo (int i) { - int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */ + int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */ - if (bar (i)) { + if (bar (i)) { baz (&j); } else { } @@ -19,7 +19,7 @@ foo (int i) int foo2( void ) { int rc; - return rc; /* { dg-warning "'rc' is used uninitialized in this function" } */ + return rc; /* { dg-warning "'rc' is used uninitialized" } */ *&rc = 0; } @@ -28,16 +28,16 @@ void frob(int *pi); int main(void) { - int i; - printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */ + int i; + printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */ frob(&i); return 0; } void foo3(int*); -void bar3(void) { - int x; - if(x) /* { dg-warning "'x' is used uninitialized in this function" "uninitialized" } */ - foo3(&x); +void bar3(void) { + int x; + if(x) /* { dg-warning "'x' is used uninitialized" "uninitialized" } */ + foo3(&x); } diff --git a/gcc/testsuite/gcc.dg/uninit-pr95136.c b/gcc/testsuite/gcc.dg/uninit-pr95136.c new file mode 100644 index 00000000000..47d16c5bbba --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-pr95136.c @@ -0,0 +1,63 @@ +/* PR middle-end/95136 - missing -Wuninitialized on an array access with + a variable offset + { dg-do compile } + { dg-options "-O -Wall" } */ + +#define NOIPA __attribute__ ((noipa)) + +NOIPA int a1_addr_varidx_plus_cst (int i) +{ + int a[4]; // { dg-message "'a' declared here" } + int *p = &a[i + 1]; + return *p; // { dg-warning "'a|a\\\[]' 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\\\[]\\\[]' is used uninitialized" } +} + +NOIPA int a2_plus_addr_varidx_cst (int i, int j) +{ + int a[4][4]; // { dg-message "'a' declared here" } + int *p = &a[i][j] + 1; + return *p; // { dg-warning "'a' is used uninitialized" } +} + +NOIPA int a2_plus_addr_cstidx_var (int i) +{ + int a[4][4]; // { dg-message "'a' declared here" } + int *p = &a[1][1] + i; + return *p; // { dg-warning "'a' is used uninitialized" } +} + +NOIPA int a2_plus_addr_varidx_var (int i, int j, int k) +{ + int a[4][4]; // { dg-message "'a' declared here" } + int *p = &a[i][j] + k; + return *p; // { dg-warning "'a' is used uninitialized" } +} diff --git a/gcc/testsuite/gfortran.dg/assignment_4.f90 b/gcc/testsuite/gfortran.dg/assignment_4.f90 index 77181a2054e..37fdbca9178 100644 --- a/gcc/testsuite/gfortran.dg/assignment_4.f90 +++ b/gcc/testsuite/gfortran.dg/assignment_4.f90 @@ -12,5 +12,5 @@ logical :: r type(event), pointer :: myEvent allocate(myEvent) - r=myEvent%task() + r=myEvent%task() ! { dg-warning "uninitialized" } end diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95 index 5dea42b2e7e..c77d47a3900 100644 --- a/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/uninit-dim-clause.f95 @@ -4,13 +4,13 @@ subroutine acc_parallel implicit none integer :: i, j, k - !$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized in this function" } + !$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized" } !$acc end parallel - !$acc parallel num_workers(j) ! { dg-warning "is used uninitialized in this function" } + !$acc parallel num_workers(j) ! { dg-warning "is used uninitialized" } !$acc end parallel - !$acc parallel vector_length(k) ! { dg-warning "is used uninitialized in this function" } + !$acc parallel vector_length(k) ! { dg-warning "is used uninitialized" } !$acc end parallel end subroutine acc_parallel @@ -18,12 +18,12 @@ subroutine acc_kernels implicit none integer :: i, j, k - !$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized in this function" } + !$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized" } !$acc end kernels - !$acc kernels num_workers(j) ! { dg-warning "is used uninitialized in this function" } + !$acc kernels num_workers(j) ! { dg-warning "is used uninitialized" } !$acc end kernels - !$acc kernels vector_length(k) ! { dg-warning "is used uninitialized in this function" } + !$acc kernels vector_length(k) ! { dg-warning "is used uninitialized" } !$acc end kernels end subroutine acc_kernels diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95 index 14d960a1f38..cd5d189a1aa 100644 --- a/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/uninit-firstprivate-clause.f95 @@ -12,7 +12,7 @@ end subroutine test subroutine test2 INTEGER :: i - !$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized in this function" } + !$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized" } i = 1 !$acc end parallel end subroutine test2 diff --git a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 b/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 index 60dc53e7850..73eb4ee1de1 100644 --- a/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/uninit-if-clause.f95 @@ -6,15 +6,15 @@ program test logical :: b, b2, b3, b4 integer :: data, data2 - !$acc parallel if(b) ! { dg-warning "is used uninitialized in this function" } + !$acc parallel if(b) ! { dg-warning "is used uninitialized" } !$acc end parallel - !$acc kernels if(b2) ! { dg-warning "is used uninitialized in this function" } + !$acc kernels if(b2) ! { dg-warning "is used uninitialized" } !$acc end kernels - !$acc data if(b3) ! { dg-warning "is used uninitialized in this function" } + !$acc data if(b3) ! { dg-warning "is used uninitialized" } !$acc end data - !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized in this function" } + !$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized" } end program test diff --git a/gcc/testsuite/gfortran.dg/pr66545_2.f90 b/gcc/testsuite/gfortran.dg/pr66545_2.f90 index e15d8ba792c..c15a2b36511 100644 --- a/gcc/testsuite/gfortran.dg/pr66545_2.f90 +++ b/gcc/testsuite/gfortran.dg/pr66545_2.f90 @@ -11,13 +11,13 @@ end program foo subroutine p1 complex :: c5 complex :: c6 - c5 = (c5) ! { dg-warning "used uninitialized in this" } - c6 = c6 ! { dg-warning "used uninitialized in this" } + c5 = (c5) ! { dg-warning "used uninitialized" } + c6 = c6 ! { dg-warning "used uninitialized" } end subroutine p1 subroutine q1 real :: r5 real :: r6 - r5 = (r5) ! { dg-warning "used uninitialized in this" } - r6 = r6 ! { dg-warning "used uninitialized in this" } + r5 = (r5) ! { dg-warning "used uninitialized" } + r6 = r6 ! { dg-warning "used uninitialized" } end subroutine q1 diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index cc785bd9d8c..2f0ff724cde 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa.h" #include "tree-cfg.h" #include "cfghooks.h" +#include "attribs.h" +#include "builtins.h" +#include "calls.h" /* This implements the pass that does predicate aware warning on uses of possibly uninitialized variables. The pass first collects the set of @@ -217,19 +220,373 @@ check_defs (ao_ref *ref, tree vdef, void *data_) return true; } +/* Counters and limits controlling the the depth of analysis and + strictness of the warning. */ +struct wlimits +{ + /* Number of VDEFs encountered. */ + unsigned int vdef_cnt; + /* Number of statements examined by walk_aliased_vdefs. */ + unsigned int oracle_cnt; + /* Limit on the number of statements visited by walk_aliased_vdefs. */ + unsigned limit; + /* Set when basic block with statement is executed unconditionally. */ + bool always_executed; + /* Set to issue -Wmaybe-uninitialized. */ + bool wmaybe_uninit; +}; + +/* Determine if REF references an uninitialized operand and diagnose + it if so. */ + +static tree +maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs, + wlimits &wlims) +{ + bool has_bit_insert = false; + use_operand_p luse_p; + imm_use_iterator liter; + + if (TREE_NO_WARNING (rhs)) + return NULL_TREE; + + /* Do not warn if the base was marked so or this is a + hard register var. */ + tree base = ao_ref_base (&ref); + if ((VAR_P (base) + && DECL_HARD_REGISTER (base)) + || TREE_NO_WARNING (base)) + return NULL_TREE; + + /* Do not warn if the access is fully outside of the variable. */ + poly_int64 decl_size; + if (DECL_P (base) + && ((known_size_p (ref.size) + && known_eq (ref.max_size, ref.size) + && known_le (ref.offset + ref.size, 0)) + || (known_ge (ref.offset, 0) + && DECL_SIZE (base) + && poly_int_tree_p (DECL_SIZE (base), &decl_size) + && known_le (decl_size, ref.offset)))) + return NULL_TREE; + + /* Do not warn if the result of the access is then used for + a BIT_INSERT_EXPR. */ + if (lhs && TREE_CODE (lhs) == SSA_NAME) + FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs) + { + gimple *use_stmt = USE_STMT (luse_p); + /* BIT_INSERT_EXPR first operand should not be considered + a use for the purpose of uninit warnings. */ + if (gassign *ass = dyn_cast (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 + ''). */ + 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 % 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 %", + fntype, mode, argno); + } + } + else if (fndecl) + { + location_t loc = DECL_SOURCE_LOCATION (fndecl); + inform (loc, "by argument %u of type %qT to %qD declared here", + argno, argtype, fndecl); + } + else + { + /* Handle calls through function pointers. */ + location_t loc = gimple_location (stmt); + inform (loc, "by argument %u of type %qT to %qT", + argno, argtype, fntype); + } + + if (DECL_P (argbase)) + { + location_t loc = DECL_SOURCE_LOCATION (argbase); + inform (loc, "%qD declared here", argbase); + } + } + + wlims.always_executed = save_always_executed; +} + + static unsigned int -warn_uninitialized_vars (bool warn_possibly_uninitialized) +warn_uninitialized_vars (bool wmaybe_uninit) { + /* Counters and limits controlling the the depth of the warning. */ + wlimits wlims = { }; + wlims.wmaybe_uninit = wmaybe_uninit; + gimple_stmt_iterator gsi; basic_block bb; - unsigned int vdef_cnt = 0; - unsigned int oracle_cnt = 0; - unsigned limit = 0; - FOR_EACH_BB_FN (bb, cfun) { basic_block succ = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); - bool always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb); + wlims.always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb); for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); @@ -253,131 +610,42 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized) continue; } use = USE_FROM_PTR (use_p); - if (always_executed) + if (wlims.always_executed) warn_uninit (OPT_Wuninitialized, use, SSA_NAME_VAR (use), SSA_NAME_VAR (use), - "%qD is used uninitialized in this function", stmt, + "%qD is used uninitialized", stmt, UNKNOWN_LOCATION); - else if (warn_possibly_uninitialized) + else if (wmaybe_uninit) warn_uninit (OPT_Wmaybe_uninitialized, use, SSA_NAME_VAR (use), SSA_NAME_VAR (use), - "%qD may be used uninitialized in this function", + "%qD may be used uninitialized", stmt, UNKNOWN_LOCATION); } /* For limiting the alias walk below we count all vdefs in the function. */ if (gimple_vdef (stmt)) - vdef_cnt++; + wlims.vdef_cnt++; - if (gimple_assign_load_p (stmt) - && gimple_has_location (stmt)) + if (is_gimple_call (stmt)) + maybe_warn_pass_by_reference (stmt, wlims); + else if (gimple_assign_load_p (stmt) + && gimple_has_location (stmt)) { tree rhs = gimple_assign_rhs1 (stmt); tree lhs = gimple_assign_lhs (stmt); - bool has_bit_insert = false; - use_operand_p luse_p; - imm_use_iterator liter; - - if (TREE_NO_WARNING (rhs)) - continue; ao_ref ref; ao_ref_init (&ref, rhs); - - /* Do not warn if the base was marked so or this is a - hard register var. */ - tree base = ao_ref_base (&ref); - if ((VAR_P (base) - && DECL_HARD_REGISTER (base)) - || TREE_NO_WARNING (base)) - continue; - - /* Do not warn if the access is fully outside of the - variable. */ - poly_int64 decl_size; - if (DECL_P (base) - && known_size_p (ref.size) - && ((known_eq (ref.max_size, ref.size) - && known_le (ref.offset + ref.size, 0)) - || (known_ge (ref.offset, 0) - && DECL_SIZE (base) - && poly_int_tree_p (DECL_SIZE (base), &decl_size) - && known_le (decl_size, ref.offset)))) - continue; - - /* Do not warn if the access is then used for a BIT_INSERT_EXPR. */ - if (TREE_CODE (lhs) == SSA_NAME) - FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs) - { - gimple *use_stmt = USE_STMT (luse_p); - /* BIT_INSERT_EXPR first operand should not be considered - a use for the purpose of uninit warnings. */ - if (gassign *ass = dyn_cast (use_stmt)) - { - if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR - && luse_p->use == gimple_assign_rhs1_ptr (ass)) - { - has_bit_insert = true; - break; - } - } - } - if (has_bit_insert) - continue; - - /* Limit the walking to a constant number of stmts after - we overcommit quadratic behavior for small functions - and O(n) behavior. */ - if (oracle_cnt > 128 * 128 - && oracle_cnt > vdef_cnt * 2) - limit = 32; - check_defs_data data; - bool fentry_reached = false; - data.found_may_defs = false; - use = gimple_vuse (stmt); - int res = walk_aliased_vdefs (&ref, use, - check_defs, &data, NULL, - &fentry_reached, limit); - if (res == -1) - { - oracle_cnt += limit; - continue; - } - oracle_cnt += res; - if (data.found_may_defs) - continue; - /* Do not warn if it can be initialized outside this function. - If we did not reach function entry then we found killing - clobbers on all paths to entry. */ - if (fentry_reached - /* ??? We'd like to use ref_may_alias_global_p but that - excludes global readonly memory and thus we get bougs - warnings from p = cond ? "a" : "b" for example. */ - && (!VAR_P (base) - || is_global_var (base))) + tree var = maybe_warn_operand (ref, stmt, lhs, rhs, wlims); + if (!var) continue; - /* We didn't find any may-defs so on all paths either - reached function entry or a killing clobber. */ - location_t location - = linemap_resolve_location (line_table, gimple_location (stmt), - LRK_SPELLING_LOCATION, NULL); - if (always_executed) + if (DECL_P (var)) { - if (warning_at (location, OPT_Wuninitialized, - "%qE is used uninitialized in this function", - rhs)) - /* ??? This is only effective for decls as in - gcc.dg/uninit-B-O0.c. Avoid doing this for - maybe-uninit uses as it may hide important - locations. */ - TREE_NO_WARNING (rhs) = 1; + location_t loc = DECL_SOURCE_LOCATION (var); + inform (loc, "%qD declared here", var); } - else if (warn_possibly_uninitialized) - warning_at (location, OPT_Wmaybe_uninitialized, - "%qE may be used uninitialized in this function", - rhs); } } } @@ -2665,7 +2933,7 @@ pass_late_warn_uninitialized::execute (function *fun) /* Re-do the plain uninitialized variable check, as optimization may have straightened control flow. Do this first so that we don't accidentally get a "may be" warning when we'd have seen an "is" warning later. */ - warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1); + warn_uninitialized_vars (/*warn_maybe_uninitialized=*/1); timevar_push (TV_TREE_UNINIT); @@ -2735,7 +3003,7 @@ execute_early_warn_uninitialized (void) optimization we need to warn here about "may be uninitialized". */ calculate_dominance_info (CDI_POST_DOMINATORS); - warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize); + warn_uninitialized_vars (/*warn_maybe_uninitialized=*/!optimize); /* Post-dominator information cannot be reliably updated. Free it after the use. */