Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clippy_lints/src/multiple_unsafe_ops_per_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> {
type NestedFilter = nested_filter::OnlyBodies;

fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if expr.span.in_external_macro(self.tcx.sess.source_map()) {
// Check the content of the expanded code to still catch the unsafe
// operation passed as macro arguments.
return walk_expr(self, expr);
}

match expr.kind {
// The `await` itself will desugar to two unsafe calls, but we should ignore those.
// Instead, check the expression that is `await`ed
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/multiple_unsafe_ops_per_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,38 @@ fn check_closures() {
}
}

fn issue16116() {
unsafe fn foo() -> u32 {
0
}

unsafe {
// Do not lint even though `format!` expansion
// contains unsafe calls.
let _ = format!("{}", foo());
}

unsafe {
//~^ multiple_unsafe_ops_per_block
let _ = format!("{}", foo());
let _ = format!("{}", foo());
}

unsafe {
// Do not lint: only one `assert!()` argument is unsafe
assert!(foo() == 0, "{}", 1 + 2);
}

unsafe {
//~^ multiple_unsafe_ops_per_block
assert!(foo() == 0, "{}", 1 + 2);
assert!(foo() == 0, "{}", 1 + 2);
}

unsafe {
//~^ multiple_unsafe_ops_per_block
assert!(foo() == 0, "{}", foo());
}
}

fn main() {}
64 changes: 63 additions & 1 deletion tests/ui/multiple_unsafe_ops_per_block.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -359,5 +359,67 @@ note: unsafe function call occurs here
LL | apply(|| f(0));
| ^^^^

error: aborting due to 16 previous errors
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:326:5
|
LL | / unsafe {
LL | |
LL | | let _ = format!("{}", foo());
LL | | let _ = format!("{}", foo());
LL | | }
| |_____^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:328:31
|
LL | let _ = format!("{}", foo());
| ^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:329:31
|
LL | let _ = format!("{}", foo());
| ^^^^^

error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:337:5
|
LL | / unsafe {
LL | |
LL | | assert!(foo() == 0, "{}", 1 + 2);
LL | | assert!(foo() == 0, "{}", 1 + 2);
LL | | }
| |_____^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:339:17
|
LL | assert!(foo() == 0, "{}", 1 + 2);
| ^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:340:17
|
LL | assert!(foo() == 0, "{}", 1 + 2);
| ^^^^^

error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:343:5
|
LL | / unsafe {
LL | |
LL | | assert!(foo() == 0, "{}", foo());
LL | | }
| |_____^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:345:17
|
LL | assert!(foo() == 0, "{}", foo());
| ^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:345:35
|
LL | assert!(foo() == 0, "{}", foo());
| ^^^^^

error: aborting due to 19 previous errors

Loading