3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-08-02 12:13:25 +00:00

Fix remaining clang warnings for fallthrough switch cases (in debug build). (#10314)

https://github.com/Z3Prover/z3/pull/10284 changed the UNREACHABLE macro
in debug.h to use __builtin_unreachable() to indicate to the compiler
that the
code leading it should be considered unreachable.

In https://github.com/Z3Prover/z3/pull/10295 Copilot figured out that
this was wrong: the unreachable macro makes calls, which shouldn't be
elided, and whose arguments should be evaluated. It partially fixed the
problem by declaring invoke_exit_action to be `[[noreturn]]`. This
eliminated warnings in non-debug builds, but when Z3_DEBUG is enabled,
`UNREACHABLE` ends with an invocation of `INVOKE_DEBUGER()`. This can
call `invoke_debugger()`, which *can* actually return (so it can't be
given the `[[noreturn]]` attribute. So we still get warnings in debug
builds.

This PR fixes those, creating a Z3_unreachable_case macro, which is just
a combination of `UNREACHABLE()` and `Z3_fallthrough`. It uses that in
the places that give warnings.

It seemed better to me to still have these cases have a single macro,
rather than `UNREACHABLE` followed by an explicit `Z3_fallthrough`; this
seemed to me like it would confuse people -- "how can you fall through
if this code is unreachable?" But I'm open to alternative suggestions!
This commit is contained in:
davedets 2026-07-30 19:24:46 -07:00 committed by GitHub
parent 141e99ffe7
commit c49eb07c3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 11 additions and 5 deletions

View file

@ -363,7 +363,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
case OP_MUL: return is_real ? m_r_mul_decl : m_i_mul_decl;
case OP_DIV: return m_r_div_decl;
case OP_IDIV: return m_i_div_decl;
case OP_IDIVIDES: UNREACHABLE();
case OP_IDIVIDES: Z3_unreachable_case();
case OP_REM: return m_i_rem_decl;
case OP_MOD: return m_i_mod_decl;
case OP_DIV0: return m_manager->mk_func_decl(symbol("/0"), m_real_decl, m_real_decl, m_real_decl, func_decl_info(m_family_id, OP_DIV0));

View file

@ -774,7 +774,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren
case PR_TRANSITIVITY_STAR: return mk_proof_decl("trans*", k, num_parents, m_transitivity_star_decls);
case PR_MONOTONICITY: return mk_proof_decl("monotonicity", k, num_parents, m_monotonicity_decls);
case PR_QUANT_INTRO: return mk_proof_decl("quant-intro", k, 1, m_quant_intro_decl);
case PR_BIND: UNREACHABLE();
case PR_BIND: Z3_unreachable_case();
case PR_DISTRIBUTIVITY: return mk_proof_decl("distributivity", k, num_parents, m_distributivity_decls);
case PR_AND_ELIM: return mk_proof_decl("and-elim", k, 1, m_and_elim_decl);
case PR_NOT_OR_ELIM: return mk_proof_decl("not-or-elim", k, 1, m_not_or_elim_decl);

View file

@ -328,7 +328,7 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
SASSERT(to_app(args[0])->get_num_args() == num_args+1);
switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) {
case l_true:
UNREACHABLE();
Z3_unreachable_case();
case l_false: {
expr* arg0 = to_app(args[0])->get_arg(0);
while (m_util.is_store(arg0) && compare_args(num_args-1, args + 1, to_app(arg0)->get_args() + 1) == l_false) {

View file

@ -780,7 +780,7 @@ namespace smt {
case OP_DISTINCT:
throw default_exception(std::string("formula has not been simplified") + " : " + mk_pp(n, m));
case OP_OEQ:
UNREACHABLE();
Z3_unreachable_case();
default:
break;
}

View file

@ -123,7 +123,7 @@ sexpr * const * sexpr::get_children() const {
void sexpr::display_atom(std::ostream & out) const {
switch (get_kind()) {
case sexpr::kind_t::COMPOSITE:
UNREACHABLE();
Z3_unreachable_case();
case sexpr::kind_t::NUMERAL:
out << static_cast<sexpr_numeral const *>(this)->m_val;
break;

View file

@ -80,6 +80,12 @@ static_assert(sizeof(int64_t) == 8, "64 bits");
# define Z3_fallthrough
#endif
// UNREACHABLE is not defined in a way that makes it clear to the compiler
// that it does not return (because it calls INVOKE_DEBUGGER() in debug builds,
// and that *may* return). Using this for unreachable switch cases avoids
// any fall-through warnings.
#define Z3_unreachable_case() UNREACHABLE(); Z3_fallthrough
static inline bool is_power_of_two(unsigned v) { return !(v & (v - 1)) && v; }
/**