From 47768b2613393e39218c255ed990169665d69df9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 8 May 2019 03:05:32 +0200 Subject: [PATCH] Document + Cleanup lang_items.rs --- src/librustc/middle/lang_items.rs | 97 +++++++++++++++++++------------ 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 5d809f1407114..0e283ca6b1cf1 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -1,13 +1,13 @@ -// Detecting language items. -// -// Language items are items that represent concepts intrinsic to the language -// itself. Examples are: -// -// * Traits that specify "kinds"; e.g., "Sync", "Send". -// -// * Traits that represent operators; e.g., "Add", "Sub", "Index". -// -// * Functions called by the compiler itself. +//! Detecting language items. +//! +//! Language items are items that represent concepts intrinsic to the language +//! itself. Examples are: +//! +//! * Traits that specify "kinds"; e.g., "Sync", "Send". +//! +//! * Traits that represent operators; e.g., "Add", "Sub", "Index". +//! +//! * Functions called by the compiler itself. pub use self::LangItem::*; @@ -32,6 +32,7 @@ macro_rules! language_item_table { ) => { enum_from_u32! { + /// A representation of all the valid language items in Rust. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum LangItem { $($variant,)* @@ -39,6 +40,9 @@ enum_from_u32! { } impl LangItem { + /// Returns the `name` in `#[lang = "$name"]`. + /// For example, `LangItem::EqTraitLangItem`, + /// that is `#[lang = "eq"]` would result in `"eq"`. fn name(self) -> &'static str { match self { $( $variant => $name, )* @@ -48,28 +52,38 @@ impl LangItem { #[derive(HashStable)] pub struct LanguageItems { + /// Mappings from lang items to their possibly found `DefId`s. + /// The index corresponds to the order in `LangItem`. pub items: Vec>, + /// Lang items that were not found during collection. pub missing: Vec, } impl LanguageItems { - pub fn new() -> LanguageItems { - fn foo(_: LangItem) -> Option { None } + /// Construct an empty collection of lang items and no missing ones. + pub fn new() -> Self { + fn init_none(_: LangItem) -> Option { None } - LanguageItems { - items: vec![$(foo($variant)),*], + Self { + items: vec![$(init_none($variant)),*], missing: Vec::new(), } } + /// Returns the mappings to the possibly found `DefId`s for each lang item. pub fn items(&self) -> &[Option] { &*self.items } + /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. + /// If it wasn't bound, e.g. due to a missing `#[lang = ""]`, + /// returns an error message as a string. pub fn require(&self, it: LangItem) -> Result { self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) } + /// Returns the kind of closure that `id`, which is one of the `Fn*` traits, corresponds to. + /// If `id` is not one of the `Fn*` traits, `None` is returned. pub fn fn_trait_kind(&self, id: DefId) -> Option { match Some(id) { x if x == self.fn_trait() => Some(ty::ClosureKind::Fn), @@ -80,6 +94,9 @@ impl LanguageItems { } $( + /// Returns the corresponding `DefId` for the lang item + #[doc = $name] + /// if it exists. #[allow(dead_code)] pub fn $method(&self) -> Option { self.items[$variant as usize] @@ -90,6 +107,7 @@ impl LanguageItems { struct LanguageItemCollector<'a, 'tcx: 'a> { items: LanguageItems, tcx: TyCtxt<'a, 'tcx, 'tcx>, + /// A mapping from the name of the lang item to its order and the form it must be of. item_refs: FxHashMap<&'static str, (usize, Target)>, } @@ -105,32 +123,28 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> { }, // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { - let mut err = struct_span_err!( + struct_span_err!( self.tcx.sess, span, E0718, "`{}` language item must be applied to a {}", value, expected_target, - ); - err.span_label( + ).span_label( span, format!( "attribute should be applied to a {}, not a {}", expected_target, actual_target, ), - ); - err.emit(); + ).emit(); }, // Unknown lang item. _ => { - let mut err = struct_span_err!( + struct_span_err!( self.tcx.sess, span, E0522, "definition of an unknown language item: `{}`", value - ); - err.span_label( + ).span_label( span, format!("definition of unknown language item `{}`", value) - ); - err.emit(); + ).emit(); }, } } @@ -190,32 +204,39 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { } } +/// Extract the first `lang = "$name"` out of a list of attributes. +/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` +/// are also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { - for attribute in attrs { - if attribute.check_name("lang") { - if let Some(value) = attribute.value_str() { - return Some((value, attribute.span)); - } - } else if attribute.check_name("panic_handler") { - return Some((Symbol::intern("panic_impl"), attribute.span)) - } else if attribute.check_name("alloc_error_handler") { - return Some((Symbol::intern("oom"), attribute.span)) - } - } - - None + attrs.iter().find_map(|attr| Some(match attr { + _ if attr.check_name("lang") => (attr.value_str()?, attr.span), + _ if attr.check_name("panic_handler") => (Symbol::intern("panic_impl"), attr.span), + _ if attr.check_name("alloc_error_handler") => (Symbol::intern("oom"), attr.span), + _ => return None, + })) } +/// Traverse and collect all the lang items in all crates. pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems { + // Initialize the collector. let mut collector = LanguageItemCollector::new(tcx); + + // Collect lang items in other crates. for &cnum in tcx.crates().iter() { for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() { collector.collect_item(item_index, def_id); } } + + // Collect lang items in this crate. tcx.hir().krate().visit_all_item_likes(&mut collector); + + // Extract out the found lang items. let LanguageItemCollector { mut items, .. } = collector; + + // Find all required but not-yet-defined lang items. weak_lang_items::check_crate(tcx, &mut items); + items } @@ -382,6 +403,8 @@ language_item_table! { } impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> { + /// Returns the `DefId` for a given `LangItem`. + /// If not found, fatally abort compilation. pub fn require_lang_item(&self, lang_item: LangItem) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { self.sess.fatal(&msg)