rapx/
def_id.rs

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    // The key is fn path, starting from `core::` or `std::`. The value is internal def id.
13    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    // The key is an index to INTRINSICS slice; the value means if the path is found.
24    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        // The reason to not make this an assertion is allowing compilation on
61        // missing instrinsics, e.g. no_std crates without using alloc will never
62        // have the dealloc intrinsic.
63        // cc https://github.com/Artisan-Lab/RAPx/issues/190#issuecomment-3303049000
64        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
102// for #![no_std] crates, intrinsics fn paths start from core instead of core.
103// cc https://github.com/Artisan-Lab/RAPx/issues/190
104intrinsics! {
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
151/// rustc_public DefId to internal DefId
152pub fn to_internal<T: CrateDef>(val: &T, tcx: TyCtxt) -> DefId {
153    rustc_internal::internal(tcx, val.def_id())
154}