Consider labels of inline asm as conditionally executed

Since an `asm!()` statement is mostly unknown, as we do not know what it
does, consider all labels' `break` as being conditionally executed only.
This commit is contained in:
Samuel Tardieu 2025-09-14 09:02:15 +02:00
parent 25cbcb4331
commit a5b3c445da
No known key found for this signature in database
GPG key ID: BDDC3208C6FEAFA8
3 changed files with 94 additions and 43 deletions

View file

@ -7,7 +7,7 @@ use clippy_utils::source::snippet;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use rustc_errors::Applicability;
use rustc_hir::{
Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr,
Block, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr,
};
use rustc_lint::LateContext;
use rustc_span::{BytePos, Span, sym};
@ -75,12 +75,19 @@ pub(super) fn check<'tcx>(
fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
for_each_expr_without_closures(block, |e| match e.kind {
ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()),
ExprKind::InlineAsm(asm) if contains_label(asm) => ControlFlow::Break(()),
ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
_ => ControlFlow::Continue(Descend::Yes),
})
.is_some()
}
fn contains_label(asm: &InlineAsm<'_>) -> bool {
asm.operands
.iter()
.any(|(op, _span)| matches!(op, InlineAsmOperand::Label { .. }))
}
/// The `never_loop` analysis keeps track of three things:
///
/// * Has any (reachable) code path hit a `continue` of the main loop?
@ -378,7 +385,15 @@ fn never_loop_expr<'tcx>(
InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => {
NeverLoopResult::Normal
},
InlineAsmOperand::Label { block } => never_loop_block(cx, block, local_labels, main_loop_id),
InlineAsmOperand::Label { block } =>
// We do not know whether the label will be executed or not, so `Diverging` must be
// downgraded to `Normal`.
{
match never_loop_block(cx, block, local_labels, main_loop_id) {
NeverLoopResult::Diverging { .. } => NeverLoopResult::Normal,
result => result,
}
},
})),
ExprKind::OffsetOf(_, _)
| ExprKind::Yield(_, _)

View file

@ -1,12 +1,9 @@
#![feature(try_blocks)]
#![allow(
clippy::eq_op,
clippy::single_match,
unused_assignments,
unused_variables,
clippy::while_immutable_condition
)]
#![expect(clippy::eq_op, clippy::single_match, clippy::while_immutable_condition)]
//@no-rustfix
use std::arch::asm;
fn test1() {
let mut x = 0;
loop {
@ -522,3 +519,30 @@ fn issue15350() {
}
}
}
fn issue15673() {
loop {
unsafe {
// No lint since we don't analyze the inside of the asm
asm! {
"/* {} */",
label {
break;
}
}
}
}
//~v never_loop
loop {
unsafe {
asm! {
"/* {} */",
label {
break;
}
}
}
return;
}
}

View file

@ -1,5 +1,5 @@
error: this loop never actually loops
--> tests/ui/never_loop.rs:12:5
--> tests/ui/never_loop.rs:9:5
|
LL | / loop {
... |
@ -10,7 +10,7 @@ LL | | }
= note: `#[deny(clippy::never_loop)]` on by default
error: this loop never actually loops
--> tests/ui/never_loop.rs:36:5
--> tests/ui/never_loop.rs:33:5
|
LL | / loop {
... |
@ -19,7 +19,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:58:5
--> tests/ui/never_loop.rs:55:5
|
LL | / loop {
... |
@ -28,7 +28,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:62:9
--> tests/ui/never_loop.rs:59:9
|
LL | / while i == 0 {
... |
@ -36,7 +36,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:76:9
--> tests/ui/never_loop.rs:73:9
|
LL | / loop {
... |
@ -45,7 +45,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:114:5
--> tests/ui/never_loop.rs:111:5
|
LL | / while let Some(y) = x {
... |
@ -53,7 +53,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:123:5
--> tests/ui/never_loop.rs:120:5
|
LL | / for x in 0..10 {
... |
@ -67,7 +67,7 @@ LL + if let Some(x) = (0..10).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:173:5
--> tests/ui/never_loop.rs:170:5
|
LL | / 'outer: while a {
... |
@ -76,7 +76,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:190:9
--> tests/ui/never_loop.rs:187:9
|
LL | / while false {
LL | |
@ -86,7 +86,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:243:13
--> tests/ui/never_loop.rs:240:13
|
LL | let _ = loop {
| _____________^
@ -99,7 +99,7 @@ LL | | };
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:266:5
--> tests/ui/never_loop.rs:263:5
|
LL | / 'a: loop {
LL | |
@ -110,7 +110,7 @@ LL | | }
| |_____^
error: sub-expression diverges
--> tests/ui/never_loop.rs:271:17
--> tests/ui/never_loop.rs:268:17
|
LL | break 'a;
| ^^^^^^^^
@ -119,7 +119,7 @@ LL | break 'a;
= help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]`
error: this loop never actually loops
--> tests/ui/never_loop.rs:303:13
--> tests/ui/never_loop.rs:300:13
|
LL | / for _ in 0..20 {
LL | |
@ -135,7 +135,7 @@ LL + if let Some(_) = (0..20).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:388:13
--> tests/ui/never_loop.rs:385:13
|
LL | / 'c: loop {
LL | |
@ -145,7 +145,7 @@ LL | | }
| |_____________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:400:5
--> tests/ui/never_loop.rs:397:5
|
LL | / loop {
LL | |
@ -155,7 +155,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:405:5
--> tests/ui/never_loop.rs:402:5
|
LL | / loop {
LL | |
@ -165,7 +165,7 @@ LL | | }
| |_____^
error: this loop never actually loops
--> tests/ui/never_loop.rs:426:5
--> tests/ui/never_loop.rs:423:5
|
LL | / for v in 0..10 {
LL | |
@ -183,7 +183,7 @@ LL ~
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:434:5
--> tests/ui/never_loop.rs:431:5
|
LL | / 'outer: for v in 0..10 {
LL | |
@ -194,7 +194,7 @@ LL | | }
| |_____^
|
help: this code is unreachable. Consider moving the reachable parts out
--> tests/ui/never_loop.rs:436:9
--> tests/ui/never_loop.rs:433:9
|
LL | / loop {
LL | |
@ -202,7 +202,7 @@ LL | | break 'outer;
LL | | }
| |_________^
help: this code is unreachable. Consider moving the reachable parts out
--> tests/ui/never_loop.rs:440:9
--> tests/ui/never_loop.rs:437:9
|
LL | return;
| ^^^^^^^
@ -213,7 +213,7 @@ LL + if let Some(v) = (0..10).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:436:9
--> tests/ui/never_loop.rs:433:9
|
LL | / loop {
LL | |
@ -222,7 +222,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:443:5
--> tests/ui/never_loop.rs:440:5
|
LL | / for v in 0..10 {
LL | |
@ -239,7 +239,7 @@ LL + if let Some(v) = (0..10).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:445:9
--> tests/ui/never_loop.rs:442:9
|
LL | / 'inner: loop {
LL | |
@ -248,7 +248,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:471:5
--> tests/ui/never_loop.rs:468:5
|
LL | / 'a: for _ in 0..1 {
LL | |
@ -264,7 +264,7 @@ LL ~
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:477:5
--> tests/ui/never_loop.rs:474:5
|
LL | / 'a: for i in 0..1 {
LL | |
@ -288,7 +288,7 @@ LL ~
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:492:5
--> tests/ui/never_loop.rs:489:5
|
LL | / for v in 0..10 {
LL | |
@ -311,7 +311,7 @@ LL ~
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:503:5
--> tests/ui/never_loop.rs:500:5
|
LL | / 'bar: for _ in 0..100 {
LL | |
@ -321,7 +321,7 @@ LL | | }
| |_____^
|
help: this code is unreachable. Consider moving the reachable parts out
--> tests/ui/never_loop.rs:505:9
--> tests/ui/never_loop.rs:502:9
|
LL | / loop {
LL | |
@ -336,7 +336,7 @@ LL + if let Some(_) = (0..100).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:505:9
--> tests/ui/never_loop.rs:502:9
|
LL | / loop {
LL | |
@ -346,7 +346,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:512:5
--> tests/ui/never_loop.rs:509:5
|
LL | / 'foo: for _ in 0..100 {
LL | |
@ -356,7 +356,7 @@ LL | | }
| |_____^
|
help: this code is unreachable. Consider moving the reachable parts out
--> tests/ui/never_loop.rs:514:9
--> tests/ui/never_loop.rs:511:9
|
LL | / loop {
LL | |
@ -372,7 +372,7 @@ LL + if let Some(_) = (0..100).next() {
|
error: this loop never actually loops
--> tests/ui/never_loop.rs:514:9
--> tests/ui/never_loop.rs:511:9
|
LL | / loop {
LL | |
@ -383,7 +383,7 @@ LL | | }
| |_________^
error: this loop never actually loops
--> tests/ui/never_loop.rs:517:13
--> tests/ui/never_loop.rs:514:13
|
LL | / loop {
LL | |
@ -392,5 +392,17 @@ LL | | break 'foo;
LL | | }
| |_____________^
error: aborting due to 29 previous errors
error: this loop never actually loops
--> tests/ui/never_loop.rs:537:5
|
LL | / loop {
LL | | unsafe {
LL | | asm! {
LL | | "/* {} */",
... |
LL | | return;
LL | | }
| |_____^
error: aborting due to 30 previous errors