diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 3f54cdd20cee..309e208a9aa8 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -5,6 +5,7 @@ use hir_def::{ body::Body, hir::{Expr, ExprId, UnaryOp}, resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + type_ref::Rawness, DefWithBodyId, }; @@ -87,12 +88,20 @@ fn walk_unsafe( let g = resolver.update_to_inner_scope(db.upcast(), def, current); let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - if db.static_data(id).mutable { + let static_data = db.static_data(id); + if static_data.mutable || static_data.is_extern { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); } } resolver.reset_to_guard(g); } + Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { + if let Expr::Path(_) = body.exprs[*expr] { + // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, + // see https://github.com/rust-lang/rust/pull/125834. + return; + } + } Expr::MethodCall { .. } => { if infer .method_resolution(current) diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index af8ac6005d7a..7e70a27f789b 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -163,6 +163,56 @@ fn main() { ); } + #[test] + fn missing_unsafe_diagnostic_with_extern_static() { + check_diagnostics( + r#" +//- minicore: copy + +extern "C" { + static EXTERN: i32; + static mut EXTERN_MUT: i32; +} + +fn main() { + let _x = EXTERN; + //^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + let _x = EXTERN_MUT; + //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + unsafe { + let _x = EXTERN; + let _x = EXTERN_MUT; + } +} +"#, + ); + } + + #[test] + fn no_unsafe_diagnostic_with_addr_of_static() { + check_diagnostics( + r#" +//- minicore: copy, addr_of + +use core::ptr::{addr_of, addr_of_mut}; + +extern "C" { + static EXTERN: i32; + static mut EXTERN_MUT: i32; +} +static mut STATIC_MUT: i32 = 0; + +fn main() { + let _x = addr_of!(EXTERN); + let _x = addr_of!(EXTERN_MUT); + let _x = addr_of!(STATIC_MUT); + let _x = addr_of_mut!(EXTERN_MUT); + let _x = addr_of_mut!(STATIC_MUT); +} +"#, + ); + } + #[test] fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { check_diagnostics( diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index f2f83d538ccb..d7ae6c750878 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -483,8 +483,8 @@ fn main() { file_id: FileId( 1, ), - full_range: 632..867, - focus_range: 693..699, + full_range: 633..868, + focus_range: 694..700, name: "FnOnce", kind: Trait, container_name: "function", @@ -8479,8 +8479,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7801..8043, - focus_range: 7866..7872, + full_range: 7802..8044, + focus_range: 7867..7873, name: "Future", kind: Trait, container_name: "future", @@ -8493,8 +8493,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 8673..9172, - focus_range: 8750..8758, + full_range: 8674..9173, + focus_range: 8751..8759, name: "Iterator", kind: Trait, container_name: "iterator", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 7e1518c25c71..4b7e23388c7e 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -65,6 +65,7 @@ //! todo: panic //! unimplemented: panic //! column: +//! addr_of: #![rustc_coherence_is_core] @@ -421,6 +422,17 @@ pub mod ptr { } // endregion:coerce_unsized // endregion:non_null + + // region:addr_of + #[rustc_macro_transparency = "semitransparent"] + pub macro addr_of($place:expr) { + &raw const $place + } + #[rustc_macro_transparency = "semitransparent"] + pub macro addr_of_mut($place:expr) { + &raw mut $place + } + // endregion:addr_of } pub mod ops {