Skip to content

Commit e429bde

Browse files
authored
Manually fulfill lint expectations for all unsafe blocks with metavars (rust-lang#14501)
Fixes rust-lang#14488 Context: the `macro_metavars_in_unsafe` lint looks for unsafe blocks with a macro span that then contain expressions with a root context span (which means that it is a macro with an unsafe block expanding a metavariable inside). In order to avoid emitting a warning for every single macro invocation, it will deduplicate the unsafe blocks by the span in the macro. This leads to the linked issue where because of the deduplicating and removing unsafe blocks that all belong to the same unsafe block in the macro, only one of the unsafe blocks will actually have its lint expectation fulfilled. This PR fixes that by manually fulfilling all of the unsafe blocks from all expansions before deduplicating them. changelog: [`macro_metavars_in_unsafe`]: fix unfulfilled `#[expect]` if macro is invoked multiple times
2 parents 46878e3 + ffaecd0 commit e429bde

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

clippy_lints/src/macro_metavars_in_unsafe.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use itertools::Itertools;
55
use rustc_hir::def_id::LocalDefId;
66
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
77
use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
8-
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
99
use rustc_session::impl_lint_pass;
1010
use rustc_span::{Span, SyntaxContext, sym};
1111
use std::collections::BTreeMap;
@@ -249,6 +249,15 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe {
249249
})
250250
.flatten()
251251
.copied()
252+
.inspect(|&unsafe_block| {
253+
if let Level::Expect(id) = cx.tcx.lint_level_at_node(MACRO_METAVARS_IN_UNSAFE, unsafe_block).0 {
254+
// Since we're going to deduplicate expanded unsafe blocks by its enclosing macro definition soon,
255+
// which would lead to unfulfilled `#[expect()]`s in all other unsafe blocks that are filtered out
256+
// except for the one we emit the warning at, we must manually fulfill the lint
257+
// for all unsafe blocks here.
258+
cx.fulfill_expectation(id);
259+
}
260+
})
252261
.map(|id| {
253262
// Remove the syntax context to hide "in this macro invocation" in the diagnostic.
254263
// The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything

tests/ui-toml/macro_metavars_in_unsafe/default/test.rs

+16
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,16 @@ pub mod issue13219 {
251251
}
252252
}
253253

254+
#[macro_export]
255+
macro_rules! issue14488 {
256+
($e:expr) => {
257+
#[expect(clippy::macro_metavars_in_unsafe)]
258+
unsafe {
259+
$e
260+
}
261+
};
262+
}
263+
254264
fn main() {
255265
allow_works!(1);
256266
simple!(1);
@@ -271,4 +281,10 @@ fn main() {
271281
multiple_unsafe_blocks!(1, 1, 1);
272282
unsafe_from_root_ctxt!(unsafe { 1 });
273283
nested_macros!(1, 1);
284+
285+
// These two invocations lead to two expanded unsafe blocks, each with an `#[expect]` on it.
286+
// Only of them gets a warning, which used to result in an unfulfilled expectation for the other
287+
// expanded unsafe block.
288+
issue14488!(1);
289+
issue14488!(2);
274290
}

0 commit comments

Comments
 (0)