about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-08-15 16:16:29 +1000
committerGitHub <noreply@github.com>2025-08-15 16:16:29 +1000
commit210097ad7e272458b48e2b4cee028e7a2876a692 (patch)
treebfe849707433edd091da85267e7fc2d4d5f18920
parente7d8d34eae23bd91164510b03e6b239ccbcfdf07 (diff)
parent0a522ccfd97de0f28e5c090431c12241be875a04 (diff)
downloadrust-210097ad7e272458b48e2b4cee028e7a2876a692.tar.gz
rust-210097ad7e272458b48e2b4cee028e7a2876a692.zip
Rollup merge of #122661 - estebank:assert-macro-span, r=petrochenkov
Change the desugaring of `assert!` for better error output

In the desugaring of `assert!`, we now expand to a `match` expression instead of `if !cond {..}`.

The span of incorrect conditions will point only at the expression, and not the whole `assert!` invocation.

```
error[E0308]: mismatched types
  --> $DIR/issue-14091.rs:2:13
   |
LL |     assert!(1,1);
   |             ^ expected `bool`, found integer
```

We no longer mention the expression needing to implement the `Not` trait.

```
error[E0308]: mismatched types
  --> $DIR/issue-14091-2.rs:15:13
   |
LL |     assert!(x, x);
   |             ^ expected `bool`, found `BytePos`
```

Now `assert!(val)` desugars to:

```rust
match val {
    true => {},
    _ => $crate::panic::panic_2021!(),
}
```

Fix #122159.
-rw-r--r--clippy_lints/src/missing_asserts_for_indexing.rs12
-rw-r--r--tests/ui/const_is_empty.rs1
-rw-r--r--tests/ui/const_is_empty.stderr10
-rw-r--r--tests/ui/incompatible_msrv.rs2
4 files changed, 16 insertions, 9 deletions
diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs
index cf0c85990b1..788a04357b1 100644
--- a/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits};
 use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::unhash::UnindexMap;
 use rustc_errors::{Applicability, Diag};
-use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
+use rustc_hir::{Body, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -135,12 +135,12 @@ fn assert_len_expr<'hir>(
     cx: &LateContext<'_>,
     expr: &'hir Expr<'hir>,
 ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
-    let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
-        && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
-        && let ExprKind::Binary(bin_op, left, right) = &condition.kind
+    let (cmp, asserted_len, slice_len) = if let Some(
+        higher::IfLetOrMatch::Match(cond, [_, then], _)
+    ) = higher::IfLetOrMatch::parse(cx, expr)
+        && let ExprKind::Binary(bin_op, left, right) = &cond.kind
         // check if `then` block has a never type expression
-        && let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
-        && cx.typeck_results().expr_ty(then_expr).is_never()
+        && cx.typeck_results().expr_ty(then.body).is_never()
     {
         len_comparison(bin_op.node, left, right)?
     } else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {
diff --git a/tests/ui/const_is_empty.rs b/tests/ui/const_is_empty.rs
index 8bb4f0e5d97..63c6342a323 100644
--- a/tests/ui/const_is_empty.rs
+++ b/tests/ui/const_is_empty.rs
@@ -196,6 +196,7 @@ fn issue_13106() {
 
     const {
         assert!(EMPTY_STR.is_empty());
+        //~^ const_is_empty
     }
 
     const {
diff --git a/tests/ui/const_is_empty.stderr b/tests/ui/const_is_empty.stderr
index 2ba189058e8..9a42518698e 100644
--- a/tests/ui/const_is_empty.stderr
+++ b/tests/ui/const_is_empty.stderr
@@ -158,10 +158,16 @@ LL |     let _ = val.is_empty();
    |             ^^^^^^^^^^^^^^
 
 error: this expression always evaluates to true
-  --> tests/ui/const_is_empty.rs:202:9
+  --> tests/ui/const_is_empty.rs:198:17
+   |
+LL |         assert!(EMPTY_STR.is_empty());
+   |                 ^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:203:9
    |
 LL |         EMPTY_STR.is_empty();
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 27 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/tests/ui/incompatible_msrv.rs b/tests/ui/incompatible_msrv.rs
index f7f21e1850d..882f909e30c 100644
--- a/tests/ui/incompatible_msrv.rs
+++ b/tests/ui/incompatible_msrv.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::incompatible_msrv)]
 #![feature(custom_inner_attributes)]
-#![allow(stable_features)]
+#![allow(stable_features, clippy::diverging_sub_expression)]
 #![feature(strict_provenance)] // For use in test
 #![clippy::msrv = "1.3.0"]