use correct edition when warning for unsafe attributes

If an attribute is re-emitted by a macro, the incorrect edition was used to emit warnings for unsafe attributes

(cherry picked from commit 2c8257493d)
This commit is contained in:
Folkert de Vries 2025-06-09 21:55:17 +02:00 committed by Josh Stone
parent 490bc3e154
commit 6f3443d5db
3 changed files with 57 additions and 1 deletions

View file

@ -180,9 +180,14 @@ pub fn check_attribute_safety(
let diag_span = attr_item.span();
// Attributes can be safe in earlier editions, and become unsafe in later ones.
//
// Use the span of the attribute's name to determine the edition: the span of the
// attribute as a whole may be inaccurate if it was emitted by a macro.
//
// See https://github.com/rust-lang/rust/issues/142182.
let emit_error = match unsafe_since {
None => true,
Some(unsafe_since) => attr.span.edition() >= unsafe_since,
Some(unsafe_since) => path_span.edition() >= unsafe_since,
};
if emit_error {

View file

@ -0,0 +1,24 @@
error: unsafe attribute used without unsafe
--> $DIR/unsafe-attr-edition-span.rs:21:3
|
LL | #[no_mangle]
| ^^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(no_mangle)]
| +++++++ +
error: unsafe attribute used without unsafe
--> $DIR/unsafe-attr-edition-span.rs:25:7
|
LL | #[no_mangle]
| ^^^^^^^^^ usage of unsafe attribute
|
help: wrap the attribute in `unsafe(...)`
|
LL | #[unsafe(no_mangle)]
| +++++++ +
error: aborting due to 2 previous errors

View file

@ -0,0 +1,27 @@
// Tests that the correct span is used to determine the edition of an attribute that was safe to use
// in earlier editions, but has become `unsafe` in later editions.
//
// Determining the correct edition is non-trivial because of macro expansion. For instance,
// the `thread_local!` macro (defined in std and hence using the most recent edition) parses the
// attribute, and then re-emits it. Therefore, the span of the `#` token starting the
// `#[no_mangle]` attribute has std's edition, while the attribute name has the edition of this
// file, which may be different.
//@ revisions: e2015 e2018 e2021 e2024
//@[e2018] edition:2018
//@[e2021] edition:2021
//@[e2024] edition:2024
//
//@[e2015] check-pass
//@[e2018] check-pass
//@[e2021] check-pass
#![crate_type = "lib"]
#[no_mangle] //[e2024]~ ERROR unsafe attribute used without unsafe
static TEST_OUTSIDE: usize = 0;
thread_local! {
#[no_mangle]//[e2024]~ ERROR unsafe attribute used without unsafe
static TEST: usize = 0;
}