Merge pull request #18475 from Veykril/push-zkvkpxttozup

Support new #[rustc_intrinsic] attribute and fallback bodies
This commit is contained in:
Lukas Wirth 2024-11-04 12:48:00 +00:00 committed by GitHub
commit 1d65cd466f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 143 additions and 174 deletions

View file

@ -13,7 +13,6 @@ use syntax::{ast, Parse};
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
attr::Attrs,
db::DefDatabase, db::DefDatabase,
expander::{Expander, Mark}, expander::{Expander, Mark},
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
@ -37,8 +36,6 @@ pub struct FunctionData {
pub name: Name, pub name: Name,
pub params: Box<[TypeRefId]>, pub params: Box<[TypeRefId]>,
pub ret_type: TypeRefId, pub ret_type: TypeRefId,
// FIXME: why are these stored here? They should be accessed via the query
pub attrs: Attrs,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub abi: Option<Symbol>, pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>, pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
@ -115,7 +112,6 @@ impl FunctionData {
.filter_map(|(_, param)| param.type_ref) .filter_map(|(_, param)| param.type_ref)
.collect(), .collect(),
ret_type: func.ret_type, ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility, visibility,
abi: func.abi.clone(), abi: func.abi.clone(),
legacy_const_generics_indices, legacy_const_generics_indices,

View file

@ -632,6 +632,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
), ),
rustc_attr!(
rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
),
rustc_attr!(
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
),
rustc_attr!( rustc_attr!(
rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing,
"the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024",

View file

@ -4,9 +4,8 @@ use super::*;
fn size_of() { fn size_of() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of<T>() -> usize; pub fn size_of<T>() -> usize;
}
const GOAL: usize = size_of::<i32>(); const GOAL: usize = size_of::<i32>();
"#, "#,
@ -19,9 +18,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X(i32, u8); struct X(i32, u8);
@ -32,9 +30,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let it: &[i32] = &[1, 2, 3]; let it: &[i32] = &[1, 2, 3];
@ -48,9 +45,8 @@ fn size_of_val() {
//- minicore: coerce_unsized, transmute //- minicore: coerce_unsized, transmute
use core::mem::transmute; use core::mem::transmute;
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X { struct X {
x: i64, x: i64,
@ -70,9 +66,8 @@ fn size_of_val() {
//- minicore: coerce_unsized, transmute //- minicore: coerce_unsized, transmute
use core::mem::transmute; use core::mem::transmute;
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X { struct X {
x: i32, x: i32,
@ -90,9 +85,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let x: &i16 = &5; let x: &i16 = &5;
@ -106,9 +100,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
size_of_val("salam") size_of_val("salam")
@ -123,9 +116,8 @@ fn min_align_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X(i32, u8); struct X(i32, u8);
@ -136,9 +128,8 @@ fn min_align_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let x: &[i32] = &[1, 2, 3]; let x: &[i32] = &[1, 2, 3];
@ -153,9 +144,8 @@ fn min_align_of_val() {
fn type_name() { fn type_name() {
check_str( check_str(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str; pub fn type_name<T: ?Sized>() -> &'static str;
}
const GOAL: &str = type_name::<i32>(); const GOAL: &str = type_name::<i32>();
"#, "#,
@ -163,9 +153,8 @@ fn type_name() {
); );
check_str( check_str(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str; pub fn type_name<T: ?Sized>() -> &'static str;
}
mod mod1 { mod mod1 {
pub mod mod2 { pub mod mod2 {
@ -183,9 +172,8 @@ fn type_name() {
fn transmute() { fn transmute() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn transmute<T, U>(e: T) -> U; pub fn transmute<T, U>(e: T) -> U;
}
const GOAL: i32 = transmute((1i16, 1i16)); const GOAL: i32 = transmute((1i16, 1i16));
"#, "#,
@ -197,10 +185,10 @@ fn transmute() {
fn read_via_copy() { fn read_via_copy() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn read_via_copy<T>(e: *const T) -> T; pub fn read_via_copy<T>(e: *const T) -> T;
pub fn volatile_load<T>(e: *const T) -> T; #[rustc_intrinsic]
} pub fn volatile_load<T>(e: *const T) -> T;
const GOAL: i32 = { const GOAL: i32 = {
let x = 2; let x = 2;
@ -399,9 +387,14 @@ fn discriminant_value() {
fn likely() { fn likely() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn likely(b: bool) -> bool; pub const fn likely(b: bool) -> bool {
pub fn unlikely(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); const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false);
@ -704,9 +697,8 @@ fn rotate() {
); );
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn rotate_right<T: Copy>(x: T, y: T) -> T; pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i32 = rotate_right(10006016, 1020315); const GOAL: i32 = rotate_right(10006016, 1020315);
"#, "#,
@ -721,9 +713,8 @@ fn simd() {
pub struct i8x16( pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
); );
extern "platform-intrinsic" { #[rustc_intrinsic]
pub fn simd_bitmask<T, U>(x: T) -> U; pub fn simd_bitmask<T, U>(x: T) -> U;
}
const GOAL: u16 = simd_bitmask(i8x16( const GOAL: u16 = simd_bitmask(i8x16(
0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0 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( pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
); );
extern "platform-intrinsic" { #[rustc_intrinsic]
pub fn simd_lt<T, U>(x: T, y: T) -> U; 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_bitmask<T, U>(x: T) -> U;
const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>( const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>(
i8x16( i8x16(
-105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

View file

@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> {
// Don't run the lint on extern "[not Rust]" fn items with the // Don't run the lint on extern "[not Rust]" fn items with the
// #[no_mangle] attribute. // #[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) { if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) {
cov_mark::hit!(extern_func_no_mangle_ignored); cov_mark::hit!(extern_func_no_mangle_ignored);
} else { } else {

View file

@ -9,7 +9,7 @@ use hir_def::{
resolver::HasResolver, resolver::HasResolver,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym; use intern::{sym, Symbol};
use crate::{ use crate::{
error_lifetime, error_lifetime,
@ -54,49 +54,32 @@ impl Evaluator<'_> {
} }
let function_data = self.db.function_data(def); let function_data = self.db.function_data(def);
let is_intrinsic = match &function_data.abi { let attrs = self.db.attrs(def.into());
Some(abi) => *abi == sym::rust_dash_intrinsic, let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
None => match def.lookup(self.db.upcast()).container { // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
hir_def::ItemContainerId::ExternBlockId(block) => { || (match &function_data.abi {
let id = block.lookup(self.db.upcast()).id; Some(abi) => *abi == sym::rust_dash_intrinsic,
id.item_tree(self.db.upcast())[id.value].abi.as_ref() None => match def.lookup(self.db.upcast()).container {
== Some(&sym::rust_dash_intrinsic) hir_def::ItemContainerId::ExternBlockId(block) => {
} let id = block.lookup(self.db.upcast()).id;
_ => false, id.item_tree(self.db.upcast())[id.value].abi.as_ref()
}, == Some(&sym::rust_dash_intrinsic)
}; }
_ => false,
},
});
if is_intrinsic { if is_intrinsic {
self.exec_intrinsic( return self.exec_intrinsic(
function_data.name.as_str(), function_data.name.as_str(),
args, args,
generic_args, generic_args,
destination, destination,
locals, locals,
span, span,
)?; !function_data.has_body()
return Ok(true); || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(),
} );
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);
} }
let is_extern_c = match def.lookup(self.db.upcast()).container { let is_extern_c = match def.lookup(self.db.upcast()).container {
hir_def::ItemContainerId::ExternBlockId(block) => { hir_def::ItemContainerId::ExternBlockId(block) => {
@ -106,27 +89,25 @@ impl Evaluator<'_> {
_ => false, _ => false,
}; };
if is_extern_c { if is_extern_c {
self.exec_extern_c( return self
function_data.name.as_str(), .exec_extern_c(
args, function_data.name.as_str(),
generic_args, args,
destination, generic_args,
locals, destination,
span, locals,
)?; span,
return Ok(true); )
.map(|()| true);
} }
let alloc_fn = function_data
.attrs let alloc_fn =
.iter() attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| {
.filter_map(|it| it.path().as_ident())
.map(|it| it.as_str())
.find(|it| {
[ [
"rustc_allocator", &sym::rustc_allocator,
"rustc_deallocator", &sym::rustc_deallocator,
"rustc_reallocator", &sym::rustc_reallocator,
"rustc_allocator_zeroed", &sym::rustc_allocator_zeroed,
] ]
.contains(it) .contains(it)
}); });
@ -270,12 +251,12 @@ impl Evaluator<'_> {
fn exec_alloc_fn( fn exec_alloc_fn(
&mut self, &mut self,
alloc_fn: &str, alloc_fn: &Symbol,
args: &[IntervalAndTy], args: &[IntervalAndTy],
destination: Interval, destination: Interval,
) -> Result<()> { ) -> Result<()> {
match alloc_fn { 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 { let [size, align] = args else {
return Err(MirEvalError::InternalError( return Err(MirEvalError::InternalError(
"rustc_allocator args are not provided".into(), "rustc_allocator args are not provided".into(),
@ -286,8 +267,8 @@ impl Evaluator<'_> {
let result = self.heap_allocate(size, align)?; let result = self.heap_allocate(size, align)?;
destination.write_from_bytes(self, &result.to_bytes())?; destination.write_from_bytes(self, &result.to_bytes())?;
} }
"rustc_deallocator" => { /* no-op for now */ } _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ }
"rustc_reallocator" => { _ if *alloc_fn == sym::rustc_reallocator => {
let [ptr, old_size, align, new_size] = args else { let [ptr, old_size, align, new_size] = args else {
return Err(MirEvalError::InternalError( return Err(MirEvalError::InternalError(
"rustc_allocator args are not provided".into(), "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( fn exec_intrinsic(
&mut self, &mut self,
name: &str, name: &str,
@ -626,9 +592,17 @@ impl Evaluator<'_> {
destination: Interval, destination: Interval,
locals: &Locals, locals: &Locals,
span: MirSpan, span: MirSpan,
) -> Result<()> { needs_override: bool,
) -> Result<bool> {
if let Some(name) = name.strip_prefix("atomic_") { 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. // FIXME(#17451): Add `f16` and `f128` intrinsics.
if let Some(name) = name.strip_suffix("f64") { if let Some(name) = name.strip_suffix("f64") {
@ -701,7 +675,7 @@ impl Evaluator<'_> {
} }
_ => not_supported!("unknown f64 intrinsic {name}"), _ => 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") { if let Some(name) = name.strip_suffix("f32") {
let result = match name { let result = match name {
@ -773,7 +747,7 @@ impl Evaluator<'_> {
} }
_ => not_supported!("unknown f32 intrinsic {name}"), _ => 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 { match name {
"size_of" => { "size_of" => {
@ -1146,12 +1120,6 @@ impl Evaluator<'_> {
}; };
destination.write_from_interval(self, arg.interval) 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" => { "ctpop" => {
let [arg] = args else { let [arg] = args else {
return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); return Err(MirEvalError::InternalError("ctpop arg is not provided".into()));
@ -1296,7 +1264,7 @@ impl Evaluator<'_> {
None, None,
span, span,
)?; )?;
return Ok(()); return Ok(true);
} }
} }
not_supported!("FnOnce was not available for executing const_eval_select"); 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); self.write_memory_using_ref(dst, size)?.fill(val);
Ok(()) 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( fn size_align_of_unsized(

View file

@ -259,25 +259,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
return true; 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()); let loc = func.lookup(db.upcast());
match loc.container { match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => { hir_def::ItemContainerId::ExternBlockId(block) => {
// Function in an `extern` block are always unsafe to call, except when if is_intrinsic || {
// it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a let id = block.lookup(db.upcast()).id;
// few exceptions. id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic)
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 {
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute // 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 { } 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() !data.is_safe()
} }
} }
_ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(),
_ => false, _ => false,
} }
} }

View file

@ -2246,35 +2246,33 @@ impl Function {
/// Does this function have `#[test]` attribute? /// Does this function have `#[test]` attribute?
pub fn is_test(self, db: &dyn HirDatabase) -> bool { pub fn is_test(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_test() db.attrs(self.id.into()).is_test()
} }
/// is this a `fn main` or a function with an `export_name` of `main`? /// is this a `fn main` or a function with an `export_name` of `main`?
pub fn is_main(self, db: &dyn HirDatabase) -> bool { pub fn is_main(self, db: &dyn HirDatabase) -> bool {
let data = db.function_data(self.id); db.attrs(self.id.into()).export_name() == Some(&sym::main)
data.attrs.export_name() == Some(&sym::main) || self.module(db).is_crate_root() && db.function_data(self.id).name == sym::main
|| self.module(db).is_crate_root() && data.name == sym::main
} }
/// Is this a function with an `export_name` of `main`? /// Is this a function with an `export_name` of `main`?
pub fn exported_main(self, db: &dyn HirDatabase) -> bool { pub fn exported_main(self, db: &dyn HirDatabase) -> bool {
let data = db.function_data(self.id); db.attrs(self.id.into()).export_name() == Some(&sym::main)
data.attrs.export_name() == Some(&sym::main)
} }
/// Does this function have the ignore attribute? /// Does this function have the ignore attribute?
pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_ignore() db.attrs(self.id.into()).is_ignore()
} }
/// Does this function have `#[bench]` attribute? /// Does this function have `#[bench]` attribute?
pub fn is_bench(self, db: &dyn HirDatabase) -> bool { pub fn is_bench(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_bench() db.attrs(self.id.into()).is_bench()
} }
/// Is this function marked as unstable with `#[feature]` attribute? /// Is this function marked as unstable with `#[feature]` attribute?
pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_unstable() db.attrs(self.id.into()).is_unstable()
} }
pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool { pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
@ -2289,8 +2287,7 @@ impl Function {
} }
pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> { pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
let function_data = db.function_data(self.id); let attrs = db.attrs(self.id.into());
let attrs = &function_data.attrs;
// FIXME: Store this in FunctionData flags? // FIXME: Store this in FunctionData flags?
if !(attrs.is_proc_macro() if !(attrs.is_proc_macro()
|| attrs.is_proc_macro_attribute() || attrs.is_proc_macro_attribute()

View file

@ -392,18 +392,22 @@ define_symbols! {
rust_2024, rust_2024,
rust_analyzer, rust_analyzer,
Rust, Rust,
rustc_allocator_zeroed,
rustc_allocator,
rustc_allow_incoherent_impl, rustc_allow_incoherent_impl,
rustc_builtin_macro, rustc_builtin_macro,
rustc_coherence_is_core, rustc_coherence_is_core,
rustc_const_panic_str, rustc_const_panic_str,
rustc_deallocator,
rustc_deprecated_safe_2024, rustc_deprecated_safe_2024,
rustc_has_incoherent_inherent_impls, rustc_has_incoherent_inherent_impls,
rustc_intrinsic,
rustc_intrinsic_must_be_overridden, rustc_intrinsic_must_be_overridden,
rustc_intrinsic,
rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start, rustc_layout_scalar_valid_range_start,
rustc_legacy_const_generics, rustc_legacy_const_generics,
rustc_macro_transparency, rustc_macro_transparency,
rustc_reallocator,
rustc_reservation_impl, rustc_reservation_impl,
rustc_safe_intrinsic, rustc_safe_intrinsic,
rustc_skip_array_during_method_dispatch, rustc_skip_array_during_method_dispatch,

View file

@ -370,15 +370,13 @@ pub mod mem {
// endregion:drop // endregion:drop
// region:transmute // region:transmute
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn transmute<Src, Dst>(src: Src) -> Dst; pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
// endregion:transmute // endregion:transmute
// region:size_of // region:size_of
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of<T>() -> usize; pub fn size_of<T>() -> usize;
}
// endregion:size_of // endregion:size_of
// region:discriminant // region:discriminant