* tree-flow.h (ssa_undefined_value_p): Remove prototype.
* tree-ssa.c (ssa_undefined_value_p): Move pass independent parts here.
(warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized,
make_pass_early_warn_uninitialized): Move to tree-ssa-uninit.c.
* tree-ssa-uninit.c (ssa_undefined_value_p): Move to tree-ssa.c
(has_undefined_value_p): New. Pass dependant parts of
ssa_undefined_value_p.
(uninit_undefined_value_p): Use has_undefined_value_p.
(warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized,
make_pass_early_warn_uninitialized): Move from tree-ssa.c
* tree-ssa.h: Adjust prototypes
===================================================================
*************** extern bool gimple_seq_may_fallthru (gim
extern bool gimple_stmt_may_fallthru (gimple);
extern bool gimple_check_call_matching_types (gimple, tree, bool);
- /* In tree-ssa-uninit.c */
- extern bool ssa_undefined_value_p (tree);
-
/* In tree-into-ssa.c */
void update_ssa (unsigned);
void delete_update_ssa (void);
===================================================================
*************** tree_ssa_strip_useless_type_conversions
}
+ /* Return true if T, an SSA_NAME, has an undefined value. */
+
+ bool
+ ssa_undefined_value_p (tree t)
+ {
+ tree var = SSA_NAME_VAR (t);
+
+ if (!var)
+ ;
+ /* Parameters get their initial value from the function entry. */
+ else if (TREE_CODE (var) == PARM_DECL)
+ return false;
+ /* When returning by reference the return address is actually a hidden
+ parameter. */
+ else if (TREE_CODE (var) == RESULT_DECL && DECL_BY_REFERENCE (var))
+ return false;
+ /* Hard register variables get their initial value from the ether. */
+ else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
+ return false;
+
+ /* The value is undefined iff its definition statement is empty. */
+ return gimple_nop_p (SSA_NAME_DEF_STMT (t));
+ }
+
+
/* Internal helper for walk_use_def_chains. VAR, FN and DATA are as
described in walk_use_def_chains.
*************** walk_use_def_chains (tree var, walk_use_
}
}
-
- /* Emit warnings for uninitialized variables. This is done in two passes.
-
- The first pass notices real uses of SSA names with undefined values.
- Such uses are unconditionally uninitialized, and we can be certain that
- such a use is a mistake. This pass is run before most optimizations,
- so that we catch as many as we can.
-
- The second pass follows PHI nodes to find uses that are potentially
- uninitialized. In this case we can't necessarily prove that the use
- is really uninitialized. This pass is run after most optimizations,
- so that we thread as many jumps and possible, and delete as much dead
- code as possible, in order to reduce false positives. We also look
- again for plain uninitialized variables, since optimization may have
- changed conditionally uninitialized to unconditionally uninitialized. */
-
- /* 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,
- tree expr, tree var, const char *gmsgid, void *data)
- {
- gimple context = (gimple) data;
- location_t location, cfun_loc;
- expanded_location xloc, floc;
-
- if (!ssa_undefined_value_p (t))
- return;
-
- /* TREE_NO_WARNING either means we already warned, or the front end
- wishes to suppress the warning. */
- 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))
- ? gimple_location (context)
- : DECL_SOURCE_LOCATION (var);
- location = linemap_resolve_location (line_table, location,
- LRK_SPELLING_LOCATION,
- NULL);
- cfun_loc = DECL_SOURCE_LOCATION (cfun->decl);
- xloc = expand_location (location);
- floc = expand_location (cfun_loc);
- if (warning_at (location, wc, gmsgid, expr))
- {
- TREE_NO_WARNING (expr) = 1;
-
- if (location == DECL_SOURCE_LOCATION (var))
- return;
- if (xloc.file != floc.file
- || linemap_location_before_p (line_table,
- location, cfun_loc)
- || linemap_location_before_p (line_table,
- cfun->function_end_locus,
- location))
- inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var);
- }
- }
-
- unsigned int
- warn_uninitialized_vars (bool warn_possibly_uninitialized)
- {
- gimple_stmt_iterator gsi;
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- 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))
- {
- gimple stmt = gsi_stmt (gsi);
- use_operand_p use_p;
- ssa_op_iter op_iter;
- tree use;
-
- if (is_gimple_debug (stmt))
- continue;
-
- /* 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_Wmaybe_uninitialized, 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_Wmaybe_uninitialized, use,
- gimple_assign_rhs1 (stmt), base,
- "%qE may be used uninitialized in this function",
- stmt);
- }
- }
- }
-
- return 0;
- }
-
- static unsigned int
- execute_early_warn_uninitialized (void)
- {
- /* Currently, this pass runs always but
- execute_late_warn_uninitialized only runs with optimization. With
- optimization we want to warn about possible uninitialized as late
- as possible, thus don't do it here. However, without
- optimization we need to warn here about "may be uninitialized".
- */
- calculate_dominance_info (CDI_POST_DOMINATORS);
-
- warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
-
- /* Post-dominator information can not be reliably updated. Free it
- after the use. */
-
- free_dominance_info (CDI_POST_DOMINATORS);
- return 0;
- }
-
- static bool
- gate_warn_uninitialized (void)
- {
- return warn_uninitialized != 0;
- }
-
- namespace {
-
- const pass_data pass_data_early_warn_uninitialized =
- {
- GIMPLE_PASS, /* type */
- "*early_warn_uninitialized", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_UNINIT, /* tv_id */
- PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- };
-
- class pass_early_warn_uninitialized : public gimple_opt_pass
- {
- public:
- pass_early_warn_uninitialized(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_early_warn_uninitialized, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate () { return gate_warn_uninitialized (); }
- unsigned int execute () { return execute_early_warn_uninitialized (); }
-
- }; // class pass_early_warn_uninitialized
-
- } // anon namespace
-
- gimple_opt_pass *
- make_pass_early_warn_uninitialized (gcc::context *ctxt)
- {
- return new pass_early_warn_uninitialized (ctxt);
- }
-
/* If necessary, rewrite the base of the reference tree *TP from
a MEM_REF to a plain or converted symbol. */
===================================================================
*************** get_mask_first_set_bit (unsigned mask)
}
#define MASK_FIRST_SET_BIT(mask) get_mask_first_set_bit (mask)
-
/* Return true if T, an SSA_NAME, has an undefined value. */
!
! bool
! ssa_undefined_value_p (tree t)
{
! tree var = SSA_NAME_VAR (t);
!
! if (!var)
! ;
! /* Parameters get their initial value from the function entry. */
! else if (TREE_CODE (var) == PARM_DECL)
! return false;
! /* When returning by reference the return address is actually a hidden
! parameter. */
! else if (TREE_CODE (var) == RESULT_DECL && DECL_BY_REFERENCE (var))
! return false;
! /* Hard register variables get their initial value from the ether. */
! else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
! return false;
!
! /* The value is undefined iff its definition statement is empty. */
! return (gimple_nop_p (SSA_NAME_DEF_STMT (t))
|| (possibly_undefined_names
&& pointer_set_contains (possibly_undefined_names, t)));
}
! /* Like ssa_undefined_value_p, but don't return true if TREE_NO_WARNING
is set on SSA_NAME_VAR. */
static inline bool
! uninit_undefined_value_p (tree t)
! {
! if (!ssa_undefined_value_p (t))
return false;
if (SSA_NAME_VAR (t) && TREE_NO_WARNING (SSA_NAME_VAR (t)))
return false;
return true;
}
/* Checks if the operand OPND of PHI is defined by
another phi with one operand defined by this PHI,
but the rest operands are all defined. If yes,
}
#define MASK_FIRST_SET_BIT(mask) get_mask_first_set_bit (mask)
/* Return true if T, an SSA_NAME, has an undefined value. */
! static bool
! has_undefined_value_p (tree t)
{
! return (ssa_undefined_value_p (t)
|| (possibly_undefined_names
&& pointer_set_contains (possibly_undefined_names, t)));
}
!
!
! /* Like has_undefined_value_p, but don't return true if TREE_NO_WARNING
is set on SSA_NAME_VAR. */
static inline bool
! uninit_undefined_value_p (tree t) {
! if (!has_undefined_value_p (t))
return false;
if (SSA_NAME_VAR (t) && TREE_NO_WARNING (SSA_NAME_VAR (t)))
return false;
return true;
}
+ /* Emit warnings for uninitialized variables. This is done in two passes.
+
+ The first pass notices real uses of SSA names with undefined values.
+ Such uses are unconditionally uninitialized, and we can be certain that
+ such a use is a mistake. This pass is run before most optimizations,
+ so that we catch as many as we can.
+
+ The second pass follows PHI nodes to find uses that are potentially
+ uninitialized. In this case we can't necessarily prove that the use
+ is really uninitialized. This pass is run after most optimizations,
+ so that we thread as many jumps and possible, and delete as much dead
+ code as possible, in order to reduce false positives. We also look
+ again for plain uninitialized variables, since optimization may have
+ changed conditionally uninitialized to unconditionally uninitialized. */
+
+ /* 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. */
+
+ static void
+ warn_uninit (enum opt_code wc, tree t,
+ tree expr, tree var, const char *gmsgid, void *data)
+ {
+ gimple context = (gimple) data;
+ location_t location, cfun_loc;
+ expanded_location xloc, floc;
+
+ if (!has_undefined_value_p (t))
+ return;
+
+ /* TREE_NO_WARNING either means we already warned, or the front end
+ wishes to suppress the warning. */
+ 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))
+ ? gimple_location (context)
+ : DECL_SOURCE_LOCATION (var);
+ location = linemap_resolve_location (line_table, location,
+ LRK_SPELLING_LOCATION,
+ NULL);
+ cfun_loc = DECL_SOURCE_LOCATION (cfun->decl);
+ xloc = expand_location (location);
+ floc = expand_location (cfun_loc);
+ if (warning_at (location, wc, gmsgid, expr))
+ {
+ TREE_NO_WARNING (expr) = 1;
+
+ if (location == DECL_SOURCE_LOCATION (var))
+ return;
+ if (xloc.file != floc.file
+ || linemap_location_before_p (line_table,
+ location, cfun_loc)
+ || linemap_location_before_p (line_table,
+ cfun->function_end_locus,
+ location))
+ inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var);
+ }
+ }
+
+ static unsigned int
+ warn_uninitialized_vars (bool warn_possibly_uninitialized)
+ {
+ gimple_stmt_iterator gsi;
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
+ {
+ 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))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ use_operand_p use_p;
+ ssa_op_iter op_iter;
+ tree use;
+
+ if (is_gimple_debug (stmt))
+ continue;
+
+ /* 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_Wmaybe_uninitialized, 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_Wmaybe_uninitialized, use,
+ gimple_assign_rhs1 (stmt), base,
+ "%qE may be used uninitialized in this function",
+ stmt);
+ }
+ }
+ }
+
+ return 0;
+ }
+
/* Checks if the operand OPND of PHI is defined by
another phi with one operand defined by this PHI,
but the rest operands are all defined. If yes,
*************** make_pass_late_warn_uninitialized (gcc::
{
return new pass_late_warn_uninitialized (ctxt);
}
+
+
+ static unsigned int
+ execute_early_warn_uninitialized (void)
+ {
+ /* Currently, this pass runs always but
+ execute_late_warn_uninitialized only runs with optimization. With
+ optimization we want to warn about possible uninitialized as late
+ as possible, thus don't do it here. However, without
+ optimization we need to warn here about "may be uninitialized".
+ */
+ calculate_dominance_info (CDI_POST_DOMINATORS);
+
+ warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
+
+ /* Post-dominator information can not be reliably updated. Free it
+ after the use. */
+
+ free_dominance_info (CDI_POST_DOMINATORS);
+ return 0;
+ }
+
+
+ namespace {
+
+ const pass_data pass_data_early_warn_uninitialized =
+ {
+ GIMPLE_PASS, /* type */
+ "*early_warn_uninitialized", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ true, /* has_gate */
+ true, /* has_execute */
+ TV_TREE_UNINIT, /* tv_id */
+ PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ };
+
+ class pass_early_warn_uninitialized : public gimple_opt_pass
+ {
+ public:
+ pass_early_warn_uninitialized(gcc::context *ctxt)
+ : gimple_opt_pass(pass_data_early_warn_uninitialized, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate () { return gate_warn_uninitialized (); }
+ unsigned int execute () { return execute_early_warn_uninitialized (); }
+
+ }; // class pass_early_warn_uninitialized
+
+ } // anon namespace
+
+ gimple_opt_pass *
+ make_pass_early_warn_uninitialized (gcc::context *ctxt)
+ {
+ return new pass_early_warn_uninitialized (ctxt);
+ }
+
+
===================================================================
*************** extern tree tree_ssa_strip_useless_type_
typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
! 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);
/* Given an edge_var_map V, return the PHI arg definition. */
typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
! extern bool ssa_undefined_value_p (tree);
extern void execute_update_addresses_taken (void);
/* Given an edge_var_map V, return the PHI arg definition. */