diff options
Diffstat (limited to 'compiler/rustc_middle')
75 files changed, 2554 insertions, 1355 deletions
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a2b78cc29..5b2ec9029 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -26,8 +26,8 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } -rustc-rayon-core = { version = "0.4.0", optional = true } -rustc-rayon = { version = "0.4.0", optional = true } +rustc-rayon-core = { version = "0.5.0", optional = true } +rustc-rayon = { version = "0.5.0", optional = true } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_middle/locales/en-US.ftl b/compiler/rustc_middle/messages.ftl index 4f4e5c6a2..bd9d89dee 100644 --- a/compiler/rustc_middle/locales/en-US.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -16,6 +16,10 @@ middle_limit_invalid = `limit` must be a non-negative integer .label = {$error_str} +middle_recursion_limit_reached = + reached the recursion limit finding the struct tail for `{$ty}` + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` + middle_const_eval_non_int = constant evaluation of enum discriminant resulted in non-integer diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 62e44b629..dd1e254f4 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,7 +36,7 @@ macro_rules! arena_types { )>, [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>, [] metadata_loader: rustc_data_structures::steal::Steal<Box<rustc_session::cstore::MetadataLoaderDyn>>, - [] crate_for_resolver: rustc_data_structures::steal::Steal<rustc_ast::ast::Crate>, + [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, @@ -94,7 +94,8 @@ macro_rules! arena_types { [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, [decode] attribute: rustc_ast::Attribute, - [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>, + [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>, + [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>, [] hir_id_set: rustc_hir::HirIdSet, // Interned types @@ -107,6 +108,7 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>, + [decode] registered_tools: rustc_middle::ty::RegisteredTools, [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, @@ -117,6 +119,7 @@ macro_rules! arena_types { [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>), + [] mod_child: rustc_middle::metadata::ModChild, ]); ) } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 84510fe21..0ddbe7d1c 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -94,7 +94,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } #[inline] - fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dep_kind as usize] + fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { + &self.query_kinds[dk as usize] } } diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 5e94da8cb..dc4aa1864 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -50,6 +50,14 @@ pub struct LimitInvalid<'a> { } #[derive(Diagnostic)] +#[diag(middle_recursion_limit_reached)] +#[help] +pub struct RecursionLimitReached<'tcx> { + pub ty: Ty<'tcx>, + pub suggested_limit: rustc_session::Limit, +} + +#[derive(Diagnostic)] #[diag(middle_const_eval_non_int)] pub struct ConstEvalNonIntError { #[primary_span] diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 4b5bacac8..e551c76f8 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,13 +1,14 @@ use crate::hir::{ModuleItems, Owner}; -use crate::ty::{DefIdTree, TyCtxt}; +use crate::query::LocalCrate; +use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; use rustc_index::vec::Idx; @@ -73,18 +74,17 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { if self.current_id == CRATE_HIR_ID { return None; } - loop { - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.parent_id(self.current_id); - if parent_id == self.current_id { - self.current_id = CRATE_HIR_ID; - return None; - } + // There are nodes that do not have entries, so we need to skip them. + let parent_id = self.map.parent_id(self.current_id); - self.current_id = parent_id; - return Some(parent_id); + if parent_id == self.current_id { + self.current_id = CRATE_HIR_ID; + return None; } + + self.current_id = parent_id; + return Some(parent_id); } } @@ -179,7 +179,19 @@ impl<'hir> Map<'hir> { /// Do not call this function directly. The query should be called. pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> { let hir_id = self.local_def_id_to_hir_id(local_def_id); - let def_kind = match self.find(hir_id)? { + let node = match self.find(hir_id) { + Some(node) => node, + None => match self.def_key(local_def_id).disambiguated_data.data { + // FIXME: Some anonymous constants do not have corresponding HIR nodes, + // so many local queries will panic on their def ids. `None` is currently + // returned here instead of `DefKind::{Anon,Inline}Const` to avoid such panics. + // Ideally all def ids should have `DefKind`s, we need to create the missing + // HIR nodes or feed relevant query results to achieve that. + DefPathData::AnonConst => return None, + _ => bug!("no HIR node for def id {local_def_id:?}"), + }, + }; + let def_kind = match node { Node::Item(item) => match item.kind { ItemKind::Static(_, mt, _) => DefKind::Static(mt), ItemKind::Const(..) => DefKind::Const, @@ -187,7 +199,7 @@ impl<'hir> Map<'hir> { ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(ref opaque) => { - if opaque.in_trait { + if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { DefKind::ImplTraitPlaceholder } else { DefKind::OpaqueTy @@ -266,7 +278,10 @@ impl<'hir> Map<'hir> { | Node::Param(_) | Node::Arm(_) | Node::Lifetime(_) - | Node::Block(_) => return None, + | Node::Block(_) => span_bug!( + self.span(hir_id), + "unexpected node with def id {local_def_id:?}: {node:?}" + ), }; Some(def_kind) } @@ -316,7 +331,7 @@ impl<'hir> Map<'hir> { /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. #[inline] pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> { - self.find(self.local_def_id_to_hir_id(id)) + self.find(self.tcx.opt_local_def_id_to_hir_id(id)?) } /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. @@ -333,7 +348,7 @@ impl<'hir> Map<'hir> { } pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> { - id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id))) + id.as_local().and_then(|id| self.find(self.tcx.opt_local_def_id_to_hir_id(id)?)) } pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { @@ -1131,10 +1146,9 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - debug_assert_eq!(crate_num, LOCAL_CRATE); +pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { let krate = tcx.hir_crate(()); - let hir_body_hash = krate.hir_hash; + let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); let upstream_crates = upstream_crates(tcx); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index c9da711e5..7770a5e47 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -7,8 +7,7 @@ pub mod nested_filter; pub mod place; use crate::ty::query::Providers; -use crate::ty::{DefIdTree, ImplSubject, TyCtxt}; -use rustc_data_structures::fingerprint::Fingerprint; +use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -24,14 +23,15 @@ use rustc_span::{ExpnId, DUMMY_SP}; #[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: OwnerNode<'tcx>, - hash_without_bodies: Fingerprint, } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { node: _, hash_without_bodies } = self; - hash_without_bodies.hash_stable(hcx, hasher) + // Perform a shallow hash instead using the deep hash saved in `OwnerNodes`. This lets us + // differentiate queries that depend on the full HIR tree from those that only depend on + // the item signature. + hcx.without_hir_bodies(|hcx| self.node.hash_stable(hcx, hasher)); } } @@ -104,11 +104,11 @@ impl<'tcx> TyCtxt<'tcx> { self.parent_module_from_def_id(id.owner.def_id) } - pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> { - self.impl_trait_ref(def_id) - .map(|t| t.subst_identity()) - .map(ImplSubject::Trait) - .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id).subst_identity())) + pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<ImplSubject<'tcx>> { + match self.impl_trait_ref(def_id) { + Some(t) => t.map_bound(ImplSubject::Trait), + None => self.type_of(def_id).map_bound(ImplSubject::Inherent), + } } } @@ -123,7 +123,7 @@ pub fn provide(providers: &mut Providers) { providers.hir_owner = |tcx, id| { let owner = tcx.hir_crate(()).owners.get(id.def_id)?.as_owner()?; let node = owner.node(); - Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies }) + Some(Owner { node }) }; providers.opt_local_def_id_to_hir_id = |tcx, id| { let owner = tcx.hir_crate(()).owners[id].map(|_| ()); @@ -147,18 +147,18 @@ pub fn provide(providers: &mut Providers) { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) }; providers.def_ident_span = |tcx, def_id| { - let def_id = def_id.expect_local(); + let def_id = def_id; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) }; providers.fn_arg_names = |tcx, id| { let hir = tcx.hir(); - let def_id = id.expect_local(); + let def_id = id; let hir_id = hir.local_def_id_to_hir_id(def_id); if let Some(body_id) = hir.maybe_body_owned_by(def_id) { tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) @@ -176,13 +176,10 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id); } }; - providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); - providers.opt_rpitit_info = |_, _| None; + providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id); providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; - providers.expn_that_defined = |tcx, id| { - let id = id.expect_local(); - tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()) - }; + providers.expn_that_defined = + |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); providers.in_scope_traits_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map) }; diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 83d3b0100..80b4c964c 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -2,7 +2,7 @@ use crate::ty; use crate::ty::Ty; use rustc_hir::HirId; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] @@ -27,7 +27,7 @@ pub enum ProjectionKind { /// the field. The field is identified by which variant /// it appears in along with a field index. The variant /// is used for enums. - Field(u32, VariantIdx), + Field(FieldIdx, VariantIdx), /// Some index like `B[x]`, where `B` is the base /// expression. We don't preserve the index `x` because diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 7f8fc1774..b5b712c36 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -35,9 +35,9 @@ use std::ops::Index; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Canonical<'tcx, V> { + pub value: V, pub max_universe: ty::UniverseIndex, pub variables: CanonicalVarInfos<'tcx>, - pub value: V, } pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>; @@ -80,6 +80,18 @@ impl CanonicalVarValues<'_> { } }) } + + pub fn is_identity_modulo_regions(&self) -> bool { + self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => true, + ty::GenericArgKind::Type(ty) => { + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) + } + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) + } + }) + } } /// When we canonicalize a value to form a query, we wind up replacing @@ -149,15 +161,15 @@ impl<'tcx> CanonicalVarInfo<'tcx> { } } - pub fn expect_anon_placeholder(self) -> u32 { + pub fn expect_placeholder_index(self) -> usize { match self.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"), - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.name.expect_anon(), - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.name.expect_anon(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.name.as_u32(), + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.bound.as_usize(), } } } @@ -411,7 +423,7 @@ impl<'tcx> CanonicalVarValues<'tcx> { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(i), - kind: ty::BrAnon(i as u32, None), + kind: ty::BrAnon(None), }; tcx.mk_re_late_bound(ty::INNERMOST, br).into() } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 41d8c7ffd..a873854f0 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -1,4 +1,4 @@ -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Region, Ty, TyCtxt}; use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; @@ -11,7 +11,20 @@ pub trait ToType { } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>); +pub struct UnifiedRegion<'tcx> { + value: Option<ty::Region<'tcx>>, +} + +impl<'tcx> UnifiedRegion<'tcx> { + pub fn new(value: Option<Region<'tcx>>) -> Self { + Self { value } + } + + /// The caller is responsible for checking universe compatibility before using this value. + pub fn get_value_ignoring_universes(self) -> Option<Region<'tcx>> { + self.value + } +} #[derive(PartialEq, Copy, Clone, Debug)] pub struct RegionVidKey<'tcx> { @@ -44,11 +57,27 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { type Error = NoError; fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { - Ok(match (value1.0, value2.0) { + // We pick the value of the least universe because it is compatible with more variables. + // This is *not* necessary for soundness, but it allows more region variables to be + // resolved to the said value. + #[cold] + fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> { + cmp::min_by_key(r1, r2, |r| match r.kind() { + ty::ReStatic + | ty::ReErased + | ty::ReFree(..) + | ty::ReEarlyBound(..) + | ty::ReError(_) => ty::UniverseIndex::ROOT, + ty::RePlaceholder(placeholder) => placeholder.universe, + ty::ReVar(..) | ty::ReLateBound(..) => bug!("not a universal region"), + }) + } + + Ok(match (value1.value, value2.value) { // Here we can just pick one value, because the full constraints graph // will be handled later. Ideally, we might want a `MultipleValues` // variant or something. For now though, this is fine. - (Some(_), Some(_)) => *value1, + (Some(val1), Some(val2)) => Self { value: Some(min_universe(val1, val2)) }, (Some(_), _) => *value1, (_, Some(_)) => *value2, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index c33b9d84e..b4edb02f6 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -33,13 +33,13 @@ #![feature(generators)] #![feature(get_mut_unchecked)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(iter_from_generator)] #![feature(local_key_cell_methods)] #![feature(negative_impls)] #![feature(never_type)] #![feature(extern_types)] #![feature(new_uninit)] -#![feature(once_cell)] #![feature(let_chains)] #![feature(min_specialization)] #![feature(trusted_len)] @@ -109,4 +109,4 @@ pub mod util { // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; -fluent_messages! { "../locales/en-US.ftl" } +fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index a8d71ce03..89014f62d 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -1,6 +1,6 @@ /// A macro for triggering an ICE. /// Calling `bug` instead of panicking will result in a nicer error message and should -/// therefore be prefered over `panic`/`unreachable` or others. +/// therefore be preferred over `panic`/`unreachable` or others. /// /// If you have a span available, you should use [`span_bug`] instead. /// diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 5ff014c78..f3170e0ec 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -5,13 +5,34 @@ use rustc_macros::HashStable; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use rustc_span::Span; +use smallvec::SmallVec; + +/// A simplified version of `ImportKind` from resolve. +/// `DefId`s here correspond to `use` and `extern crate` items themselves, not their targets. +#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, HashStable)] +pub enum Reexport { + Single(DefId), + Glob(DefId), + ExternCrate(DefId), + MacroUse, + MacroExport, +} + +impl Reexport { + pub fn id(self) -> Option<DefId> { + match self { + Reexport::Single(id) | Reexport::Glob(id) | Reexport::ExternCrate(id) => Some(id), + Reexport::MacroUse | Reexport::MacroExport => None, + } + } +} /// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates /// during name resolution. Right now the bindings are not recreated entirely precisely so we may /// need to add more data in the future to correctly support macros 2.0, for example. /// Module child can be either a proper item or a reexport (including private imports). /// In case of reexport all the fields describe the reexport item itself, not what it refers to. -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Debug, TyEncodable, TyDecodable, HashStable)] pub struct ModChild { /// Name of the item. pub ident: Ident, @@ -22,6 +43,7 @@ pub struct ModChild { pub vis: ty::Visibility<DefId>, /// Span of the item. pub span: Span, - /// A proper `macro_rules` item (not a reexport). - pub macro_rules: bool, + /// Reexport chain linking this module child to its original reexported item. + /// Empty if the module child is a proper item. + pub reexport_chain: SmallVec<[Reexport; 2]>, } diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 631fd09ec..c0c0fd07b 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), Generic(DefId, SubstsRef<'tcx>), DropGlue(Ty<'tcx>), + ThreadLocalShim(DefId), NoDefId(ty::SymbolName<'tcx>), } @@ -58,6 +59,10 @@ impl<'tcx> ExportedSymbol<'tcx> { ExportedSymbol::DropGlue(ty) => { tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) } + ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { + def: ty::InstanceDef::ThreadLocalShim(def_id), + substs: ty::InternalSubsts::empty(), + }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, } } diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 0b6774f1b..9c25f3009 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -19,7 +19,7 @@ pub mod lib_features { .stable .iter() .map(|(f, (s, _))| (*f, Some(*s))) - .chain(self.unstable.iter().map(|(f, _)| (*f, None))) + .chain(self.unstable.keys().map(|f| (*f, None))) .collect(); all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap()); all_features diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 893bf54b8..967fed687 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -1,12 +1,12 @@ //! A pass that checks to make sure private fields and methods aren't used //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. -use crate::ty::{DefIdTree, TyCtxt, Visibility}; +use crate::ty::{TyCtxt, Visibility}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; use std::hash::Hash; /// Represents the levels of effective visibility an item can have. @@ -107,12 +107,16 @@ impl EffectiveVisibilities { }) } + pub fn update_root(&mut self) { + self.map.insert(CRATE_DEF_ID, EffectiveVisibility::from_vis(Visibility::Public)); + } + // FIXME: Share code with `fn update`. pub fn update_eff_vis( &mut self, def_id: LocalDefId, eff_vis: &EffectiveVisibility, - tree: impl DefIdTree, + tcx: TyCtxt<'_>, ) { use std::collections::hash_map::Entry; match self.map.entry(def_id) { @@ -122,7 +126,7 @@ impl EffectiveVisibilities { let vis_at_level = eff_vis.at_level(l); let old_vis_at_level = old_eff_vis.at_level_mut(l); if vis_at_level != old_vis_at_level - && vis_at_level.is_at_least(*old_vis_at_level, tree) + && vis_at_level.is_at_least(*old_vis_at_level, tcx) { *old_vis_at_level = *vis_at_level } @@ -219,7 +223,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { lazy_private_vis: impl FnOnce() -> Visibility, inherited_effective_vis: EffectiveVisibility, level: Level, - tree: impl DefIdTree, + tcx: TyCtxt<'_>, ) -> bool { let mut changed = false; let mut current_effective_vis = self @@ -240,7 +244,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { && level != l) { calculated_effective_vis = - if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) { + if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { inherited_effective_vis_at_level } else { nominal_vis @@ -249,7 +253,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { // effective visibility can't be decreased at next update call for the // same id if *current_effective_vis_at_level != calculated_effective_vis - && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tree) + && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tcx) { changed = true; *current_effective_vis_at_level = calculated_effective_vis; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 354c84e22..b61f7806b 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -3,7 +3,7 @@ pub use self::StabilityLevel::*; -use crate::ty::{self, DefIdTree, TyCtxt}; +use crate::ty::{self, TyCtxt}; use rustc_ast::NodeId; use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index b93871769..3fb468379 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -6,7 +6,7 @@ use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::OnceCell; -use rustc_index::vec::IndexVec; +use rustc_index::vec::{IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use smallvec::SmallVec; @@ -124,10 +124,10 @@ impl<'tcx> BasicBlocks<'tcx> { } impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { - type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>; + type Target = IndexSlice<BasicBlock, BasicBlockData<'tcx>>; #[inline] - fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { + fn deref(&self) -> &IndexSlice<BasicBlock, BasicBlockData<'tcx>> { &self.basic_blocks } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 48375ed30..1a8e48264 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -2,8 +2,6 @@ mod init_mask; mod provenance_map; -#[cfg(test)] -mod tests; use std::borrow::Cow; use std::fmt; @@ -111,26 +109,34 @@ const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH; // large. impl hash::Hash for Allocation { fn hash<H: hash::Hasher>(&self, state: &mut H) { + let Self { + bytes, + provenance, + init_mask, + align, + mutability, + extra: (), // don't bother hashing () + } = self; + // Partially hash the `bytes` buffer when it is large. To limit collisions with common // prefixes and suffixes, we hash the length and some slices of the buffer. - let byte_count = self.bytes.len(); + let byte_count = bytes.len(); if byte_count > MAX_HASHED_BUFFER_LEN { // Hash the buffer's length. byte_count.hash(state); // And its head and tail. - self.bytes[..MAX_BYTES_TO_HASH].hash(state); - self.bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); + bytes[..MAX_BYTES_TO_HASH].hash(state); + bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); } else { - self.bytes.hash(state); + bytes.hash(state); } // Hash the other fields as usual. - self.provenance.hash(state); - self.init_mask.hash(state); - self.align.hash(state); - self.mutability.hash(state); - self.extra.hash(state); + provenance.hash(state); + init_mask.hash(state); + align.hash(state); + mutability.hash(state); } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index 82e9a961a..dcb56a175 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use std::hash; use std::iter; use std::ops::Range; @@ -10,20 +13,185 @@ type Block = u64; /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte /// is initialized. If it is `false` the byte is uninitialized. -// Note: for performance reasons when interning, some of the `InitMask` fields can be partially -// hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable)] -#[derive(HashStable)] +/// The actual bits are only materialized when needed, and we try to keep this data lazy as long as +/// possible. Currently, if all the blocks have the same value, then the mask represents either a +/// fully initialized or fully uninitialized const allocation, so we can only store that single +/// value. +#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub struct InitMask { - blocks: Vec<Block>, + blocks: InitMaskBlocks, len: Size, } +#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +enum InitMaskBlocks { + Lazy { + /// Whether the lazy init mask is fully initialized or uninitialized. + state: bool, + }, + Materialized(InitMaskMaterialized), +} + +impl InitMask { + pub fn new(size: Size, state: bool) -> Self { + // Blocks start lazily allocated, until we have to materialize them. + let blocks = InitMaskBlocks::Lazy { state }; + InitMask { len: size, blocks } + } + + /// Checks whether the `range` is entirely initialized. + /// + /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte + /// indexes for the first contiguous span of the uninitialized access. + #[inline] + pub fn is_range_initialized(&self, range: AllocRange) -> Result<(), AllocRange> { + let end = range.end(); + if end > self.len { + return Err(AllocRange::from(self.len..end)); + } + + match self.blocks { + InitMaskBlocks::Lazy { state } => { + // Lazily allocated blocks represent the full mask, and cover the requested range by + // definition. + if state { Ok(()) } else { Err(range) } + } + InitMaskBlocks::Materialized(ref blocks) => { + blocks.is_range_initialized(range.start, end) + } + } + } + + /// Sets a specified range to a value. If the range is out-of-bounds, the mask will grow to + /// accommodate it entirely. + pub fn set_range(&mut self, range: AllocRange, new_state: bool) { + let start = range.start; + let end = range.end(); + + let is_full_overwrite = start == Size::ZERO && end >= self.len; + + // Optimize the cases of a full init/uninit state, while handling growth if needed. + match self.blocks { + InitMaskBlocks::Lazy { ref mut state } if is_full_overwrite => { + // This is fully overwriting the mask, and we'll still have a single initialization + // state: the blocks can stay lazy. + *state = new_state; + self.len = end; + } + InitMaskBlocks::Materialized(_) if is_full_overwrite => { + // This is also fully overwriting materialized blocks with a single initialization + // state: we'll have no need for these blocks anymore and can make them lazy. + self.blocks = InitMaskBlocks::Lazy { state: new_state }; + self.len = end; + } + InitMaskBlocks::Lazy { state } if state == new_state => { + // Here we're partially overwriting the mask but the initialization state doesn't + // change: the blocks can stay lazy. + if end > self.len { + self.len = end; + } + } + _ => { + // Otherwise, we have a partial overwrite that can result in a mix of initialization + // states, so we'll need materialized blocks. + let len = self.len; + let blocks = self.materialize_blocks(); + + // There are 3 cases of interest here, if we have: + // + // [--------] + // ^ ^ + // 0 len + // + // 1) the range to set can be in-bounds: + // + // xxxx = [start, end] + // [--------] + // ^ ^ + // 0 len + // + // Here, we'll simply set the single `start` to `end` range. + // + // 2) the range to set can be partially out-of-bounds: + // + // xxxx = [start, end] + // [--------] + // ^ ^ + // 0 len + // + // We have 2 subranges to handle: + // - we'll set the existing `start` to `len` range. + // - we'll grow and set the `len` to `end` range. + // + // 3) the range to set can be fully out-of-bounds: + // + // ---xxxx = [start, end] + // [--------] + // ^ ^ + // 0 len + // + // Since we're growing the mask to a single `new_state` value, we consider the gap + // from `len` to `start` to be part of the range, and have a single subrange to + // handle: we'll grow and set the `len` to `end` range. + // + // Note that we have to materialize, set blocks, and grow the mask. We could + // therefore slightly optimize things in situations where these writes overlap. + // However, as of writing this, growing the mask doesn't happen in practice yet, so + // we don't do this micro-optimization. + + if end <= len { + // Handle case 1. + blocks.set_range_inbounds(start, end, new_state); + } else { + if start < len { + // Handle the first subrange of case 2. + blocks.set_range_inbounds(start, len, new_state); + } + + // Handle the second subrange of case 2, and case 3. + blocks.grow(len, end - len, new_state); // `Size` operation + self.len = end; + } + } + } + } + + /// Materializes this mask's blocks when the mask is lazy. + #[inline] + fn materialize_blocks(&mut self) -> &mut InitMaskMaterialized { + if let InitMaskBlocks::Lazy { state } = self.blocks { + self.blocks = InitMaskBlocks::Materialized(InitMaskMaterialized::new(self.len, state)); + } + + let InitMaskBlocks::Materialized(ref mut blocks) = self.blocks else { + bug!("initmask blocks must be materialized here") + }; + blocks + } + + /// Returns the initialization state at the specified in-bounds index. + #[inline] + pub fn get(&self, idx: Size) -> bool { + match self.blocks { + InitMaskBlocks::Lazy { state } => state, + InitMaskBlocks::Materialized(ref blocks) => blocks.get(idx), + } + } +} + +/// The actual materialized blocks of the bitmask, when we can't keep the `InitMask` lazy. +// Note: for performance reasons when interning, some of the fields can be partially +// hashed. (see the `Hash` impl below for more details), so the impl is not derived. +#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)] +struct InitMaskMaterialized { + blocks: Vec<Block>, +} + // Const allocations are only hashed for interning. However, they can be large, making the hashing // expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially // big buffers like the allocation's init mask. We can partially hash some fields when they're // large. -impl hash::Hash for InitMask { +impl hash::Hash for InitMaskMaterialized { fn hash<H: hash::Hasher>(&self, state: &mut H) { const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / std::mem::size_of::<Block>(); const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / std::mem::size_of::<Block>(); @@ -41,18 +209,15 @@ impl hash::Hash for InitMask { } else { self.blocks.hash(state); } - - // Hash the other fields as usual. - self.len.hash(state); } } -impl InitMask { +impl InitMaskMaterialized { pub const BLOCK_SIZE: u64 = 64; - pub fn new(size: Size, state: bool) -> Self { - let mut m = InitMask { blocks: vec![], len: Size::ZERO }; - m.grow(size, state); + fn new(size: Size, state: bool) -> Self { + let mut m = InitMaskMaterialized { blocks: vec![] }; + m.grow(Size::ZERO, size, state); m } @@ -62,8 +227,8 @@ impl InitMask { // Each bit in a `Block` represents the initialization state of one byte of an allocation, // so we use `.bytes()` here. let bits = bits.bytes(); - let a = bits / InitMask::BLOCK_SIZE; - let b = bits % InitMask::BLOCK_SIZE; + let a = bits / Self::BLOCK_SIZE; + let b = bits % Self::BLOCK_SIZE; (usize::try_from(a).unwrap(), usize::try_from(b).unwrap()) } @@ -71,7 +236,7 @@ impl InitMask { fn size_from_bit_index(block: impl TryInto<u64>, bit: impl TryInto<u64>) -> Size { let block = block.try_into().ok().unwrap(); let bit = bit.try_into().ok().unwrap(); - Size::from_bytes(block * InitMask::BLOCK_SIZE + bit) + Size::from_bytes(block * Self::BLOCK_SIZE + bit) } /// Checks whether the `range` is entirely initialized. @@ -79,13 +244,8 @@ impl InitMask { /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte /// indexes for the first contiguous span of the uninitialized access. #[inline] - pub fn is_range_initialized(&self, range: AllocRange) -> Result<(), AllocRange> { - let end = range.end(); - if end > self.len { - return Err(AllocRange::from(self.len..end)); - } - - let uninit_start = self.find_bit(range.start, end, false); + fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> { + let uninit_start = self.find_bit(start, end, false); match uninit_start { Some(uninit_start) => { @@ -96,81 +256,80 @@ impl InitMask { } } - pub fn set_range(&mut self, range: AllocRange, new_state: bool) { - let end = range.end(); - let len = self.len; - if end > len { - self.grow(end - len, new_state); - } - self.set_range_inbounds(range.start, end, new_state); - } - fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) { - let (blocka, bita) = Self::bit_index(start); - let (blockb, bitb) = Self::bit_index(end); - if blocka == blockb { - // First set all bits except the first `bita`, - // then unset the last `64 - bitb` bits. - let range = if bitb == 0 { - u64::MAX << bita + let (block_a, bit_a) = Self::bit_index(start); + let (block_b, bit_b) = Self::bit_index(end); + if block_a == block_b { + // First set all bits except the first `bit_a`, + // then unset the last `64 - bit_b` bits. + let range = if bit_b == 0 { + u64::MAX << bit_a } else { - (u64::MAX << bita) & (u64::MAX >> (64 - bitb)) + (u64::MAX << bit_a) & (u64::MAX >> (64 - bit_b)) }; if new_state { - self.blocks[blocka] |= range; + self.blocks[block_a] |= range; } else { - self.blocks[blocka] &= !range; + self.blocks[block_a] &= !range; } return; } // across block boundaries if new_state { - // Set `bita..64` to `1`. - self.blocks[blocka] |= u64::MAX << bita; - // Set `0..bitb` to `1`. - if bitb != 0 { - self.blocks[blockb] |= u64::MAX >> (64 - bitb); + // Set `bit_a..64` to `1`. + self.blocks[block_a] |= u64::MAX << bit_a; + // Set `0..bit_b` to `1`. + if bit_b != 0 { + self.blocks[block_b] |= u64::MAX >> (64 - bit_b); } // Fill in all the other blocks (much faster than one bit at a time). - for block in (blocka + 1)..blockb { + for block in (block_a + 1)..block_b { self.blocks[block] = u64::MAX; } } else { - // Set `bita..64` to `0`. - self.blocks[blocka] &= !(u64::MAX << bita); - // Set `0..bitb` to `0`. - if bitb != 0 { - self.blocks[blockb] &= !(u64::MAX >> (64 - bitb)); + // Set `bit_a..64` to `0`. + self.blocks[block_a] &= !(u64::MAX << bit_a); + // Set `0..bit_b` to `0`. + if bit_b != 0 { + self.blocks[block_b] &= !(u64::MAX >> (64 - bit_b)); } // Fill in all the other blocks (much faster than one bit at a time). - for block in (blocka + 1)..blockb { + for block in (block_a + 1)..block_b { self.blocks[block] = 0; } } } #[inline] - pub fn get(&self, i: Size) -> bool { + fn get(&self, i: Size) -> bool { let (block, bit) = Self::bit_index(i); (self.blocks[block] & (1 << bit)) != 0 } - fn grow(&mut self, amount: Size, new_state: bool) { + fn grow(&mut self, len: Size, amount: Size, new_state: bool) { if amount.bytes() == 0 { return; } let unused_trailing_bits = - u64::try_from(self.blocks.len()).unwrap() * Self::BLOCK_SIZE - self.len.bytes(); + u64::try_from(self.blocks.len()).unwrap() * Self::BLOCK_SIZE - len.bytes(); + + // If there's not enough capacity in the currently allocated blocks, allocate some more. if amount.bytes() > unused_trailing_bits { let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1; - self.blocks.extend( - // FIXME(oli-obk): optimize this by repeating `new_state as Block`. - iter::repeat(0).take(usize::try_from(additional_blocks).unwrap()), - ); + + // We allocate the blocks to the correct value for the requested init state, so we won't + // have to manually set them with another write. + let block = if new_state { u64::MAX } else { 0 }; + self.blocks + .extend(iter::repeat(block).take(usize::try_from(additional_blocks).unwrap())); + } + + // New blocks have already been set here, so we only need to set the unused trailing bits, + // if any. + if unused_trailing_bits > 0 { + let in_bounds_tail = Size::from_bytes(unused_trailing_bits); + self.set_range_inbounds(len, len + in_bounds_tail, new_state); // `Size` operation } - let start = self.len; - self.len += amount; - self.set_range_inbounds(start, start + amount, new_state); // `Size` operation } /// Returns the index of the first bit in `start..end` (end-exclusive) that is equal to is_init. @@ -188,7 +347,7 @@ impl InitMask { /// ``` /// Also, if not stated, assume that `is_init = true`, that is, we are searching for the first 1 bit. fn find_bit_fast( - init_mask: &InitMask, + init_mask: &InitMaskMaterialized, start: Size, end: Size, is_init: bool, @@ -223,7 +382,7 @@ impl InitMask { None } else { let bit = bits.trailing_zeros(); - Some(InitMask::size_from_bit_index(block, bit)) + Some(InitMaskMaterialized::size_from_bit_index(block, bit)) } } @@ -253,9 +412,9 @@ impl InitMask { // This provides the desired behavior of searching blocks 0 and 1 for (a), // and searching only block 0 for (b). // There is no concern of overflows since we checked for `start >= end` above. - let (start_block, start_bit) = InitMask::bit_index(start); + let (start_block, start_bit) = InitMaskMaterialized::bit_index(start); let end_inclusive = Size::from_bytes(end.bytes() - 1); - let (end_block_inclusive, _) = InitMask::bit_index(end_inclusive); + let (end_block_inclusive, _) = InitMaskMaterialized::bit_index(end_inclusive); // Handle first block: need to skip `start_bit` bits. // @@ -340,7 +499,7 @@ impl InitMask { #[cfg_attr(not(debug_assertions), allow(dead_code))] fn find_bit_slow( - init_mask: &InitMask, + init_mask: &InitMaskMaterialized, start: Size, end: Size, is_init: bool, @@ -436,10 +595,19 @@ impl<'a> Iterator for InitChunkIter<'a> { return None; } - let end_of_chunk = - self.init_mask.find_bit(self.start, self.end, !self.is_init).unwrap_or(self.end); + let end_of_chunk = match self.init_mask.blocks { + InitMaskBlocks::Lazy { .. } => { + // If we're iterating over the chunks of lazy blocks, we just emit a single + // full-size chunk. + self.end + } + InitMaskBlocks::Materialized(ref blocks) => { + let end_of_chunk = + blocks.find_bit(self.start, self.end, !self.is_init).unwrap_or(self.end); + end_of_chunk + } + }; let range = self.start..end_of_chunk; - let ret = Some(if self.is_init { InitChunk::Init(range) } else { InitChunk::Uninit(range) }); @@ -504,17 +672,19 @@ impl InitMask { /// Applies multiple instances of the run-length encoding to the initialization mask. pub fn apply_copy(&mut self, defined: InitCopy, range: AllocRange, repeat: u64) { - // An optimization where we can just overwrite an entire range of initialization - // bits if they are going to be uniformly `1` or `0`. + // An optimization where we can just overwrite an entire range of initialization bits if + // they are going to be uniformly `1` or `0`. If this happens to be a full-range overwrite, + // we won't need materialized blocks either. if defined.ranges.len() <= 1 { - self.set_range_inbounds( - range.start, - range.start + range.size * repeat, // `Size` operations - defined.initial, - ); + let start = range.start; + let end = range.start + range.size * repeat; // `Size` operations + self.set_range(AllocRange::from(start..end), defined.initial); return; } + // We're about to do one or more partial writes, so we ensure the blocks are materialized. + let blocks = self.materialize_blocks(); + for mut j in 0..repeat { j *= range.size.bytes(); j += range.start.bytes(); @@ -522,7 +692,7 @@ impl InitMask { for range in &defined.ranges { let old_j = j; j += range; - self.set_range_inbounds(Size::from_bytes(old_j), Size::from_bytes(j), cur); + blocks.set_range_inbounds(Size::from_bytes(old_j), Size::from_bytes(j), cur); cur = !cur; } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask/tests.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask/tests.rs new file mode 100644 index 000000000..1a7934bc2 --- /dev/null +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask/tests.rs @@ -0,0 +1,195 @@ +use super::*; +use crate::mir::interpret::alloc_range; + +#[test] +fn uninit_mask() { + let mut mask = InitMask::new(Size::from_bytes(500), false); + assert!(!mask.get(Size::from_bytes(499))); + mask.set_range(alloc_range(Size::from_bytes(499), Size::from_bytes(1)), true); + assert!(mask.get(Size::from_bytes(499))); + mask.set_range((100..256).into(), true); + for i in 0..100 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } + for i in 100..256 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + for i in 256..499 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } +} + +/// Returns the number of materialized blocks for this mask. +fn materialized_block_count(mask: &InitMask) -> usize { + match mask.blocks { + InitMaskBlocks::Lazy { .. } => 0, + InitMaskBlocks::Materialized(ref blocks) => blocks.blocks.len(), + } +} + +#[test] +fn materialize_mask_within_range() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), false); + assert_eq!(materialized_block_count(&mask), 0); + + // Forces materialization, but doesn't require growth. This is case #1 documented in the + // `set_range` method. + mask.set_range((8..16).into(), true); + assert_eq!(materialized_block_count(&mask), 1); + + for i in 0..8 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } + for i in 8..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } +} + +#[test] +fn grow_within_unused_bits_with_full_overwrite() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + for i in 0..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + // Grow without requiring an additional block. Full overwrite. + // This can be fully handled without materialization. + let range = (0..32).into(); + mask.set_range(range, true); + + for i in 0..32 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + assert_eq!(materialized_block_count(&mask), 0); +} + +// This test checks that an initmask's spare capacity is correctly used when growing within block +// capacity. This can be fully handled without materialization. +#[test] +fn grow_same_state_within_unused_bits() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + for i in 0..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + // Grow without requiring an additional block. The gap between the current length and the + // range's beginning should be set to the same value as the range. + let range = (24..32).into(); + mask.set_range(range, true); + + // We want to make sure the unused bits in the first block are correct + for i in 16..24 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + for i in 24..32 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + assert_eq!(1, mask.range_as_init_chunks((0..32).into()).count()); + assert_eq!(materialized_block_count(&mask), 0); +} + +// This is the same test as `grow_same_state_within_unused_bits` but with both init and uninit +// states: this forces materialization; otherwise the mask could stay lazy even when needing to +// grow. +#[test] +fn grow_mixed_state_within_unused_bits() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + for i in 0..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + // Grow without requiring an additional block. The gap between the current length and the + // range's beginning should be set to the same value as the range. Note: since this is fully + // out-of-bounds of the current mask, this is case #3 described in the `set_range` method. + let range = (24..32).into(); + mask.set_range(range, false); + + // We want to make sure the unused bits in the first block are correct + for i in 16..24 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } + + for i in 24..32 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } + + assert_eq!(1, mask.range_as_init_chunks((0..16).into()).count()); + assert_eq!(2, mask.range_as_init_chunks((0..32).into()).count()); + assert_eq!(materialized_block_count(&mask), 1); +} + +// This is similar to `grow_mixed_state_within_unused_bits` to force materialization, but the range +// to set partially overlaps the mask, so this requires a different growth + write pattern in the +// mask. +#[test] +fn grow_within_unused_bits_with_overlap() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + for i in 0..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + + // Grow without requiring an additional block, but leave no gap after the current len. Note: + // since this is partially out-of-bounds of the current mask, this is case #2 described in the + // `set_range` method. + let range = (8..24).into(); + mask.set_range(range, false); + + // We want to make sure the unused bits in the first block are correct + for i in 8..24 { + assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); + } + + assert_eq!(1, mask.range_as_init_chunks((0..8).into()).count()); + assert_eq!(2, mask.range_as_init_chunks((0..24).into()).count()); + assert_eq!(materialized_block_count(&mask), 1); +} + +// Force materialization before a full overwrite: the mask can now become lazy. +#[test] +fn grow_mixed_state_within_unused_bits_and_full_overwrite() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + let range = (0..16).into(); + assert!(mask.is_range_initialized(range).is_ok()); + + // Force materialization. + let range = (8..24).into(); + mask.set_range(range, false); + assert!(mask.is_range_initialized(range).is_err()); + assert_eq!(materialized_block_count(&mask), 1); + + // Full overwrite, lazy blocks would be enough from now on. + let range = (0..32).into(); + mask.set_range(range, true); + assert!(mask.is_range_initialized(range).is_ok()); + + assert_eq!(1, mask.range_as_init_chunks((0..32).into()).count()); + assert_eq!(materialized_block_count(&mask), 0); +} + +// Check that growth outside the current capacity can still be lazy: if the init state doesn't +// change, we don't need materialized blocks. +#[test] +fn grow_same_state_outside_capacity() { + // To have spare bits, we use a mask size smaller than its block size of 64. + let mut mask = InitMask::new(Size::from_bytes(16), true); + for i in 0..16 { + assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); + } + assert_eq!(materialized_block_count(&mask), 0); + + // Grow to 10 blocks with the same init state. + let range = (24..640).into(); + mask.set_range(range, true); + + assert_eq!(1, mask.range_as_init_chunks((0..640).into()).count()); + assert_eq!(materialized_block_count(&mask), 0); +} diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index ddd3f3943..318f93e12 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -14,7 +14,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; #[derive(HashStable)] pub struct ProvenanceMap<Prov = AllocId> { /// Provenance in this map applies from the given offset for an entire pointer-size worth of - /// bytes. Two entires in this map are always at least a pointer size apart. + /// bytes. Two entries in this map are always at least a pointer size apart. ptrs: SortedMap<Size, Prov>, /// Provenance in this map only applies to the given single byte. /// This map is disjoint from the previous. It will always be empty when diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/tests.rs b/compiler/rustc_middle/src/mir/interpret/allocation/tests.rs deleted file mode 100644 index c9c3c50c5..000000000 --- a/compiler/rustc_middle/src/mir/interpret/allocation/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; - -#[test] -fn uninit_mask() { - let mut mask = InitMask::new(Size::from_bytes(500), false); - assert!(!mask.get(Size::from_bytes(499))); - mask.set_range(alloc_range(Size::from_bytes(499), Size::from_bytes(1)), true); - assert!(mask.get(Size::from_bytes(499))); - mask.set_range((100..256).into(), true); - for i in 0..100 { - assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); - } - for i in 100..256 { - assert!(mask.get(Size::from_bytes(i)), "{i} should be set"); - } - for i in 256..499 { - assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set"); - } -} diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 1766d7a66..1f8b650e3 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -263,7 +263,8 @@ impl AllocDecodingState { } pub fn new(data_offsets: Vec<u32>) -> Self { - let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()]; + let decoding_state = + std::iter::repeat_with(|| Lock::new(State::Empty)).take(data_offsets.len()).collect(); Self { decoding_state, data_offsets } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 99cdb769d..2ea8602af 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -10,7 +10,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::ty::{self, DefIdTree, List, Ty, TyCtxt}; +use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; @@ -21,13 +21,13 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::{self, GeneratorKind, ImplicitSelfKind}; use rustc_hir::{self as hir, HirId}; use rustc_session::Session; -use rustc_target::abi::{Size, VariantIdx}; +use rustc_target::abi::{FieldIdx, Size, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::{Idx, IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -70,12 +70,19 @@ pub use self::pretty::{ }; /// Types for locals -pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>; +pub type LocalDecls<'tcx> = IndexSlice<Local, LocalDecl<'tcx>>; pub trait HasLocalDecls<'tcx> { fn local_decls(&self) -> &LocalDecls<'tcx>; } +impl<'tcx> HasLocalDecls<'tcx> for IndexVec<Local, LocalDecl<'tcx>> { + #[inline] + fn local_decls(&self) -> &LocalDecls<'tcx> { + self + } +} + impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> { #[inline] fn local_decls(&self) -> &LocalDecls<'tcx> { @@ -250,7 +257,7 @@ pub struct Body<'tcx> { /// The first local is the return value pointer, followed by `arg_count` /// locals for the function arguments, followed by any user-declared /// variables and temporaries. - pub local_decls: LocalDecls<'tcx>, + pub local_decls: IndexVec<Local, LocalDecl<'tcx>>, /// User type annotations. pub user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, @@ -311,7 +318,7 @@ impl<'tcx> Body<'tcx> { source: MirSource<'tcx>, basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, - local_decls: LocalDecls<'tcx>, + local_decls: IndexVec<Local, LocalDecl<'tcx>>, user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, var_debug_info: Vec<VarDebugInfo<'tcx>>, @@ -401,8 +408,6 @@ impl<'tcx> Body<'tcx> { LocalKind::ReturnPointer } else if index < self.arg_count + 1 { LocalKind::Arg - } else if self.local_decls[local].is_user_variable() { - LocalKind::Var } else { LocalKind::Temp } @@ -572,6 +577,13 @@ impl<T> ClearCrossCrate<T> { } } + pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> { + match self { + ClearCrossCrate::Clear => ClearCrossCrate::Clear, + ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), + } + } + pub fn assert_crate_local(self) -> T { match self { ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), @@ -661,9 +673,7 @@ impl Atom for Local { /// Classifies locals into categories. See `Body::local_kind`. #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { - /// User-declared variable binding. - Var, - /// Compiler-introduced temporary. + /// User-declared variable binding or compiler-introduced temporary. Temp, /// Function argument. Arg, @@ -760,7 +770,7 @@ pub struct LocalDecl<'tcx> { pub mutability: Mutability, // FIXME(matthewjasper) Don't store in this in `Body` - pub local_info: Option<Box<LocalInfo<'tcx>>>, + pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>, /// `true` if this is an internal local. /// @@ -778,13 +788,6 @@ pub struct LocalDecl<'tcx> { /// generator. pub internal: bool, - /// If this local is a temporary and `is_block_tail` is `Some`, - /// then it is a temporary created for evaluation of some - /// subexpression of some block's tail expression (with no - /// intervening statement context). - // FIXME(matthewjasper) Don't store in this in `Body` - pub is_block_tail: Option<BlockTailInfo>, - /// The type of this local. pub ty: Ty<'tcx>, @@ -890,7 +893,7 @@ pub enum LocalInfo<'tcx> { /// The `BindingForm` is solely used for local diagnostics when generating /// warnings/errors when compiling the current crate, and therefore it need /// not be visible across crates. - User(ClearCrossCrate<BindingForm<'tcx>>), + User(BindingForm<'tcx>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, /// A temporary created that references the const with the given `DefId` @@ -898,13 +901,23 @@ pub enum LocalInfo<'tcx> { /// A temporary created during the creation of an aggregate /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`) AggregateTemp, + /// A temporary created for evaluation of some subexpression of some block's tail expression + /// (with no intervening statement context). + // FIXME(matthewjasper) Don't store in this in `Body` + BlockTailTemp(BlockTailInfo), /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, /// A temporary created for borrow checking. FakeBorrow, + /// A local without anything interesting about it. + Boring, } impl<'tcx> LocalDecl<'tcx> { + pub fn local_info(&self) -> &LocalInfo<'tcx> { + &self.local_info.as_ref().assert_crate_local() + } + /// Returns `true` only if local is a binding that can itself be /// made mutable via the addition of the `mut` keyword, namely /// something like the occurrences of `x` in: @@ -913,15 +926,15 @@ impl<'tcx> LocalDecl<'tcx> { /// - or `match ... { C(x) => ... }` pub fn can_be_made_mutable(&self) -> bool { matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set( + self.local_info(), + LocalInfo::User( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), - ))) + ) ) } @@ -930,15 +943,15 @@ impl<'tcx> LocalDecl<'tcx> { /// mutable bindings, but the inverse does not necessarily hold). pub fn is_nonref_binding(&self) -> bool { matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set( + self.local_info(), + LocalInfo::User( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(_), - ))) + ) ) } @@ -946,38 +959,35 @@ impl<'tcx> LocalDecl<'tcx> { /// parameter declared by the user. #[inline] pub fn is_user_variable(&self) -> bool { - matches!(self.local_info, Some(box LocalInfo::User(_))) + matches!(self.local_info(), LocalInfo::User(_)) } /// Returns `true` if this is a reference to a variable bound in a `match` /// expression that is used to access said variable for the guard of the /// match arm. pub fn is_ref_for_guard(&self) -> bool { - matches!( - self.local_info, - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) - ) + matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard)) } /// Returns `Some` if this is a reference to a static item that is used to /// access that static. pub fn is_ref_to_static(&self) -> bool { - matches!(self.local_info, Some(box LocalInfo::StaticRef { .. })) + matches!(self.local_info(), LocalInfo::StaticRef { .. }) } /// Returns `Some` if this is a reference to a thread-local static item that is used to /// access that static. pub fn is_ref_to_thread_local(&self) -> bool { - match self.local_info { - Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local, + match self.local_info() { + LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local, _ => false, } } /// Returns `true` if this is a DerefTemp pub fn is_deref_temp(&self) -> bool { - match self.local_info { - Some(box LocalInfo::DerefTemp) => return true, + match self.local_info() { + LocalInfo::DerefTemp => return true, _ => (), } return false; @@ -1001,9 +1011,8 @@ impl<'tcx> LocalDecl<'tcx> { pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self { LocalDecl { mutability: Mutability::Mut, - local_info: None, + local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)), internal: false, - is_block_tail: None, ty, user_ty: None, source_info, @@ -1023,20 +1032,11 @@ impl<'tcx> LocalDecl<'tcx> { self.mutability = Mutability::Not; self } - - /// Converts `self` into same `LocalDecl` except tagged as internal temporary. - #[inline] - pub fn block_tail(mut self, info: BlockTailInfo) -> Self { - assert!(self.is_block_tail.is_none()); - self.is_block_tail = Some(info); - self - } } #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum VarDebugInfoContents<'tcx> { - /// NOTE(eddyb) There's an unenforced invariant that this `Place` is - /// based on a `Local`, not a `Static`, and contains no indexing. + /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), Const(Constant<'tcx>), /// The user variable's data is split across several fragments, @@ -1046,6 +1046,7 @@ pub enum VarDebugInfoContents<'tcx> { /// the underlying debuginfo feature this relies on. Composite { /// Type of the original user variable. + /// This cannot contain a union or an enum. ty: Ty<'tcx>, /// All the parts of the original user variable, which ended /// up in disjoint places, due to optimizations. @@ -1074,17 +1075,16 @@ pub struct VarDebugInfoFragment<'tcx> { /// Where in the composite user variable this fragment is, /// represented as a "projection" into the composite variable. /// At lower levels, this corresponds to a byte/bit range. - // NOTE(eddyb) there's an unenforced invariant that this contains - // only `Field`s, and not into `enum` variants or `union`s. - // FIXME(eddyb) support this for `enum`s by either using DWARF's + /// + /// This can only contain `PlaceElem::Field`. + // FIXME support this for `enum`s by either using DWARF's // more advanced control-flow features (unsupported by LLVM?) // to match on the discriminant, or by using custom type debuginfo // with non-overlapping variants for the composite variable. pub projection: Vec<PlaceElem<'tcx>>, /// Where the data for this fragment can be found. - // NOTE(eddyb) There's an unenforced invariant that this `Place` is - // contains no indexing (with a non-constant index). + /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. pub contents: Place<'tcx>, } @@ -1115,6 +1115,11 @@ pub struct VarDebugInfo<'tcx> { /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents<'tcx>, + + /// When present, indicates what argument number this variable is in the function that it + /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the + /// argument number in the original function before it was inlined. + pub argument_index: Option<u16>, } /////////////////////////////////////////////////////////////////////////// @@ -1274,9 +1279,16 @@ impl<'tcx> BasicBlockData<'tcx> { } impl<O> AssertKind<O> { + /// Returns true if this an overflow checking assertion controlled by -C overflow-checks. + pub fn is_optional_overflow_check(&self) -> bool { + use AssertKind::*; + use BinOp::*; + matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..)) + } + /// Getting a description does not require `O` to be printable, and does not /// require allocation. - /// The caller is expected to handle `BoundsCheck` separately. + /// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` separately. pub fn description(&self) -> &'static str { use AssertKind::*; match self { @@ -1295,7 +1307,9 @@ impl<O> AssertKind<O> { ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion", ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking", ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking", - BoundsCheck { .. } => bug!("Unexpected AssertKind"), + BoundsCheck { .. } | MisalignedPointerDereference { .. } => { + bug!("Unexpected AssertKind") + } } } @@ -1352,6 +1366,13 @@ impl<O> AssertKind<O> { Overflow(BinOp::Shl, _, r) => { write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r) } + MisalignedPointerDereference { required, found } => { + write!( + f, + "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {:?}, {:?}", + required, found + ) + } _ => write!(f, "\"{}\"", self.description()), } } @@ -1396,6 +1417,13 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { Overflow(BinOp::Shl, _, r) => { write!(f, "attempt to shift left by `{:#?}`, which would overflow", r) } + MisalignedPointerDereference { required, found } => { + write!( + f, + "misaligned pointer dereference: address must be a multiple of {:?} but is {:?}", + required, found + ) + } _ => write!(f, "{}", self.description()), } } @@ -1453,6 +1481,9 @@ impl Debug for Statement<'_> { write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) } Deinit(ref place) => write!(fmt, "Deinit({:?})", place), + PlaceMention(ref place) => { + write!(fmt, "PlaceMention({:?})", place) + } AscribeUserType(box (ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } @@ -1508,31 +1539,26 @@ impl<V, T> ProjectionElem<V, T> { } /// Returns `true` if this is a `Field` projection with the given index. - pub fn is_field_to(&self, f: Field) -> bool { + pub fn is_field_to(&self, f: FieldIdx) -> bool { matches!(*self, Self::Field(x, _) if x == f) } + + /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`. + pub fn can_use_in_debuginfo(&self) -> bool { + match self { + Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true, + Self::ConstantIndex { .. } + | Self::Index(_) + | Self::OpaqueCast(_) + | Self::Subslice { .. } => false, + } + } } /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; -rustc_index::newtype_index! { - /// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG] - /// - /// A field (e.g., `f` in `_1.f`) is one variant of [`ProjectionElem`]. Conceptually, - /// rustc can identify that a field projection refers to either two different regions of memory - /// or the same one between the base and the 'projection element'. - /// Read more about projections in the [rustc-dev-guide][mir-datatypes] - /// - /// [wrapper]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#newtype - /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg - /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types - #[derive(HashStable)] - #[debug_format = "field[{}]"] - pub struct Field {} -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct PlaceRef<'tcx> { pub local: Local, @@ -1775,7 +1801,7 @@ impl SourceScope { /// from the function that was inlined instead of the function call site. pub fn lint_root( self, - source_scopes: &IndexVec<SourceScope, SourceScopeData<'_>>, + source_scopes: &IndexSlice<SourceScope, SourceScopeData<'_>>, ) -> Option<HirId> { let mut data = &source_scopes[self]; // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it @@ -1795,7 +1821,7 @@ impl SourceScope { #[inline] pub fn inlined_instance<'tcx>( self, - source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>, + source_scopes: &IndexSlice<SourceScope, SourceScopeData<'tcx>>, ) -> Option<ty::Instance<'tcx>> { let scope_data = &source_scopes[self]; if let Some((inlined_instance, _)) = scope_data.inlined { @@ -1963,7 +1989,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::PtrToPtr | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress - | CastKind::DynStar, + | CastKind::DynStar + | CastKind::Transmute, _, _, ) @@ -1979,6 +2006,13 @@ impl<'tcx> Rvalue<'tcx> { } impl BorrowKind { + pub fn mutability(&self) -> Mutability { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Mut { .. } => Mutability::Mut, + } + } + pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, @@ -1995,13 +2029,6 @@ impl BorrowKind { } } -impl BinOp { - pub fn is_checkable(self) -> bool { - use self::BinOp::*; - matches!(self, Add | Sub | Mul | Shl | Shr) - } -} - impl<'tcx> Debug for Rvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Rvalue::*; @@ -2528,7 +2555,7 @@ impl<'tcx> ConstantKind<'tcx> { let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) && let Some(parent_did) = parent_hir_id.as_owner() { - InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) + InternalSubsts::identity_for_item(tcx, parent_did) } else { List::empty() }; @@ -2557,7 +2584,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::Unevaluated( UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), promoted: None, }, ty, @@ -2687,12 +2714,17 @@ impl<'tcx> UserTypeProjections { self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) } - pub fn leaf(self, field: Field) -> Self { + pub fn leaf(self, field: FieldIdx) -> Self { self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) } - pub fn variant(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx, field: Field) -> Self { - self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) + pub fn variant( + self, + adt_def: AdtDef<'tcx>, + variant_index: VariantIdx, + field_index: FieldIdx, + ) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index)) } } @@ -2735,7 +2767,7 @@ impl UserTypeProjection { self } - pub(crate) fn leaf(mut self, field: Field) -> Self { + pub(crate) fn leaf(mut self, field: FieldIdx) -> Self { self.projs.push(ProjectionElem::Field(field, ())); self } @@ -2744,13 +2776,13 @@ impl UserTypeProjection { mut self, adt_def: AdtDef<'_>, variant_index: VariantIdx, - field: Field, + field_index: FieldIdx, ) -> Self { self.projs.push(ProjectionElem::Downcast( Some(adt_def.variant(variant_index).name), variant_index, )); - self.projs.push(ProjectionElem::Field(field, ())); + self.projs.push(ProjectionElem::Field(field_index, ())); self } } @@ -3085,7 +3117,7 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(BasicBlockData<'_>, 144); - static_assert_size!(LocalDecl<'_>, 56); + static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(Statement<'_>, 32); static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 112); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7a05ee2ff..f592f1515 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -381,7 +381,9 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => None, + | InstanceDef::CloneShim(..) + | InstanceDef::ThreadLocalShim(..) + | InstanceDef::FnPtrAddrShim(..) => None, } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 24fe3b472..f62853c3e 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -12,6 +12,9 @@ pub struct MirPatch<'tcx> { new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec<LocalDecl<'tcx>>, resume_block: Option<BasicBlock>, + // Only for unreachable in cleanup path. + unreachable_cleanup_block: Option<BasicBlock>, + terminate_block: Option<BasicBlock>, body_span: Span, next_local: usize, } @@ -25,14 +28,31 @@ impl<'tcx> MirPatch<'tcx> { new_locals: vec![], next_local: body.local_decls.len(), resume_block: None, + unreachable_cleanup_block: None, + terminate_block: None, body_span: body.span, }; - // Check if we already have a resume block for (bb, block) in body.basic_blocks.iter_enumerated() { + // Check if we already have a resume block if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() { result.resume_block = Some(bb); - break; + continue; + } + + // Check if we already have an unreachable block + if let TerminatorKind::Unreachable = block.terminator().kind + && block.statements.is_empty() + && block.is_cleanup + { + result.unreachable_cleanup_block = Some(bb); + continue; + } + + // Check if we already have a terminate block + if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() { + result.terminate_block = Some(bb); + continue; } } @@ -56,6 +76,40 @@ impl<'tcx> MirPatch<'tcx> { bb } + pub fn unreachable_cleanup_block(&mut self) -> BasicBlock { + if let Some(bb) = self.unreachable_cleanup_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Unreachable, + }), + is_cleanup: true, + }); + self.unreachable_cleanup_block = Some(bb); + bb + } + + pub fn terminate_block(&mut self) -> BasicBlock { + if let Some(bb) = self.terminate_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Terminate, + }), + is_cleanup: true, + }); + self.terminate_block = Some(bb); + bb + } + pub fn is_patched(&self, bb: BasicBlock) -> bool { self.patch_map[bb].is_some() } @@ -72,28 +126,28 @@ impl<'tcx> MirPatch<'tcx> { &mut self, ty: Ty<'tcx>, span: Span, - local_info: Option<Box<LocalInfo<'tcx>>>, + local_info: LocalInfo<'tcx>, ) -> Local { let index = self.next_local; self.next_local += 1; let mut new_decl = LocalDecl::new(ty, span).internal(); - new_decl.local_info = local_info; + **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); - Local::new(index as usize) + Local::new(index) } pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span)); - Local::new(index as usize) + Local::new(index) } pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index as usize) + Local::new(index) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d8829e3e7..7e5195359 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -123,6 +123,7 @@ fn dump_matched_mir_node<'tcx, F>( // see notes on #41697 above let def_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + // ignore-tidy-odd-backticks the literal below is fine write!(file, "// MIR for `{}", def_path)?; match body.source.promoted { None => write!(file, "`")?, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index b964c1852..cfdf1dcf5 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,20 +2,20 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::vec_map::VecMap; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::Span; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; use smallvec::SmallVec; use std::cell::Cell; use std::fmt::{self, Debug}; -use super::{Field, SourceInfo}; +use super::SourceInfo; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { @@ -123,7 +123,7 @@ pub struct UnsafetyCheckResult { pub violations: Vec<UnsafetyViolation>, /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint. - pub used_unsafe_blocks: FxHashSet<hir::HirId>, + pub used_unsafe_blocks: UnordSet<hir::HirId>, /// This is `Some` iff the item is not a closure. pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>, @@ -152,7 +152,7 @@ pub struct GeneratorLayout<'tcx> { /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. - pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>, + pub variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, GeneratorSavedLocal>>, /// The source that led to each variant being created (usually, a yield or /// await). @@ -227,9 +227,9 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, - pub used_mut_upvars: SmallVec<[Field; 8]>, + pub used_mut_upvars: SmallVec<[FieldIdx; 8]>, pub tainted_by_errors: Option<ErrorGuaranteed>, } @@ -353,7 +353,7 @@ pub enum ConstraintCategory<'tcx> { /// like `Foo { field: my_val }`) Usage, OpaqueType, - ClosureUpvar(Field), + ClosureUpvar(FieldIdx), /// A constraint from a user-written predicate /// with the provided span, written on the item @@ -375,7 +375,7 @@ pub enum ConstraintCategory<'tcx> { #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ReturnConstraint { Normal, - ClosureUpvar(Field), + ClosureUpvar(FieldIdx), } /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing @@ -411,10 +411,8 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { let inner = tcx.fold_regions(ty, |r, depth| match r.kind() { ty::ReVar(vid) => { - let br = ty::BoundRegion { - var: ty::BoundVar::new(vid.index()), - kind: ty::BrAnon(vid.as_u32(), None), - }; + let br = + ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) }; tcx.mk_re_late_bound(depth, br) } _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 28a3b51b7..2165403da 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -247,6 +247,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { StorageLive(..) => "StorageLive", StorageDead(..) => "StorageDead", Retag(..) => "Retag", + PlaceMention(..) => "PlaceMention", AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", Intrinsic(..) => "Intrinsic", @@ -261,11 +262,10 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { Goto { .. } => "Goto", SwitchInt { .. } => "SwitchInt", Resume => "Resume", - Abort => "Abort", + Terminate => "Terminate", Return => "Return", Unreachable => "Unreachable", Drop { .. } => "Drop", - DropAndReplace { .. } => "DropAndReplace", Call { .. } => "Call", Assert { .. } => "Assert", Yield { .. } => "Yield", diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ae09562a8..93800d484 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -3,7 +3,7 @@ //! This is in a dedicated file so that changes to this file can be reviewed more carefully. //! The intention is that this file only contains datatype declarations, no code. -use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection}; +use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection}; use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::traits::Reveal; @@ -16,7 +16,8 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir}; use rustc_hir::{self, GeneratorKind}; -use rustc_target::abi::VariantIdx; +use rustc_index::vec::IndexVec; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_span::def_id::LocalDefId; @@ -78,7 +79,8 @@ pub enum MirPhase { /// MIR, this is UB. /// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way /// that Rust itself has them. Where exactly these are is generally subject to change, and so we - /// don't document this here. Runtime MIR has all retags explicit. + /// don't document this here. Runtime MIR has most retags explicit (though implicit retags + /// can still occur at `Rvalue::{Ref,AddrOf}`). /// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has /// access to. This occurs in generator bodies. Such locals do not behave like other locals, /// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals - @@ -133,7 +135,6 @@ pub enum AnalysisPhase { pub enum RuntimePhase { /// In addition to the semantic changes, beginning with this phase, the following variants are /// disallowed: - /// * [`TerminatorKind::DropAndReplace`] /// * [`TerminatorKind::Yield`] /// * [`TerminatorKind::GeneratorDrop`] /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` @@ -219,6 +220,11 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except + // that they do not require their pointee to be marked as a mutable. + // They should still be treated as mutable borrows in every other way, + // e.g. for variance or overlap checking. Unique, /// Data is mutable and not aliasable. @@ -326,6 +332,15 @@ pub enum StatementKind<'tcx> { /// Only `RetagKind::Default` and `RetagKind::FnEntry` are permitted. Retag(RetagKind, Box<Place<'tcx>>), + /// This statement exists to preserve a trace of a scrutinee matched against a wildcard binding. + /// This is especially useful for `let _ = PLACE;` bindings that desugar to a single + /// `PlaceMention(PLACE)`. + /// + /// When executed at runtime this is a nop. + /// + /// Disallowed after drop elaboration. + PlaceMention(Box<Place<'tcx>>), + /// Encodes a user's type ascription. These need to be preserved /// intact so that NLL can respect them. For example: /// ```ignore (illustrative) @@ -505,15 +520,15 @@ pub struct CopyNonOverlapping<'tcx> { /// /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such -/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then -/// once the current function is reached, execution continues at the given basic block, if any. If -/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is -/// equivalent to the execution of a `Resume` terminator. +/// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then +/// once the current function is reached, an action will be taken based on the `unwind` field. +/// If the action is `Cleanup`, then the execution continues at the given basic block. If the +/// action is `Continue` then no cleanup is performed, and the stack continues unwinding. /// -/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` -/// basic blocks have a couple restrictions: -/// 1. All `cleanup` fields in them must be `None`. -/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. +/// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set. +/// `cleanup` basic blocks have a couple restrictions: +/// 1. All `unwind` fields in them must be `UnwindAction::Terminate` or `UnwindAction::Unreachable`. +/// 2. `Return` terminators are not allowed in them. `Terminate` and `Resume` terminators are. /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks /// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// still an error to have such an edge in the CFG even if it's known that it won't be taken at @@ -555,11 +570,11 @@ pub enum TerminatorKind<'tcx> { /// deaggregation runs. Resume, - /// Indicates that the landing pad is finished and that the process should abort. + /// Indicates that the landing pad is finished and that the process should terminate. /// /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in /// cleanup blocks. - Abort, + Terminate, /// Returns from the function. /// @@ -594,44 +609,7 @@ pub enum TerminatorKind<'tcx> { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, - - /// Drops the place and assigns a new value to it. - /// - /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator; - /// it then additionally assigns the `value` to the `place` as if by an assignment statement. - /// This assignment occurs both in the unwind and the regular code paths. The semantics are best - /// explained by the elaboration: - /// - /// ```ignore (MIR) - /// BB0 { - /// DropAndReplace(P <- V, goto BB1, unwind BB2) - /// } - /// ``` - /// - /// becomes - /// - /// ```ignore (MIR) - /// BB0 { - /// Drop(P, goto BB1, unwind BB2) - /// } - /// BB1 { - /// // P is now uninitialized - /// P <- V - /// } - /// BB2 { - /// // P is now uninitialized -- its dtor panicked - /// P <- V - /// } - /// ``` - /// - /// Disallowed after drop elaboration. - DropAndReplace { - place: Place<'tcx>, - value: Operand<'tcx>, - target: BasicBlock, - unwind: Option<BasicBlock>, - }, + Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. @@ -655,8 +633,8 @@ pub enum TerminatorKind<'tcx> { destination: Place<'tcx>, /// Where to go after this call returns. If none, the call necessarily diverges. target: Option<BasicBlock>, - /// Cleanups to be done if the call unwinds. - cleanup: Option<BasicBlock>, + /// Action to be taken if the call unwinds. + unwind: UnwindAction, /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, @@ -675,14 +653,13 @@ pub enum TerminatorKind<'tcx> { /// When overflow checking is disabled and this is run-time MIR (as opposed to compile-time MIR /// that is used for CTFE), the following variants of this terminator behave as `goto target`: /// - `OverflowNeg(..)`, - /// - `Overflow(op, ..)` if op is a "checkable" operation (add, sub, mul, shl, shr, but NOT - /// div or rem). + /// - `Overflow(op, ..)` if op is add, sub, mul, shl, shr, but NOT div or rem. Assert { cond: Operand<'tcx>, expected: bool, msg: AssertMessage<'tcx>, target: BasicBlock, - cleanup: Option<BasicBlock>, + unwind: UnwindAction, }, /// Marks a suspend point. @@ -748,9 +725,8 @@ pub enum TerminatorKind<'tcx> { /// in practice, but in order to avoid fragility we want to always /// consider it in borrowck. We don't want to accept programs which /// pass borrowck only when `panic=abort` or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an `Option` because - /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. - unwind: Option<BasicBlock>, + /// due to release vs. debug mode builds. + unwind: UnwindAction, }, /// Block ends with an inline assembly block. This is a terminator since @@ -773,12 +749,31 @@ pub enum TerminatorKind<'tcx> { /// diverging (InlineAsmOptions::NORETURN). destination: Option<BasicBlock>, - /// Cleanup to be done if the inline assembly unwinds. This is present + /// Action to be taken if the inline assembly unwinds. This is present /// if and only if InlineAsmOptions::MAY_UNWIND is set. - cleanup: Option<BasicBlock>, + unwind: UnwindAction, }, } +/// Action to be taken when a stack unwind happens. +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum UnwindAction { + /// No action is to be taken. Continue unwinding. + /// + /// This is similar to `Cleanup(bb)` where `bb` does nothing but `Resume`, but they are not + /// equivalent, as presence of `Cleanup(_)` will make a frame non-POF. + Continue, + /// Triggers undefined behavior if unwind happens. + Unreachable, + /// Terminates the execution if unwind happens. + /// + /// Depending on the platform and situation this may cause a non-unwindable panic or abort. + Terminate, + /// Cleanups to be done. + Cleanup(BasicBlock), +} + /// Information about an assertion failure. #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum AssertKind<O> { @@ -789,6 +784,7 @@ pub enum AssertKind<O> { RemainderByZero(O), ResumedAfterReturn(GeneratorKind), ResumedAfterPanic(GeneratorKind), + MisalignedPointerDereference { required: O, found: O }, } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -917,7 +913,15 @@ pub struct Place<'tcx> { #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum ProjectionElem<V, T> { Deref, - Field(Field, T), + + /// A field (e.g., `f` in `_1.f`) is one variant of [`ProjectionElem`]. Conceptually, + /// rustc can identify that a field projection refers to either two different regions of memory + /// or the same one between the base and the 'projection element'. + /// Read more about projections in the [rustc-dev-guide][mir-datatypes] + /// + /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types + Field(FieldIdx, T), + /// Index into a slice/array. /// /// Note that this does not also dereference, and so it does not exactly correspond to slice @@ -1110,11 +1114,7 @@ pub enum Rvalue<'tcx> { /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// /// For addition, subtraction, and multiplication on integers the error condition is set when - /// the infinite precision result would be unequal to the actual result. - /// - /// For shift operations on integers the error condition is set when the value of right-hand - /// side is greater than or equal to the number of bits in the type of the left-hand side, or - /// when the value of right-hand side is negative. + /// the infinite precision result would not be equal to the actual result. /// /// Other combinations of types and operators are unsupported. CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), @@ -1149,7 +1149,7 @@ pub enum Rvalue<'tcx> { /// /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After /// generator lowering, `Generator` aggregate kinds are disallowed too. - Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), + Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>), /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. /// @@ -1189,6 +1189,13 @@ pub enum CastKind { IntToFloat, PtrToPtr, FnPtrToPtr, + /// Reinterpret the bits of the input as a different type. + /// + /// MIR is well-formed if the input and output types have different sizes, + /// but running a transmute between differently-sized types is UB. + /// + /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`]. + Transmute, } #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -1199,11 +1206,11 @@ pub enum AggregateKind<'tcx> { Tuple, /// The second field is the variant index. It's equal to 0 for struct - /// and union expressions. The fourth field is + /// and union expressions. The last field is the /// active field number and is present only for union expressions /// -- e.g., for a union expression `SomeUnion { c: .. }`, the /// active field index would identity the field `c` - Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), + Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<FieldIdx>), Closure(DefId, SubstsRef<'tcx>), Generator(DefId, SubstsRef<'tcx>, hir::Movability), @@ -1280,7 +1287,7 @@ pub enum BinOp { mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(AggregateKind<'_>, 40); + static_assert_size!(AggregateKind<'_>, 32); static_assert_size!(Operand<'_>, 24); static_assert_size!(Place<'_>, 16); static_assert_size!(PlaceElem<'_>, 24); diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 0aa2c500f..4f00abf7f 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -6,7 +6,7 @@ use crate::mir::*; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct PlaceTy<'tcx> { @@ -33,7 +33,7 @@ impl<'tcx> PlaceTy<'tcx> { /// /// Note that the resulting type has not been normalized. #[instrument(level = "debug", skip(tcx), ret)] - pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> { + pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { match self.ty.kind() { ty::Adt(adt_def, substs) => { let variant_def = match self.variant_index { @@ -43,7 +43,7 @@ impl<'tcx> PlaceTy<'tcx> { &adt_def.variant(variant_index) } }; - let field_def = &variant_def.fields[f.index()]; + let field_def = &variant_def.fields[f]; field_def.ty(tcx, substs) } ty::Tuple(tys) => tys[f.index()], @@ -61,14 +61,14 @@ impl<'tcx> PlaceTy<'tcx> { /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` /// projects `place_ty` onto `elem`, returning the appropriate /// `Ty` or downcast variant corresponding to that projection. - /// The `handle_field` callback must map a `Field` to its `Ty`, + /// The `handle_field` callback must map a `FieldIdx` to its `Ty`, /// (which should be trivial when `T` = `Ty`). pub fn projection_ty_core<V, T>( self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem<V, T>, - mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, + mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where @@ -98,7 +98,7 @@ impl<'tcx> PlaceTy<'tcx> { ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); - let len = size - (from as u64) - (to as u64); + let len = size - from - to; tcx.mk_array(*inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), @@ -116,7 +116,7 @@ impl<'tcx> PlaceTy<'tcx> { } impl<'tcx> Place<'tcx> { - pub fn ty_from<D>( + pub fn ty_from<D: ?Sized>( local: Local, projection: &[PlaceElem<'tcx>], local_decls: &D, @@ -132,7 +132,7 @@ impl<'tcx> Place<'tcx> { }) } - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx>, { @@ -141,7 +141,7 @@ impl<'tcx> Place<'tcx> { } impl<'tcx> PlaceRef<'tcx> { - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx>, { @@ -155,7 +155,7 @@ pub enum RvalueInitializationState { } impl<'tcx> Rvalue<'tcx> { - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> where D: HasLocalDecls<'tcx>, { @@ -164,17 +164,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Repeat(ref operand, count) => { tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count) } - Rvalue::ThreadLocalRef(did) => { - let static_ty = tcx.type_of(did).subst_identity(); - if tcx.is_mutable_static(did) { - tcx.mk_mut_ptr(static_ty) - } else if tcx.is_foreign_item(did) { - tcx.mk_imm_ptr(static_ty) - } else { - // FIXME: These things don't *really* have 'static lifetime. - tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty) - } - } + Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) @@ -227,7 +217,7 @@ impl<'tcx> Rvalue<'tcx> { } impl<'tcx> Operand<'tcx> { - pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> where D: HasLocalDecls<'tcx>, { diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 6e905224c..2c6126cdd 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,6 +1,6 @@ use smallvec::SmallVec; -use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind}; +use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction}; use rustc_ast::InlineAsmTemplatePiece; pub use rustc_ast::Mutability; use rustc_macros::HashStable; @@ -118,11 +118,11 @@ impl<'tcx> Terminator<'tcx> { self.kind.successors_mut() } - pub fn unwind(&self) -> Option<&Option<BasicBlock>> { + pub fn unwind(&self) -> Option<&UnwindAction> { self.kind.unwind() } - pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { + pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { self.kind.unwind_mut() } } @@ -135,35 +135,33 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { target: None, cleanup: None, .. } - | InlineAsm { destination: None, cleanup: None, .. } => { - None.into_iter().chain((&[]).into_iter().copied()) + Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } + | Yield { resume: t, drop: Some(ref u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) } Goto { target: t } - | Call { target: None, cleanup: Some(t), .. } - | Call { target: Some(t), cleanup: None, .. } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } | Yield { resume: t, drop: None, .. } - | DropAndReplace { target: t, unwind: None, .. } - | Drop { target: t, unwind: None, .. } - | Assert { target: t, cleanup: None, .. } - | FalseUnwind { real_target: t, unwind: None } - | InlineAsm { destination: Some(t), cleanup: None, .. } - | InlineAsm { destination: None, cleanup: Some(t), .. } => { + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | FalseUnwind { real_target: t, unwind: _ } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { Some(t).into_iter().chain((&[]).into_iter().copied()) } - Call { target: Some(t), cleanup: Some(ref u), .. } - | Yield { resume: t, drop: Some(ref u), .. } - | DropAndReplace { target: t, unwind: Some(ref u), .. } - | Drop { target: t, unwind: Some(ref u), .. } - | Assert { target: t, cleanup: Some(ref u), .. } - | FalseUnwind { real_target: t, unwind: Some(ref u) } - | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => { - Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + Resume + | Terminate + | GeneratorDrop + | Return + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { + None.into_iter().chain((&[]).into_iter().copied()) } SwitchInt { ref targets, .. } => { None.into_iter().chain(targets.targets.iter().copied()) @@ -177,34 +175,34 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { target: None, cleanup: None, .. } - | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), + Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. } + | Yield { resume: ref mut t, drop: Some(ref mut u), .. } + | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } + | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } + | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } + | InlineAsm { + destination: Some(ref mut t), + unwind: UnwindAction::Cleanup(ref mut u), + .. + } => Some(t).into_iter().chain(slice::from_mut(u)), Goto { target: ref mut t } - | Call { target: None, cleanup: Some(ref mut t), .. } - | Call { target: Some(ref mut t), cleanup: None, .. } + | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } + | Call { target: Some(ref mut t), unwind: _, .. } | Yield { resume: ref mut t, drop: None, .. } - | DropAndReplace { target: ref mut t, unwind: None, .. } - | Drop { target: ref mut t, unwind: None, .. } - | Assert { target: ref mut t, cleanup: None, .. } - | FalseUnwind { real_target: ref mut t, unwind: None } - | InlineAsm { destination: Some(ref mut t), cleanup: None, .. } - | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => { + | Drop { target: ref mut t, unwind: _, .. } + | Assert { target: ref mut t, unwind: _, .. } + | FalseUnwind { real_target: ref mut t, unwind: _ } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. } + | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { Some(t).into_iter().chain(&mut []) } - Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } - | Drop { target: ref mut t, unwind: Some(ref mut u), .. } - | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } - | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } - | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => { - Some(t).into_iter().chain(slice::from_mut(u)) - } + Resume + | Terminate + | GeneratorDrop + | Return + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []), SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets), FalseEdge { ref mut real_target, ref mut imaginary_target } => { Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) @@ -212,43 +210,41 @@ impl<'tcx> TerminatorKind<'tcx> { } } - pub fn unwind(&self) -> Option<&Option<BasicBlock>> { + pub fn unwind(&self) -> Option<&UnwindAction> { match *self { TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } => None, - TerminatorKind::Call { cleanup: ref unwind, .. } - | TerminatorKind::Assert { cleanup: ref unwind, .. } - | TerminatorKind::DropAndReplace { ref unwind, .. } + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } | TerminatorKind::Drop { ref unwind, .. } | TerminatorKind::FalseUnwind { ref unwind, .. } - | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind), + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), } } - pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> { + pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { match *self { TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } => None, - TerminatorKind::Call { cleanup: ref mut unwind, .. } - | TerminatorKind::Assert { cleanup: ref mut unwind, .. } - | TerminatorKind::DropAndReplace { ref mut unwind, .. } + TerminatorKind::Call { ref mut unwind, .. } + | TerminatorKind::Assert { ref mut unwind, .. } | TerminatorKind::Drop { ref mut unwind, .. } | TerminatorKind::FalseUnwind { ref mut unwind, .. } - | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind), + | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind), } } @@ -274,11 +270,17 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { let labels = self.fmt_successor_labels(); assert_eq!(successor_count, labels.len()); - match successor_count { - 0 => Ok(()), - - 1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()), - + let unwind = match self.unwind() { + // Not needed or included in successors + None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None, + Some(UnwindAction::Unreachable) => Some("unwind unreachable"), + Some(UnwindAction::Terminate) => Some("unwind terminate"), + }; + + match (successor_count, unwind) { + (0, None) => Ok(()), + (0, Some(unwind)) => write!(fmt, " -> {}", unwind), + (1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()), _ => { write!(fmt, " -> [")?; for (i, target) in self.successors().enumerate() { @@ -287,6 +289,9 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { } write!(fmt, "{}: {:?}", labels[i], target)?; } + if let Some(unwind) = unwind { + write!(fmt, ", {unwind}")?; + } write!(fmt, "]") } } @@ -305,13 +310,10 @@ impl<'tcx> TerminatorKind<'tcx> { Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), - Abort => write!(fmt, "abort"), + Terminate => write!(fmt, "abort"), Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), Drop { place, .. } => write!(fmt, "drop({:?})", place), - DropAndReplace { place, value, .. } => { - write!(fmt, "replace({:?} <- {:?})", place, value) - } Call { func, args, destination, .. } => { write!(fmt, "{:?} = ", destination)?; write!(fmt, "{:?}(", func)?; @@ -387,7 +389,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { use self::TerminatorKind::*; match *self { - Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], + Return | Resume | Terminate | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref targets, .. } => targets .values @@ -395,31 +397,35 @@ impl<'tcx> TerminatorKind<'tcx> { .map(|&u| Cow::Owned(u.to_string())) .chain(iter::once("otherwise".into())) .collect(), - Call { target: Some(_), cleanup: Some(_), .. } => { + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { vec!["return".into(), "unwind".into()] } - Call { target: Some(_), cleanup: None, .. } => vec!["return".into()], - Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()], - Call { target: None, cleanup: None, .. } => vec![], + Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()], + Call { target: None, unwind: _, .. } => vec![], Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], Yield { drop: None, .. } => vec!["resume".into()], - DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { - vec!["return".into()] - } - DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => { - vec!["return".into(), "unwind".into()] + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: _, .. } => vec!["return".into()], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] } - Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => vec!["success".into(), "unwind".into()], + Assert { unwind: _, .. } => vec!["success".into()], FalseEdge { .. } => vec!["real".into(), "imaginary".into()], - FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], - FalseUnwind { unwind: None, .. } => vec!["real".into()], - InlineAsm { destination: Some(_), cleanup: Some(_), .. } => { + FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["real".into(), "unwind".into()] + } + FalseUnwind { unwind: _, .. } => vec!["real".into()], + InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { vec!["return".into(), "unwind".into()] } - InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()], - InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], - InlineAsm { destination: None, cleanup: None, .. } => vec![], + InlineAsm { destination: Some(_), unwind: _, .. } => { + vec!["return".into()] + } + InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => { + vec!["unwind".into()] + } + InlineAsm { destination: None, unwind: _, .. } => vec![], } } } diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index f37222cb2..7d247eeb6 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx> { - basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>, + basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, visited: BitSet<BasicBlock>, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, @@ -109,7 +109,7 @@ pub struct Postorder<'a, 'tcx> { impl<'a, 'tcx> Postorder<'a, 'tcx> { pub fn new( - basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>, + basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, root: BasicBlock, ) -> Postorder<'a, 'tcx> { let mut po = Postorder { @@ -178,17 +178,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - loop { - let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(bb) = iter.next() { - bb - } else { - break; - } - } else { - break; - }; - + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 5c056b299..caa5edc32 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -335,12 +335,14 @@ macro_rules! make_mir_visitor { ty::InstanceDef::VTableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | + ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | ty::InstanceDef::DropGlue(_def_id, Some(ty)) | - ty::InstanceDef::CloneShim(_def_id, ty) => { + ty::InstanceDef::CloneShim(_def_id, ty) | + ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } @@ -405,6 +407,13 @@ macro_rules! make_mir_visitor { StatementKind::Retag(kind, place) => { self.visit_retag($(& $mutability)? *kind, place, location); } + StatementKind::PlaceMention(place) => { + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::PlaceMention), + location + ); + } StatementKind::AscribeUserType( box (place, user_ty), variance @@ -453,7 +462,7 @@ macro_rules! make_mir_visitor { match kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | - TerminatorKind::Abort | + TerminatorKind::Terminate | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } | @@ -495,26 +504,12 @@ macro_rules! make_mir_visitor { ); } - TerminatorKind::DropAndReplace { - place, - value, - target: _, - unwind: _, - } => { - self.visit_place( - place, - PlaceContext::MutatingUse(MutatingUseContext::Drop), - location - ); - self.visit_operand(value, location); - } - TerminatorKind::Call { func, args, destination, target: _, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _ } => { @@ -534,7 +529,7 @@ macro_rules! make_mir_visitor { expected: _, msg, target: _, - cleanup: _, + unwind: _, } => { self.visit_operand(cond, location); self.visit_assert_message(msg, location); @@ -560,7 +555,7 @@ macro_rules! make_mir_visitor { options: _, line_spans: _, destination: _, - cleanup: _, + unwind: _, } => { for op in operands { match op { @@ -615,6 +610,10 @@ macro_rules! make_mir_visitor { ResumedAfterReturn(_) | ResumedAfterPanic(_) => { // Nothing to visit } + MisalignedPointerDereference { required, found } => { + self.visit_operand(required, location); + self.visit_operand(found, location); + } } } @@ -641,8 +640,8 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::NonMutatingUse( - NonMutatingUseContext::UniqueBorrow + BorrowKind::Unique => PlaceContext::MutatingUse( + MutatingUseContext::Borrow ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), @@ -811,7 +810,6 @@ macro_rules! make_mir_visitor { source_info, internal: _, local_info: _, - is_block_tail: _, } = local_decl; self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { @@ -834,6 +832,7 @@ macro_rules! make_mir_visitor { name: _, source_info, value, + argument_index: _, } = var_debug_info; self.visit_source_info(source_info); @@ -1248,8 +1247,6 @@ pub enum NonMutatingUseContext { SharedBorrow, /// Shallow borrow. ShallowBorrow, - /// Unique borrow. - UniqueBorrow, /// AddressOf for *const pointer. AddressOf, /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place. @@ -1302,6 +1299,8 @@ pub enum NonUseContext { AscribeUserTy, /// The data of a user variable, for debug info. VarDebugInfo, + /// PlaceMention statement. + PlaceMention, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -1323,9 +1322,7 @@ impl PlaceContext { matches!( self, PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::ShallowBorrow - | NonMutatingUseContext::UniqueBorrow + NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) ) } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs new file mode 100644 index 000000000..7d9aea022 --- /dev/null +++ b/compiler/rustc_middle/src/query/erase.rs @@ -0,0 +1,336 @@ +use crate::mir; +use crate::traits; +use crate::ty::{self, Ty}; +use std::mem::{size_of, transmute_copy, MaybeUninit}; + +#[derive(Copy, Clone)] +pub struct Erased<T: Copy> { + // We use `MaybeUninit` here so we can store any value + // in `data` since we aren't actually storing a `T`. + data: MaybeUninit<T>, +} + +pub trait EraseType: Copy { + type Result: Copy; +} + +// Allow `type_alias_bounds` since compilation will fail without `EraseType`. +#[allow(type_alias_bounds)] +pub type Erase<T: EraseType> = Erased<impl Copy>; + +#[inline(always)] +pub fn erase<T: EraseType>(src: T) -> Erase<T> { + // Ensure the sizes match + const { + if std::mem::size_of::<T>() != std::mem::size_of::<T::Result>() { + panic!("size of T must match erased type T::Result") + } + }; + + Erased::<<T as EraseType>::Result> { + // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. + data: unsafe { transmute_copy(&src) }, + } +} + +/// Restores an erased value. +#[inline(always)] +pub fn restore<T: EraseType>(value: Erase<T>) -> T { + let value: Erased<<T as EraseType>::Result> = value; + // SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance + // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of + // the right size. + unsafe { transmute_copy(&value.data) } +} + +impl<T> EraseType for &'_ T { + type Result = [u8; size_of::<*const ()>()]; +} + +impl<T> EraseType for &'_ [T] { + type Result = [u8; size_of::<*const [()]>()]; +} + +impl<T> EraseType for &'_ ty::List<T> { + type Result = [u8; size_of::<*const ()>()]; +} + +impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> { + type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()]; +} + +impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()]; +} + +impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> { + type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()]; +} + +impl<T> EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> { + type Result = [u8; size_of::<Result<&'static (), ty::layout::FnAbiError<'static>>>()]; +} + +impl<T> EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::< + Result<(&'static (), rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed>, + >()]; +} + +impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()]; +} + +impl EraseType for Result<Option<ty::Const<'_>>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::<Result<Option<ty::Const<'static>>, rustc_errors::ErrorGuaranteed>>()]; +} + +impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> { + type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()]; +} + +impl EraseType for Result<bool, ty::layout::LayoutError<'_>> { + type Result = [u8; size_of::<Result<bool, ty::layout::LayoutError<'static>>>()]; +} + +impl EraseType for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, ty::layout::LayoutError<'_>> { + type Result = [u8; size_of::< + Result< + rustc_target::abi::TyAndLayout<'static, Ty<'static>>, + ty::layout::LayoutError<'static>, + >, + >()]; +} + +impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> { + type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> { + type Result = + [u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result<mir::interpret::ConstAlloc<'_>, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result<mir::interpret::ConstAlloc<'static>, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result<mir::interpret::ConstValue<'_>, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result<mir::interpret::ConstValue<'static>, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result<Option<ty::ValTree<'_>>, mir::interpret::ErrorHandled> { + type Result = + [u8; size_of::<Result<Option<ty::ValTree<'static>>, mir::interpret::ErrorHandled>>()]; +} + +impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> { + type Result = + [u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()]; +} + +impl<T> EraseType for Option<&'_ T> { + type Result = [u8; size_of::<Option<&'static ()>>()]; +} + +impl<T> EraseType for Option<&'_ [T]> { + type Result = [u8; size_of::<Option<&'static [()]>>()]; +} + +impl EraseType for Option<rustc_middle::hir::Owner<'_>> { + type Result = [u8; size_of::<Option<rustc_middle::hir::Owner<'static>>>()]; +} + +impl EraseType for Option<mir::DestructuredConstant<'_>> { + type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()]; +} + +impl EraseType for Option<ty::EarlyBinder<ty::TraitRef<'_>>> { + type Result = [u8; size_of::<Option<ty::EarlyBinder<ty::TraitRef<'static>>>>()]; +} + +impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> { + type Result = [u8; size_of::<Option<ty::EarlyBinder<Ty<'static>>>>()]; +} + +impl<T> EraseType for rustc_hir::MaybeOwner<&'_ T> { + type Result = [u8; size_of::<rustc_hir::MaybeOwner<&'static ()>>()]; +} + +impl<T: EraseType> EraseType for ty::EarlyBinder<T> { + type Result = T::Result; +} + +impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { + type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()]; +} + +impl<T0, T1> EraseType for (&'_ T0, &'_ T1) { + type Result = [u8; size_of::<(&'static (), &'static ())>()]; +} + +impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) { + type Result = [u8; size_of::<(&'static (), &'static [()])>()]; +} + +macro_rules! trivial { + ($($ty:ty),+ $(,)?) => { + $( + impl EraseType for $ty { + type Result = [u8; size_of::<$ty>()]; + } + )* + } +} + +trivial! { + (), + bool, + Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, + Option<rustc_ast::expand::allocator::AllocatorKind>, + Option<rustc_attr::ConstStability>, + Option<rustc_attr::DefaultBodyStability>, + Option<rustc_attr::Stability>, + Option<rustc_data_structures::svh::Svh>, + Option<rustc_hir::def::DefKind>, + Option<rustc_hir::GeneratorKind>, + Option<rustc_hir::HirId>, + Option<rustc_middle::middle::stability::DeprecationEntry>, + Option<rustc_middle::ty::Destructor>, + Option<rustc_middle::ty::ImplTraitInTraitData>, + Option<rustc_span::def_id::CrateNum>, + Option<rustc_span::def_id::DefId>, + Option<rustc_span::def_id::LocalDefId>, + Option<rustc_span::Span>, + Option<rustc_target::spec::PanicStrategy>, + Option<usize>, + Result<(), rustc_errors::ErrorGuaranteed>, + Result<(), rustc_middle::traits::query::NoSolution>, + Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>, + rustc_ast::expand::allocator::AllocatorKind, + rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, + rustc_attr::Deprecation, + rustc_attr::Stability, + rustc_data_structures::svh::Svh, + rustc_errors::ErrorGuaranteed, + rustc_hir::Constness, + rustc_hir::def_id::DefId, + rustc_hir::def_id::DefIndex, + rustc_hir::def_id::LocalDefId, + rustc_hir::def::DefKind, + rustc_hir::Defaultness, + rustc_hir::definitions::DefKey, + rustc_hir::GeneratorKind, + rustc_hir::HirId, + rustc_hir::IsAsync, + rustc_hir::ItemLocalId, + rustc_hir::LangItem, + rustc_hir::OwnerId, + rustc_hir::Upvar, + rustc_index::bit_set::FiniteBitSet<u32>, + rustc_middle::middle::dependency_format::Linkage, + rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, + rustc_middle::middle::resolve_bound_vars::ResolvedArg, + rustc_middle::middle::stability::DeprecationEntry, + rustc_middle::mir::ConstQualifs, + rustc_middle::mir::interpret::AllocId, + rustc_middle::mir::interpret::ErrorHandled, + rustc_middle::mir::interpret::LitToConstError, + rustc_middle::thir::ExprId, + rustc_middle::traits::CodegenObligationError, + rustc_middle::traits::EvaluationResult, + rustc_middle::traits::OverflowError, + rustc_middle::traits::query::NoSolution, + rustc_middle::traits::WellFormedLoc, + rustc_middle::ty::adjustment::CoerceUnsizedInfo, + rustc_middle::ty::AssocItem, + rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::BoundVariableKind, + rustc_middle::ty::DeducedParamAttrs, + rustc_middle::ty::Destructor, + rustc_middle::ty::fast_reject::SimplifiedType, + rustc_middle::ty::ImplPolarity, + rustc_middle::ty::Representability, + rustc_middle::ty::ReprOptions, + rustc_middle::ty::UnusedGenericParams, + rustc_middle::ty::util::AlwaysRequiresDrop, + rustc_middle::ty::Visibility<rustc_span::def_id::DefId>, + rustc_session::config::CrateType, + rustc_session::config::EntryFnType, + rustc_session::config::OptLevel, + rustc_session::config::SymbolManglingVersion, + rustc_session::cstore::CrateDepKind, + rustc_session::cstore::ExternCrate, + rustc_session::cstore::LinkagePreference, + rustc_session::Limits, + rustc_session::lint::LintExpectationId, + rustc_span::def_id::CrateNum, + rustc_span::def_id::DefPathHash, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::symbol::Ident, + rustc_target::spec::PanicStrategy, + rustc_type_ir::Variance, + u32, + usize, +} + +macro_rules! tcx_lifetime { + ($($($fake_path:ident)::+),+ $(,)?) => { + $( + impl<'tcx> EraseType for $($fake_path)::+<'tcx> { + type Result = [u8; size_of::<$($fake_path)::+<'static>>()]; + } + )* + } +} + +tcx_lifetime! { + rustc_middle::hir::Owner, + rustc_middle::middle::exported_symbols::ExportedSymbol, + rustc_middle::mir::ConstantKind, + rustc_middle::mir::DestructuredConstant, + rustc_middle::mir::interpret::ConstAlloc, + rustc_middle::mir::interpret::ConstValue, + rustc_middle::mir::interpret::GlobalId, + rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::traits::ChalkEnvironmentAndGoal, + rustc_middle::traits::query::MethodAutoderefStepsResult, + rustc_middle::traits::query::type_op::AscribeUserType, + rustc_middle::traits::query::type_op::Eq, + rustc_middle::traits::query::type_op::ProvePredicate, + rustc_middle::traits::query::type_op::Subtype, + rustc_middle::ty::AdtDef, + rustc_middle::ty::AliasTy, + rustc_middle::ty::Clause, + rustc_middle::ty::ClosureTypeInfo, + rustc_middle::ty::Const, + rustc_middle::ty::DestructuredConst, + rustc_middle::ty::ExistentialTraitRef, + rustc_middle::ty::FnSig, + rustc_middle::ty::GenericArg, + rustc_middle::ty::GenericPredicates, + rustc_middle::ty::inhabitedness::InhabitedPredicate, + rustc_middle::ty::Instance, + rustc_middle::ty::InstanceDef, + rustc_middle::ty::layout::FnAbiError, + rustc_middle::ty::layout::LayoutError, + rustc_middle::ty::ParamEnv, + rustc_middle::ty::Predicate, + rustc_middle::ty::SymbolName, + rustc_middle::ty::TraitRef, + rustc_middle::ty::Ty, + rustc_middle::ty::UnevaluatedConst, + rustc_middle::ty::ValTree, + rustc_middle::ty::VtblEntry, +} diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 78ee8a6a8..23b28ac5c 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -12,6 +12,11 @@ use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi::FieldIdx; + +/// Placeholder for `CrateNum`'s "local" counterpart +#[derive(Copy, Clone, Debug)] +pub struct LocalCrate; /// The `Key` trait controls what types can legally be used as the key /// for a query. @@ -21,15 +26,11 @@ pub trait Key: Sized { // // ...But r-a doesn't support them yet and using a default here causes r-a to not infer // return types of queries which is very annoying. Thus, until r-a support associated - // type defaults, plese restrain from using them here <3 + // type defaults, please restrain from using them here <3 // // r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693> type CacheSelector; - /// Given an instance of this key, what crate is it referring to? - /// This is used to find the provider. - fn query_crate_is_local(&self) -> bool; - /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? fn default_span(&self, tcx: TyCtxt<'_>) -> Span; @@ -45,14 +46,17 @@ pub trait Key: Sized { } } +pub trait AsLocalKey: Key { + type LocalKey; + + /// Given an instance of this key, what crate is it referring to? + /// This is used to find the provider. + fn as_local_key(&self) -> Option<Self::LocalKey>; +} + impl Key for () { type CacheSelector = SingleCacheSelector; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -61,23 +65,22 @@ impl Key for () { impl<'tcx> Key for ty::InstanceDef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } } -impl<'tcx> Key for ty::Instance<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; +impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { + type LocalKey = Self; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option<Self::LocalKey> { + self.def_id().is_local().then(|| *self) } +} + +impl<'tcx> Key for ty::Instance<'tcx> { + type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -87,11 +90,6 @@ impl<'tcx> Key for ty::Instance<'tcx> { impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.instance.default_span(tcx) } @@ -100,11 +98,6 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -113,11 +106,6 @@ impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -126,25 +114,27 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { impl Key for CrateNum { type CacheSelector = VecCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - *self == LOCAL_CRATE - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for OwnerId { - type CacheSelector = VecCacheSelector<Self>; +impl AsLocalKey for CrateNum { + type LocalKey = LocalCrate; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option<Self::LocalKey> { + (*self == LOCAL_CRATE).then_some(LocalCrate) } +} + +impl Key for OwnerId { + type CacheSelector = VecCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { Some(self.to_def_id()) } @@ -153,13 +143,10 @@ impl Key for OwnerId { impl Key for LocalDefId { type CacheSelector = VecCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) } + fn key_as_def_id(&self) -> Option<DefId> { Some(self.to_def_id()) } @@ -168,26 +155,28 @@ impl Key for LocalDefId { impl Key for DefId { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) } + #[inline(always)] fn key_as_def_id(&self) -> Option<DefId> { Some(*self) } } -impl Key for ty::WithOptConstParam<LocalDefId> { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for DefId { + type LocalKey = LocalDefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true + fn as_local_key(&self) -> Option<Self::LocalKey> { + self.as_local() } +} + +impl Key for ty::WithOptConstParam<LocalDefId> { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.did.default_span(tcx) } @@ -196,10 +185,6 @@ impl Key for ty::WithOptConstParam<LocalDefId> { impl Key for SimplifiedType { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -208,10 +193,6 @@ impl Key for SimplifiedType { impl Key for (DefId, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -220,10 +201,6 @@ impl Key for (DefId, DefId) { impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -232,10 +209,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { impl Key for (DefId, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -244,10 +217,6 @@ impl Key for (DefId, LocalDefId) { impl Key for (LocalDefId, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -256,38 +225,27 @@ impl Key for (LocalDefId, DefId) { impl Key for (LocalDefId, LocalDefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } } -impl Key for (DefId, Option<Ident>) { +impl Key for (DefId, Ident) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) } + #[inline(always)] fn key_as_def_id(&self) -> Option<DefId> { Some(self.0) } } -impl Key for (DefId, LocalDefId, Ident) { +impl Key for (LocalDefId, LocalDefId, Ident) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } @@ -296,34 +254,40 @@ impl Key for (DefId, LocalDefId, Ident) { impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) } } -impl Key for (CrateNum, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for (CrateNum, DefId) { + type LocalKey = DefId; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0 == LOCAL_CRATE + fn as_local_key(&self) -> Option<Self::LocalKey> { + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (CrateNum, SimplifiedType) { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } } -impl Key for (DefId, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; +impl AsLocalKey for (CrateNum, SimplifiedType) { + type LocalKey = SimplifiedType; #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE + fn as_local_key(&self) -> Option<Self::LocalKey> { + (self.0 == LOCAL_CRATE).then(|| self.1) } +} + +impl Key for (DefId, SimplifiedType) { + type CacheSelector = DefaultCacheSelector<Self>; + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -332,10 +296,6 @@ impl Key for (DefId, SimplifiedType) { impl<'tcx> Key for SubstsRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -344,10 +304,6 @@ impl<'tcx> Key for SubstsRef<'tcx> { impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -356,10 +312,6 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - (self.0).def.did.krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { (self.0).def.did.default_span(tcx) } @@ -368,10 +320,6 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -380,22 +328,14 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.1.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.1.def_id()) } } -impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { +impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -404,10 +344,6 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -416,10 +352,6 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -428,10 +360,6 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) } @@ -440,10 +368,6 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.0.def_id().krate == LOCAL_CRATE - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0.def_id()) } @@ -452,10 +376,6 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for GenericArg<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -464,10 +384,6 @@ impl<'tcx> Key for GenericArg<'tcx> { impl<'tcx> Key for mir::ConstantKind<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -476,10 +392,6 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { impl<'tcx> Key for ty::Const<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -488,13 +400,10 @@ impl<'tcx> Key for ty::Const<'tcx> { impl<'tcx> Key for Ty<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } + fn ty_adt_id(&self) -> Option<DefId> { match self.kind() { ty::Adt(adt, _) => Some(adt.did()), @@ -506,10 +415,6 @@ impl<'tcx> Key for Ty<'tcx> { impl<'tcx> Key for TyAndLayout<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -518,10 +423,6 @@ impl<'tcx> Key for TyAndLayout<'tcx> { impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -530,10 +431,6 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -542,10 +439,6 @@ impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { impl<'tcx> Key for ty::ParamEnv<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -554,10 +447,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - self.value.query_crate_is_local() - } fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } @@ -566,10 +455,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { impl Key for Symbol { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -578,10 +463,6 @@ impl Key for Symbol { impl Key for Option<Symbol> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -589,14 +470,9 @@ impl Key for Option<Symbol> { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. -impl<'tcx, T> Key for Canonical<'tcx, T> { +impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -605,11 +481,6 @@ impl<'tcx, T> Key for Canonical<'tcx, T> { impl Key for (Symbol, u32, u32) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -618,11 +489,6 @@ impl Key for (Symbol, u32, u32) { impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -631,11 +497,6 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -644,11 +505,6 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -657,11 +513,6 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) } @@ -670,11 +521,6 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP } @@ -683,11 +529,6 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { impl Key for HirId { type CacheSelector = DefaultCacheSelector<Self>; - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.hir().span(*self) } @@ -702,10 +543,6 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; // Just forward to `Ty<'tcx>` - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5133da342..7a5a16035 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,8 +7,9 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; +pub mod erase; mod keys; -pub use keys::Key; +pub use keys::{AsLocalKey, Key, LocalCrate}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -26,6 +27,15 @@ rustc_queries! { desc { "triggering a delay span bug" } } + query registered_tools(_: ()) -> &'tcx ty::RegisteredTools { + arena_cache + desc { "compute registered tools for crate" } + } + + query early_lint_checks(_: ()) -> () { + desc { "perform lints prior to macro expansion" } + } + query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { feedable no_hash @@ -87,7 +97,7 @@ rustc_queries! { /// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any. /// - /// Definitions that were generated with no HIR, would be feeded to return `None`. + /// Definitions that were generated with no HIR, would be fed to return `None`. query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId>{ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) } feedable @@ -182,6 +192,7 @@ rustc_queries! { { desc { "determine whether the opaque is a type-alias impl trait" } separate_provide_extern + feedable } query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> @@ -616,20 +627,26 @@ rustc_queries! { separate_provide_extern } + query implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the implied predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the /// subset of super-predicates that reference traits that define the given associated type. /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_type(key: (DefId, Option<rustc_span::symbol::Ident>)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the super traits of `{}`{}", + query super_predicates_that_define_assoc_type(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the super traits of `{}` with associated type name `{}`", tcx.def_path_str(key.0), - if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, + key.1 } } /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (LocalDefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } } @@ -764,7 +781,7 @@ rustc_queries! { /// /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be ///`{ trait_f: impl_f, trait_g: impl_g }` - query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> { + query impl_item_implementor_ids(impl_id: DefId) -> &'tcx DefIdMap<DefId> { arena_cache desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) } } @@ -775,7 +792,7 @@ rustc_queries! { /// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it /// creates and returns the associated items that correspond to each impl trait in return position /// of the implemented trait. - query associated_items_for_impl_trait_in_trait(fn_def_id: DefId) -> &'tcx [DefId] { + query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] { desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) } cache_on_disk_if { fn_def_id.is_local() } separate_provide_extern @@ -783,10 +800,9 @@ rustc_queries! { /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. - query associated_item_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { + query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } cache_on_disk_if { true } - separate_provide_extern } /// Given an `impl_id`, return the trait it implements. @@ -906,8 +922,8 @@ rustc_queries! { /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and /// their respective impl (i.e., part of the derive macro) query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx ( - FxHashSet<LocalDefId>, - FxHashMap<LocalDefId, Vec<(DefId, DefId)>> + LocalDefIdSet, + LocalDefIdMap<Vec<(DefId, DefId)>> ) { arena_cache desc { "finding live symbols in crate" } @@ -1105,9 +1121,9 @@ rustc_queries! { desc { "converting literal to mir constant" } } - query check_match(key: DefId) { - desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } + query check_match(key: LocalDefId) { + desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } } /// Performs part of the privacy check and computes effective visibilities. @@ -1120,7 +1136,7 @@ rustc_queries! { desc { "checking for private elements in public interfaces" } } - query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> { + query reachable_set(_: ()) -> &'tcx LocalDefIdSet { arena_cache desc { "reachability" } } @@ -1152,14 +1168,6 @@ rustc_queries! { feedable } - /// The `opt_rpitit_info` query returns the pair of the def id of the function where the RPIT - /// is defined and the opaque def id if any. - query opt_rpitit_info(def_id: DefId) -> Option<ty::ImplTraitInTraitData> { - desc { |tcx| "opt_rpitit_info `{}`", tcx.def_path_str(def_id) } - cache_on_disk_if { def_id.is_local() } - feedable - } - /// Gets the span for the definition. query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } @@ -1229,7 +1237,7 @@ rustc_queries! { separate_provide_extern } - query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> { + query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> { desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) } } @@ -1324,6 +1332,7 @@ rustc_queries! { /// might want to use `reveal_all()` method to change modes. query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } + feedable } /// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode. @@ -1507,10 +1516,6 @@ rustc_queries! { desc { "getting traits in scope at a block" } } - query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> { - desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) } - } - query impl_defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } @@ -1845,7 +1850,7 @@ rustc_queries! { query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> { desc { "fetching potentially unused trait imports" } } - query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> { + query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet<Symbol> { desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) } } @@ -2114,7 +2119,7 @@ rustc_queries! { desc { "raw operations for metadata file access" } } - query crate_for_resolver((): ()) -> &'tcx Steal<rustc_ast::ast::Crate> { + query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> { feedable no_hash desc { "the ast before macro expansion and name resolution" } @@ -2213,7 +2218,7 @@ rustc_queries! { } /// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being - /// equal to eachother. This might return `Ok` even if the types are unequal, but will never return `Err` if + /// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if /// the types might be equal. query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> { desc { "check whether two const param are definitely not equal to eachother"} diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3b11fab8c..7d79a13d3 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -17,14 +17,14 @@ use rustc_index::newtype_index; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; -use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp}; +use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; @@ -227,6 +227,9 @@ pub enum StmtKind<'tcx> { /// The lint level for this `let` statement. lint_level: LintLevel, + + /// Span of the `let <PAT> = <INIT>` part. + span: Span, }, } @@ -366,7 +369,7 @@ pub enum ExprKind<'tcx> { /// Variant containing the field. variant_index: VariantIdx, /// This can be a named (`.foo`) or unnamed (`.0`) field. - name: Field, + name: FieldIdx, }, /// A *non-overloaded* indexing operation. Index { @@ -491,7 +494,7 @@ pub enum ExprKind<'tcx> { /// This is used in struct constructors. #[derive(Clone, Debug, HashStable)] pub struct FieldExpr { - pub name: Field, + pub name: FieldIdx, pub expr: ExprId, } @@ -570,7 +573,7 @@ pub enum BindingMode { #[derive(Clone, Debug, HashStable)] pub struct FieldPat<'tcx> { - pub field: Field, + pub field: FieldIdx, pub pattern: Box<Pat<'tcx>>, } @@ -594,6 +597,55 @@ impl<'tcx> Pat<'tcx> { _ => None, } } + + /// Call `f` on every "binding" in a pattern, e.g., on `a` in + /// `match foo() { Some(a) => (), None => () }` + pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) { + self.walk_always(|p| { + if let PatKind::Binding { name, mode, ty, .. } = p.kind { + f(name, mode, ty, p.span); + } + }); + } + + /// Walk the pattern in left-to-right order. + /// + /// If `it(pat)` returns `false`, the children are not visited. + pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) { + self.walk_(&mut it) + } + + fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) { + if !it(self) { + return; + } + + use PatKind::*; + match &self.kind { + Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {} + AscribeUserType { subpattern, .. } + | Binding { subpattern: Some(subpattern), .. } + | Deref { subpattern } => subpattern.walk_(it), + Leaf { subpatterns } | Variant { subpatterns, .. } => { + subpatterns.iter().for_each(|field| field.pattern.walk_(it)) + } + Or { pats } => pats.iter().for_each(|p| p.walk_(it)), + Array { box ref prefix, ref slice, box ref suffix } + | Slice { box ref prefix, ref slice, box ref suffix } => { + prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it)) + } + } + } + + /// Walk the pattern in left-to-right order. + /// + /// If you always want to recurse, prefer this method over `walk`. + pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) { + self.walk(|p| { + it(p); + true + }) + } } impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { @@ -784,7 +836,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { if let PatKind::Wild = p.pattern.kind { continue; } - let name = variant.fields[p.field.index()].name; + let name = variant.fields[p.field].name; write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; printed += 1; } @@ -879,7 +931,7 @@ mod size_asserts { static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 56); - static_assert_size!(Stmt<'_>, 48); - static_assert_size!(StmtKind<'_>, 40); + static_assert_size!(Stmt<'_>, 56); + static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 79a0e75aa..5614528c4 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -175,6 +175,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm ref pattern, lint_level: _, else_block, + span: _, } => { if let Some(init) = initializer { visitor.visit_expr(&visitor.thir()[*init]); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6231dd9b6..91f07389f 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -305,8 +305,6 @@ pub enum ObligationCauseCode<'tcx> { SizedReturnType, /// Yield type must be `Sized`. SizedYieldType, - /// Box expression result type must be `Sized`. - SizedBoxType, /// Inline asm operand type must be `Sized`. InlineAsmSized, /// `[expr; N]` requires `type_of(expr): Copy`. @@ -699,9 +697,9 @@ impl<'tcx, N> ImplSource<'tcx, N> { } pub fn borrow_nested_obligations(&self) -> &[N] { - match &self { - ImplSource::UserDefined(i) => &i.nested[..], - ImplSource::Param(n, _) => &n, + match self { + ImplSource::UserDefined(i) => &i.nested, + ImplSource::Param(n, _) => n, ImplSource::Builtin(i) => &i.nested, ImplSource::AutoImpl(d) => &d.nested, ImplSource::Closure(c) => &c.nested, @@ -715,6 +713,23 @@ impl<'tcx, N> ImplSource<'tcx, N> { } } + pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { + match self { + ImplSource::UserDefined(i) => &mut i.nested, + ImplSource::Param(n, _) => n, + ImplSource::Builtin(i) => &mut i.nested, + ImplSource::AutoImpl(d) => &mut d.nested, + ImplSource::Closure(c) => &mut c.nested, + ImplSource::Generator(c) => &mut c.nested, + ImplSource::Future(c) => &mut c.nested, + ImplSource::Object(d) => &mut d.nested, + ImplSource::FnPointer(d) => &mut d.nested, + ImplSource::TraitAlias(d) => &mut d.nested, + ImplSource::TraitUpcasting(d) => &mut d.nested, + ImplSource::ConstDestruct(i) => &mut i.nested, + } + } + pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M> where F: FnMut(N) -> M, @@ -899,6 +914,9 @@ pub enum ObjectSafetyViolation { /// (e.g., `trait Foo : Bar<Self>`). SupertraitSelf(SmallVec<[Span; 1]>), + // Supertrait has a non-lifetime `for<T>` binder. + SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>), + /// Method has something illegal. Method(Symbol, MethodViolationCode, Span), @@ -921,6 +939,9 @@ impl ObjectSafetyViolation { .into() } } + ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { + "where clause cannot reference non-lifetime `for<...>` variables".into() + } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() } @@ -971,7 +992,9 @@ impl ObjectSafetyViolation { pub fn solution(&self, err: &mut Diagnostic) { match self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {} + ObjectSafetyViolation::SizedSelf(_) + | ObjectSafetyViolation::SupertraitSelf(_) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {} ObjectSafetyViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), @@ -1025,7 +1048,8 @@ impl ObjectSafetyViolation { // diagnostics use a `note` instead of a `span_label`. match self { ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), + | ObjectSafetyViolation::SizedSelf(spans) + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) | ObjectSafetyViolation::GAT(_, span) | ObjectSafetyViolation::Method(_, _, span) diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index bd43867a3..fef2be133 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,12 +1,113 @@ use std::ops::ControlFlow; use rustc_data_structures::intern::Interned; +use rustc_query_system::cache::Cache; -use crate::infer::canonical::QueryRegionConstraints; +use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; +use crate::traits::query::NoSolution; +use crate::traits::Canonical; use crate::ty::{ - FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, + TypeVisitor, }; +pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>; + +/// A goal is a statement, i.e. `predicate`, we want to prove +/// given some assumptions, i.e. `param_env`. +/// +/// Most of the time the `param_env` contains the `where`-bounds of the function +/// we're currently typechecking while the `predicate` is some trait bound. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub struct Goal<'tcx, P> { + pub predicate: P, + pub param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx, P> Goal<'tcx, P> { + pub fn new( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: impl ToPredicate<'tcx, P>, + ) -> Goal<'tcx, P> { + Goal { param_env, predicate: predicate.to_predicate(tcx) } + } + + /// Updates the goal to one with a different `predicate` but the same `param_env`. + pub fn with<Q>(self, tcx: TyCtxt<'tcx>, predicate: impl ToPredicate<'tcx, Q>) -> Goal<'tcx, Q> { + Goal { param_env: self.param_env, predicate: predicate.to_predicate(tcx) } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub struct Response<'tcx> { + pub certainty: Certainty, + pub var_values: CanonicalVarValues<'tcx>, + /// Additional constraints returned by this query. + pub external_constraints: ExternalConstraints<'tcx>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub enum Certainty { + Yes, + Maybe(MaybeCause), +} + +impl Certainty { + pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); + + /// Use this function to merge the certainty of multiple nested subgoals. + /// + /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested + /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`. + /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in + /// success, we merge these two responses. This results in ambiguity. + /// + /// If we unify ambiguity with overflow, we return overflow. This doesn't matter + /// inside of the solver as we distinguish ambiguity from overflow. It does + /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar` + /// in ambiguity without changing the inference state, we still want to tell the + /// user that `T: Baz` results in overflow. + pub fn unify_with(self, other: Certainty) -> Certainty { + match (self, other) { + (Certainty::Yes, Certainty::Yes) => Certainty::Yes, + (Certainty::Yes, Certainty::Maybe(_)) => other, + (Certainty::Maybe(_), Certainty::Yes) => self, + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { + Certainty::Maybe(MaybeCause::Ambiguity) + } + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { + Certainty::Maybe(MaybeCause::Overflow) + } + } + } +} + +/// Why we failed to evaluate a goal. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub enum MaybeCause { + /// We failed due to ambiguity. This ambiguity can either + /// be a true ambiguity, i.e. there are multiple different answers, + /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals. + Ambiguity, + /// We gave up due to an overflow, most often by hitting the recursion limit. + Overflow, +} + +pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>; + +pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; + +/// The result of evaluating a canonical query. +/// +/// FIXME: We use a different type than the existing canonical queries. This is because +/// we need to add a `Certainty` for `overflow` and may want to restructure this code without +/// having to worry about changes to currently used code. Once we've made progress on this +/// solver, merge the two responses again. +pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; + #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); @@ -14,7 +115,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { type Target = ExternalConstraintsData<'tcx>; fn deref(&self) -> &Self::Target { - &*self.0 + &self.0 } } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index df9aa765d..468c2c818 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -37,10 +37,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { self.tcx } - fn intercrate(&self) -> bool { - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -48,10 +44,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 8ce06404d..cd0f7e8da 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; use rustc_span::Span; +use rustc_target::abi::FieldIdx; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum PointerCast { @@ -208,5 +209,5 @@ pub struct CoerceUnsizedInfo { #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)] pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. - Struct(usize), + Struct(FieldIdx), } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index ec21030b3..3a03c0901 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -10,11 +10,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::{IndexSlice, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; -use rustc_target::abi::{ReprOptions, VariantIdx}; +use rustc_target::abi::{ReprOptions, VariantIdx, FIRST_VARIANT}; use std::cell::RefCell; use std::cmp::Ordering; @@ -168,7 +168,7 @@ impl<'tcx> AdtDef<'tcx> { } #[inline] - pub fn variants(self) -> &'tcx IndexVec<VariantIdx, VariantDef> { + pub fn variants(self) -> &'tcx IndexSlice<VariantIdx, VariantDef> { &self.0.0.variants } @@ -228,7 +228,7 @@ impl AdtDefData { AdtKind::Struct => AdtFlags::IS_STRUCT, }; - if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor.is_some() { + if kind == AdtKind::Struct && variants[FIRST_VARIANT].ctor.is_some() { flags |= AdtFlags::HAS_CTOR; } @@ -357,7 +357,7 @@ impl<'tcx> AdtDef<'tcx> { /// Asserts this is a struct or union and returns its unique variant. pub fn non_enum_variant(self) -> &'tcx VariantDef { assert!(self.is_struct() || self.is_union()); - &self.variant(VariantIdx::new(0)) + &self.variant(FIRST_VARIANT) } #[inline] @@ -493,7 +493,7 @@ impl<'tcx> AdtDef<'tcx> { #[inline] pub fn variant_range(self) -> Range<VariantIdx> { - VariantIdx::new(0)..VariantIdx::new(self.variants().len()) + FIRST_VARIANT..self.variants().next_index() } /// Computes the discriminant value used by a specific variant. diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index f1a9e50a4..090b76932 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -1,6 +1,6 @@ pub use self::AssocItemContainer::*; -use crate::ty::{self, DefIdTree}; +use crate::ty; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; @@ -30,6 +30,11 @@ pub struct AssocItem { /// Whether this is a method with an explicit self /// as its first parameter, allowing method calls. pub fn_has_self_parameter: bool, + + /// `Some` if the associated item (an associated type) comes from the + /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` + /// provides additional information about its source. + pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>, } impl AssocItem { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index dc2bd54b7..f29bf92b0 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -158,12 +158,12 @@ impl<'tcx> CapturedPlace<'tcx> { for proj in self.place.projections.iter() { match proj.kind { HirProjectionKind::Field(idx, variant) => match ty.kind() { - ty::Tuple(_) => write!(&mut symbol, "__{}", idx).unwrap(), + ty::Tuple(_) => write!(&mut symbol, "__{}", idx.index()).unwrap(), ty::Adt(def, ..) => { write!( &mut symbol, "__{}", - def.variant(variant).fields[idx as usize].name.as_str(), + def.variant(variant).fields[idx].name.as_str(), ) .unwrap(); } @@ -356,11 +356,11 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc curr_string = format!( "{}.{}", curr_string, - def.variant(variant).fields[idx as usize].name.as_str() + def.variant(variant).fields[idx].name.as_str() ); } ty::Tuple(_) => { - curr_string = format!("{}.{}", curr_string, idx); + curr_string = format!("{}.{}", curr_string, idx.index()); } _ => { bug!( diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 3ce80e06a..8ef4a46a7 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -511,8 +511,6 @@ macro_rules! implement_ty_decoder { read_isize -> isize; read_bool -> bool; - read_f64 -> f64; - read_f32 -> f32; read_char -> char; read_str -> &str; } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 527ec9f6e..bcedae233 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,10 +1,10 @@ use crate::middle::resolve_bound_vars as rbv; use crate::mir::interpret::LitToConstInput; -use crate::ty::{self, DefIdTree, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; use std::fmt; @@ -83,7 +83,7 @@ impl<'tcx> Const<'tcx> { None => tcx.mk_const( ty::UnevaluatedConst { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: InternalSubsts::identity_for_item(tcx, def.did), }, ty, ), @@ -135,6 +135,9 @@ impl<'tcx> Const<'tcx> { _, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, )) => { + // Use the type from the param's definition, since we can resolve it, + // not the expected parameter type from WithOptConstParam. + let param_ty = tcx.type_of(def_id).subst_identity(); match tcx.named_bound_var(expr.hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of @@ -143,14 +146,14 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(tcx.mk_const(ty::ParamConst::new(index, name), ty)) + Some(tcx.mk_const(ty::ParamConst::new(index, name), param_ty)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const( ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), - ty, + param_ty, )), Some(rbv::ResolvedArg::Error(guar)) => { - Some(tcx.const_error_with_guaranteed(ty, guar)) + Some(tcx.const_error_with_guaranteed(param_ty, guar)) } arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } @@ -262,8 +265,8 @@ impl<'tcx> Const<'tcx> { } } -pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> { - let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) { +pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> { + let default_def_id = match tcx.hir().get_by_def_id(def_id) { hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(ac), .. }, .. diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index eecd78ab6..c0e557d48 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -237,7 +237,7 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. - /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the /// `ScalarInt`s size in that case. #[inline] pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { @@ -297,7 +297,7 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to a signed integer of the given size. - /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the /// `ScalarInt`s size in that case. #[inline] pub fn try_to_int(self, size: Size) -> Result<i128, Size> { @@ -306,38 +306,38 @@ impl ScalarInt { } /// Tries to convert the `ScalarInt` to i8. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 1 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i8(self) -> Result<i8, Size> { self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i16. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 2 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i16(self) -> Result<i16, Size> { self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i32. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 4 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i32(self) -> Result<i32, Size> { self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i64. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 8 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i64(self) -> Result<i64, Size> { self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) } /// Tries to convert the `ScalarInt` to i128. - /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }` + /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i128(self) -> Result<i128, Size> { - self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) + self.try_to_int(Size::from_bits(128)) } } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 5ed4af2e9..8b96864dd 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -79,7 +79,7 @@ impl<'tcx> ValTree<'tcx> { } pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_scalar_int().map(|s| s.try_to_target_usize(tcx).ok()).flatten() + self.try_to_scalar_int().and_then(|s| s.try_to_target_usize(tcx).ok()) } /// Get the values inside the ValTree as a slice of bytes. This only works for diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d9af2fd74..63f7cc2ee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -8,26 +8,26 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::infer::canonical::CanonicalVarInfo; use crate::lint::struct_lint_level; +use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_bound_vars; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation}; -use crate::mir::{ - Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted, -}; +use crate::mir::{Body, BorrowCheckResult, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::query::LocalCrate; use crate::thir::Thir; use crate::traits; +use crate::traits::solve; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData}; use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, FloatTy, FloatVar, - FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, - ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, - Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, + GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, + TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; @@ -37,6 +37,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal}; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, }; @@ -63,13 +64,14 @@ use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags}; use std::any::Any; +use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -310,7 +312,7 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec<Region<'tcx>>, /// Pre-interned values of the form: - /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) })` + /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(None) })` /// for small values of `i` and `v`. pub re_late_bounds: Vec<Vec<Region<'tcx>>>, } @@ -385,10 +387,7 @@ impl<'tcx> CommonLifetimes<'tcx> { .map(|v| { mk(ty::ReLateBound( ty::DebruijnIndex::from(i), - ty::BoundRegion { - var: ty::BoundVar::from(v), - kind: ty::BrAnon(v, None), - }, + ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon(None) }, )) }) .collect() @@ -537,6 +536,9 @@ pub struct GlobalCtxt<'tcx> { /// Merge this with `selection_cache`? pub evaluation_cache: traits::EvaluationCache<'tcx>, + /// Caches the results of goal evaluation in the new solver. + pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>, + /// Data layout specification for the current target. pub data_layout: TargetDataLayout, @@ -712,6 +714,7 @@ impl<'tcx> TyCtxt<'tcx> { pred_rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), + new_solver_evaluation_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), } @@ -922,7 +925,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name, // Don't print the whole stable crate id. That's just // annoying in debug output. - stable_crate_id.to_u64() >> 8 * 6, + stable_crate_id.to_u64() >> (8 * 6), self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -2044,6 +2047,12 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { + debug_assert_matches!( + (kind, self.def_kind(alias_ty.def_id)), + (ty::Opaque, DefKind::OpaqueTy) + | (ty::Projection, DefKind::AssocTy) + | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) + ); self.mk_ty_from_kind(Alias(kind, alias_ty)) } @@ -2064,10 +2073,9 @@ impl<'tcx> TyCtxt<'tcx> { bound_region: ty::BoundRegion, ) -> Region<'tcx> { // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon(v, None) } = bound_region - && var.as_u32() == v + if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region && let Some(inner) = self.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(v as usize).copied() + && let Some(re) = inner.get(var.as_usize()).copied() { re } else { @@ -2112,7 +2120,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { + pub fn mk_place_field(self, place: Place<'tcx>, f: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> { self.mk_place_elem(place, PlaceElem::Field(f, ty)) } @@ -2372,7 +2380,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { let map = self.in_scope_traits_map(id.owner)?; let candidates = map.get(&id.local_id)?; - Some(&*candidates) + Some(candidates) } pub fn named_bound_var(self, id: HirId) -> Option<resolve_bound_vars::ResolvedArg> { @@ -2440,6 +2448,40 @@ impl<'tcx> TyCtxt<'tcx> { pub fn trait_solver_next(self) -> bool { self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next } + + pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool { + self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty + } + + pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { + if self.lower_impl_trait_in_trait_to_assoc_ty() { + self.opt_rpitit_info(def_id).is_some() + } else { + self.def_kind(def_id) == DefKind::ImplTraitPlaceholder + } + } + + /// Named module children from all items except `use` and `extern crate` imports. + /// + /// In addition to regular items this list also includes struct or variant constructors, and + /// items inside `extern {}` blocks because all of them introduce names into parent module. + /// For non-reexported children every such name is associated with a separate `DefId`. + /// + /// Module here is understood in name resolution sense - it can be a `mod` item, + /// or a crate root, or an enum, or a trait. + pub fn module_children_non_reexports(self, def_id: LocalDefId) -> &'tcx [LocalDefId] { + self.resolutions(()).module_children_non_reexports.get(&def_id).map_or(&[], |v| &v[..]) + } + + /// Named module children from `use` and `extern crate` imports. + /// + /// Reexported names are not associated with individual `DefId`s, + /// e.g. a glob import can introduce a lot of names, all with the same `DefId`. + /// That's why the list needs to contain `ModChild` structures describing all the names + /// individually instead of `DefId`s. + pub fn module_children_reexports(self, def_id: LocalDefId) -> &'tcx [ModChild] { + self.resolutions(()).module_children_reexports.get(&def_id).map_or(&[], |v| &v[..]) + } } impl<'tcx> TyCtxtAt<'tcx> { @@ -2482,26 +2524,21 @@ pub struct DeducedParamAttrs { } pub fn provide(providers: &mut ty::query::Providers) { - providers.module_reexports = - |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { - tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default()) + tcx.arena.alloc(UnordSet::from( + tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default(), + )) }; providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); - providers.is_panic_runtime = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) - }; - providers.is_compiler_builtins = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins) - }; - providers.has_panic_handler = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); + providers.is_panic_runtime = + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + providers.is_compiler_builtins = + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + providers.has_panic_handler = |tcx, LocalCrate| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) }; diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 5426ac8d7..fb0d90930 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -4,6 +4,8 @@ use crate::dep_graph::TaskDepsRef; use crate::ty::query; use rustc_data_structures::sync::{self, Lock}; use rustc_errors::Diagnostic; +#[cfg(not(parallel_compiler))] +use std::cell::Cell; use std::mem; use std::ptr; use thin_vec::ThinVec; @@ -47,52 +49,15 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { } } +// Import the thread-local variable from Rayon, which is preserved for Rayon jobs. #[cfg(parallel_compiler)] -mod tlv { - use rustc_rayon_core as rayon_core; - use std::ptr; - - /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. - /// This is used to get the pointer to the current `ImplicitCtxt`. - #[inline] - pub(super) fn get_tlv() -> *const () { - ptr::from_exposed_addr(rayon_core::tlv::get()) - } - - /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs - /// to `value` during the call to `f`. It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[inline] - pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R { - rayon_core::tlv::with(value.expose_addr(), f) - } -} +use rayon_core::tlv::TLV; +// Otherwise define our own #[cfg(not(parallel_compiler))] -mod tlv { - use std::cell::Cell; - use std::ptr; - - thread_local! { - /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. - static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }; - } - - /// Gets the pointer to the current `ImplicitCtxt`. - #[inline] - pub(super) fn get_tlv() -> *const () { - TLV.with(|tlv| tlv.get()) - } - - /// Sets TLV to `value` during the call to `f`. - /// It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[inline] - pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R { - let old = TLV.replace(value); - let _reset = rustc_data_structures::OnDrop(move || TLV.set(old)); - f() - } +thread_local! { + /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. + static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }; } #[inline] @@ -111,7 +76,11 @@ pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> where F: FnOnce() -> R, { - tlv::with_tlv(erase(context), f) + TLV.with(|tlv| { + let old = tlv.replace(erase(context)); + let _reset = rustc_data_structures::OnDrop(move || tlv.set(old)); + f() + }) } /// Allows access to the current `ImplicitCtxt` in a closure if one is available. @@ -120,7 +89,7 @@ pub fn with_context_opt<F, R>(f: F) -> R where F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, { - let context = tlv::get_tlv(); + let context = TLV.get(); if context.is_null() { f(None) } else { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index e894e1aaf..ae0bb4949 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,9 +3,9 @@ use std::ops::ControlFlow; use crate::ty::{ - AliasTy, Const, ConstKind, DefIdTree, FallibleTypeFolder, InferConst, InferTy, Opaque, - PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitor, + AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate, + Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; @@ -117,7 +117,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( } let param_name = trait_pred.skip_binder().self_ty().to_string(); - let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + let mut constraint = trait_pred.to_string(); if let Some((name, term)) = associated_ty { // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. @@ -144,7 +144,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( this requirement", if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" }, ), - format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint), + format!("{} {constraint}", generics.add_where_or_trailing_comma()), Applicability::MaybeIncorrect, ); true diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 9c171a69d..aff6c77e0 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -151,12 +151,8 @@ impl<'tcx> TypeError<'tcx> { .into(), RegionsPlaceholderMismatch => "one type is more general than the other".into(), ArgumentSorts(values, _) | Sorts(values) => { - let mut expected = values.expected.sort_string(tcx); - let mut found = values.found.sort_string(tcx); - if expected == found { - expected = values.expected.sort_string(tcx); - found = values.found.sort_string(tcx); - } + let expected = values.expected.sort_string(tcx); + let found = values.found.sort_string(tcx); report_maybe_different(&expected, &found).into() } Traits(values) => { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 59deade0a..31d00b65e 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,6 +1,6 @@ use crate::mir::Mutability; use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; use std::fmt::Debug; use std::hash::Hash; @@ -51,15 +51,36 @@ pub enum SimplifiedType { /// generic parameters as if they were inference variables in that case. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum TreatParams { - /// Treat parameters as placeholders in the given environment. + /// Treat parameters as infer vars. This is the correct mode for caching + /// an impl's type for lookup. + AsCandidateKey, + /// Treat parameters as placeholders in the given environment. This is the + /// correct mode for *lookup*, as during candidate selection. /// - /// Note that this also causes us to treat projections as if they were - /// placeholders. This is only correct if the given projection cannot - /// be normalized in the current context. Even if normalization fails, - /// it may still succeed later if the projection contains any inference - /// variables. - AsPlaceholder, - AsInfer, + /// This also treats projections with inference variables as infer vars + /// since they could be further normalized. + ForLookup, + /// Treat parameters as placeholders in the given environment. This is the + /// correct mode for *lookup*, as during candidate selection. + /// + /// N.B. during deep rejection, this acts identically to `ForLookup`. + NextSolverLookup, +} + +/// During fast-rejection, we have the choice of treating projection types +/// as either simplifyable or not, depending on whether we expect the projection +/// to be normalized/rigid. +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub enum TreatProjections { + /// In the old solver we don't try to normalize projections + /// when looking up impls and only access them by using the + /// current self type. This means that if the self type is + /// a projection which could later be normalized, we must not + /// treat it as rigid. + ForLookup, + /// We can treat projections in the self type as opaque as + /// we separately look up impls for the normalized self type. + NextSolverLookup, } /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. @@ -115,19 +136,20 @@ pub fn simplify_type<'tcx>( ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), ty::Placeholder(..) => Some(PlaceholderSimplifiedType), ty::Param(_) => match treat_params { - TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType), - TreatParams::AsInfer => None, + TreatParams::ForLookup | TreatParams::NextSolverLookup => { + Some(PlaceholderSimplifiedType) + } + TreatParams::AsCandidateKey => None, }, ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. // // We will have to be careful with lazy normalization here. - TreatParams::AsPlaceholder if !ty.has_non_region_infer() => { - debug!("treating `{}` as a placeholder", ty); - Some(PlaceholderSimplifiedType) - } - TreatParams::AsPlaceholder | TreatParams::AsInfer => None, + // FIXME(lazy_normalization): This is probably not right... + TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType), + TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, @@ -166,22 +188,24 @@ pub struct DeepRejectCtxt { } impl DeepRejectCtxt { - pub fn generic_args_may_unify<'tcx>( + pub fn substs_refs_may_unify<'tcx>( self, - obligation_arg: ty::GenericArg<'tcx>, - impl_arg: ty::GenericArg<'tcx>, + obligation_substs: SubstsRef<'tcx>, + impl_substs: SubstsRef<'tcx>, ) -> bool { - match (obligation_arg.unpack(), impl_arg.unpack()) { - // We don't fast reject based on regions for now. - (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, - (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { - self.types_may_unify(obl, imp) - } - (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { - self.consts_may_unify(obl, imp) + iter::zip(obligation_substs, impl_substs).all(|(obl, imp)| { + match (obl.unpack(), imp.unpack()) { + // We don't fast reject based on regions for now. + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, + (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { + self.types_may_unify(obl, imp) + } + (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { + self.consts_may_unify(obl, imp) + } + _ => bug!("kind mismatch: {obl} {imp}"), } - _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"), - } + }) } pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool { @@ -236,9 +260,7 @@ impl DeepRejectCtxt { }, ty::Adt(obl_def, obl_substs) => match k { &ty::Adt(impl_def, impl_substs) => { - obl_def == impl_def - && iter::zip(obl_substs, impl_substs) - .all(|(obl, imp)| self.generic_args_may_unify(obl, imp)) + obl_def == impl_def && self.substs_refs_may_unify(obl_substs, impl_substs) } _ => false, }, @@ -290,15 +312,20 @@ impl DeepRejectCtxt { // Impls cannot contain these types as these cannot be named directly. ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false, + // Placeholder types don't unify with anything on their own ty::Placeholder(..) | ty::Bound(..) => false, // Depending on the value of `treat_obligation_params`, we either // treat generic parameters like placeholders or like inference variables. ty::Param(_) => match self.treat_obligation_params { - TreatParams::AsPlaceholder => false, - TreatParams::AsInfer => true, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::AsCandidateKey => true, }, + ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(), + + ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(), + ty::Infer(_) => true, // As we're walking the whole type, it may encounter projections @@ -333,10 +360,13 @@ impl DeepRejectCtxt { let k = impl_ct.kind(); match obligation_ct.kind() { ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::AsPlaceholder => false, - TreatParams::AsInfer => true, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, + TreatParams::AsCandidateKey => true, }, + // Placeholder consts don't unify with anything on their own + ty::ConstKind::Placeholder(_) => false, + // As we don't necessarily eagerly evaluate constants, // they might unify with any value. ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { @@ -349,7 +379,7 @@ impl DeepRejectCtxt { ty::ConstKind::Infer(_) => true, - ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + ty::ConstKind::Bound(..) => { bug!("unexpected obl const: {:?}", obligation_ct) } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 91241ff40..5a6ee1238 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -288,7 +288,7 @@ impl FlagComputation { self.add_ty(ty); } ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::AliasEq(t1, t2) => { + ty::PredicateKind::AliasRelate(t1, t2, _) => { self.add_term(t1); self.add_term(t2); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index d66f436f9..203e16bea 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -51,9 +51,7 @@ where // Region folder impl<'tcx> TyCtxt<'tcx> { - /// Folds the escaping and free regions in `value` using `f`, and - /// sets `skipped_regions` to true if any late-bound region was found - /// and skipped. + /// Folds the escaping and free regions in `value` using `f`. pub fn fold_regions<T>( self, value: T, @@ -64,17 +62,6 @@ impl<'tcx> TyCtxt<'tcx> { { value.fold_with(&mut RegionFolder::new(self, &mut f)) } - - pub fn super_fold_regions<T>( - self, - value: T, - mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> T - where - T: TypeSuperFoldable<TyCtxt<'tcx>>, - { - value.super_fold_with(&mut RegionFolder::new(self, &mut f)) - } } /// Folds over the substructure of a type, visiting its component @@ -392,9 +379,7 @@ impl<'tcx> TyCtxt<'tcx> { let index = entry.index(); let var = ty::BoundVar::from_usize(index); let kind = entry - .or_insert_with(|| { - ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None)) - }) + .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None))) .expect_region(); let br = ty::BoundRegion { var, kind }; self.tcx.mk_re_late_bound(ty::INNERMOST, br) @@ -404,9 +389,7 @@ impl<'tcx> TyCtxt<'tcx> { let index = entry.index(); let var = ty::BoundVar::from_usize(index); let kind = entry - .or_insert_with(|| { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon(index as u32)) - }) + .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)) .expect_ty(); self.tcx.mk_bound(ty::INNERMOST, BoundTy { var, kind }) } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index e268553f8..ac42d6e05 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -1,5 +1,5 @@ use crate::ty::context::TyCtxt; -use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty}; +use crate::ty::{self, DefId, ParamEnv, Ty}; /// Represents whether some type is inhabited in a given context. /// Examples of uninhabited types are `!`, `enum Void {}`, or a struct diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f4028a5a9..e73225f70 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -82,6 +82,11 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is the ID of the `call_once` method in `FnOnce`. ClosureOnceShim { call_once: DefId, track_caller: bool }, + /// Compiler-generated accessor for thread locals which returns a reference to the thread local + /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking + /// native support. + ThreadLocalShim(DefId), + /// `core::ptr::drop_in_place::<T>`. /// /// The `DefId` is for `core::ptr::drop_in_place`. @@ -96,6 +101,13 @@ pub enum InstanceDef<'tcx> { /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. CloneShim(DefId, Ty<'tcx>), + + /// Compiler-generated `<T as FnPtr>::addr` implementation. + /// + /// Automatically generated for all potentially higher-ranked `fn(I) -> R` types. + /// + /// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`. + FnPtrAddrShim(DefId, Ty<'tcx>), } impl<'tcx> Instance<'tcx> { @@ -149,9 +161,11 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) + | InstanceDef::ThreadLocalShim(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) => def_id, + | InstanceDef::CloneShim(def_id, _) + | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, } } @@ -159,7 +173,9 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> { match self { ty::InstanceDef::Item(def) => Some(def.did), - ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => { + Some(def_id) + } InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) @@ -167,7 +183,8 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) => None, + | InstanceDef::CloneShim(..) + | InstanceDef::FnPtrAddrShim(..) => None, } } @@ -182,12 +199,18 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Intrinsic(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), + | InstanceDef::CloneShim(def_id, _) + | InstanceDef::ThreadLocalShim(def_id) + | InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), } } #[inline] - pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + &self, + tcx: TyCtxt<'tcx>, + attr: Symbol, + ) -> impl Iterator<Item = &'tcx rustc_ast::Attribute> { tcx.get_attrs(self.def_id(), attr) } @@ -201,6 +224,7 @@ impl<'tcx> InstanceDef<'tcx> { let def_id = match *self { ty::InstanceDef::Item(def) => def.did, ty::InstanceDef::DropGlue(_, Some(_)) => return false, + ty::InstanceDef::ThreadLocalShim(_) => return false, _ => return true, }; matches!( @@ -241,6 +265,9 @@ impl<'tcx> InstanceDef<'tcx> { ) }); } + if let ty::InstanceDef::ThreadLocalShim(..) = *self { + return false; + } tcx.codegen_fn_attrs(self.def_id()).requests_inline() } @@ -264,6 +291,8 @@ impl<'tcx> InstanceDef<'tcx> { pub fn has_polymorphic_mir_body(&self) -> bool { match *self { InstanceDef::CloneShim(..) + | InstanceDef::ThreadLocalShim(..) + | InstanceDef::FnPtrAddrShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } @@ -295,6 +324,7 @@ fn fmt_instance( InstanceDef::Item(_) => Ok(()), InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), + InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty), @@ -302,6 +332,7 @@ fn fmt_instance( InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty), InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty), + InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({})", ty), } } @@ -781,6 +812,12 @@ fn needs_fn_once_adapter_shim( #[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)] pub struct UnusedGenericParams(FiniteBitSet<u32>); +impl Default for UnusedGenericParams { + fn default() -> Self { + UnusedGenericParams::new_all_used() + } +} + impl UnusedGenericParams { pub fn new_all_unused(amount: u32) -> Self { let mut bitset = FiniteBitSet::new_empty(); @@ -807,4 +844,12 @@ impl UnusedGenericParams { pub fn all_used(&self) -> bool { self.0.is_empty() } + + pub fn bits(&self) -> u32 { + self.0.0 + } + + pub fn from_bits(bits: u32) -> UnusedGenericParams { + UnusedGenericParams(FiniteBitSet(bits)) + } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 254ffc33c..195d951f9 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,7 +5,7 @@ use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; +use rustc_index::vec::IndexVec; use rustc_session::config::OptLevel; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -281,6 +281,12 @@ pub enum SizeSkeleton<'tcx> { /// Any statically computable Layout. Known(Size), + /// This is a generic const expression (i.e. N * 2), which may contain some parameters. + /// It must be of type usize, and represents the size of a type in bytes. + /// It is not required to be evaluatable to a concrete value, but can be used to check + /// that another SizeSkeleton is of equal size. + Generic(ty::Const<'tcx>), + /// A potentially-fat pointer. Pointer { /// If true, this pointer is never null. @@ -326,6 +332,37 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } + ty::Array(inner, len) + if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => + { + match SizeSkeleton::compute(inner, tcx, param_env)? { + // This may succeed because the multiplication of two types may overflow + // but a single size of a nested array will not. + SizeSkeleton::Known(s) => { + if let Some(c) = len.try_eval_target_usize(tcx, param_env) { + let size = s + .bytes() + .checked_mul(c) + .ok_or_else(|| LayoutError::SizeOverflow(ty))?; + return Ok(SizeSkeleton::Known(Size::from_bytes(size))); + } + let len = tcx.expand_abstract_consts(len); + let prev = ty::Const::from_target_usize(tcx, s.bytes()); + let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else { + return Err(LayoutError::SizeOverflow(ty)); + }; + Ok(SizeSkeleton::Generic(gen_size)) + } + SizeSkeleton::Pointer { .. } => Err(err), + SizeSkeleton::Generic(g) => { + let len = tcx.expand_abstract_consts(len); + let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else { + return Err(LayoutError::SizeOverflow(ty)); + }; + Ok(SizeSkeleton::Generic(gen_size)) + } + } + } ty::Adt(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. @@ -335,7 +372,7 @@ impl<'tcx> SizeSkeleton<'tcx> { // Get a zero-sized variant or a pointer newtype. let zero_or_ptr_variant = |i| { - let i = VariantIdx::new(i); + let i = VariantIdx::from_usize(i); let fields = def.variant(i).fields.iter().map(|field| { SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env) @@ -355,6 +392,9 @@ impl<'tcx> SizeSkeleton<'tcx> { } ptr = Some(field); } + SizeSkeleton::Generic(_) => { + return Err(err); + } } } Ok(ptr) @@ -410,11 +450,66 @@ impl<'tcx> SizeSkeleton<'tcx> { (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => { a == b } + // constants are always pre-normalized into a canonical form so this + // only needs to check if their pointers are identical. + (SizeSkeleton::Generic(a), SizeSkeleton::Generic(b)) => a == b, _ => false, } } } +/// When creating the layout for types with abstract conts in their size (i.e. [usize; 4 * N]), +/// to ensure that they have a canonical order and can be compared directly we combine all +/// constants, and sort the other terms. This allows comparison of expressions of sizes, +/// allowing for things like transmutating between types that depend on generic consts. +/// This returns `None` if multiplication of constants overflows. +fn mul_sorted_consts<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, +) -> Option<ty::Const<'tcx>> { + use crate::mir::BinOp::Mul; + use ty::ConstKind::Expr; + use ty::Expr::Binop; + + let mut work = vec![a, b]; + let mut done = vec![]; + while let Some(n) = work.pop() { + if let Expr(Binop(Mul, l, r)) = n.kind() { + work.push(l); + work.push(r) + } else { + done.push(n); + } + } + let mut k = 1; + let mut overflow = false; + done.retain(|c| { + let Some(c) = c.try_eval_target_usize(tcx, param_env) else { + return true; + }; + let Some(next) = c.checked_mul(k) else { + overflow = true; + return false; + }; + k = next; + false + }); + if overflow { + return None; + } + if k != 1 { + done.push(ty::Const::from_target_usize(tcx, k)); + } else if k == 0 { + return Some(ty::Const::from_target_usize(tcx, 0)); + } + done.sort_unstable(); + + // create a single tree from the buffer + done.into_iter().reduce(|acc, n| tcx.mk_const(Expr(Binop(Mul, n, acc)), n.ty())) +} + pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx(&self) -> TyCtxt<'tcx>; } @@ -636,7 +731,7 @@ where variants: Variants::Single { index: variant_index }, fields: match NonZeroUsize::new(fields) { Some(fields) => FieldsShape::Union(fields), - None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] }, + None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, abi: Abi::Uninhabited, largest_niche: None, @@ -730,7 +825,11 @@ where */ }; - let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() { + let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() + // Projection eagerly bails out when the pointee references errors, + // fall back to structurally deducing metadata. + && !pointee.references_error() + { let metadata = tcx.normalize_erasing_regions( cx.param_env(), tcx.mk_projection(metadata_def_id, [pointee]), @@ -794,7 +893,8 @@ where ty::Adt(def, substs) => { match this.variants { Variants::Single { index } => { - TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs)) + let field = &def.variant(index).fields[FieldIdx::from_usize(i)]; + TyMaybeWithLayout::Ty(field.ty(tcx, substs)) } // Discriminant field for enums (where applicable). @@ -1126,10 +1226,11 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> | AvrNonBlockingInterrupt | CCmseNonSecureCall | Wasm - | RustIntrinsic | PlatformIntrinsic | Unadjusted => false, - Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, + Rust | RustCall | RustCold | RustIntrinsic => { + tcx.sess.panic_strategy() == PanicStrategy::Unwind + } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dce18a585..2e516f291 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -34,6 +34,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -44,10 +45,12 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; +use rustc_session::lint::LintBuffer; +pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; -use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx}; +use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; @@ -148,8 +151,6 @@ mod typeck_results; // Data types -pub type RegisteredTools = FxHashSet<Ident>; - pub struct ResolverOutputs { pub global_ctxt: ResolverGlobalCtxt, pub ast_lowering: ResolverAstLowering, @@ -165,7 +166,8 @@ pub struct ResolverGlobalCtxt { pub effective_visibilities: EffectiveVisibilities, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, - pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>, + pub module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>, + pub module_children_reexports: LocalDefIdMap<Vec<ModChild>>, pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, pub main_def: Option<MainDefinition>, pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>, @@ -175,7 +177,6 @@ pub struct ResolverGlobalCtxt { /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxHashMap<Span, Span>, - pub registered_tools: RegisteredTools, pub doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>, pub doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>, pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, @@ -209,6 +210,9 @@ pub struct ResolverAstLowering { pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet<ast::NodeId>, + + /// Lints that were emitted by the resolver and early lints. + pub lint_buffer: Steal<LintBuffer>, } #[derive(Clone, Copy, Debug)] @@ -325,12 +329,15 @@ pub struct ClosureSizeProfileData<'tcx> { pub after_feature_tys: Ty<'tcx>, } -pub trait DefIdTree: Copy { - fn opt_parent(self, id: DefId) -> Option<DefId>; +impl TyCtxt<'_> { + #[inline] + pub fn opt_parent(self, id: DefId) -> Option<DefId> { + self.def_key(id).parent.map(|index| DefId { index, ..id }) + } #[inline] #[track_caller] - fn parent(self, id: DefId) -> DefId { + pub fn parent(self, id: DefId) -> DefId { match self.opt_parent(id) { Some(id) => id, // not `unwrap_or_else` to avoid breaking caller tracking @@ -340,17 +347,17 @@ pub trait DefIdTree: Copy { #[inline] #[track_caller] - fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> { + pub fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> { self.opt_parent(id.to_def_id()).map(DefId::expect_local) } #[inline] #[track_caller] - fn local_parent(self, id: LocalDefId) -> LocalDefId { + pub fn local_parent(self, id: LocalDefId) -> LocalDefId { self.parent(id.to_def_id()).expect_local() } - fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { + pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { if descendant.krate != ancestor.krate { return false; } @@ -365,13 +372,6 @@ pub trait DefIdTree: Copy { } } -impl<'tcx> DefIdTree for TyCtxt<'tcx> { - #[inline] - fn opt_parent(self, id: DefId) -> Option<DefId> { - self.def_key(id).parent.map(|index| DefId { index, ..id }) - } -} - impl<Id> Visibility<Id> { pub fn is_public(self) -> bool { matches!(self, Visibility::Public) @@ -391,19 +391,19 @@ impl<Id: Into<DefId>> Visibility<Id> { } /// Returns `true` if an item with this visibility is accessible from the given module. - pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool { + pub fn is_accessible_from(self, module: impl Into<DefId>, tcx: TyCtxt<'_>) -> bool { match self { // Public items are visible everywhere. Visibility::Public => true, - Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()), + Visibility::Restricted(id) => tcx.is_descendant_of(module.into(), id.into()), } } /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool { + pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tcx: TyCtxt<'_>) -> bool { match vis { Visibility::Public => self.is_public(), - Visibility::Restricted(id) => self.is_accessible_from(id, tree), + Visibility::Restricted(id) => self.is_accessible_from(id, tcx), } } } @@ -544,7 +544,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(Clause::TypeOutlives(_)) | PredicateKind::Clause(Clause::Projection(_)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) @@ -641,7 +641,23 @@ pub enum PredicateKind<'tcx> { /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver - AliasEq(Term<'tcx>, Term<'tcx>), + AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, Debug)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +impl std::fmt::Display for AliasRelationDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AliasRelationDirection::Equate => write!(f, "=="), + AliasRelationDirection::Subtype => write!(f, "<:"), + } + } } /// The crate outlives map is computed during typeck and contains the @@ -977,11 +993,11 @@ impl<'tcx> Term<'tcx> { } } - /// This function returns `None` for `AliasKind::Opaque`. + /// This function returns the inner `AliasTy` if this term is a projection. /// /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly /// deal with constants. - pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { + pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { match self.unpack() { TermKind::Ty(ty) => match ty.kind() { ty::Alias(kind, alias_ty) => match kind { @@ -999,7 +1015,7 @@ impl<'tcx> Term<'tcx> { pub fn is_infer(&self) -> bool { match self.unpack() { - TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(), + TermKind::Ty(ty) => ty.is_ty_var(), TermKind::Const(ct) => ct.is_ct_infer(), } } @@ -1036,6 +1052,21 @@ impl<'tcx> TermKind<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ParamTerm { + Ty(ParamTy), + Const(ParamConst), +} + +impl ParamTerm { + pub fn index(self) -> usize { + match self { + ParamTerm::Ty(ty) => ty.index as usize, + ParamTerm::Const(ct) => ct.index as usize, + } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1129,6 +1160,13 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T { } } +impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1143,6 +1181,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { } } +impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(self).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1193,7 +1238,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1214,7 +1259,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1236,7 +1281,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1386,7 +1431,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + let id_substs = InternalSubsts::identity_for_item(tcx, def_id); debug!(?id_substs); // This zip may have several times the same lifetime in `substs` paired with a different @@ -1410,12 +1455,12 @@ impl<'tcx> OpaqueHiddenType<'tcx> { #[derive(HashStable, TyEncodable, TyDecodable)] pub struct Placeholder<T> { pub universe: UniverseIndex, - pub name: T, + pub bound: T, } -pub type PlaceholderRegion = Placeholder<BoundRegionKind>; +pub type PlaceholderRegion = Placeholder<BoundRegion>; -pub type PlaceholderType = Placeholder<BoundTyKind>; +pub type PlaceholderType = Placeholder<BoundTy>; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TyEncodable, TyDecodable, PartialOrd, Ord)] @@ -1847,7 +1892,7 @@ pub struct VariantDef { /// Discriminant of this variant. pub discr: VariantDiscr, /// Fields of this variant. - pub fields: Vec<FieldDef>, + pub fields: IndexVec<FieldIdx, FieldDef>, /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, } @@ -1874,7 +1919,7 @@ impl VariantDef { variant_did: Option<DefId>, ctor: Option<(CtorKind, DefId)>, discr: VariantDiscr, - fields: Vec<FieldDef>, + fields: IndexVec<FieldIdx, FieldDef>, adt_kind: AdtKind, parent_did: DefId, recovered: bool, @@ -2028,7 +2073,6 @@ impl<'tcx> FieldDef { } } -pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>; #[derive(Debug, PartialEq, Eq)] pub enum ImplOverlapKind { /// These impls are always allowed to overlap. @@ -2071,7 +2115,9 @@ pub enum ImplOverlapKind { Issue33140, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +/// Useful source information about where a desugared associated type for an +/// RPITIT originated from. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable)] pub enum ImplTraitInTraitData { Trait { fn_def_id: DefId, opaque_def_id: DefId }, Impl { fn_def_id: DefId }, @@ -2214,26 +2260,37 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> { - variant - .fields - .iter() - .position(|field| self.hygienic_eq(ident, field.ident(self), variant.def_id)) + /// If the def-id is an associated type that was desugared from a + /// return-position `impl Trait` from a trait, then provide the source info + /// about where that RPITIT came from. + pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> { + if let DefKind::AssocTy = self.def_kind(def_id) { + self.associated_item(def_id).opt_rpitit_info + } else { + None + } + } + + pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> { + variant.fields.iter_enumerated().find_map(|(i, field)| { + self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i) + }) } /// Returns `true` if the impls are the same polarity and the trait either /// has no items or is annotated `#[marker]` and prevents item overrides. + #[instrument(level = "debug", skip(self), ret)] pub fn impls_are_allowed_to_overlap( self, def_id1: DefId, def_id2: DefId, ) -> Option<ImplOverlapKind> { + let impl_trait_ref1 = self.impl_trait_ref(def_id1); + let impl_trait_ref2 = self.impl_trait_ref(def_id2); // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error()) - || self - .impl_trait_ref(def_id2) - .map_or(false, |tr| tr.subst_identity().references_error()) + if impl_trait_ref1.map_or(false, |tr| tr.subst_identity().references_error()) + || impl_trait_ref2.map_or(false, |tr| tr.subst_identity().references_error()) { return Some(ImplOverlapKind::Permitted { marker: false }); } @@ -2241,19 +2298,11 @@ impl<'tcx> TyCtxt<'tcx> { match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { (ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => { // `#[rustc_reservation_impl]` impls don't overlap with anything - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)", - def_id1, def_id2 - ); return Some(ImplOverlapKind::Permitted { marker: false }); } (ImplPolarity::Positive, ImplPolarity::Negative) | (ImplPolarity::Negative, ImplPolarity::Positive) => { // `impl AutoTrait for Type` + `impl !AutoTrait for Type` - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)", - def_id1, def_id2 - ); return None; } (ImplPolarity::Positive, ImplPolarity::Positive) @@ -2261,38 +2310,25 @@ impl<'tcx> TyCtxt<'tcx> { }; let is_marker_overlap = { - let is_marker_impl = |def_id: DefId| -> bool { - let trait_ref = self.impl_trait_ref(def_id); + let is_marker_impl = |trait_ref: Option<EarlyBinder<TraitRef<'_>>>| -> bool { trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker) }; - is_marker_impl(def_id1) && is_marker_impl(def_id2) + is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) }; if is_marker_overlap { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)", - def_id1, def_id2 - ); Some(ImplOverlapKind::Permitted { marker: true }) } else { if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { if let Some(self_ty2) = self.issue33140_self_ty(def_id2) { if self_ty1 == self_ty2 { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - issue #33140 HACK", - def_id1, def_id2 - ); return Some(ImplOverlapKind::Issue33140); } else { - debug!( - "impls_are_allowed_to_overlap({:?}, {:?}) - found {:?} != {:?}", - def_id1, def_id2, self_ty1, self_ty2 - ); + debug!("found {self_ty1:?} != {self_ty2:?}"); } } } - debug!("impls_are_allowed_to_overlap({:?}, {:?}) = None", def_id1, def_id2); None } } @@ -2349,7 +2385,9 @@ impl<'tcx> TyCtxt<'tcx> { | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) => self.mir_shims(instance), + | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::ThreadLocalShim(..) + | ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance), } } @@ -2363,7 +2401,12 @@ impl<'tcx> TyCtxt<'tcx> { } /// Gets all attributes with the given name. - pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> { + pub fn get_attrs( + self, + did: impl Into<DefId>, + attr: Symbol, + ) -> impl Iterator<Item = &'tcx ast::Attribute> { + let did: DefId = did.into(); let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) @@ -2374,8 +2417,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { + pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + let did: DefId = did.into(); bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); } else { self.get_attrs(did, attr).next() @@ -2383,7 +2427,8 @@ impl<'tcx> TyCtxt<'tcx> { } /// Determines whether an item is annotated with an attribute. - pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { + pub fn has_attr(self, did: impl Into<DefId>, attr: Symbol) -> bool { + let did: DefId = did.into(); if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) { bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { @@ -2493,7 +2538,7 @@ impl<'tcx> TyCtxt<'tcx> { ident } - // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId + // FIXME(vincenzopalazzo): move the HirId to a LocalDefId pub fn adjust_ident_and_get_scope( self, mut ident: Ident, @@ -2540,12 +2585,18 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) } - pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId { - while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { - debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); - def_id = self.parent(def_id); + pub fn impl_trait_in_trait_parent_fn(self, mut def_id: DefId) -> DefId { + match self.opt_rpitit_info(def_id) { + Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) + | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id, + None => { + while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn { + debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder); + def_id = self.parent(def_id); + } + def_id + } } - def_id } pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { @@ -2560,6 +2611,12 @@ impl<'tcx> TyCtxt<'tcx> { let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + if self.lower_impl_trait_in_trait_to_assoc_ty() { + return !self + .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) + .is_empty(); + } + // FIXME(RPITIT): This does a somewhat manual walk through the signature // of the trait fn to look for any RPITITs, but that's kinda doing a lot // of work. We can probably remove this when we refactor RPITITs to be diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 8849e7eab..7534d06ae 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -63,6 +63,7 @@ trivially_parameterized_over_tcx! { ty::DeducedParamAttrs, ty::Generics, ty::ImplPolarity, + ty::ImplTraitInTraitData, ty::ReprOptions, ty::TraitDef, ty::UnusedGenericParams, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 021c20b58..d947d9604 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,5 +1,5 @@ use crate::ty::GenericArg; -use crate::ty::{self, DefIdTree, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6a053c368..72caadaf6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,6 +1,6 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::{ - self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, + self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use crate::ty::{GenericArg, GenericArgKind}; @@ -701,10 +701,12 @@ pub trait PrettyPrinter<'tcx>: ty::Error(_) => p!("[type error]"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon(bv) => { - self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? - } - ty::BoundTyKind::Param(_, s) => p!(write("{}", s)), + ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, + ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { + true if debruijn == ty::INNERMOST => p!(write("^{}", s)), + true => p!(write("^{}_{}", debruijn.index(), s)), + false => p!(write("{}", s)), + }, }, ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); @@ -728,15 +730,15 @@ pub trait PrettyPrinter<'tcx>: } ty::Alias(ty::Projection, ref data) => { if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) - && self.tcx().def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + && self.tcx().is_impl_trait_in_trait(data.def_id) { return self.pretty_print_opaque_impl_type(data.def_id, data.substs); } else { p!(print(data)) } } - ty::Placeholder(placeholder) => match placeholder.name { - ty::BoundTyKind::Anon(_) => p!(write("Placeholder({:?})", placeholder)), + ty::Placeholder(placeholder) => match placeholder.bound.kind { + ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)), ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { @@ -1345,7 +1347,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose())) } } - defkind => bug!("`{:?}` has unexpcted defkind {:?}", ct, defkind), + defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind), } } ty::ConstKind::Infer(infer_ct) => { @@ -2100,7 +2102,9 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: br, .. }, .. + }) => { if br.is_named() { return true; } @@ -2177,7 +2181,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: br, .. }, .. + }) => { if let ty::BrNamed(_, name) = br && br.is_named() { p!(write("{}", name)); return Ok(self); @@ -2255,7 +2261,10 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { ty::ReLateBound(db, br) if db >= self.current_index => { *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) } - ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => { + ty::RePlaceholder(ty::PlaceholderRegion { + bound: ty::BoundRegion { kind, .. }, + .. + }) => { // If this is an anonymous placeholder, don't rename. Otherwise, in some // async fns, we get a `for<'r> Send` bound match kind { @@ -2847,7 +2856,7 @@ define_print_and_forward_display! { p!("the type `", print(ty), "` is found in the environment") } ty::PredicateKind::Ambiguous => p!("ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)), + ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2bc51baf8..fa9fea723 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -17,7 +17,8 @@ use crate::mir::interpret::{ }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; -use crate::query::Key; +use crate::query::erase::{erase, restore, Erase}; +use crate::query::{AsLocalKey, Key}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -41,7 +42,7 @@ use rustc_arena::TypedArena; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -50,11 +51,15 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, DocLinkResMap}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; +use rustc_hir::def_id::{ + CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, +}; use rustc_hir::hir_id::OwnerId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::vec::IndexVec; +pub(crate) use rustc_query_system::query::QueryJobId; +use rustc_query_system::query::*; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; @@ -64,18 +69,19 @@ use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi; use rustc_target::spec::PanicStrategy; + +use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; -pub(crate) use rustc_query_system::query::QueryJobId; -use rustc_query_system::query::*; - #[derive(Default)] pub struct QuerySystem<'tcx> { pub arenas: QueryArenas<'tcx>, pub caches: QueryCaches<'tcx>, + // Since we erase query value types we tell the typesystem about them with `PhantomData`. + _phantom_values: QueryPhantomValues<'tcx>, } #[derive(Copy, Clone)] @@ -97,6 +103,11 @@ pub struct TyCtxtEnsure<'tcx> { pub tcx: TyCtxt<'tcx>, } +#[derive(Copy, Clone)] +pub struct TyCtxtEnsureWithValue<'tcx> { + pub tcx: TyCtxt<'tcx>, +} + impl<'tcx> TyCtxt<'tcx> { /// Returns a transparent wrapper for `TyCtxt`, which ensures queries /// are executed instead of just returning their results. @@ -105,6 +116,15 @@ impl<'tcx> TyCtxt<'tcx> { TyCtxtEnsure { tcx: self } } + /// Returns a transparent wrapper for `TyCtxt`, which ensures queries + /// are executed instead of just returning their results. + /// + /// This version verifies that the computed result exists in the cache before returning. + #[inline(always)] + pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> { + TyCtxtEnsureWithValue { tcx: self } + } + /// Returns a transparent wrapper for `TyCtxt` which uses /// `span` as the location of queries performed through it. #[inline(always)] @@ -135,6 +155,20 @@ macro_rules! query_if_arena { }; } +/// If `separate_provide_if_extern`, then the key can be projected to its +/// local key via `<$K as AsLocalKey>::LocalKey`. +macro_rules! local_key_if_separate_extern { + ([] $($K:tt)*) => { + $($K)* + }; + ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => { + <$($K)* as AsLocalKey>::LocalKey + }; + ([$other:tt $($modifiers:tt)*] $($K:tt)*) => { + local_key_if_separate_extern!([$($modifiers)*] $($K)*) + }; +} + macro_rules! separate_provide_extern_decl { ([][$name:ident]) => { () @@ -196,6 +230,12 @@ macro_rules! define_callbacks { $(pub type $name<'tcx> = $($K)*;)* } #[allow(nonstandard_style, unused_lifetimes)] + pub mod query_keys_local { + use super::*; + + $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)* + } + #[allow(nonstandard_style, unused_lifetimes)] pub mod query_values { use super::*; @@ -227,8 +267,8 @@ macro_rules! define_callbacks { pub fn $name<'tcx>( _tcx: TyCtxt<'tcx>, value: query_provided::$name<'tcx>, - ) -> query_values::$name<'tcx> { - query_if_arena!([$($modifiers)*] + ) -> Erase<query_values::$name<'tcx>> { + erase(query_if_arena!([$($modifiers)*] { if mem::needs_drop::<query_provided::$name<'tcx>>() { &*_tcx.query_system.arenas.$name.alloc(value) @@ -237,7 +277,7 @@ macro_rules! define_callbacks { } } (value) - ) + )) } )* } @@ -246,10 +286,40 @@ macro_rules! define_callbacks { use super::*; $( - pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache; + pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache; )* } + $( + // Ensure that keys grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<query_keys::$name<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a key type `", + stringify!($($K)*), + "` that is too large" + )); + } + }; + + // Ensure that values grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<query_values::$name<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a value type `", + stringify!($V), + "` that is too large" + )); + } + }; + )* + pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] (WorkerLocal<TypedArena<<$V as Deref>::Target>>) @@ -269,6 +339,11 @@ macro_rules! define_callbacks { } #[derive(Default)] + pub struct QueryPhantomValues<'tcx> { + $($(#[$attr])* pub $name: PhantomData<query_values::$name<'tcx>>,)* + } + + #[derive(Default)] pub struct QueryCaches<'tcx> { $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* } @@ -282,7 +357,31 @@ macro_rules! define_callbacks { match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(_) => return, - None => self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure), + None => self.tcx.queries.$name( + self.tcx, + DUMMY_SP, + key, + QueryMode::Ensure { check_cache: false }, + ), + }; + })* + } + + impl<'tcx> TyCtxtEnsureWithValue<'tcx> { + $($(#[$attr])* + #[inline(always)] + pub fn $name(self, key: query_helper_param_ty!($($K)*)) { + let key = key.into_query_param(); + opt_remap_env_constness!([$($modifiers)*][key]); + + match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { + Some(_) => return, + None => self.tcx.queries.$name( + self.tcx, + DUMMY_SP, + key, + QueryMode::Ensure { check_cache: true }, + ), }; })* } @@ -305,17 +404,17 @@ macro_rules! define_callbacks { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); - match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { + restore::<$V>(match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(value) => value, None => self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap(), - } + }) })* } pub struct Providers { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, - query_keys::$name<'tcx>, + query_keys_local::$name<'tcx>, ) -> query_provided::$name<'tcx>,)* } @@ -325,17 +424,14 @@ macro_rules! define_callbacks { impl Default for Providers { fn default() -> Self { - use crate::query::Key; - Providers { $($name: |_, key| bug!( - "`tcx.{}({:?})` is not supported for {} crate;\n\ + "`tcx.{}({:?})` is not supported for this key;\n\ hint: Queries can be either made to the local crate, or the external crate. \ This error means you tried to use it for one that's not supported.\n\ If that's not the case, {} was likely never assigned to a provider function.\n", stringify!($name), key, - if key.query_crate_is_local() { "local" } else { "external" }, stringify!($name), ),)* } @@ -372,7 +468,7 @@ macro_rules! define_callbacks { span: Span, key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option<$V>;)* + ) -> Option<Erase<$V>>;)* } }; } @@ -399,11 +495,13 @@ macro_rules! define_feedable { opt_remap_env_constness!([$($modifiers)*][key]); let tcx = self.tcx; - let value = query_provided_to_value::$name(tcx, value); + let erased = query_provided_to_value::$name(tcx, value); + let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; match try_get_cached(tcx, cache, &key) { Some(old) => { + let old = restore::<$V>(old); bug!( "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), @@ -418,7 +516,7 @@ macro_rules! define_feedable { &value, hash_result!([$($modifiers)*]), ); - cache.complete(key, value, dep_node_index); + cache.complete(key, erased, dep_node_index); value } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3fc5f5bed..46c931d61 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -22,8 +22,6 @@ pub enum Cause { pub trait TypeRelation<'tcx>: Sized { fn tcx(&self) -> TyCtxt<'tcx>; - fn intercrate(&self) -> bool; - fn param_env(&self) -> ty::ParamEnv<'tcx>; /// Returns a static string we can use for printouts. @@ -33,9 +31,6 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; - /// Used during coherence. If called, must emit an always-ambiguous obligation. - fn mark_ambiguous(&mut self); - fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -559,23 +554,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }), ) if a_def_id == b_def_id => { - if relation.intercrate() { - // During coherence, opaque types should be treated as equal to each other, even if their generic params - // differ, as they could resolve to the same hidden type, even for different generic params. - relation.mark_ambiguous(); - Ok(a) - } else { - let opt_variances = tcx.variances_of(a_def_id); - let substs = relate_substs_with_variances( - relation, - a_def_id, - opt_variances, - a_substs, - b_substs, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(tcx.mk_opaque(a_def_id, substs)) - } + let opt_variances = tcx.variances_of(a_def_id); + let substs = relate_substs_with_variances( + relation, + a_def_id, + opt_variances, + a_substs, + b_substs, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?; + Ok(tcx.mk_opaque(a_def_id, substs)) } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index ef643531b..5c604bb6d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -4,7 +4,7 @@ //! to help with the tedium. use crate::mir::interpret; -use crate::mir::{Field, ProjectionKind}; +use crate::mir::ProjectionKind; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -68,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"), + ty::BrAnon(span) => write!(f, "BrAnon({span:?})"), ty::BrNamed(did, name) => { if did.is_crate_root() { write!(f, "BrNamed({})", name) @@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "TypeWellFormedFromEnv({:?})", ty) } ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"), + ty::PredicateKind::AliasRelate(t1, t2, dir) => { + write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") + } } } } @@ -215,6 +217,7 @@ CloneLiftImpls! { // implementation and traversal implementations (the latter only for // TyCtxt<'_> interners). TrivialTypeTraversalAndLiftImpls! { + ::rustc_target::abi::FieldIdx, ::rustc_target::abi::VariantIdx, crate::middle::region::Scope, crate::ty::FloatTy, @@ -250,8 +253,9 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::AliasKind, - crate::ty::Placeholder<crate::ty::BoundRegionKind>, - crate::ty::Placeholder<crate::ty::BoundTyKind>, + crate::ty::AliasRelationDirection, + crate::ty::Placeholder<crate::ty::BoundRegion>, + crate::ty::Placeholder<crate::ty::BoundTy>, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, @@ -265,7 +269,6 @@ TrivialTypeTraversalAndLiftImpls! { ::rustc_span::Span, ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, - Field, interpret::Scalar, rustc_target::abi::Size, ty::BoundVar, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6a73e8bb..96c1577d5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -7,14 +7,15 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ - self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, AdtDef, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, }; use crate::ty::{List, ParamEnv}; use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; @@ -22,8 +23,8 @@ use rustc_index::vec::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use rustc_target::abi::VariantIdx; -use rustc_target::spec::abi; +use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_target::spec::abi::{self, Abi}; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; @@ -60,7 +61,7 @@ pub struct FreeRegion { #[derive(HashStable)] pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) - BrAnon(u32, Option<Span>), + BrAnon(Option<Span>), /// Named region parameters for functions (a in &'a T) /// @@ -107,15 +108,6 @@ impl BoundRegionKind { _ => None, } } - - pub fn expect_anon(&self) -> u32 { - match *self { - BoundRegionKind::BrNamed(_, _) | BoundRegionKind::BrEnv => { - bug!("expected anon region: {self:?}") - } - BoundRegionKind::BrAnon(idx, _) => idx, - } - } } pub trait Article { @@ -136,10 +128,6 @@ impl<'tcx> Article for TyKind<'tcx> { } } -// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyKind<'_>, 32); - /// A closure can be modeled as a struct that looks like: /// ```ignore (illustrative) /// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U); @@ -517,8 +505,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { #[inline] pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> { // FIXME requires optimized MIR - let num_variants = tcx.generator_layout(def_id).unwrap().variant_fields.len(); - VariantIdx::new(0)..VariantIdx::new(num_variants) + FIRST_VARIANT..tcx.generator_layout(def_id).unwrap().variant_fields.next_index() } /// The discriminant for the given variant. Panics if the `variant_index` is @@ -878,8 +865,8 @@ impl<'tcx> PolyTraitRef<'tcx> { } } -impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { +impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { self.to_string().into_diagnostic_arg() } } @@ -924,6 +911,12 @@ impl<'tcx> ExistentialTraitRef<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for ExistentialTraitRef<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { @@ -940,12 +933,6 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } -impl rustc_errors::IntoDiagnosticArg for PolyExistentialTraitRef<'_> { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { @@ -1160,78 +1147,12 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> { } } -struct SkipBindersAt<'tcx> { - tcx: TyCtxt<'tcx>, - index: ty::DebruijnIndex, -} - -impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for SkipBindersAt<'tcx> { - type Error = (); - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error> - where - T: ty::TypeFoldable<TyCtxt<'tcx>>, - { - self.index.shift_in(1); - let value = t.try_map_bound(|t| t.try_fold_with(self)); - self.index.shift_out(1); - value - } - - fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { - if !ty.has_escaping_bound_vars() { - Ok(ty) - } else if let ty::Bound(index, bv) = *ty.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_bound(index.shifted_out(1), bv)) - } - } else { - ty.try_super_fold_with(self) - } - } - - fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> { - if !r.has_escaping_bound_vars() { - Ok(r) - } else if let ty::ReLateBound(index, bv) = r.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_re_late_bound(index.shifted_out(1), bv)) - } - } else { - r.try_super_fold_with(self) - } - } - - fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { - if !ct.has_escaping_bound_vars() { - Ok(ct) - } else if let ty::ConstKind::Bound(index, bv) = ct.kind() { - if index == self.index { - Err(()) - } else { - Ok(self.interner().mk_const( - ty::ConstKind::Bound(index.shifted_out(1), bv), - ct.ty().try_fold_with(self)?, - )) - } - } else { - ct.try_super_fold_with(self) - } - } - - fn try_fold_predicate( - &mut self, - p: ty::Predicate<'tcx>, - ) -> Result<ty::Predicate<'tcx>, Self::Error> { - if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) } +impl<'tcx, T> IntoDiagnosticArg for Binder<'tcx, T> +where + T: IntoDiagnosticArg, +{ + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.0.into_diagnostic_arg() } } @@ -1288,7 +1209,7 @@ impl<'tcx> AliasTy<'tcx> { match tcx.def_kind(self.def_id) { DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), DefKind::ImplTraitPlaceholder => { - tcx.parent(tcx.impl_trait_in_trait_parent(self.def_id)) + tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id)) } kind => bug!("expected a projection AliasTy; found {kind:?}"), } @@ -1376,6 +1297,12 @@ impl<'tcx> FnSig<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for FnSig<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; impl<'tcx> PolyFnSig<'tcx> { @@ -1403,6 +1330,18 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn abi(&self) -> abi::Abi { self.skip_binder().abi } + + pub fn is_fn_trait_compatible(&self) -> bool { + matches!( + self.skip_binder(), + ty::FnSig { + unsafety: rustc_hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } + ) + } } pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; @@ -1522,22 +1461,13 @@ pub struct BoundTy { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundTyKind { - Anon(u32), + Anon, Param(DefId, Symbol), } -impl BoundTyKind { - pub fn expect_anon(self) -> u32 { - match self { - BoundTyKind::Anon(i) => i, - _ => bug!(), - } - } -} - impl From<BoundVar> for BoundTy { fn from(var: BoundVar) -> Self { - BoundTy { var, kind: BoundTyKind::Anon(var.as_u32()) } + BoundTy { var, kind: BoundTyKind::Anon } } } @@ -1616,19 +1546,24 @@ impl<'tcx> Region<'tcx> { pub fn get_name(self) -> Option<Symbol> { if self.has_name() { - let name = match *self { + match *self { ty::ReEarlyBound(ebr) => Some(ebr.name), ty::ReLateBound(_, br) => br.kind.get_name(), ty::ReFree(fr) => fr.bound_region.get_name(), ty::ReStatic => Some(kw::StaticLifetime), - ty::RePlaceholder(placeholder) => placeholder.name.get_name(), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), _ => None, - }; - - return name; + } + } else { + None } + } - None + pub fn get_name_or_anon(self) -> Symbol { + match self.get_name() { + Some(name) => name, + None => sym::anon, + } } /// Is this region named by the user? @@ -1639,7 +1574,7 @@ impl<'tcx> Region<'tcx> { ty::ReFree(fr) => fr.bound_region.is_named(), ty::ReStatic => true, ty::ReVar(..) => false, - ty::RePlaceholder(placeholder) => placeholder.name.is_named(), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), ty::ReErased => false, ty::ReError(_) => false, } @@ -1762,10 +1697,10 @@ impl<'tcx> Region<'tcx> { matches!(self.kind(), ty::ReVar(_)) } - pub fn as_var(self) -> Option<RegionVid> { + pub fn as_var(self) -> RegionVid { match self.kind() { - ty::ReVar(vid) => Some(vid), - _ => None, + ty::ReVar(vid) => vid, + _ => bug!("expected region {:?} to be of kind ReVar", self), } } } @@ -1892,7 +1827,7 @@ impl<'tcx> Ty<'tcx> { Adt(def, substs) => { assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type"); let variant = def.non_enum_variant(); - let f0_ty = variant.fields[0].ty(tcx, substs); + let f0_ty = variant.fields[FieldIdx::from_u32(0)].ty(tcx, substs); match f0_ty.kind() { // If the first field is an array, we assume it is the only field and its @@ -1902,7 +1837,7 @@ impl<'tcx> Ty<'tcx> { // The way we evaluate the `N` in `[T; N]` here only works since we use // `simd_size_and_type` post-monomorphization. It will probably start to ICE // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_target_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty) + (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) } // Otherwise, the fields of this Adt are the SIMD components (and we assume they // all have the same type). @@ -1914,11 +1849,6 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_region_ptr(self) -> bool { - matches!(self.kind(), Ref(..)) - } - - #[inline] pub fn is_mutable_ptr(self) -> bool { matches!( self.kind(), @@ -1944,7 +1874,7 @@ impl<'tcx> Ty<'tcx> { /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] pub fn is_any_ptr(self) -> bool { - self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] @@ -2508,3 +2438,14 @@ impl<'tcx> VarianceDiagInfo<'tcx> { } } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // tidy-alphabetical-start + static_assert_size!(RegionKind<'_>, 28); + static_assert_size!(TyKind<'_>, 32); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index b090bd9d8..f05b87343 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -302,8 +302,8 @@ impl<'tcx> InternalSubsts<'tcx> { } /// Creates an `InternalSubsts` that maps each generic parameter to itself. - pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { - Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) + pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: impl Into<DefId>) -> SubstsRef<'tcx> { + Self::for_item(tcx, def_id.into(), |param, _| tcx.mk_param_from_def(param)) } /// Creates an `InternalSubsts` for generic parameter definitions, diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 233c0df2d..6747da7ab 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; +use crate::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{Ident, Ty, TyCtxt}; use hir::def_id::LOCAL_CRATE; @@ -100,8 +100,9 @@ impl<'tcx> TraitDef { } impl<'tcx> TyCtxt<'tcx> { - pub fn for_each_impl<F: FnMut(DefId)>(self, def_id: DefId, mut f: F) { - let impls = self.trait_impls_of(def_id); + /// `trait_def_id` MUST BE the `DefId` of a trait. + pub fn for_each_impl<F: FnMut(DefId)>(self, trait_def_id: DefId, mut f: F) { + let impls = self.trait_impls_of(trait_def_id); for &impl_def_id in impls.blanket_impls.iter() { f(impl_def_id); @@ -114,27 +115,45 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Iterate over every impl that could possibly match the - /// self type `self_ty`. - pub fn for_each_relevant_impl<F: FnMut(DefId)>( + /// Iterate over every impl that could possibly match the self type `self_ty`. + /// + /// `trait_def_id` MUST BE the `DefId` of a trait. + pub fn for_each_relevant_impl( self, - def_id: DefId, + trait_def_id: DefId, self_ty: Ty<'tcx>, - mut f: F, + f: impl FnMut(DefId), ) { - let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| { - f(did); - None - }); + self.for_each_relevant_impl_treating_projections( + trait_def_id, + self_ty, + TreatProjections::ForLookup, + f, + ) } + pub fn for_each_relevant_impl_treating_projections( + self, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + treat_projections: TreatProjections, + mut f: impl FnMut(DefId), + ) { + let _: Option<()> = + self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| { + f(did); + None + }); + } + + /// `trait_def_id` MUST BE the `DefId` of a trait. pub fn non_blanket_impls_for_ty( self, - def_id: DefId, + trait_def_id: DefId, self_ty: Ty<'tcx>, ) -> impl Iterator<Item = DefId> + 'tcx { - let impls = self.trait_impls_of(def_id); - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) { + let impls = self.trait_impls_of(trait_def_id); + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -145,18 +164,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Applies function to every impl that could possibly match the self type `self_ty` and returns /// the first non-none value. - pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>( + /// + /// `trait_def_id` MUST BE the `DefId` of a trait. + pub fn find_map_relevant_impl<T>( self, - def_id: DefId, + trait_def_id: DefId, self_ty: Ty<'tcx>, - mut f: F, + treat_projections: TreatProjections, + mut f: impl FnMut(DefId) -> Option<T>, ) -> Option<T> { // FIXME: This depends on the set of all impls for the trait. That is // unfortunate wrt. incremental compilation. // // If we want to be faster, we could have separate queries for // blanket and non-blanket impls, and compare them separately. - let impls = self.trait_impls_of(def_id); + let impls = self.trait_impls_of(trait_def_id); for &impl_def_id in impls.blanket_impls.iter() { if let result @ Some(_) = f(impl_def_id) { @@ -164,14 +186,17 @@ impl<'tcx> TyCtxt<'tcx> { } } - // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using - // `TreatParams::AsInfer` while actually adding them. - // + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using + // `TreatParams::AsCandidateKey` while actually adding them. + let treat_params = match treat_projections { + TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, + TreatProjections::ForLookup => TreatParams::ForLookup, + }; // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { if let result @ Some(_) = f(impl_def_id) { @@ -190,9 +215,11 @@ impl<'tcx> TyCtxt<'tcx> { None } - /// Returns an iterator containing all impls - pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { - let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); + /// Returns an iterator containing all impls for `trait_def_id`. + /// + /// `trait_def_id` MUST BE the `DefId` of a trait. + pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { + let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(trait_def_id); blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned() } @@ -231,7 +258,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer) + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 586958247..47943b94c 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -8,10 +8,9 @@ use crate::{ }, }; use rustc_data_structures::{ - fx::FxHashMap, + fx::{FxHashMap, FxIndexMap}, sync::Lrc, unord::{UnordItems, UnordSet}, - vec_map::VecMap, }; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -26,6 +25,7 @@ use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; +use rustc_target::abi::FieldIdx; use std::{collections::hash_map::Entry, hash::Hash, iter}; use super::RvalueScopes; @@ -43,7 +43,7 @@ pub struct TypeckResults<'tcx> { /// or patterns (`S { field }`). The index is often useful by itself, but to learn more /// about the field you also need definition of the variant to which the field /// belongs, but it may not exist if it's a tuple field (`tuple.0`). - field_indices: ItemLocalMap<usize>, + field_indices: ItemLocalMap<FieldIdx>, /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated outside inference. See @@ -155,7 +155,7 @@ pub struct TypeckResults<'tcx> { /// by this function. We also store the /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -314,19 +314,19 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs } } - pub fn field_indices(&self) -> LocalTableInContext<'_, usize> { + pub fn field_indices(&self) -> LocalTableInContext<'_, FieldIdx> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices } } - pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> { + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, FieldIdx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices } } - pub fn field_index(&self, id: hir::HirId) -> usize { + pub fn field_index(&self, id: hir::HirId) -> FieldIdx { self.field_indices().get(id).cloned().expect("no index for a field") } - pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> { + pub fn opt_field_index(&self, id: hir::HirId) -> Option<FieldIdx> { self.field_indices().get(id).cloned() } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 90270e0ee..c8a78ec03 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,10 +2,11 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir; +use crate::ty::fast_reject::TreatProjections; use crate::ty::layout::IntegerExt; use crate::ty::{ - self, DefIdTree, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, + self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, }; use crate::ty::{GenericArgKind, SubstsRef}; use rustc_apfloat::Float as _; @@ -14,11 +15,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; -use rustc_span::{sym, DUMMY_SP}; +use rustc_session::Limit; +use rustc_span::sym; use rustc_target::abi::{Integer, IntegerType, Size, TargetDataLayout}; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; @@ -59,22 +61,13 @@ impl<'tcx> fmt::Display for Discr<'tcx> { } } -fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { - let (int, signed) = match *ty.kind() { - ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true), - ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), - _ => bug!("non integer discriminant"), - }; - (int.size(), signed) -} - impl<'tcx> Discr<'tcx> { /// Adds `1` to the value and wraps around if the maximum for the type is reached. pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self { self.checked_add(tcx, 1).0 } pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) { - let (size, signed) = int_size_and_signed(tcx, self.ty); + let (size, signed) = self.ty.int_size_and_signed(tcx); let (val, oflo) = if signed { let min = size.signed_int_min(); let max = size.signed_int_max(); @@ -233,17 +226,20 @@ impl<'tcx> TyCtxt<'tcx> { let recursion_limit = self.recursion_limit(); for iteration in 0.. { if !recursion_limit.value_within_limit(iteration) { - return self.ty_error_with_message( - DUMMY_SP, - &format!("reached the recursion limit finding the struct tail for {}", ty), - ); + let suggested_limit = match recursion_limit { + Limit(0) => Limit(2), + limit => limit * 2, + }; + let reported = + self.sess.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit }); + return self.ty_error(reported); } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { break; } - match def.non_enum_variant().fields.last() { + match def.non_enum_variant().fields.raw.last() { Some(field) => { f(); ty = field.ty(self, substs); @@ -317,7 +313,7 @@ impl<'tcx> TyCtxt<'tcx> { (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { - if let Some(f) = a_def.non_enum_variant().fields.last() { + if let Some(f) = a_def.non_enum_variant().fields.raw.last() { a = f.ty(self, a_substs); b = f.ty(self, b_substs); } else { @@ -363,14 +359,20 @@ impl<'tcx> TyCtxt<'tcx> { self.ensure().coherent_trait(drop_trait); let ty = self.type_of(adt_did).subst_identity(); - let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { - if let Some(item_id) = self.associated_item_def_ids(impl_did).first() { - if validate(self, impl_did).is_ok() { - return Some((*item_id, self.constness(impl_did))); + let (did, constness) = self.find_map_relevant_impl( + drop_trait, + ty, + // FIXME: This could also be some other mode, like "unexpected" + TreatProjections::ForLookup, + |impl_did| { + if let Some(item_id) = self.associated_item_def_ids(impl_did).first() { + if validate(self, impl_did).is_ok() { + return Some((*item_id, self.constness(impl_did))); + } } - } - None - })?; + None + }, + )?; Some(ty::Destructor { did, constness }) } @@ -599,6 +601,28 @@ impl<'tcx> TyCtxt<'tcx> { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } + /// Returns `true` if the item pointed to by `def_id` is a thread local which needs a + /// thread local shim generated. + #[inline] + pub fn needs_thread_local_shim(self, def_id: DefId) -> bool { + !self.sess.target.dll_tls_export + && self.is_thread_local_static(def_id) + && !self.is_foreign_item(def_id) + } + + /// Returns the type a reference to the thread local takes in MIR. + pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { + let static_ty = self.type_of(def_id).subst_identity(); + if self.is_mutable_static(def_id) { + self.mk_mut_ptr(static_ty) + } else if self.is_foreign_item(def_id) { + self.mk_imm_ptr(static_ty) + } else { + // FIXME: These things don't *really* have 'static lifetime. + self.mk_imm_ref(self.lifetimes.re_static, static_ty) + } + } + /// Get the type of the pointer to the static that we use in MIR. pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. @@ -684,10 +708,6 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.explicit_item_bounds(def_id)) } - pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> { - ty::EarlyBinder(self.impl_subject(def_id)) - } - /// Returns names of captured upvars for closures and generators. /// /// Here are some examples: @@ -922,12 +942,21 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { } impl<'tcx> Ty<'tcx> { + pub fn int_size_and_signed(self, tcx: TyCtxt<'tcx>) -> (Size, bool) { + let (int, signed) = match *self.kind() { + ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true), + ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), + _ => bug!("non integer discriminant"), + }; + (int.size(), signed) + } + /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { - let (size, signed) = int_size_and_signed(tcx, self); + let (size, signed) = self.int_size_and_signed(tcx); let val = if signed { size.signed_int_max() as u128 } else { size.unsigned_int_max() }; Some(val) @@ -948,7 +977,7 @@ impl<'tcx> Ty<'tcx> { pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { - let (size, signed) = int_size_and_signed(tcx, self); + let (size, signed) = self.int_size_and_signed(tcx); let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 }; Some(val) } @@ -1432,8 +1461,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( } /// Determines whether an item is annotated with `doc(hidden)`. -fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - assert!(def_id.is_local()); +fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.get_attrs(def_id, sym::doc) .filter_map(|attr| attr.meta_item_list()) .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) @@ -1447,7 +1475,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } /// Determines whether an item is an intrinsic by Abi. -pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 6814cadb9..08a62c900 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -83,6 +83,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { | TypeFlags::HAS_CT_PLACEHOLDER, ) } + fn has_non_region_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER) + } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c4f526dbd..55aa4fcff 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -4,7 +4,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::query::QueryInfo; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; |