about summary refs log tree commit diff
diff options
context:
space:
mode:
authorroife <roifewu@gmail.com>2024-10-20 19:48:15 +0800
committerroife <roifewu@gmail.com>2024-10-20 19:49:57 +0800
commit1b90ae48926850fbada77692c48f1fd5eee85cd8 (patch)
tree373893118d87516fc56d9f1d2405a14373783c13
parentccfc8e20633ed94ef2be849e68a4752e99dac483 (diff)
downloadrust-1b90ae48926850fbada77692c48f1fd5eee85cd8.tar.gz
rust-1b90ae48926850fbada77692c48f1fd5eee85cd8.zip
fix: do not emit unsafe diagnositcs for safe statics in extern blocks
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs35
6 files changed, 62 insertions, 3 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index f2c49813fa0..263fad51d78 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -571,6 +571,8 @@ pub struct StaticData {
     pub visibility: RawVisibility,
     pub mutable: bool,
     pub is_extern: bool,
+    pub has_safe_kw: bool,
+    pub has_unsafe_kw: bool,
 }
 
 impl StaticData {
@@ -585,6 +587,8 @@ impl StaticData {
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+            has_safe_kw: statik.has_safe_kw,
+            has_unsafe_kw: statik.has_unsafe_kw,
         })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 4bee7eeb9e5..7cb833fdce7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -823,7 +823,10 @@ pub struct Const {
 pub struct Static {
     pub name: Name,
     pub visibility: RawVisibilityId,
+    // TODO: use bitflags when we have more flags
     pub mutable: bool,
+    pub has_safe_kw: bool,
+    pub has_unsafe_kw: bool,
     pub type_ref: Interned<TypeRef>,
     pub ast_id: FileAstId<ast::Static>,
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 1d8d236d971..431a7f66f40 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -487,8 +487,11 @@ impl<'a> Ctx<'a> {
         let type_ref = self.lower_type_ref_opt(static_.ty());
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
+        let has_safe_kw = static_.safe_token().is_some();
+        let has_unsafe_kw = static_.unsafe_token().is_some();
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res = Static { name, visibility, mutable, type_ref, ast_id };
+        let res =
+            Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw };
         Some(id(self.data().statics.alloc(res)))
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 5ab4718a36b..9dce28b2e49 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -382,9 +382,23 @@ impl Printer<'_> {
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
-                let Static { name, visibility, mutable, type_ref, ast_id } = &self.tree[it];
+                let Static {
+                    name,
+                    visibility,
+                    mutable,
+                    type_ref,
+                    ast_id,
+                    has_safe_kw,
+                    has_unsafe_kw,
+                } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
+                if *has_safe_kw {
+                    w!(self, "safe ");
+                }
+                if *has_unsafe_kw {
+                    w!(self, "unsafe ");
+                }
                 w!(self, "static ");
                 if *mutable {
                     w!(self, "mut ");
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index ff45c725c73..bcfc37c8671 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -89,7 +89,7 @@ fn walk_unsafe(
             let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
             if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
                 let static_data = db.static_data(id);
-                if static_data.mutable || static_data.is_extern {
+                if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
                     unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index a53dd31286f..cc0f4bfccc9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -595,4 +595,39 @@ unsafe fn foo(p: *mut i32) {
             "#,
         )
     }
+
+    #[test]
+    fn no_unsafe_diagnostic_with_safe_kw() {
+        check_diagnostics(
+            r#"
+unsafe extern {
+    pub safe fn f();
+
+    pub unsafe fn g();
+
+    pub fn h();
+
+    pub safe static S1: i32;
+
+    pub unsafe static S2: i32;
+
+    pub static S3: i32;
+}
+
+fn main() {
+    f();
+    g();
+  //^^^💡 error: this operation is unsafe and requires an unsafe function or block
+    h();
+  //^^^💡 error: this operation is unsafe and requires an unsafe function or block
+
+    let _ = S1;
+    let _ = S2;
+          //^^💡 error: this operation is unsafe and requires an unsafe function or block
+    let _ = S3;
+          //^^💡 error: this operation is unsafe and requires an unsafe function or block
+}
+"#,
+        );
+    }
 }