about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
authorJieyou Xu <jieyouxu@outlook.com>2025-05-03 21:57:19 +0800
committerJieyou Xu <jieyouxu@outlook.com>2025-05-04 21:44:50 +0800
commiteb3a8e5b81db989764a2e8a7568318c6bc8aa986 (patch)
tree3a2e2f09e70be2278315ba9e7ff4848a6c7c3ab4 /compiler/rustc_parse/src
parent622ac043764d5d4ffff8de8cf86a1cc938a8a71b (diff)
downloadrust-eb3a8e5b81db989764a2e8a7568318c6bc8aa986.tar.gz
rust-eb3a8e5b81db989764a2e8a7568318c6bc8aa986.zip
Make attribute safety validation logic more obvious
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs61
1 files changed, 47 insertions, 14 deletions
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index aa29b24fe91..378cbb84637 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
         return;
     }
 
-    let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
-    let attr_item = attr.get_normal_item();
+    let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
 
-    // All non-builtin attributes are considered safe
-    let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
-    check_attribute_safety(psess, safety, attr, id);
+    let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
+    check_attribute_safety(psess, builtin_attr_safety, attr, id);
 
     // Check input tokens for built-in and key-value attributes.
-    match attr_info {
+    match builtin_attr_info {
         // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
         Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
             match parse_meta(psess, attr) {
@@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
             }
         }
         _ => {
+            let attr_item = attr.get_normal_item();
             if let AttrArgs::Eq { .. } = attr_item.args {
                 // All key-value attributes are restricted to meta-item syntax.
                 match parse_meta(psess, attr) {
@@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
 
 pub fn check_attribute_safety(
     psess: &ParseSess,
-    safety: AttributeSafety,
+    builtin_attr_safety: Option<AttributeSafety>,
     attr: &Attribute,
     id: NodeId,
 ) {
     let attr_item = attr.get_normal_item();
+    match (builtin_attr_safety, attr_item.unsafety) {
+        // - Unsafe builtin attribute
+        // - User wrote `#[unsafe(..)]`, which is permitted on any edition
+        (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
+            // OK
+        }
 
-    if let AttributeSafety::Unsafe { unsafe_since } = safety {
-        if let ast::Safety::Default = attr_item.unsafety {
+        // - Unsafe builtin attribute
+        // - User did not write `#[unsafe(..)]`
+        (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
             let path_span = attr_item.path.span;
 
             // If the `attr_item`'s span is not from a macro, then just suggest
@@ -199,11 +205,38 @@ pub fn check_attribute_safety(
                 );
             }
         }
-    } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
-        psess.dcx().emit_err(errors::InvalidAttrUnsafe {
-            span: unsafe_span,
-            name: attr_item.path.clone(),
-        });
+
+        // - Normal builtin attribute, or any non-builtin attribute
+        // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
+        //   not permitted on non-builtin attributes or normal builtin attributes
+        (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
+            psess.dcx().emit_err(errors::InvalidAttrUnsafe {
+                span: unsafe_span,
+                name: attr_item.path.clone(),
+            });
+        }
+
+        // - Normal builtin attribute
+        // - No explicit `#[unsafe(..)]` written.
+        (Some(AttributeSafety::Normal), Safety::Default) => {
+            // OK
+        }
+
+        // - Non-builtin attribute
+        // - No explicit `#[unsafe(..)]` written.
+        (None, Safety::Default) => {
+            // OK
+        }
+
+        (
+            Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
+            Safety::Safe(..),
+        ) => {
+            psess.dcx().span_delayed_bug(
+                attr_item.span(),
+                "`check_attribute_safety` does not expect `Safety::Safe` on attributes",
+            );
+        }
     }
 }