about summary refs log tree commit diff
diff options
context:
space:
mode:
authorcarbotaniuman <41451839+carbotaniuman@users.noreply.github.com>2024-05-15 18:52:08 -0500
committercarbotaniuman <41451839+carbotaniuman@users.noreply.github.com>2024-06-06 20:26:28 -0500
commit230b58febf78bb1680b4960d32350a7430a8aab5 (patch)
tree166d5480509f2d73ef11e8be99ec0b7f1aeee73e
parent48851d9adbd358a678e8ef8102d131aaa42884fc (diff)
downloadrust-230b58febf78bb1680b4960d32350a7430a8aab5.tar.gz
rust-230b58febf78bb1680b4960d32350a7430a8aab5.zip
Error on unsafe on non-unsafe attribute
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_feature/src/lib.rs4
-rw-r--r--compiler/rustc_passes/messages.ftl4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs22
-rw-r--r--compiler/rustc_passes/src/errors.rs11
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute.rs6
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr10
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs8
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr10
9 files changed, 75 insertions, 4 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 8fa0c30173e..f901f5c8c41 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1146,6 +1146,10 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool {
     })
 }
 
+pub fn is_unsafe_attr(name: Symbol) -> bool {
+    BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe)
+}
+
 pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
     LazyLock::new(|| {
         let mut map = FxHashMap::default();
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 9cbf836ec76..9db9073e2f0 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -123,8 +123,8 @@ pub use accepted::ACCEPTED_FEATURES;
 pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
-    is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
-    GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
+    BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::REMOVED_FEATURES;
 pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d850644bb45..07c82065a80 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level =
 passes_invalid_attr_at_crate_level_item =
     the inner attribute doesn't annotate this {$kind}
 
+passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
+    .suggestion = remove the `unsafe(...)`
+    .note = extraneous unsafe is not allowed in attributes
+
 passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
 
 passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 39cb48c1af3..d826eacbd15 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,9 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::StashKey;
 use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan};
-use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{
+    is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP,
+};
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir};
@@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
+            self.check_unsafe_attr(attr);
+
             match attr.path().as_slice() {
                 [sym::diagnostic, sym::do_not_recommend] => {
                     self.check_do_not_recommend(attr.span, hir_id, target)
@@ -308,6 +312,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         true
     }
 
+
+    /// Checks if `unsafe()` is applied to an invalid attribute.
+    fn check_unsafe_attr(&self, attr: &Attribute) {
+        if !attr.is_doc_comment() {
+            let attr_item = attr.get_normal_item();
+            if let ast::Unsafe::Yes(unsafe_span) = attr_item.unsafety {
+                if !is_unsafe_attr(attr.name_or_empty()) {
+                    self.dcx().emit_err(errors::InvalidAttrUnsafe {
+                        span: unsafe_span,
+                        name: attr_item.path.clone(),
+                    });
+                }
+            }
+        }
+    }
+
     /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
     fn check_diagnostic_on_unimplemented(
         &self,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7fdd9924b51..a935f1ad7d3 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -4,7 +4,7 @@ use std::{
 };
 
 use crate::fluent_generated as fluent;
-use rustc_ast::Label;
+use rustc_ast::{ast, Label};
 use rustc_errors::{
     codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
@@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel {
     pub item: Option<ItemFollowingInnerAttr>,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_invalid_attr_unsafe)]
+#[note]
+pub struct InvalidAttrUnsafe {
+    #[primary_span]
+    pub span: Span,
+    pub name: ast::Path,
+}
+
 #[derive(Clone, Copy)]
 pub struct ItemFollowingInnerAttr {
     pub span: Span,
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
new file mode 100644
index 00000000000..67db36afd2e
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
@@ -0,0 +1,6 @@
+#![feature(unsafe_attributes)]
+
+#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
+struct Foo {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
new file mode 100644
index 00000000000..0602af34e4f
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
@@ -0,0 +1,10 @@
+error: `repr` is not an unsafe attribute
+  --> $DIR/unsafe-safe-attribute.rs:3:3
+   |
+LL | #[unsafe(repr(C))]
+   |   ^^^^^^
+   |
+   = note: extraneous unsafe is not allowed in attributes
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
new file mode 100644
index 00000000000..ff2eb61b405
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
@@ -0,0 +1,8 @@
+#![feature(unsafe_attributes)]
+
+#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
+    message = "testing",
+))]
+trait Foo {}
+
+fn main() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
new file mode 100644
index 00000000000..584dacf4d8c
--- /dev/null
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
@@ -0,0 +1,10 @@
+error: `diagnostic::on_unimplemented` is not an unsafe attribute
+  --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3
+   |
+LL | #[unsafe(diagnostic::on_unimplemented(
+   |   ^^^^^^
+   |
+   = note: extraneous unsafe is not allowed in attributes
+
+error: aborting due to 1 previous error
+