if (const gassign *assign = dyn_cast <const gassign *> (stmt))
{
tree lhs = gimple_assign_lhs (assign);
- /* Use region IDs to compare lhs with DST_REP. */
- if (dst_state.m_region_model->get_lvalue (lhs, NULL)
- == dst_state.m_region_model->get_lvalue (dst_rep, NULL))
+ /* Use region IDs to compare lhs with DST_REP, bulletproofing against
+ cases where they can't have lvalues by using
+ tentative_region_model_context. */
+ tentative_region_model_context ctxt;
+ region_id lhs_rid = dst_state.m_region_model->get_lvalue (lhs, &ctxt);
+ region_id dst_rep_rid
+ = dst_state.m_region_model->get_lvalue (dst_rep, &ctxt);
+ if (lhs_rid == dst_rep_rid && !ctxt.had_errors_p ())
{
tree rhs1 = gimple_assign_rhs1 (assign);
enum tree_code op = gimple_assign_rhs_code (assign);
path->maybe_log (get_logger (), "pruned");
}
+/* A cheap test to determine if EXPR can be the expression of interest in
+ an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
+ We don't have always have a model when calling this, so we can't use
+ tentative_region_model_context, so there can be false positives. */
+
+static bool
+can_be_expr_of_interest_p (tree expr)
+{
+ if (!expr)
+ return false;
+
+ /* Reject constants. */
+ if (CONSTANT_CLASS_P (expr))
+ return false;
+
+ /* Otherwise assume that it can be an lvalue. */
+ return true;
+}
+
/* First pass of diagnostic_manager::prune_path: apply verbosity level,
pruning unrelated state change events.
tree var,
state_machine::state_t state) const
{
- /* If we have a constant (such as NULL), assume its state is also
- constant, so as not to attempt to get its lvalue whilst tracking the
- origin of the state. */
- if (var && CONSTANT_CLASS_P (var))
- var = NULL_TREE;
+ update_for_unsuitable_sm_exprs (&var);
int idx = path->num_events () - 1;
while (idx >= 0 && idx < (signed)path->num_events ())
else
log ("considering event %i", idx);
}
- gcc_assert (var == NULL || !CONSTANT_CLASS_P (var));
+ gcc_assert (var == NULL || can_be_expr_of_interest_p (var));
switch (base_event->m_kind)
{
default:
case EK_STATE_CHANGE:
{
state_change_event *state_change = (state_change_event *)base_event;
- if (state_change->get_lvalue (state_change->m_var)
- == state_change->get_lvalue (var))
+ /* Use region IDs to compare var with the state_change's m_var,
+ bulletproofing against cases where they can't have lvalues by
+ using tentative_region_model_context. */
+ tentative_region_model_context ctxt;
+ region_id state_var_rid
+ = state_change->get_lvalue (state_change->m_var, &ctxt);
+ region_id var_rid = state_change->get_lvalue (var, &ctxt);
+ if (state_var_rid == var_rid && !ctxt.had_errors_p ())
{
if (state_change->m_origin)
{
log ("event %i: switching var of interest from %qE to %qE",
idx, var, state_change->m_origin);
var = state_change->m_origin;
- if (var && CONSTANT_CLASS_P (var))
- {
- log ("new var is a constant; setting var to NULL");
- var = NULL_TREE;
- }
+ update_for_unsuitable_sm_exprs (&var);
}
log ("event %i: switching state of interest from %qs to %qs",
idx, sm->get_state_name (state_change->m_to),
else
log ("filtering event %i: state change to %qE",
idx, state_change->m_var);
+ if (ctxt.had_errors_p ())
+ log ("context had errors");
path->delete_event (idx);
}
}
/* If we've chosen a bad exploded_path, then the
phi arg might be a constant. Fail gracefully for
this case. */
- if (CONSTANT_CLASS_P (var))
- {
- log ("new var is a constant (bad path?);"
- " setting var to NULL");
- var = NULL;
- }
+ update_for_unsuitable_sm_exprs (&var);
}
}
var = caller_var;
if (expr.param_p ())
event->record_critical_state (var, state);
- if (var && CONSTANT_CLASS_P (var))
- {
- log ("new var is a constant; setting var to NULL");
- var = NULL_TREE;
- }
+ update_for_unsuitable_sm_exprs (&var);
}
}
break;
var = callee_var;
if (expr.return_value_p ())
event->record_critical_state (var, state);
- if (var && CONSTANT_CLASS_P (var))
- {
- log ("new var is a constant; setting var to NULL");
- var = NULL_TREE;
- }
+ update_for_unsuitable_sm_exprs (&var);
}
}
}
}
}
+/* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
+ If *EXPR is not suitable to be the expression of interest in
+ an sm-diagnostic, set *EXPR to NULL and log. */
+
+void
+diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
+{
+ gcc_assert (expr);
+ if (*expr && !can_be_expr_of_interest_p (*expr))
+ {
+ log ("new var %qE is unsuitable; setting var to NULL", *expr);
+ *expr = NULL_TREE;
+ }
+}
+
/* Second pass of diagnostic_manager::prune_path: remove redundant
interprocedural information.
const dump_location_t &loc) = 0;
};
+/* A subclass of region_model_context for determining if operations fail
+ e.g. "can we generate a region for the lvalue of EXPR?". */
+
+class tentative_region_model_context : public region_model_context
+{
+public:
+ tentative_region_model_context () : m_num_unexpected_codes (0) {}
+
+ void warn (pending_diagnostic *) FINAL OVERRIDE {}
+ void remap_svalue_ids (const svalue_id_map &) FINAL OVERRIDE {}
+ int on_svalue_purge (svalue_id, const svalue_id_map &) FINAL OVERRIDE
+ {
+ return 0;
+ }
+ logger *get_logger () FINAL OVERRIDE { return NULL; }
+ void on_inherited_svalue (svalue_id parent_sid ATTRIBUTE_UNUSED,
+ svalue_id child_sid ATTRIBUTE_UNUSED)
+ FINAL OVERRIDE
+ {
+ }
+ void on_cast (svalue_id src_sid ATTRIBUTE_UNUSED,
+ svalue_id dst_sid ATTRIBUTE_UNUSED) FINAL OVERRIDE
+ {
+ }
+ void on_condition (tree lhs ATTRIBUTE_UNUSED,
+ enum tree_code op ATTRIBUTE_UNUSED,
+ tree rhs ATTRIBUTE_UNUSED) FINAL OVERRIDE
+ {
+ }
+ void on_unknown_change (svalue_id sid ATTRIBUTE_UNUSED) FINAL OVERRIDE
+ {
+ }
+ void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
+ tree rhs ATTRIBUTE_UNUSED) FINAL OVERRIDE
+ {
+ }
+ void on_unexpected_tree_code (tree, const dump_location_t &)
+ FINAL OVERRIDE
+ {
+ m_num_unexpected_codes++;
+ }
+
+ bool had_errors_p () const { return m_num_unexpected_codes > 0; }
+
+private:
+ int m_num_unexpected_codes;
+};
+
/* A bundle of data for use when attempting to merge two region_model
instances to make a third. */