diff options
| author | Lukas Wirth <lukastw97@gmail.com> | 2024-11-03 16:29:35 +0100 |
|---|---|---|
| committer | Lukas Wirth <lukastw97@gmail.com> | 2024-11-04 13:33:55 +0100 |
| commit | 5cbfb7422b09d46734f2a4a150fb581ede92d735 (patch) | |
| tree | 22da8d780b250450153e48db6dbf3a78e18cb1f9 /src/tools/rust-analyzer/crates/hir-ty | |
| parent | 56e89bc5a4c1a37cd073d27dfc16e72d10c08b2e (diff) | |
| download | rust-5cbfb7422b09d46734f2a4a150fb581ede92d735.tar.gz rust-5cbfb7422b09d46734f2a4a150fb581ede92d735.zip | |
Support new #[rustc_intrinsic] attribute and fallback bodies
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty')
4 files changed, 113 insertions, 152 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index c5706172b20..c1ac7ae173b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -4,9 +4,8 @@ use super::*; fn size_of() { check_number( r#" - extern "rust-intrinsic" { - pub fn size_of<T>() -> usize; - } + #[rustc_intrinsic] + pub fn size_of<T>() -> usize; const GOAL: usize = size_of::<i32>(); "#, @@ -19,9 +18,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X(i32, u8); @@ -32,9 +30,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let it: &[i32] = &[1, 2, 3]; @@ -48,9 +45,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X { x: i64, @@ -70,9 +66,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X { x: i32, @@ -90,9 +85,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let x: &i16 = &5; @@ -106,9 +100,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { size_of_val("salam") @@ -123,9 +116,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; struct X(i32, u8); @@ -136,9 +128,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let x: &[i32] = &[1, 2, 3]; @@ -153,9 +144,8 @@ fn min_align_of_val() { fn type_name() { check_str( r#" - extern "rust-intrinsic" { - pub fn type_name<T: ?Sized>() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name<T: ?Sized>() -> &'static str; const GOAL: &str = type_name::<i32>(); "#, @@ -163,9 +153,8 @@ fn type_name() { ); check_str( r#" - extern "rust-intrinsic" { - pub fn type_name<T: ?Sized>() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name<T: ?Sized>() -> &'static str; mod mod1 { pub mod mod2 { @@ -183,9 +172,8 @@ fn type_name() { fn transmute() { check_number( r#" - extern "rust-intrinsic" { - pub fn transmute<T, U>(e: T) -> U; - } + #[rustc_intrinsic] + pub fn transmute<T, U>(e: T) -> U; const GOAL: i32 = transmute((1i16, 1i16)); "#, @@ -197,10 +185,10 @@ fn transmute() { fn read_via_copy() { check_number( r#" - extern "rust-intrinsic" { - pub fn read_via_copy<T>(e: *const T) -> T; - pub fn volatile_load<T>(e: *const T) -> T; - } + #[rustc_intrinsic] + pub fn read_via_copy<T>(e: *const T) -> T; + #[rustc_intrinsic] + pub fn volatile_load<T>(e: *const T) -> T; const GOAL: i32 = { let x = 2; @@ -399,9 +387,14 @@ fn discriminant_value() { fn likely() { check_number( r#" - extern "rust-intrinsic" { - pub fn likely(b: bool) -> bool; - pub fn unlikely(b: bool) -> bool; + #[rustc_intrinsic] + pub const fn likely(b: bool) -> bool { + b + } + + #[rustc_intrinsic] + pub const fn unlikely(b: bool) -> bool { + b } const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false); @@ -704,9 +697,8 @@ fn rotate() { ); check_number( r#" - extern "rust-intrinsic" { - pub fn rotate_right<T: Copy>(x: T, y: T) -> T; - } + #[rustc_intrinsic] + pub fn rotate_right<T: Copy>(x: T, y: T) -> T; const GOAL: i32 = rotate_right(10006016, 1020315); "#, @@ -721,9 +713,8 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_bitmask<T, U>(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_bitmask<T, U>(x: T) -> U; const GOAL: u16 = simd_bitmask(i8x16( 0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0 )); @@ -735,10 +726,10 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_lt<T, U>(x: T, y: T) -> U; - pub fn simd_bitmask<T, U>(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_lt<T, U>(x: T, y: T) -> U; + #[rustc_intrinsic] + pub fn simd_bitmask<T, U>(x: T) -> U; const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>( i8x16( -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index c9ab0acc084..4991d173b9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> { // Don't run the lint on extern "[not Rust]" fn items with the // #[no_mangle] attribute. - let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); + let no_mangle = self.db.attrs(func.into()).by_key(&sym::no_mangle).exists(); if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { cov_mark::hit!(extern_func_no_mangle_ignored); } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 0cdad74a4f6..0a78f4a5b24 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -9,7 +9,7 @@ use hir_def::{ resolver::HasResolver, }; use hir_expand::name::Name; -use intern::sym; +use intern::{sym, Symbol}; use crate::{ error_lifetime, @@ -54,49 +54,32 @@ impl Evaluator<'_> { } let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::rust_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::rust_dash_intrinsic) - } - _ => false, - }, - }; + let attrs = self.db.attrs(def.into()); + let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists() + // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used + || (match &function_data.abi { + Some(abi) => *abi == sym::rust_dash_intrinsic, + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_ref() + == Some(&sym::rust_dash_intrinsic) + } + _ => false, + }, + }); + if is_intrinsic { - self.exec_intrinsic( + return self.exec_intrinsic( function_data.name.as_str(), args, generic_args, destination, locals, span, - )?; - return Ok(true); - } - let is_platform_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::platform_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::platform_dash_intrinsic) - } - _ => false, - }, - }; - if is_platform_intrinsic { - self.exec_platform_intrinsic( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + !function_data.has_body() + || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(), + ); } let is_extern_c = match def.lookup(self.db.upcast()).container { hir_def::ItemContainerId::ExternBlockId(block) => { @@ -106,27 +89,25 @@ impl Evaluator<'_> { _ => false, }; if is_extern_c { - self.exec_extern_c( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + return self + .exec_extern_c( + function_data.name.as_str(), + args, + generic_args, + destination, + locals, + span, + ) + .map(|()| true); } - let alloc_fn = function_data - .attrs - .iter() - .filter_map(|it| it.path().as_ident()) - .map(|it| it.as_str()) - .find(|it| { + + let alloc_fn = + attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| { [ - "rustc_allocator", - "rustc_deallocator", - "rustc_reallocator", - "rustc_allocator_zeroed", + &sym::rustc_allocator, + &sym::rustc_deallocator, + &sym::rustc_reallocator, + &sym::rustc_allocator_zeroed, ] .contains(it) }); @@ -270,12 +251,12 @@ impl Evaluator<'_> { fn exec_alloc_fn( &mut self, - alloc_fn: &str, + alloc_fn: &Symbol, args: &[IntervalAndTy], destination: Interval, ) -> Result<()> { match alloc_fn { - "rustc_allocator_zeroed" | "rustc_allocator" => { + _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => { let [size, align] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -286,8 +267,8 @@ impl Evaluator<'_> { let result = self.heap_allocate(size, align)?; destination.write_from_bytes(self, &result.to_bytes())?; } - "rustc_deallocator" => { /* no-op for now */ } - "rustc_reallocator" => { + _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ } + _ if *alloc_fn == sym::rustc_reallocator => { let [ptr, old_size, align, new_size] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -603,21 +584,6 @@ impl Evaluator<'_> { } } - fn exec_platform_intrinsic( - &mut self, - name: &str, - args: &[IntervalAndTy], - generic_args: &Substitution, - destination: Interval, - locals: &Locals, - span: MirSpan, - ) -> Result<()> { - if let Some(name) = name.strip_prefix("simd_") { - return self.exec_simd_intrinsic(name, args, generic_args, destination, locals, span); - } - not_supported!("unknown platform intrinsic {name}"); - } - fn exec_intrinsic( &mut self, name: &str, @@ -626,9 +592,17 @@ impl Evaluator<'_> { destination: Interval, locals: &Locals, span: MirSpan, - ) -> Result<()> { + needs_override: bool, + ) -> Result<bool> { if let Some(name) = name.strip_prefix("atomic_") { - return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); + return self + .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); + } + if let Some(name) = name.strip_prefix("simd_") { + return self + .exec_simd_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); } // FIXME(#17451): Add `f16` and `f128` intrinsics. if let Some(name) = name.strip_suffix("f64") { @@ -701,7 +675,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f64 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } if let Some(name) = name.strip_suffix("f32") { let result = match name { @@ -773,7 +747,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f32 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } match name { "size_of" => { @@ -1146,12 +1120,6 @@ impl Evaluator<'_> { }; destination.write_from_interval(self, arg.interval) } - "likely" | "unlikely" => { - let [arg] = args else { - return Err(MirEvalError::InternalError("likely arg is not provided".into())); - }; - destination.write_from_interval(self, arg.interval) - } "ctpop" => { let [arg] = args else { return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); @@ -1296,7 +1264,7 @@ impl Evaluator<'_> { None, span, )?; - return Ok(()); + return Ok(true); } } not_supported!("FnOnce was not available for executing const_eval_select"); @@ -1349,8 +1317,10 @@ impl Evaluator<'_> { self.write_memory_using_ref(dst, size)?.fill(val); Ok(()) } - _ => not_supported!("unknown intrinsic {name}"), + _ if needs_override => not_supported!("intrinsic {name} is not implemented"), + _ => return Ok(false), } + .map(|()| true) } fn size_align_of_unsized( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 0a436ff2b41..7429ce3c73e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -259,25 +259,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { return true; } + let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists() + || data.abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let loc = func.lookup(db.upcast()); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - // Function in an `extern` block are always unsafe to call, except when - // it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a - // few exceptions. - let id = block.lookup(db.upcast()).id; - - let is_intrinsic = - id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); - - if is_intrinsic { + if is_intrinsic || { + let id = block.lookup(db.upcast()).id; + id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic) + } { // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute - !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() + !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() } else { - // Extern items without `safe` modifier are always unsafe + // Function in an `extern` block are always unsafe to call, except when + // it is marked as `safe`. !data.is_safe() } } + _ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(), _ => false, } } |
