about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs7
-rw-r--r--tests/ui/editions/unsafe-attr-edition-span.e2024.stderr24
-rw-r--r--tests/ui/editions/unsafe-attr-edition-span.rs27
3 files changed, 57 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 378cbb84637..555ab3cdb2b 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -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 {
diff --git a/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr
new file mode 100644
index 00000000000..28871a1cce4
--- /dev/null
+++ b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr
@@ -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
+
diff --git a/tests/ui/editions/unsafe-attr-edition-span.rs b/tests/ui/editions/unsafe-attr-edition-span.rs
new file mode 100644
index 00000000000..bc44b34063c
--- /dev/null
+++ b/tests/ui/editions/unsafe-attr-edition-span.rs
@@ -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;
+}