about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0755.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0756.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0757.md7
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs33
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs10
5 files changed, 40 insertions, 18 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md
index 88b7f484969..b67f078c78e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0755.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0755.md
@@ -5,7 +5,7 @@ Erroneous code example:
 ```compile_fail,E0755
 #![feature(ffi_pure)]
 
-#[ffi_pure] // error!
+#[unsafe(ffi_pure)] // error!
 pub fn foo() {}
 # fn main() {}
 ```
@@ -17,7 +17,7 @@ side effects or infinite loops:
 #![feature(ffi_pure)]
 
 extern "C" {
-    #[ffi_pure] // ok!
+    #[unsafe(ffi_pure)] // ok!
     pub fn strlen(s: *const i8) -> isize;
 }
 # fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md
index ffdc421aab5..aadde038d12 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0756.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0756.md
@@ -6,7 +6,7 @@ Erroneous code example:
 ```compile_fail,E0756
 #![feature(ffi_const)]
 
-#[ffi_const] // error!
+#[unsafe(ffi_const)] // error!
 pub fn foo() {}
 # fn main() {}
 ```
@@ -18,7 +18,7 @@ which have no side effects except for their return value:
 #![feature(ffi_const)]
 
 extern "C" {
-    #[ffi_const] // ok!
+    #[unsafe(ffi_const)] // ok!
     pub fn strlen(s: *const i8) -> i32;
 }
 # fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0757.md b/compiler/rustc_error_codes/src/error_codes/E0757.md
index 41b06b23c4f..fb75b028f45 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0757.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0757.md
@@ -6,8 +6,9 @@ Erroneous code example:
 #![feature(ffi_const, ffi_pure)]
 
 extern "C" {
-    #[ffi_const]
-    #[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
+    #[unsafe(ffi_const)]
+    #[unsafe(ffi_pure)]
+    //~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
     pub fn square(num: i32) -> i32;
 }
 ```
@@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the
 #![feature(ffi_const)]
 
 extern "C" {
-    #[ffi_const]
+    #[unsafe(ffi_const)]
     pub fn square(num: i32) -> i32;
 }
 ```
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 1e33e2e9393..7615362e1f9 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -6,6 +6,7 @@ use AttributeDuplicates::*;
 use AttributeGate::*;
 use AttributeType::*;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_span::edition::Edition;
 use rustc_span::{Symbol, sym};
 
 use crate::{Features, Stability};
@@ -65,9 +66,12 @@ pub enum AttributeSafety {
     /// Normal attribute that does not need `#[unsafe(...)]`
     Normal,
 
-    /// Unsafe attribute that requires safety obligations
-    /// to be discharged
-    Unsafe,
+    /// Unsafe attribute that requires safety obligations to be discharged.
+    ///
+    /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
+    /// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
+    /// earlier editions, but become unsafe in later ones.
+    Unsafe { unsafe_since: Option<Edition> },
 }
 
 #[derive(Clone, Copy)]
@@ -187,12 +191,23 @@ macro_rules! template {
 }
 
 macro_rules! ungated {
+    (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            encode_cross_crate: $encode_cross_crate,
+            type_: $typ,
+            safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
+            template: $tpl,
+            gate: Ungated,
+            duplicates: $duplicates,
+        }
+    };
     (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
-            safety: AttributeSafety::Unsafe,
+            safety: AttributeSafety::Unsafe { unsafe_since: None },
             template: $tpl,
             gate: Ungated,
             duplicates: $duplicates,
@@ -217,7 +232,7 @@ macro_rules! gated {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
-            safety: AttributeSafety::Unsafe,
+            safety: AttributeSafety::Unsafe { unsafe_since: None },
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
@@ -228,7 +243,7 @@ macro_rules! gated {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
             type_: $typ,
-            safety: AttributeSafety::Unsafe,
+            safety: AttributeSafety::Unsafe { unsafe_since: None },
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
@@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
-    ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
+    ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+    ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+    ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
     ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
     ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 6bbd650dcdf..6a1c2af48ed 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
 pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
     let attr_item = attr.get_normal_item();
 
-    if safety == AttributeSafety::Unsafe {
+    if let AttributeSafety::Unsafe { unsafe_since } = safety {
         if let ast::Safety::Default = attr_item.unsafety {
             let path_span = attr_item.path.span;
 
@@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
             // square bracket respectively.
             let diag_span = attr_item.span();
 
-            if attr.span.at_least_rust_2024() {
+            // Attributes can be safe in earlier editions, and become unsafe in later ones.
+            let emit_error = match unsafe_since {
+                None => true,
+                Some(unsafe_since) => attr.span.edition() >= unsafe_since,
+            };
+
+            if emit_error {
                 psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
                     span: path_span,
                     suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {