re PR middle-end/50040 (missed warning: ‘x.y’ is used uninitialized in this function)
2011-08-11 Richard Guenther <rguenther@suse.de> PR middle-end/50040 * gimplify.c (gimplify_modify_expr_complex_part): Mark the load of the other piece with TREE_NO_WARNING. * tree-flow.h (warn_uninit): Adjust prototype. * tree-ssa.c (warn_uninit): Take uninitialized SSA name, the base variable and the expression that is used separately. Properly query all TREE_NO_WARNING flags. (struct walk_data): Remove. (warn_uninitialized_var): Likewise. (warn_uninitialized_vars): Do not walk gimple pieces but simply look at all SSA uses of the statement. Handle unused memory separately. * tree-ssa-uninit.c (warn_uninitialized_phi): Adjust. * g++.dg/warn/unit-1.C: Un-XFAIL. * gcc.dg/uninit-I.c: Likewise. From-SVN: r177667
This commit is contained in:
parent
0f8de04340
commit
8d2b04104d
7 changed files with 96 additions and 124 deletions
|
@ -1,3 +1,19 @@
|
|||
2011-08-11 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/50040
|
||||
* gimplify.c (gimplify_modify_expr_complex_part): Mark the
|
||||
load of the other piece with TREE_NO_WARNING.
|
||||
* tree-flow.h (warn_uninit): Adjust prototype.
|
||||
* tree-ssa.c (warn_uninit): Take uninitialized SSA name,
|
||||
the base variable and the expression that is used separately.
|
||||
Properly query all TREE_NO_WARNING flags.
|
||||
(struct walk_data): Remove.
|
||||
(warn_uninitialized_var): Likewise.
|
||||
(warn_uninitialized_vars): Do not walk gimple pieces but simply
|
||||
look at all SSA uses of the statement. Handle unused memory
|
||||
separately.
|
||||
* tree-ssa-uninit.c (warn_uninitialized_phi): Adjust.
|
||||
|
||||
2011-08-11 Kazuhiro Inaoka <kazuhiro.inaoka.ud@renesas.com>
|
||||
|
||||
* config/rx/rx.md (movsicc): Allow register to register
|
||||
|
|
|
@ -4483,6 +4483,7 @@ gimplify_modify_expr_complex_part (tree *expr_p, gimple_seq *pre_p,
|
|||
|
||||
ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR;
|
||||
other = build1 (ocode, TREE_TYPE (rhs), lhs);
|
||||
TREE_NO_WARNING (other) = 1;
|
||||
other = get_formal_tmp_var (other, pre_p);
|
||||
|
||||
realpart = code == REALPART_EXPR ? rhs : other;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
struct a { int mode; };
|
||||
int sys_msgctl (void)
|
||||
{
|
||||
struct a setbuf; /* { dg-warning "'setbuf.mode' is used" "" { xfail *-*-* } } */
|
||||
return setbuf.mode;
|
||||
struct a setbuf;
|
||||
return setbuf.mode; /* { dg-warning "'setbuf.a::mode' is used" "" } */
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
int sys_msgctl (void)
|
||||
{
|
||||
struct { int mode; } setbuf; /* { dg-warning "'setbuf\.mode' is used" "" { xfail *-*-* } } */
|
||||
return setbuf.mode;
|
||||
struct { int mode; } setbuf;
|
||||
return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used" "" } */
|
||||
}
|
||||
|
|
|
@ -542,7 +542,7 @@ extern void flush_pending_stmts (edge);
|
|||
extern void verify_ssa (bool);
|
||||
extern void delete_tree_ssa (void);
|
||||
extern bool ssa_undefined_value_p (tree);
|
||||
extern void warn_uninit (enum opt_code, tree, const char *, void *);
|
||||
extern void warn_uninit (enum opt_code, tree, tree, tree, const char *, void *);
|
||||
extern unsigned int warn_uninitialized_vars (bool);
|
||||
extern void execute_update_addresses_taken (void);
|
||||
|
||||
|
|
|
@ -1953,7 +1953,8 @@ warn_uninitialized_phi (gimple phi, VEC(gimple, heap) **worklist,
|
|||
return;
|
||||
|
||||
uninit_op = gimple_phi_arg_def (phi, MASK_FIRST_SET_BIT (uninit_opnds));
|
||||
warn_uninit (OPT_Wmaybe_uninitialized, uninit_op,
|
||||
warn_uninit (OPT_Wmaybe_uninitialized, uninit_op, SSA_NAME_VAR (uninit_op),
|
||||
SSA_NAME_VAR (uninit_op),
|
||||
"%qD may be used uninitialized in this function",
|
||||
uninit_use_stmt);
|
||||
|
||||
|
|
190
gcc/tree-ssa.c
190
gcc/tree-ssa.c
|
@ -1652,14 +1652,15 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
|
|||
again for plain uninitialized variables, since optimization may have
|
||||
changed conditionally uninitialized to unconditionally uninitialized. */
|
||||
|
||||
/* Emit a warning for T, an SSA_NAME, being uninitialized. The exact
|
||||
/* Emit a warning for EXPR based on variable VAR at the point in the
|
||||
program T, an SSA_NAME, is used being uninitialized. The exact
|
||||
warning text is in MSGID and LOCUS may contain a location or be null.
|
||||
WC is the warning code. */
|
||||
|
||||
void
|
||||
warn_uninit (enum opt_code wc, tree t, const char *gmsgid, void *data)
|
||||
warn_uninit (enum opt_code wc, tree t,
|
||||
tree expr, tree var, const char *gmsgid, void *data)
|
||||
{
|
||||
tree var = SSA_NAME_VAR (t);
|
||||
gimple context = (gimple) data;
|
||||
location_t location;
|
||||
expanded_location xloc, floc;
|
||||
|
@ -1669,11 +1670,11 @@ warn_uninit (enum opt_code wc, tree t, const char *gmsgid, void *data)
|
|||
|
||||
/* TREE_NO_WARNING either means we already warned, or the front end
|
||||
wishes to suppress the warning. */
|
||||
if (TREE_NO_WARNING (var))
|
||||
return;
|
||||
|
||||
/* Do not warn if it can be initialized outside this module. */
|
||||
if (is_global_var (var))
|
||||
if ((context
|
||||
&& (gimple_no_warning_p (context)
|
||||
|| (gimple_assign_single_p (context)
|
||||
&& TREE_NO_WARNING (gimple_assign_rhs1 (context)))))
|
||||
|| TREE_NO_WARNING (expr))
|
||||
return;
|
||||
|
||||
location = (context != NULL && gimple_has_location (context))
|
||||
|
@ -1681,9 +1682,9 @@ warn_uninit (enum opt_code wc, tree t, const char *gmsgid, void *data)
|
|||
: DECL_SOURCE_LOCATION (var);
|
||||
xloc = expand_location (location);
|
||||
floc = expand_location (DECL_SOURCE_LOCATION (cfun->decl));
|
||||
if (warning_at (location, wc, gmsgid, var))
|
||||
if (warning_at (location, wc, gmsgid, expr))
|
||||
{
|
||||
TREE_NO_WARNING (var) = 1;
|
||||
TREE_NO_WARNING (expr) = 1;
|
||||
|
||||
if (location == DECL_SOURCE_LOCATION (var))
|
||||
return;
|
||||
|
@ -1694,126 +1695,79 @@ warn_uninit (enum opt_code wc, tree t, const char *gmsgid, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
struct walk_data {
|
||||
gimple stmt;
|
||||
bool always_executed;
|
||||
bool warn_possibly_uninitialized;
|
||||
};
|
||||
|
||||
/* Called via walk_tree, look for SSA_NAMEs that have empty definitions
|
||||
and warn about them. */
|
||||
|
||||
static tree
|
||||
warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data_)
|
||||
{
|
||||
struct walk_stmt_info *wi = (struct walk_stmt_info *) data_;
|
||||
struct walk_data *data = (struct walk_data *) wi->info;
|
||||
tree t = *tp;
|
||||
|
||||
/* We do not care about LHS. */
|
||||
if (wi->is_lhs)
|
||||
{
|
||||
/* Except for operands of dereferences. */
|
||||
if (!INDIRECT_REF_P (t)
|
||||
&& TREE_CODE (t) != MEM_REF)
|
||||
return NULL_TREE;
|
||||
t = TREE_OPERAND (t, 0);
|
||||
}
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case ADDR_EXPR:
|
||||
/* Taking the address of an uninitialized variable does not
|
||||
count as using it. */
|
||||
*walk_subtrees = 0;
|
||||
break;
|
||||
|
||||
case VAR_DECL:
|
||||
{
|
||||
/* A VAR_DECL in the RHS of a gimple statement may mean that
|
||||
this variable is loaded from memory. */
|
||||
use_operand_p vuse;
|
||||
tree op;
|
||||
|
||||
/* If there is not gimple stmt,
|
||||
or alias information has not been computed,
|
||||
then we cannot check VUSE ops. */
|
||||
if (data->stmt == NULL)
|
||||
return NULL_TREE;
|
||||
|
||||
/* If the load happens as part of a call do not warn about it. */
|
||||
if (is_gimple_call (data->stmt))
|
||||
return NULL_TREE;
|
||||
|
||||
vuse = gimple_vuse_op (data->stmt);
|
||||
if (vuse == NULL_USE_OPERAND_P)
|
||||
return NULL_TREE;
|
||||
|
||||
op = USE_FROM_PTR (vuse);
|
||||
if (t != SSA_NAME_VAR (op)
|
||||
|| !SSA_NAME_IS_DEFAULT_DEF (op))
|
||||
return NULL_TREE;
|
||||
/* If this is a VUSE of t and it is the default definition,
|
||||
then warn about op. */
|
||||
t = op;
|
||||
/* Fall through into SSA_NAME. */
|
||||
}
|
||||
|
||||
case SSA_NAME:
|
||||
/* We only do data flow with SSA_NAMEs, so that's all we
|
||||
can warn about. */
|
||||
if (data->always_executed)
|
||||
warn_uninit (OPT_Wuninitialized,
|
||||
t, "%qD is used uninitialized in this function",
|
||||
data->stmt);
|
||||
else if (data->warn_possibly_uninitialized)
|
||||
warn_uninit (OPT_Wuninitialized,
|
||||
t, "%qD may be used uninitialized in this function",
|
||||
data->stmt);
|
||||
*walk_subtrees = 0;
|
||||
break;
|
||||
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
/* The total store transformation performed during gimplification
|
||||
creates uninitialized variable uses. If all is well, these will
|
||||
be optimized away, so don't warn now. */
|
||||
if (TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
|
||||
*walk_subtrees = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (IS_TYPE_OR_DECL_P (t))
|
||||
*walk_subtrees = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
warn_uninitialized_vars (bool warn_possibly_uninitialized)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
basic_block bb;
|
||||
struct walk_data data;
|
||||
|
||||
data.warn_possibly_uninitialized = warn_possibly_uninitialized;
|
||||
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
data.always_executed = dominated_by_p (CDI_POST_DOMINATORS,
|
||||
bool always_executed = dominated_by_p (CDI_POST_DOMINATORS,
|
||||
single_succ (ENTRY_BLOCK_PTR), bb);
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
struct walk_stmt_info wi;
|
||||
data.stmt = gsi_stmt (gsi);
|
||||
if (is_gimple_debug (data.stmt))
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
use_operand_p use_p;
|
||||
ssa_op_iter op_iter;
|
||||
tree use;
|
||||
|
||||
if (is_gimple_debug (stmt))
|
||||
continue;
|
||||
memset (&wi, 0, sizeof (wi));
|
||||
wi.info = &data;
|
||||
walk_gimple_op (gsi_stmt (gsi), warn_uninitialized_var, &wi);
|
||||
|
||||
/* We only do data flow with SSA_NAMEs, so that's all we
|
||||
can warn about. */
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, op_iter, SSA_OP_USE)
|
||||
{
|
||||
use = USE_FROM_PTR (use_p);
|
||||
if (always_executed)
|
||||
warn_uninit (OPT_Wuninitialized, use,
|
||||
SSA_NAME_VAR (use), SSA_NAME_VAR (use),
|
||||
"%qD is used uninitialized in this function",
|
||||
stmt);
|
||||
else if (warn_possibly_uninitialized)
|
||||
warn_uninit (OPT_Wuninitialized, use,
|
||||
SSA_NAME_VAR (use), SSA_NAME_VAR (use),
|
||||
"%qD may be used uninitialized in this function",
|
||||
stmt);
|
||||
}
|
||||
|
||||
/* For memory the only cheap thing we can do is see if we
|
||||
have a use of the default def of the virtual operand.
|
||||
??? Note that at -O0 we do not have virtual operands.
|
||||
??? Not so cheap would be to use the alias oracle via
|
||||
walk_aliased_vdefs, if we don't find any aliasing vdef
|
||||
warn as is-used-uninitialized, if we don't find an aliasing
|
||||
vdef that kills our use (stmt_kills_ref_p), warn as
|
||||
may-be-used-uninitialized. But this walk is quadratic and
|
||||
so must be limited which means we would miss warning
|
||||
opportunities. */
|
||||
use = gimple_vuse (stmt);
|
||||
if (use
|
||||
&& gimple_assign_single_p (stmt)
|
||||
&& !gimple_vdef (stmt)
|
||||
&& SSA_NAME_IS_DEFAULT_DEF (use))
|
||||
{
|
||||
tree rhs = gimple_assign_rhs1 (stmt);
|
||||
tree base = get_base_address (rhs);
|
||||
|
||||
/* Do not warn if it can be initialized outside this function. */
|
||||
if (TREE_CODE (base) != VAR_DECL
|
||||
|| DECL_HARD_REGISTER (base)
|
||||
|| is_global_var (base))
|
||||
continue;
|
||||
|
||||
if (always_executed)
|
||||
warn_uninit (OPT_Wuninitialized, use, gimple_assign_rhs1 (stmt),
|
||||
base,
|
||||
"%qE is used uninitialized in this function",
|
||||
stmt);
|
||||
else if (warn_possibly_uninitialized)
|
||||
warn_uninit (OPT_Wuninitialized, use, gimple_assign_rhs1 (stmt),
|
||||
base,
|
||||
"%qE may be used uninitialized in this function",
|
||||
stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue