analyzer: remove add_any_constraints_from_ssa_def_stmt
I'm working on reimplementing -Wanalyzer-use-of-uninitialized-value, but I ran into issues with region_model::add_any_constraints_from_ssa_def_stmt. This function is from the initial commit of the analyzer and walks the SSA names finding conditions that were missed due to the GCC 10 era region_model not retaining useful information on how values were created; as of GCC 11 the symbolic values contain this information, and so the conditions can be reconstructed from them instead. region_model::add_any_constraints_from_ssa_def_stmt is a liability when tracking uninitialized values as it requires looking up SSA values when those values may have been purged, thus greatly complicating detection of uses of uninitialized values. It's simplest to eliminate it and reimplement the condition-finding via the makeup of the svalues, which this patch does. Doing so requires supporting add_condition on svalues rather than just on trees, which requires some changes to ana::state_machine and its subclasses. gcc/analyzer/ChangeLog: * diagnostic-manager.cc (null_assignment_sm_context::get_state): New overload. (null_assignment_sm_context::set_next_state): New overload. (null_assignment_sm_context::get_diagnostic_tree): New. * engine.cc (impl_sm_context::get_state): New overload. (impl_sm_context::set_next_state): New overload. (impl_sm_context::get_diagnostic_tree): New overload. (impl_region_model_context::on_condition): Convert params from tree to const svalue *. * exploded-graph.h (impl_region_model_context::on_condition): Likewise. * region-model.cc (region_model::on_call_pre): Move handling of internal calls to before checking for get_fndecl_for_call. (region_model::add_constraints_from_binop): New. (region_model::add_constraint): Split out into a new overload working on const svalue * rather than tree. Call add_constraints_from_binop. Drop call to add_any_constraints_from_ssa_def_stmt. (region_model::add_any_constraints_from_ssa_def_stmt): Delete. (region_model::add_any_constraints_from_gassign): Delete. (region_model::add_any_constraints_from_gcall): Delete. * region-model.h (region_model::add_any_constraints_from_ssa_def_stmt): Delete. (region_model::add_any_constraints_from_gassign): Delete. (region_model::add_any_constraints_from_gcall): Delete. (region_model::add_constraint): Add overload decl. (region_model::add_constraints_from_binop): New decl. (region_model_context::on_condition): Convert params from tree to const svalue *. (noop_region_model_context::on_condition): Likewise. * sm-file.cc (fileptr_state_machine::condition): Likewise. * sm-malloc.cc (malloc_state_machine::on_condition): Likewise. * sm-pattern-test.cc: Include tristate.h, selftest.h, analyzer/call-string.h, analyzer/program-point.h, analyzer/store.h, and analyzer/region-model.h. (pattern_test_state_machine::on_condition): Convert params from tree to const svalue *. * sm-sensitive.cc (sensitive_state_machine::on_condition): Delete. * sm-signal.cc (signal_state_machine::on_condition): Delete. * sm-taint.cc (taint_state_machine::on_condition): Convert params from tree to const svalue *. * sm.cc: Include tristate.h, selftest.h, analyzer/call-string.h, analyzer/program-point.h, analyzer/store.h, and analyzer/region-model.h. (any_pointer_p): Add overload taking const svalue *sval. * sm.h (any_pointer_p): Add overload taking const svalue *sval. (state_machine::on_condition): Convert params from tree to const svalue *. Provide no-op default implementation. (sm_context::get_state): Add overload taking const svalue *sval. (sm_context::set_next_state): Likewise. (sm_context::on_transition): Likewise. (sm_context::get_diagnostic_tree): Likewise. * svalue.cc (svalue::all_zeroes_p): New. (constant_svalue::all_zeroes_p): New. (repeated_svalue::all_zeroes_p): Convert to vfunc. * svalue.h (svalue::all_zeroes_p): New decl. (constant_svalue::all_zeroes_p): New decl. (repeated_svalue::all_zeroes_p): Convert decl to vfunc. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/pattern-test-2.c: Update expected results. * gcc.dg/plugin/analyzer_gil_plugin.c (gil_state_machine::on_condition): Remove. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
a110855667
commit
48e8a7a677
|
@ -1377,6 +1377,14 @@ struct null_assignment_sm_context : public sm_context
|
|||
return current;
|
||||
}
|
||||
|
||||
state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
const svalue *sval) FINAL OVERRIDE
|
||||
{
|
||||
const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
|
||||
state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
|
||||
return current;
|
||||
}
|
||||
|
||||
void set_next_state (const gimple *stmt,
|
||||
tree var,
|
||||
state_machine::state_t to,
|
||||
|
@ -1401,6 +1409,28 @@ struct null_assignment_sm_context : public sm_context
|
|||
*m_new_state));
|
||||
}
|
||||
|
||||
void set_next_state (const gimple *stmt,
|
||||
const svalue *sval,
|
||||
state_machine::state_t to,
|
||||
tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE
|
||||
{
|
||||
state_machine::state_t from = get_state (stmt, sval);
|
||||
if (from != m_sm.get_start_state ())
|
||||
return;
|
||||
|
||||
const supernode *supernode = m_point->get_supernode ();
|
||||
int stack_depth = m_point->get_stack_depth ();
|
||||
|
||||
m_emission_path->add_event (new state_change_event (supernode,
|
||||
m_stmt,
|
||||
stack_depth,
|
||||
m_sm,
|
||||
sval,
|
||||
from, to,
|
||||
NULL,
|
||||
*m_new_state));
|
||||
}
|
||||
|
||||
void warn (const supernode *, const gimple *,
|
||||
tree, pending_diagnostic *d) FINAL OVERRIDE
|
||||
{
|
||||
|
@ -1412,6 +1442,11 @@ struct null_assignment_sm_context : public sm_context
|
|||
return expr;
|
||||
}
|
||||
|
||||
tree get_diagnostic_tree (const svalue *sval) FINAL OVERRIDE
|
||||
{
|
||||
return m_new_state->m_region_model->get_representative_tree (sval);
|
||||
}
|
||||
|
||||
state_machine::state_t get_global_state () const FINAL OVERRIDE
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -245,6 +245,16 @@ public:
|
|||
= m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
|
||||
return current;
|
||||
}
|
||||
state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
const svalue *sval)
|
||||
{
|
||||
logger * const logger = get_logger ();
|
||||
LOG_FUNC (logger);
|
||||
state_machine::state_t current
|
||||
= m_old_smap->get_state (sval, m_eg.get_ext_state ());
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
void set_next_state (const gimple *stmt,
|
||||
tree var,
|
||||
|
@ -280,6 +290,41 @@ public:
|
|||
to, origin_new_sval, m_eg.get_ext_state ());
|
||||
}
|
||||
|
||||
void set_next_state (const gimple *stmt,
|
||||
const svalue *sval,
|
||||
state_machine::state_t to,
|
||||
tree origin)
|
||||
{
|
||||
logger * const logger = get_logger ();
|
||||
LOG_FUNC (logger);
|
||||
impl_region_model_context old_ctxt
|
||||
(m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
|
||||
NULL, stmt);
|
||||
|
||||
impl_region_model_context new_ctxt (m_eg, m_enode_for_diag,
|
||||
m_old_state, m_new_state,
|
||||
NULL,
|
||||
stmt);
|
||||
const svalue *origin_new_sval
|
||||
= m_new_state->m_region_model->get_rvalue (origin, &new_ctxt);
|
||||
|
||||
state_machine::state_t current
|
||||
= m_old_smap->get_state (sval, m_eg.get_ext_state ());
|
||||
if (logger)
|
||||
{
|
||||
logger->start_log_line ();
|
||||
logger->log_partial ("%s: state transition of ",
|
||||
m_sm.get_name ());
|
||||
sval->dump_to_pp (logger->get_printer (), true);
|
||||
logger->log_partial (": %s -> %s",
|
||||
current->get_name (),
|
||||
to->get_name ());
|
||||
logger->end_log_line ();
|
||||
}
|
||||
m_new_smap->set_state (m_new_state->m_region_model, sval,
|
||||
to, origin_new_sval, m_eg.get_ext_state ());
|
||||
}
|
||||
|
||||
void warn (const supernode *snode, const gimple *stmt,
|
||||
tree var, pending_diagnostic *d) FINAL OVERRIDE
|
||||
{
|
||||
|
@ -323,6 +368,11 @@ public:
|
|||
return expr;
|
||||
}
|
||||
|
||||
tree get_diagnostic_tree (const svalue *sval) FINAL OVERRIDE
|
||||
{
|
||||
return m_new_state->m_region_model->get_representative_tree (sval);
|
||||
}
|
||||
|
||||
state_machine::state_t get_global_state () const FINAL OVERRIDE
|
||||
{
|
||||
return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
|
||||
|
@ -654,7 +704,9 @@ impl_region_model_context::on_state_leak (const state_machine &sm,
|
|||
state transitions. */
|
||||
|
||||
void
|
||||
impl_region_model_context::on_condition (tree lhs, enum tree_code op, tree rhs)
|
||||
impl_region_model_context::on_condition (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs)
|
||||
{
|
||||
int sm_idx;
|
||||
sm_state_map *smap;
|
||||
|
|
|
@ -59,7 +59,9 @@ class impl_region_model_context : public region_model_context
|
|||
const svalue *sval,
|
||||
state_machine::state_t state);
|
||||
|
||||
void on_condition (tree lhs, enum tree_code op, tree rhs) FINAL OVERRIDE;
|
||||
void on_condition (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs) FINAL OVERRIDE;
|
||||
|
||||
void on_unknown_change (const svalue *sval, bool is_mutable) FINAL OVERRIDE;
|
||||
|
||||
|
|
|
@ -881,12 +881,23 @@ bool
|
|||
region_model::on_call_pre (const gcall *call, region_model_context *ctxt,
|
||||
bool *out_terminate_path)
|
||||
{
|
||||
call_details cd (call, this, ctxt);
|
||||
|
||||
bool unknown_side_effects = false;
|
||||
|
||||
if (gimple_call_internal_p (call))
|
||||
{
|
||||
switch (gimple_call_internal_fn (call))
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case IFN_BUILTIN_EXPECT:
|
||||
return impl_call_builtin_expect (cd);
|
||||
}
|
||||
}
|
||||
|
||||
if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
|
||||
{
|
||||
call_details cd (call, this, ctxt);
|
||||
|
||||
/* The various impl_call_* member functions are implemented
|
||||
in region-model-impl-calls.cc.
|
||||
Having them split out into separate functions makes it easier
|
||||
|
@ -958,16 +969,6 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt,
|
|||
on the return value. */
|
||||
break;
|
||||
}
|
||||
else if (gimple_call_internal_p (call))
|
||||
switch (gimple_call_internal_fn (call))
|
||||
{
|
||||
default:
|
||||
if (!DECL_PURE_P (callee_fndecl))
|
||||
unknown_side_effects = true;
|
||||
break;
|
||||
case IFN_BUILTIN_EXPECT:
|
||||
return impl_call_builtin_expect (cd);
|
||||
}
|
||||
else if (is_named_call_p (callee_fndecl, "malloc", call, 1))
|
||||
return impl_call_malloc (cd);
|
||||
else if (is_named_call_p (callee_fndecl, "calloc", call, 2))
|
||||
|
@ -2251,6 +2252,123 @@ region_model::compare_initial_and_pointer (const initial_svalue *init,
|
|||
return tristate::TS_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Handle various constraints of the form:
|
||||
LHS: ((bool)INNER_LHS INNER_OP INNER_RHS))
|
||||
OP : == or !=
|
||||
RHS: zero
|
||||
and (with a cast):
|
||||
LHS: CAST([long]int, ((bool)INNER_LHS INNER_OP INNER_RHS))
|
||||
OP : == or !=
|
||||
RHS: zero
|
||||
by adding constraints for INNER_LHS INNEROP INNER_RHS.
|
||||
|
||||
Return true if this function can fully handle the constraint; if
|
||||
so, add the implied constraint(s) and write true to *OUT if they
|
||||
are consistent with existing constraints, or write false to *OUT
|
||||
if they contradicts existing constraints.
|
||||
|
||||
Return false for cases that this function doeesn't know how to handle.
|
||||
|
||||
For example, if we're checking a stored conditional, we'll have
|
||||
something like:
|
||||
LHS: CAST(long int, (&HEAP_ALLOCATED_REGION(8)!=(int *)0B))
|
||||
OP : NE_EXPR
|
||||
RHS: zero
|
||||
which this function can turn into an add_constraint of:
|
||||
(&HEAP_ALLOCATED_REGION(8) != (int *)0B)
|
||||
|
||||
Similarly, optimized && and || conditionals lead to e.g.
|
||||
if (p && q)
|
||||
becoming gimple like this:
|
||||
_1 = p_6 == 0B;
|
||||
_2 = q_8 == 0B
|
||||
_3 = _1 | _2
|
||||
On the "_3 is false" branch we can have constraints of the form:
|
||||
((&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
|
||||
| (&HEAP_ALLOCATED_REGION(10)!=(int *)0B))
|
||||
== 0
|
||||
which implies that both _1 and _2 are false,
|
||||
which this function can turn into a pair of add_constraints of
|
||||
(&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
|
||||
and:
|
||||
(&HEAP_ALLOCATED_REGION(10)!=(int *)0B). */
|
||||
|
||||
bool
|
||||
region_model::add_constraints_from_binop (const svalue *outer_lhs,
|
||||
enum tree_code outer_op,
|
||||
const svalue *outer_rhs,
|
||||
bool *out,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
while (const svalue *cast = outer_lhs->maybe_undo_cast ())
|
||||
outer_lhs = cast;
|
||||
const binop_svalue *binop_sval = outer_lhs->dyn_cast_binop_svalue ();
|
||||
if (!binop_sval)
|
||||
return false;
|
||||
if (!outer_rhs->all_zeroes_p ())
|
||||
return false;
|
||||
|
||||
const svalue *inner_lhs = binop_sval->get_arg0 ();
|
||||
enum tree_code inner_op = binop_sval->get_op ();
|
||||
const svalue *inner_rhs = binop_sval->get_arg1 ();
|
||||
|
||||
if (outer_op != NE_EXPR && outer_op != EQ_EXPR)
|
||||
return false;
|
||||
|
||||
/* We have either
|
||||
- "OUTER_LHS != false" (i.e. OUTER is true), or
|
||||
- "OUTER_LHS == false" (i.e. OUTER is false). */
|
||||
bool is_true = outer_op == NE_EXPR;
|
||||
|
||||
switch (inner_op)
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
{
|
||||
/* ...and "(inner_lhs OP inner_rhs) == 0"
|
||||
then (inner_lhs OP inner_rhs) must have the same
|
||||
logical value as LHS. */
|
||||
if (!is_true)
|
||||
inner_op = invert_tree_comparison (inner_op, false /* honor_nans */);
|
||||
*out = add_constraint (inner_lhs, inner_op, inner_rhs, ctxt);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
if (is_true)
|
||||
{
|
||||
/* ...and "(inner_lhs & inner_rhs) != 0"
|
||||
then both inner_lhs and inner_rhs must be true. */
|
||||
const svalue *false_sval
|
||||
= m_mgr->get_or_create_constant_svalue (boolean_false_node);
|
||||
bool sat1 = add_constraint (inner_lhs, NE_EXPR, false_sval, ctxt);
|
||||
bool sat2 = add_constraint (inner_rhs, NE_EXPR, false_sval, ctxt);
|
||||
*out = sat1 && sat2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case BIT_IOR_EXPR:
|
||||
if (!is_true)
|
||||
{
|
||||
/* ...and "(inner_lhs | inner_rhs) == 0"
|
||||
i.e. "(inner_lhs | inner_rhs)" is false
|
||||
then both inner_lhs and inner_rhs must be false. */
|
||||
const svalue *false_sval
|
||||
= m_mgr->get_or_create_constant_svalue (boolean_false_node);
|
||||
bool sat1 = add_constraint (inner_lhs, EQ_EXPR, false_sval, ctxt);
|
||||
bool sat2 = add_constraint (inner_rhs, EQ_EXPR, false_sval, ctxt);
|
||||
*out = sat1 && sat2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to add the constraint "LHS OP RHS" to this region_model.
|
||||
If it is consistent with existing constraints, add it, and return true.
|
||||
Return false if it contradicts existing constraints.
|
||||
|
@ -2268,7 +2386,21 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
|
|||
const svalue *lhs_sval = get_rvalue (lhs, ctxt);
|
||||
const svalue *rhs_sval = get_rvalue (rhs, ctxt);
|
||||
|
||||
tristate t_cond = eval_condition (lhs_sval, op, rhs_sval);
|
||||
return add_constraint (lhs_sval, op, rhs_sval, ctxt);
|
||||
}
|
||||
|
||||
/* Attempt to add the constraint "LHS OP RHS" to this region_model.
|
||||
If it is consistent with existing constraints, add it, and return true.
|
||||
Return false if it contradicts existing constraints.
|
||||
Use CTXT for reporting any diagnostics associated with the accesses. */
|
||||
|
||||
bool
|
||||
region_model::add_constraint (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
tristate t_cond = eval_condition (lhs, op, rhs);
|
||||
|
||||
/* If we already have the condition, do nothing. */
|
||||
if (t_cond.is_true ())
|
||||
|
@ -2279,10 +2411,12 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
|
|||
if (t_cond.is_false ())
|
||||
return false;
|
||||
|
||||
/* Store the constraint. */
|
||||
m_constraints->add_constraint (lhs_sval, op, rhs_sval);
|
||||
bool out;
|
||||
if (add_constraints_from_binop (lhs, op, rhs, &out, ctxt))
|
||||
return out;
|
||||
|
||||
add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
|
||||
/* Store the constraint. */
|
||||
m_constraints->add_constraint (lhs, op, rhs);
|
||||
|
||||
/* Notify the context, if any. This exists so that the state machines
|
||||
in a program_state can be notified about the condition, and so can
|
||||
|
@ -2293,9 +2427,10 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
|
|||
|
||||
/* If we have ®ION == NULL, then drop dynamic extents for REGION (for
|
||||
the case where REGION is heap-allocated and thus could be NULL). */
|
||||
if (op == EQ_EXPR && zerop (rhs))
|
||||
if (const region_svalue *region_sval = lhs_sval->dyn_cast_region_svalue ())
|
||||
unset_dynamic_extents (region_sval->get_pointee ());
|
||||
if (tree rhs_cst = rhs->maybe_get_constant ())
|
||||
if (op == EQ_EXPR && zerop (rhs_cst))
|
||||
if (const region_svalue *region_sval = lhs->dyn_cast_region_svalue ())
|
||||
unset_dynamic_extents (region_sval->get_pointee ());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2314,137 +2449,6 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
|
|||
return sat;
|
||||
}
|
||||
|
||||
/* Subroutine of region_model::add_constraint for handling optimized
|
||||
&& and || conditionals.
|
||||
|
||||
If we have an SSA_NAME for a boolean compared against 0,
|
||||
look at anything implied by the def stmt and call add_constraint
|
||||
for it (which could recurse).
|
||||
|
||||
For example, if we have
|
||||
_1 = p_6 == 0B;
|
||||
_2 = p_8 == 0B
|
||||
_3 = _1 | _2
|
||||
and add the constraint
|
||||
(_3 == 0),
|
||||
then the def stmt for _3 implies that _1 and _2 are both false,
|
||||
and hence we can add the constraints:
|
||||
p_6 != 0B
|
||||
p_8 != 0B. */
|
||||
|
||||
void
|
||||
region_model::add_any_constraints_from_ssa_def_stmt (tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
if (TREE_CODE (lhs) != SSA_NAME)
|
||||
return;
|
||||
|
||||
if (!zerop (rhs))
|
||||
return;
|
||||
|
||||
if (op != NE_EXPR && op != EQ_EXPR)
|
||||
return;
|
||||
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
|
||||
if (const gassign *assign = dyn_cast<gassign *> (def_stmt))
|
||||
add_any_constraints_from_gassign (op, rhs, assign, ctxt);
|
||||
else if (gcall *call = dyn_cast<gcall *> (def_stmt))
|
||||
add_any_constraints_from_gcall (op, rhs, call, ctxt);
|
||||
}
|
||||
|
||||
/* Add any constraints for an SSA_NAME defined by ASSIGN
|
||||
where the result OP RHS. */
|
||||
|
||||
void
|
||||
region_model::add_any_constraints_from_gassign (enum tree_code op,
|
||||
tree rhs,
|
||||
const gassign *assign,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
/* We have either
|
||||
- "LHS != false" (i.e. LHS is true), or
|
||||
- "LHS == false" (i.e. LHS is false). */
|
||||
bool is_true = op == NE_EXPR;
|
||||
|
||||
enum tree_code rhs_code = gimple_assign_rhs_code (assign);
|
||||
|
||||
switch (rhs_code)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case NOP_EXPR:
|
||||
case VIEW_CONVERT_EXPR:
|
||||
{
|
||||
add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt);
|
||||
}
|
||||
break;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
{
|
||||
if (is_true)
|
||||
{
|
||||
/* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
|
||||
then both rhs1 and rhs2 must be true. */
|
||||
tree rhs1 = gimple_assign_rhs1 (assign);
|
||||
tree rhs2 = gimple_assign_rhs2 (assign);
|
||||
add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
|
||||
add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BIT_IOR_EXPR:
|
||||
{
|
||||
if (!is_true)
|
||||
{
|
||||
/* ...and "LHS == (rhs1 | rhs2)
|
||||
i.e. "(rhs1 | rhs2)" is false
|
||||
then both rhs1 and rhs2 must be false. */
|
||||
tree rhs1 = gimple_assign_rhs1 (assign);
|
||||
tree rhs2 = gimple_assign_rhs2 (assign);
|
||||
add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
|
||||
add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
{
|
||||
/* ...and "LHS == (rhs1 OP rhs2)"
|
||||
then rhs1 OP rhs2 must have the same logical value as LHS. */
|
||||
tree rhs1 = gimple_assign_rhs1 (assign);
|
||||
tree rhs2 = gimple_assign_rhs2 (assign);
|
||||
if (!is_true)
|
||||
rhs_code
|
||||
= invert_tree_comparison (rhs_code, false /* honor_nans */);
|
||||
add_constraint (rhs1, rhs_code, rhs2, ctxt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add any constraints for an SSA_NAME defined by CALL
|
||||
where the result OP RHS. */
|
||||
|
||||
void
|
||||
region_model::add_any_constraints_from_gcall (enum tree_code op,
|
||||
tree rhs,
|
||||
const gcall *call,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
if (gimple_call_builtin_p (call, BUILT_IN_EXPECT)
|
||||
|| gimple_call_builtin_p (call, BUILT_IN_EXPECT_WITH_PROBABILITY)
|
||||
|| gimple_call_internal_p (call, IFN_BUILTIN_EXPECT))
|
||||
{
|
||||
/* __builtin_expect's return value is its initial argument. */
|
||||
add_constraint (gimple_call_arg (call, 0), op, rhs, ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine what is known about the condition "LHS OP RHS" within
|
||||
this model.
|
||||
Use CTXT for reporting any diagnostics associated with the accesses. */
|
||||
|
|
|
@ -691,18 +691,15 @@ class region_model
|
|||
get_representative_path_var_1 (const region *reg,
|
||||
svalue_set *visited) const;
|
||||
|
||||
void add_any_constraints_from_ssa_def_stmt (tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs,
|
||||
region_model_context *ctxt);
|
||||
void add_any_constraints_from_gassign (enum tree_code op,
|
||||
tree rhs,
|
||||
const gassign *assign,
|
||||
region_model_context *ctxt);
|
||||
void add_any_constraints_from_gcall (enum tree_code op,
|
||||
tree rhs,
|
||||
const gcall *call,
|
||||
region_model_context *ctxt);
|
||||
bool add_constraint (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs,
|
||||
region_model_context *ctxt);
|
||||
bool add_constraints_from_binop (const svalue *outer_lhs,
|
||||
enum tree_code outer_op,
|
||||
const svalue *outer_rhs,
|
||||
bool *out,
|
||||
region_model_context *ctxt);
|
||||
|
||||
void update_for_call_superedge (const call_superedge &call_edge,
|
||||
region_model_context *ctxt);
|
||||
|
@ -781,7 +778,9 @@ class region_model_context
|
|||
and use them to trigger sm-state transitions (e.g. transitions due
|
||||
to ptrs becoming known to be NULL or non-NULL, rather than just
|
||||
"unchecked") */
|
||||
virtual void on_condition (tree lhs, enum tree_code op, tree rhs) = 0;
|
||||
virtual void on_condition (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs) = 0;
|
||||
|
||||
/* Hooks for clients to be notified when an unknown change happens
|
||||
to SVAL (in response to a call to an unknown function). */
|
||||
|
@ -812,9 +811,9 @@ public:
|
|||
void on_liveness_change (const svalue_set &,
|
||||
const region_model *) OVERRIDE {}
|
||||
logger *get_logger () OVERRIDE { return NULL; }
|
||||
void on_condition (tree lhs ATTRIBUTE_UNUSED,
|
||||
void on_condition (const svalue *lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
tree rhs ATTRIBUTE_UNUSED) OVERRIDE
|
||||
const svalue *rhs ATTRIBUTE_UNUSED) OVERRIDE
|
||||
{
|
||||
}
|
||||
void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED,
|
||||
|
|
|
@ -77,9 +77,9 @@ public:
|
|||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
const svalue *rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
|
||||
|
@ -381,19 +381,18 @@ void
|
|||
fileptr_state_machine::on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const
|
||||
const svalue *rhs) const
|
||||
{
|
||||
if (!zerop (rhs))
|
||||
if (!rhs->all_zeroes_p ())
|
||||
return;
|
||||
|
||||
// TODO: has to be a FILE *, specifically
|
||||
if (TREE_CODE (TREE_TYPE (lhs)) != POINTER_TYPE)
|
||||
if (!any_pointer_p (lhs))
|
||||
return;
|
||||
|
||||
// TODO: has to be a FILE *, specifically
|
||||
if (TREE_CODE (TREE_TYPE (rhs)) != POINTER_TYPE)
|
||||
if (!any_pointer_p (rhs))
|
||||
return;
|
||||
|
||||
if (op == NE_EXPR)
|
||||
|
|
|
@ -375,9 +375,9 @@ public:
|
|||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
const svalue *rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
|
||||
|
@ -1863,11 +1863,11 @@ void
|
|||
malloc_state_machine::on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const
|
||||
const svalue *rhs) const
|
||||
{
|
||||
if (!zerop (rhs))
|
||||
if (!rhs->all_zeroes_p ())
|
||||
return;
|
||||
|
||||
if (!any_pointer_p (lhs))
|
||||
|
|
|
@ -37,6 +37,12 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/analyzer-logging.h"
|
||||
#include "analyzer/sm.h"
|
||||
#include "analyzer/pending-diagnostic.h"
|
||||
#include "tristate.h"
|
||||
#include "selftest.h"
|
||||
#include "analyzer/call-string.h"
|
||||
#include "analyzer/program-point.h"
|
||||
#include "analyzer/store.h"
|
||||
#include "analyzer/region-model.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -61,9 +67,9 @@ public:
|
|||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
const svalue *rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
};
|
||||
|
@ -118,18 +124,22 @@ void
|
|||
pattern_test_state_machine::on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const
|
||||
const svalue *rhs) const
|
||||
{
|
||||
if (stmt == NULL)
|
||||
return;
|
||||
|
||||
if (!CONSTANT_CLASS_P (rhs))
|
||||
tree rhs_cst = rhs->maybe_get_constant ();
|
||||
if (!rhs_cst)
|
||||
return;
|
||||
|
||||
pending_diagnostic *diag = new pattern_match (lhs, op, rhs);
|
||||
sm_ctxt->warn (node, stmt, lhs, diag);
|
||||
if (tree lhs_expr = sm_ctxt->get_diagnostic_tree (lhs))
|
||||
{
|
||||
pending_diagnostic *diag = new pattern_match (lhs_expr, op, rhs_cst);
|
||||
sm_ctxt->warn (node, stmt, lhs_expr, diag);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -58,13 +58,6 @@ public:
|
|||
const supernode *node,
|
||||
const gimple *stmt) const FINAL OVERRIDE;
|
||||
|
||||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
|
||||
/* State for "sensitive" data, such as a password. */
|
||||
|
@ -222,17 +215,6 @@ sensitive_state_machine::on_stmt (sm_context *sm_ctxt,
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
sensitive_state_machine::on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
tree lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
tree rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
/* Empty. */
|
||||
}
|
||||
|
||||
bool
|
||||
sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
|
|
|
@ -81,13 +81,6 @@ public:
|
|||
const supernode *node,
|
||||
const gimple *stmt) const FINAL OVERRIDE;
|
||||
|
||||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
|
||||
/* These states are "global", rather than per-expression. */
|
||||
|
@ -363,20 +356,6 @@ signal_state_machine::on_stmt (sm_context *sm_ctxt,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Implementation of state_machine::on_condition vfunc for
|
||||
signal_state_machine. */
|
||||
|
||||
void
|
||||
signal_state_machine::on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
tree lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
tree rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
bool
|
||||
signal_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
|
|
|
@ -61,9 +61,9 @@ public:
|
|||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
const svalue *rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
|
||||
|
@ -281,9 +281,9 @@ void
|
|||
taint_state_machine::on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
const svalue *lhs,
|
||||
enum tree_code op,
|
||||
tree rhs ATTRIBUTE_UNUSED) const
|
||||
const svalue *rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
if (stmt == NULL)
|
||||
return;
|
||||
|
|
|
@ -35,6 +35,11 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/analyzer.h"
|
||||
#include "analyzer/analyzer-logging.h"
|
||||
#include "analyzer/sm.h"
|
||||
#include "tristate.h"
|
||||
#include "analyzer/call-string.h"
|
||||
#include "analyzer/program-point.h"
|
||||
#include "analyzer/store.h"
|
||||
#include "analyzer/svalue.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -48,6 +53,15 @@ any_pointer_p (tree var)
|
|||
return POINTER_TYPE_P (TREE_TYPE (var));
|
||||
}
|
||||
|
||||
/* Return true if SVAL has pointer or reference type. */
|
||||
|
||||
bool
|
||||
any_pointer_p (const svalue *sval)
|
||||
{
|
||||
if (!sval->get_type ())
|
||||
return false;
|
||||
return POINTER_TYPE_P (sval->get_type ());
|
||||
}
|
||||
|
||||
/* class state_machine::state. */
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ class state_machine;
|
|||
class sm_context;
|
||||
class pending_diagnostic;
|
||||
|
||||
extern bool any_pointer_p (tree var);
|
||||
extern bool any_pointer_p (tree expr);
|
||||
extern bool any_pointer_p (const svalue *sval);
|
||||
|
||||
/* An abstract base class for a state machine describing an API.
|
||||
Manages a set of state objects, and has various virtual functions
|
||||
|
@ -89,10 +90,14 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs, enum tree_code op, tree rhs) const = 0;
|
||||
virtual void on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
const svalue *lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
const svalue *rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
}
|
||||
|
||||
/* Return true if it safe to discard the given state (to help
|
||||
when simplifying state objects).
|
||||
|
@ -182,6 +187,8 @@ public:
|
|||
/* Get the old state of VAR at STMT. */
|
||||
virtual state_machine::state_t get_state (const gimple *stmt,
|
||||
tree var) = 0;
|
||||
virtual state_machine::state_t get_state (const gimple *stmt,
|
||||
const svalue *) = 0;
|
||||
/* Set the next state of VAR to be TO, recording the "origin" of the
|
||||
state as ORIGIN.
|
||||
Use STMT for location information. */
|
||||
|
@ -189,6 +196,10 @@ public:
|
|||
tree var,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE) = 0;
|
||||
virtual void set_next_state (const gimple *stmt,
|
||||
const svalue *var,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE) = 0;
|
||||
|
||||
/* Called by state_machine in response to pattern matches:
|
||||
if VAR is in state FROM, transition it to state TO, potentially
|
||||
|
@ -206,6 +217,18 @@ public:
|
|||
set_next_state (stmt, var, to, origin);
|
||||
}
|
||||
|
||||
void on_transition (const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt,
|
||||
const svalue *var,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE)
|
||||
{
|
||||
state_machine::state_t current = get_state (stmt, var);
|
||||
if (current == from)
|
||||
set_next_state (stmt, var, to, origin);
|
||||
}
|
||||
|
||||
/* Called by state_machine in response to pattern matches:
|
||||
issue a diagnostic D using NODE and STMT for location information. */
|
||||
virtual void warn (const supernode *node, const gimple *stmt,
|
||||
|
@ -220,6 +243,7 @@ public:
|
|||
{
|
||||
return expr;
|
||||
}
|
||||
virtual tree get_diagnostic_tree (const svalue *) = 0;
|
||||
|
||||
virtual state_machine::state_t get_global_state () const = 0;
|
||||
virtual void set_global_state (state_machine::state_t) = 0;
|
||||
|
|
|
@ -557,6 +557,15 @@ svalue::maybe_fold_bits_within (tree,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Base implementation of svalue::all_zeroes_p.
|
||||
Return true if this value is known to be all zeroes. */
|
||||
|
||||
bool
|
||||
svalue::all_zeroes_p () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* class region_svalue : public svalue. */
|
||||
|
||||
/* Implementation of svalue::dump_to_pp vfunc for region_svalue. */
|
||||
|
@ -742,6 +751,14 @@ constant_svalue::maybe_fold_bits_within (tree type,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Implementation of svalue::all_zeroes_p for constant_svalue. */
|
||||
|
||||
bool
|
||||
constant_svalue::all_zeroes_p () const
|
||||
{
|
||||
return zerop (m_cst_expr);
|
||||
}
|
||||
|
||||
/* class unknown_svalue : public svalue. */
|
||||
|
||||
/* Implementation of svalue::dump_to_pp vfunc for unknown_svalue. */
|
||||
|
@ -1154,15 +1171,12 @@ repeated_svalue::accept (visitor *v) const
|
|||
m_inner_svalue->accept (v);
|
||||
}
|
||||
|
||||
/* Return true if this value is known to be all zeroes. */
|
||||
/* Implementation of svalue::all_zeroes_p for repeated_svalue. */
|
||||
|
||||
bool
|
||||
repeated_svalue::all_zeroes_p () const
|
||||
{
|
||||
if (tree cst = m_inner_svalue->maybe_get_constant ())
|
||||
if (zerop (cst))
|
||||
return true;
|
||||
return false;
|
||||
return m_inner_svalue->all_zeroes_p ();
|
||||
}
|
||||
|
||||
/* Implementation of svalue::maybe_fold_bits_within vfunc
|
||||
|
|
|
@ -157,6 +157,8 @@ public:
|
|||
const bit_range &subrange,
|
||||
region_model_manager *mgr) const;
|
||||
|
||||
virtual bool all_zeroes_p () const;
|
||||
|
||||
protected:
|
||||
svalue (complexity c, tree type)
|
||||
: m_complexity (c), m_type (type)
|
||||
|
@ -277,6 +279,8 @@ public:
|
|||
const bit_range &subrange,
|
||||
region_model_manager *mgr) const FINAL OVERRIDE;
|
||||
|
||||
bool all_zeroes_p () const FINAL OVERRIDE;
|
||||
|
||||
private:
|
||||
tree m_cst_expr;
|
||||
};
|
||||
|
@ -858,7 +862,7 @@ public:
|
|||
const svalue *get_outer_size () const { return m_outer_size; }
|
||||
const svalue *get_inner_svalue () const { return m_inner_svalue; }
|
||||
|
||||
bool all_zeroes_p () const;
|
||||
bool all_zeroes_p () const FINAL OVERRIDE;
|
||||
|
||||
const svalue *
|
||||
maybe_fold_bits_within (tree type,
|
||||
|
|
|
@ -25,11 +25,8 @@ void test_2 (void *p, void *q)
|
|||
return;
|
||||
foo(p);
|
||||
|
||||
/* { dg-warning "pattern match on 'tmp1 == 0'" "tmp1 == 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on 'tmp2 == 0'" "tmp2 == 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on '<unknown> == 0'" "<unknown> == 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on '<unknown> != 0'" "<unknown> != 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on 'p != 0'" "p != 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on 'tmp1 | tmp2 != 0'" "tmp1 | tmp2 != 0" { target *-*-* } cond_2 } */
|
||||
/* { dg-warning "pattern match on 'q != 0'" "q != 0" { target *-*-* } cond_2 } */
|
||||
}
|
||||
|
||||
|
@ -44,10 +41,7 @@ void test_3 (void *p, void *q)
|
|||
return;
|
||||
foo(p);
|
||||
|
||||
/* { dg-warning "pattern match on 'tmp1 != 0'" "tmp1 != 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on 'tmp2 != 0'" "tmp2 != 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on '<unknown> == 0'" "<unknown> == 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on '<unknown> != 0'" "<unknown> != 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on 'p == 0'" "p == 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on 'tmp1 & tmp2 == 0'" "tmp1 & tmp2 == 0" { target *-*-* } cond_3 } */
|
||||
/* { dg-warning "pattern match on 'q == 0'" "q == 0" { target *-*-* } cond_3 } */
|
||||
}
|
||||
|
|
|
@ -53,13 +53,6 @@ public:
|
|||
const supernode *node,
|
||||
const gimple *stmt) const FINAL OVERRIDE;
|
||||
|
||||
void on_condition (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs) const FINAL OVERRIDE;
|
||||
|
||||
bool can_purge_p (state_t s) const FINAL OVERRIDE;
|
||||
|
||||
void check_for_pyobject_usage_without_gil (sm_context *sm_ctxt,
|
||||
|
@ -365,20 +358,6 @@ gil_state_machine::on_stmt (sm_context *sm_ctxt,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Implementation of state_machine::on_condition vfunc for
|
||||
gil_state_machine. */
|
||||
|
||||
void
|
||||
gil_state_machine::on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
tree lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
tree rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
bool
|
||||
gil_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue