diff options
Diffstat (limited to 'compiler/rustc_middle/src')
30 files changed, 515 insertions, 243 deletions
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5043bd855cc..a1bcee84d4c 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -20,44 +20,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::spec::abi::Abi; -#[inline] -pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { - match node { - Node::Item(Item { - owner_id, - kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), - .. - }) - | Node::TraitItem(TraitItem { - owner_id, - kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), - .. - }) - | Node::ImplItem(ImplItem { - owner_id, - kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), - .. - }) => Some((owner_id.def_id, *body)), - - Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { - Some((*def_id, *body)) - } - - Node::AnonConst(constant) => Some((constant.def_id, constant.body)), - Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), - - _ => None, - } -} - -fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool { - match associated_body(node) { - Some((_, b)) => b.hir_id == hir_id, - None => false, - } -} - // FIXME: the structure was necessary in the past but now it // only serves as "namespace" for HIR-related methods, and can be // removed if all the methods are reasonably renamed and moved to tcx @@ -114,20 +76,16 @@ impl<'hir> Iterator for ParentOwnerIterator<'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.def_key(self.current_id.owner.def_id).parent; - let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { - let def_id = LocalDefId { local_def_index }; - self.map.tcx.local_def_id_to_hir_id(def_id).owner - }); - self.current_id = HirId::make_owner(parent_id.def_id); + let parent_id = self.map.def_key(self.current_id.owner.def_id).parent; + let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + self.map.tcx.local_def_id_to_hir_id(def_id).owner + }); + self.current_id = HirId::make_owner(parent_id.def_id); - // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. - let node = self.map.tcx.hir_owner_node(self.current_id.owner); - return Some((self.current_id.owner, node)); - } + let node = self.map.tcx.hir_owner_node(self.current_id.owner); + return Some((self.current_id.owner, node)); } } @@ -208,12 +166,12 @@ impl<'hir> Map<'hir> { #[inline] pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir { - self.tcx.hir_crate_items(()).items.iter().copied() + self.tcx.hir_crate_items(()).free_items.iter().copied() } #[inline] pub fn module_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> + 'hir { - self.tcx.hir_module_items(module).items() + self.tcx.hir_module_items(module).free_items() } pub fn def_key(self, def_id: LocalDefId) -> DefKey { @@ -273,7 +231,7 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { for (_, node) in self.parent_iter(hir_id) { - if let Some((def_id, _)) = associated_body(node) { + if let Some((def_id, _)) = node.associated_body() { return def_id; } } @@ -286,20 +244,18 @@ impl<'hir> Map<'hir> { /// item (possibly associated), a closure, or a `hir::AnonConst`. pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId { let parent = self.tcx.parent_hir_id(hir_id); - assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}"); + assert_eq!(self.tcx.hir_node(parent).body_id().unwrap().hir_id, hir_id, "{hir_id:?}"); parent } pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { - associated_body(self.tcx.parent_hir_node(hir_id)).unwrap().0 + self.tcx.parent_hir_node(hir_id).associated_body().unwrap().0 } /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> { - let node = self.tcx.hir_node_by_def_id(id); - let (_, body_id) = associated_body(node)?; - Some(body_id) + self.tcx.hir_node_by_def_id(id).body_id() } /// Given a body owner's id, returns the `BodyId` associated with it. @@ -462,7 +418,7 @@ impl<'hir> Map<'hir> { V: Visitor<'hir>, { let krate = self.tcx.hir_crate_items(()); - walk_list!(visitor, visit_item, krate.items().map(|id| self.item(id))); + walk_list!(visitor, visit_item, krate.free_items().map(|id| self.item(id))); walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id))); walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id))); walk_list!( @@ -480,7 +436,7 @@ impl<'hir> Map<'hir> { V: Visitor<'hir>, { let module = self.tcx.hir_module_items(module); - walk_list!(visitor, visit_item, module.items().map(|id| self.item(id))); + walk_list!(visitor, visit_item, module.free_items().map(|id| self.item(id))); walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id))); walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id))); walk_list!( @@ -954,7 +910,7 @@ impl<'hir> Map<'hir> { Node::Crate(item) => item.spans.inner_span, Node::WhereBoundPredicate(pred) => pred.span, Node::ArrayLenInfer(inf) => inf.span, - Node::AssocOpaqueTy(..) => unreachable!(), + Node::Synthetic => unreachable!(), Node::Err(span) => *span, } } @@ -1219,7 +1175,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::Crate(..) => String::from("(root_crate)"), Node::WhereBoundPredicate(_) => node_str("where bound predicate"), Node::ArrayLenInfer(_) => node_str("array len infer"), - Node::AssocOpaqueTy(..) => unreachable!(), + Node::Synthetic => unreachable!(), Node::Err(_) => node_str("error"), } } @@ -1241,7 +1197,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod } = collector; return ModuleItems { submodules: submodules.into_boxed_slice(), - items: items.into_boxed_slice(), + free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), @@ -1270,7 +1226,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { return ModuleItems { submodules: submodules.into_boxed_slice(), - items: items.into_boxed_slice(), + free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), @@ -1314,7 +1270,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_item(&mut self, item: &'hir Item<'hir>) { - if associated_body(Node::Item(item)).is_some() { + if Node::Item(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1355,7 +1311,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { - if associated_body(Node::TraitItem(item)).is_some() { + if Node::TraitItem(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1364,7 +1320,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { - if associated_body(Node::ImplItem(item)).is_some() { + if Node::ImplItem(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f9fa8ac2f7a..28f7574f66f 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -22,7 +22,7 @@ use rustc_span::{ErrorGuaranteed, ExpnId}; #[derive(Debug, HashStable, Encodable, Decodable)] pub struct ModuleItems { submodules: Box<[OwnerId]>, - items: Box<[ItemId]>, + free_items: Box<[ItemId]>, trait_items: Box<[TraitItemId]>, impl_items: Box<[ImplItemId]>, foreign_items: Box<[ForeignItemId]>, @@ -30,14 +30,22 @@ pub struct ModuleItems { } impl ModuleItems { - pub fn items(&self) -> impl Iterator<Item = ItemId> + '_ { - self.items.iter().copied() + /// Returns all non-associated locally defined items in all modules. + /// + /// Note that this does *not* include associated items of `impl` blocks! It also does not + /// include foreign items. If you want to e.g. get all functions, use `definitions()` below. + /// + /// However, this does include the `impl` blocks themselves. + pub fn free_items(&self) -> impl Iterator<Item = ItemId> + '_ { + self.free_items.iter().copied() } pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ { self.trait_items.iter().copied() } + /// Returns all items that are associated with some `impl` block (both inherent and trait impl + /// blocks). pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ { self.impl_items.iter().copied() } @@ -47,7 +55,7 @@ impl ModuleItems { } pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ { - self.items + self.free_items .iter() .map(|id| id.owner_id) .chain(self.trait_items.iter().map(|id| id.owner_id)) @@ -63,7 +71,7 @@ impl ModuleItems { &self, f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - try_par_for_each_in(&self.items[..], |&id| f(id)) + try_par_for_each_in(&self.free_items[..], |&id| f(id)) } pub fn par_trait_items( diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e47668b9110..e52a5863fd0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -24,13 +24,13 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![cfg_attr(bootstrap, feature(exhaustive_patterns))] -#![cfg_attr(not(bootstrap), feature(min_exhaustive_patterns))] +#![feature(min_exhaustive_patterns)] #![feature(rustdoc_internals)] #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(closure_track_caller)] #![feature(core_intrinsics)] #![feature(const_type_name)] #![feature(discriminant_kind)] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 0ee97a6bed0..f70ef51107f 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -11,12 +11,18 @@ /// [`span_bug`]: crate::span_bug #[macro_export] macro_rules! bug { - () => ( $crate::bug!("impossible case reached") ); - ($msg:expr) => ({ $crate::util::bug::bug_fmt(::std::format_args!($msg)) }); - ($msg:expr,) => ({ $crate::bug!($msg) }); - ($fmt:expr, $($arg:tt)+) => ({ + () => ( + $crate::bug!("impossible case reached") + ); + ($msg:expr) => ( + $crate::util::bug::bug_fmt(::std::format_args!($msg)) + ); + ($msg:expr,) => ( + $crate::bug!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ( $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+)) - }); + ); } /// A macro for triggering an ICE with a span. @@ -30,11 +36,15 @@ macro_rules! bug { /// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug #[macro_export] macro_rules! span_bug { - ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) }); - ($span:expr, $msg:expr,) => ({ $crate::span_bug!($span, $msg) }); - ($span:expr, $fmt:expr, $($arg:tt)+) => ({ + ($span:expr, $msg:expr) => ( + $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) + ); + ($span:expr, $msg:expr,) => ( + $crate::span_bug!($span, $msg) + ); + ($span:expr, $fmt:expr, $($arg:tt)+) => ( $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+)) - }); + ); } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 214297b9869..02185cbeacf 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -456,7 +456,7 @@ impl<'tcx> Const<'tcx> { } /// An unevaluated (potentially generic) constant used in MIR. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 645a417c322..588aa1f40d7 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -88,14 +88,13 @@ pub enum CoverageKind { /// Marks a span that might otherwise not be represented in MIR, so that /// coverage instrumentation can associate it with its enclosing block/BCB. /// - /// Only used by the `InstrumentCoverage` pass, and has no effect during - /// codegen. + /// Should be erased before codegen (at some point after `InstrumentCoverage`). SpanMarker, /// Marks its enclosing basic block with an ID that can be referred to by /// side data in [`BranchInfo`]. /// - /// Has no effect during codegen. + /// Should be erased before codegen (at some point after `InstrumentCoverage`). BlockMarker { id: BlockMarkerId }, /// Marks the point in MIR control flow represented by a coverage counter. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 4047891d769..00faa211853 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -37,9 +37,16 @@ pub trait AllocBytes: /// Create a zeroed `AllocBytes` of the specified size and alignment. /// Returns `None` if we ran out of memory on the host. fn zeroed(size: Size, _align: Align) -> Option<Self>; + + /// Gives direct access to the raw underlying storage. + /// + /// Crucially this pointer is compatible with: + /// - other pointers retunred by this method, and + /// - references returned from `deref()`, as long as there was no write. + fn as_mut_ptr(&mut self) -> *mut u8; } -// Default `bytes` for `Allocation` is a `Box<[u8]>`. +/// Default `bytes` for `Allocation` is a `Box<u8>`. impl AllocBytes for Box<[u8]> { fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self { Box::<[u8]>::from(slice.into()) @@ -51,6 +58,11 @@ impl AllocBytes for Box<[u8]> { let bytes = unsafe { bytes.assume_init() }; Some(bytes) } + + fn as_mut_ptr(&mut self) -> *mut u8 { + // Carefully avoiding any intermediate references. + ptr::addr_of_mut!(**self).cast() + } } /// This type represents an Allocation in the Miri/CTFE core engine. @@ -399,10 +411,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> /// Byte accessors. impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> { - pub fn base_addr(&self) -> *const u8 { - self.bytes.as_ptr() - } - /// This is the entirely abstraction-violating way to just grab the raw bytes without /// caring about provenance or initialization. /// @@ -452,13 +460,14 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> Ok(self.get_bytes_unchecked(range)) } - /// Just calling this already marks everything as defined and removes provenance, - /// so be sure to actually put data there! + /// This is the entirely abstraction-violating way to just get mutable access to the raw bytes. + /// Just calling this already marks everything as defined and removes provenance, so be sure to + /// actually overwrite all the data there! /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods /// on `InterpCx` instead. - pub fn get_bytes_mut( + pub fn get_bytes_unchecked_for_overwrite( &mut self, cx: &impl HasDataLayout, range: AllocRange, @@ -469,8 +478,9 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]) } - /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory. - pub fn get_bytes_mut_ptr( + /// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases + /// into this memory. + pub fn get_bytes_unchecked_for_overwrite_ptr( &mut self, cx: &impl HasDataLayout, range: AllocRange, @@ -479,10 +489,19 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> self.provenance.clear(range, cx)?; assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check + // Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); let len = range.end().bytes_usize() - range.start.bytes_usize(); Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len)) } + + /// This gives direct mutable access to the entire buffer, just exposing their internal state + /// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if + /// `OFFSET_IS_ADDR` is true. + pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 { + assert!(Prov::OFFSET_IS_ADDR); + self.bytes.as_mut_ptr() + } } /// Reading and writing. @@ -589,7 +608,8 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> }; let endian = cx.data_layout().endian; - let dst = self.get_bytes_mut(cx, range)?; + // Yes we do overwrite all the bytes in `dst`. + let dst = self.get_bytes_unchecked_for_overwrite(cx, range)?; write_target_uint(endian, dst, bytes).unwrap(); // See if we have to also store some provenance. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index f9edbb3c5ae..6275942bafe 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -671,11 +671,11 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, i // So we do not read exactly 16 bytes into the u128, just the "payload". let uint = match endianness { Endian::Little => { - source.read(&mut buf)?; + source.read_exact(&mut buf[..source.len()])?; Ok(u128::from_le_bytes(buf)) } Endian::Big => { - source.read(&mut buf[16 - source.len()..])?; + source.read_exact(&mut buf[16 - source.len()..])?; Ok(u128::from_be_bytes(buf)) } }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d57ffc0f8b5..48edbde68e5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -20,6 +20,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind}; use rustc_hir::{self as hir, HirId}; use rustc_session::Session; +use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, VariantIdx}; use polonius_engine::Atom; @@ -44,6 +45,7 @@ use std::ops::{Index, IndexMut}; use std::{iter, mem}; pub use self::query::*; +use self::visit::TyContext; pub use basic_blocks::BasicBlocks; mod basic_blocks; @@ -278,13 +280,6 @@ pub struct CoroutineInfo<'tcx> { /// using `run_passes`. pub by_move_body: Option<Body<'tcx>>, - /// The body of the coroutine, modified to take its upvars by mutable ref rather than by - /// immutable ref. - /// - /// FIXME(async_closures): This is literally the same body as the parent body. Find a better - /// way to represent the by-mut signature (or cap the closure-kind of the coroutine). - pub by_mut_body: Option<Body<'tcx>>, - /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option<CoroutineLayout<'tcx>>, @@ -305,13 +300,27 @@ impl<'tcx> CoroutineInfo<'tcx> { yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), by_move_body: None, - by_mut_body: None, coroutine_drop: None, coroutine_layout: None, } } } +/// Some item that needs to monomorphize successfully for a MIR body to be considered well-formed. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum MentionedItem<'tcx> { + /// A function that gets called. We don't necessarily know its precise type yet, since it can be + /// hidden behind a generic. + Fn(Ty<'tcx>), + /// A type that has its drop shim called. + Drop(Ty<'tcx>), + /// Unsizing casts might require vtables, so we have to record them. + UnsizeCast { source_ty: Ty<'tcx>, target_ty: Ty<'tcx> }, + /// A closure that is coerced to a function pointer. + Closure(Ty<'tcx>), +} + /// The lowered representation of a single function. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct Body<'tcx> { @@ -375,8 +384,24 @@ pub struct Body<'tcx> { /// Constants that are required to evaluate successfully for this MIR to be well-formed. /// We hold in this field all the constants we are not able to evaluate yet. + /// + /// This is soundness-critical, we make a guarantee that all consts syntactically mentioned in a + /// function have successfully evaluated if the function ever gets executed at runtime. pub required_consts: Vec<ConstOperand<'tcx>>, + /// Further items that were mentioned in this function and hence *may* become monomorphized, + /// depending on optimizations. We use this to avoid optimization-dependent compile errors: the + /// collector recursively traverses all "mentioned" items and evaluates all their + /// `required_consts`. + /// + /// This is *not* soundness-critical and the contents of this list are *not* a stable guarantee. + /// All that's relevant is that this set is optimization-level-independent, and that it includes + /// everything that the collector would consider "used". (For example, we currently compute this + /// set after drop elaboration, so some drop calls that can never be reached are not considered + /// "mentioned".) See the documentation of `CollectionMode` in + /// `compiler/rustc_monomorphize/src/collector.rs` for more context. + pub mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>, + /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. /// /// Note that this does not actually mean that this body is not computable right now. @@ -453,6 +478,7 @@ impl<'tcx> Body<'tcx> { var_debug_info, span, required_consts: Vec::new(), + mentioned_items: Vec::new(), is_polymorphic: false, injection_phase: None, tainted_by_errors, @@ -482,6 +508,7 @@ impl<'tcx> Body<'tcx> { spread_arg: None, span: DUMMY_SP, required_consts: Vec::new(), + mentioned_items: Vec::new(), var_debug_info: Vec::new(), is_polymorphic: false, injection_phase: None, @@ -576,6 +603,17 @@ impl<'tcx> Body<'tcx> { } } + pub fn span_for_ty_context(&self, ty_context: TyContext) -> Span { + match ty_context { + TyContext::UserTy(span) => span, + TyContext::ReturnTy(source_info) + | TyContext::LocalDecl { source_info, .. } + | TyContext::YieldTy(source_info) + | TyContext::ResumeTy(source_info) => source_info.span, + TyContext::Location(loc) => self.source_info(loc).span, + } + } + /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn return_ty(&self) -> Ty<'tcx> { @@ -628,10 +666,6 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref()?.by_move_body.as_ref() } - pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> { - self.coroutine.as_ref()?.by_mut_body.as_ref() - } - #[inline] pub fn coroutine_kind(&self) -> Option<CoroutineKind> { self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 8bd872c1b19..731e050ca9b 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -284,8 +284,15 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// order of the category, thereby influencing diagnostic output. /// /// See also `rustc_const_eval::borrow_check::constraints`. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] +#[derive(derivative::Derivative)] +#[derivative( + PartialOrd, + Ord, + PartialOrd = "feature_allow_slow_enum", + Ord = "feature_allow_slow_enum" +)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, @@ -295,6 +302,7 @@ pub enum ConstraintCategory<'tcx> { Cast { /// Whether this is an unsizing cast and if yes, this contains the target type. /// Region variables are erased to ReErased. + #[derivative(PartialOrd = "ignore", Ord = "ignore")] unsize_to: Option<Ty<'tcx>>, }, @@ -304,7 +312,7 @@ pub enum ConstraintCategory<'tcx> { ClosureBounds, /// Contains the function type if available. - CallArgument(Option<Ty<'tcx>>), + CallArgument(#[derivative(PartialOrd = "ignore", Ord = "ignore")] Option<Ty<'tcx>>), CopyBound, SizedBound, Assignment, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 0ab797134c0..752f5845afb 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -124,6 +124,7 @@ pub enum AnalysisPhase { /// * [`TerminatorKind::FalseEdge`] /// * [`StatementKind::FakeRead`] /// * [`StatementKind::AscribeUserType`] + /// * [`StatementKind::Coverage`] with [`CoverageKind::BlockMarker`] or [`CoverageKind::SpanMarker`] /// * [`Rvalue::Ref`] with `BorrowKind::Fake` /// /// Furthermore, `Deref` projections must be the first projection within any place (if they diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 845b1717550..be960669ff4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -345,8 +345,11 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | - ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } | + ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: _def_id, + receiver_by_ref: _, + } | + ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 865299e15c8..10d92583a55 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -343,11 +343,14 @@ rustc_queries! { } } - /// Returns the list of bounds that can be used for - /// `SelectionCandidate::ProjectionCandidate(_)` and - /// `ProjectionTyCandidate::TraitDef`. - /// Specifically this is the bounds written on the trait's type - /// definition, or those after the `impl` keyword + /// Returns the list of bounds that are required to be satsified + /// by a implementation or definition. For associated types, these + /// must be satisfied for an implementation to be well-formed, + /// and for opaque types, these are required to be satisfied by + /// the hidden-type of the opaque. + /// + /// Syntactially, these are the bounds written on the trait's type + /// definition, or those after the `impl` keyword for an opaque: /// /// ```ignore (incomplete) /// type X: Bound + 'lt @@ -363,7 +366,16 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern - feedable + } + + /// The set of item bounds (see [`TyCtxt::explicit_item_bounds`]) that + /// share the `Self` type of the item. These are a subset of the bounds + /// that may explicitly be used for things like closure signature + /// deduction. + query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -390,6 +402,14 @@ rustc_queries! { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } + query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } + } + + query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } + } + /// Look up all native libraries this crate depends on. /// These are assembled from the following places: /// - `extern` blocks (depending on their `link` attributes) @@ -703,8 +723,8 @@ rustc_queries! { separate_provide_extern } - query adt_sized_constraint(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> { - desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } + query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<Ty<'tcx>>> { + desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) } } query adt_dtorck_constraint( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 96a61883cc1..f684f83a261 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> { AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } + | DerefPattern { subpattern } | InlineConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) @@ -762,6 +763,11 @@ pub enum PatKind<'tcx> { subpattern: Box<Pat<'tcx>>, }, + /// Deref pattern, written `box P` for now. + DerefPattern { + subpattern: Box<Pat<'tcx>>, + }, + /// One of the following: /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus /// exhaustiveness checking will detect if you use the same string twice in different @@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } write!(f, "{subpattern}") } + PatKind::DerefPattern { ref subpattern } => { + write!(f, "deref!({subpattern})") + } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { write!(f, "{} (from inline const)", subpattern) diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5952c296fb6..99ab006bcc0 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } + | DerefPattern { subpattern } | Binding { subpattern: Some(subpattern), mutability: _, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2e1c7df6454..a7144316769 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -590,10 +590,10 @@ impl<'tcx> AdtDef<'tcx> { tcx.adt_destructor(self.did()) } - /// Returns a list of types such that `Self: Sized` if and only if that - /// type is `Sized`, or `ty::Error` if this type has a recursive layout. - pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> { - tcx.adt_sized_constraint(self.did()) + /// Returns a type such that `Self: Sized` if and only if that type is `Sized`, + /// or `None` if the type is always sized. + pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<Ty<'tcx>>> { + if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None } } } @@ -601,5 +601,5 @@ impl<'tcx> AdtDef<'tcx> { #[derive(HashStable)] pub enum Representability { Representable, - Infinite, + Infinite(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 10a4da40429..8a87538e788 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -596,6 +596,27 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { pub fn feed_owner_id(&self) -> TyCtxtFeed<'tcx, hir::OwnerId> { TyCtxtFeed { tcx: self.tcx, key: hir::OwnerId { def_id: self.key } } } + + // Fills in all the important parts needed by HIR queries + pub fn feed_hir(&self) { + self.local_def_id_to_hir_id(HirId::make_owner(self.def_id())); + + let node = hir::OwnerNode::Synthetic; + let bodies = Default::default(); + let attrs = hir::AttributeMap::EMPTY; + + let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map); + let node = node.into(); + self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { + opt_hash_including_bodies, + nodes: IndexVec::from_elem_n( + hir::ParentedNode { parent: hir::ItemLocalId::INVALID, node }, + 1, + ), + bodies, + }))); + self.feed_owner_id().hir_attrs(attrs); + } } /// The central data structure of the compiler. It stores references @@ -1807,7 +1828,7 @@ impl<'tcx> TyCtxt<'tcx> { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; let future_trait = self.require_lang_item(LangItem::Future, None); - self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { + self.explicit_item_super_predicates(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { return false; }; diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 788ccd5dbbd..5e256dc8d26 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -85,6 +85,7 @@ where /// Allows access to the current `ImplicitCtxt` in a closure if one is available. #[inline] +#[track_caller] pub fn with_context_opt<F, R>(f: F) -> R where F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, @@ -147,9 +148,13 @@ where /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. /// The closure is passed None if there is no `ImplicitCtxt` available. #[inline] +#[track_caller] pub fn with_opt<F, R>(f: F) -> R where F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R, { - with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) + with_context_opt( + #[track_caller] + |opt_context| f(opt_context.map(|context| context.tcx)), + ) } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 05463b8554f..ee18647cdd8 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized { /// inference variables to be suggestable. fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool; - fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>; + fn make_suggestable( + self, + tcx: TyCtxt<'tcx>, + infer_suggestable: bool, + placeholder: Option<Ty<'tcx>>, + ) -> Option<Self>; } impl<'tcx, T> IsSuggestable<'tcx> for T @@ -103,8 +108,13 @@ where self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue() } - fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> { - self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok() + fn make_suggestable( + self, + tcx: TyCtxt<'tcx>, + infer_suggestable: bool, + placeholder: Option<Ty<'tcx>>, + ) -> Option<T> { + self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok() } } @@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> { pub struct MakeSuggestableFolder<'tcx> { tcx: TyCtxt<'tcx>, infer_suggestable: bool, + placeholder: Option<Ty<'tcx>>, } impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { @@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { let t = match *t.kind() { Infer(InferTy::TyVar(_)) if self.infer_suggestable => t, - FnDef(def_id, args) => { + FnDef(def_id, args) if self.placeholder.is_none() => { Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args)) } - // FIXME(compiler-errors): We could replace these with infer, I guess. Closure(..) + | FnDef(..) | Infer(..) | Coroutine(..) | CoroutineWitness(..) | Bound(_, _) | Placeholder(_) | Error(_) => { - return Err(()); + if let Some(placeholder) = self.placeholder { + // We replace these with infer (which is passed in from an infcx). + placeholder + } else { + return Err(()); + } } Alias(Opaque, AliasTy { def_id, .. }) => { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index bbcc244cb26..da5d57db5be 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { return InhabitedPredicate::True; } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 814c3629b08..4748e961019 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -90,15 +90,19 @@ pub enum InstanceDef<'tcx> { /// and dispatch to the `FnMut::call_mut` instance for the closure. ClosureOnceShim { call_once: DefId, track_caller: bool }, - /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or - /// `<[Fn coroutine-closure] as FnMut>::call_mut`. + /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` /// /// The body generated here differs significantly from the `ClosureOnceShim`, /// since we need to generate a distinct coroutine type that will move the /// closure's upvars *out* of the closure. ConstructCoroutineInClosureShim { coroutine_closure_def_id: DefId, - target_kind: ty::ClosureKind, + // Whether the generated MIR body takes the coroutine by-ref. This is + // because the signature of `<{async fn} as FnMut>::call_mut` is: + // `fn(&mut self, args: A) -> <Self as FnOnce>::Output`, that is to say + // that it returns the `FnOnce`-flavored coroutine but takes the closure + // by mut ref (and similarly for `Fn::call`). + receiver_by_ref: bool, }, /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` @@ -107,7 +111,7 @@ pub enum InstanceDef<'tcx> { /// /// This will select the body that is produced by the `ByMoveBody` transform, and thus /// take and use all of its upvars by-move rather than by-ref. - CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind }, + CoroutineKindShim { coroutine_def_id: DefId }, /// 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 @@ -192,9 +196,9 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: def_id, - target_kind: _, + receiver_by_ref: _, } - | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ } + | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -651,10 +655,7 @@ impl<'tcx> Instance<'tcx> { Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else { Some(Instance { - def: ty::InstanceDef::CoroutineKindShim { - coroutine_def_id, - target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), - }, + def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id }, args, }) } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 11fd73c9094..595ef71cc32 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::{self, ConstKind, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, @@ -356,21 +356,10 @@ impl<'tcx> SizeSkeleton<'tcx> { .ok_or_else(|| &*tcx.arena.alloc(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(tcx.arena.alloc(LayoutError::SizeOverflow(ty))); - }; - Ok(SizeSkeleton::Generic(gen_size)) + Err(tcx.arena.alloc(LayoutError::Unknown(ty))) } 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(tcx.arena.alloc(LayoutError::SizeOverflow(ty))); - }; - Ok(SizeSkeleton::Generic(gen_size)) - } + SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))), } } @@ -468,56 +457,6 @@ impl<'tcx> SizeSkeleton<'tcx> { } } -/// When creating the layout for types with abstract consts 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 transmuting 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; - - let mut work = vec![a, b]; - let mut done = vec![]; - while let Some(n) = work.pop() { - if let ConstKind::Expr(ty::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| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty())) -} - pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx(&self) -> TyCtxt<'tcx>; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8565f90957f..6632d980bff 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1752,9 +1752,8 @@ impl<'tcx> TyCtxt<'tcx> { let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) - } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) { - bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { + debug_assert!(rustc_feature::encode_cross_crate(attr)); self.item_attrs(did).iter().filter(filter_fn) } } @@ -1786,12 +1785,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether an item is annotated with an attribute. 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 { - self.get_attrs(did, attr).next().is_some() - } + self.get_attrs(did, attr).next().is_some() } /// Returns `true` if this is an `auto trait`. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 802953867ac..995b439d10a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -4,7 +4,7 @@ use crate::query::Providers; use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing}; use crate::ty::GenericArgKind; use crate::ty::{ - ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, + ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_apfloat::ieee::{Double, Single}; @@ -270,6 +270,31 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } + /// Prints `(...)` around what `f` prints. + fn parenthesized( + &mut self, + f: impl FnOnce(&mut Self) -> Result<(), PrintError>, + ) -> Result<(), PrintError> { + self.write_str("(")?; + f(self)?; + self.write_str(")")?; + Ok(()) + } + + /// Prints `(...)` around what `f` prints if `parenthesized` is true, otherwise just prints `f`. + fn maybe_parenthesized( + &mut self, + f: impl FnOnce(&mut Self) -> Result<(), PrintError>, + parenthesized: bool, + ) -> Result<(), PrintError> { + if parenthesized { + self.parenthesized(f)?; + } else { + f(self)?; + } + Ok(()) + } + /// Prints `<...>` around what `f` prints. fn generic_delimiters( &mut self, @@ -1490,12 +1515,137 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? - ty::ConstKind::Expr(_) => p!("{{const expr}}"), + ty::ConstKind::Expr(expr) => self.pretty_print_const_expr(expr, print_ty)?, ty::ConstKind::Error(_) => p!("{{const error}}"), }; Ok(()) } + fn pretty_print_const_expr( + &mut self, + expr: Expr<'tcx>, + print_ty: bool, + ) -> Result<(), PrintError> { + define_scoped_cx!(self); + match expr { + Expr::Binop(op, c1, c2) => { + let precedence = |binop: rustc_middle::mir::BinOp| { + use rustc_ast::util::parser::AssocOp; + AssocOp::from_ast_binop(binop.to_hir_binop().into()).precedence() + }; + let op_precedence = precedence(op); + let formatted_op = op.to_hir_binop().as_str(); + let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) { + ( + ty::ConstKind::Expr(Expr::Binop(lhs_op, _, _)), + ty::ConstKind::Expr(Expr::Binop(rhs_op, _, _)), + ) => (precedence(lhs_op) < op_precedence, precedence(rhs_op) < op_precedence), + (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), ty::ConstKind::Expr(_)) => { + (precedence(lhs_op) < op_precedence, true) + } + (ty::ConstKind::Expr(_), ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { + (true, precedence(rhs_op) < op_precedence) + } + (ty::ConstKind::Expr(_), ty::ConstKind::Expr(_)) => (true, true), + (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), _) => { + (precedence(lhs_op) < op_precedence, false) + } + (_, ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { + (false, precedence(rhs_op) < op_precedence) + } + (ty::ConstKind::Expr(_), _) => (true, false), + (_, ty::ConstKind::Expr(_)) => (false, true), + _ => (false, false), + }; + + self.maybe_parenthesized( + |this| this.pretty_print_const(c1, print_ty), + lhs_parenthesized, + )?; + p!(write(" {formatted_op} ")); + self.maybe_parenthesized( + |this| this.pretty_print_const(c2, print_ty), + rhs_parenthesized, + )?; + } + Expr::UnOp(op, ct) => { + use rustc_middle::mir::UnOp; + let formatted_op = match op { + UnOp::Not => "!", + UnOp::Neg => "-", + }; + let parenthesized = match ct.kind() { + ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op, + ty::ConstKind::Expr(_) => true, + _ => false, + }; + p!(write("{formatted_op}")); + self.maybe_parenthesized( + |this| this.pretty_print_const(ct, print_ty), + parenthesized, + )? + } + Expr::FunctionCall(fn_def, fn_args) => { + use ty::TyKind; + match fn_def.ty().kind() { + TyKind::FnDef(def_id, gen_args) => { + p!(print_value_path(*def_id, gen_args), "("); + if print_ty { + let tcx = self.tcx(); + let sig = tcx.fn_sig(def_id).instantiate(tcx, gen_args).skip_binder(); + + let mut args_with_ty = fn_args.iter().map(|ct| (ct, ct.ty())); + let output_ty = sig.output(); + + if let Some((ct, ty)) = args_with_ty.next() { + self.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + ": ", + )?; + for (ct, ty) in args_with_ty { + p!(", "); + self.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + ": ", + )?; + } + } + p!(write(") -> {output_ty}")); + } else { + p!(comma_sep(fn_args.iter()), ")"); + } + } + _ => bug!("unexpected type of fn def"), + } + } + Expr::Cast(kind, ct, ty) => { + use ty::abstract_const::CastKind; + if kind == CastKind::As || (kind == CastKind::Use && self.should_print_verbose()) { + let parenthesized = match ct.kind() { + ty::ConstKind::Expr(Expr::Cast(_, _, _)) => false, + ty::ConstKind::Expr(_) => true, + _ => false, + }; + self.maybe_parenthesized( + |this| { + this.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + " as ", + ) + }, + parenthesized, + )?; + } else { + self.pretty_print_const(ct, print_ty)? + } + } + } + Ok(()) + } + fn pretty_print_const_scalar( &mut self, scalar: Scalar, diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 7abc3cd2838..c66b9864e46 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -251,6 +251,7 @@ impl<'tcx> Region<'tcx> { } ty::ReError(_) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_ERROR; } } @@ -336,7 +337,9 @@ pub struct EarlyParamRegion { impl std::fmt::Debug for EarlyParamRegion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) + // FIXME(BoxyUwU): self.def_id goes first because of `erased-regions-in-hidden-ty.rs` being impossible to write + // error annotations for otherwise. :). Ideally this would be `self.name, self.index, self.def_id`. + write!(f, "{:?}_{}/#{}", self.def_id, self.name, self.index) } } @@ -381,13 +384,25 @@ pub enum BoundRegionKind { BrEnv, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] #[derive(HashStable)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, } +impl core::fmt::Debug for BoundRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + BoundRegionKind::BrAnon => write!(f, "{:?}", self.var), + BoundRegionKind::BrEnv => write!(f, "{:?}.Env", self.var), + BoundRegionKind::BrNamed(def, symbol) => { + write!(f, "{:?}.Named({:?}, {:?})", self.var, def, symbol) + } + } + } +} + impl BoundRegionKind { pub fn is_named(&self) -> bool { match *self { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 11065b2a382..6e0a9eb86dd 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -483,7 +483,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { self.to_coroutine( tcx, parent_args, - Ty::from_closure_kind(tcx, goal_kind), + Ty::from_coroutine_closure_kind(tcx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) @@ -2456,6 +2456,25 @@ impl<'tcx> Ty<'tcx> { } } + /// Like [`Ty::to_opt_closure_kind`], but it caps the "maximum" closure kind + /// to `FnMut`. This is because although we have three capability states, + /// `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`, we only need to distinguish two coroutine + /// bodies: by-ref and by-value. + /// + /// See the definition of `AsyncFn` and `AsyncFnMut` and the `CallRefFuture` + /// associated type for why we don't distinguish [`ty::ClosureKind::Fn`] and + /// [`ty::ClosureKind::FnMut`] for the purpose of the generated MIR bodies. + /// + /// This method should be used when constructing a `Coroutine` out of a + /// `CoroutineClosure`, when the `Coroutine`'s `kind` field is being populated + /// directly from the `CoroutineClosure`'s `kind`. + pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => tcx.types.i16, + ty::ClosureKind::FnOnce => tcx.types.i32, + } + } + /// Fast path helper for testing if a type is `Sized`. /// /// Returning true means the type is known to be sized. Returning @@ -2484,13 +2503,16 @@ impl<'tcx> Ty<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _args) => def.sized_constraint(tcx).skip_binder().is_empty(), + ty::Adt(def, args) => def + .sized_constraint(tcx) + .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4287b382604..d8541f4b25a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -568,6 +568,11 @@ impl<'a, V> LocalTableInContextMut<'a, V> { self.data.get_mut(&id.local_id) } + pub fn get(&mut self, id: hir::HirId) -> Option<&V> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.get(&id.local_id) + } + pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.entry(id.local_id) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index a6526b06851..e1081423489 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -682,6 +682,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Return the set of types that should be taken into account when checking /// trait bounds on a coroutine's internal state. + // FIXME(compiler-errors): We should remove this when the old solver goes away; + // and all other usages of this function should go through `bound_coroutine_hidden_types` + // instead. pub fn coroutine_hidden_types( self, def_id: DefId, @@ -694,6 +697,33 @@ impl<'tcx> TyCtxt<'tcx> { .map(|decl| ty::EarlyBinder::bind(decl.ty)) } + /// Return the set of types that should be taken into account when checking + /// trait bounds on a coroutine's internal state. This properly replaces + /// `ReErased` with new existential bound lifetimes. + pub fn bound_coroutine_hidden_types( + self, + def_id: DefId, + ) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> { + let coroutine_layout = self.mir_coroutine_witnesses(def_id); + coroutine_layout + .as_ref() + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) + .filter(|decl| !decl.ignore_for_traits) + .map(move |decl| { + let mut vars = vec![]; + let ty = self.fold_regions(decl.ty, |re, debruijn| { + assert_eq!(re, self.lifetimes.re_erased); + let var = ty::BoundVar::from_usize(vars.len()); + vars.push(ty::BoundVariableKind::Region(ty::BrAnon)); + ty::Region::new_bound(self, debruijn, ty::BoundRegion { var, kind: ty::BrAnon }) + }); + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( + ty, + self.mk_bound_variable_kinds(&vars), + )) + }) + } + /// Expands the given impl trait type, stopping if the type is recursive. #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( @@ -998,8 +1028,10 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { Some(expanded_ty) => *expanded_ty, None => { if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) { - for bty in self.tcx.coroutine_hidden_types(def_id) { - let hidden_ty = bty.instantiate(self.tcx, args); + for bty in self.tcx.bound_coroutine_hidden_types(def_id) { + let hidden_ty = self.tcx.instantiate_bound_regions_with_erased( + bty.instantiate(self.tcx, args), + ); self.fold_ty(hidden_ty); } } diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index a67ec991582..43853a10896 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -28,14 +28,17 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>( args: fmt::Arguments<'_>, location: &Location<'_>, ) -> ! { - tls::with_opt(move |tcx| { - let msg = format!("{location}: {args}"); - match (tcx, span) { - (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), - (Some(tcx), None) => tcx.dcx().bug(msg), - (None, _) => panic_any(msg), - } - }) + tls::with_opt( + #[track_caller] + move |tcx| { + let msg = format!("{location}: {args}"); + match (tcx, span) { + (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), + (Some(tcx), None) => tcx.dcx().bug(msg), + (None, _) => panic_any(msg), + } + }, + ) } /// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index f7a3879a7d4..5c17c0b3088 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -106,8 +106,8 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability { representable_ids.insert(def_id); } } - recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite + let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); + Representability::Infinite(guar) } } @@ -268,7 +268,7 @@ pub fn recursive_type_error( tcx: TyCtxt<'_>, mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, representable_ids: &FxHashSet<LocalDefId>, -) { +) -> ErrorGuaranteed { const ITEM_LIMIT: usize = 5; // Rotate the cycle so that the item with the lowest span is first @@ -344,7 +344,7 @@ pub fn recursive_type_error( suggestion, Applicability::HasPlaceholders, ) - .emit(); + .emit() } fn find_item_ty_spans( |
