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 for krate in rustc_public::external_crates() {
26 if !CRATES.iter().any(|name| *name == krate.name) {
27 continue;
28 }
29
30 for fn_def in krate.fn_defs() {
31 let fn_name = fn_def.name();
32 if let Some(name) = INTRINSICS.iter().enumerate().find_map(|(idx, paths)| {
33 if paths.iter().any(|path| **path == fn_name) {
34 assert_eq!(
35 indices.insert(idx, true),
36 Some(false),
37 "DefId for {fn_name} has been found: {:?}",
38 map.get(&*fn_name)
39 );
40 Some(fn_name.as_str().into())
41 } else {
42 None
43 }
44 }) {
45 let def_id = rustc_internal::internal(tcx, fn_def.def_id());
46 if map.contains_key(&name) {
47 panic!("DefId of {fn_name} has been inserted: {def_id:?}");
48 } else {
49 map.insert(name, def_id);
50 }
51 }
52 }
53 }
54
55 map.sort_unstable_by(|a, _, b, _| a.cmp(b));
56
57 if INTRINSICS.len() != map.len() {
58 let not_found = indices
63 .iter()
64 .filter_map(|(&idx, &found)| (!found).then_some(INTRINSICS[idx]))
65 .collect::<Vec<_>>();
66 rap_warn!(
67 "Intrinsic functions is incompletely retrieved.\n\
68 {} fn ids are not found: {not_found:#?}",
69 not_found.len()
70 );
71 }
72
73 Intrinsics { map }
74}
75
76macro_rules! intrinsics {
77 ($( $id:ident : $paths:expr ,)+ ) => {
78 const INTRINSICS: &[&[&str]] = &[$( $paths ,)+];
79 $(
80 pub fn ${concat($id, _opt)} () -> Option<DefId> {
91 let map = &INIT.get().expect("Intrinsics DefIds haven't been initialized.").map;
92 for path in $paths {
93 match map.get(*path) {
94 Some(id) => return Some(*id),
95 None => ()
96 }
97 }
98 None
99 }
100 )+
101 };
102}
103
104intrinsics! {
107 assume_init_drop: &[
108 "std::mem::MaybeUninit::<T>::assume_init_drop",
109 "core::mem::MaybeUninit::<T>::assume_init_drop"
110 ],
111 call_mut: &[
112 "std::ops::FnMut::call_mut",
113 "core::ops::FnMut::call_mut"
114 ],
115 clone: &[
116 "std::clone::Clone::clone",
117 "core::clone::Clone::clone"
118 ],
119 copy_from: &[
120 "std::ptr::mut_ptr::<impl *mut T>::copy_from",
121 "core::ptr::mut_ptr::<impl *mut T>::copy_from"
122 ],
123 copy_from_nonoverlapping: &[
124 "std::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping",
125 "core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping"
126 ],
127 copy_to: &[
128 "std::ptr::const_ptr::<impl *const T>::copy_to",
129 "core::ptr::const_ptr::<impl *const T>::copy_to",
130 ],
131 copy_to_nonoverlapping: &[
132 "std::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping",
133 "core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping"
134 ],
135 dealloc: &[
136 "std::alloc::dealloc",
137 "alloc::alloc::dealloc"
138 ],
139 drop: &[
140 "std::mem::drop",
141 "core::mem::drop",
142 ],
143 drop_in_place: &[
144 "std::ptr::drop_in_place",
145 "core::ptr::drop_in_place",
146 ],
147 manually_drop: &[
148 "std::mem::ManuallyDrop::<T>::drop",
149 "core::mem::ManuallyDrop::<T>::drop"
150 ],
151 replace: &[
152 "std::mem::replace",
153 "core::mem::replace"
154 ],
155 take: &[
156 "std::mem::take",
157 "core::mem::take"
158 ],
159 read_via_copy: &[
160 "std::intrinsics::read_via_copy",
161 "core::intrinsics::read_via_copy"
162 ],
163 write_via_copy: &[
164 "std::intrinsics::write_via_move",
165 "core::intrinsics::write_via_move"
166 ],
167}
168
169pub fn to_internal<T: CrateDef>(val: &T, tcx: TyCtxt) -> DefId {
171 rustc_internal::internal(tcx, val.def_id())
172}
173
174pub fn is_drop_fn(target: DefId) -> bool {
177 let drop_fn = [
178 drop_opt(),
179 drop_in_place_opt(),
180 manually_drop_opt(),
181 dealloc_opt(),
182 ];
183 contains(&drop_fn, target)
184}
185
186pub fn contains(v: &[Option<DefId>], target: DefId) -> bool {
188 v.contains(&Some(target))
189}