1use indexmap::IndexMap;
2use rustc_hir::def_id::DefId;
3use rustc_middle::ty::TyCtxt;
4use rustc_public::{CrateDef, rustc_internal};
5use std::sync::OnceLock;
6
7static INIT: OnceLock<Intrinsics> = OnceLock::new();
8
9struct Intrinsics {
10 map: IndexMap<Box<str>, DefId>,
12}
13
14pub fn init(tcx: TyCtxt) {
15 INIT.get_or_init(|| init_inner(tcx));
16}
17
18fn init_inner(tcx: TyCtxt) -> Intrinsics {
19 const CRATES: &[&str] = &["core", "std", "alloc"];
20
21 let mut indices: IndexMap<_, _> = (0..INTRINSICS.len()).map(|idx| (idx, false)).collect();
23
24 let mut map = IndexMap::<Box<str>, DefId>::with_capacity(INTRINSICS.len());
25
26 for krate in std::iter::once(rustc_public::local_crate())
27 .chain(rustc_public::external_crates().into_iter())
28 .filter(|krate| CRATES.iter().any(|name| *name == krate.name))
29 {
30 for fn_def in krate.fn_defs() {
31 let fn_name: Box<str> = fn_def.name().into();
32 let fn_name_str: &str = &fn_name;
33 if let Some(name) = INTRINSICS.iter().enumerate().find_map(|(idx, paths)| {
34 if paths.iter().any(|&path| {
35 path == fn_name_str
36 || path.strip_prefix("core::").is_some_and(|s| s == fn_name_str)
37 || path.strip_prefix("std::").is_some_and(|s| s == fn_name_str)
38 || path.strip_prefix("alloc::").is_some_and(|s| s == fn_name_str)
39 }) {
40 assert_eq!(
41 indices.insert(idx, true),
42 Some(false),
43 "DefId for {fn_name} has been found: {:?}",
44 map.get(&*fn_name)
45 );
46 Some(fn_name.clone())
47 } else {
48 None
49 }
50 }) {
51 let def_id = rustc_internal::internal(tcx, fn_def.def_id());
52 if map.contains_key(&name) {
53 panic!("DefId of {fn_name} has been inserted: {def_id:?}");
54 } else {
55 map.insert(name, def_id);
56 }
57 }
58 }
59 }
60
61 map.sort_unstable_by(|a, _, b, _| a.cmp(b));
62
63 if INTRINSICS.len() != map.len() {
64 let not_found = indices
69 .iter()
70 .filter_map(|(&idx, &found)| (!found).then_some(INTRINSICS[idx]))
71 .collect::<Vec<_>>();
72 rap_warn!(
73 "Intrinsic functions is incompletely retrieved.\n\
74 {} fn ids are not found: {not_found:#?}",
75 not_found.len()
76 );
77 }
78
79 Intrinsics { map }
80}
81
82macro_rules! intrinsics {
83 ($( $id:ident : $paths:expr ,)+ ) => {
84 const INTRINSICS: &[&[&str]] = &[$( $paths ,)+];
85 $(
86 paste::paste! {
87 pub fn [<$id _opt>] () -> Option<DefId> {
88 let map = &INIT.get().expect("Intrinsics DefIds haven't been initialized.").map;
89 for path in $paths {
90 match map.get(*path) {
91 Some(id) => return Some(*id),
92 None => ()
93 }
94 }
95 None
96 }
97 }
98 )+
99 };
100}
101
102intrinsics! {
105 assume_init_drop: &[
106 "std::mem::MaybeUninit::<T>::assume_init_drop",
107 "core::mem::MaybeUninit::<T>::assume_init_drop",
108 "std::mem::maybe_uninit::MaybeUninit::<T>::assume_init_drop",
109 "core::mem::maybe_uninit::MaybeUninit::<T>::assume_init_drop"
110 ],
111 call_mut: &[
112 "std::ops::FnMut::call_mut",
113 "core::ops::FnMut::call_mut",
114 "std::ops::function::FnMut::call_mut",
115 "core::ops::function::FnMut::call_mut"
116 ],
117 clone: &[
118 "std::clone::Clone::clone",
119 "core::clone::Clone::clone"
120 ],
121 copy_from: &[
122 "std::ptr::mut_ptr::<impl *mut T>::copy_from",
123 "core::ptr::mut_ptr::<impl *mut T>::copy_from"
124 ],
125 copy_from_nonoverlapping: &[
126 "std::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping",
127 "core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping"
128 ],
129 copy_to: &[
130 "std::ptr::const_ptr::<impl *const T>::copy_to",
131 "core::ptr::const_ptr::<impl *const T>::copy_to",
132 ],
133 copy_to_nonoverlapping: &[
134 "std::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping",
135 "core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping"
136 ],
137 dealloc: &[
138 "std::alloc::dealloc",
139 "alloc::alloc::dealloc"
140 ],
141 drop: &[
142 "std::mem::drop",
143 "core::mem::drop",
144 ],
145 drop_in_place: &[
146 "std::ptr::drop_in_place",
147 "core::ptr::drop_in_place",
148 ],
149 manually_drop: &[
150 "std::mem::ManuallyDrop::<T>::drop",
151 "core::mem::ManuallyDrop::<T>::drop",
152 "std::mem::manually_drop::ManuallyDrop::<T>::drop",
153 "core::mem::manually_drop::ManuallyDrop::<T>::drop"
154 ],
155 replace: &[
156 "std::mem::replace",
157 "core::mem::replace"
158 ],
159 take: &[
160 "std::mem::take",
161 "core::mem::take"
162 ],
163 read_via_copy: &[
164 "std::intrinsics::read_via_copy",
165 "core::intrinsics::read_via_copy"
166 ],
167 write_via_copy: &[
168 "std::intrinsics::write_via_move",
169 "core::intrinsics::write_via_move"
170 ],
171}
172
173pub fn to_internal<T: CrateDef>(val: &T, tcx: TyCtxt) -> DefId {
175 rustc_internal::internal(tcx, val.def_id())
176}
177
178pub fn is_drop_fn(target: DefId) -> bool {
181 let drop_fn = [
182 drop_opt(),
183 drop_in_place_opt(),
184 manually_drop_opt(),
185 dealloc_opt(),
186 ];
187 contains(&drop_fn, target)
188}
189
190pub fn contains(v: &[Option<DefId>], target: DefId) -> bool {
192 v.contains(&Some(target))
193}