From 6cb61e50ade62f1e7c8653b8d6fc6a632fd3977f Mon Sep 17 00:00:00 2001 From: Qing Zhao Date: Mon, 17 Jan 2022 17:41:07 +0000 Subject: [PATCH] Enable -Wuninitialized + -ftrivial-auto-var-init for address taken variables. With -ftrivial-auto-var-init, the address taken auto variable is replaced with a temporary variable during gimplification, and the original auto variable might be eliminated by compiler optimization completely. As a result, the current uninitialized warning analysis cannot get enough information from the IR, therefore the uninitialized warnings for address taken variable cannot be issued based on the current implemenation of -ftrival-auto-var-init. For more info please refer to: https://gcc.gnu.org/pipermail/gcc-patches/2021-August/577431.html In order to improve this situation, we can improve uninitialized analysis for address taken auto variables with -ftrivial-auto-var-init as following: for the following stmt: _1 = .DEFERRED_INIT (4, 2, &"alt_reloc"[0]); if (_1 != 0) The original variable DECL has been eliminated from the IR, all the necessary information that is needed for reporting the warnings for DECL can be acquired from the call to .DEFERRED_INIT. A. the name string of DECL from the 3rd parameter of the call; B. the location of the DECL from the location of the call; C. the call can also be used to hold the information on whether the warning has been issued or not to suppress warning messages when needed; The current testing cases for uninitialized warnings + -ftrivial-auto-var-init are adjusted to reflect the fact that we can issue warnings for address taken variables. gcc/ChangeLog: 2022-01-17 qing zhao * tree-ssa-uninit.c (warn_uninit): Delete the 4th parameter. Handle .DEFERRED_INIT call with an anonymous SSA_NAME specially. (check_defs): Handle .DEFERRED_INIT call with an anonymous SSA_NAME specially. (warn_uninit_phi_uses): Delete the 4th actual when call warn_uninit. (warn_uninitialized_vars): Likewise. (warn_uninitialized_phi): Likewise. gcc/testsuite/ChangeLog: 2022-01-17 qing zhao * gcc.dg/auto-init-uninit-16.c (testfunc): Delete xfail to reflect the fact that address taken variable can be warned. * gcc.dg/auto-init-uninit-34.c (warn_scalar_1): Likewise. (warn_scalar_2): Likewise. * gcc.dg/auto-init-uninit-37.c (T1): Likewise. (T2): Likewise. * gcc.dg/auto-init-uninit-B.c (baz): Likewise. --- gcc/testsuite/gcc.dg/auto-init-uninit-16.c | 4 +- gcc/testsuite/gcc.dg/auto-init-uninit-34.c | 8 +- gcc/testsuite/gcc.dg/auto-init-uninit-37.c | 44 +++++---- gcc/testsuite/gcc.dg/auto-init-uninit-B.c | 4 +- gcc/tree-ssa-uninit.c | 141 +++++++++++++++++++++++------ 5 files changed, 141 insertions(+), 60 deletions(-) diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-16.c b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c index 38e1950..f14864b 100644 --- a/gcc/testsuite/gcc.dg/auto-init-uninit-16.c +++ b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c @@ -1,7 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */ -/* -ftrivial-auto-var-init will make the uninitialized warning for address - taken auto var going away, FIXME later. */ int foo, bar; @@ -20,6 +18,6 @@ void testfunc() decode_reloc(foo, &alt_reloc); - if (alt_reloc) /* { dg-warning "may be used uninitialized" "" { xfail *-*-* } } */ + if (alt_reloc) /* { dg-warning "may be used uninitialized" "" } */ bar = 42; } diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-34.c b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c index 1a68765..d6e7ed3 100644 --- a/gcc/testsuite/gcc.dg/auto-init-uninit-34.c +++ b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c @@ -4,8 +4,6 @@ to functions declared with attribute access is diagnosed where expected. { dg-do compile } { dg-options "-O -Wall -ftrivial-auto-var-init=zero" } */ -/* -ftrivial-auto-var-init will make the uninitialized warning for address - taken auto var going away, FIXME later. */ #define RW(...) __attribute__ ((access (read_write, __VA_ARGS__))) @@ -21,10 +19,10 @@ void nowarn_scalar (void) void warn_scalar_1 (void) { - int i1; // { dg-message "declared here" "" { xfail *-*-* } } + int i1; // { dg-message "declared here" "" } int i2, i3 = 1, i4; - f4pi (&i1, &i2, &i3, &i4); // { dg-warning "'i1' may be used uninitialized" "" { xfail *-*-* } } + f4pi (&i1, &i2, &i3, &i4); // { dg-warning "'i1' may be used uninitialized" "" } } void warn_scalar_2 (void) @@ -32,7 +30,7 @@ void warn_scalar_2 (void) int j1 = 0, j2, j4; int j3; - f4pi (&j1, &j2, &j3, &j4); // { dg-warning "'j3' may be used uninitialized" "" { xfail *-*-* } } + f4pi (&j1, &j2, &j3, &j4); // { dg-warning "'j3' may be used uninitialized" "" } } diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-37.c b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c index 2791b37..aea5542 100644 --- a/gcc/testsuite/gcc.dg/auto-init-uninit-37.c +++ b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c @@ -5,8 +5,6 @@ arguments of array, VLA, or pointer types. { dg-do compile } { dg-options "-O2 -Wall -ftrack-macro-expansion=0 -ftrivial-auto-var-init=zero" } */ -/* -ftrivial-auto-var-init will make the uninitialized warning for address - taken auto var going away, FIXME later. */ #define NONE /* none */ #define RO(...) __attribute__ ((access (read_only, __VA_ARGS__))) @@ -42,9 +40,9 @@ typedef int IA_[]; typedef const int CIA_[]; T1 (NONE, fia_, IA_); -T1 (NONE, fcia_, CIA_); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froia_, IA_); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwia_, IA_); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fcia_, CIA_); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froia_, IA_); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwia_, IA_); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoia_, IA_); T1 (X (1), fxia_, IA_); @@ -53,9 +51,9 @@ typedef int IA1[1]; typedef const int CIA1[1]; T1 (NONE, fia1, IA1); -T1 (NONE, fcia1, CIA1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froia1, IA1); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwia1, IA1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fcia1, CIA1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froia1, IA1); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwia1, IA1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoia1, IA1); T1 (X (1), fxia1, IA1); @@ -64,9 +62,9 @@ T1 (X (1), fxia1, IA1); #define CIARS1 const int[restrict static 1] T1 (NONE, fiars1, IARS1); -T1 (NONE, fciars1, CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fciars1, CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoiars1, IARS1); T1 (X (1), fxiars1, IARS1); @@ -75,9 +73,9 @@ T1 (X (1), fxiars1, IARS1); #define CIAS1 const int[static 1] T1 (NONE, fias1, IAS1); -T1 (NONE, fcias1, CIAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froias1, IAS1); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwias1, IAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fcias1, CIAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froias1, IAS1); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwias1, IAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoias1, IAS1); T1 (X (1), fxias1, IAS1); @@ -86,9 +84,9 @@ T1 (X (1), fxias1, IAS1); #define CIAX const int[*] T1 (NONE, fiax, IAX); -T1 (NONE, fciax, CIAX); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froiax, IAX); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwiax, IAX); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fciax, CIAX); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froiax, IAX); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwiax, IAX); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoiax, IAX); T1 (X (1), fxiax, IAX); @@ -97,9 +95,9 @@ T1 (X (1), fxiax, IAX); #define CIAN int n, const int[n] T2 (NONE, fian, IAN); -T2 (NONE, fcian, CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T2 (RO (2, 1), froian, IAN); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T2 (RW (2, 1), frwian, IAN); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T2 (NONE, fcian, CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T2 (RO (2, 1), froian, IAN); // { dg-warning "\\\[-Wuninitialized" "" } +T2 (RW (2, 1), frwian, IAN); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T2 (WO (2, 1), fwoian, IAN); T2 (X (2, 1), fxian, IAN); @@ -108,9 +106,9 @@ typedef int* IP; typedef const int* CIP; T1 (NONE, fip, IP); -T1 (NONE, fcip, CIP); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } -T1 (RO (1), froip, IP); // { dg-warning "\\\[-Wuninitialized" "" { xfail *-*-* } } -T1 (RW (1), frwip, IP); // { dg-warning "\\\[-Wmaybe-uninitialized" "" { xfail *-*-* } } +T1 (NONE, fcip, CIP); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } +T1 (RO (1), froip, IP); // { dg-warning "\\\[-Wuninitialized" "" } +T1 (RW (1), frwip, IP); // { dg-warning "\\\[-Wmaybe-uninitialized" "" } T1 (WO (1), fwoip, IP); T1 (X (1), fxip, IP); diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-B.c b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c index b6d3efd..40d3196 100644 --- a/gcc/testsuite/gcc.dg/auto-init-uninit-B.c +++ b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c @@ -1,7 +1,5 @@ /* Origin: PR c/179 from Gray Watson , adapted as a testcase by Joseph Myers . */ -/* -ftrivial-auto-var-init will make the uninitialized warning for address - taken auto var going away, FIXME later. */ /* { dg-do compile } */ /* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */ extern void foo (int *); @@ -11,7 +9,7 @@ void baz (void) { int i; - if (i) /* { dg-warning "is used uninitialized" "uninit i warning" { xfail *-*-* } } */ + if (i) /* { dg-warning "is used uninitialized" "uninit i warning" } */ bar (i); foo (&i); } diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 7a6df30..02e88d5 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -132,8 +132,8 @@ uninit_undefined_value_p (tree t) or UNKNOWN_LOCATION otherwise. */ static void -warn_uninit (opt_code opt, tree t, tree var, const char *gmsgid, - gimple *context, location_t phi_arg_loc = UNKNOWN_LOCATION) +warn_uninit (opt_code opt, tree t, tree var, gimple *context, + location_t phi_arg_loc = UNKNOWN_LOCATION) { /* Bail if the value isn't provably uninitialized. */ if (!has_undefined_value_p (t)) @@ -182,24 +182,70 @@ warn_uninit (opt_code opt, tree t, tree var, const char *gmsgid, } /* Anonymous SSA_NAMEs shouldn't be uninitialized, but ssa_undefined_value_p - can return true if the def stmt of an anonymous SSA_NAME is COMPLEX_EXPR - created for conversion from scalar to complex. Use the underlying var of - the COMPLEX_EXPRs real part in that case. See PR71581. */ + can return true if the def stmt of an anonymous SSA_NAME is + 1. A COMPLEX_EXPR created for conversion from scalar to complex. Use the + underlying var of the COMPLEX_EXPRs real part in that case. See PR71581. + + Or + + 2. A call to .DEFERRED_INIT internal function. Since the original variable + has been eliminated by optimziation, we need to get the variable name, + and variable declaration location from this call. We recorded variable + name into VAR_NAME_STR, and will get location info and record warning + suppressed info to VAR_DEF_STMT, which is the .DEFERRED_INIT call. */ + + const char *var_name_str = NULL; + gimple *var_def_stmt = NULL; + if (!var && !SSA_NAME_VAR (t)) { - gimple *def_stmt = SSA_NAME_DEF_STMT (t); - if (is_gimple_assign (def_stmt) - && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR) + var_def_stmt = SSA_NAME_DEF_STMT (t); + + if (is_gimple_assign (var_def_stmt) + && gimple_assign_rhs_code (var_def_stmt) == COMPLEX_EXPR) { - tree v = gimple_assign_rhs1 (def_stmt); + tree v = gimple_assign_rhs1 (var_def_stmt); if (TREE_CODE (v) == SSA_NAME && has_undefined_value_p (v) - && zerop (gimple_assign_rhs2 (def_stmt))) + && zerop (gimple_assign_rhs2 (var_def_stmt))) var = SSA_NAME_VAR (v); } + + if (gimple_call_internal_p (var_def_stmt, IFN_DEFERRED_INIT)) + { + /* Ignore the call to .DEFERRED_INIT that define the original + var itself as the following case: + temp = .DEFERRED_INIT (4, 2, “alt_reloc"); + alt_reloc = temp; + In order to avoid generating warning for the fake usage + at alt_reloc = temp. + */ + tree lhs_var = NULL_TREE; + tree lhs_var_name = NULL_TREE; + const char *lhs_var_name_str = NULL; + + /* Get the variable name from the 3rd argument of call. */ + tree var_name = gimple_call_arg (var_def_stmt, 2); + var_name = TREE_OPERAND (TREE_OPERAND (var_name, 0), 0); + var_name_str = TREE_STRING_POINTER (var_name); + + if (is_gimple_assign (context)) + { + if (TREE_CODE (gimple_assign_lhs (context)) == VAR_DECL) + lhs_var = gimple_assign_lhs (context); + else if (TREE_CODE (gimple_assign_lhs (context)) == SSA_NAME) + lhs_var = SSA_NAME_VAR (gimple_assign_lhs (context)); + } + if (lhs_var + && (lhs_var_name = DECL_NAME (lhs_var)) + && (lhs_var_name_str = IDENTIFIER_POINTER (lhs_var_name)) + && (strcmp (lhs_var_name_str, var_name_str) == 0)) + return; + gcc_assert (var_name_str && var_def_stmt); + } } - if (var == NULL_TREE) + if (var == NULL_TREE && var_name_str == NULL) return; /* Avoid warning if we've already done so or if the warning has been @@ -207,36 +253,66 @@ warn_uninit (opt_code opt, tree t, tree var, const char *gmsgid, if (((warning_suppressed_p (context, OPT_Wuninitialized) || (gimple_assign_single_p (context) && get_no_uninit_warning (gimple_assign_rhs1 (context))))) - || get_no_uninit_warning (var)) + || (var && get_no_uninit_warning (var)) + || (var_name_str + && warning_suppressed_p (var_def_stmt, OPT_Wuninitialized))) return; /* Use either the location of the read statement or that of the PHI argument, or that of the uninitialized variable, in that order, whichever is valid. */ - location_t location; + location_t location = UNKNOWN_LOCATION; if (gimple_has_location (context)) location = gimple_location (context); else if (phi_arg_loc != UNKNOWN_LOCATION) location = phi_arg_loc; - else + else if (var) location = DECL_SOURCE_LOCATION (var); + else if (var_name_str) + location = gimple_location (var_def_stmt); + location = linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, NULL); auto_diagnostic_group d; - if (!warning_at (location, opt, gmsgid, var)) - return; + gcc_assert (opt == OPT_Wuninitialized || opt == OPT_Wmaybe_uninitialized); + if (var) + { + if ((opt == OPT_Wuninitialized + && !warning_at (location, opt, "%qD is used uninitialized", var)) + || (opt == OPT_Wmaybe_uninitialized + && !warning_at (location, opt, "%qD may be used uninitialized", + var))) + return; + } + else if (var_name_str) + { + if ((opt == OPT_Wuninitialized + && !warning_at (location, opt, "%qs is used uninitialized", + var_name_str)) + || (opt == OPT_Wmaybe_uninitialized + && !warning_at (location, opt, "%qs may be used uninitialized", + var_name_str))) + return; + } /* Avoid subsequent warnings for reads of the same variable again. */ - suppress_warning (var, opt); + if (var) + suppress_warning (var, opt); + else if (var_name_str) + suppress_warning (var_def_stmt, opt); /* Issue a note pointing to the read variable unless the warning is at the same location. */ - location_t var_loc = DECL_SOURCE_LOCATION (var); + location_t var_loc = var ? DECL_SOURCE_LOCATION (var) + : gimple_location (var_def_stmt); if (location == var_loc) return; - inform (var_loc, "%qD was declared here", var); + if (var) + inform (var_loc, "%qD was declared here", var); + else if (var_name_str) + inform (var_loc, "%qs was declared here", var_name_str); } struct check_defs_data @@ -380,6 +456,20 @@ check_defs (ao_ref *ref, tree vdef, void *data_) if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT)) return false; + /* For address taken variable, a temporary variable is added between + the variable and the call to .DEFERRED_INIT function as: + _1 = .DEFERRED_INIT (4, 2, &"i1"[0]); + i1 = _1; + Ignore this vdef as well. */ + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == SSA_NAME) + { + tree tmp_var = gimple_assign_rhs1 (def_stmt); + if (gimple_call_internal_p (SSA_NAME_DEF_STMT (tmp_var), + IFN_DEFERRED_INIT)) + return false; + } + /* The ASAN_MARK intrinsic doesn't modify the variable. */ if (is_gimple_call (def_stmt)) { @@ -877,8 +967,8 @@ warn_uninit_phi_uses (basic_block bb) use_stmt = NULL; } if (use_stmt) - warn_uninit (OPT_Wuninitialized, def, SSA_NAME_VAR (def), - "%qD is used uninitialized", use_stmt); + warn_uninit (OPT_Wuninitialized, def, + SSA_NAME_VAR (def), use_stmt); } } @@ -931,11 +1021,11 @@ warn_uninitialized_vars (bool wmaybe_uninit) } tree use = USE_FROM_PTR (use_p); if (wlims.always_executed) - warn_uninit (OPT_Wuninitialized, use, SSA_NAME_VAR (use), - "%qD is used uninitialized", stmt); + warn_uninit (OPT_Wuninitialized, use, + SSA_NAME_VAR (use), stmt); else if (wmaybe_uninit) - warn_uninit (OPT_Wmaybe_uninitialized, use, SSA_NAME_VAR (use), - "%qD may be used uninitialized", stmt); + warn_uninit (OPT_Wmaybe_uninitialized, use, + SSA_NAME_VAR (use), stmt); } /* For limiting the alias walk below we count all @@ -1182,7 +1272,6 @@ warn_uninitialized_phi (gphi *phi, vec *worklist, warn_uninit (OPT_Wmaybe_uninitialized, uninit_op, SSA_NAME_VAR (uninit_op), - "%qD may be used uninitialized in this function", uninit_use_stmt, loc); } -- 2.7.4