Skip to content

Commit 8e6d217

Browse files
committed
Improve error message for assert!() macro in functions returning bool
When assert!() is used in a function that returns a value, the compiler emits a confusing error message suggesting the if expression is missing an else clause. This commit detects when the if expression comes from an assert!() or debug_assert!() macro expansion and provides a clearer error message explaining that assert!() does not return a value.
1 parent 625b63f commit 8e6d217

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
44
use rustc_hir::{self as hir, ExprKind, HirId, PatKind};
55
use rustc_hir_pretty::ty_to_string;
66
use rustc_middle::ty::{self, Ty};
7-
use rustc_span::Span;
7+
use rustc_span::{sym, Span};
88
use rustc_trait_selection::traits::{
99
MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
1010
};
@@ -302,15 +302,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
302302
then_expr: &'tcx hir::Expr<'tcx>,
303303
error: &mut bool,
304304
) {
305+
// Check if this `if` expression comes from an `assert!()` or `debug_assert!()` macro expansion
306+
// Walk the macro expansion chain to find the root assert macro, similar to how panic_call does it
307+
let mut is_assert_macro = false;
308+
let mut expn = if_span.ctxt().outer_expn_data();
309+
loop {
310+
if let Some(def_id) = expn.macro_def_id {
311+
if self.tcx.is_diagnostic_item(sym::assert_macro, def_id)
312+
|| self.tcx.is_diagnostic_item(sym::debug_assert_macro, def_id)
313+
{
314+
is_assert_macro = true;
315+
break;
316+
}
317+
}
318+
let parent = expn.call_site.ctxt().outer_expn_data();
319+
if parent.macro_def_id.is_none() {
320+
break;
321+
}
322+
expn = parent;
323+
}
324+
305325
if let Some((if_span, msg)) = ret_reason {
306326
err.span_label(if_span, msg);
307327
} else if let ExprKind::Block(block, _) = then_expr.kind
308328
&& let Some(expr) = block.expr
309329
{
310330
err.span_label(expr.span, "found here");
311331
}
312-
err.note("`if` expressions without `else` evaluate to `()`");
313-
err.help("consider adding an `else` block that evaluates to the expected type");
332+
333+
if is_assert_macro {
334+
err.note("`assert!()` macro expands to an `if` expression without an `else` clause");
335+
err.help("`assert!()` does not return a value; consider using a different approach or adding a return statement");
336+
} else {
337+
err.note("`if` expressions without `else` evaluate to `()`");
338+
err.help("consider adding an `else` block that evaluates to the expected type");
339+
}
314340
*error = true;
315341
if let ExprKind::Let(hir::LetExpr { span, pat, init, .. }) = cond_expr.kind
316342
&& let ExprKind::Block(block, _) = then_expr.kind
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ dont-require-annotations: NOTE
2+
3+
fn f() -> bool {
4+
assert!(1 < 2)
5+
//~^ ERROR `if` may be missing an `else` clause [E0317]
6+
//~| NOTE expected `bool`, found `()`
7+
}
8+
9+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0317]: `if` may be missing an `else` clause
2+
--> $DIR/assert-macro-without-else.rs:4:5
3+
|
4+
LL | fn f() -> bool {
5+
| ---- expected `bool` because of this return type
6+
LL | assert!(1 < 2)
7+
| ^^^^^^^^^^^^^^ expected `bool`, found `()`
8+
|
9+
= note: `assert!()` macro expands to an `if` expression without an `else` clause
10+
= help: `assert!()` does not return a value; consider using a different approach or adding a return statement
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0317`.

0 commit comments

Comments
 (0)