|
| 1 | +//! Detecting language items. |
| 2 | +//! |
| 3 | +//! Language items are items that represent concepts intrinsic to the language |
| 4 | +//! itself. Examples are: |
| 5 | +//! |
| 6 | +//! * Traits that specify "kinds"; e.g., `Sync`, `Send`. |
| 7 | +//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. |
| 8 | +//! * Functions called by the compiler itself. |
| 9 | +
|
| 10 | +pub use self::LangItem::*; |
| 11 | + |
| 12 | +use crate::Target; |
| 13 | + |
| 14 | +use rustc_data_structures::fx::FxHashMap; |
| 15 | +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| 16 | +use rustc_hir::def_id::DefId; |
| 17 | +use rustc_macros::HashStable_Generic; |
| 18 | +use rustc_span::symbol::{sym, Symbol}; |
| 19 | +use rustc_span::Span; |
| 20 | +use syntax::ast; |
| 21 | + |
| 22 | +use lazy_static::lazy_static; |
| 23 | + |
| 24 | +// The actual lang items defined come at the end of this file in one handy table. |
| 25 | +// So you probably just want to nip down to the end. |
| 26 | +macro_rules! language_item_table { |
| 27 | + ( |
| 28 | + $( $variant:ident, $name:expr, $method:ident, $target:path; )* |
| 29 | + ) => { |
| 30 | + |
| 31 | +enum_from_u32! { |
| 32 | + /// A representation of all the valid language items in Rust. |
| 33 | + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
| 34 | + pub enum LangItem { |
| 35 | + $($variant,)* |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +impl LangItem { |
| 40 | + /// Returns the `name` in `#[lang = "$name"]`. |
| 41 | + /// For example, `LangItem::EqTraitLangItem`, |
| 42 | + /// that is `#[lang = "eq"]` would result in `"eq"`. |
| 43 | + pub fn name(self) -> &'static str { |
| 44 | + match self { |
| 45 | + $( $variant => $name, )* |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +#[derive(HashStable_Generic)] |
| 51 | +pub struct LanguageItems { |
| 52 | + /// Mappings from lang items to their possibly found `DefId`s. |
| 53 | + /// The index corresponds to the order in `LangItem`. |
| 54 | + pub items: Vec<Option<DefId>>, |
| 55 | + /// Lang items that were not found during collection. |
| 56 | + pub missing: Vec<LangItem>, |
| 57 | +} |
| 58 | + |
| 59 | +impl LanguageItems { |
| 60 | + /// Construct an empty collection of lang items and no missing ones. |
| 61 | + pub fn new() -> Self { |
| 62 | + fn init_none(_: LangItem) -> Option<DefId> { None } |
| 63 | + |
| 64 | + Self { |
| 65 | + items: vec![$(init_none($variant)),*], |
| 66 | + missing: Vec::new(), |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + /// Returns the mappings to the possibly found `DefId`s for each lang item. |
| 71 | + pub fn items(&self) -> &[Option<DefId>] { |
| 72 | + &*self.items |
| 73 | + } |
| 74 | + |
| 75 | + /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. |
| 76 | + /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`, |
| 77 | + /// returns an error message as a string. |
| 78 | + pub fn require(&self, it: LangItem) -> Result<DefId, String> { |
| 79 | + self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) |
| 80 | + } |
| 81 | + |
| 82 | + $( |
| 83 | + /// Returns the corresponding `DefId` for the lang item |
| 84 | + #[doc = $name] |
| 85 | + /// if it exists. |
| 86 | + #[allow(dead_code)] |
| 87 | + pub fn $method(&self) -> Option<DefId> { |
| 88 | + self.items[$variant as usize] |
| 89 | + } |
| 90 | + )* |
| 91 | +} |
| 92 | + |
| 93 | +lazy_static! { |
| 94 | + /// A mapping from the name of the lang item to its order and the form it must be of. |
| 95 | + pub static ref ITEM_REFS: FxHashMap<&'static str, (usize, Target)> = { |
| 96 | + let mut item_refs = FxHashMap::default(); |
| 97 | + $( item_refs.insert($name, ($variant as usize, $target)); )* |
| 98 | + item_refs |
| 99 | + }; |
| 100 | +} |
| 101 | + |
| 102 | +// End of the macro |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +impl<CTX> HashStable<CTX> for LangItem { |
| 107 | + fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { |
| 108 | + ::std::hash::Hash::hash(self, hasher); |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +/// Extracts the first `lang = "$name"` out of a list of attributes. |
| 113 | +/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` |
| 114 | +/// are also extracted out when found. |
| 115 | +pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { |
| 116 | + attrs.iter().find_map(|attr| { |
| 117 | + Some(match attr { |
| 118 | + _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span), |
| 119 | + _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span), |
| 120 | + _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span), |
| 121 | + _ => return None, |
| 122 | + }) |
| 123 | + }) |
| 124 | +} |
| 125 | + |
| 126 | +language_item_table! { |
| 127 | +// Variant name, Name, Method name, Target; |
| 128 | + BoolImplItem, "bool", bool_impl, Target::Impl; |
| 129 | + CharImplItem, "char", char_impl, Target::Impl; |
| 130 | + StrImplItem, "str", str_impl, Target::Impl; |
| 131 | + SliceImplItem, "slice", slice_impl, Target::Impl; |
| 132 | + SliceU8ImplItem, "slice_u8", slice_u8_impl, Target::Impl; |
| 133 | + StrAllocImplItem, "str_alloc", str_alloc_impl, Target::Impl; |
| 134 | + SliceAllocImplItem, "slice_alloc", slice_alloc_impl, Target::Impl; |
| 135 | + SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Target::Impl; |
| 136 | + ConstPtrImplItem, "const_ptr", const_ptr_impl, Target::Impl; |
| 137 | + MutPtrImplItem, "mut_ptr", mut_ptr_impl, Target::Impl; |
| 138 | + I8ImplItem, "i8", i8_impl, Target::Impl; |
| 139 | + I16ImplItem, "i16", i16_impl, Target::Impl; |
| 140 | + I32ImplItem, "i32", i32_impl, Target::Impl; |
| 141 | + I64ImplItem, "i64", i64_impl, Target::Impl; |
| 142 | + I128ImplItem, "i128", i128_impl, Target::Impl; |
| 143 | + IsizeImplItem, "isize", isize_impl, Target::Impl; |
| 144 | + U8ImplItem, "u8", u8_impl, Target::Impl; |
| 145 | + U16ImplItem, "u16", u16_impl, Target::Impl; |
| 146 | + U32ImplItem, "u32", u32_impl, Target::Impl; |
| 147 | + U64ImplItem, "u64", u64_impl, Target::Impl; |
| 148 | + U128ImplItem, "u128", u128_impl, Target::Impl; |
| 149 | + UsizeImplItem, "usize", usize_impl, Target::Impl; |
| 150 | + F32ImplItem, "f32", f32_impl, Target::Impl; |
| 151 | + F64ImplItem, "f64", f64_impl, Target::Impl; |
| 152 | + F32RuntimeImplItem, "f32_runtime", f32_runtime_impl, Target::Impl; |
| 153 | + F64RuntimeImplItem, "f64_runtime", f64_runtime_impl, Target::Impl; |
| 154 | + |
| 155 | + SizedTraitLangItem, "sized", sized_trait, Target::Trait; |
| 156 | + UnsizeTraitLangItem, "unsize", unsize_trait, Target::Trait; |
| 157 | + // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). |
| 158 | + StructuralPeqTraitLangItem, "structural_peq", structural_peq_trait, Target::Trait; |
| 159 | + // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). |
| 160 | + StructuralTeqTraitLangItem, "structural_teq", structural_teq_trait, Target::Trait; |
| 161 | + CopyTraitLangItem, "copy", copy_trait, Target::Trait; |
| 162 | + CloneTraitLangItem, "clone", clone_trait, Target::Trait; |
| 163 | + SyncTraitLangItem, "sync", sync_trait, Target::Trait; |
| 164 | + FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait; |
| 165 | + |
| 166 | + DropTraitLangItem, "drop", drop_trait, Target::Trait; |
| 167 | + |
| 168 | + CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; |
| 169 | + DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; |
| 170 | + |
| 171 | + AddTraitLangItem, "add", add_trait, Target::Trait; |
| 172 | + SubTraitLangItem, "sub", sub_trait, Target::Trait; |
| 173 | + MulTraitLangItem, "mul", mul_trait, Target::Trait; |
| 174 | + DivTraitLangItem, "div", div_trait, Target::Trait; |
| 175 | + RemTraitLangItem, "rem", rem_trait, Target::Trait; |
| 176 | + NegTraitLangItem, "neg", neg_trait, Target::Trait; |
| 177 | + NotTraitLangItem, "not", not_trait, Target::Trait; |
| 178 | + BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait; |
| 179 | + BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait; |
| 180 | + BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait; |
| 181 | + ShlTraitLangItem, "shl", shl_trait, Target::Trait; |
| 182 | + ShrTraitLangItem, "shr", shr_trait, Target::Trait; |
| 183 | + AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait; |
| 184 | + SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait; |
| 185 | + MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait; |
| 186 | + DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait; |
| 187 | + RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait; |
| 188 | + BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait; |
| 189 | + BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait; |
| 190 | + BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait; |
| 191 | + ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait; |
| 192 | + ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; |
| 193 | + IndexTraitLangItem, "index", index_trait, Target::Trait; |
| 194 | + IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; |
| 195 | + |
| 196 | + UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; |
| 197 | + VaListTypeLangItem, "va_list", va_list, Target::Struct; |
| 198 | + |
| 199 | + DerefTraitLangItem, "deref", deref_trait, Target::Trait; |
| 200 | + DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait; |
| 201 | + ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait; |
| 202 | + |
| 203 | + FnTraitLangItem, "fn", fn_trait, Target::Trait; |
| 204 | + FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait; |
| 205 | + FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait; |
| 206 | + |
| 207 | + FutureTraitLangItem, "future_trait", future_trait, Target::Trait; |
| 208 | + GeneratorStateLangItem, "generator_state", gen_state, Target::Enum; |
| 209 | + GeneratorTraitLangItem, "generator", gen_trait, Target::Trait; |
| 210 | + UnpinTraitLangItem, "unpin", unpin_trait, Target::Trait; |
| 211 | + PinTypeLangItem, "pin", pin_type, Target::Struct; |
| 212 | + |
| 213 | + // Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`. |
| 214 | + EqTraitLangItem, "eq", eq_trait, Target::Trait; |
| 215 | + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait; |
| 216 | + |
| 217 | + // A number of panic-related lang items. The `panic` item corresponds to |
| 218 | + // divide-by-zero and various panic cases with `match`. The |
| 219 | + // `panic_bounds_check` item is for indexing arrays. |
| 220 | + // |
| 221 | + // The `begin_unwind` lang item has a predefined symbol name and is sort of |
| 222 | + // a "weak lang item" in the sense that a crate is not required to have it |
| 223 | + // defined to use it, but a final product is required to define it |
| 224 | + // somewhere. Additionally, there are restrictions on crates that use a weak |
| 225 | + // lang item, but do not have it defined. |
| 226 | + PanicFnLangItem, "panic", panic_fn, Target::Fn; |
| 227 | + PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn; |
| 228 | + PanicInfoLangItem, "panic_info", panic_info, Target::Struct; |
| 229 | + PanicLocationLangItem, "panic_location", panic_location, Target::Struct; |
| 230 | + PanicImplLangItem, "panic_impl", panic_impl, Target::Fn; |
| 231 | + // Libstd panic entry point. Necessary for const eval to be able to catch it |
| 232 | + BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn; |
| 233 | + |
| 234 | + ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Target::Fn; |
| 235 | + BoxFreeFnLangItem, "box_free", box_free_fn, Target::Fn; |
| 236 | + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Target::Fn; |
| 237 | + OomLangItem, "oom", oom, Target::Fn; |
| 238 | + AllocLayoutLangItem, "alloc_layout", alloc_layout, Target::Struct; |
| 239 | + |
| 240 | + StartFnLangItem, "start", start_fn, Target::Fn; |
| 241 | + |
| 242 | + EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn; |
| 243 | + EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Target::Fn; |
| 244 | + EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static; |
| 245 | + |
| 246 | + OwnedBoxLangItem, "owned_box", owned_box, Target::Struct; |
| 247 | + |
| 248 | + PhantomDataItem, "phantom_data", phantom_data, Target::Struct; |
| 249 | + |
| 250 | + ManuallyDropItem, "manually_drop", manually_drop, Target::Struct; |
| 251 | + |
| 252 | + MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; |
| 253 | + |
| 254 | + // Align offset for stride != 1; must not panic. |
| 255 | + AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; |
| 256 | + |
| 257 | + TerminationTraitLangItem, "termination", termination, Target::Trait; |
| 258 | + |
| 259 | + Arc, "arc", arc, Target::Struct; |
| 260 | + Rc, "rc", rc, Target::Struct; |
| 261 | +} |
0 commit comments