From a227c706b7809ff07021baf3856b7540d5b57f8a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 27 Jan 2020 21:01:52 +0000 Subject: [PATCH] Use lang items instead of hard-coded paths in HIR lowering --- src/libcore/convert/mod.rs | 1 + src/libcore/iter/traits/collect.rs | 1 + src/libcore/iter/traits/iterator.rs | 1 + src/libcore/ops/range.rs | 6 + src/libcore/ops/try.rs | 3 + src/libcore/option.rs | 2 + src/libcore/pin.rs | 1 + src/libcore/result.rs | 2 + src/libcore/task/poll.rs | 2 + src/librustc/hir/mod.rs | 11 + src/librustc/ich/impls_hir.rs | 6 - src/librustc/macros.rs | 37 -- src/librustc/middle/lang_items.rs | 476 ++++++++----------------- src/librustc/traits/select.rs | 5 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/print/pretty.rs | 2 +- src/librustc_ast_lowering/expr.rs | 223 ++++-------- src/librustc_ast_lowering/item.rs | 4 +- src/librustc_ast_lowering/lib.rs | 140 +++----- src/librustc_hir/hir.rs | 103 +++--- src/librustc_hir/intravisit.rs | 5 + src/librustc_hir/lang_item.rs | 362 +++++++++++++++++++ src/librustc_hir/lib.rs | 1 + src/librustc_hir/print.rs | 11 + src/librustc_lint/builtin.rs | 1 + src/librustc_lint/types.rs | 4 +- src/librustc_mir/shim.rs | 2 +- src/librustc_passes/liveness.rs | 6 +- src/librustc_privacy/lib.rs | 1 + src/librustc_resolve/lib.rs | 31 -- src/librustc_resolve/lifetimes.rs | 28 ++ src/librustc_typeck/astconv.rs | 70 +++- src/librustc_typeck/check/closure.rs | 9 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/expr.rs | 9 + src/librustc_typeck/check/mod.rs | 33 +- src/librustc_typeck/check/pat.rs | 1 + src/librustc_typeck/collect.rs | 26 ++ src/librustdoc/clean/mod.rs | 58 +++ src/libstd/future.rs | 2 + src/test/ui/hygiene/hir-res-hygiene.rs | 19 + src/test/ui/range/range-1.stderr | 6 +- 44 files changed, 987 insertions(+), 732 deletions(-) create mode 100644 src/librustc_hir/lang_item.rs create mode 100644 src/test/ui/hygiene/hir-res-hygiene.rs diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs index 959fd63df51c2..b0fba34c950d5 100644 --- a/src/libcore/convert/mod.rs +++ b/src/libcore/convert/mod.rs @@ -381,6 +381,7 @@ pub trait Into: Sized { pub trait From: Sized { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "from_method")] fn from(_: T) -> Self; } diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index f21ab8dbc3737..74ef8def391b7 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -236,6 +236,7 @@ pub trait IntoIterator { /// assert_eq!(None, iter.next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "into_iter")] fn into_iter(self) -> Self::IntoIter; } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 21a569867b178..79c83bcf57ff7 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -127,6 +127,7 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "iter_next")] fn next(&mut self) -> Option; /// Returns the bounds on the remaining length of the iterator. diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d38b35165695c..7d27d1561b874 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -41,6 +41,7 @@ use crate::hash::{Hash, Hasher}; #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "range_full")] pub struct RangeFull; #[stable(feature = "rust1", since = "1.0.0")] @@ -73,6 +74,7 @@ impl fmt::Debug for RangeFull { #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "range")] pub struct Range { /// The lower bound of the range (inclusive). #[stable(feature = "rust1", since = "1.0.0")] @@ -178,6 +180,7 @@ impl> Range { #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "range_from")] pub struct RangeFrom { /// The lower bound of the range (inclusive). #[stable(feature = "rust1", since = "1.0.0")] @@ -262,6 +265,7 @@ impl> RangeFrom { #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), lang = "range_to")] pub struct RangeTo { /// The upper bound of the range (exclusive). #[stable(feature = "rust1", since = "1.0.0")] @@ -404,6 +408,7 @@ impl RangeInclusive { #[inline] #[rustc_promotable] #[rustc_const_stable(feature = "const_range_new", since = "1.32.0")] + #[cfg_attr(not(bootstrap), lang = "range_inclusive")] pub const fn new(start: Idx, end: Idx) -> Self { Self { start, end, is_empty: None } } @@ -607,6 +612,7 @@ impl> RangeInclusive { #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] +#[cfg_attr(not(bootstrap), lang = "range_to_inclusive")] pub struct RangeToInclusive { /// The upper bound of the range (inclusive) #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 996a01d413cbc..cb14512bf00ba 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -43,15 +43,18 @@ pub trait Try { /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. #[unstable(feature = "try_trait", issue = "42327")] + #[cfg_attr(not(bootstrap), lang = "try_into_result")] fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. #[unstable(feature = "try_trait", issue = "42327")] + #[cfg_attr(not(bootstrap), lang = "try_from_error")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. #[unstable(feature = "try_trait", issue = "42327")] + #[cfg_attr(not(bootstrap), lang = "try_from_ok")] fn from_ok(v: Self::Ok) -> Self; } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cb4247d98745e..5e1b906055158 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -156,9 +156,11 @@ use crate::{ pub enum Option { /// No value #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "option_none")] None, /// Some value `T` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "option_some")] Some(#[stable(feature = "rust1", since = "1.0.0")] T), } diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 676d2c784acee..7ca48017fffd0 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -562,6 +562,7 @@ impl Pin

{ /// [`mem::swap`]: ../../std/mem/fn.swap.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] + #[cfg_attr(not(bootstrap), lang = "pin_new_unchecked")] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bc70dbd62eb52..746e31191790f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -247,10 +247,12 @@ use crate::ops::{self, Deref, DerefMut}; pub enum Result { /// Contains the success value #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "result_ok")] Ok(#[stable(feature = "rust1", since = "1.0.0")] T), /// Contains the error value #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), lang = "result_err")] Err(#[stable(feature = "rust1", since = "1.0.0")] E), } diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs index b3a4bd20b8f04..1f41b91f08f7b 100644 --- a/src/libcore/task/poll.rs +++ b/src/libcore/task/poll.rs @@ -11,6 +11,7 @@ use crate::result::Result; pub enum Poll { /// Represents that a value is immediately ready. #[stable(feature = "futures_api", since = "1.36.0")] + #[cfg_attr(not(bootstrap), lang = "poll_ready")] Ready(#[stable(feature = "futures_api", since = "1.36.0")] T), /// Represents that a value is not ready yet. @@ -19,6 +20,7 @@ pub enum Poll { /// ensure that the current task is scheduled to be awoken when /// progress can be made. #[stable(feature = "futures_api", since = "1.36.0")] + #[cfg_attr(not(bootstrap), lang = "poll_pending")] Pending, } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 97c14dd7e0054..5ed4889d018c0 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -8,9 +8,20 @@ pub mod map; pub mod upvars; use crate::ty::query::Providers; +use crate::ty::TyCtxt; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_item::LangItem; +use rustc_span::Span; pub fn provide(providers: &mut Providers<'_>) { check_attr::provide(providers); map::provide(providers); upvars::provide(providers); } + +impl hir::RequireLangItem for TyCtxt<'_> { + fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId { + self.require_lang_item(lang_item, Some(span)) + } +} diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 8961f7cd4bc95..4ea284e006cc3 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -283,12 +283,6 @@ impl<'a> ToStableHashKey> for hir::def_id::DefIndex { } } -impl<'a> HashStable> for crate::middle::lang_items::LangItem { - fn hash_stable(&self, _: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } -} - impl<'a> HashStable> for hir::TraitCandidate { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 2bda0c0bef02d..88ddd96eec8f5 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -1,40 +1,3 @@ -macro_rules! enum_from_u32 { - ($(#[$attr:meta])* pub enum $name:ident { - $($variant:ident = $e:expr,)* - }) => { - $(#[$attr])* - pub enum $name { - $($variant = $e),* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - }; - ($(#[$attr:meta])* pub enum $name:ident { - $($variant:ident,)* - }) => { - $(#[$attr])* - pub enum $name { - $($variant,)* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - } -} - #[macro_export] macro_rules! bug { () => ( bug!("impossible case reached") ); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 27b769742a9fc..74b5f483473f3 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -7,9 +7,8 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -pub use self::LangItem::*; +pub use rustc_hir::lang_item::*; -use crate::hir::check_attr::Target; use crate::middle::cstore::ExternCrate; use crate::middle::weak_lang_items; use crate::ty::{self, TyCtxt}; @@ -19,162 +18,51 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_macros::HashStable; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use syntax::ast; -// The actual lang items defined come at the end of this file in one handy table. -// So you probably just want to nip down to the end. -macro_rules! language_item_table { - ( - $( $variant:ident, $name:expr, $method:ident, $target:path; )* - ) => { - -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,)* - } -} - -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, )* - } - } -} - -#[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 { - /// Construct an empty collection of lang items and no missing ones. - pub fn new() -> Self { - fn init_none(_: LangItem) -> Option { None } +/// Traverses and collects all the lang items in all crates. +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems { + // Initialize the collector. + let mut collector = LanguageItemCollector::new(tcx); - Self { - items: vec![$(init_none($variant)),*], - missing: Vec::new(), + // 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); } } - /// Returns the mappings to the possibly found `DefId`s for each lang item. - pub fn items(&self) -> &[Option] { - &*self.items - } + // Collect lang items in this crate. + tcx.hir().krate().visit_all_item_likes(&mut collector); - /// 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())) - } + // Extract out the found lang items. + let LanguageItemCollector { mut items, .. } = collector; - /// 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), - x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut), - x if x == self.fn_once_trait() => Some(ty::ClosureKind::FnOnce), - _ => None - } - } + // Find all required but not-yet-defined lang items. + weak_lang_items::check_crate(tcx, &mut items); - $( - /// 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] - } - )* + items } struct LanguageItemCollector<'tcx> { items: LanguageItems, tcx: TyCtxt<'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)>, -} - -impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { - fn visit_item(&mut self, item: &hir::Item<'_>) { - if let Some((value, span)) = extract(&item.attrs) { - let actual_target = Target::from_item(item); - match self.item_refs.get(&*value.as_str()).cloned() { - // Known lang item with attribute on correct target. - Some((item_index, expected_target)) if actual_target == expected_target => { - let def_id = self.tcx.hir().local_def_id(item.hir_id); - self.collect_item(item_index, def_id); - }, - // Known lang item with attribute on incorrect target. - Some((_, expected_target)) => { - struct_span_err!( - self.tcx.sess, span, E0718, - "`{}` language item must be applied to a {}", - value, expected_target, - ).span_label( - span, - format!( - "attribute should be applied to a {}, not a {}", - expected_target, actual_target, - ), - ).emit(); - }, - // Unknown lang item. - _ => { - struct_span_err!( - self.tcx.sess, span, E0522, - "definition of an unknown language item: `{}`", - value - ).span_label( - span, - format!("definition of unknown language item `{}`", value) - ).emit(); - }, - } - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) { - // At present, lang items are always items, not trait items. - } - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) { - // At present, lang items are always items, not impl items. - } + item_refs: FxHashMap<&'static str, (usize, Location)>, } -impl LanguageItemCollector<'tcx> { +impl LanguageItemCollector<'_> { fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { - let mut item_refs = FxHashMap::default(); - - $( item_refs.insert($name, ($variant as usize, $target)); )* - - LanguageItemCollector { - tcx, - items: LanguageItems::new(), - item_refs, - } + LanguageItemCollector { tcx, items: LanguageItems::new(), item_refs: LangItem::table() } } fn collect_item(&mut self, item_index: usize, item_def_id: DefId) { + let item_place = &mut self.items.items[item_index]; + // Check for duplicates. - if let Some(original_def_id) = self.items.items[item_index] { + if let Some(original_def_id) = *item_place { if original_def_id != item_def_id { let name = LangItem::from_u32(item_index as u32).unwrap().name(); let mut err = match self.tcx.hir().span_if_local(item_def_id) { @@ -185,37 +73,38 @@ impl LanguageItemCollector<'tcx> { "found duplicate lang item `{}`", name ), - None => { - match self.tcx.extern_crate(item_def_id) { - Some(ExternCrate {dependency_of, ..}) => { - self.tcx.sess.struct_err(&format!( + None => match self.tcx.extern_crate(item_def_id) { + Some(ExternCrate { dependency_of, .. }) => { + self.tcx.sess.struct_err(&format!( "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.", self.tcx.crate_name(item_def_id.krate), self.tcx.crate_name(*dependency_of), - name)) - }, - _ => { - self.tcx.sess.struct_err(&format!( - "duplicate lang item in crate `{}`: `{}`.", - self.tcx.crate_name(item_def_id.krate), - name)) - } + name + )) } + _ => self.tcx.sess.struct_err(&format!( + "duplicate lang item in crate `{}`: `{}`.", + self.tcx.crate_name(item_def_id.krate), + name + )), }, }; if let Some(span) = self.tcx.hir().span_if_local(original_def_id) { err.span_note(span, "first defined here"); } else { match self.tcx.extern_crate(original_def_id) { - Some(ExternCrate {dependency_of, ..}) => { + Some(ExternCrate { dependency_of, .. }) => { err.note(&format!( - "first defined in crate `{}` (which `{}` depends on)", - self.tcx.crate_name(original_def_id.krate), - self.tcx.crate_name(*dependency_of))); - }, + "first defined in crate `{}` (which `{}` depends on)", + self.tcx.crate_name(original_def_id.krate), + self.tcx.crate_name(*dependency_of) + )); + } _ => { - err.note(&format!("first defined in crate `{}`.", - self.tcx.crate_name(original_def_id.krate))); + err.note(&format!( + "first defined in crate `{}`.", + self.tcx.crate_name(original_def_id.krate) + )); } } } @@ -224,191 +113,132 @@ impl LanguageItemCollector<'tcx> { } // Matched. - self.items.items[item_index] = Some(item_def_id); + *item_place = Some(item_def_id); } -} -/// Extracts 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)> { - attrs.iter().find_map(|attr| Some(match attr { - _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span), - _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span), - _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span), - _ => return None, - })) -} - -/// Traverses and collects all the lang items in all crates. -pub fn collect<'tcx>(tcx: TyCtxt<'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); - } + /// Emits a diagnostic error when `value` is an unknown lang item. + fn unknown_lang_item(&self, value: Symbol, span: Span) { + struct_span_err!( + self.tcx.sess, + span, + E0522, + "definition of an unknown language item: `{}`", + value + ) + .span_label(span, format!("definition of unknown language item `{}`", value)) + .emit(); } - // 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); + /// Known lang item with attribute on incorrect target. + fn wrong_location(&self, value: Symbol, span: Span, expected: Location, actual: Location) { + struct_span_err!( + self.tcx.sess, + span, + E0718, + "`{}` language item must be applied to a {}", + value, + expected, + ) + .span_label( + span, + format!("attribute should be applied to a {}, not a {}", expected, actual), + ) + .emit(); + } - items -} + /// The item form does not admit language items. + fn lang_items_not_allowed_here(&self, span: Span) { + struct_span_err!(self.tcx.sess, span, E0719, "item cannot be a language item").emit(); + } -// End of the macro + /// Visit an item-like object and possibly collect it as a lang item. + /// It has to have at least a sequence of attributes to scan for ยด#[lang(..)]`. + /// The `DefId` that is collected is determined by the given `HirId`. + /// Finally, the `locator` determines the `Location` of the `HirId` + /// or returns `None` should the location be invalid. + fn visit_item_like( + &mut self, + attrs: &[ast::Attribute], + hir_id: hir::HirId, + locator: impl FnOnce() -> Option, + ) { + if let Some((value, span)) = extract(attrs) { + if let Some(actual) = locator() { + match self.item_refs.get(&*value.as_str()).cloned() { + Some((item_index, expected)) if actual == expected => { + // Known lang item with attribute on correct location. + let def_id = self.tcx.hir().local_def_id(hir_id); + self.collect_item(item_index, def_id); + } + Some((_, expected)) => self.wrong_location(value, span, expected, actual), + _ => self.unknown_lang_item(value, span), + } + } else { + self.lang_items_not_allowed_here(span); + } + } } } -language_item_table! { -// Variant name, Name, Method name, Target; - BoolImplItem, "bool", bool_impl, Target::Impl; - CharImplItem, "char", char_impl, Target::Impl; - StrImplItem, "str", str_impl, Target::Impl; - SliceImplItem, "slice", slice_impl, Target::Impl; - SliceU8ImplItem, "slice_u8", slice_u8_impl, Target::Impl; - StrAllocImplItem, "str_alloc", str_alloc_impl, Target::Impl; - SliceAllocImplItem, "slice_alloc", slice_alloc_impl, Target::Impl; - SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Target::Impl; - ConstPtrImplItem, "const_ptr", const_ptr_impl, Target::Impl; - MutPtrImplItem, "mut_ptr", mut_ptr_impl, Target::Impl; - I8ImplItem, "i8", i8_impl, Target::Impl; - I16ImplItem, "i16", i16_impl, Target::Impl; - I32ImplItem, "i32", i32_impl, Target::Impl; - I64ImplItem, "i64", i64_impl, Target::Impl; - I128ImplItem, "i128", i128_impl, Target::Impl; - IsizeImplItem, "isize", isize_impl, Target::Impl; - U8ImplItem, "u8", u8_impl, Target::Impl; - U16ImplItem, "u16", u16_impl, Target::Impl; - U32ImplItem, "u32", u32_impl, Target::Impl; - U64ImplItem, "u64", u64_impl, Target::Impl; - U128ImplItem, "u128", u128_impl, Target::Impl; - UsizeImplItem, "usize", usize_impl, Target::Impl; - F32ImplItem, "f32", f32_impl, Target::Impl; - F64ImplItem, "f64", f64_impl, Target::Impl; - F32RuntimeImplItem, "f32_runtime", f32_runtime_impl, Target::Impl; - F64RuntimeImplItem, "f64_runtime", f64_runtime_impl, Target::Impl; - - SizedTraitLangItem, "sized", sized_trait, Target::Trait; - UnsizeTraitLangItem, "unsize", unsize_trait, Target::Trait; - // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). - StructuralPeqTraitLangItem, "structural_peq", structural_peq_trait, Target::Trait; - // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). - StructuralTeqTraitLangItem, "structural_teq", structural_teq_trait, Target::Trait; - CopyTraitLangItem, "copy", copy_trait, Target::Trait; - CloneTraitLangItem, "clone", clone_trait, Target::Trait; - SyncTraitLangItem, "sync", sync_trait, Target::Trait; - FreezeTraitLangItem, "freeze", freeze_trait, Target::Trait; - - DropTraitLangItem, "drop", drop_trait, Target::Trait; - - CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; - DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; - - AddTraitLangItem, "add", add_trait, Target::Trait; - SubTraitLangItem, "sub", sub_trait, Target::Trait; - MulTraitLangItem, "mul", mul_trait, Target::Trait; - DivTraitLangItem, "div", div_trait, Target::Trait; - RemTraitLangItem, "rem", rem_trait, Target::Trait; - NegTraitLangItem, "neg", neg_trait, Target::Trait; - NotTraitLangItem, "not", not_trait, Target::Trait; - BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait; - BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait; - BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait; - ShlTraitLangItem, "shl", shl_trait, Target::Trait; - ShrTraitLangItem, "shr", shr_trait, Target::Trait; - AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait; - SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait; - MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait; - DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait; - RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait; - BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait; - BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait; - BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait; - ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait; - ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; - IndexTraitLangItem, "index", index_trait, Target::Trait; - IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; - - UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; - VaListTypeLangItem, "va_list", va_list, Target::Struct; - - DerefTraitLangItem, "deref", deref_trait, Target::Trait; - DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait; - ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait; - - FnTraitLangItem, "fn", fn_trait, Target::Trait; - FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait; - FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait; - - FutureTraitLangItem, "future_trait", future_trait, Target::Trait; - GeneratorStateLangItem, "generator_state", gen_state, Target::Enum; - GeneratorTraitLangItem, "generator", gen_trait, Target::Trait; - UnpinTraitLangItem, "unpin", unpin_trait, Target::Trait; - PinTypeLangItem, "pin", pin_type, Target::Struct; - - // Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`. - EqTraitLangItem, "eq", eq_trait, Target::Trait; - PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait; - - // A number of panic-related lang items. The `panic` item corresponds to - // divide-by-zero and various panic cases with `match`. The - // `panic_bounds_check` item is for indexing arrays. - // - // The `begin_unwind` lang item has a predefined symbol name and is sort of - // a "weak lang item" in the sense that a crate is not required to have it - // defined to use it, but a final product is required to define it - // somewhere. Additionally, there are restrictions on crates that use a weak - // lang item, but do not have it defined. - PanicFnLangItem, "panic", panic_fn, Target::Fn; - PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn; - PanicInfoLangItem, "panic_info", panic_info, Target::Struct; - PanicLocationLangItem, "panic_location", panic_location, Target::Struct; - PanicImplLangItem, "panic_impl", panic_impl, Target::Fn; - // Libstd panic entry point. Necessary for const eval to be able to catch it - BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn; - - ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Target::Fn; - BoxFreeFnLangItem, "box_free", box_free_fn, Target::Fn; - DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Target::Fn; - OomLangItem, "oom", oom, Target::Fn; - AllocLayoutLangItem, "alloc_layout", alloc_layout, Target::Struct; - - StartFnLangItem, "start", start_fn, Target::Fn; - - EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn; - EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Target::Fn; - EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static; - - OwnedBoxLangItem, "owned_box", owned_box, Target::Struct; - - PhantomDataItem, "phantom_data", phantom_data, Target::Struct; - - ManuallyDropItem, "manually_drop", manually_drop, Target::Struct; - - MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; - - // Align offset for stride != 1; must not panic. - AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; +impl ItemLikeVisitor<'_> for LanguageItemCollector<'_> { + fn visit_item(&mut self, item: &hir::Item<'_>) { + use hir::ItemKind::*; + self.visit_item_like(&item.attrs, item.hir_id, || { + Some(match item.kind { + Enum(..) => Location::Enum, + Fn(..) => Location::Fn, + Impl { .. } => Location::Impl, + Static(..) => Location::Static, + Struct(..) => Location::Struct, + Trait(..) => Location::Trait, + Union(..) => Location::Union, + _ => return None, + }) + }); + + if let Enum(ref def, _) = item.kind { + for variant in def.variants { + self.visit_item_like(&variant.attrs, variant.id, || Some(Location::Variant)); + } + } + } - TerminationTraitLangItem, "termination", termination, Target::Trait; + fn visit_impl_item(&mut self, item: &hir::ImplItem<'_>) { + use hir::ImplItemKind::*; + self.visit_item_like(&item.attrs, item.hir_id, || { + Some(match item.kind { + Method(..) => Location::Method, + _ => return None, + }) + }); + } - Arc, "arc", arc, Target::Struct; - Rc, "rc", rc, Target::Struct; + fn visit_trait_item(&mut self, item: &hir::TraitItem<'_>) { + use hir::TraitItemKind::*; + self.visit_item_like(&item.attrs, item.hir_id, || { + Some(match item.kind { + Method(..) => Location::Method, + _ => return None, + }) + }); + } } impl<'tcx> TyCtxt<'tcx> { + /// 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 { + let lang_items = self.lang_items(); + match Some(id) { + x if x == lang_items.fn_trait() => Some(ty::ClosureKind::Fn), + x if x == lang_items.fn_mut_trait() => Some(ty::ClosureKind::FnMut), + x if x == lang_items.fn_once_trait() => Some(ty::ClosureKind::FnOnce), + _ => None, + } + } /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index ac1ca4db9d6bb..03dff3cae5db1 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1913,7 +1913,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) { + let kind = match self.tcx().fn_trait_kind(obligation.predicate.def_id()) { Some(k) => k, None => { return Ok(()); @@ -1956,7 +1956,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { // We provide impl of all fn traits for fn pointers. - if self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()).is_none() { + if self.tcx().fn_trait_kind(obligation.predicate.def_id()).is_none() { return Ok(()); } @@ -3170,7 +3170,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = self .tcx() - .lang_items() .fn_trait_kind(obligation.predicate.def_id()) .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a51f0f7f24c36..86cc80ca0a178 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -462,7 +462,7 @@ impl<'tcx> TypeckTables<'tcx> { pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .type_dependent_def(id) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 51a18f8eae274..cc77d49e0ee00 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -449,7 +449,7 @@ fn resolve_associated_item<'tcx>( substs: generator_data.substs, }), traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); + let trait_closure_kind = tcx.fn_trait_kind(trait_id).unwrap(); Some(Instance::resolve_closure( tcx, closure_data.closure_def_id, diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 7dd3c8f4a7295..19dea16a86d71 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -724,7 +724,7 @@ pub trait PrettyPrinter<'tcx>: let mut resugared = false; // Special-case `Fn(...) -> ...` and resugar it. - let fn_trait_kind = self.tcx().lang_items().fn_trait_kind(principal.def_id); + let fn_trait_kind = self.tcx().fn_trait_kind(principal.def_id); if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { if let ty::Tuple(ref args) = principal.substs.type_at(0).kind { let mut projections = predicates.projection_bounds(); diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 5dc855e935c07..d501b2f113d30 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -5,6 +5,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; +use rustc_hir::lang_item::LangItem; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Symbol}; use syntax::ast::*; @@ -321,7 +322,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Lower condition: let cond = self.lower_expr(cond); let span_block = - self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None); + self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `if cond { ... }` does not // let temporaries live outside of `cond`. @@ -385,7 +386,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Lower condition: let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond)); let span_block = - self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None); + self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `while cond { ... }` does not // let temporaries live outside of `cond`. @@ -416,11 +417,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.with_catch_scope(body.id, |this| { let mut block = this.lower_block_noalloc(body, true); - let try_span = this.mark_span_with_reason( - DesugaringKind::TryBlock, - body.span, - this.allow_try_trait.clone(), - ); + let try_span = this.mark_span_with_reason(DesugaringKind::TryBlock, body.span); // Final expression of the block (if present) or `()` with span at the end of block let tail_expr = block @@ -429,33 +426,20 @@ impl<'hir> LoweringContext<'_, 'hir> { .unwrap_or_else(|| this.expr_unit(this.sess.source_map().end_point(try_span))); let ok_wrapped_span = - this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None); + this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span); // `::std::ops::Try::from_ok($tail_expr)` - block.expr = Some(this.wrap_in_try_constructor( - sym::from_ok, + block.expr = Some(this.expr_call_lang_item_fn( + LangItem::TryFromOk, try_span, - tail_expr, ok_wrapped_span, + std::slice::from_ref(tail_expr), )); hir::ExprKind::Block(this.arena.alloc(block), None) }) } - fn wrap_in_try_constructor( - &mut self, - method: Symbol, - method_span: Span, - expr: &'hir hir::Expr<'hir>, - overall_span: Span, - ) -> &'hir hir::Expr<'hir> { - let path = &[sym::ops, sym::Try, method]; - let constructor = - self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new())); - self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) - } - fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { hir::Arm { hir_id: self.next_id(), @@ -506,17 +490,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }; // `future::from_generator`: - let unstable_span = - self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let gen_future = self.expr_std_path( - unstable_span, - &[sym::future, sym::from_generator], - None, - ThinVec::new(), - ); - - // `future::from_generator(generator)`: - hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator]) + let fn_path = hir::QPath::LangItem(LangItem::FromGenerator, span); + let fn_expr = + self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + hir::ExprKind::Call(fn_expr, arena_vec![self; generator]) } /// Desugar `.await` into: @@ -550,12 +527,7 @@ impl<'hir> LoweringContext<'_, 'hir> { err.emit(); } } - let span = self.mark_span_with_reason(DesugaringKind::Await, await_span, None); - let gen_future_span = self.mark_span_with_reason( - DesugaringKind::Await, - await_span, - self.allow_gen_future.clone(), - ); + let span = self.mark_span_with_reason(DesugaringKind::Await, await_span); let pinned_ident = Ident::with_dummy_span(sym::pinned); let (pinned_pat, pinned_pat_hid) = @@ -567,20 +539,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let poll_expr = { let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid); let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); - let pin_ty_id = self.next_id(); - let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( - pin_ty_id, + let new_unchecked = self.expr_call_lang_item_fn( + LangItem::PinNewUnchecked, + span, span, - &[sym::pin, sym::Pin], - "new_unchecked", arena_vec![self; ref_mut_pinned], ); - let new_unchecked = - self.arena.alloc(self.expr(span, new_unchecked_expr_kind, ThinVec::new())); let unsafe_expr = self.expr_unsafe(new_unchecked); - self.expr_call_std_path( - gen_future_span, - &[sym::future, sym::poll_with_tls_context], + self.expr_call_lang_item_fn( + LangItem::PollWithTlsContext, + span, + span, arena_vec![self; unsafe_expr], ) }; @@ -592,11 +561,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_ident = Ident::with_dummy_span(sym::result); let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); let x_expr = self.expr_ident(span, x_ident, x_pat_hid); - let ready_pat = self.pat_std_enum( - span, - &[sym::task, sym::Poll, sym::Ready], - arena_vec![self; x_pat], - ); + let field = self.single_pat_field(span, x_pat); + let ready_pat = self.pat_lang_item_variant(LangItem::PollReady, span, field); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -607,7 +573,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` let pending_arm = { - let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]); + let pending_pat = self.pat_lang_item_variant(LangItem::PollPending, span, &[]); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) }; @@ -764,16 +730,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `..=` into `std::ops::RangeInclusive::new(, )`. fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { - let id = self.next_id(); let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - self.expr_call_std_assoc_fn( - id, - span, - &[sym::ops, sym::RangeInclusive], - "new", - arena_vec![self; e1, e2], - ) + let fn_path = hir::QPath::LangItem(LangItem::RangeInclusiveNew, span); + let fn_expr = + self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } fn lower_expr_range( @@ -785,12 +747,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { use syntax::ast::RangeLimits::*; - let path = match (e1, e2, lims) { - (None, None, HalfOpen) => sym::RangeFull, - (Some(..), None, HalfOpen) => sym::RangeFrom, - (None, Some(..), HalfOpen) => sym::RangeTo, - (Some(..), Some(..), HalfOpen) => sym::Range, - (None, Some(..), Closed) => sym::RangeToInclusive, + let lang_item = match (e1, e2, lims) { + (None, None, HalfOpen) => LangItem::RangeFull, + (Some(..), None, HalfOpen) => LangItem::RangeFrom, + (None, Some(..), HalfOpen) => LangItem::RangeTo, + (Some(..), Some(..), HalfOpen) => LangItem::Range, + (None, Some(..), Closed) => LangItem::RangeToInclusive, (Some(..), Some(..), Closed) => unreachable!(), (_, None, Closed) => { self.diagnostic().span_fatal(span, "inclusive range with no end").raise() @@ -805,16 +767,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }), ); - let is_unit = fields.is_empty(); - let struct_path = [sym::ops, path]; - let struct_path = self.std_path(span, &struct_path, None, is_unit); - let struct_path = hir::QPath::Resolved(None, struct_path); - - if is_unit { - hir::ExprKind::Path(struct_path) - } else { - hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None) - } + hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None) } fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { @@ -990,7 +943,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::Expr<'hir> { // expand let mut head = self.lower_expr_mut(head); - let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); + let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span); head.span = desugared_span; let iter = Ident::with_dummy_span(sym::iter); @@ -1033,9 +986,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let match_expr = { let iter = self.expr_ident(desugared_span, iter, iter_pat_nid); let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter); - let next_path = &[sym::iter, sym::Iterator, sym::next]; - let next_expr = - self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]); + let next_expr = self.expr_call_lang_item_fn( + LangItem::IterNext, + desugared_span, + desugared_span, + arena_vec![self; ref_mut_iter], + ); let arms = arena_vec![self; pat_arm, break_arm]; self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar) @@ -1086,10 +1042,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let iter_arm = self.arm(iter_pat, loop_expr); // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter]; - self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head]) - }; + let into_iter_expr = self.expr_call_lang_item_fn( + LangItem::IntoIter, + desugared_span, + desugared_span, + arena_vec![self; head], + ); let match_expr = self.arena.alloc(self.expr_match( desugared_span, @@ -1119,25 +1077,21 @@ impl<'hir> LoweringContext<'_, 'hir> { /// } /// ``` fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> { - let unstable_span = self.mark_span_with_reason( - DesugaringKind::QuestionMark, - span, - self.allow_try_trait.clone(), - ); let try_span = self.sess.source_map().end_point(span); - let try_span = self.mark_span_with_reason( - DesugaringKind::QuestionMark, - try_span, - self.allow_try_trait.clone(), - ); + let try_span = self.mark_span_with_reason(DesugaringKind::QuestionMark, try_span); + let unstable_span = self.mark_span_with_reason(DesugaringKind::QuestionMark, span); // `Try::into_result()` let scrutinee = { // expand let sub_expr = self.lower_expr_mut(sub_expr); - let path = &[sym::ops, sym::Try, sym::into_result]; - self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr]) + self.expr_call_lang_item_fn( + LangItem::TryIntoResult, + unstable_span, + unstable_span, + arena_vec![self; sub_expr], + ) }; // `#[allow(unreachable_code)]` @@ -1173,12 +1127,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let err_ident = Ident::with_dummy_span(sym::err); let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { - let from_path = &[sym::convert, sym::From, sym::from]; let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid); - self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr]) + self.expr_call_lang_item_fn( + LangItem::FromMethod, + try_span, + try_span, + arena_vec![self; err_expr], + ) }; - let from_err_expr = - self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span); + let from_err_expr = self.expr_call_lang_item_fn( + LangItem::TryFromError, + unstable_span, + try_span, + std::slice::from_ref(from_expr), + ); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().map(|x| *x); let ret_expr = if let Some(catch_node) = catch_scope { @@ -1280,54 +1242,17 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())) } - // Note: associated functions must use `expr_call_std_path`. - fn expr_call_std_path( + fn expr_call_lang_item_fn( &mut self, - span: Span, - path_components: &[Symbol], + lang_item: LangItem, + fn_span: Span, + call_span: Span, args: &'hir [hir::Expr<'hir>], ) -> &'hir hir::Expr<'hir> { - let path = - self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new())); - self.expr_call(span, path, args) - } - - // Create an expression calling an associated function of an std type. - // - // Associated functions cannot be resolved through the normal `std_path` function, - // as they are resolved differently and so cannot use `expr_call_std_path`. - // - // This function accepts the path component (`ty_path_components`) separately from - // the name of the associated function (`assoc_fn_name`) in order to facilitate - // separate resolution of the type and creation of a path referring to its associated - // function. - fn expr_call_std_assoc_fn( - &mut self, - ty_path_id: hir::HirId, - span: Span, - ty_path_components: &[Symbol], - assoc_fn_name: &str, - args: &'hir [hir::Expr<'hir>], - ) -> hir::ExprKind<'hir> { - let ty_path = self.std_path(span, ty_path_components, None, false); - let ty = - self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path))); - let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name))); - let fn_path = hir::QPath::TypeRelative(ty, fn_seg); + let fn_path = hir::QPath::LangItem(lang_item, fn_span); let fn_expr = - self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); - hir::ExprKind::Call(fn_expr, args) - } - - fn expr_std_path( - &mut self, - span: Span, - components: &[Symbol], - params: Option<&'hir hir::GenericArgs<'hir>>, - attrs: AttrVec, - ) -> hir::Expr<'hir> { - let path = self.std_path(span, components, params, true); - self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs) + self.arena.alloc(self.expr(fn_span, hir::ExprKind::Path(fn_path), ThinVec::new())); + self.expr_call(call_span, fn_expr, args) } pub(super) fn expr_ident( diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 2025d0c1c8e34..b90414294f246 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -1098,7 +1098,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; - let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None); + let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span); // Construct a parameter representing `__argN: ` to replace the parameter of the // async function. @@ -1189,7 +1189,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Transform into `drop-temps { }`, an expression: let desugared_span = - this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); + this.mark_span_with_reason(DesugaringKind::Async, user_body.span); let user_body = this.expr_drop_temps( desugared_span, this.arena.alloc(user_body), diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 284ede3b4fa1a..1a382d02f9c4d 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -40,12 +40,12 @@ use rustc::hir::map::Map; use rustc::{bug, span_bug}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX}; use rustc_hir::intravisit; +use rustc_hir::lang_item::LangItem; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::IndexVec; use rustc_session::config::nightly_options; @@ -54,7 +54,7 @@ use rustc_session::node_id::NodeMap; use rustc_session::Session; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind}; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use syntax::ast; use syntax::ast::*; @@ -86,8 +86,6 @@ mod path; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; struct LoweringContext<'a, 'hir: 'a> { - crate_root: Option, - /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, @@ -163,9 +161,6 @@ struct LoweringContext<'a, 'hir: 'a> { current_hir_id_owner: Vec<(DefIndex, u32)>, item_local_id_counters: NodeMap, node_id_to_hir_id: IndexVec, - - allow_try_trait: Option>, - allow_gen_future: Option>, } pub trait Resolver { @@ -186,16 +181,6 @@ pub trait Resolver { /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; - /// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and - /// resolves it based on `is_value`. - fn resolve_str_path( - &mut self, - span: Span, - crate_root: Option, - components: &[Symbol], - ns: Namespace, - ) -> (ast::Path, Res); - fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; @@ -269,7 +254,6 @@ pub fn lower_crate<'a, 'hir>( let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); LoweringContext { - crate_root: sess.parse_sess.injected_crate_name.try_get().copied(), sess, resolver, nt_to_tokenstream, @@ -298,8 +282,6 @@ pub fn lower_crate<'a, 'hir>( lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), - allow_try_trait: Some([sym::try_trait][..].into()), - allow_gen_future: Some([sym::gen_future][..].into()), } .lower_crate(krate) } @@ -693,16 +675,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. - fn mark_span_with_reason( - &self, - reason: DesugaringKind, - span: Span, - allow_internal_unstable: Option>, - ) -> Span { - span.fresh_expansion(ExpnData { - allow_internal_unstable, - ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) - }) + fn mark_span_with_reason(&self, reason: DesugaringKind, span: Span) -> Span { + span.fresh_expansion(ExpnData::default( + ExpnKind::Desugaring(reason), + span, + self.sess.edition(), + )) } fn with_anonymous_lifetime_mode( @@ -1372,7 +1350,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // desugaring that explicitly states that we don't want to track that. // Not tracking it makes lints in rustc and clippy very fragile, as // frequently opened issues show. - let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); + let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span); let opaque_ty_def_index = self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap(); @@ -1801,7 +1779,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = output.span(); - let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); + let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span); let opaque_ty_def_index = self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap(); @@ -1972,24 +1950,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; // "" - let future_params = self.arena.alloc(hir::GenericArgs { + let future_args = self.arena.alloc(hir::GenericArgs { args: &[], bindings: arena_vec![self; self.output_ty_binding(span, output_ty)], parenthesized: false, }); - // ::std::future::Future - let future_path = - self.std_path(span, &[sym::future, sym::Future], Some(future_params), false); - - hir::GenericBound::Trait( - hir::PolyTraitRef { - trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() }, - bound_generic_params: &[], - span, - }, - hir::TraitBoundModifier::None, - ) + // ::std::future::Future + hir::GenericBound::LangItemTrait { + lang_item: LangItem::FutureTraitLangItem, + span, + hir_id: self.next_id(), + args: future_args, + } } fn lower_param_bound( @@ -2361,34 +2334,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(LangItem::ResultOk, span, field) } fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(LangItem::ResultErr, span, field) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], arena_vec![self; pat]) + let field = self.single_pat_field(span, pat); + self.pat_lang_item_variant(LangItem::OptionSome, span, field) } fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> { - self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], &[]) + self.pat_lang_item_variant(LangItem::OptionNone, span, &[]) } - fn pat_std_enum( + fn single_pat_field( &mut self, span: Span, - components: &[Symbol], - subpats: &'hir [&'hir hir::Pat<'hir>], - ) -> &'hir hir::Pat<'hir> { - let path = self.std_path(span, components, None, true); - let qpath = hir::QPath::Resolved(None, path); - let pt = if subpats.is_empty() { - hir::PatKind::Path(qpath) - } else { - hir::PatKind::TupleStruct(qpath, subpats, None) + pat: &'hir hir::Pat<'hir>, + ) -> &'hir [hir::FieldPat<'hir>] { + let field = hir::FieldPat { + hir_id: self.next_id(), + ident: Ident::new(sym::integer(0), span), + is_shorthand: false, + pat, + span, }; + arena_vec![self; field] + } + + fn pat_lang_item_variant( + &mut self, + lang_item: LangItem, + span: Span, + fields: &'hir [hir::FieldPat<'hir>], + ) -> &'hir hir::Pat<'hir> { + let qpath = hir::QPath::LangItem(lang_item, span); + let pt = hir::PatKind::Struct(qpath, fields, false); self.pat(span, pt) } @@ -2422,42 +2408,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span }) } - /// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when - /// `fld.cx.use_std`, and `::core::b::c::d` otherwise. - /// The path is also resolved according to `is_value`. - fn std_path( - &mut self, - span: Span, - components: &[Symbol], - params: Option<&'hir hir::GenericArgs<'hir>>, - is_value: bool, - ) -> &'hir hir::Path<'hir> { - let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS }; - let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns); - - let mut segments: Vec<_> = path - .segments - .iter() - .map(|segment| { - let res = self.expect_full_res(segment.id); - hir::PathSegment { - ident: segment.ident, - hir_id: Some(self.lower_node_id(segment.id)), - res: Some(self.lower_res(res)), - infer_args: true, - args: None, - } - }) - .collect(); - segments.last_mut().unwrap().args = params; - - self.arena.alloc(hir::Path { - span, - res: res.map_id(|_| panic!("unexpected `NodeId`")), - segments: self.arena.alloc_from_iter(segments), - }) - } - fn ty_path( &mut self, mut hir_id: hir::HirId, diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index b62a7e413e303..d5ae39dd8004c 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2,6 +2,7 @@ use crate::def::{DefKind, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::itemlikevisit; +use crate::lang_item::LangItem; use crate::print; crate use BlockCheckMode::*; @@ -13,7 +14,7 @@ use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_errors::FatalError; use rustc_macros::HashStable_Generic; use rustc_session::node_id::NodeMap; -use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; @@ -374,21 +375,38 @@ pub enum TraitBoundModifier { #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), + /// A trait bound that refers to a lang item trait. Used in HIR lowering to + /// defer resolution of trait bounds until typeck. + LangItemTrait { + lang_item: LangItem, + span: Span, + /// This is an `HirId` that identifies this bound, not the `HirId` of the lang item. + hir_id: HirId, + args: &'hir GenericArgs<'hir>, + }, Outlives(Lifetime), } +pub trait RequireLangItem { + fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId; +} + impl GenericBound<'_> { - pub fn trait_def_id(&self) -> Option { - match self { - GenericBound::Trait(data, _) => Some(data.trait_ref.trait_def_id()), + pub fn trait_def_id(&self, tcx: impl RequireLangItem) -> Option { + match *self { + GenericBound::Trait(ref data, _) => Some(data.trait_ref.trait_def_id()), + GenericBound::LangItemTrait { lang_item, span, .. } => { + Some(tcx.require_lang_item(lang_item, span)) + } _ => None, } } pub fn span(&self) -> Span { - match self { - &GenericBound::Trait(ref t, ..) => t.span, - &GenericBound::Outlives(ref l) => l.span, + match *self { + GenericBound::Trait(ref t, ..) => t.span, + GenericBound::Outlives(ref l) => l.span, + GenericBound::LangItemTrait { span, .. } => span, } } } @@ -1402,6 +1420,7 @@ impl Expr<'_> { // Partially qualified paths in expressions can only legally // refer to associated items which are always rvalues. ExprKind::Path(QPath::TypeRelative(..)) + | ExprKind::Path(QPath::LangItem(..)) | ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Struct(..) @@ -1457,64 +1476,29 @@ impl fmt::Debug for Expr<'_> { /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). -/// -/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`, -/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`. -pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool { - // Returns whether the given path represents a (desugared) range, - // either in std or core, i.e. has either a `::std::ops::Range` or - // `::core::ops::Range` prefix. - fn is_range_path(path: &Path<'_>) -> bool { - let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect(); - let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect(); - - // "{{root}}" is the equivalent of `::` prefix in `Path`. - if let ["{{root}}", std_core, "ops", range] = segs.as_slice() { - (*std_core == "std" || *std_core == "core") && range.starts_with("Range") - } else { - false - } - }; - - // Check whether a span corresponding to a range expression is a - // range literal, rather than an explicit struct or `new()` call. - fn is_lit(sm: &SourceMap, span: &Span) -> bool { - let end_point = sm.end_point(*span); - - if let Ok(end_string) = sm.span_to_snippet(end_point) { - !(end_string.ends_with("}") || end_string.ends_with(")")) - } else { - false - } - }; - +pub fn is_range_literal(expr: &Expr<'_>) -> bool { match expr.kind { - // All built-in range literals but `..=` and `..` desugar to `Struct`s. - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && is_lit(sm, &expr.span); - } - } - - // `..` desugars to its struct path. - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_lit(sm, &expr.span); - } + // All built-in range literals but `..=` desugar to `Struct`s. + ExprKind::Struct(ref qpath, _, _) => match **qpath { + QPath::LangItem(LangItem::Range, _) + | QPath::LangItem(LangItem::RangeTo, _) + | QPath::LangItem(LangItem::RangeFrom, _) + | QPath::LangItem(LangItem::RangeFull, _) + | QPath::LangItem(LangItem::RangeToInclusive, _) => true, + _ => false, + }, // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { - if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { - let new_call = segment.ident.name == sym::new; - return is_range_path(&path) && is_lit(sm, &expr.span) && new_call; - } + if let ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)) = func.kind { + true + } else { + false } } - _ => {} + _ => false, } - - false } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] @@ -1647,6 +1631,11 @@ pub enum QPath<'hir> { /// `::new`, and `T::X::Y::method` into `<<::X>::Y>::method`, /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`. TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>), + + /// A reference to a `#[lang = "foo"]` item. + /// This is matched up with the corresponding `DefId` lazily. + /// Any generic args are inferred. + LangItem(LangItem, Span), } /// Hints at the original code for a let statement. diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 539a0eee0e312..7bc01636f0991 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -698,6 +698,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( visitor.visit_ty(qself); visitor.visit_path_segment(span, segment); } + QPath::LangItem(..) => {} } } @@ -812,6 +813,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB GenericBound::Trait(ref typ, modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } + GenericBound::LangItemTrait { span, args, hir_id, .. } => { + visitor.visit_id(hir_id); + visitor.visit_generic_args(span, args); + } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), } } diff --git a/src/librustc_hir/lang_item.rs b/src/librustc_hir/lang_item.rs new file mode 100644 index 0000000000000..1a296f7dc3921 --- /dev/null +++ b/src/librustc_hir/lang_item.rs @@ -0,0 +1,362 @@ +//! 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::*; + +use crate::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_macros::HashStable_Generic; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; +use syntax::ast; + +use std::fmt; + +/// All the locations that a `#[lang = ""]` attribute is valid on. +/// The variant names correspond to the variants in `DefKind`. +#[derive(Copy, Clone, PartialEq)] +pub enum Location { + Enum, + Fn, + Impl, + Method, + Static, + Struct, + Trait, + Union, + Variant, +} + +impl fmt::Display for Location { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Enum => "enum", + Self::Fn => "function", + Self::Impl => "implementation", + Self::Method => "method", + Self::Static => "static item", + Self::Struct => "struct", + Self::Trait => "trait", + Self::Union => "union", + Self::Variant => "variant", + }) + } +} + +macro_rules! enum_from_u32 { + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident = $e:expr,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant = $e),* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + }; + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant,)* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + } +} + +// The actual lang items defined come at the end of this file in one handy table. +// So you probably just want to nip down to the end. +macro_rules! language_item_table { + ( + $( $variant:ident, $name:expr, $method:ident, $location:path; )* + ) => { + +enum_from_u32! { + /// A representation of all the valid language items in Rust. + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[derive(HashStable_Generic, RustcEncodable, RustcDecodable)] + pub enum LangItem { + $($variant,)* + } +} + +impl LangItem { + /// Returns the `name` in `#[lang = "$name"]`. + /// For example, `LangItem::EqTraitLangItem`, + /// that is `#[lang = "eq"]` would result in `"eq"`. + pub fn name(self) -> &'static str { + match self { + $( $variant => $name, )* + } + } + + /// Returns the `Location` where the lang item may be attached. + pub fn location(self) -> Location { + match self { + $( $variant => $location, )* + } + } + + /// Get a mapping from the name of the lang item to its index and + /// the form it must be of. + pub fn table() -> FxHashMap<&'static str, (usize, Location)> { + let mut item_refs = FxHashMap::default(); + + $( item_refs.insert($name, ($variant as usize, $location)); )* + + item_refs + } +} + +#[derive(HashStable_Generic, Debug)] +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 { + /// Construct an empty collection of lang items and no missing ones. + pub fn new() -> Self { + fn init_none(_: LangItem) -> Option { None } + + 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 corresponding `DefId` for the lang item + #[doc = $name] + /// if it exists. + #[allow(dead_code)] + pub fn $method(&self) -> Option { + self.items[$variant as usize] + } + )* +} + +/// Extracts 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)> { + attrs.iter().find_map(|attr| { + Some(match attr { + _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span), + _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span), + _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span), + _ => return None, + }) + }) +} + +// End of the macro + } +} + +language_item_table! { +// Variant name, Name, Method name, Location; + BoolImplItem, "bool", bool_impl, Location::Impl; + CharImplItem, "char", char_impl, Location::Impl; + StrImplItem, "str", str_impl, Location::Impl; + SliceImplItem, "slice", slice_impl, Location::Impl; + SliceU8ImplItem, "slice_u8", slice_u8_impl, Location::Impl; + StrAllocImplItem, "str_alloc", str_alloc_impl, Location::Impl; + SliceAllocImplItem, "slice_alloc", slice_alloc_impl, Location::Impl; + SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl, Location::Impl; + ConstPtrImplItem, "const_ptr", const_ptr_impl, Location::Impl; + MutPtrImplItem, "mut_ptr", mut_ptr_impl, Location::Impl; + I8ImplItem, "i8", i8_impl, Location::Impl; + I16ImplItem, "i16", i16_impl, Location::Impl; + I32ImplItem, "i32", i32_impl, Location::Impl; + I64ImplItem, "i64", i64_impl, Location::Impl; + I128ImplItem, "i128", i128_impl, Location::Impl; + IsizeImplItem, "isize", isize_impl, Location::Impl; + U8ImplItem, "u8", u8_impl, Location::Impl; + U16ImplItem, "u16", u16_impl, Location::Impl; + U32ImplItem, "u32", u32_impl, Location::Impl; + U64ImplItem, "u64", u64_impl, Location::Impl; + U128ImplItem, "u128", u128_impl, Location::Impl; + UsizeImplItem, "usize", usize_impl, Location::Impl; + F32ImplItem, "f32", f32_impl, Location::Impl; + F64ImplItem, "f64", f64_impl, Location::Impl; + F32RuntimeImplItem, "f32_runtime", f32_runtime_impl, Location::Impl; + F64RuntimeImplItem, "f64_runtime", f64_runtime_impl, Location::Impl; + + SizedTraitLangItem, "sized", sized_trait, Location::Trait; + // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ"). + StructuralPeqTraitLangItem, "structural_peq", structural_peq_trait, Location::Trait; + // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize). + StructuralTeqTraitLangItem, "structural_teq", structural_teq_trait, Location::Trait; + UnsizeTraitLangItem, "unsize", unsize_trait, Location::Trait; + CopyTraitLangItem, "copy", copy_trait, Location::Trait; + CloneTraitLangItem, "clone", clone_trait, Location::Trait; + SyncTraitLangItem, "sync", sync_trait, Location::Trait; + FreezeTraitLangItem, "freeze", freeze_trait, Location::Trait; + + DropTraitLangItem, "drop", drop_trait, Location::Trait; + + CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Location::Trait; + DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Location::Trait; + + AddTraitLangItem, "add", add_trait, Location::Trait; + SubTraitLangItem, "sub", sub_trait, Location::Trait; + MulTraitLangItem, "mul", mul_trait, Location::Trait; + DivTraitLangItem, "div", div_trait, Location::Trait; + RemTraitLangItem, "rem", rem_trait, Location::Trait; + NegTraitLangItem, "neg", neg_trait, Location::Trait; + NotTraitLangItem, "not", not_trait, Location::Trait; + BitXorTraitLangItem, "bitxor", bitxor_trait, Location::Trait; + BitAndTraitLangItem, "bitand", bitand_trait, Location::Trait; + BitOrTraitLangItem, "bitor", bitor_trait, Location::Trait; + ShlTraitLangItem, "shl", shl_trait, Location::Trait; + ShrTraitLangItem, "shr", shr_trait, Location::Trait; + AddAssignTraitLangItem, "add_assign", add_assign_trait, Location::Trait; + SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Location::Trait; + MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Location::Trait; + DivAssignTraitLangItem, "div_assign", div_assign_trait, Location::Trait; + RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Location::Trait; + BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Location::Trait; + BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Location::Trait; + BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Location::Trait; + ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Location::Trait; + ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Location::Trait; + IndexTraitLangItem, "index", index_trait, Location::Trait; + IndexMutTraitLangItem, "index_mut", index_mut_trait, Location::Trait; + + UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Location::Struct; + VaListTypeLangItem, "va_list", va_list, Location::Struct; + + DerefTraitLangItem, "deref", deref_trait, Location::Trait; + DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Location::Trait; + ReceiverTraitLangItem, "receiver", receiver_trait, Location::Trait; + + FnTraitLangItem, "fn", fn_trait, Location::Trait; + FnMutTraitLangItem, "fn_mut", fn_mut_trait, Location::Trait; + FnOnceTraitLangItem, "fn_once", fn_once_trait, Location::Trait; + + FutureTraitLangItem, "future_trait", future_trait, Location::Trait; + GeneratorStateLangItem, "generator_state", gen_state, Location::Enum; + GeneratorTraitLangItem, "generator", gen_trait, Location::Trait; + UnpinTraitLangItem, "unpin", unpin_trait, Location::Trait; + PinTypeLangItem, "pin", pin_type, Location::Struct; + + EqTraitLangItem, "eq", eq_trait, Location::Trait; + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Location::Trait; + OrdTraitLangItem, "ord", ord_trait, Location::Trait; + + // A number of panic-related lang items. The `panic` item corresponds to + // divide-by-zero and various panic cases with `match`. The + // `panic_bounds_check` item is for indexing arrays. + // + // The `begin_unwind` lang item has a predefined symbol name and is sort of + // a "weak lang item" in the sense that a crate is not required to have it + // defined to use it, but a final product is required to define it + // somewhere. Additionally, there are restrictions on crates that use a weak + // lang item, but do not have it defined. + PanicFnLangItem, "panic", panic_fn, Location::Fn; + PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Location::Fn; + PanicInfoLangItem, "panic_info", panic_info, Location::Struct; + PanicLocationLangItem, "panic_location", panic_location, Location::Struct; + PanicImplLangItem, "panic_impl", panic_impl, Location::Fn; + // Libstd panic entry point. Necessary for const eval to be able to catch it + BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Location::Fn; + + ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn, Location::Fn; + BoxFreeFnLangItem, "box_free", box_free_fn, Location::Fn; + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn, Location::Fn; + OomLangItem, "oom", oom, Location::Fn; + AllocLayoutLangItem, "alloc_layout", alloc_layout, Location::Struct; + + StartFnLangItem, "start", start_fn, Location::Fn; + + EhPersonalityLangItem, "eh_personality", eh_personality, Location::Fn; + EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Location::Fn; + EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Location::Static; + + OwnedBoxLangItem, "owned_box", owned_box, Location::Struct; + + PhantomDataItem, "phantom_data", phantom_data, Location::Struct; + + ManuallyDropItem, "manually_drop", manually_drop, Location::Struct; + + MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Location::Union; + + // Align offset for stride != 1; must not panic. + AlignOffsetLangItem, "align_offset", align_offset_fn, Location::Fn; + + TerminationTraitLangItem, "termination", termination, Location::Trait; + + Arc, "arc", arc, Location::Struct; + Rc, "rc", rc, Location::Struct; + + // Things used in lowering. + + // Range expressions: + RangeInclusiveNew, "range_inclusive", range_inclusive_fn, Location::Method; + Range, "range", range, Location::Struct; + RangeFrom, "range_from", range_from, Location::Struct; + RangeTo, "range_to", range_to, Location::Struct; + RangeFull, "range_full", range_full, Location::Struct; + RangeToInclusive, "range_to_inclusive", range_to_inclusive, Location::Struct; + + // For loops: + IntoIter, "into_iter", into_iter, Location::Method; + IterNext, "iter_next", iter_next, Location::Method; + OptionSome, "option_some", option_some, Location::Variant; + OptionNone, "option_none", option_none, Location::Variant; + + // `?` and `try { }` + TryFromOk, "try_from_ok", try_from_ok, Location::Method; + TryFromError, "try_from_error", try_from_error, Location::Method; + TryIntoResult, "try_into_result", try_into_result, Location::Method; + FromMethod, "from_method", from_method, Location::Method; + ResultOk, "result_ok", result_ok, Location::Variant; + ResultErr, "result_err", result_err, Location::Variant; + + // `async` (also uses FutureTraitLangItem) + FromGenerator, "from_generator", from_generator, Location::Fn; + + // `.await` + PollWithTlsContext, "poll_with_context", poll_with_context, Location::Fn; + PinNewUnchecked, "pin_new_unchecked", pin_new_unchecked, Location::Method; + PollReady, "poll_ready", poll_ready, Location::Variant; + PollPending, "poll_pending", poll_pending, Location::Variant; +} diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs index f54fa291bd6e8..248f1bc68be75 100644 --- a/src/librustc_hir/lib.rs +++ b/src/librustc_hir/lib.rs @@ -17,6 +17,7 @@ mod hir; pub mod hir_id; pub mod intravisit; pub mod itemlikevisit; +pub mod lang_item; pub mod pat_util; pub mod print; mod stable_hash_impls; diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index b9598c9376146..7a91770240d26 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -1562,6 +1562,11 @@ impl<'a> State<'a> { colons_before_params, ) } + hir::QPath::LangItem(lang_item, _) => { + self.s.word("(#[lang = \""); + self.s.word(lang_item.name()); + self.s.word("\"])"); + } } } @@ -1974,6 +1979,12 @@ impl<'a> State<'a> { } self.print_poly_trait_ref(tref); } + GenericBound::LangItemTrait { lang_item, args, .. } => { + self.s.word("(#[lang = \""); + self.s.word(lang_item.name()); + self.s.word("\"])"); + self.print_generic_args(args, false, true); + } GenericBound::Outlives(lt) => { self.print_lifetime(lt); } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c8d3d5f9c83d8..aaef731e39482 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1077,6 +1077,7 @@ impl TypeAliasBounds { } } hir::QPath::Resolved(..) => false, + hir::QPath::LangItem(..) => false, } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 674a82b61961c..091ef4358f7db 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -260,7 +260,7 @@ fn lint_int_literal<'a, 'tcx>( let par_id = cx.tcx.hir().get_parent_node(e.hir_id); if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { if let hir::ExprKind::Struct(..) = par_e.kind { - if is_range_literal(cx.sess().source_map(), par_e) + if is_range_literal(par_e) && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) { // The overflowing literal lint was overridden. @@ -312,7 +312,7 @@ fn lint_uint_literal<'a, 'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => { + hir::ExprKind::Struct(..) if is_range_literal(par_e) => { let t = t.name_str(); if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { // The overflowing literal lint was overridden. diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index b84616142cb07..7003042cb54a2 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -40,7 +40,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx ), ty::InstanceDef::FnPtrShim(def_id, ty) => { let trait_ = tcx.trait_of_item(def_id).unwrap(); - let adjustment = match tcx.lang_items().fn_trait_kind(trait_) { + let adjustment = match tcx.fn_trait_kind(trait_) { Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, Some(ty::ClosureKind::FnMut) | Some(ty::ClosureKind::Fn) => Adjustment::Deref, None => bug!("fn pointer {:?} is not an fn", ty), diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 7718139f6e924..3ab0c4bc49696 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -536,8 +536,9 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Box(..) | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) - | hir::ExprKind::Err - | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { + | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) + | hir::ExprKind::Path(hir::QPath::LangItem(..)) + | hir::ExprKind::Err => { intravisit::walk_expr(ir, expr); } } @@ -1186,6 +1187,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Lit(..) | hir::ExprKind::Err + | hir::ExprKind::Path(hir::QPath::LangItem(..)) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => succ, // Note that labels have been resolved, so we don't need to look diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 60bf271d2d2a8..bccce63e87145 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1312,6 +1312,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { let name = match *qpath { hir::QPath::Resolved(_, ref path) => path.to_string(), hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(), + hir::QPath::LangItem(li, _) => li.name().to_string(), }; let msg = format!("{} `{}` is private", kind.descr(def_id), name); self.tcx.sess.span_err(span, &msg); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0e6f40fa8466a..bb715ac5d2a41 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1036,37 +1036,6 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } - fn resolve_str_path( - &mut self, - span: Span, - crate_root: Option, - components: &[Name], - ns: Namespace, - ) -> (ast::Path, Res) { - let root = if crate_root.is_some() { kw::PathRoot } else { kw::Crate }; - let segments = iter::once(Ident::with_dummy_span(root)) - .chain( - crate_root - .into_iter() - .chain(components.iter().cloned()) - .map(Ident::with_dummy_span), - ) - .map(|i| self.new_ast_path_segment(i)) - .collect::>(); - - let path = ast::Path { span, segments }; - - let parent_scope = &ParentScope::module(self.graph_root); - let res = match self.resolve_ast_path(&path, ns, parent_scope) { - Ok(res) => res, - Err((span, error)) => { - self.report_error(span, error); - Res::Err - } - }; - (path, res) - } - fn get_partial_res(&mut self, id: NodeId) -> Option { self.partial_res_map.get(&id).cloned() } diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs index 6e9ed5fdc179c..e329f6bbb549d 100644 --- a/src/librustc_resolve/lifetimes.rs +++ b/src/librustc_resolve/lifetimes.rs @@ -946,6 +946,24 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { + match bound { + hir::GenericBound::LangItemTrait { .. } if !self.trait_ref_hack => { + let scope = Scope::Binder { + lifetimes: FxHashMap::default(), + s: self.scope, + next_early_index: self.next_early_index(), + track_lifetime_uses: true, + opaque_type_parent: false, + }; + self.with(scope, |_, this| { + intravisit::walk_param_bound(this, bound); + }); + } + _ => intravisit::walk_param_bound(self, bound), + } + } + fn visit_poly_trait_ref( &mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>, @@ -2295,6 +2313,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { intravisit::walk_generic_param(self, param); } + fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) { + if let hir::GenericBound::LangItemTrait { .. } = bound { + self.outer_index.shift_in(1); + intravisit::walk_param_bound(self, bound); + self.outer_index.shift_out(1); + } else { + intravisit::walk_param_bound(self, bound); + } + } + fn visit_poly_trait_ref( &mut self, trait_ref: &hir::PolyTraitRef<'_>, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 89eeed8d11ebc..81a842032df13 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -27,6 +27,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; +use rustc_hir::lang_item::LangItem; use rustc_hir::print; use rustc_hir::{ExprKind, GenericArg, GenericArgs}; use rustc_span::symbol::sym; @@ -195,16 +196,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, span: Span, def_id: DefId, - item_segment: &hir::PathSegment<'_>, + generic_args: &GenericArgs<'_>, + infer_args: bool, ) -> SubstsRef<'tcx> { - let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( - span, - def_id, - &[], - item_segment.generic_args(), - item_segment.infer_args, - None, - ); + let (substs, assoc_bindings, _) = + self.create_substs_for_ast_path(span, def_id, &[], generic_args, infer_args, None); assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span)); @@ -1011,6 +1007,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } + pub fn instantiate_lang_item_trait_ref( + &self, + lang_item: LangItem, + span: Span, + hir_id: hir::HirId, + args: &GenericArgs<'_>, + self_ty: Ty<'tcx>, + bounds: &mut Bounds<'tcx>, + ) { + let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); + let (substs, assoc_bindings, _) = + self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty)); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + let mut dup_bindings = FxHashMap::default(); + bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); + for binding in assoc_bindings { + // Specify type to assert that error was already reported in `Err` case. + let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding( + hir_id, + poly_trait_ref, + &binding, + bounds, + false, + &mut dup_bindings, + span, + ); + // Okay to ignore `Err` because of `ErrorReported` (see above). + } + } + fn ast_path_to_mono_trait_ref( &self, span: Span, @@ -1197,6 +1223,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds.push((b, Constness::NotConst)) } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} + hir::GenericBound::LangItemTrait { lang_item, span, hir_id, args } => { + self.instantiate_lang_item_trait_ref( + lang_item, span, hir_id, args, param_ty, bounds, + ); + } hir::GenericBound::Outlives(ref l) => region_bounds.push(l), } } @@ -1411,7 +1442,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { did: DefId, item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { - let substs = self.ast_path_substs_for_ty(span, did, item_segment); + let substs = self.ast_path_substs_for_ty( + span, + did, + item_segment.generic_args(), + item_segment.infer_args, + ); self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) } @@ -2521,7 +2557,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(ty::is_impl_trait_defn(tcx, did).is_none()); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1); - let substs = self.ast_path_substs_for_ty(span, did, item_segment.0); + let substs = self.ast_path_substs_for_ty( + span, + did, + item_segment.0.generic_args(), + item_segment.0.infer_args, + ); self.normalize_ty(span, tcx.mk_opaque(did, substs)) } Res::Def(DefKind::Enum, did) @@ -2657,6 +2698,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|(ty, _, _)| ty) .unwrap_or(tcx.types.err) } + hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { + let tcx = self.tcx(); + let span = ast_ty.span; + let def_id = tcx.require_lang_item(lang_item, Some(span)); + let substs = self.ast_path_substs_for_ty(span, def_id, &GenericArgs::none(), true); + self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) + } hir::TyKind::Array(ref ty, ref length) => { let length = self.ast_const_to_const(length, tcx.types.usize); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 084e6c8d083c5..bfc05af961898 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -168,9 +168,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.deduce_sig_from_projection(None, &pb) }) .next(); - let kind = object_type - .principal_def_id() - .and_then(|did| self.tcx.lang_items().fn_trait_kind(did)); + let kind = + object_type.principal_def_id().and_then(|did| self.tcx.fn_trait_kind(did)); (sig, kind) } ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), @@ -208,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // many viable options, so pick the most restrictive. let expected_kind = self .obligations_for_self_ty(expected_vid) - .filter_map(|(tr, _)| self.tcx.lang_items().fn_trait_kind(tr.def_id())) + .filter_map(|(tr, _)| self.tcx.fn_trait_kind(tr.def_id())) .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); (expected_sig, expected_kind) @@ -231,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_ref = projection.to_poly_trait_ref(tcx); - let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some(); + let is_fn = tcx.fn_trait_kind(trait_ref.def_id()).is_some(); let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem, cause_span); let is_gen = gen_trait == trait_ref.def_id(); if !is_fn && !is_gen { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 54b32c3a50fcd..be2b5cf1cc0e2 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1403,7 +1403,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { { // Are of this `impl Trait`'s traits object safe? is_object_safe = bounds.iter().all(|bound| { - bound.trait_def_id().map_or(false, |def_id| { + bound.trait_def_id(fcx.tcx).map_or(false, |def_id| { object_safety_violations(fcx.tcx, def_id).is_empty() }) }) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index e0f9fcc69325c..113607ad206ec 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(self.tcx.sess.source_map(), expr) => true, + _ if is_range_literal(expr) => true, _ => false, }; let sugg_expr = if needs_parens { format!("({})", src) } else { src }; diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index b4c2b85241f96..3e5bd682e2137 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -31,6 +31,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::lang_item::LangItem; use rustc_hir::{ExprKind, QPath}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; @@ -229,6 +230,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, ref oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } + ExprKind::Path(QPath::LangItem(lang_item, _)) => { + self.check_lang_item_path(lang_item, expr) + } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr), ExprKind::InlineAsm(ref asm) => { for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) { @@ -466,6 +470,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_lang_item_path(&self, lang_item: LangItem, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { + self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 + } + fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span); @@ -1100,6 +1108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let path_span = match *qpath { QPath::Resolved(_, ref path) => path.span, QPath::TypeRelative(ref qself, _) => qself.span, + QPath::LangItem(_, span) => span, }; // Prohibit struct expressions when non-exhaustive flag is set. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2dc198b6d9695..27e3059a844fb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -112,8 +112,8 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts}; use rustc::ty::util::{Discr, IntTypeExt, Representability}; use rustc::ty::{ - self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, WithConstness, + self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, RegionKind, + ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType, WithConstness, }; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -123,6 +123,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::lang_item::LangItem; use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; use rustc_index::vec::Idx; use rustc_span::hygiene::DesugaringKind; @@ -4201,6 +4202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let path_span = match *qpath { QPath::Resolved(_, ref path) => path.span, QPath::TypeRelative(ref qself, _) => qself.span, + QPath::LangItem(_, span) => span, }; let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); let variant = match def { @@ -4282,9 +4284,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) } + QPath::LangItem(lang_item, _) => { + self.resolve_lang_item_path(lang_item, path_span, hir_id) + } } } + fn resolve_lang_item_path( + &self, + lang_item: LangItem, + span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self + .tcx + .def_kind(def_id) + .expect("Lang item path used for lang item without a DefKind."); + let item_ty = if let DefKind::Variant = def_kind { + self.tcx.type_of(self.tcx.parent(def_id).expect("variant without a parent")) + } else { + self.tcx.type_of(def_id) + }; + let substs = self.infcx.fresh_substs_for_item(span, def_id); + self.write_resolution(hir_id, Ok((def_kind, def_id))); + let ty = item_ty.subst(self.tcx, substs); + self.add_required_obligations(span, def_id, &substs); + (Res::Def(def_kind, def_id), ty) + } + /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. pub fn resolve_ty_and_res_ufcs<'b>( @@ -4303,6 +4331,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::LangItem(..) => bug!("resolve_ty_and_res_ufcs called on LangItem path"), }; if let Some(&cached_result) = self.tables.borrow().type_dependent_defs().get(hir_id) { // Return directly on cache hit. This is useful to avoid doubly reporting diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index f9dee0e477f79..c09c7a039fdb5 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -835,6 +835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let qpath_span = match qpath { hir::QPath::Resolved(_, path) => path.span, hir::QPath::TypeRelative(_, ps) => ps.ident.span, + hir::QPath::LangItem(_, span) => *span, }; (qpath_span.shrink_to_hi(), pat_span) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 843872d0ff99a..669281c36bde3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2350,6 +2350,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat predicates.extend(bounds.predicates(tcx, ty)); } + &hir::GenericBound::LangItemTrait { lang_item, span, hir_id, args } => { + let mut bounds = Bounds::default(); + AstConv::instantiate_lang_item_trait_ref( + &icx, + lang_item, + span, + hir_id, + args, + ty, + &mut bounds, + ); + predicates.extend(bounds.predicates(tcx, ty)); + } + &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region)); @@ -2533,6 +2547,18 @@ fn predicates_from_bound<'tcx>( let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); bounds.predicates(astconv.tcx(), param_ty) } + hir::GenericBound::LangItemTrait { lang_item, span, hir_id, args } => { + let mut bounds = Bounds::default(); + astconv.instantiate_lang_item_trait_ref( + lang_item, + span, + hir_id, + args, + param_ty, + &mut bounds, + ); + bounds.predicates(astconv.tcx(), param_ty) + } hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7a7d69c68a585..2d6a8f82e5c73 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1480,6 +1480,9 @@ impl Clean for hir::Ty<'_> { trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id), } } + TyKind::Path(hir::QPath::LangItem(..)) => { + panic!("Shouldn't have to document lang items") + } TyKind::TraitObject(ref bounds, ref lifetime) => { match bounds[0].clean(cx).trait_ { ResolvedPath { path, param_names: None, did, is_generic } => { @@ -1978,6 +1981,61 @@ impl Clean for hir::PathSegment<'_> { } } +fn strip_type(ty: Type) -> Type { + match ty { + Type::ResolvedPath { path, param_names, did, is_generic } => { + Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic } + } + Type::Tuple(inner_tys) => { + Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) + } + Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), + Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), + Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))), + Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), + Type::BorrowedRef { lifetime, mutability, type_ } => { + Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } + } + Type::QPath { name, self_type, trait_ } => Type::QPath { + name, + self_type: Box::new(strip_type(*self_type)), + trait_: Box::new(strip_type(*trait_)), + }, + _ => ty, + } +} + +fn strip_path(path: &Path) -> Path { + let segments = path + .segments + .iter() + .map(|s| PathSegment { + name: s.name.clone(), + args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] }, + }) + .collect(); + + Path { global: path.global, res: path.res.clone(), segments } +} + +fn qpath_to_string(p: &hir::QPath) -> String { + let segments = match *p { + hir::QPath::Resolved(_, ref path) => &path.segments, + hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(), + hir::QPath::LangItem(li, _) => return li.name().to_string(), + }; + + let mut s = String::new(); + for (i, seg) in segments.iter().enumerate() { + if i > 0 { + s.push_str("::"); + } + if seg.ident.name != keywords::PathRoot.name() { + s.push_str(&*seg.ident.as_str()); + } + } +} + impl Clean for Ident { #[inline] fn clean(&self, cx: &DocContext<'_>) -> String { diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 9c7422c2b20a6..ff2f53e703445 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -18,6 +18,7 @@ pub use core::future::*; /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[cfg_attr(not(bootstrap), lang = "from_generator")] pub fn from_generator>(x: T) -> impl Future { GenFuture(x) } @@ -72,6 +73,7 @@ unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop { #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[cfg_attr(not(bootstrap), lang = "poll_with_context")] /// Polls a future in the current thread-local task waker. pub fn poll_with_tls_context(f: Pin<&mut F>) -> Poll where diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs new file mode 100644 index 0000000000000..7cd1c41f18cfd --- /dev/null +++ b/src/test/ui/hygiene/hir-res-hygiene.rs @@ -0,0 +1,19 @@ +// Make sure that paths created in HIR are not affected by in scope names. + +// check-pass +// edition:2018 +// aux-build:not-libstd.rs + +extern crate not_libstd as std; + +async fn the_future() { + async {}.await; +} + +fn main() -> Result<(), ()> { + for i in 0..10 {} + for j in 0..=10 {} + Ok(())?; + Ok(()) +} + diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 05009358106fa..bb8c7c2128d85 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -17,10 +17,14 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi | LL | let range = *arr..; | ^^^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/libcore/ops/range.rs:LL:COL + | +LL | pub struct RangeFrom { + | --- required by this bound in `std::ops::RangeFrom` | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` = note: to learn more, visit - = note: required by `std::ops::RangeFrom` error: aborting due to 3 previous errors