1extern crate indexmap;
2
3use indexmap::IndexMap;
4use rustc_hir::def_id::DefId;
5use rustc_middle::ty::TyCtxt;
6use rustc_public::{rustc_internal, CrateDef};
7use std::sync::OnceLock;
8
9static INIT: OnceLock<Intrinsics> = OnceLock::new();
10
11struct Intrinsics {
12 map: IndexMap<Box<str>, DefId>,
14}
15
16pub fn init(tcx: TyCtxt) {
17 INIT.get_or_init(|| init_inner(tcx));
18}
19
20fn init_inner(tcx: TyCtxt) -> Intrinsics {
21 const CRATES: &[&str] = &["core", "std", "alloc"];
22
23 let mut indices: IndexMap<_, _> = (0..INTRINSICS.len()).map(|idx| (idx, false)).collect();
25
26 let mut map = IndexMap::<Box<str>, DefId>::with_capacity(INTRINSICS.len());
27 for krate in rustc_public::external_crates() {
28 if !CRATES.iter().any(|name| *name == krate.name) {
29 continue;
30 }
31
32 for fn_def in krate.fn_defs() {
33 let fn_name = fn_def.name();
34 if let Some(name) = INTRINSICS.iter().enumerate().find_map(|(idx, paths)| {
35 if paths.iter().any(|path| **path == fn_name) {
36 assert_eq!(
37 indices.insert(idx, true),
38 Some(false),
39 "DefId for {fn_name} has been found: {:?}",
40 map.get(&*fn_name)
41 );
42 Some(fn_name.as_str().into())
43 } else {
44 None
45 }
46 }) {
47 let def_id = rustc_internal::internal(tcx, fn_def.def_id());
48 if map.contains_key(&name) {
49 panic!("DefId of {fn_name} has been inserted: {def_id:?}");
50 } else {
51 map.insert(name, def_id);
52 }
53 }
54 }
55 }
56
57 map.sort_unstable_by(|a, _, b, _| a.cmp(b));
58
59 if INTRINSICS.len() != map.len() {
60 let not_found = indices
65 .iter()
66 .filter_map(|(&idx, &found)| (!found).then_some(INTRINSICS[idx]))
67 .collect::<Vec<_>>();
68 rap_warn!(
69 "Intrinsic functions is incompletely retrieved.\n\
70 {} fn ids are not found: {not_found:#?}",
71 not_found.len()
72 );
73 }
74
75 Intrinsics { map }
76}
77
78macro_rules! intrinsics {
79 ($( $id:ident : $paths:expr ,)+ ) => {
80 const INTRINSICS: &[&[&str]] = &[$( $paths ,)+];
81 $(
82 pub fn $id() -> DefId {
83 ${concat($id, _opt)} ().unwrap_or_else(||
84 panic!("Failed to retrieve the DefId of {:#?}.", $paths)
85 )
86 }
87
88 pub fn ${concat($id, _opt)} () -> Option<DefId> {
89 let map = &INIT.get().expect("Intrinsics DefIds haven't been initialized.").map;
90 for path in $paths {
91 match map.get(*path) {
92 Some(id) => return Some(*id),
93 None => ()
94 }
95 }
96 None
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 ],
109 call_mut: &[
110 "std::ops::FnMut::call_mut",
111 "core::ops::FnMut::call_mut"
112 ],
113 clone: &[
114 "std::clone::Clone::clone",
115 "core::clone::Clone::clone"
116 ],
117 copy_from: &[
118 "std::ptr::mut_ptr::<impl *mut T>::copy_from",
119 "core::ptr::mut_ptr::<impl *mut T>::copy_from"
120 ],
121 copy_from_nonoverlapping: &[
122 "std::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping",
123 "core::ptr::mut_ptr::<impl *mut T>::copy_from_nonoverlapping"
124 ],
125 copy_to: &[
126 "std::ptr::const_ptr::<impl *const T>::copy_to",
127 "core::ptr::const_ptr::<impl *const T>::copy_to",
128 ],
129 copy_to_nonoverlapping: &[
130 "std::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping",
131 "core::ptr::const_ptr::<impl *const T>::copy_to_nonoverlapping"
132 ],
133 dealloc: &[
134 "std::alloc::dealloc",
135 "alloc::alloc::dealloc"
136 ],
137 drop: &[
138 "std::mem::drop",
139 "core::mem::drop",
140 ],
141 drop_in_place: &[
142 "std::ptr::drop_in_place",
143 "core::ptr::drop_in_place",
144 ],
145 manually_drop: &[
146 "std::mem::ManuallyDrop::<T>::drop",
147 "core::mem::ManuallyDrop::<T>::drop"
148 ],
149}
150
151pub fn to_internal<T: CrateDef>(val: &T, tcx: TyCtxt) -> DefId {
153 rustc_internal::internal(tcx, val.def_id())
154}