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 path_to_idx: std::collections::HashMap<&str, usize> = INTRINSICS
22 .iter()
23 .enumerate()
24 .flat_map(|(idx, paths)| paths.iter().map(move |&p| (p, idx)))
25 .collect();
26
27 let mut indices: IndexMap<_, _> = (0..INTRINSICS.len()).map(|idx| (idx, false)).collect();
28 let mut map = IndexMap::<Box<str>, DefId>::with_capacity(INTRINSICS.len());
29
30 for krate in std::iter::once(rustc_public::local_crate())
31 .chain(rustc_public::external_crates().into_iter())
32 .filter(|krate| CRATES.iter().any(|name| *name == krate.name))
33 {
34 for fn_def in krate.fn_defs() {
35 let fn_name: Box<str> = fn_def.name().into();
36 let idx = path_to_idx
37 .get(&*fn_name)
38 .copied()
39 .or_else(|| {
40 fn_name
41 .strip_prefix("core::")
42 .and_then(|s| path_to_idx.get(s).copied())
43 })
44 .or_else(|| {
45 fn_name
46 .strip_prefix("std::")
47 .and_then(|s| path_to_idx.get(s).copied())
48 })
49 .or_else(|| {
50 fn_name
51 .strip_prefix("alloc::")
52 .and_then(|s| path_to_idx.get(s).copied())
53 });
54 if let Some(idx) = idx {
55 assert_eq!(
56 indices.insert(idx, true),
57 Some(false),
58 "DefId for {fn_name} has been found: {:?}",
59 map.get(&*fn_name)
60 );
61 let def_id = rustc_internal::internal(tcx, fn_def.def_id());
62 map.insert(fn_name, def_id);
63 }
64 }
65 }
66
67 #[cfg(debug_assertions)]
68 map.sort_unstable_by(|a, _, b, _| a.cmp(b));
69
70 if INTRINSICS.len() != map.len() {
71 let not_found = indices
76 .iter()
77 .filter_map(|(&idx, &found)| (!found).then_some(INTRINSICS[idx]))
78 .collect::<Vec<_>>();
79 rap_warn!(
80 "Intrinsic functions is incompletely retrieved.\n\
81 {} fn ids are not found: {not_found:#?}",
82 not_found.len()
83 );
84 }
85
86 Intrinsics { map }
87}
88
89macro_rules! intrinsics {
90 ($( $id:ident : $paths:expr ,)+) => {
91 const INTRINSICS: &[&[&str]] = &[$( $paths ,)+];
92 $(
93 paste::paste! {
94 #[allow(dead_code)]
95 pub fn [<$id _opt>] () -> Option<DefId> {
96 let map = &INIT.get().expect("Intrinsics DefIds haven't been initialized.").map;
97 for path in $paths {
98 match map.get(*path) {
99 Some(id) => return Some(*id),
100 None => ()
101 }
102 }
103 None
104 }
105 }
106 )+
107 };
108}
109
110intrinsics! {
113 assume_init_drop: &[
114 "std::mem::MaybeUninit::<T>::assume_init_drop",
115 "core::mem::MaybeUninit::<T>::assume_init_drop",
116 "std::mem::maybe_uninit::MaybeUninit::<T>::assume_init_drop",
117 "core::mem::maybe_uninit::MaybeUninit::<T>::assume_init_drop"
118 ],
119 call_mut: &[
120 "std::ops::FnMut::call_mut",
121 "core::ops::FnMut::call_mut",
122 "std::ops::function::FnMut::call_mut",
123 "core::ops::function::FnMut::call_mut"
124 ],
125 clone: &[
126 "std::clone::Clone::clone",
127 "core::clone::Clone::clone"
128 ],
129 copy_from: &[
130 "std::ptr::mut_ptr::<impl *mut T>::copy_from",
131 "core::ptr::mut_ptr::<impl *mut T>::copy_from"
132 ],
133 copy_from_nonoverlapping: &[
134 "std::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping",
135 "core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping"
136 ],
137 copy_to: &[
138 "std::ptr::const_ptr::<impl *const T>::copy_to",
139 "core::ptr::const_ptr::<impl *const T>::copy_to",
140 ],
141 copy_to_nonoverlapping: &[
142 "std::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping",
143 "core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping"
144 ],
145 dealloc: &[
146 "std::alloc::dealloc",
147 "alloc::alloc::dealloc"
148 ],
149 drop: &[
150 "std::mem::drop",
151 "core::mem::drop",
152 ],
153 drop_in_place: &[
154 "std::ptr::drop_in_place",
155 "core::ptr::drop_in_place",
156 ],
157 manually_drop: &[
158 "std::mem::ManuallyDrop::<T>::drop",
159 "core::mem::ManuallyDrop::<T>::drop",
160 "std::mem::manually_drop::ManuallyDrop::<T>::drop",
161 "core::mem::manually_drop::ManuallyDrop::<T>::drop"
162 ],
163 replace: &[
164 "std::mem::replace",
165 "core::mem::replace"
166 ],
167 take: &[
168 "std::mem::take",
169 "core::mem::take"
170 ],
171 read_via_copy: &[
172 "std::intrinsics::read_via_copy",
173 "core::intrinsics::read_via_copy"
174 ],
175 write_via_copy: &[
176 "std::intrinsics::write_via_move",
177 "core::intrinsics::write_via_move"
178 ],
179}
180
181pub fn to_internal<T: CrateDef>(val: &T, tcx: TyCtxt) -> DefId {
183 rustc_internal::internal(tcx, val.def_id())
184}
185
186pub fn is_drop_fn(target: DefId) -> bool {
189 let drop_fn = [
190 drop_opt(),
191 drop_in_place_opt(),
192 manually_drop_opt(),
193 dealloc_opt(),
194 ];
195 contains(&drop_fn, target)
196}
197
198pub fn contains(v: &[Option<DefId>], target: DefId) -> bool {
200 v.contains(&Some(target))
201}