return get_or_create_cast (type, arg1);
}
break;
+
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ case RDIV_EXPR:
+ case EXACT_DIV_EXPR:
+ if (cst1 && zerop (cst1))
+ return get_or_create_unknown_svalue (type);
+ break;
}
/* For associative ops, fold "(X op CST_A) op CST_B)" to
}
}
+ if (ctxt
+ && (op == TRUNC_DIV_EXPR
+ || op == CEIL_DIV_EXPR
+ || op == FLOOR_DIV_EXPR
+ || op == ROUND_DIV_EXPR
+ || op == TRUNC_MOD_EXPR
+ || op == CEIL_MOD_EXPR
+ || op == FLOOR_MOD_EXPR
+ || op == ROUND_MOD_EXPR
+ || op == RDIV_EXPR
+ || op == EXACT_DIV_EXPR))
+ {
+ if (const tree rhs2_cst = rhs2_sval->maybe_get_constant ())
+ if (zerop (rhs2_cst))
+ {
+ /* Ideally we should issue a warning here;
+ see PR analyzer/124217. */
+ return nullptr;
+ }
+ }
+
const svalue *sval_binop
= m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
rhs1_sval, rhs2_sval);
return true;
}
-/* Base implementation of svalue::maybe_get_value_range vfunc.
+/* Base implementation of svalue::maybe_get_value_range_1 vfunc.
If there is a suitable underlying type, write a "varying" for it to OUT
(for "any value of that type") and return true; otherwise return false. */
bool
-svalue::maybe_get_value_range (value_range &out) const
+svalue::maybe_get_value_range_1 (value_range &out) const
{
tree type = get_type ();
if (!type_can_have_value_range_p (type))
}
-/* Implementation of svalue::maybe_get_value_range for constant_svalue.
+/* Implementation of svalue::maybe_get_value_range_1 for constant_svalue.
If there is a suitable underlying type, write the value_range for the
single value of m_cst_expr to OUT and return true; otherwise return
false. */
bool
-constant_svalue::maybe_get_value_range (value_range &out) const
+constant_svalue::maybe_get_value_range_1 (value_range &out) const
{
if (!type_can_have_value_range_p (get_type ()))
return false;
}
bool
-unknown_svalue::maybe_get_value_range (value_range &) const
+unknown_svalue::maybe_get_value_range_1 (value_range &) const
{
/* Don't attempt to participate in range ops. */
return false;
return nullptr;
}
-/* Implementation of svalue::maybe_get_value_range for unaryop_svalue. */
+/* Implementation of svalue::maybe_get_value_range_1 for unaryop_svalue. */
bool
-unaryop_svalue::maybe_get_value_range (value_range &out) const
+unaryop_svalue::maybe_get_value_range_1 (value_range &out) const
{
tree type = get_type ();
if (!type_can_have_value_range_p (type))
gcc_assert (parent_svalue->can_have_associated_state_p ());
}
-/* Implementation of svalue::maybe_get_value_range for binop_svalue. */
+/* Implementation of svalue::maybe_get_value_range_1 for binop_svalue. */
bool
-binop_svalue::maybe_get_value_range (value_range &out) const
+binop_svalue::maybe_get_value_range_1 (value_range &out) const
{
tree type = get_type ();
if (!type_can_have_value_range_p (type))
/* If we can get a value_range for this svalue, write it to OUT
and return true. Otherwise return false. */
- virtual bool maybe_get_value_range (value_range &out) const;
+ bool
+ maybe_get_value_range (value_range &out) const
+ {
+ if (maybe_get_value_range_1 (out))
+ {
+ gcc_assert (!out.undefined_p ());
+ return true;
+ }
+ return false;
+ }
protected:
svalue (complexity c, symbol::id_t id, tree type)
virtual void
add_dump_widget_children (text_art::tree_widget &,
const dump_widget_info &dwi) const = 0;
+ virtual bool
+ maybe_get_value_range_1 (value_range &out) const;
tree m_type;
};
bool all_zeroes_p () const final override;
- bool maybe_get_value_range (value_range &out) const final override;
+ bool maybe_get_value_range_1 (value_range &out) const final override;
private:
tree m_cst_expr;
const bit_range &subrange,
region_model_manager *mgr) const final override;
- bool maybe_get_value_range (value_range &out) const final override;
+ bool maybe_get_value_range_1 (value_range &out) const final override;
/* Unknown values are singletons per-type, so can't have state. */
bool can_have_associated_state_p () const final override { return false; }
const bit_range &subrange,
region_model_manager *mgr) const final override;
- bool maybe_get_value_range (value_range &out) const final override;
+ bool maybe_get_value_range_1 (value_range &out) const final override;
private:
enum tree_code m_op;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
- bool maybe_get_value_range (value_range &out) const final override;
+ bool maybe_get_value_range_1 (value_range &out) const final override;
enum tree_code get_op () const { return m_op; }
const svalue *get_arg0 () const { return m_arg0; }
--- /dev/null
+#include "analyzer-decls.h"
+
+static int __attribute__((noipa))
+return_zero (void)
+{
+ return 0;
+}
+
+void
+test_div (int a)
+{
+ __analyzer_eval (a / return_zero () == 0); /* { dg-warning "UNKNOWN" } */
+}
+
+void
+test_mod (int a)
+{
+ __analyzer_eval (a % return_zero () == 0); /* { dg-warning "UNKNOWN" } */
+}
--- /dev/null
+short s;
+
+int
+foo()
+{
+ s %= 0; /* { dg-warning "division by zero" } */
+ return s > 0;
+}
--- /dev/null
+short s;
+
+int
+foo()
+{
+ s %= (0, 0);
+ return s > 0;
+}