diff options
Diffstat (limited to 'compiler/rustc_middle')
72 files changed, 1659 insertions, 2116 deletions
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 2c34df6ea61..aebd2181f31 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "rustc_middle" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" either = "1.5.0" -field-offset = "0.3.5" gsgdt = "0.1.2" polonius-engine = "0.13.0" rustc-rayon-core = { version = "0.5.0" } @@ -15,7 +14,6 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links @@ -23,6 +21,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_graphviz = { path = "../rustc_graphviz" } +rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index ded1c580572..0b3c0be1a4e 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -1,6 +1,3 @@ -middle_adjust_for_foreign_abi_error = - target architecture {$arch} does not support `extern {$abi}` ABI - middle_assert_async_resume_after_panic = `async fn` resumed after panicking middle_assert_async_resume_after_return = `async fn` resumed after completion @@ -40,9 +37,6 @@ middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty} middle_bounds_check = index out of bounds: the length is {$len} but the index is {$index} -middle_cannot_be_normalized = - unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized - middle_conflict_types = this expression supplies two conflicting concrete types for the same opaque type @@ -55,9 +49,6 @@ middle_const_eval_non_int = middle_const_not_used_in_type_alias = const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias -middle_cycle = - a cycle occurred during layout computation - middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note -> [true] : {$note} *[other] {""} @@ -81,12 +72,22 @@ middle_erroneous_constant = erroneous constant encountered middle_failed_writing_file = failed to write file {$path}: {$error}" +middle_layout_cycle = + a cycle occurred during layout computation + +middle_layout_normalization_failure = + unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized + middle_layout_references_error = the type has an unknown layout -middle_limit_invalid = - `limit` must be a non-negative integer - .label = {$error_str} +middle_layout_size_overflow = + values of the type `{$ty}` are too big for the target architecture + +middle_layout_too_generic = the type `{$ty}` does not have a fixed layout + +middle_layout_unknown = + the type `{$ty}` has an unknown layout middle_opaque_hidden_type_mismatch = concrete type differs from previous defining opaque type use @@ -105,16 +106,8 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute -middle_too_generic = `{$ty}` does not have a fixed size - middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` -middle_unknown_layout = - the type `{$ty}` has an unknown layout - middle_unsupported_union = we don't support unions yet: '{$ty_name}' -middle_values_too_big = - values of the type `{$ty}` are too big for the target architecture - middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index eaccd8c360e..aef56ea46e9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -31,7 +31,7 @@ macro_rules! arena_types { [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, [] resolver: rustc_data_structures::steal::Steal<( rustc_middle::ty::ResolverAstLowering, - rustc_data_structures::sync::Lrc<rustc_ast::Crate>, + std::sync::Arc<rustc_ast::Crate>, )>, [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, @@ -90,6 +90,7 @@ macro_rules! arena_types { [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>, [] pats: rustc_middle::ty::PatternKind<'tcx>, + [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index b30d3a950c6..be8a3403ba9 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -11,7 +11,7 @@ use crate::ty::Ty; #[derive(Diagnostic)] #[diag(middle_drop_check_overflow, code = E0320)] #[note] -pub struct DropCheckOverflow<'tcx> { +pub(crate) struct DropCheckOverflow<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, @@ -20,14 +20,14 @@ pub struct DropCheckOverflow<'tcx> { #[derive(Diagnostic)] #[diag(middle_failed_writing_file)] -pub struct FailedWritingFile<'a> { +pub(crate) struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, } #[derive(Diagnostic)] #[diag(middle_opaque_hidden_type_mismatch)] -pub struct OpaqueHiddenTypeMismatch<'tcx> { +pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> { pub self_ty: Ty<'tcx>, pub other_ty: Ty<'tcx>, #[primary_span] @@ -37,12 +37,14 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> { pub sub: TypeMismatchReason, } +// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_unsupported_union)] pub struct UnsupportedUnion { pub ty_name: String, } +// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_autodiff_unsafe_inner_const_ref)] pub struct AutodiffUnsafeInnerConstRef { @@ -66,26 +68,16 @@ pub enum TypeMismatchReason { } #[derive(Diagnostic)] -#[diag(middle_limit_invalid)] -pub struct LimitInvalid<'a> { - #[primary_span] - pub span: Span, - #[label] - pub value_span: Span, - pub error_str: &'a str, -} - -#[derive(Diagnostic)] #[diag(middle_recursion_limit_reached)] #[help] -pub struct RecursionLimitReached<'tcx> { +pub(crate) struct RecursionLimitReached<'tcx> { pub ty: Ty<'tcx>, pub suggested_limit: rustc_session::Limit, } #[derive(Diagnostic)] #[diag(middle_const_eval_non_int)] -pub struct ConstEvalNonIntError { +pub(crate) struct ConstEvalNonIntError { #[primary_span] pub span: Span, } @@ -140,19 +132,19 @@ impl fmt::Debug for CustomSubdiagnostic<'_> { #[derive(Diagnostic)] pub enum LayoutError<'tcx> { - #[diag(middle_unknown_layout)] + #[diag(middle_layout_unknown)] Unknown { ty: Ty<'tcx> }, - #[diag(middle_too_generic)] + #[diag(middle_layout_too_generic)] TooGeneric { ty: Ty<'tcx> }, - #[diag(middle_values_too_big)] + #[diag(middle_layout_size_overflow)] Overflow { ty: Ty<'tcx> }, - #[diag(middle_cannot_be_normalized)] + #[diag(middle_layout_normalization_failure)] NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, - #[diag(middle_cycle)] + #[diag(middle_layout_cycle)] Cycle, #[diag(middle_layout_references_error)] @@ -160,26 +152,16 @@ pub enum LayoutError<'tcx> { } #[derive(Diagnostic)] -#[diag(middle_adjust_for_foreign_abi_error)] -pub struct UnsupportedFnAbi { - pub arch: Symbol, - pub abi: &'static str, -} - -#[derive(Diagnostic)] #[diag(middle_erroneous_constant)] -pub struct ErroneousConstant { +pub(crate) struct ErroneousConstant { #[primary_span] pub span: Span, } -/// Used by `rustc_const_eval` -pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; - #[derive(Diagnostic)] #[diag(middle_type_length_limit)] #[help(middle_consider_type_length_limit)] -pub struct TypeLengthLimit { +pub(crate) struct TypeLengthLimit { #[primary_span] pub span: Span, pub shrunk: String, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map.rs index 4df4624971d..fad8c7dcbcb 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -10,11 +10,10 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; use rustc_hir_pretty as pprust_hir; -use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans}; -use crate::hir::ModuleItems; +use crate::hir::{ModuleItems, nested_filter}; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; @@ -29,22 +28,22 @@ pub struct Map<'hir> { } /// An iterator that walks up the ancestor tree of a given `HirId`. -/// Constructed using `tcx.hir().parent_iter(hir_id)`. -struct ParentHirIterator<'hir> { +/// Constructed using `tcx.hir_parent_iter(hir_id)`. +struct ParentHirIterator<'tcx> { current_id: HirId, - map: Map<'hir>, + tcx: TyCtxt<'tcx>, // Cache the current value of `hir_owner_nodes` to avoid repeatedly calling the same query for // the same owner, which will uselessly record many times the same query dependency. - current_owner_nodes: Option<&'hir OwnerNodes<'hir>>, + current_owner_nodes: Option<&'tcx OwnerNodes<'tcx>>, } -impl<'hir> ParentHirIterator<'hir> { - fn new(map: Map<'hir>, current_id: HirId) -> ParentHirIterator<'hir> { - ParentHirIterator { current_id, map, current_owner_nodes: None } +impl<'tcx> ParentHirIterator<'tcx> { + fn new(tcx: TyCtxt<'tcx>, current_id: HirId) -> ParentHirIterator<'tcx> { + ParentHirIterator { current_id, tcx, current_owner_nodes: None } } } -impl<'hir> Iterator for ParentHirIterator<'hir> { +impl<'tcx> Iterator for ParentHirIterator<'tcx> { type Item = HirId; fn next(&mut self) -> Option<Self::Item> { @@ -57,10 +56,10 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { let parent_id = if local_id == ItemLocalId::ZERO { // We go from an owner to its parent, so clear the cache. self.current_owner_nodes = None; - self.map.tcx.hir_owner_parent(owner) + self.tcx.hir_owner_parent(owner) } else { let owner_nodes = - self.current_owner_nodes.get_or_insert_with(|| self.map.tcx.hir_owner_nodes(owner)); + self.current_owner_nodes.get_or_insert_with(|| self.tcx.hir_owner_nodes(owner)); let parent_local_id = owner_nodes.nodes[local_id].parent; // HIR indexing should have checked that. debug_assert_ne!(parent_local_id, local_id); @@ -75,33 +74,33 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { } /// An iterator that walks up the ancestor tree of a given `HirId`. -/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`. -pub struct ParentOwnerIterator<'hir> { +/// Constructed using `tcx.hir_parent_owner_iter(hir_id)`. +pub struct ParentOwnerIterator<'tcx> { current_id: HirId, - map: Map<'hir>, + tcx: TyCtxt<'tcx>, } -impl<'hir> Iterator for ParentOwnerIterator<'hir> { - type Item = (OwnerId, OwnerNode<'hir>); +impl<'tcx> Iterator for ParentOwnerIterator<'tcx> { + type Item = (OwnerId, OwnerNode<'tcx>); fn next(&mut self) -> Option<Self::Item> { if self.current_id.local_id.index() != 0 { self.current_id.local_id = ItemLocalId::ZERO; - let node = self.map.tcx.hir_owner_node(self.current_id.owner); + let node = self.tcx.hir_owner_node(self.current_id.owner); return Some((self.current_id.owner, node)); } if self.current_id == CRATE_HIR_ID { return None; } - let parent_id = self.map.def_key(self.current_id.owner.def_id).parent; + let parent_id = self.tcx.hir_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.tcx.local_def_id_to_hir_id(def_id).owner }); self.current_id = HirId::make_owner(parent_id.def_id); - let node = self.map.tcx.hir_owner_node(self.current_id.owner); + let node = self.tcx.hir_owner_node(self.current_id.owner); Some((self.current_id.owner, node)) } } @@ -147,7 +146,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `HirId` of the parent HIR node of node with this `hir_id`. /// Returns the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`. /// - /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. + /// If calling repeatedly and iterating over parents, prefer [`TyCtxt::hir_parent_iter`]. pub fn parent_hir_id(self, hir_id: HirId) -> HirId { let HirId { owner, local_id } = hir_id; if local_id == ItemLocalId::ZERO { @@ -165,131 +164,124 @@ impl<'tcx> TyCtxt<'tcx> { pub fn parent_hir_node(self, hir_id: HirId) -> Node<'tcx> { self.hir_node(self.parent_hir_id(hir_id)) } -} -impl<'hir> Map<'hir> { #[inline] - pub fn krate(self) -> &'hir Crate<'hir> { - self.tcx.hir_crate(()) - } - - #[inline] - pub fn root_module(self) -> &'hir Mod<'hir> { - match self.tcx.hir_owner_node(CRATE_OWNER_ID) { + pub fn hir_root_module(self) -> &'tcx Mod<'tcx> { + match self.hir_owner_node(CRATE_OWNER_ID) { OwnerNode::Crate(item) => item, _ => bug!(), } } #[inline] - pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir { - self.tcx.hir_crate_items(()).free_items.iter().copied() + pub fn hir_free_items(self) -> impl Iterator<Item = ItemId> { + self.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).free_items() + pub fn hir_module_free_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> { + self.hir_module_items(module).free_items() } - pub fn def_key(self, def_id: LocalDefId) -> DefKey { + pub fn hir_def_key(self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. - self.tcx.definitions_untracked().def_key(def_id) + self.definitions_untracked().def_key(def_id) } - pub fn def_path(self, def_id: LocalDefId) -> DefPath { + pub fn hir_def_path(self, def_id: LocalDefId) -> DefPath { // Accessing the DefPath is ok, since it is part of DefPathHash. - self.tcx.definitions_untracked().def_path(def_id) + self.definitions_untracked().def_path(def_id) } #[inline] - pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash { + pub fn hir_def_path_hash(self, def_id: LocalDefId) -> DefPathHash { // Accessing the DefPathHash is ok, it is incr. comp. stable. - self.tcx.definitions_untracked().def_path_hash(def_id) + self.definitions_untracked().def_path_hash(def_id) } - pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> { - id.as_local().map(|id| self.tcx.hir_node_by_def_id(id)) + pub fn hir_get_if_local(self, id: DefId) -> Option<Node<'tcx>> { + id.as_local().map(|id| self.hir_node_by_def_id(id)) } - pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { - self.tcx.opt_hir_owner_node(id)?.generics() + pub fn hir_get_generics(self, id: LocalDefId) -> Option<&'tcx Generics<'tcx>> { + self.opt_hir_owner_node(id)?.generics() } - pub fn item(self, id: ItemId) -> &'hir Item<'hir> { - self.tcx.hir_owner_node(id.owner_id).expect_item() + pub fn hir_item(self, id: ItemId) -> &'tcx Item<'tcx> { + self.hir_owner_node(id.owner_id).expect_item() } - pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.tcx.hir_owner_node(id.owner_id).expect_trait_item() + pub fn hir_trait_item(self, id: TraitItemId) -> &'tcx TraitItem<'tcx> { + self.hir_owner_node(id.owner_id).expect_trait_item() } - pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.tcx.hir_owner_node(id.owner_id).expect_impl_item() + pub fn hir_impl_item(self, id: ImplItemId) -> &'tcx ImplItem<'tcx> { + self.hir_owner_node(id.owner_id).expect_impl_item() } - pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.tcx.hir_owner_node(id.owner_id).expect_foreign_item() + pub fn hir_foreign_item(self, id: ForeignItemId) -> &'tcx ForeignItem<'tcx> { + self.hir_owner_node(id.owner_id).expect_foreign_item() } - pub fn body(self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id] + pub fn hir_body(self, id: BodyId) -> &'tcx Body<'tcx> { + self.hir_owner_nodes(id.hir_id.owner).bodies[&id.hir_id.local_id] } #[track_caller] - pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { - self.tcx.hir_node(hir_id).fn_decl() + pub fn hir_fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'tcx FnDecl<'tcx>> { + self.hir_node(hir_id).fn_decl() } #[track_caller] - pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> { - self.tcx.hir_node(hir_id).fn_sig() + pub fn hir_fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'tcx FnSig<'tcx>> { + self.hir_node(hir_id).fn_sig() } #[track_caller] - pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { - for (_, node) in self.parent_iter(hir_id) { + pub fn hir_enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { + for (_, node) in self.hir_parent_iter(hir_id) { if let Some((def_id, _)) = node.associated_body() { return def_id; } } - bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id); + bug!("no `hir_enclosing_body_owner` for hir_id `{}`", hir_id); } /// Returns the `HirId` that corresponds to the definition of /// which this is the body of, i.e., a `fn`, `const` or `static` /// 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_eq!(self.tcx.hir_node(parent).body_id().unwrap().hir_id, hir_id, "{hir_id:?}"); + pub fn hir_body_owner(self, BodyId { hir_id }: BodyId) -> HirId { + let parent = self.parent_hir_id(hir_id); + assert_eq!(self.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 { - self.tcx.parent_hir_node(hir_id).associated_body().unwrap().0 + pub fn hir_body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { + self.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<&'hir Body<'hir>> { - Some(self.body(self.tcx.hir_node_by_def_id(id).body_id()?)) + pub fn hir_maybe_body_owned_by(self, id: LocalDefId) -> Option<&'tcx Body<'tcx>> { + Some(self.hir_body(self.hir_node_by_def_id(id).body_id()?)) } /// Given a body owner's id, returns the `BodyId` associated with it. #[track_caller] - pub fn body_owned_by(self, id: LocalDefId) -> &'hir Body<'hir> { - self.maybe_body_owned_by(id).unwrap_or_else(|| { - let hir_id = self.tcx.local_def_id_to_hir_id(id); + pub fn hir_body_owned_by(self, id: LocalDefId) -> &'tcx Body<'tcx> { + self.hir_maybe_body_owned_by(id).unwrap_or_else(|| { + let hir_id = self.local_def_id_to_hir_id(id); span_bug!( - self.span(hir_id), + self.hir().span(hir_id), "body_owned_by: {} has no associated body", - self.node_to_string(hir_id) + self.hir().node_to_string(hir_id) ); }) } - pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir { - self.body(id).params.iter().map(|arg| match arg.pat.kind { + pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> { + self.hir_body(id).params.iter().map(|arg| match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident, _ => Ident::empty(), }) @@ -298,9 +290,9 @@ impl<'hir> Map<'hir> { /// Returns the `BodyOwnerKind` of this `LocalDefId`. /// /// Panics if `LocalDefId` does not have an associated body. - pub fn body_owner_kind(self, def_id: impl Into<DefId>) -> BodyOwnerKind { + pub fn hir_body_owner_kind(self, def_id: impl Into<DefId>) -> BodyOwnerKind { let def_id = def_id.into(); - match self.tcx.def_kind(def_id) { + match self.def_kind(def_id) { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { BodyOwnerKind::Const { inline: false } } @@ -310,6 +302,7 @@ impl<'hir> Map<'hir> { DefKind::Static { safety: _, mutability, nested: false } => { BodyOwnerKind::Static(mutability) } + DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm, dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -321,18 +314,18 @@ impl<'hir> Map<'hir> { /// This should only be used for determining the context of a body, a return /// value of `Some` does not always suggest that the owner of the body is `const`, /// just that it has to be checked as if it were. - pub fn body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstContext> { + pub fn hir_body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstContext> { let def_id = def_id.into(); - let ccx = match self.body_owner_kind(def_id) { + let ccx = match self.hir_body_owner_kind(def_id) { BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), - BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None, - BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => { + BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, + BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { ConstContext::ConstFn } - BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn, - BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, + BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn, + BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; Some(ccx) @@ -342,55 +335,55 @@ impl<'hir> Map<'hir> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. #[inline] - pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { - self.tcx.hir_crate_items(()).body_owners.iter().copied() + pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> { + self.hir_crate_items(()).body_owners.iter().copied() } #[inline] - pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { - par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); + pub fn par_hir_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { + par_for_each_in(&self.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } - pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { - let def_kind = self.tcx.def_kind(def_id); + pub fn hir_ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { + let def_kind = self.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => def_id, DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { - self.tcx.local_parent(def_id) + self.local_parent(def_id) } _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), } } - pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol { - let def_kind = self.tcx.def_kind(def_id); + pub fn hir_ty_param_name(self, def_id: LocalDefId) -> Symbol { + let def_kind = self.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { - self.tcx.item_name(def_id.to_def_id()) + self.item_name(def_id.to_def_id()) } _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), } } - pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] { - self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..]) + pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] { + self.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..]) } /// Gets the attributes on the crate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. - pub fn krate_attrs(self) -> &'hir [Attribute] { - self.attrs(CRATE_HIR_ID) + pub fn hir_krate_attrs(self) -> &'tcx [Attribute] { + self.hir().attrs(CRATE_HIR_ID) } - pub fn rustc_coherence_is_core(self) -> bool { - self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core)) + pub fn hir_rustc_coherence_is_core(self) -> bool { + self.hir_krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core)) } - pub fn get_module(self, module: LocalModDefId) -> (&'hir Mod<'hir>, Span, HirId) { + pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) { let hir_id = HirId::make_owner(module.to_local_def_id()); - match self.tcx.hir_owner_node(hir_id.owner) { + match self.hir_owner_node(hir_id.owner) { OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id), OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id), node => panic!("not a module: {node:?}"), @@ -398,20 +391,20 @@ impl<'hir> Map<'hir> { } /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`. - pub fn walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result + pub fn hir_walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result where - V: Visitor<'hir>, + V: Visitor<'tcx>, { - let (top_mod, span, hir_id) = self.get_module(LocalModDefId::CRATE_DEF_ID); + let (top_mod, span, hir_id) = self.hir_get_module(LocalModDefId::CRATE_DEF_ID); visitor.visit_mod(top_mod, span, hir_id) } /// Walks the attributes in a crate. - pub fn walk_attributes<V>(self, visitor: &mut V) -> V::Result + pub fn hir_walk_attributes<V>(self, visitor: &mut V) -> V::Result where - V: Visitor<'hir>, + V: Visitor<'tcx>, { - let krate = self.krate(); + let krate = self.hir_crate(()); for info in krate.owners.iter() { if let MaybeOwner::Owner(info) = info { for attrs in info.attrs.map.values() { @@ -425,68 +418,80 @@ impl<'hir> Map<'hir> { /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you /// need to process every item-like, and don't care about visiting nested items in a particular /// order then this method is the best choice. If you do care about this nesting, you should - /// use the `tcx.hir().walk_toplevel_module`. + /// use the `tcx.hir_walk_toplevel_module`. /// /// Note that this function will access HIR for all the item-likes in the crate. If you only /// need to access some of them, it is usually better to manually loop on the iterators /// provided by `tcx.hir_crate_items(())`. /// /// Please see the notes in `intravisit.rs` for more information. - pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V) -> V::Result + pub fn hir_visit_all_item_likes_in_crate<V>(self, visitor: &mut V) -> V::Result where - V: Visitor<'hir>, + V: Visitor<'tcx>, { - let krate = self.tcx.hir_crate_items(()); - 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))); + let krate = self.hir_crate_items(()); + walk_list!(visitor, visit_item, krate.free_items().map(|id| self.hir_item(id))); + walk_list!( + visitor, + visit_trait_item, + krate.trait_items().map(|id| self.hir_trait_item(id)) + ); + walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.hir_impl_item(id))); walk_list!( visitor, visit_foreign_item, - krate.foreign_items().map(|id| self.foreign_item(id)) + krate.foreign_items().map(|id| self.hir_foreign_item(id)) ); V::Result::output() } /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to /// item-likes in a single module. - pub fn visit_item_likes_in_module<V>(self, module: LocalModDefId, visitor: &mut V) -> V::Result + pub fn hir_visit_item_likes_in_module<V>( + self, + module: LocalModDefId, + visitor: &mut V, + ) -> V::Result where - V: Visitor<'hir>, + V: Visitor<'tcx>, { - let module = self.tcx.hir_module_items(module); - 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))); + let module = self.hir_module_items(module); + walk_list!(visitor, visit_item, module.free_items().map(|id| self.hir_item(id))); + walk_list!( + visitor, + visit_trait_item, + module.trait_items().map(|id| self.hir_trait_item(id)) + ); + walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.hir_impl_item(id))); walk_list!( visitor, visit_foreign_item, - module.foreign_items().map(|id| self.foreign_item(id)) + module.foreign_items().map(|id| self.hir_foreign_item(id)) ); V::Result::output() } - pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) { - let crate_items = self.tcx.hir_crate_items(()); + pub fn hir_for_each_module(self, mut f: impl FnMut(LocalModDefId)) { + let crate_items = self.hir_crate_items(()); for module in crate_items.submodules.iter() { f(LocalModDefId::new_unchecked(module.def_id)) } } #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) { - let crate_items = self.tcx.hir_crate_items(()); + pub fn par_hir_for_each_module(self, f: impl Fn(LocalModDefId) + DynSend + DynSync) { + let crate_items = self.hir_crate_items(()); par_for_each_in(&crate_items.submodules[..], |module| { f(LocalModDefId::new_unchecked(module.def_id)) }) } #[inline] - pub fn try_par_for_each_module( + pub fn try_par_hir_for_each_module( self, f: impl Fn(LocalModDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, ) -> Result<(), ErrorGuaranteed> { - let crate_items = self.tcx.hir_crate_items(()); + let crate_items = self.hir_crate_items(()); try_par_for_each_in(&crate_items.submodules[..], |module| { f(LocalModDefId::new_unchecked(module.def_id)) }) @@ -495,27 +500,27 @@ impl<'hir> Map<'hir> { /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] - pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir { + pub fn hir_parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> { ParentHirIterator::new(self, current_id) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] - pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> { - self.parent_id_iter(current_id).map(move |id| (id, self.tcx.hir_node(id))) + pub fn hir_parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'tcx>)> { + self.hir_parent_id_iter(current_id).map(move |id| (id, self.hir_node(id))) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] - pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { - ParentOwnerIterator { current_id, map: self } + pub fn hir_parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'tcx> { + ParentOwnerIterator { current_id, tcx: self } } /// Checks if the node is left-hand side of an assignment. - pub fn is_lhs(self, id: HirId) -> bool { - match self.tcx.parent_hir_node(id) { + pub fn hir_is_lhs(self, id: HirId) -> bool { + match self.parent_hir_node(id) { Node::Expr(expr) => match expr.kind { ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id, _ => false, @@ -526,8 +531,8 @@ impl<'hir> Map<'hir> { /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. - pub fn is_inside_const_context(self, hir_id: HirId) -> bool { - self.body_const_context(self.enclosing_body_owner(hir_id)).is_some() + pub fn hir_is_inside_const_context(self, hir_id: HirId) -> bool { + self.hir_body_const_context(self.hir_enclosing_body_owner(hir_id)).is_some() } /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is @@ -552,11 +557,11 @@ impl<'hir> Map<'hir> { /// false /// } /// ``` - pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> { - let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id)); + pub fn hir_get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> { + let enclosing_body_owner = self.local_def_id_to_hir_id(self.hir_enclosing_body_owner(id)); // Return `None` if the `id` expression is not the returned value of the enclosing body - let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable(); + let mut iter = [id].into_iter().chain(self.hir_parent_id_iter(id)).peekable(); while let Some(cur_id) = iter.next() { if enclosing_body_owner == cur_id { break; @@ -564,14 +569,16 @@ impl<'hir> Map<'hir> { // A return statement is always the value returned from the enclosing body regardless of // what the parent expressions are. - if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) { + if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.hir_node(cur_id) { break; } - // If the current expression's value doesnt get used as the parent expressions value then return `None` + // If the current expression's value doesnt get used as the parent expressions value + // then return `None` if let Some(&parent_id) = iter.peek() { - match self.tcx.hir_node(parent_id) { - // The current node is not the tail expression of the block expression parent expr. + match self.hir_node(parent_id) { + // The current node is not the tail expression of the block expression parent + // expr. Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None, Node::Block(Block { expr: Some(e), .. }) if matches!(e.kind, ExprKind::If(_, _, None)) => @@ -579,7 +586,8 @@ impl<'hir> Map<'hir> { return None; } - // The current expression's value does not pass up through these parent expressions + // The current expression's value does not pass up through these parent + // expressions. Node::Block(Block { expr: None, .. }) | Node::Expr(Expr { kind: ExprKind::Loop(..), .. }) | Node::LetStmt(..) => return None, @@ -596,11 +604,11 @@ impl<'hir> Map<'hir> { /// parent item is in this map. The "parent item" is the closest parent node /// in the HIR which is recorded by the map and is an item, either an item /// in a module, trait, or impl. - pub fn get_parent_item(self, hir_id: HirId) -> OwnerId { + pub fn hir_get_parent_item(self, hir_id: HirId) -> OwnerId { if hir_id.local_id != ItemLocalId::ZERO { // If this is a child of a HIR owner, return the owner. hir_id.owner - } else if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() { + } else if let Some((def_id, _node)) = self.hir_parent_owner_iter(hir_id).next() { def_id } else { CRATE_OWNER_ID @@ -612,8 +620,8 @@ impl<'hir> Map<'hir> { /// /// Used by error reporting when there's a type error in an if or match arm caused by the /// expression needing to be unit. - pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> { - for (_, node) in self.parent_iter(hir_id) { + pub fn hir_get_if_cause(self, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { + for (_, node) in self.hir_parent_iter(hir_id) { match node { Node::Item(_) | Node::ForeignItem(_) @@ -630,8 +638,8 @@ impl<'hir> Map<'hir> { } /// Returns the nearest enclosing scope. A scope is roughly an item or block. - pub fn get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> { - for (hir_id, node) in self.parent_iter(hir_id) { + pub fn hir_get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> { + for (hir_id, node) in self.hir_parent_iter(hir_id) { if let Node::Item(Item { kind: ItemKind::Fn { .. } @@ -657,18 +665,20 @@ impl<'hir> Map<'hir> { } /// Returns the defining scope for an opaque type definition. - pub fn get_defining_scope(self, id: HirId) -> HirId { + pub fn hir_get_defining_scope(self, id: HirId) -> HirId { let mut scope = id; loop { - scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); - if scope == CRATE_HIR_ID || !matches!(self.tcx.hir_node(scope), Node::Block(_)) { + scope = self.hir_get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); + if scope == CRATE_HIR_ID || !matches!(self.hir_node(scope), Node::Block(_)) { return scope; } } } +} +impl<'hir> Map<'hir> { pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi { - let parent = self.get_parent_item(hir_id); + let parent = self.tcx.hir_get_parent_item(hir_id); if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = self.tcx.hir_owner_node(parent) { @@ -922,7 +932,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, - Node::ConstBlock(constant) => self.body(constant.body).value.span, + Node::ConstBlock(constant) => self.tcx.hir_body(constant.body).value.span, Node::ConstArg(const_arg) => const_arg.span(), Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, @@ -1015,39 +1025,35 @@ impl<'hir> Map<'hir> { } } -impl<'hir> intravisit::Map<'hir> for Map<'hir> { - fn hir_node(&self, hir_id: HirId) -> Node<'hir> { - self.tcx.hir_node(hir_id) - } - - fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> { - self.tcx.hir_node_by_def_id(def_id) +impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { + fn hir_node(&self, hir_id: HirId) -> Node<'tcx> { + (*self).hir_node(hir_id) } - fn body(&self, id: BodyId) -> &'hir Body<'hir> { - (*self).body(id) + fn hir_body(&self, id: BodyId) -> &'tcx Body<'tcx> { + (*self).hir_body(id) } - fn item(&self, id: ItemId) -> &'hir Item<'hir> { - (*self).item(id) + fn hir_item(&self, id: ItemId) -> &'tcx Item<'tcx> { + (*self).hir_item(id) } - fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - (*self).trait_item(id) + fn hir_trait_item(&self, id: TraitItemId) -> &'tcx TraitItem<'tcx> { + (*self).hir_trait_item(id) } - fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - (*self).impl_item(id) + fn hir_impl_item(&self, id: ImplItemId) -> &'tcx ImplItem<'tcx> { + (*self).hir_impl_item(id) } - fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - (*self).foreign_item(id) + fn hir_foreign_item(&self, id: ForeignItemId) -> &'tcx ForeignItem<'tcx> { + (*self).hir_foreign_item(id) } } impl<'tcx> pprust_hir::PpAnn for TyCtxt<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - pprust_hir::PpAnn::nested(&(&self.hir() as &dyn intravisit::Map<'_>), state, nested) + pprust_hir::PpAnn::nested(&(self as &dyn intravisit::HirTyCtxt<'_>), state, nested) } } @@ -1158,7 +1164,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "mod", ItemKind::ForeignMod { .. } => "foreign mod", - ItemKind::GlobalAsm(..) => "global asm", + ItemKind::GlobalAsm { .. } => "global asm", ItemKind::TyAlias(..) => "ty", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", @@ -1240,7 +1246,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems { let mut collector = ItemCollector::new(tcx, false); - let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id); + let (hir_mod, span, hir_id) = tcx.hir_get_module(module_id); collector.visit_mod(hir_mod, span, hir_id); let ItemCollector { @@ -1273,7 +1279,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { // module item (the former starts at the crate root) but only // the former needs to collect it. ItemCollector does not do this for us. collector.submodules.push(CRATE_OWNER_ID); - tcx.hir().walk_toplevel_module(&mut collector); + tcx.hir_walk_toplevel_module(&mut collector); let ItemCollector { submodules, @@ -1334,8 +1340,8 @@ impl<'tcx> ItemCollector<'tcx> { impl<'hir> Visitor<'hir> for ItemCollector<'hir> { type NestedFilter = nested_filter::All; - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx } fn visit_item(&mut self, item: &'hir Item<'hir>) { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 0d2acf96d08..6071a58367e 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -40,25 +40,25 @@ impl ModuleItems { /// 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> + '_ { + pub fn free_items(&self) -> impl Iterator<Item = ItemId> { self.free_items.iter().copied() } - pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ { + 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> + '_ { + pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> { self.impl_items.iter().copied() } - pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> + '_ { + pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> { self.foreign_items.iter().copied() } - pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ { + pub fn owners(&self) -> impl Iterator<Item = OwnerId> { self.free_items .iter() .map(|id| id.owner_id) @@ -67,15 +67,15 @@ impl ModuleItems { .chain(self.foreign_items.iter().map(|id| id.owner_id)) } - pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> + '_ { + pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> { self.opaques.iter().copied() } - pub fn nested_bodies(&self) -> impl Iterator<Item = LocalDefId> + '_ { + pub fn nested_bodies(&self) -> impl Iterator<Item = LocalDefId> { self.nested_bodies.iter().copied() } - pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ { + pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> { self.owners().map(|id| id.def_id) } @@ -213,7 +213,7 @@ pub fn provide(providers: &mut Providers) { providers.fn_arg_names = |tcx, def_id| { let hir = tcx.hir(); if let Some(body_id) = tcx.hir_node_by_def_id(def_id).body_id() { - tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) + tcx.arena.alloc_from_iter(tcx.hir_body_param_names(body_id)) } else if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(_, TraitFn::Required(idents)), .. diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs index adbe81bb22c..e18c28a8eac 100644 --- a/compiler/rustc_middle/src/hir/nested_filter.rs +++ b/compiler/rustc_middle/src/hir/nested_filter.rs @@ -1,5 +1,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter; +use crate::ty::TyCtxt; + /// Do not visit nested item-like things, but visit nested things /// that are inside of an item-like. /// @@ -12,8 +14,8 @@ use rustc_hir::intravisit::nested_filter::NestedFilter; /// and to have the visitor that visits the contents of each item /// using this setting. pub struct OnlyBodies(()); -impl<'hir> NestedFilter<'hir> for OnlyBodies { - type Map = crate::hir::map::Map<'hir>; +impl<'tcx> NestedFilter<'tcx> for OnlyBodies { + type MaybeTyCtxt = TyCtxt<'tcx>; const INTER: bool = false; const INTRA: bool = true; } @@ -24,8 +26,8 @@ impl<'hir> NestedFilter<'hir> for OnlyBodies { /// process everything within their lexical context. Typically you /// kick off the visit by doing `walk_krate()`. pub struct All(()); -impl<'hir> NestedFilter<'hir> for All { - type Map = crate::hir::map::Map<'hir>; +impl<'tcx> NestedFilter<'tcx> for All { + type MaybeTyCtxt = TyCtxt<'tcx>; const INTER: bool = true; const INTRA: bool = true; } diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 66b701523b7..316ad80eb98 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -97,7 +97,7 @@ impl<'tcx> Place<'tcx> { /// The types are in the reverse order that they are applied. So if /// `x: &*const u32` and the `Place` is `**x`, then the types returned are ///`*const u32` then `&*const u32`. - pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { + pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> { self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| { if ProjectionKind::Deref == proj.kind { Some(self.ty_before_projection(index)) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 276a02b4e0f..c5ce6efcb81 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -98,6 +98,10 @@ declare_hooks! { hook save_dep_graph() -> (); hook query_key_hash_verify_all() -> (); + + /// Ensure the given scalar is valid for the given type. + /// This checks non-recursive runtime validity. + hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool; } #[cold] diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 0f408375e05..3cd148cd442 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -142,10 +142,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> { pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>); -TrivialTypeTraversalImpls! { - crate::infer::canonical::Certainty, -} - #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { map: Lock< diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 7a6d329fd47..93a7227d65e 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -56,7 +56,6 @@ #![feature(ptr_alignment_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(trait_upcasting)] #![feature(trusted_len)] #![feature(try_blocks)] #![feature(try_trait_v2)] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index ab711aca573..88bf17070b9 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -131,7 +131,7 @@ impl ShallowLintLevelMap { let mut owner = start.owner; let mut specs = &self.specs; - for parent in tcx.hir().parent_id_iter(start) { + for parent in tcx.hir_parent_id_iter(start) { if parent.owner != owner { owner = parent.owner; specs = &tcx.shallow_lint_levels_on(owner).specs; diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index b3064d8fe25..b5f3a0e1482 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -83,7 +83,7 @@ macro_rules! TrivialTypeTraversalImpls { _: &mut F) -> F::Result { - <F::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + <F::Result as ::rustc_middle::ty::visit::VisitorResult>::output() } } )+ diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 1784665bcae..311bc60c3cd 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -178,7 +178,7 @@ impl CodegenFnAttrs { || match self.linkage { // These are private, so make sure we don't try to consider // them external. - None | Some(Linkage::Internal | Linkage::Private) => false, + None | Some(Linkage::Internal) => false, Some(_) => true, } } diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index c241c06fce4..5a811321f58 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; +use std::sync::Arc; -use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable}; #[derive(HashStable)] @@ -15,7 +15,7 @@ pub enum DebuggerVisualizerType { #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] pub struct DebuggerVisualizerFile { /// The complete debugger visualizer source. - pub src: Lrc<[u8]>, + pub src: Arc<[u8]>, /// Indicates which visualizer type this targets. pub visualizer_type: DebuggerVisualizerType, /// The file path to the visualizer file. This is used for reporting @@ -26,13 +26,13 @@ pub struct DebuggerVisualizerFile { } impl DebuggerVisualizerFile { - pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self { + pub fn new(src: Arc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self { DebuggerVisualizerFile { src, visualizer_type, path: Some(path) } } pub fn path_erased(&self) -> Self { DebuggerVisualizerFile { - src: Lrc::clone(&self.src), + src: Arc::clone(&self.src), visualizer_type: self.visualizer_type, path: None, } diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs deleted file mode 100644 index 8a367a947d1..00000000000 --- a/compiler/rustc_middle/src/middle/limits.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Registering limits: -//! * recursion_limit, -//! * move_size_limit, and -//! * type_length_limit -//! -//! There are various parts of the compiler that must impose arbitrary limits -//! on how deeply they recurse to prevent stack overflow. Users can override -//! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass -//! just peeks and looks for that attribute. - -use std::num::IntErrorKind; - -use rustc_ast::attr::AttributeExt; -use rustc_session::{Limit, Limits, Session}; -use rustc_span::{Symbol, sym}; - -use crate::error::LimitInvalid; -use crate::query::Providers; - -pub fn provide(providers: &mut Providers) { - providers.limits = |tcx, ()| Limits { - recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess), - move_size_limit: get_limit( - tcx.hir().krate_attrs(), - tcx.sess, - sym::move_size_limit, - tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0), - ), - type_length_limit: get_limit( - tcx.hir().krate_attrs(), - tcx.sess, - sym::type_length_limit, - 2usize.pow(24), - ), - } -} - -pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit { - get_limit(krate_attrs, sess, sym::recursion_limit, 128) -} - -fn get_limit( - krate_attrs: &[impl AttributeExt], - sess: &Session, - name: Symbol, - default: usize, -) -> Limit { - match get_limit_size(krate_attrs, sess, name) { - Some(size) => Limit::new(size), - None => Limit::new(default), - } -} - -pub fn get_limit_size( - krate_attrs: &[impl AttributeExt], - sess: &Session, - name: Symbol, -) -> Option<usize> { - for attr in krate_attrs { - if !attr.has_name(name) { - continue; - } - - if let Some(sym) = attr.value_str() { - match sym.as_str().parse() { - Ok(n) => return Some(n), - Err(e) => { - let error_str = match e.kind() { - IntErrorKind::PosOverflow => "`limit` is too large", - IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::NegOverflow => { - bug!("`limit` should never negatively overflow") - } - IntErrorKind::Zero => bug!("zero is a valid `limit`"), - kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), - }; - sess.dcx().emit_err(LimitInvalid { - span: attr.span(), - value_span: attr.value_span().unwrap(), - error_str, - }); - } - } - } - } - None -} diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 692fe027c49..4587dcaddc4 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -25,17 +25,12 @@ pub mod lib_features { self.stability .to_sorted_stable_ord() .iter() - .map(|(&sym, &(stab, _))| (sym, stab)) + .map(|&(&sym, &(stab, _))| (sym, stab)) .collect() } } } -pub mod limits; pub mod privacy; pub mod region; pub mod resolve_bound_vars; pub mod stability; - -pub fn provide(providers: &mut crate::query::Providers) { - limits::provide(providers); -} diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 77a7da2c74b..2260cad41b9 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -13,7 +13,6 @@ use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer}; @@ -23,6 +22,7 @@ use tracing::debug; pub use self::StabilityLevel::*; use crate::ty::TyCtxt; +use crate::ty::print::with_no_trimmed_paths; #[derive(PartialEq, Clone, Copy, Debug)] pub enum StabilityLevel { @@ -373,7 +373,7 @@ impl<'tcx> TyCtxt<'tcx> { // Deprecated attributes apply in-crate and cross-crate. if let Some(id) = id { if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { - let parent_def_id = self.hir().get_parent_item(id); + let parent_def_id = self.hir_get_parent_item(id); let skip = self .lookup_deprecation_entry(parent_def_id.to_def_id()) .is_some_and(|parent_depr| parent_depr.same_origin(&depr_entry)); diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 3eb563d7d6e..171542d1279 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -20,7 +20,22 @@ pub struct BasicBlocks<'tcx> { // Typically 95%+ of basic blocks have 4 or fewer predecessors. type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>; -type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>; +/// Each `(target, switch)` entry in the map contains a list of switch values +/// that lead to a `target` block from a `switch` block. +/// +/// Note: this type is currently never instantiated, because it's only used for +/// `BasicBlocks::switch_sources`, which is only called by backwards analyses +/// that do `SwitchInt` handling, and we don't have any of those, not even in +/// tests. See #95120 and #94576. +type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[SwitchTargetValue; 1]>>; + +#[derive(Debug, Clone, Copy)] +pub enum SwitchTargetValue { + // A normal switch value. + Normal(u128), + // The final "otherwise" fallback value. + Otherwise, +} #[derive(Clone, Default, Debug)] struct Cache { @@ -64,14 +79,14 @@ impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { self.cache.reverse_postorder.get_or_init(|| { - let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, ()).collect(); + let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, None).collect(); rpo.reverse(); rpo }) } - /// `switch_sources()[&(target, switch)]` returns a list of switch - /// values that lead to a `target` block from a `switch` block. + /// Returns info about switch values that lead from one block to another + /// block. See `SwitchSources`. #[inline] pub fn switch_sources(&self) -> &SwitchSources { self.cache.switch_sources.get_or_init(|| { @@ -82,9 +97,15 @@ impl<'tcx> BasicBlocks<'tcx> { }) = &data.terminator { for (value, target) in targets.iter() { - switch_sources.entry((target, bb)).or_default().push(Some(value)); + switch_sources + .entry((target, bb)) + .or_default() + .push(SwitchTargetValue::Normal(value)); } - switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); + switch_sources + .entry((targets.otherwise(), bb)) + .or_default() + .push(SwitchTargetValue::Otherwise); } } switch_sources @@ -163,6 +184,7 @@ impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { } } +// Done here instead of in `structural_impls.rs` because `Cache` is private, as is `basic_blocks`. TrivialTypeTraversalImpls! { Cache } impl<S: Encoder> Encodable<S> for Cache { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 46534697e1d..8c6b11a681e 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -2,8 +2,8 @@ use std::fmt::{self, Debug, Formatter}; -use rustc_index::IndexVec; -use rustc_index::bit_set::DenseBitSet; +use rustc_data_structures::fx::FxIndexMap; +use rustc_index::{Idx, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Span; @@ -103,23 +103,12 @@ pub enum CoverageKind { /// 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. + /// Marks its enclosing basic block with the ID of the coverage graph node + /// that it was part of during the `InstrumentCoverage` MIR pass. /// - /// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR. - /// - /// If this statement does not survive MIR optimizations, any mappings that - /// refer to this counter can have those references simplified to zero. - CounterIncrement { id: CounterId }, - - /// Marks the point in MIR control-flow represented by a coverage expression. - /// - /// If this statement does not survive MIR optimizations, any mappings that - /// refer to this expression can have those references simplified to zero. - /// - /// (This is only inserted for expression IDs that are directly used by - /// mappings. Intermediate expressions with no direct mappings are - /// retained/zeroed based on whether they are transitively used.) - ExpressionUsed { id: ExpressionId }, + /// During codegen, this might be lowered to `llvm.instrprof.increment` or + /// to a no-op, depending on the outcome of counter-creation. + VirtualCounter { bcb: BasicCoverageBlock }, /// Marks the point in MIR control flow represented by a evaluated condition. /// @@ -138,8 +127,7 @@ impl Debug for CoverageKind { match self { SpanMarker => write!(fmt, "SpanMarker"), BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), - CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), - ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), + VirtualCounter { bcb } => write!(fmt, "VirtualCounter({bcb:?})"), CondBitmapUpdate { index, decision_depth } => { write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth) } @@ -179,34 +167,19 @@ pub struct Expression { #[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub enum MappingKind { /// Associates a normal region of code with a counter/expression/zero. - Code(CovTerm), + Code { bcb: BasicCoverageBlock }, /// Associates a branch region with separate counters for true and false. - Branch { true_term: CovTerm, false_term: CovTerm }, + Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock }, /// Associates a branch region with separate counters for true and false. - MCDCBranch { true_term: CovTerm, false_term: CovTerm, mcdc_params: ConditionInfo }, + MCDCBranch { + true_bcb: BasicCoverageBlock, + false_bcb: BasicCoverageBlock, + mcdc_params: ConditionInfo, + }, /// Associates a decision region with a bitmap and number of conditions. MCDCDecision(DecisionInfo), } -impl MappingKind { - /// Returns a copy of this mapping kind, in which all coverage terms have - /// been replaced with ones returned by the given function. - pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self { - match *self { - Self::Code(term) => Self::Code(map_fn(term)), - Self::Branch { true_term, false_term } => { - Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) } - } - Self::MCDCBranch { true_term, false_term, mcdc_params } => Self::MCDCBranch { - true_term: map_fn(true_term), - false_term: map_fn(false_term), - mcdc_params, - }, - Self::MCDCDecision(param) => Self::MCDCDecision(param), - } - } -} - #[derive(Clone, Debug)] #[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub struct Mapping { @@ -222,10 +195,15 @@ pub struct Mapping { pub struct FunctionCoverageInfo { pub function_source_hash: u64, pub body_span: Span, - pub num_counters: usize, - pub mcdc_bitmap_bits: usize, - pub expressions: IndexVec<ExpressionId, Expression>, + + /// Used in conjunction with `priority_list` to create physical counters + /// and counter expressions, after MIR optimizations. + pub node_flow_data: NodeFlowData<BasicCoverageBlock>, + pub priority_list: Vec<BasicCoverageBlock>, + pub mappings: Vec<Mapping>, + + pub mcdc_bitmap_bits: usize, /// The depth of the deepest decision is used to know how many /// temp condbitmaps should be allocated for the function. pub mcdc_num_condition_bitmaps: usize, @@ -292,40 +270,55 @@ pub struct MCDCDecisionSpan { pub num_conditions: usize, } -/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass -/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations -/// have had a chance to potentially remove some of them. +/// Contains information needed during codegen, obtained by inspecting the +/// function's MIR after MIR optimizations. /// -/// Used by the `coverage_ids_info` query. +/// Returned by the `coverage_ids_info` query. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)] pub struct CoverageIdsInfo { - pub counters_seen: DenseBitSet<CounterId>, - pub zero_expressions: DenseBitSet<ExpressionId>, + pub num_counters: u32, + pub phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>, + pub term_for_bcb: IndexVec<BasicCoverageBlock, Option<CovTerm>>, + pub expressions: IndexVec<ExpressionId, Expression>, } -impl CoverageIdsInfo { - /// Coverage codegen needs to know how many coverage counters are ever - /// incremented within a function, so that it can set the `num-counters` - /// argument of the `llvm.instrprof.increment` intrinsic. +rustc_index::newtype_index! { + /// During the `InstrumentCoverage` MIR pass, a BCB is a node in the + /// "coverage graph", which is a refinement of the MIR control-flow graph + /// that merges or omits some blocks that aren't relevant to coverage. /// - /// This may be less than the highest counter ID emitted by the - /// InstrumentCoverage MIR pass, if the highest-numbered counter increments - /// were removed by MIR optimizations. - pub fn num_counters_after_mir_opts(&self) -> u32 { - // FIXME(Zalathar): Currently this treats an unused counter as "used" - // if its ID is less than that of the highest counter that really is - // used. Fixing this would require adding a renumbering step somewhere. - self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1) + /// After that pass is complete, the coverage graph no longer exists, so a + /// BCB is effectively an opaque ID. + #[derive(HashStable)] + #[encodable] + #[orderable] + #[debug_format = "bcb{}"] + pub struct BasicCoverageBlock { + const START_BCB = 0; } +} - /// Returns `true` if the given term is known to have a value of zero, taking - /// into account knowledge of which counters are unused and which expressions - /// are always zero. - pub fn is_zero_term(&self, term: CovTerm) -> bool { - match term { - CovTerm::Zero => true, - CovTerm::Counter(id) => !self.counters_seen.contains(id), - CovTerm::Expression(id) => self.zero_expressions.contains(id), - } - } +/// Data representing a view of some underlying graph, in which each node's +/// successors have been merged into a single "supernode". +/// +/// The resulting supernodes have no obvious meaning on their own. +/// However, merging successor nodes means that a node's out-edges can all +/// be combined into a single out-edge, whose flow is the same as the flow +/// (execution count) of its corresponding node in the original graph. +/// +/// With all node flows now in the original graph now represented as edge flows +/// in the merged graph, it becomes possible to analyze the original node flows +/// using techniques for analyzing edge flows. +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable)] +pub struct NodeFlowData<Node: Idx> { + /// Maps each node to the supernode that contains it, indicated by some + /// arbitrary "root" node that is part of that supernode. + pub supernodes: IndexVec<Node, Node>, + /// For each node, stores the single supernode that all of its successors + /// have been merged into. + /// + /// (Note that each node in a supernode can potentially have a _different_ + /// successor supernode from its peers.) + pub succ_supernodes: IndexVec<Node, Node>, } diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index a52ec58a1ee..3fd73712b09 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -1,5 +1,6 @@ use gsgdt::{Edge, Graph, Node, NodeStyle}; -use rustc_middle::mir::*; + +use crate::mir::*; /// Convert an MIR function into a gsgdt Graph pub(crate) fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph { diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index e1c3d8156d8..bce7beb521d 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -2,7 +2,8 @@ use std::io::{self, Write}; use rustc_data_structures::graph::{self, iterate}; use rustc_graphviz as dot; -use rustc_middle::ty::TyCtxt; + +use crate::ty::TyCtxt; pub struct GraphvizWriter< 'a, diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index 7bb41193d5c..a64b122fbc9 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -2,10 +2,10 @@ use std::io::{self, Write}; use gsgdt::GraphvizSettings; use rustc_graphviz as dot; -use rustc_middle::mir::*; use super::generic_graph::mir_fn_to_generic_graph; use super::pretty::dump_mir_def_ids; +use crate::mir::*; /// Write a graphviz DOT graph of a list of MIRs. pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()> diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2e4d258ffff..95bc9b71fe0 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -317,10 +317,13 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { Ok(Allocation { bytes, provenance: ProvenanceMap::new(), - init_mask: InitMask::new(size, match init { - AllocInit::Uninit => false, - AllocInit::Zero => true, - }), + init_mask: InitMask::new( + size, + match init { + AllocInit::Uninit => false, + AllocInit::Zero => true, + }, + ), align, mutability: Mutability::Mut, extra: (), 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 78196b05361..2f13f963578 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -121,7 +121,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { } /// Yields all the provenances stored in this map. - pub fn provenances(&self) -> impl Iterator<Item = Prov> + '_ { + pub fn provenances(&self) -> impl Iterator<Item = Prov> { let bytes = self.bytes.iter().flat_map(|b| b.values()); self.ptrs.values().chain(bytes).copied() } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 8c085fa310a..743812e3a20 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -5,7 +5,6 @@ use std::{convert, fmt, mem, ops}; use either::Either; use rustc_abi::{Align, Size, VariantIdx, WrappingRange}; -use rustc_ast_ir::Mutability; use rustc_data_structures::sync::Lock; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; @@ -16,7 +15,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::ty::{self, Ty, TyCtxt, ValTree, layout, tls}; +use crate::ty::{self, Mutability, Ty, TyCtxt, ValTree, layout, tls}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum ErrorHandled { @@ -95,8 +94,6 @@ impl From<ReportedErrorInfo> for ErrorGuaranteed { } } -TrivialTypeTraversalImpls! { ErrorHandled } - pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; @@ -218,10 +215,6 @@ pub enum InvalidProgramInfo<'tcx> { AlreadyReported(ReportedErrorInfo), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), - /// An error occurred during FnAbi computation: the passed --target lacks FFI support - /// (which unfortunately typeck does not reject). - /// Not using `FnAbiError` as that contains a nested `LayoutError`. - FnAbiAdjustForForeignAbi(rustc_target::callconv::AdjustForForeignAbiError), } /// Details of why a pointer had to be in-bounds. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 45c862e0d34..c48cfffa05c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -20,7 +20,6 @@ use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; use tracing::{debug, trace}; // Also make the error macros available from this module. @@ -46,6 +45,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; +use crate::ty::print::with_no_trimmed_paths; use crate::ty::{self, Instance, Ty, TyCtxt}; /// Uniquely identifies one of the following: diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cfb78e5dddf..cf90df1b198 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -4,15 +4,14 @@ use std::borrow::Cow; use std::fmt::{self, Debug, Formatter}; +use std::iter; use std::ops::{Index, IndexMut}; -use std::{iter, mem}; -pub use basic_blocks::BasicBlocks; +pub use basic_blocks::{BasicBlocks, SwitchTargetValue}; use either::Either; use polonius_engine::Atom; use rustc_abi::{FieldIdx, VariantIdx}; pub use rustc_ast::Mutability; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; @@ -30,11 +29,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::{debug, trace}; pub use self::query::*; -use self::visit::TyContext; use crate::mir::interpret::{AllocRange, Scalar}; -use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{ @@ -50,16 +46,13 @@ pub mod generic_graphviz; pub mod graphviz; pub mod interpret; pub mod mono; -pub mod patch; pub mod pretty; mod query; mod statement; mod syntax; -pub mod tcx; mod terminator; pub mod traversal; -mod type_foldable; pub mod visit; pub use consts::*; @@ -103,24 +96,17 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { } impl MirPhase { - /// Gets the index of the current MirPhase within the set of all `MirPhase`s. - /// - /// FIXME(JakobDegen): Return a `(usize, usize)` instead. - pub fn phase_index(&self) -> usize { - const BUILT_PHASE_COUNT: usize = 1; - const ANALYSIS_PHASE_COUNT: usize = 2; - match self { - MirPhase::Built => 1, - MirPhase::Analysis(analysis_phase) => { - 1 + BUILT_PHASE_COUNT + (*analysis_phase as usize) - } - MirPhase::Runtime(runtime_phase) => { - 1 + BUILT_PHASE_COUNT + ANALYSIS_PHASE_COUNT + (*runtime_phase as usize) - } + /// Gets the (dialect, phase) index of the current `MirPhase`. Both numbers + /// are 1-indexed. + pub fn index(&self) -> (usize, usize) { + match *self { + MirPhase::Built => (1, 1), + MirPhase::Analysis(analysis_phase) => (2, 1 + analysis_phase as usize), + MirPhase::Runtime(runtime_phase) => (3, 1 + runtime_phase as usize), } } - /// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason. + /// Parses a `MirPhase` from a pair of strings. Panics if this isn't possible for any reason. pub fn parse(dialect: String, phase: Option<String>) -> Self { match &*dialect.to_ascii_lowercase() { "built" => { @@ -485,7 +471,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable locals. #[inline] - pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a { + pub fn mut_vars_iter(&self) -> impl Iterator<Item = Local> { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -495,9 +481,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable arguments and locals. #[inline] - pub fn mut_vars_and_args_iter<'a>( - &'a self, - ) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a { + pub fn mut_vars_and_args_iter(&self) -> impl Iterator<Item = Local> { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -527,7 +511,7 @@ impl<'tcx> Body<'tcx> { } #[inline] - pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a { + pub fn drain_vars_and_temps(&mut self) -> impl Iterator<Item = LocalDecl<'tcx>> { self.local_decls.drain(self.arg_count + 1..) } @@ -544,17 +528,6 @@ 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> { @@ -796,7 +769,7 @@ impl<T> ClearCrossCrate<T> { } } - pub fn assert_crate_local(self) -> T { + pub fn unwrap_crate_local(self) -> T { match self { ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), ClearCrossCrate::Set(v) => v, @@ -927,8 +900,6 @@ pub enum BindingForm<'tcx> { RefForGuard, } -TrivialTypeTraversalImpls! { BindingForm<'tcx> } - mod binding_form_impl { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_query_system::ich::StableHashingContext; @@ -955,7 +926,7 @@ mod binding_form_impl { /// involved in borrow_check errors, e.g., explanations of where the /// temporaries come from, when their destructors are run, and/or how /// one might revise the code to satisfy the borrow checker's rules. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub struct BlockTailInfo { /// If `true`, then the value resulting from evaluating this tail /// expression is ignored by the block's expression context. @@ -979,7 +950,6 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return place are always mutable. pub mutability: Mutability, - // FIXME(matthewjasper) Don't store in this in `Body` pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>, /// The type of this local. @@ -989,7 +959,6 @@ pub struct LocalDecl<'tcx> { /// e.g., via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. - // FIXME(matthewjasper) Don't store in this in `Body` pub user_ty: Option<Box<UserTypeProjections>>, /// The *syntactic* (i.e., not visibility) source scope the local is defined @@ -1097,7 +1066,6 @@ pub enum LocalInfo<'tcx> { 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 evaluating `if` predicate, possibly for pattern matching for `let`s, /// and subject to Edition 2024 temporary lifetime rules @@ -1112,7 +1080,7 @@ pub enum LocalInfo<'tcx> { impl<'tcx> LocalDecl<'tcx> { pub fn local_info(&self) -> &LocalInfo<'tcx> { - self.local_info.as_ref().assert_crate_local() + self.local_info.as_ref().unwrap_crate_local() } /// Returns `true` only if local is a binding that can itself be @@ -1370,70 +1338,6 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } - pub fn retain_statements<F>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'_>) -> bool, - { - for s in &mut self.statements { - if !f(s) { - s.make_nop(); - } - } - } - - pub fn expand_statements<F, I>(&mut self, mut f: F) - where - F: FnMut(&mut Statement<'tcx>) -> Option<I>, - I: iter::TrustedLen<Item = Statement<'tcx>>, - { - // Gather all the iterators we'll need to splice in, and their positions. - let mut splices: Vec<(usize, I)> = vec![]; - let mut extra_stmts = 0; - for (i, s) in self.statements.iter_mut().enumerate() { - if let Some(mut new_stmts) = f(s) { - if let Some(first) = new_stmts.next() { - // We can already store the first new statement. - *s = first; - - // Save the other statements for optimized splicing. - let remaining = new_stmts.size_hint().0; - if remaining > 0 { - splices.push((i + 1 + extra_stmts, new_stmts)); - extra_stmts += remaining; - } - } else { - s.make_nop(); - } - } - } - - // Splice in the new statements, from the end of the block. - // FIXME(eddyb) This could be more efficient with a "gap buffer" - // where a range of elements ("gap") is left uninitialized, with - // splicing adding new elements to the end of that gap and moving - // existing elements from before the gap to the end of the gap. - // For now, this is safe code, emulating a gap but initializing it. - let mut gap = self.statements.len()..self.statements.len() + extra_stmts; - self.statements.resize(gap.end, Statement { - source_info: SourceInfo::outermost(DUMMY_SP), - kind: StatementKind::Nop, - }); - for (splice_start, new_stmts) in splices.into_iter().rev() { - let splice_end = splice_start + new_stmts.size_hint().0; - while gap.end > splice_end { - gap.start -= 1; - gap.end -= 1; - self.statements.swap(gap.start, gap.end); - } - self.statements.splice(splice_start..splice_end, new_stmts); - gap.end = splice_start; - } - } - - pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { &self.statements[index] } else { &self.terminator } - } - /// Does the block have no statements and an unreachable terminator? #[inline] pub fn is_empty_unreachable(&self) -> bool { @@ -1565,7 +1469,7 @@ pub struct SourceScopeLocalData { /// &'static str`. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct UserTypeProjections { - pub contents: Vec<(UserTypeProjection, Span)>, + pub contents: Vec<UserTypeProjection>, } impl<'tcx> UserTypeProjections { @@ -1577,26 +1481,17 @@ impl<'tcx> UserTypeProjections { self.contents.is_empty() } - pub fn projections_and_spans( - &self, - ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { - self.contents.iter() - } - pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator { - self.contents.iter().map(|&(ref user_type, _span)| user_type) + self.contents.iter() } - pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { - self.contents.push((user_ty.clone(), span)); + pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self { + self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] }); self } - fn map_projections( - mut self, - mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, - ) -> Self { - self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect(); + fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self { + self.contents = self.contents.into_iter().map(f).collect(); self } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 75931956310..58d5c94d033 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -6,8 +6,9 @@ use rustc_attr_parsing::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_data_structures::unord::UnordMap; +use rustc_hashes::Hash128; use rustc_hir::ItemId; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; use rustc_index::Idx; @@ -242,7 +243,7 @@ impl<'tcx> MonoItem<'tcx> { /// Returns the item's `CrateNum` pub fn krate(&self) -> CrateNum { match self { - MonoItem::Fn(ref instance) => instance.def_id().krate, + MonoItem::Fn(instance) => instance.def_id().krate, MonoItem::Static(def_id) => def_id.krate, MonoItem::GlobalAsm(..) => LOCAL_CRATE, } @@ -327,9 +328,7 @@ pub enum Linkage { LinkOnceODR, WeakAny, WeakODR, - Appending, Internal, - Private, ExternalWeak, Common, } diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs deleted file mode 100644 index 18c48d99b81..00000000000 --- a/compiler/rustc_middle/src/mir/patch.rs +++ /dev/null @@ -1,257 +0,0 @@ -use rustc_middle::mir::*; -use tracing::debug; - -/// This struct represents a patch to MIR, which can add -/// new statements and basic blocks and patch over block -/// terminators. -pub struct MirPatch<'tcx> { - patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>, - new_blocks: Vec<BasicBlockData<'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>, - // Only for unreachable not in cleanup path. - unreachable_no_cleanup_block: Option<BasicBlock>, - // Cached block for UnwindTerminate (with reason) - terminate_block: Option<(BasicBlock, UnwindTerminateReason)>, - body_span: Span, - next_local: usize, -} - -impl<'tcx> MirPatch<'tcx> { - pub fn new(body: &Body<'tcx>) -> Self { - let mut result = MirPatch { - patch_map: IndexVec::from_elem(None, &body.basic_blocks), - new_blocks: vec![], - new_statements: vec![], - new_locals: vec![], - next_local: body.local_decls.len(), - resume_block: None, - unreachable_cleanup_block: None, - unreachable_no_cleanup_block: None, - terminate_block: None, - body_span: body.span, - }; - - for (bb, block) in body.basic_blocks.iter_enumerated() { - // Check if we already have a resume block - if matches!(block.terminator().kind, TerminatorKind::UnwindResume) - && block.statements.is_empty() - { - result.resume_block = Some(bb); - continue; - } - - // Check if we already have an unreachable block - if matches!(block.terminator().kind, TerminatorKind::Unreachable) - && block.statements.is_empty() - { - if block.is_cleanup { - result.unreachable_cleanup_block = Some(bb); - } else { - result.unreachable_no_cleanup_block = Some(bb); - } - continue; - } - - // Check if we already have a terminate block - if let TerminatorKind::UnwindTerminate(reason) = block.terminator().kind - && block.statements.is_empty() - { - result.terminate_block = Some((bb, reason)); - continue; - } - } - - result - } - - pub fn resume_block(&mut self) -> BasicBlock { - if let Some(bb) = self.resume_block { - return bb; - } - - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: SourceInfo::outermost(self.body_span), - kind: TerminatorKind::UnwindResume, - }), - is_cleanup: true, - }); - self.resume_block = Some(bb); - 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 unreachable_no_cleanup_block(&mut self) -> BasicBlock { - if let Some(bb) = self.unreachable_no_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: false, - }); - self.unreachable_no_cleanup_block = Some(bb); - bb - } - - pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block - && reason == cached_reason - { - return cached_bb; - } - - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { - source_info: SourceInfo::outermost(self.body_span), - kind: TerminatorKind::UnwindTerminate(reason), - }), - is_cleanup: true, - }); - self.terminate_block = Some((bb, reason)); - bb - } - - pub fn is_patched(&self, bb: BasicBlock) -> bool { - self.patch_map[bb].is_some() - } - - pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(body.basic_blocks.len()) { - Some(index) => self.new_blocks[index].statements.len(), - None => body[bb].statements.len(), - }; - Location { block: bb, statement_index: offset } - } - - pub fn new_local_with_info( - &mut self, - ty: Ty<'tcx>, - span: Span, - local_info: LocalInfo<'tcx>, - ) -> Local { - let index = self.next_local; - self.next_local += 1; - let mut new_decl = LocalDecl::new(ty, span); - **new_decl.local_info.as_mut().assert_crate_local() = local_info; - self.new_locals.push(new_decl); - 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) - } - - pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = BasicBlock::new(self.patch_map.len()); - debug!("MirPatch: new_block: {:?}: {:?}", block, data); - self.new_blocks.push(data); - self.patch_map.push(None); - block - } - - pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { - assert!(self.patch_map[block].is_none()); - debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); - self.patch_map[block] = Some(new); - } - - pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) { - debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt); - self.new_statements.push((loc, stmt)); - } - - pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { - self.add_statement(loc, StatementKind::Assign(Box::new((place, rv)))); - } - - pub fn apply(self, body: &mut Body<'tcx>) { - debug!( - "MirPatch: {:?} new temps, starting from index {}: {:?}", - self.new_locals.len(), - body.local_decls.len(), - self.new_locals - ); - debug!( - "MirPatch: {} new blocks, starting from index {}", - self.new_blocks.len(), - body.basic_blocks.len() - ); - let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() { - body.basic_blocks.as_mut_preserves_cfg() - } else { - body.basic_blocks.as_mut() - }; - bbs.extend(self.new_blocks); - body.local_decls.extend(self.new_locals); - for (src, patch) in self.patch_map.into_iter_enumerated() { - if let Some(patch) = patch { - debug!("MirPatch: patching block {:?}", src); - bbs[src].terminator_mut().kind = patch; - } - } - - let mut new_statements = self.new_statements; - new_statements.sort_by_key(|s| s.0); - - let mut delta = 0; - let mut last_bb = START_BLOCK; - for (mut loc, stmt) in new_statements { - if loc.block != last_bb { - delta = 0; - last_bb = loc.block; - } - debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); - loc.statement_index += delta; - let source_info = Self::source_info_for_index(&body[loc.block], loc); - body[loc.block] - .statements - .insert(loc.statement_index, Statement { source_info, kind: stmt }); - delta += 1; - } - } - - pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { - match data.statements.get(loc.statement_index) { - Some(stmt) => stmt.source_info, - None => data.terminator().source_info, - } - } - - pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(body.basic_blocks.len()) { - Some(new) => &self.new_blocks[new], - None => &body[loc.block], - }; - Self::source_info_for_index(data, loc) - } -} diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 3007b787496..875f5282bf2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -5,17 +5,16 @@ use std::{fs, io}; use rustc_abi::Size; use rustc_ast::InlineAsmTemplatePiece; -use rustc_middle::mir::interpret::{ - AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, - read_target_uint, -}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::*; use tracing::trace; use ty::print::PrettyPrinter; use super::graphviz::write_mir_fn_graphviz; -use crate::mir::interpret::ConstAllocation; +use crate::mir::interpret::{ + AllocBytes, AllocId, Allocation, ConstAllocation, GlobalAlloc, Pointer, Provenance, + alloc_range, read_target_uint, +}; +use crate::mir::visit::Visitor; +use crate::mir::*; const INDENT: &str = " "; /// Alignment for lining up comments following MIR statements @@ -23,7 +22,7 @@ pub(crate) const ALIGN: usize = 40; /// An indication of where we are in the control flow graph. Used for printing /// extra information in `dump_mir` -#[derive(Clone)] +#[derive(Clone, Copy)] pub enum PassWhere { /// We have not started dumping the control flow graph, but we are about to. BeforeCFG, @@ -232,7 +231,8 @@ fn dump_path<'tcx>( let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() } else if pass_num { - format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) + let (dialect_index, phase_index) = body.phase.index(); + format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) } else { ".-------".to_string() }; @@ -619,13 +619,9 @@ fn write_function_coverage_info( function_coverage_info: &coverage::FunctionCoverageInfo, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } = - function_coverage_info; + let coverage::FunctionCoverageInfo { body_span, mappings, .. } = function_coverage_info; writeln!(w, "{INDENT}coverage body span: {body_span:?}")?; - for (id, expression) in expressions.iter_enumerated() { - writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?; - } for coverage::Mapping { kind, span } in mappings { writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?; } @@ -974,7 +970,7 @@ impl<'tcx> TerminatorKind<'tcx> { } FalseEdge { .. } => write!(fmt, "falseEdge"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), - InlineAsm { template, ref operands, options, .. } => { + InlineAsm { template, operands, options, .. } => { write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?; for op in operands { write!(fmt, ", ")?; @@ -1527,7 +1523,7 @@ pub fn write_allocations<'tcx>( ) -> io::Result<()> { fn alloc_ids_from_alloc( alloc: ConstAllocation<'_>, - ) -> impl DoubleEndedIterator<Item = AllocId> + '_ { + ) -> impl DoubleEndedIterator<Item = AllocId> { alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id()) } @@ -1593,7 +1589,7 @@ pub fn write_allocations<'tcx>( Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { write!(w, " (static: {}", tcx.def_path_str(did))?; if body.phase <= MirPhase::Runtime(RuntimePhase::PostCleanup) - && tcx.hir().body_const_context(body.source.def_id()).is_some() + && tcx.hir_body_const_context(body.source.def_id()).is_some() { // Statics may be cyclic and evaluating them too early // in the MIR pipeline may cause cycle errors even though diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d345c99f902..595a5e548b0 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,7 +1,10 @@ //! Functionality for statements, operands, places, and things that appear in them. +use tracing::{debug, instrument}; + use super::interpret::GlobalAlloc; use super::*; +use crate::ty::CoroutineArgsExt; /////////////////////////////////////////////////////////////////////////// // Statements @@ -19,15 +22,6 @@ impl Statement<'_> { pub fn make_nop(&mut self) { self.kind = StatementKind::Nop } - - /// Changes a statement to a nop and returns the original statement. - #[must_use = "If you don't need the statement, use `make_nop` instead"] - pub fn replace_nop(&mut self) -> Self { - Statement { - source_info: self.source_info, - kind: mem::replace(&mut self.kind, StatementKind::Nop), - } - } } impl<'tcx> StatementKind<'tcx> { @@ -49,6 +43,162 @@ impl<'tcx> StatementKind<'tcx> { /////////////////////////////////////////////////////////////////////////// // Places +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] +pub struct PlaceTy<'tcx> { + pub ty: Ty<'tcx>, + /// Downcast to a particular variant of an enum or a coroutine, if included. + pub variant_index: Option<VariantIdx>, +} + +// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. +#[cfg(target_pointer_width = "64")] +rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16); + +impl<'tcx> PlaceTy<'tcx> { + #[inline] + pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { + PlaceTy { ty, variant_index: None } + } + + /// `place_ty.field_ty(tcx, f)` computes the type of a given field. + /// + /// Most clients of `PlaceTy` can instead just extract the relevant type + /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>` + /// do not carry a `Ty` for `T`. + /// + /// Note that the resulting type has not been normalized. + #[instrument(level = "debug", skip(tcx), ret)] + pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { + if let Some(variant_index) = self.variant_index { + match *self.ty.kind() { + ty::Adt(adt_def, args) if adt_def.is_enum() => { + adt_def.variant(variant_index).fields[f].ty(tcx, args) + } + ty::Coroutine(def_id, args) => { + let mut variants = args.as_coroutine().state_tys(def_id, tcx); + let Some(mut variant) = variants.nth(variant_index.into()) else { + bug!("variant {variant_index:?} of coroutine out of range: {self:?}"); + }; + + variant + .nth(f.index()) + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")) + } + _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"), + } + } else { + match self.ty.kind() { + ty::Adt(adt_def, args) if !adt_def.is_enum() => { + adt_def.non_enum_variant().fields[f].ty(tcx, args) + } + ty::Closure(_, args) => args + .as_closure() + .upvar_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + ty::CoroutineClosure(_, args) => args + .as_coroutine_closure() + .upvar_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + // Only prefix fields (upvars and current state) are + // accessible without a variant index. + ty::Coroutine(_, args) => args + .as_coroutine() + .prefix_tys() + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + ty::Tuple(tys) => tys + .get(f.index()) + .copied() + .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + _ => bug!("can't project out of {self:?}"), + } + } + } + + pub fn multi_projection_ty( + self, + tcx: TyCtxt<'tcx>, + elems: &[PlaceElem<'tcx>], + ) -> PlaceTy<'tcx> { + elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem)) + } + + /// Convenience wrapper around `projection_ty_core` for + /// `PlaceElem`, where we can just use the `Ty` that is already + /// stored inline on field projection elems. + pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { + self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) + } + + /// `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 `FieldIdx` to its `Ty`, + /// (which should be trivial when `T` = `Ty`). + pub fn projection_ty_core<V, T>( + self, + tcx: TyCtxt<'tcx>, + elem: &ProjectionElem<V, T>, + mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, + mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, + ) -> PlaceTy<'tcx> + where + V: ::std::fmt::Debug, + T: ::std::fmt::Debug + Copy, + { + if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { + bug!("cannot use non field projection on downcasted place") + } + let answer = match *elem { + ProjectionElem::Deref => { + let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", self) + }); + PlaceTy::from_ty(ty) + } + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { + PlaceTy::from_ty(self.ty.builtin_index().unwrap()) + } + ProjectionElem::Subslice { from, to, from_end } => { + PlaceTy::from_ty(match self.ty.kind() { + ty::Slice(..) => self.ty, + ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), + ty::Array(inner, size) if from_end => { + let size = size + .try_to_target_usize(tcx) + .expect("expected subslice projection on fixed-size array"); + let len = size - from - to; + Ty::new_array(tcx, *inner, len) + } + _ => bug!("cannot subslice non-array type: `{:?}`", self), + }) + } + ProjectionElem::Downcast(_name, index) => { + PlaceTy { ty: self.ty, variant_index: Some(index) } + } + ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), + ProjectionElem::OpaqueCast(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + ProjectionElem::Subtype(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + + // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. + ProjectionElem::UnwrapUnsafeBinder(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + }; + debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); + answer + } +} + impl<V, T> ProjectionElem<V, T> { /// Returns `true` if the target of this projection may refer to a different region of memory /// than the base. @@ -192,6 +342,25 @@ impl<'tcx> Place<'tcx> { self.as_ref().project_deeper(more_projections, tcx) } + + pub fn ty_from<D: ?Sized>( + local: Local, + projection: &[PlaceElem<'tcx>], + local_decls: &D, + tcx: TyCtxt<'tcx>, + ) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection) + } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, self.projection, local_decls, tcx) + } } impl From<Local> for Place<'_> { @@ -294,6 +463,13 @@ impl<'tcx> PlaceRef<'tcx> { Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(self.local, self.projection, local_decls, tcx) + } } impl From<Local> for PlaceRef<'_> { @@ -388,6 +564,28 @@ impl<'tcx> Operand<'tcx> { let const_ty = self.constant()?.const_.ty(); if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + where + D: HasLocalDecls<'tcx>, + { + match self { + &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, + Operand::Constant(c) => c.const_.ty(), + } + } + + pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span + where + D: HasLocalDecls<'tcx>, + { + match self { + &Operand::Copy(ref l) | &Operand::Move(ref l) => { + local_decls.local_decls()[l.local].source_info.span + } + Operand::Constant(c) => c.span, + } + } } impl<'tcx> ConstOperand<'tcx> { @@ -413,6 +611,11 @@ impl<'tcx> ConstOperand<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Rvalues +pub enum RvalueInitializationState { + Shallow, + Deep, +} + impl<'tcx> Rvalue<'tcx> { /// Returns true if rvalue can be safely removed when the result is unused. #[inline] @@ -452,6 +655,70 @@ impl<'tcx> Rvalue<'tcx> { | Rvalue::WrapUnsafeBinder(_, _) => true, } } + + pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> + where + D: HasLocalDecls<'tcx>, + { + match *self { + Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), + Rvalue::Repeat(ref operand, count) => { + Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) + } + Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), + Rvalue::Ref(reg, bk, ref place) => { + let place_ty = place.ty(local_decls, tcx).ty; + Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy()) + } + Rvalue::RawPtr(kind, ref place) => { + let place_ty = place.ty(local_decls, tcx).ty; + Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) + } + Rvalue::Len(..) => tcx.types.usize, + Rvalue::Cast(.., ty) => ty, + Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { + let lhs_ty = lhs.ty(local_decls, tcx); + let rhs_ty = rhs.ty(local_decls, tcx); + op.ty(tcx, lhs_ty, rhs_ty) + } + Rvalue::UnaryOp(op, ref operand) => { + let arg_ty = operand.ty(local_decls, tcx); + op.ty(tcx, arg_ty) + } + Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { + tcx.types.usize + } + Rvalue::NullaryOp(NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::Aggregate(ref ak, ref ops) => match **ak { + AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), + AggregateKind::Tuple => { + Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) + } + AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), + AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), + AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), + AggregateKind::CoroutineClosure(did, args) => { + Ty::new_coroutine_closure(tcx, did, args) + } + AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability), + }, + Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), + Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, + Rvalue::WrapUnsafeBinder(_, ty) => ty, + } + } + + #[inline] + /// Returns `true` if this rvalue is deeply initialized (most rvalues) or + /// whether its only shallowly initialized (`Rvalue::Box`). + pub fn initialization_state(&self) -> RvalueInitializationState { + match *self { + Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, + _ => RvalueInitializationState::Deep, + } + } } impl BorrowKind { @@ -474,4 +741,124 @@ impl BorrowKind { BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } + + pub fn to_mutbl_lossy(self) -> hir::Mutability { + match self { + BorrowKind::Mut { .. } => hir::Mutability::Mut, + BorrowKind::Shared => hir::Mutability::Not, + + // We have no type corresponding to a shallow borrow, so use + // `&` as an approximation. + BorrowKind::Fake(_) => hir::Mutability::Not, + } + } +} + +impl<'tcx> UnOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { + match self { + UnOp::Not | UnOp::Neg => arg_ty, + UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx), + } + } +} + +impl<'tcx> BinOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { + // FIXME: handle SIMD correctly + match self { + &BinOp::Add + | &BinOp::AddUnchecked + | &BinOp::Sub + | &BinOp::SubUnchecked + | &BinOp::Mul + | &BinOp::MulUnchecked + | &BinOp::Div + | &BinOp::Rem + | &BinOp::BitXor + | &BinOp::BitAnd + | &BinOp::BitOr => { + // these should be integers or floats of the same size. + assert_eq!(lhs_ty, rhs_ty); + lhs_ty + } + &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => { + // these should be integers of the same size. + assert_eq!(lhs_ty, rhs_ty); + Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool]) + } + &BinOp::Shl + | &BinOp::ShlUnchecked + | &BinOp::Shr + | &BinOp::ShrUnchecked + | &BinOp::Offset => { + lhs_ty // lhs_ty can be != rhs_ty + } + &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { + tcx.types.bool + } + &BinOp::Cmp => { + // these should be integer-like types of the same size. + assert_eq!(lhs_ty, rhs_ty); + tcx.ty_ordering_enum(None) + } + } + } + pub(crate) fn to_hir_binop(self) -> hir::BinOpKind { + match self { + // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending + // on whether overflow checks are enabled or not. + BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add, + BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub, + BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul, + BinOp::Div => hir::BinOpKind::Div, + BinOp::Rem => hir::BinOpKind::Rem, + BinOp::BitXor => hir::BinOpKind::BitXor, + BinOp::BitAnd => hir::BinOpKind::BitAnd, + BinOp::BitOr => hir::BinOpKind::BitOr, + BinOp::Shl => hir::BinOpKind::Shl, + BinOp::Shr => hir::BinOpKind::Shr, + BinOp::Eq => hir::BinOpKind::Eq, + BinOp::Ne => hir::BinOpKind::Ne, + BinOp::Lt => hir::BinOpKind::Lt, + BinOp::Gt => hir::BinOpKind::Gt, + BinOp::Le => hir::BinOpKind::Le, + BinOp::Ge => hir::BinOpKind::Ge, + // We don't have HIR syntax for these. + BinOp::Cmp + | BinOp::AddUnchecked + | BinOp::SubUnchecked + | BinOp::MulUnchecked + | BinOp::ShlUnchecked + | BinOp::ShrUnchecked + | BinOp::Offset => { + unreachable!() + } + } + } + + /// If this is a `FooWithOverflow`, return `Some(Foo)`. + pub fn overflowing_to_wrapping(self) -> Option<BinOp> { + Some(match self { + BinOp::AddWithOverflow => BinOp::Add, + BinOp::SubWithOverflow => BinOp::Sub, + BinOp::MulWithOverflow => BinOp::Mul, + _ => return None, + }) + } + + /// Returns whether this is a `FooWithOverflow` + pub fn is_overflowing(self) -> bool { + self.overflowing_to_wrapping().is_some() + } + + /// If this is a `Foo`, return `Some(FooWithOverflow)`. + pub fn wrapping_to_overflowing(self) -> Option<BinOp> { + Some(match self { + BinOp::Add => BinOp::AddWithOverflow, + BinOp::Sub => BinOp::SubWithOverflow, + BinOp::Mul => BinOp::MulWithOverflow, + _ => return None, + }) + } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9cec8d832dd..af6f0e4c551 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -23,68 +23,77 @@ use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex} /// Represents the "flavors" of MIR. /// -/// All flavors of MIR use the same data structure, but there are some important differences. These -/// differences come in two forms: Dialects and phases. +/// The MIR pipeline is structured into a few major dialects, with one or more phases within each +/// dialect. A MIR flavor is identified by a dialect-phase pair. A single `MirPhase` value +/// specifies such a pair. All flavors of MIR use the same data structure to represent the program. /// -/// Dialects represent a stronger distinction than phases. This is because the transitions between -/// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In -/// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but -/// have different semantic meaning and different behavior at runtime. +/// Different MIR dialects have different semantics. (The differences between dialects are small, +/// but they do exist.) The progression from one MIR dialect to the next is technically a lowering +/// from one IR to another. In other words, a single well-formed [`Body`](crate::mir::Body) might +/// have different semantic meaning and different behavior at runtime in the different dialects. +/// The specific differences between dialects are described on the variants below. /// -/// Each dialect additionally has a number of phases. However, phase changes never involve semantic -/// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed -/// that it has the same semantic meaning. In this sense, phase changes can only add additional -/// restrictions on what MIR is well-formed. +/// Phases exist only to place restrictions on what language constructs are permitted in +/// well-formed MIR, and subsequent phases mostly increase those restrictions. I.e. to convert MIR +/// from one phase to the next might require removing/replacing certain MIR constructs. /// -/// When adding phases, remember to update [`MirPhase::phase_index`]. +/// When adding dialects or phases, remember to update [`MirPhase::index`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] pub enum MirPhase { - /// The MIR that is generated by MIR building. + /// The "built MIR" dialect, as generated by MIR building. /// /// The only things that operate on this dialect are unsafeck, the various MIR lints, and const /// qualifs. /// - /// This has no distinct phases. + /// This dialect has just the one (implicit) phase, which places few restrictions on what MIR + /// constructs are allowed. Built, - /// The MIR used for most analysis. + + /// The "analysis MIR" dialect, used for borrowck and friends. /// - /// The only semantic change between analysis and built MIR is constant promotion. In built MIR, - /// sequences of statements that would generally be subject to constant promotion are - /// semantically constants, while in analysis MIR all constants are explicit. + /// The only semantic difference between built MIR and analysis MIR relates to constant + /// promotion. In built MIR, sequences of statements that would generally be subject to + /// constant promotion are semantically constants, while in analysis MIR all constants are + /// explicit. /// - /// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries. + /// The result of const promotion is available from the `mir_promoted` and `promoted_mir` + /// queries. /// - /// This is the version of MIR used by borrowck and friends. + /// The phases of this dialect are described in `AnalysisPhase`. Analysis(AnalysisPhase), - /// The MIR used for CTFE, optimizations, and codegen. - /// - /// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows: - /// - /// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking, - /// if dataflow analysis determines that the place being dropped is uninitialized, the drop will - /// not be executed. The exact semantics of this aren't written down anywhere, which means they - /// are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional; - /// when a `Drop` terminator is reached, if the type has drop glue that drop glue is always - /// executed. This may be UB if the underlying place is not initialized. - /// - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception - /// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned - /// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such - /// rules, and dropping a misaligned place is simply UB. - /// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime - /// 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 most retags explicit (though implicit retags - /// can still occur at `Rvalue::{Ref,AddrOf}`). - /// - Coroutine bodies: In analysis MIR, locals may actually be behind a pointer that user code has - /// access to. This occurs in coroutine 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 - - /// all coroutine bodies are lowered and so all places that look like locals really are locals. + + /// The "runtime MIR" dialect, used for CTFE, optimizations, and codegen. + /// + /// The semantic differences between analysis MIR and runtime MIR are as follows. + /// + /// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly + /// speaking, if dataflow analysis determines that the place being dropped is uninitialized, + /// the drop will not be executed. The exact semantics of this aren't written down anywhere, + /// which means they are essentially "what drop elaboration does." In runtime MIR, the drops + /// are unconditional; when a `Drop` terminator is reached, if the type has drop glue that + /// drop glue is always executed. This may be UB if the underlying place is not initialized. + /// - Packed drops: Places might in general be misaligned - in most cases this is UB, the + /// exception is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be + /// misaligned for this reason implicitly moves `P` to a temporary before dropping. Runtime + /// MIR has no such rules, and dropping a misaligned place is simply UB. + /// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In + /// runtime 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 most retags explicit (though implicit + /// retags can still occur at `Rvalue::{Ref,AddrOf}`). + /// - Coroutine bodies: In analysis MIR, locals may actually be behind a pointer that user code + /// has access to. This occurs in coroutine bodies. Such locals do not behave like other + /// locals, because they e.g. may be aliased in surprising ways. Runtime MIR has no such + /// special locals. All coroutine bodies are lowered and so all places that look like locals + /// really are locals. /// /// Also note that the lint pass which reports eg `200_u8 + 200_u8` as an error is run as a part /// of analysis to runtime MIR lowering. To ensure lints are reported reliably, this means that - /// transformations which may suppress such errors should not run on analysis MIR. + /// transformations that can suppress such errors should not run on analysis MIR. + /// + /// The phases of this dialect are described in `RuntimePhase`. Runtime(RuntimePhase), } @@ -111,7 +120,8 @@ pub enum AnalysisPhase { /// * [`TerminatorKind::FalseEdge`] /// * [`StatementKind::FakeRead`] /// * [`StatementKind::AscribeUserType`] - /// * [`StatementKind::Coverage`] with [`CoverageKind::BlockMarker`] or [`CoverageKind::SpanMarker`] + /// * [`StatementKind::Coverage`] with [`CoverageKind::BlockMarker`] or + /// [`CoverageKind::SpanMarker`] /// * [`Rvalue::Ref`] with `BorrowKind::Fake` /// * [`CastKind::PointerCoercion`] with any of the following: /// * [`PointerCoercion::ArrayToPointer`] @@ -1015,22 +1025,30 @@ impl TerminatorKind<'_> { #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { - /// Possible values. The locations to branch to in each case - /// are found in the corresponding indices from the `targets` vector. + /// Possible values. For each value, the location to branch to is found in + /// the corresponding element in the `targets` vector. pub(super) values: SmallVec<[Pu128; 1]>, - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. + /// Possible branch targets. The last element of this vector is used for + /// the "otherwise" branch, so `targets.len() == values.len() + 1` always + /// holds. + // + // Note: This invariant is non-obvious and easy to violate. This would be a + // more rigorous representation: // - // This invariant is quite non-obvious and also could be improved. - // One way to make this invariant is to have something like this instead: + // normal: SmallVec<[(Pu128, BasicBlock); 1]>, + // otherwise: BasicBlock, // - // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option<BasicBlock> // exhaustive if None + // But it's important to have the targets in a sliceable type, because + // target slices show up elsewhere. E.g. `TerminatorKind::InlineAsm` has a + // boxed slice, and `TerminatorKind::FalseEdge` has a single target that + // can be converted to a slice with `slice::from_ref`. // - // However we’ve decided to keep this as-is until we figure a case - // where some other approach seems to be strictly better than other. + // Why does this matter? In functions like `TerminatorKind::successors` we + // return `impl Iterator` and a non-slice-of-targets representation here + // causes problems because multiple different concrete iterator types would + // be involved and we would need a boxed trait object, which requires an + // allocation, which is expensive if done frequently. pub(super) targets: SmallVec<[BasicBlock; 2]>, } @@ -1125,7 +1143,7 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; /// /// 1. The address in memory that the place refers to. /// 2. The provenance with which the place is being accessed. -/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy]. +/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::PlaceTy]. /// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. /// /// We'll give a description below of how all pieces of the place except for the provenance are diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs deleted file mode 100644 index af23c8b2ea7..00000000000 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ /dev/null @@ -1,412 +0,0 @@ -/*! - * Methods for the various MIR types. These are intended for use after - * building is complete. - */ - -use rustc_hir as hir; -use tracing::{debug, instrument}; -use ty::CoroutineArgsExt; - -use crate::mir::*; - -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] -pub struct PlaceTy<'tcx> { - pub ty: Ty<'tcx>, - /// Downcast to a particular variant of an enum or a coroutine, if included. - pub variant_index: Option<VariantIdx>, -} - -// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. -#[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(PlaceTy<'_>, 16); - -impl<'tcx> PlaceTy<'tcx> { - #[inline] - pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { - PlaceTy { ty, variant_index: None } - } - - /// `place_ty.field_ty(tcx, f)` computes the type of a given field. - /// - /// Most clients of `PlaceTy` can instead just extract the relevant type - /// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>` - /// do not carry a `Ty` for `T`. - /// - /// Note that the resulting type has not been normalized. - #[instrument(level = "debug", skip(tcx), ret)] - pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { - if let Some(variant_index) = self.variant_index { - match *self.ty.kind() { - ty::Adt(adt_def, args) if adt_def.is_enum() => { - adt_def.variant(variant_index).fields[f].ty(tcx, args) - } - ty::Coroutine(def_id, args) => { - let mut variants = args.as_coroutine().state_tys(def_id, tcx); - let Some(mut variant) = variants.nth(variant_index.into()) else { - bug!("variant {variant_index:?} of coroutine out of range: {self:?}"); - }; - - variant - .nth(f.index()) - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")) - } - _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"), - } - } else { - match self.ty.kind() { - ty::Adt(adt_def, args) if !adt_def.is_enum() => { - adt_def.non_enum_variant().fields[f].ty(tcx, args) - } - ty::Closure(_, args) => args - .as_closure() - .upvar_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - ty::CoroutineClosure(_, args) => args - .as_coroutine_closure() - .upvar_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - // Only prefix fields (upvars and current state) are - // accessible without a variant index. - ty::Coroutine(_, args) => args - .as_coroutine() - .prefix_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - ty::Tuple(tys) => tys - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - _ => bug!("can't project out of {self:?}"), - } - } - } - - /// Convenience wrapper around `projection_ty_core` for - /// `PlaceElem`, where we can just use the `Ty` that is already - /// stored inline on field projection elems. - pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) - } - - /// `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 `FieldIdx` to its `Ty`, - /// (which should be trivial when `T` = `Ty`). - pub fn projection_ty_core<V, T>( - self, - tcx: TyCtxt<'tcx>, - elem: &ProjectionElem<V, T>, - mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, - mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, - ) -> PlaceTy<'tcx> - where - V: ::std::fmt::Debug, - T: ::std::fmt::Debug + Copy, - { - if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { - bug!("cannot use non field projection on downcasted place") - } - let answer = match *elem { - ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }); - PlaceTy::from_ty(ty) - } - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - PlaceTy::from_ty(self.ty.builtin_index().unwrap()) - } - ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind() { - ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), - ty::Array(inner, size) if from_end => { - let size = size - .try_to_target_usize(tcx) - .expect("expected subslice projection on fixed-size array"); - let len = size - from - to; - Ty::new_array(tcx, *inner, len) - } - _ => bug!("cannot subslice non-array type: `{:?}`", self), - }) - } - ProjectionElem::Downcast(_name, index) => { - PlaceTy { ty: self.ty, variant_index: Some(index) } - } - ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - ProjectionElem::OpaqueCast(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - ProjectionElem::Subtype(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - - // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. - ProjectionElem::UnwrapUnsafeBinder(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - }; - debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); - answer - } -} - -impl<'tcx> Place<'tcx> { - pub fn ty_from<D: ?Sized>( - local: Local, - projection: &[PlaceElem<'tcx>], - local_decls: &D, - tcx: TyCtxt<'tcx>, - ) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - projection - .iter() - .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| { - place_ty.projection_ty(tcx, elem) - }) - } - - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - Place::ty_from(self.local, self.projection, local_decls, tcx) - } -} - -impl<'tcx> PlaceRef<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, - { - Place::ty_from(self.local, self.projection, local_decls, tcx) - } -} - -pub enum RvalueInitializationState { - Shallow, - Deep, -} - -impl<'tcx> Rvalue<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match *self { - Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), - Rvalue::Repeat(ref operand, count) => { - Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) - } - Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), - Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy()) - } - Rvalue::RawPtr(kind, ref place) => { - let place_ty = place.ty(local_decls, tcx).ty; - Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) - } - Rvalue::Len(..) => tcx.types.usize, - Rvalue::Cast(.., ty) => ty, - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { - let lhs_ty = lhs.ty(local_decls, tcx); - let rhs_ty = rhs.ty(local_decls, tcx); - op.ty(tcx, lhs_ty, rhs_ty) - } - Rvalue::UnaryOp(op, ref operand) => { - let arg_ty = operand.ty(local_decls, tcx); - op.ty(tcx, arg_ty) - } - Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { - tcx.types.usize - } - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, - Rvalue::Aggregate(ref ak, ref ops) => match **ak { - AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), - AggregateKind::Tuple => { - Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) - } - AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args), - AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args), - AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args), - AggregateKind::CoroutineClosure(did, args) => { - Ty::new_coroutine_closure(tcx, did, args) - } - AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability), - }, - Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), - Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, - Rvalue::WrapUnsafeBinder(_, ty) => ty, - } - } - - #[inline] - /// Returns `true` if this rvalue is deeply initialized (most rvalues) or - /// whether its only shallowly initialized (`Rvalue::Box`). - pub fn initialization_state(&self) -> RvalueInitializationState { - match *self { - Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, - _ => RvalueInitializationState::Deep, - } - } -} - -impl<'tcx> Operand<'tcx> { - pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> - where - D: HasLocalDecls<'tcx>, - { - match self { - &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - Operand::Constant(c) => c.const_.ty(), - } - } - - pub fn span<D: ?Sized>(&self, local_decls: &D) -> Span - where - D: HasLocalDecls<'tcx>, - { - match self { - &Operand::Copy(ref l) | &Operand::Move(ref l) => { - local_decls.local_decls()[l.local].source_info.span - } - Operand::Constant(c) => c.span, - } - } -} - -impl<'tcx> BinOp { - pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> { - // FIXME: handle SIMD correctly - match self { - &BinOp::Add - | &BinOp::AddUnchecked - | &BinOp::Sub - | &BinOp::SubUnchecked - | &BinOp::Mul - | &BinOp::MulUnchecked - | &BinOp::Div - | &BinOp::Rem - | &BinOp::BitXor - | &BinOp::BitAnd - | &BinOp::BitOr => { - // these should be integers or floats of the same size. - assert_eq!(lhs_ty, rhs_ty); - lhs_ty - } - &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => { - // these should be integers of the same size. - assert_eq!(lhs_ty, rhs_ty); - Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool]) - } - &BinOp::Shl - | &BinOp::ShlUnchecked - | &BinOp::Shr - | &BinOp::ShrUnchecked - | &BinOp::Offset => { - lhs_ty // lhs_ty can be != rhs_ty - } - &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { - tcx.types.bool - } - &BinOp::Cmp => { - // these should be integer-like types of the same size. - assert_eq!(lhs_ty, rhs_ty); - tcx.ty_ordering_enum(None) - } - } - } -} - -impl<'tcx> UnOp { - pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { - match self { - UnOp::Not | UnOp::Neg => arg_ty, - UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx), - } - } -} - -impl BorrowKind { - pub fn to_mutbl_lossy(self) -> hir::Mutability { - match self { - BorrowKind::Mut { .. } => hir::Mutability::Mut, - BorrowKind::Shared => hir::Mutability::Not, - - // We have no type corresponding to a shallow borrow, so use - // `&` as an approximation. - BorrowKind::Fake(_) => hir::Mutability::Not, - } - } -} - -impl BinOp { - pub(crate) fn to_hir_binop(self) -> hir::BinOpKind { - match self { - // HIR `+`/`-`/`*` can map to either of these MIR BinOp, depending - // on whether overflow checks are enabled or not. - BinOp::Add | BinOp::AddWithOverflow => hir::BinOpKind::Add, - BinOp::Sub | BinOp::SubWithOverflow => hir::BinOpKind::Sub, - BinOp::Mul | BinOp::MulWithOverflow => hir::BinOpKind::Mul, - BinOp::Div => hir::BinOpKind::Div, - BinOp::Rem => hir::BinOpKind::Rem, - BinOp::BitXor => hir::BinOpKind::BitXor, - BinOp::BitAnd => hir::BinOpKind::BitAnd, - BinOp::BitOr => hir::BinOpKind::BitOr, - BinOp::Shl => hir::BinOpKind::Shl, - BinOp::Shr => hir::BinOpKind::Shr, - BinOp::Eq => hir::BinOpKind::Eq, - BinOp::Ne => hir::BinOpKind::Ne, - BinOp::Lt => hir::BinOpKind::Lt, - BinOp::Gt => hir::BinOpKind::Gt, - BinOp::Le => hir::BinOpKind::Le, - BinOp::Ge => hir::BinOpKind::Ge, - // We don't have HIR syntax for these. - BinOp::Cmp - | BinOp::AddUnchecked - | BinOp::SubUnchecked - | BinOp::MulUnchecked - | BinOp::ShlUnchecked - | BinOp::ShrUnchecked - | BinOp::Offset => { - unreachable!() - } - } - } - - /// If this is a `FooWithOverflow`, return `Some(Foo)`. - pub fn overflowing_to_wrapping(self) -> Option<BinOp> { - Some(match self { - BinOp::AddWithOverflow => BinOp::Add, - BinOp::SubWithOverflow => BinOp::Sub, - BinOp::MulWithOverflow => BinOp::Mul, - _ => return None, - }) - } - - /// Returns whether this is a `FooWithOverflow` - pub fn is_overflowing(self) -> bool { - self.overflowing_to_wrapping().is_some() - } - - /// If this is a `Foo`, return `Some(FooWithOverflow)`. - pub fn wrapping_to_overflowing(self) -> Option<BinOp> { - Some(match self { - BinOp::Add => BinOp::AddWithOverflow, - BinOp::Sub => BinOp::SubWithOverflow, - BinOp::Mul => BinOp::MulWithOverflow, - _ => return None, - }) - } -} diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 2fe116212eb..fdfcb128778 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -86,7 +86,7 @@ impl SwitchTargets { self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise()) } - /// Adds a new target to the switch. But You cannot add an already present value. + /// Adds a new target to the switch. Panics if you add an already present value. #[inline] pub fn add_target(&mut self, value: u128, bb: BasicBlock) { let value = Pu128(value); @@ -226,7 +226,7 @@ impl<O> AssertKind<O> { { use AssertKind::*; match self { - BoundsCheck { ref len, ref index } => write!( + BoundsCheck { len, index } => write!( f, "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}" ), @@ -272,7 +272,7 @@ impl<O> AssertKind<O> { "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}" ) } - NullPointerDereference => write!(f, "\"null pointer dereference occured\""), + NullPointerDereference => write!(f, "\"null pointer dereference occurred\""), ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after completion\"") } diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 0e7dcc24daf..5950ac295af 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -104,23 +104,21 @@ 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, C> { +pub struct Postorder<'a, 'tcx> { basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, visited: DenseBitSet<BasicBlock>, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, - extra: C, + /// A non-empty `extra` allows for a precise calculation of the successors. + extra: Option<(TyCtxt<'tcx>, Instance<'tcx>)>, } -impl<'a, 'tcx, C> Postorder<'a, 'tcx, C> -where - C: Customization<'tcx>, -{ +impl<'a, 'tcx> Postorder<'a, 'tcx> { pub fn new( basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, root: BasicBlock, - extra: C, - ) -> Postorder<'a, 'tcx, C> { + extra: Option<(TyCtxt<'tcx>, Instance<'tcx>)>, + ) -> Postorder<'a, 'tcx> { let mut po = Postorder { basic_blocks, visited: DenseBitSet::new_empty(basic_blocks.len()), @@ -140,7 +138,11 @@ where return; } let data = &self.basic_blocks[bb]; - let successors = C::successors(data, self.extra); + let successors = if let Some(extra) = self.extra { + data.mono_successors(extra.0, extra.1) + } else { + data.terminator().successors() + }; self.visit_stack.push((bb, successors)); } @@ -198,10 +200,7 @@ where } } -impl<'tcx, C> Iterator for Postorder<'_, 'tcx, C> -where - C: Customization<'tcx>, -{ +impl<'tcx> Iterator for Postorder<'_, 'tcx> { type Item = BasicBlock; fn next(&mut self) -> Option<BasicBlock> { @@ -241,32 +240,12 @@ pub fn postorder<'a, 'tcx>( reverse_postorder(body).rev() } -/// Lets us plug in some additional logic and data into a Postorder traversal. Or not. -pub trait Customization<'tcx>: Copy { - fn successors<'a>(_: &'a BasicBlockData<'tcx>, _: Self) -> Successors<'a>; -} - -impl<'tcx> Customization<'tcx> for () { - fn successors<'a>(data: &'a BasicBlockData<'tcx>, _: ()) -> Successors<'a> { - data.terminator().successors() - } -} - -impl<'tcx> Customization<'tcx> for (TyCtxt<'tcx>, Instance<'tcx>) { - fn successors<'a>( - data: &'a BasicBlockData<'tcx>, - (tcx, instance): (TyCtxt<'tcx>, Instance<'tcx>), - ) -> Successors<'a> { - data.mono_successors(tcx, instance) - } -} - pub fn mono_reachable_reverse_postorder<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, ) -> Vec<BasicBlock> { - let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, (tcx, instance)); + let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, Some((tcx, instance))); let mut items = Vec::with_capacity(body.basic_blocks.len()); while let Some(block) = iter.next() { items.push(block); diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs deleted file mode 100644 index 9893dd0484c..00000000000 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! `TypeFoldable` implementations for MIR types - -use rustc_ast::InlineAsmTemplatePiece; -use rustc_hir::UnsafeBinderCastKind; -use rustc_hir::def_id::LocalDefId; - -use super::*; - -TrivialTypeTraversalImpls! { - BlockTailInfo, - MirPhase, - SourceInfo, - FakeReadCause, - RetagKind, - SourceScope, - SourceScopeLocalData, - UserTypeAnnotationIndex, - BorrowKind, - RawPtrKind, - CastKind, - BasicBlock, - SwitchTargets, - CoroutineKind, - CoroutineSavedLocal, - UnsafeBinderCastKind, -} - -TrivialTypeTraversalImpls! { - ConstValue<'tcx>, - NullOp<'tcx>, -} - -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - _folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(self) - } -} - -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - _folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(self) - } -} - -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<LocalDefId> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - _folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(self) - } -} - -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v)) - } -} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8d04bbb95bd..3c83d962900 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -270,10 +270,12 @@ macro_rules! make_mir_visitor { fn visit_local( &mut self, - _local: $(& $mutability)? Local, - _context: PlaceContext, - _location: Location, - ) {} + local: $(& $mutability)? Local, + context: PlaceContext, + location: Location, + ) { + self.super_local(local, context, location) + } fn visit_source_scope( &mut self, @@ -292,9 +294,11 @@ macro_rules! make_mir_visitor { super_body!(self, body, $($mutability, true)?); } - fn super_basic_block_data(&mut self, - block: BasicBlock, - data: & $($mutability)? BasicBlockData<'tcx>) { + fn super_basic_block_data( + &mut self, + block: BasicBlock, + data: & $($mutability)? BasicBlockData<'tcx>) + { let BasicBlockData { statements, terminator, @@ -339,24 +343,24 @@ macro_rules! make_mir_visitor { match callee_def { ty::InstanceKind::Item(_def_id) => {} - ty::InstanceKind::Intrinsic(_def_id) | - ty::InstanceKind::VTableShim(_def_id) | - ty::InstanceKind::ReifyShim(_def_id, _) | - ty::InstanceKind::Virtual(_def_id, _) | - ty::InstanceKind::ThreadLocalShim(_def_id) | - ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceKind::ConstructCoroutineInClosureShim { + ty::InstanceKind::Intrinsic(_def_id) + | ty::InstanceKind::VTableShim(_def_id) + | ty::InstanceKind::ReifyShim(_def_id, _) + | ty::InstanceKind::Virtual(_def_id, _) + | ty::InstanceKind::ThreadLocalShim(_def_id) + | ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } + | ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, receiver_by_ref: _, - } | - ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) | - ty::InstanceKind::DropGlue(_def_id, None) => {} - - ty::InstanceKind::FnPtrShim(_def_id, ty) | - ty::InstanceKind::DropGlue(_def_id, Some(ty)) | - ty::InstanceKind::CloneShim(_def_id, ty) | - ty::InstanceKind::FnPtrAddrShim(_def_id, ty) | - ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { + } + | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) + | ty::InstanceKind::DropGlue(_def_id, None) => {} + + ty::InstanceKind::FnPtrShim(_def_id, ty) + | ty::InstanceKind::DropGlue(_def_id, Some(ty)) + | ty::InstanceKind::CloneShim(_def_id, ty) + | ty::InstanceKind::FnPtrAddrShim(_def_id, ty) + | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } @@ -368,19 +372,16 @@ macro_rules! make_mir_visitor { } } - fn super_statement(&mut self, - statement: & $($mutability)? Statement<'tcx>, - location: Location) { - let Statement { - source_info, - kind, - } = statement; + fn super_statement( + &mut self, + statement: & $($mutability)? Statement<'tcx>, + location: Location + ) { + let Statement { source_info, kind } = statement; self.visit_source_info(source_info); match kind { - StatementKind::Assign( - box (place, rvalue) - ) => { + StatementKind::Assign(box (place, rvalue)) => { self.visit_assign(place, rvalue, location); } StatementKind::FakeRead(box (_, place)) => { @@ -428,11 +429,13 @@ macro_rules! make_mir_visitor { location ); } - StatementKind::AscribeUserType( - box (place, user_ty), - variance - ) => { - self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location); + StatementKind::AscribeUserType(box (place, user_ty), variance) => { + self.visit_ascribe_user_ty( + place, + $(& $mutability)? *variance, + user_ty, + location + ); } StatementKind::Coverage(coverage) => { self.visit_coverage( @@ -440,10 +443,14 @@ macro_rules! make_mir_visitor { location ) } - StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { + StatementKind::Intrinsic(box intrinsic) => { match intrinsic { NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src, + dst, + count + }) => { self.visit_operand(src, location); self.visit_operand(dst, location); self.visit_operand(count, location); @@ -456,10 +463,12 @@ macro_rules! make_mir_visitor { } } - fn super_assign(&mut self, - place: &$($mutability)? Place<'tcx>, - rvalue: &$($mutability)? Rvalue<'tcx>, - location: Location) { + fn super_assign( + &mut self, + place: &$($mutability)? Place<'tcx>, + rvalue: &$($mutability)? Rvalue<'tcx>, + location: Location + ) { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Store), @@ -468,20 +477,22 @@ macro_rules! make_mir_visitor { self.visit_rvalue(rvalue, location); } - fn super_terminator(&mut self, - terminator: &$($mutability)? Terminator<'tcx>, - location: Location) { + fn super_terminator( + &mut self, + terminator: &$($mutability)? Terminator<'tcx>, + location: Location + ) { let Terminator { source_info, kind } = terminator; self.visit_source_info(source_info); match kind { - TerminatorKind::Goto { .. } | - TerminatorKind::UnwindResume | - TerminatorKind::UnwindTerminate(_) | - TerminatorKind::CoroutineDrop | - TerminatorKind::Unreachable | - TerminatorKind::FalseEdge { .. } | - TerminatorKind::FalseUnwind { .. } => {} + TerminatorKind::Goto { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::CoroutineDrop + | TerminatorKind::Unreachable + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => {} TerminatorKind::Return => { // `return` logically moves from the return place `_0`. Note that the place @@ -500,19 +511,11 @@ macro_rules! make_mir_visitor { ); } - TerminatorKind::SwitchInt { - discr, - targets: _ - } => { + TerminatorKind::SwitchInt { discr, targets: _ } => { self.visit_operand(discr, location); } - TerminatorKind::Drop { - place, - target: _, - unwind: _, - replace: _, - } => { + TerminatorKind::Drop { place, target: _, unwind: _, replace: _ } => { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Drop), @@ -527,8 +530,9 @@ macro_rules! make_mir_visitor { target: _, unwind: _, call_source: _, - fn_span: _ + fn_span, } => { + self.visit_span($(& $mutability)? *fn_span); self.visit_operand(func, location); for arg in args { self.visit_operand(&$($mutability)? arg.node, location); @@ -540,34 +544,20 @@ macro_rules! make_mir_visitor { ); } - TerminatorKind::TailCall { - func, - args, - fn_span: _, - } => { + TerminatorKind::TailCall { func, args, fn_span } => { + self.visit_span($(& $mutability)? *fn_span); self.visit_operand(func, location); for arg in args { self.visit_operand(&$($mutability)? arg.node, location); } }, - TerminatorKind::Assert { - cond, - expected: _, - msg, - target: _, - unwind: _, - } => { + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { self.visit_operand(cond, location); self.visit_assert_message(msg, location); } - TerminatorKind::Yield { - value, - resume: _, - resume_arg, - drop: _, - } => { + TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { self.visit_operand(value, location); self.visit_place( resume_arg, @@ -620,9 +610,11 @@ macro_rules! make_mir_visitor { } } - fn super_assert_message(&mut self, - msg: & $($mutability)? AssertMessage<'tcx>, - location: Location) { + fn super_assert_message( + &mut self, + msg: & $($mutability)? AssertMessage<'tcx>, + location: Location + ) { use crate::mir::AssertKind::*; match msg { BoundsCheck { len, index } => { @@ -646,9 +638,11 @@ macro_rules! make_mir_visitor { } } - fn super_rvalue(&mut self, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { + fn super_rvalue( + &mut self, + rvalue: & $($mutability)? Rvalue<'tcx>, + location: Location + ) { match rvalue { Rvalue::Use(operand) => { self.visit_operand(operand, location); @@ -675,6 +669,7 @@ macro_rules! make_mir_visitor { }; self.visit_place(path, ctx, location); } + Rvalue::CopyForDeref(place) => { self.visit_place( place, @@ -738,8 +733,7 @@ macro_rules! make_mir_visitor { AggregateKind::Array(ty) => { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } - AggregateKind::Tuple => { - } + AggregateKind::Tuple => {} AggregateKind::Adt( _adt_def, _variant_index, @@ -749,22 +743,13 @@ macro_rules! make_mir_visitor { ) => { self.visit_args(args, location); } - AggregateKind::Closure( - _, - closure_args - ) => { + AggregateKind::Closure(_, closure_args) => { self.visit_args(closure_args, location); } - AggregateKind::Coroutine( - _, - coroutine_args, - ) => { + AggregateKind::Coroutine(_, coroutine_args) => { self.visit_args(coroutine_args, location); } - AggregateKind::CoroutineClosure( - _, - coroutine_closure_args, - ) => { + AggregateKind::CoroutineClosure(_, coroutine_closure_args) => { self.visit_args(coroutine_closure_args, location); } AggregateKind::RawPtr(ty, _) => { @@ -789,9 +774,11 @@ macro_rules! make_mir_visitor { } } - fn super_operand(&mut self, - operand: & $($mutability)? Operand<'tcx>, - location: Location) { + fn super_operand( + &mut self, + operand: & $($mutability)? Operand<'tcx>, + location: Location + ) { match operand { Operand::Copy(place) => { self.visit_place( @@ -813,28 +800,36 @@ macro_rules! make_mir_visitor { } } - fn super_ascribe_user_ty(&mut self, - place: & $($mutability)? Place<'tcx>, - variance: $(& $mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection, - location: Location) { + fn super_ascribe_user_ty( + &mut self, + place: & $($mutability)? Place<'tcx>, + variance: $(& $mutability)? ty::Variance, + user_ty: & $($mutability)? UserTypeProjection, + location: Location) + { self.visit_place( place, - PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)), + PlaceContext::NonUse( + NonUseContext::AscribeUserTy($(* &$mutability *)? variance) + ), location ); self.visit_user_type_projection(user_ty); } - fn super_coverage(&mut self, - _kind: & $($mutability)? coverage::CoverageKind, - _location: Location) { + fn super_coverage( + &mut self, + _kind: & $($mutability)? coverage::CoverageKind, + _location: Location + ) { } - fn super_retag(&mut self, - _kind: $(& $mutability)? RetagKind, - place: & $($mutability)? Place<'tcx>, - location: Location) { + fn super_retag( + &mut self, + _kind: $(& $mutability)? RetagKind, + place: & $($mutability)? Place<'tcx>, + location: Location + ) { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Retag), @@ -842,9 +837,11 @@ macro_rules! make_mir_visitor { ); } - fn super_local_decl(&mut self, - local: Local, - local_decl: & $($mutability)? LocalDecl<'tcx>) { + fn super_local_decl( + &mut self, + local: Local, + local_decl: & $($mutability)? LocalDecl<'tcx> + ) { let LocalDecl { mutability: _, ty, @@ -853,16 +850,25 @@ macro_rules! make_mir_visitor { local_info: _, } = local_decl; + self.visit_source_info(source_info); + self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { local, source_info: *source_info, }); if let Some(user_ty) = user_ty { - for (user_ty, _) in & $($mutability)? user_ty.contents { + for user_ty in & $($mutability)? user_ty.contents { self.visit_user_type_projection(user_ty); } } - self.visit_source_info(source_info); + } + + fn super_local( + &mut self, + _local: $(& $mutability)? Local, + _context: PlaceContext, + _location: Location, + ) { } fn super_var_debug_info( @@ -879,7 +885,10 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); let location = Location::START; - if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite { + if let Some(box VarDebugInfoFragment { + ty, + projection + }) = composite { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); for elem in projection { let ProjectionElem::Field(_, ty) = elem else { bug!() }; @@ -897,10 +906,7 @@ macro_rules! make_mir_visitor { } } - fn super_source_scope( - &mut self, - _scope: $(& $mutability)? SourceScope - ) {} + fn super_source_scope(&mut self, _scope: $(& $mutability)? SourceScope) {} fn super_const_operand( &mut self, @@ -916,8 +922,12 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); match const_ { Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), - Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), - Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), + Const::Val(_, ty) => { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } + Const::Unevaluated(_, ty) => { + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } } } @@ -926,27 +936,18 @@ macro_rules! make_mir_visitor { _ct: $(& $mutability)? ty::Const<'tcx>, _location: Location, ) { - } - fn super_span(&mut self, _span: $(& $mutability)? Span) { - } + fn super_span(&mut self, _span: $(& $mutability)? Span) {} fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { - let SourceInfo { - span, - scope, - } = source_info; + let SourceInfo { span, scope } = source_info; self.visit_span($(& $mutability)? *span); self.visit_source_scope($(& $mutability)? *scope); } - fn super_user_type_projection( - &mut self, - _ty: & $($mutability)? UserTypeProjection, - ) { - } + fn super_user_type_projection(&mut self, _ty: & $($mutability)? UserTypeProjection) {} fn super_user_type_annotation( &mut self, @@ -957,14 +958,11 @@ macro_rules! make_mir_visitor { self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); } - fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { - } + fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {} - fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) { - } + fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {} - fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) { - } + fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) {} // Convenience methods @@ -973,7 +971,8 @@ macro_rules! make_mir_visitor { body: &$($mutability)? Body<'tcx>, location: Location ) { - let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; + let basic_block = + & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { self.visit_terminator(terminator, location) @@ -1252,28 +1251,6 @@ macro_rules! visit_place_fns { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor, mut); -pub trait MirVisitable<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>); -} - -impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_statement(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self, location) - } -} - -impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { - fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { - visitor.visit_terminator(self.as_ref().unwrap(), location) - } -} - /// Extra information passed to `visit_ty` and friends to give context /// about where the type etc appears. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] @@ -1387,13 +1364,13 @@ impl PlaceContext { matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop)) } - /// Returns `true` if this place context represents a borrow. + /// Returns `true` if this place context represents a borrow, excluding fake borrows + /// (which are an artifact of borrowck and not actually borrows in runtime MIR). pub fn is_borrow(self) -> bool { matches!( self, - PlaceContext::NonMutatingUse( - NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow - ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) + | PlaceContext::MutatingUse(MutatingUseContext::Borrow) ) } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 14f871cbbdc..cbd60920bc5 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -101,9 +101,9 @@ impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()]; } -impl<T> EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { +impl<T> EraseType for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> { type Result = [u8; size_of::< - Result<(&'static (), rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed>, + Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>, >()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6c442fc1047..7c4ea06a746 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -18,7 +18,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, DocLinkResMap}; @@ -117,7 +116,7 @@ rustc_queries! { } query early_lint_checks(_: ()) { - desc { "perform lints prior to macro expansion" } + desc { "perform lints prior to AST lowering" } } query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { @@ -125,7 +124,7 @@ rustc_queries! { desc { "getting the resolver outputs" } } - query resolver_for_lowering_raw(_: ()) -> (&'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)>, &'tcx ty::ResolverGlobalCtxt) { + query resolver_for_lowering_raw(_: ()) -> (&'tcx Steal<(ty::ResolverAstLowering, Arc<ast::Crate>)>, &'tcx ty::ResolverGlobalCtxt) { eval_always no_hash desc { "getting the resolver for lowering" } @@ -164,7 +163,7 @@ rustc_queries! { /// The items in a module. /// - /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. + /// This can be conveniently accessed by `tcx.hir_visit_item_likes_in_module`. /// Avoid calling this query directly. query hir_module_items(key: LocalModDefId) -> &'tcx rustc_middle::hir::ModuleItems { arena_cache @@ -615,9 +614,16 @@ rustc_queries! { feedable } - /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass - /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations - /// have had a chance to potentially remove some of them. + /// Scans through a function's MIR after MIR optimizations, to prepare the + /// information needed by codegen when `-Cinstrument-coverage` is active. + /// + /// This includes the details of where to insert `llvm.instrprof.increment` + /// intrinsics, and the expression tables to be embedded in the function's + /// coverage metadata. + /// + /// FIXME(Zalathar): This query's purpose has drifted a bit and should + /// probably be renamed, but that can wait until after the potential + /// follow-ups to #136053 have settled down. /// /// Returns `None` for functions that were not instrumented. query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> Option<&'tcx mir::coverage::CoverageIdsInfo> { @@ -765,7 +771,7 @@ rustc_queries! { query type_param_predicates( key: (LocalDefId, LocalDefId, rustc_span::Ident) ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { - desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } + desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir_ty_param_name(key.1) } } query trait_def(key: DefId) -> &'tcx ty::TraitDef { @@ -796,7 +802,7 @@ rustc_queries! { query adt_dtorck_constraint( key: DefId - ) -> Result<&'tcx DropckConstraint<'tcx>, NoSolution> { + ) -> &'tcx DropckConstraint<'tcx> { desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } } @@ -1628,7 +1634,7 @@ rustc_queries! { separate_provide_extern } - query dependency_formats(_: ()) -> &'tcx Lrc<crate::middle::dependency_format::Dependencies> { + query dependency_formats(_: ()) -> &'tcx Arc<crate::middle::dependency_format::Dependencies> { arena_cache desc { "getting the linkage format of all dependencies" } } @@ -2077,7 +2083,7 @@ rustc_queries! { desc { "seeing if we're missing an `extern crate` item for this crate" } separate_provide_extern } - query used_crate_source(_: CrateNum) -> &'tcx Lrc<CrateSource> { + query used_crate_source(_: CrateNum) -> &'tcx Arc<CrateSource> { arena_cache eval_always desc { "looking at the source for a crate" } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 4a144ebb899..d9035efaf56 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -1,21 +1,16 @@ use std::collections::hash_map::Entry; use std::mem; +use std::sync::Arc; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; +use rustc_data_structures::sync::{HashMapExt, Lock, RwLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; use rustc_macros::{Decodable, Encodable}; -use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::{self, interpret}; -use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; -use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::query::QuerySideEffects; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -29,6 +24,13 @@ use rustc_span::{ SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; +use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use crate::mir::mono::MonoItem; +use crate::mir::{self, interpret}; +use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; +use crate::ty::{self, Ty, TyCtxt}; + const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; // A normal span encoded with both location information and a `SyntaxContext` @@ -60,7 +62,7 @@ pub struct OnDiskCache { file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>, // Caches that are populated lazily during decoding. - file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, + file_index_to_file: Lock<FxHashMap<SourceFileIndex, Arc<SourceFile>>>, // A map from dep-node to the position of the cached query result in // `serialized_data`. @@ -326,15 +328,18 @@ impl OnDiskCache { // Encode the file footer. let footer_pos = encoder.position() as u64; - encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { - file_index_to_stable_id, - query_result_index, - side_effects_index, - interpret_alloc_index, - syntax_contexts, - expn_data, - foreign_expn_data, - }); + encoder.encode_tagged( + TAG_FILE_FOOTER, + &Footer { + file_index_to_stable_id, + query_result_index, + side_effects_index, + interpret_alloc_index, + syntax_contexts, + expn_data, + foreign_expn_data, + }, + ); // Encode the position of the footer as the last 8 bytes of the // file so we know where to look for it. @@ -453,7 +458,7 @@ impl OnDiskCache { pub struct CacheDecoder<'a, 'tcx> { tcx: TyCtxt<'tcx>, opaque: MemDecoder<'a>, - file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, + file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Arc<SourceFile>>>, file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>, alloc_decoding_session: AllocDecodingSession<'a>, syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>, @@ -464,10 +469,10 @@ pub struct CacheDecoder<'a, 'tcx> { impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { #[inline] - fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> { + fn file_index_to_file(&self, index: SourceFileIndex) -> Arc<SourceFile> { let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, .. } = *self; - Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { + Arc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { let source_file_id = &file_index_to_stable_id[&index]; let source_file_cnum = tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id); @@ -559,7 +564,7 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { } } -rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt @@ -824,7 +829,7 @@ pub struct CacheEncoder<'a, 'tcx> { impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { #[inline] - fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex { + fn source_file_index(&mut self, source_file: Arc<SourceFile>) -> SourceFileIndex { self.file_to_file_index[&(&raw const *source_file)] } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 6c019b427db..690b8128b1a 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -1,6 +1,5 @@ use std::ops::Deref; -use field_offset::FieldOffset; use rustc_data_structures::sync::{AtomicU64, WorkerLocal}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; @@ -24,8 +23,10 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub eval_always: bool, pub dep_kind: DepKind, pub handle_cycle_error: HandleCycleError, - pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>, - pub query_cache: FieldOffset<QueryCaches<'tcx>, C>, + // Offset of this query's state field in the QueryStates struct + pub query_state: usize, + // Offset of this query's cache field in the QueryCaches struct + pub query_cache: usize, pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e2e2029a362..e5592de81cd 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -11,6 +11,7 @@ use std::cmp::Ordering; use std::fmt; use std::ops::Index; +use std::sync::Arc; use rustc_abi::{FieldIdx, Integer, Size, VariantIdx}; use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece}; @@ -19,20 +20,21 @@ use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::{IndexVec, newtype_index}; use rustc_macros::{HashStable, TypeVisitable}; -use rustc_middle::middle::region; -use rustc_middle::mir::interpret::AllocId; -use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{ - self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, - TyCtxt, UpvarArgs, -}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; use tracing::instrument; +use crate::middle::region; +use crate::mir::interpret::AllocId; +use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; +use crate::ty::adjustment::PointerCoercion; +use crate::ty::layout::IntegerExt; +use crate::ty::{ + self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, + TyCtxt, UpvarArgs, +}; + pub mod visit; macro_rules! thir_with_elements { @@ -92,6 +94,7 @@ thir_with_elements! { pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), + GlobalAsm(Ty<'tcx>), } /// Description of a type-checked function parameter. @@ -374,7 +377,6 @@ pub enum ExprKind<'tcx> { /// A `match` expression. Match { scrutinee: ExprId, - scrutinee_hir_id: HirId, arms: Box<[ArmId]>, match_source: MatchSource, }, @@ -604,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - value: mir::Const<'tcx>, - span: Span, + value: ExprId, }, SymStatic { def_id: DefId, @@ -618,7 +619,7 @@ pub enum InlineAsmOperand<'tcx> { #[derive(Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, - pub pattern: Box<Pat<'tcx>>, + pub pattern: Pat<'tcx>, } #[derive(Debug, HashStable, TypeVisitable)] @@ -677,9 +678,8 @@ impl<'tcx> Pat<'tcx> { 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)) + Array { box prefix, slice, box suffix } | Slice { box prefix, slice, box suffix } => { + prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it)) } } } @@ -836,28 +836,28 @@ pub enum PatKind<'tcx> { subpattern: Box<Pat<'tcx>>, }, - Range(Box<PatRange<'tcx>>), + Range(Arc<PatRange<'tcx>>), /// Matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// e.g., `&[ref xs @ ..]`. Slice { - prefix: Box<[Box<Pat<'tcx>>]>, + prefix: Box<[Pat<'tcx>]>, slice: Option<Box<Pat<'tcx>>>, - suffix: Box<[Box<Pat<'tcx>>]>, + suffix: Box<[Pat<'tcx>]>, }, /// Fixed match against an array; irrefutable. Array { - prefix: Box<[Box<Pat<'tcx>>]>, + prefix: Box<[Pat<'tcx>]>, slice: Option<Box<Pat<'tcx>>>, - suffix: Box<[Box<Pat<'tcx>>]>, + suffix: Box<[Pat<'tcx>]>, }, /// An or-pattern, e.g. `p | q`. /// Invariant: `pats.len() >= 2`. Or { - pats: Box<[Box<Pat<'tcx>>]>, + pats: Box<[Pat<'tcx>]>, }, /// A never pattern `!`. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 13b8af55e51..a9df4d1625b 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -172,7 +172,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } - | SymFn { value: _, span: _ } + | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => visitor.visit_block(&visitor.thir()[*block]), } @@ -194,7 +194,7 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( initializer, remainder_scope: _, init_scope: _, - ref pattern, + pattern, lint_level: _, else_block, span: _, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d0ce4e6242e..d033ecc75db 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -10,9 +10,9 @@ mod structural_impls; use std::borrow::Cow; use std::hash::{Hash, Hasher}; +use std::sync::Arc; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, Diag, EmissionGuarantee}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def_id::DefId; @@ -51,7 +51,7 @@ pub struct ObligationCause<'tcx> { /// information. pub body_id: LocalDefId, - code: InternedObligationCauseCode<'tcx>, + code: ObligationCauseCodeHandle<'tcx>, } // This custom hash function speeds up hashing for `Obligation` deduplication @@ -97,7 +97,7 @@ impl<'tcx> ObligationCause<'tcx> { pub fn map_code( &mut self, - f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>, + f: impl FnOnce(ObligationCauseCodeHandle<'tcx>) -> ObligationCauseCode<'tcx>, ) { self.code = f(std::mem::take(&mut self.code)).into(); } @@ -144,23 +144,16 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeVisitable, TypeFoldable)] -pub struct UnifyReceiverContext<'tcx> { - pub assoc_item: ty::AssocItem, - pub param_env: ty::ParamEnv<'tcx>, - pub args: GenericArgsRef<'tcx>, -} - +/// A compact form of `ObligationCauseCode`. #[derive(Clone, PartialEq, Eq, Default, HashStable)] #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] -pub struct InternedObligationCauseCode<'tcx> { +pub struct ObligationCauseCodeHandle<'tcx> { /// `None` for `ObligationCauseCode::Misc` (a common case, occurs ~60% of /// the time). `Some` otherwise. - code: Option<Lrc<ObligationCauseCode<'tcx>>>, + code: Option<Arc<ObligationCauseCode<'tcx>>>, } -impl<'tcx> std::fmt::Debug for InternedObligationCauseCode<'tcx> { +impl<'tcx> std::fmt::Debug for ObligationCauseCodeHandle<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let cause: &ObligationCauseCode<'_> = self; cause.fmt(f) @@ -169,14 +162,14 @@ impl<'tcx> std::fmt::Debug for InternedObligationCauseCode<'tcx> { impl<'tcx> ObligationCauseCode<'tcx> { #[inline(always)] - fn into(self) -> InternedObligationCauseCode<'tcx> { - InternedObligationCauseCode { - code: if let ObligationCauseCode::Misc = self { None } else { Some(Lrc::new(self)) }, + fn into(self) -> ObligationCauseCodeHandle<'tcx> { + ObligationCauseCodeHandle { + code: if let ObligationCauseCode::Misc = self { None } else { Some(Arc::new(self)) }, } } } -impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { +impl<'tcx> std::ops::Deref for ObligationCauseCodeHandle<'tcx> { type Target = ObligationCauseCode<'tcx>; fn deref(&self) -> &Self::Target { @@ -305,7 +298,7 @@ pub enum ObligationCauseCode<'tcx> { /// The node of the function call. call_hir_id: HirId, /// The obligation introduced by this argument. - parent_code: InternedObligationCauseCode<'tcx>, + parent_code: ObligationCauseCodeHandle<'tcx>, }, /// Error derived when checking an impl item is compatible with @@ -359,8 +352,6 @@ pub enum ObligationCauseCode<'tcx> { /// Method receiver MethodReceiver, - UnifyReceiver(Box<UnifyReceiverContext<'tcx>>), - /// `return` with no expression ReturnNoExpression, @@ -390,7 +381,8 @@ pub enum ObligationCauseCode<'tcx> { /// `WellFormed(None)`. WellFormed(Option<WellFormedLoc>), - /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. + /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching + /// against. MatchImpl(ObligationCause<'tcx>, DefId), BinOp { @@ -413,7 +405,7 @@ pub enum ObligationCauseCode<'tcx> { ConstParam(Ty<'tcx>), /// Obligations emitted during the normalization of a weak type alias. - TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId), + TypeAlias(ObligationCauseCodeHandle<'tcx>, Span, DefId), } /// Whether a value can be extracted into a const. @@ -427,10 +419,6 @@ pub enum IsConstable { Ctor, } -TrivialTypeTraversalAndLiftImpls! { - IsConstable, -} - /// The 'location' at which we try to perform HIR-based wf checking. /// This information is used to obtain an `hir::Ty`, which /// we can walk in order to obtain precise spans for any @@ -518,12 +506,6 @@ impl<'tcx> ObligationCauseCode<'tcx> { #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ObligationCauseCode<'_>, 48); -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum StatementAsExpression { - CorrectType, - NeedsBoxing, -} - #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct MatchExpressionArmCause<'tcx> { @@ -588,7 +570,7 @@ pub struct DerivedCause<'tcx> { pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>, /// The parent trait had this cause. - pub parent_code: InternedObligationCauseCode<'tcx>, + pub parent_code: ObligationCauseCodeHandle<'tcx>, } #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] @@ -596,9 +578,9 @@ pub struct DerivedCause<'tcx> { pub struct ImplDerivedCause<'tcx> { pub derived: DerivedCause<'tcx>, /// The `DefId` of the `impl` that gave rise to the `derived` obligation. - /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl, - /// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle - /// that exceptional case where appropriate. + /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic + /// impl, then this will be the `DefId` of that trait alias. Care should therefore be taken to + /// handle that exceptional case where appropriate. pub impl_or_alias_def_id: DefId, /// The index of the derived predicate in the parent impl's predicates. pub impl_def_predicate_index: Option<usize>, @@ -615,7 +597,7 @@ pub struct DerivedHostCause<'tcx> { pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, /// The parent trait had this cause. - pub parent_code: InternedObligationCauseCode<'tcx>, + pub parent_code: ObligationCauseCodeHandle<'tcx>, } #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] @@ -794,7 +776,7 @@ impl DynCompatibilityViolation { pub fn error_msg(&self) -> Cow<'static, str> { match self { DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - DynCompatibilityViolation::SupertraitSelf(ref spans) => { + DynCompatibilityViolation::SupertraitSelf(spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { "it uses `Self` as a type parameter".into() } else { @@ -1004,4 +986,7 @@ pub enum CodegenObligationError { /// but was included during typeck due to the trivial_bounds feature. Unimplemented, FulfillmentError, + /// The selected impl has unconstrained generic parameters. This will emit an error + /// during impl WF checking. + UnconstrainedParam(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 8cd04a6f5e4..76f3d2bab9c 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -41,11 +41,18 @@ pub mod type_op { pub predicate: Predicate<'tcx>, } + /// Normalizes, but not in the new solver. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct Normalize<T> { pub value: T, } + /// Normalizes, and deeply normalizes in the new solver. + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] + pub struct DeeplyNormalize<T> { + pub value: T, + } + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, @@ -68,18 +75,15 @@ pub type CanonicalPredicateGoal<'tcx> = pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>; -pub type CanonicalTypeOpEqGoal<'tcx> = - CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>; - -pub type CanonicalTypeOpSubtypeGoal<'tcx> = - CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>; - pub type CanonicalTypeOpProvePredicateGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>; pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; +pub type CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T> = + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::DeeplyNormalize<T>>>; + pub type CanonicalImpliedOutlivesBoundsGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ImpliedOutlivesBounds<'tcx>>>; diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 094fc62afbb..811bd8fb458 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -168,6 +168,8 @@ pub enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, BuiltinUnsizeCandidate, + + BikeshedGuaranteedNoDropCandidate, } /// The result of trait evaluation. The order is important @@ -260,8 +262,6 @@ impl From<ErrorGuaranteed> for OverflowError { } } -TrivialTypeTraversalImpls! { OverflowError } - impl<'tcx> From<OverflowError> for SelectionError<'tcx> { fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { match overflow_error { diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index f659bf8125a..9c74f6263b3 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,9 +1,9 @@ -use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; +use crate::ty::visit::try_visit; use crate::ty::{ self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 002d3819621..c9b9ec771b3 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -30,8 +30,6 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable { } } -TrivialTypeTraversalImpls! { NotConstEvaluatable } - pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<'tcx, ty::Const<'tcx>>>, ErrorGuaranteed>; diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index e28fcc555dc..3585f28b4a5 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -4,7 +4,6 @@ use std::ops::Range; use std::str; use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -217,6 +216,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> { self.is_phantom_data() } + fn is_manually_drop(self) -> bool { + self.is_manually_drop() + } + fn all_field_tys( self, tcx: TyCtxt<'tcx>, @@ -536,7 +539,7 @@ impl<'tcx> AdtDef<'tcx> { pub fn discriminants( self, tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> { + ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> { assert!(self.is_enum()); let repr_type = self.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index b1316ceef5a..10f7d589636 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -2,8 +2,8 @@ // typeck and codegen. use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_middle::mir; +use crate::mir; use crate::ty::{self, Ty}; /// Types that are represented as ints. diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index c4d5367e2f0..3605f2402e7 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -1,6 +1,5 @@ use std::fmt::Write; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::HirId; @@ -415,7 +414,7 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( parent_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, -) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> { +) -> impl Iterator<Item = T> { std::iter::from_coroutine( #[coroutine] move || { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 94bf1aa4f03..41958949836 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -13,8 +13,6 @@ use std::marker::DiscriminantKind; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::source_map::Spanned; @@ -23,9 +21,10 @@ pub use rustc_type_ir::{TyDecoder, TyEncoder}; use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance}; +use crate::mir::mono::MonoItem; use crate::mir::{self}; use crate::traits; -use crate::ty::{self, AdtDef, GenericArgsRef, Ty}; +use crate::ty::{self, AdtDef, GenericArgsRef, Ty, TyCtxt}; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -147,6 +146,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ValTree<'tcx> { + fn encode(&self, e: &mut E) { + self.0.0.encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) { self.inner().encode(e) @@ -356,12 +361,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> { } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { - fn decode(decoder: &mut D) -> &'tcx Self { - decoder - .interner() - .arena - .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ValTree<'tcx> { + fn decode(decoder: &mut D) -> Self { + decoder.interner().intern_valtree(Decodable::decode(decoder)) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index d77fb1cc91e..d30520a0222 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -20,7 +20,7 @@ pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>; #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); +rustc_data_structures::static_assert_size!(ConstKind<'_>, 24); #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -190,7 +190,7 @@ impl<'tcx> Const<'tcx> { .size; ty::Const::new_value( tcx, - ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()), + ty::ValTree::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap()), ty, ) } @@ -198,7 +198,7 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - ty::Const::new_value(tcx, ty::ValTree::zst(), ty) + ty::Const::new_value(tcx, ty::ValTree::zst(tcx), ty) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 5905076c4d0..72263d84580 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,4 +1,8 @@ -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use std::fmt; +use std::ops::Deref; + +use rustc_data_structures::intern::Interned; +use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::ScalarInt; use crate::mir::interpret::Scalar; @@ -16,9 +20,9 @@ use crate::ty::{self, Ty, TyCtxt}; /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq)] #[derive(HashStable, TyEncodable, TyDecodable)] -pub enum ValTree<'tcx> { +pub enum ValTreeKind<'tcx> { /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. @@ -33,50 +37,90 @@ pub enum ValTree<'tcx> { /// the fields of the variant. /// /// ZST types are represented as an empty slice. - Branch(&'tcx [ValTree<'tcx>]), + Branch(Box<[ValTree<'tcx>]>), } -impl<'tcx> ValTree<'tcx> { - pub fn zst() -> Self { - Self::Branch(&[]) - } - +impl<'tcx> ValTreeKind<'tcx> { #[inline] - pub fn unwrap_leaf(self) -> ScalarInt { + pub fn unwrap_leaf(&self) -> ScalarInt { match self { - Self::Leaf(s) => s, + Self::Leaf(s) => *s, _ => bug!("expected leaf, got {:?}", self), } } #[inline] - pub fn unwrap_branch(self) -> &'tcx [Self] { + pub fn unwrap_branch(&self) -> &[ValTree<'tcx>] { match self { - Self::Branch(branch) => branch, + Self::Branch(branch) => &**branch, _ => bug!("expected branch, got {:?}", self), } } - pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self { - let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b))); - let interned = tcx.arena.alloc_from_iter(branches); + pub fn try_to_scalar(&self) -> Option<Scalar> { + self.try_to_scalar_int().map(Scalar::Int) + } - Self::Branch(interned) + pub fn try_to_scalar_int(&self) -> Option<ScalarInt> { + match self { + Self::Leaf(s) => Some(*s), + Self::Branch(_) => None, + } } - pub fn from_scalar_int(i: ScalarInt) -> Self { - Self::Leaf(i) + pub fn try_to_branch(&self) -> Option<&[ValTree<'tcx>]> { + match self { + Self::Branch(branch) => Some(&**branch), + Self::Leaf(_) => None, + } } +} - pub fn try_to_scalar(self) -> Option<Scalar> { - self.try_to_scalar_int().map(Scalar::Int) +/// An interned valtree. Use this rather than `ValTreeKind`, whenever possible. +/// +/// See the docs of [`ValTreeKind`] or the [dev guide] for an explanation of this type. +/// +/// [dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html#valtrees +#[derive(Copy, Clone, Hash, Eq, PartialEq)] +#[derive(HashStable)] +pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ValTreeKind<'tcx>>); + +impl<'tcx> ValTree<'tcx> { + /// Returns the zero-sized valtree: `Branch([])`. + pub fn zst(tcx: TyCtxt<'tcx>) -> Self { + tcx.consts.valtree_zst } - pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - match self { - Self::Leaf(s) => Some(s), - Self::Branch(_) => None, - } + pub fn is_zst(self) -> bool { + matches!(*self, ValTreeKind::Branch(box [])) + } + + pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self { + let branches = bytes.iter().map(|&b| Self::from_scalar_int(tcx, b.into())); + Self::from_branches(tcx, branches) + } + + pub fn from_branches(tcx: TyCtxt<'tcx>, branches: impl IntoIterator<Item = Self>) -> Self { + tcx.intern_valtree(ValTreeKind::Branch(branches.into_iter().collect())) + } + + pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self { + tcx.intern_valtree(ValTreeKind::Leaf(i)) + } +} + +impl<'tcx> Deref for ValTree<'tcx> { + type Target = &'tcx ValTreeKind<'tcx>; + + #[inline] + fn deref(&self) -> &&'tcx ValTreeKind<'tcx> { + &self.0.0 + } +} + +impl fmt::Debug for ValTree<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) } } @@ -84,7 +128,7 @@ impl<'tcx> ValTree<'tcx> { /// /// Represents a typed, fully evaluated constant. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)] pub struct Value<'tcx> { pub ty: Ty<'tcx>, pub valtree: ValTree<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 86248b495cd..238ba127e2e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -10,7 +10,7 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Bound, Deref}; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock}; use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; @@ -24,7 +24,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, DynSend, DynSync, FreezeReadGuard, Lock, Lrc, RwLock, WorkerLocal, + self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_data_structures::unord::UnordSet; use rustc_errors::{ @@ -76,11 +76,11 @@ use crate::traits::solve::{ }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, BoundConstness, Clause, Clauses, Const, GenericArg, - GenericArgs, GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, - ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, - PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, - TyKind, TyVid, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, + GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, ParamTy, + Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, + PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, + ValTree, ValTreeKind, Visibility, }; #[allow(rustc::usage_of_ty_tykind)] @@ -194,6 +194,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.variances_of(def_id) } + fn opt_alias_variances( + self, + kind: impl Into<ty::AliasTermKind>, + def_id: DefId, + ) -> Option<&'tcx [ty::Variance]> { + self.opt_alias_variances(kind, def_id) + } + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of(def_id) } @@ -682,6 +690,7 @@ bidirectional_lang_item_map! { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, @@ -798,6 +807,7 @@ pub struct CtxtInterners<'tcx> { local_def_ids: InternedSet<'tcx, List<LocalDefId>>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, + valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -827,6 +837,7 @@ impl<'tcx> CtxtInterners<'tcx> { local_def_ids: Default::default(), captures: Default::default(), offset_of: Default::default(), + valtree: Default::default(), } } @@ -1018,6 +1029,8 @@ pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, pub true_: Const<'tcx>, pub false_: Const<'tcx>, + /// Use [`ty::ValTree::zst`] instead. + pub(crate) valtree_zst: ValTree<'tcx>, } impl<'tcx> CommonTypes<'tcx> { @@ -1086,10 +1099,13 @@ impl<'tcx> CommonLifetimes<'tcx> { .map(|i| { (0..NUM_PREINTERNED_RE_LATE_BOUNDS_V) .map(|v| { - mk(ty::ReBound(ty::DebruijnIndex::from(i), ty::BoundRegion { - var: ty::BoundVar::from(v), - kind: ty::BoundRegionKind::Anon, - })) + mk(ty::ReBound( + ty::DebruijnIndex::from(i), + ty::BoundRegion { + var: ty::BoundVar::from(v), + kind: ty::BoundRegionKind::Anon, + }, + )) }) .collect() }) @@ -1118,19 +1134,30 @@ impl<'tcx> CommonConsts<'tcx> { ) }; + let mk_valtree = |v| { + ty::ValTree(Interned::new_unchecked( + interners.valtree.intern(v, |v| InternedInSet(interners.arena.alloc(v))).0, + )) + }; + + let valtree_zst = mk_valtree(ty::ValTreeKind::Branch(Box::default())); + let valtree_true = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::TRUE)); + let valtree_false = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::FALSE)); + CommonConsts { unit: mk_const(ty::ConstKind::Value(ty::Value { ty: types.unit, - valtree: ty::ValTree::zst(), + valtree: valtree_zst, })), true_: mk_const(ty::ConstKind::Value(ty::Value { ty: types.bool, - valtree: ty::ValTree::Leaf(ty::ScalarInt::TRUE), + valtree: valtree_true, })), false_: mk_const(ty::ConstKind::Value(ty::Value { ty: types.bool, - valtree: ty::ValTree::Leaf(ty::ScalarInt::FALSE), + valtree: valtree_false, })), + valtree_zst, } } } @@ -1290,9 +1317,6 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } -// Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. -unsafe impl DynSend for TyCtxt<'_> {} -unsafe impl DynSync for TyCtxt<'_> {} fn _assert_tcx_fields() { sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>(); sync::assert_dyn_send::<&'_ GlobalCtxt<'_>>(); @@ -1346,7 +1370,6 @@ pub struct GlobalCtxt<'tcx> { // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>, - pub pred_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Predicate<'tcx>>>, /// Caches the results of trait selection. This cache is used /// for things that do not have to do with the parameters in scope. @@ -1406,7 +1429,7 @@ impl<'tcx> GlobalCtxt<'tcx> { pub struct CurrentGcx { /// This stores a pointer to a `GlobalCtxt`. This is set to `Some` inside `GlobalCtxt::enter` /// and reset to `None` when that function returns or unwinds. - value: Lrc<RwLock<Option<*const ()>>>, + value: Arc<RwLock<Option<*const ()>>>, } unsafe impl DynSend for CurrentGcx {} @@ -1414,7 +1437,7 @@ unsafe impl DynSync for CurrentGcx {} impl CurrentGcx { pub fn new() -> Self { - Self { value: Lrc::new(RwLock::new(None)) } + Self { value: Arc::new(RwLock::new(None)) } } pub fn access<R>(&self, f: impl for<'tcx> FnOnce(&'tcx GlobalCtxt<'tcx>) -> R) -> R { @@ -1449,7 +1472,11 @@ impl<'tcx> TyCtxt<'tcx> { self.codegen_fn_attrs(def_id) } else if matches!( def_kind, - DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst + DefKind::AnonConst + | DefKind::AssocConst + | DefKind::Const + | DefKind::InlineConst + | DefKind::GlobalAsm ) { CodegenFnAttrs::EMPTY } else { @@ -1577,7 +1604,6 @@ impl<'tcx> TyCtxt<'tcx> { query_system, query_kinds, ty_rcache: Default::default(), - pred_rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), new_solver_evaluation_cache: Default::default(), @@ -1917,7 +1943,7 @@ impl<'tcx> TyCtxt<'tcx> { Ok(TyCtxtFeed { key: num, tcx: self }) } - pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx { + pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> { // Create a dependency to the red node to be sure we re-execute this when the amount of // definitions change. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); @@ -2055,7 +2081,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.local_def_id_to_hir_id(scope_def_id); let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = - self.hir().fn_decl_by_hir_id(hir_id) + self.hir_fn_decl_by_hir_id(hir_id) else { return vec![]; }; @@ -2075,7 +2101,7 @@ impl<'tcx> TyCtxt<'tcx> { let hir_id = self.local_def_id_to_hir_id(scope_def_id); let mut v = TraitObjectVisitor(vec![], self.hir()); // when the return type is a type alias - if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) + if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id) && let hir::TyKind::Path(hir::QPath::Resolved( None, hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind @@ -2144,15 +2170,19 @@ impl<'tcx> TyCtxt<'tcx> { self.limits(()).move_size_limit } + pub fn pattern_complexity_limit(self) -> Limit { + self.limits(()).pattern_complexity_limit + } + /// All traits in the crate graph, including those not visible to the user. - pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { + pub fn all_traits(self) -> impl Iterator<Item = DefId> { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) } /// All traits that are visible within the crate graph (i.e. excluding private dependencies). - pub fn visible_traits(self) -> impl Iterator<Item = DefId> + 'tcx { + pub fn visible_traits(self) -> impl Iterator<Item = DefId> { let visible_crates = self.crates(()).iter().copied().filter(move |cnum| self.is_user_visible_dep(*cnum)); @@ -2243,45 +2273,24 @@ macro_rules! nop_list_lift { }; } -nop_lift! {type_; Ty<'a> => Ty<'tcx>} -nop_lift! {region; Region<'a> => Region<'tcx>} -nop_lift! {const_; Const<'a> => Const<'tcx>} -nop_lift! {pat; Pattern<'a> => Pattern<'tcx>} -nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} -nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} -nop_lift! {predicate; Clause<'a> => Clause<'tcx>} -nop_lift! {layout; Layout<'a> => Layout<'tcx>} - -nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>} -nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>} -nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind} - -// This is the impl for `&'a GenericArgs<'a>`. -nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>} - -macro_rules! nop_slice_lift { - ($ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for &'a [$ty] { - type Lifted = &'tcx [$lifted]; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if self.is_empty() { - return Some(&[]); - } - tcx.interners - .arena - .dropless - .contains_slice(self) - .then(|| unsafe { mem::transmute(self) }) - } - } - }; +nop_lift! { type_; Ty<'a> => Ty<'tcx> } +nop_lift! { region; Region<'a> => Region<'tcx> } +nop_lift! { const_; Const<'a> => Const<'tcx> } +nop_lift! { pat; Pattern<'a> => Pattern<'tcx> } +nop_lift! { const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx> } +nop_lift! { predicate; Predicate<'a> => Predicate<'tcx> } +nop_lift! { predicate; Clause<'a> => Clause<'tcx> } +nop_lift! { layout; Layout<'a> => Layout<'tcx> } +nop_lift! { valtree; ValTree<'a> => ValTree<'tcx> } + +nop_list_lift! { type_lists; Ty<'a> => Ty<'tcx> } +nop_list_lift! { + poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx> } +nop_list_lift! { bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind } -nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} - -TrivialLiftImpls! { - ImplPolarity, PredicatePolarity, Promoted, BoundConstness, -} +// This is the impl for `&'a GenericArgs<'a>`. +nop_list_lift! { args; GenericArg<'a> => GenericArg<'tcx> } macro_rules! sty_debug_print { ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{ @@ -2358,7 +2367,7 @@ macro_rules! sty_debug_print { } impl<'tcx> TyCtxt<'tcx> { - pub fn debug_stats(self) -> impl fmt::Debug + 'tcx { + pub fn debug_stats(self) -> impl fmt::Debug { fmt::from_fn(move |fmt| { sty_debug_print!( fmt, @@ -2527,6 +2536,7 @@ macro_rules! direct_interners { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + valtree: pub(crate) intern_valtree(ValTreeKind<'tcx>): ValTree -> ValTree<'tcx>, pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutData<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>, @@ -3011,7 +3021,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Find the crate root and the appropriate span where `use` and outer attributes can be /// inserted at. pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option<Span> { - for (_hir_id, node) in self.hir().parent_iter(hir_id) { + for (_hir_id, node) in self.hir_parent_iter(hir_id) { if let hir::Node::Crate(m) = node { return Some(m.spans.inject_use_span.shrink_to_lo()); } @@ -3140,12 +3150,15 @@ impl<'tcx> TyCtxt<'tcx> { } let generics = self.generics_of(new_parent); - return ty::Region::new_early_param(self, ty::EarlyParamRegion { - index: generics - .param_def_id_to_index(self, ebv.to_def_id()) - .expect("early-bound var should be present in fn generics"), - name: self.item_name(ebv.to_def_id()), - }); + return ty::Region::new_early_param( + self, + ty::EarlyParamRegion { + index: generics + .param_def_id_to_index(self, ebv.to_def_id()) + .expect("early-bound var should be present in fn generics"), + name: self.item_name(ebv.to_def_id()), + }, + ); } resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv) => { let new_parent = self.local_parent(lbv); @@ -3224,7 +3237,7 @@ impl<'tcx> TyCtxt<'tcx> { self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]) } - pub fn resolver_for_lowering(self) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> { + pub fn resolver_for_lowering(self) -> &'tcx Steal<(ty::ResolverAstLowering, Arc<ast::Crate>)> { self.resolver_for_lowering_raw(()).0 } @@ -3286,9 +3299,9 @@ pub fn provide(providers: &mut Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); providers.is_panic_runtime = - |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + |tcx, LocalCrate| contains_name(tcx.hir_krate_attrs(), sym::panic_runtime); providers.is_compiler_builtins = - |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + |tcx, LocalCrate| 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().is_some_and(|did| did.is_local()) diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 067516917ef..4ea4050ed8b 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -280,21 +280,26 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars); - self.replace_escaping_bound_vars_uncached(value, FnMutDelegate { - regions: &mut |r: ty::BoundRegion| { - ty::Region::new_bound(self, ty::INNERMOST, ty::BoundRegion { - var: shift_bv(r.var), - kind: r.kind, - }) + self.replace_escaping_bound_vars_uncached( + value, + FnMutDelegate { + regions: &mut |r: ty::BoundRegion| { + ty::Region::new_bound( + self, + ty::INNERMOST, + ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, + ) + }, + types: &mut |t: ty::BoundTy| { + Ty::new_bound( + self, + ty::INNERMOST, + ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, + ) + }, + consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), }, - types: &mut |t: ty::BoundTy| { - Ty::new_bound(self, ty::INNERMOST, ty::BoundTy { - var: shift_bv(t.var), - kind: t.kind, - }) - }, - consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), - }) + ) } /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index fd84d75b53f..ed0b3059d75 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -6,8 +6,6 @@ use std::mem; use std::num::NonZero; use std::ptr::NonNull; -use rustc_ast_ir::visit::VisitorResult; -use rustc_ast_ir::walk_visitable_list; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; @@ -18,7 +16,7 @@ use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::visit::{TypeVisitable, TypeVisitor}; +use crate::ty::visit::{TypeVisitable, TypeVisitor, VisitorResult, walk_visitable_list}; use crate::ty::{ self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt, }; @@ -481,25 +479,23 @@ impl<'tcx> GenericArgs<'tcx> { } #[inline] - pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx { + pub fn types(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> { self.iter().filter_map(|k| k.as_type()) } #[inline] - pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx { + pub fn regions(&self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> { self.iter().filter_map(|k| k.as_region()) } #[inline] - pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx { + pub fn consts(&self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> { self.iter().filter_map(|k| k.as_const()) } - /// Returns generic arguments that are not lifetimes or host effect params. + /// Returns generic arguments that are not lifetimes. #[inline] - pub fn non_erasable_generics( - &'tcx self, - ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx { + pub fn non_erasable_generics(&self) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> { self.iter().filter_map(|k| match k.unpack() { ty::GenericArgKind::Lifetime(_) => None, generic => Some(generic), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b7a648aae3f..e9c19331e4a 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -10,13 +10,13 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::FiniteBitSet; use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; -use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::{debug, instrument}; use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::print::{FmtPrinter, Printer, shrunk_instance_name}; use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3ced64b5b80..eb14ed20fba 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -11,6 +11,7 @@ use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; +use rustc_hashes::Hash64; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; @@ -24,7 +25,6 @@ use rustc_target::spec::{ use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; -use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; @@ -229,11 +229,32 @@ impl fmt::Display for ValidityRequirement { #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub enum LayoutError<'tcx> { + /// A type doesn't have a sensible layout. + /// + /// This variant is used for layout errors that don't necessarily cause + /// compile errors. + /// + /// For example, this can happen if a struct contains an unsized type in a + /// non-tail field, but has an unsatisfiable bound like `str: Sized`. Unknown(Ty<'tcx>), + /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`]. SizeOverflow(Ty<'tcx>), + /// The layout can vary due to a generic parameter. + /// + /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout + /// may become computable after further instantiating the generic parameter(s). TooGeneric(Ty<'tcx>), + /// An alias failed to normalize. + /// + /// This variant is necessary, because, due to trait solver incompleteness, it is + /// possible than an alias that was rigid during analysis fails to normalize after + /// revealing opaque types. + /// + /// See `tests/ui/layout/normalization-failure.rs` for an example. NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), + /// A non-layout error is reported elsewhere. ReferencesError(ErrorGuaranteed), + /// A type has cyclic layout, i.e. the type contains itself without indirection. Cycle(ErrorGuaranteed), } @@ -243,11 +264,11 @@ impl<'tcx> LayoutError<'tcx> { use crate::fluent_generated::*; match self { - Unknown(_) => middle_unknown_layout, - SizeOverflow(_) => middle_values_too_big, - TooGeneric(_) => middle_too_generic, - NormalizationFailure(_, _) => middle_cannot_be_normalized, - Cycle(_) => middle_cycle, + Unknown(_) => middle_layout_unknown, + SizeOverflow(_) => middle_layout_size_overflow, + TooGeneric(_) => middle_layout_too_generic, + NormalizationFailure(_, _) => middle_layout_normalization_failure, + Cycle(_) => middle_layout_cycle, ReferencesError(_) => middle_layout_references_error, } } @@ -276,7 +297,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"), LayoutError::TooGeneric(ty) => { - write!(f, "`{ty}` does not have a fixed size") + write!(f, "the type `{ty}` does not have a fixed layout") } LayoutError::SizeOverflow(ty) => { write!(f, "values of the type `{ty}` are too big for the target architecture") @@ -369,7 +390,7 @@ impl<'tcx> SizeSkeleton<'tcx> { match *ty.kind() { ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { - let non_zero = !ty.is_unsafe_ptr(); + let non_zero = !ty.is_raw_ptr(); let tail = tcx.struct_tail_raw( pointee, @@ -773,13 +794,14 @@ where Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, - backend_repr: BackendRepr::Uninhabited, + backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, + uninhabited: true, align: tcx.data_layout.i8_align, size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: tcx.data_layout.i8_align.abi, - randomization_seed: 0, + randomization_seed: Hash64::ZERO, }) } @@ -841,7 +863,7 @@ where // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { let nil = tcx.types.unit; - let unit_ptr_ty = if this.ty.is_unsafe_ptr() { + let unit_ptr_ty = if this.ty.is_raw_ptr() { Ty::new_mut_ptr(tcx, nil) } else { Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil) @@ -1275,18 +1297,12 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) pub enum FnAbiError<'tcx> { /// Error produced by a `layout_of` call, while computing `FnAbi` initially. Layout(LayoutError<'tcx>), - - /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. - AdjustForForeignAbi(rustc_target::callconv::AdjustForForeignAbiError), } impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level), - Self::AdjustForForeignAbi( - rustc_target::callconv::AdjustForForeignAbiError::Unsupported { arch, abi }, - ) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diag(dcx, level), } } } @@ -1369,10 +1385,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { // `def_span` unconditionally (which may have a perf penalty). let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; - self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance { - instance, - extra_args, - }) + self.handle_fn_abi_err( + *err, + span, + FnAbiRequest::OfInstance { instance, extra_args }, + ) }), ) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 88eea6101b5..8ed5a118093 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,6 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -48,7 +47,7 @@ pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::*; +pub use rustc_type_ir::{Movability, Mutability, *}; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; @@ -60,7 +59,8 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, Value, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, + Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, @@ -94,7 +94,7 @@ pub use self::sty::{ pub use self::trait_def::TraitDef; pub use self::typeck_results::{ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, - TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, + Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, }; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; @@ -179,7 +179,7 @@ pub struct ResolverGlobalCtxt { pub confused_type_with_std_module: FxIndexMap<Span, Span>, pub doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>, pub doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>, - pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, + pub all_macro_rules: FxHashSet<Symbol>, pub stripped_cfg_items: Steal<Vec<StrippedCfgItem>>, } @@ -1469,7 +1469,7 @@ pub enum ImplTraitInTraitData { impl<'tcx> TyCtxt<'tcx> { pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> { - self.typeck(self.hir().body_owner_def_id(body)) + self.typeck(self.hir_body_owner_def_id(body)) } pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> { @@ -1486,8 +1486,7 @@ impl<'tcx> TyCtxt<'tcx> { // Generate a deterministically-derived seed from the item's path hash // to allow for cross-crate compilation to actually work - let mut field_shuffle_seed = - self.def_path_hash(did.to_def_id()).0.to_smaller_hash().as_u64(); + let mut field_shuffle_seed = self.def_path_hash(did.to_def_id()).0.to_smaller_hash(); // If the user defined a custom seed for layout randomization, xor the item's // path hash with the user defined seed, this will allowing determinism while @@ -1799,14 +1798,11 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn get_attrs_by_path<'attr>( + pub fn get_attrs_by_path( self, did: DefId, - attr: &'attr [Symbol], - ) -> impl Iterator<Item = &'tcx hir::Attribute> + 'attr - where - 'tcx: 'attr, - { + attr: &[Symbol], + ) -> impl Iterator<Item = &'tcx hir::Attribute> { let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) @@ -2167,7 +2163,6 @@ pub fn provide(providers: &mut Providers) { util::provide(providers); print::provide(providers); super::util::bug::provide(providers); - super::middle::provide(providers); *providers = Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 584cac22ae8..553de83dfcb 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -1,6 +1,5 @@ use std::cmp::Ordering; -use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, extension}; @@ -336,9 +335,9 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { } #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> + 'a { + pub fn projection_bounds( + &self, + ) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> { self.iter().filter_map(|predicate| { predicate .map_bound(|pred| match pred { @@ -350,16 +349,14 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { } #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'a { + pub fn auto_traits(&self) -> impl Iterator<Item = DefId> { self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) } - pub fn without_auto_traits( - &self, - ) -> impl Iterator<Item = ty::PolyExistentialPredicate<'tcx>> + '_ { + pub fn without_auto_traits(&self) -> impl Iterator<Item = ty::PolyExistentialPredicate<'tcx>> { self.iter().filter(|predicate| { !matches!(predicate.as_ref().skip_binder(), ExistentialPredicate::AutoTrait(_)) }) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3431081b189..ed0839f47e6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -232,7 +232,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { f: F, ) -> Result<(), PrintError> where - T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, + T: TypeFoldable<TyCtxt<'tcx>>, { f(value.as_ref().skip_binder(), self) } @@ -1056,7 +1056,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; - for ((bound_args, is_async), entry) in fn_traits { + for ((bound_args_and_self_ty, is_async), entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if paren_needed { "(" } else { "" })?; @@ -1067,7 +1067,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }; if let Some(return_ty) = entry.return_ty { - self.wrap_binder(&bound_args, |args, cx| { + self.wrap_binder(&bound_args_and_self_ty, |(args, _), cx| { define_scoped_cx!(cx); p!(write("{}", tcx.item_name(trait_def_id))); p!("("); @@ -1093,9 +1093,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } else { // Otherwise, render this like a regular trait. traits.insert( - bound_args.map_bound(|args| ty::TraitPredicate { + bound_args_and_self_ty.map_bound(|(args, self_ty)| ty::TraitPredicate { polarity: ty::PredicatePolarity::Positive, - trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]), + trait_ref: ty::TraitRef::new( + tcx, + trait_def_id, + [self_ty, Ty::new_tup(tcx, args)], + ), }), FxIndexMap::default(), ); @@ -1229,7 +1233,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>, >, fn_traits: &mut FxIndexMap< - (ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>, bool), + (ty::Binder<'tcx, (&'tcx ty::List<Ty<'tcx>>, Ty<'tcx>)>, bool), OpaqueFnEntry<'tcx>, >, ) { @@ -1249,7 +1253,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind() { let entry = fn_traits - .entry((trait_pred.rebind(types), is_async)) + .entry((trait_pred.rebind((types, trait_pred.skip_binder().self_ty())), is_async)) .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None }); if kind.extends(entry.kind) { entry.kind = kind; @@ -1512,7 +1516,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ExprKind::Binop(op) => { let (_, _, c1, c2) = expr.binop_args(); - let precedence = |binop: rustc_middle::mir::BinOp| { + let precedence = |binop: crate::mir::BinOp| { use rustc_ast::util::parser::AssocOp; AssocOp::from_ast_binop(binop.to_hir_binop()).precedence() }; @@ -1558,7 +1562,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ExprKind::UnOp(op) => { let (_, ct) = expr.unop_args(); - use rustc_middle::mir::UnOp; + use crate::mir::UnOp; let formatted_op = match op { UnOp::Not => "!", UnOp::Neg => "-", @@ -1639,14 +1643,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { - if let ty::Array(elem, len) = inner.kind() + if let ty::Array(elem, ct_len) = inner.kind() && let ty::Uint(ty::UintTy::U8) = elem.kind() - && let ty::ConstKind::Value(cv) = len.kind() - && let ty::ValTree::Leaf(int) = cv.valtree + && let Some(len) = ct_len.try_to_target_usize(self.tcx()) { match self.tcx().try_get_global_alloc(prov.alloc_id()) { Some(GlobalAlloc::Memory(alloc)) => { - let len = int.to_bits(self.tcx().data_layout.pointer_size); let range = AllocRange { start: offset, size: Size::from_bytes(len) }; if let Ok(byte_str) = alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) @@ -1741,7 +1743,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { " as ", )?; } - ty::Pat(base_ty, pat) => { + ty::Pat(base_ty, pat) if self.tcx().validate_scalar_in_layout(int, ty) => { self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?; p!(write(" is {pat:?}")); } @@ -1800,8 +1802,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } let u8_type = self.tcx().types.u8; - match (cv.valtree, cv.ty.kind()) { - (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { + match (*cv.valtree, *cv.ty.kind()) { + (ty::ValTreeKind::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { ty::Slice(t) if *t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!( @@ -1820,13 +1822,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } _ => { - let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty }; + let cv = ty::Value { valtree: cv.valtree, ty: inner_ty }; p!("&"); p!(pretty_print_const_valtree(cv, print_ty)); return Ok(()); } }, - (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { + (ty::ValTreeKind::Branch(_), ty::Array(t, _)) if t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); @@ -1835,7 +1837,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } // Aggregates, printed as array/tuple/struct/variant construction syntax. - (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { + (ty::ValTreeKind::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { let contents = self.tcx().destructure_const(ty::Const::new_value( self.tcx(), cv.valtree, @@ -1891,12 +1893,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } return Ok(()); } - (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { + (ty::ValTreeKind::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { p!(write("&")); - return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + return self.pretty_print_const_scalar_int(*leaf, inner_ty, print_ty); } - (ty::ValTree::Leaf(leaf), _) => { - return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty); + (ty::ValTreeKind::Leaf(leaf), _) => { + return self.pretty_print_const_scalar_int(*leaf, cv.ty, print_ty); + } + (_, ty::FnDef(def_id, args)) => { + // Never allowed today, but we still encounter them in invalid const args. + p!(print_value_path(def_id, args)); + return Ok(()); } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. @@ -1904,7 +1911,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // fallback - if cv.valtree == ty::ValTree::zst() { + if cv.valtree.is_zst() { p!(write("<ZST>")); } else { p!(write("{:?}", cv.valtree)); @@ -2376,7 +2383,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { f: C, ) -> Result<(), PrintError> where - T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, + T: TypeFoldable<TyCtxt<'tcx>>, { self.pretty_wrap_binder(value, f) } @@ -2630,7 +2637,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { value: &ty::Binder<'tcx, T>, ) -> Result<(T, UnordMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error> where - T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, + T: TypeFoldable<TyCtxt<'tcx>>, { fn name_by_region_index( index: usize, @@ -2811,7 +2818,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { f: C, ) -> Result<(), fmt::Error> where - T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, + T: TypeFoldable<TyCtxt<'tcx>>, { let old_region_index = self.region_index; let (new_value, _) = self.name_all_regions(value)?; @@ -3296,13 +3303,12 @@ define_print_and_forward_display! { fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) { // Iterate all local crate items no matter where they are defined. - let hir = tcx.hir(); - for id in hir.items() { + for id in tcx.hir_free_items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Use) { continue; } - let item = hir.item(id); + let item = tcx.hir_item(id); if item.ident.name == kw::Empty { continue; } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index afdec7a86d4..839c1c346a4 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -79,20 +79,14 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate< b: Self, ) -> RelateResult<'tcx, Self> { let tcx = relation.cx(); - - // FIXME: this is wasteful, but want to do a perf run to see how slow it is. - // We need to perform this deduplication as we sometimes generate duplicate projections - // in `a`. - let mut a_v: Vec<_> = a.into_iter().collect(); - let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.dedup(); - b_v.dedup(); - if a_v.len() != b_v.len() { + // Fast path for when the auto traits do not match, or if the principals + // are from different traits and therefore the projections definitely don't + // match up. + if a.len() != b.len() { return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); } - - let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { - match (ep_a.skip_binder(), ep_b.skip_binder()) { + let v = + iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) { (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), @@ -109,8 +103,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate< ty::ExistentialPredicate::AutoTrait(b), ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))), - } - }); + }); tcx.mk_poly_existential_predicates_from_iter(v) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 03b26b44538..db9e9fbc643 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -6,15 +6,17 @@ use std::fmt::{self, Debug}; use rustc_abi::TyAndLayout; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; +use rustc_ast::InlineAsmTemplatePiece; use rustc_hir::def::Namespace; +use rustc_hir::def_id::LocalDefId; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_type_ir::ConstKind; +use rustc_type_ir::visit::{VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; -use crate::mir::interpret; +use crate::mir::PlaceElem; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -162,13 +164,9 @@ impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If this is a value, we spend some effort to make it look nice. - if let ConstKind::Value(_) = self.kind() { + if let ConstKind::Value(cv) = self.kind() { return ty::tls::with(move |tcx| { - // ValTrees aren't interned, so we lift the entire constant. - let lifted = tcx.lift(*self).unwrap(); - let ConstKind::Value(cv) = lifted.kind() else { - bug!("we checked that this is a valtree") - }; + let cv = tcx.lift(cv).unwrap(); let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); cx.pretty_print_const_valtree(cv, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) @@ -221,76 +219,89 @@ impl<'tcx> fmt::Debug for Region<'tcx> { // copy...), just add them to one of these lists as appropriate. // For things for which the type library provides traversal implementations -// for all Interners, we only need to provide a Lift implementation: +// for all Interners, we only need to provide a Lift implementation. TrivialLiftImpls! { - (), - bool, - usize, - u64, + (), + bool, + usize, + u64, + // tidy-alphabetical-start + crate::mir::interpret::AllocId, + crate::mir::interpret::Scalar, + crate::mir::Promoted, + rustc_abi::ExternAbi, + rustc_abi::Size, + rustc_hir::Safety, + rustc_type_ir::BoundConstness, + rustc_type_ir::PredicatePolarity, + // tidy-alphabetical-end } // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal // implementation (only for TyCtxt<'_> interners). TrivialTypeTraversalImpls! { - ::rustc_abi::FieldIdx, - ::rustc_abi::VariantIdx, - crate::middle::region::Scope, - ::rustc_ast::InlineAsmOptions, - ::rustc_ast::InlineAsmTemplatePiece, - ::rustc_ast::NodeId, - ::rustc_hir::def::Res, - ::rustc_hir::def_id::LocalDefId, - ::rustc_hir::ByRef, - ::rustc_hir::HirId, - ::rustc_hir::MatchSource, - ::rustc_target::asm::InlineAsmRegOrRegClass, - crate::mir::coverage::BlockMarkerId, - crate::mir::coverage::CounterId, - crate::mir::coverage::ExpressionId, - crate::mir::coverage::ConditionId, + // tidy-alphabetical-start + crate::infer::canonical::Certainty, + crate::mir::BasicBlock, + crate::mir::BindingForm<'tcx>, + crate::mir::BlockTailInfo, + crate::mir::BorrowKind, + crate::mir::CastKind, + crate::mir::ConstValue<'tcx>, + crate::mir::CoroutineSavedLocal, + crate::mir::FakeReadCause, crate::mir::Local, + crate::mir::MirPhase, + crate::mir::NullOp<'tcx>, crate::mir::Promoted, + crate::mir::RawPtrKind, + crate::mir::RetagKind, + crate::mir::SourceInfo, + crate::mir::SourceScope, + crate::mir::SourceScopeLocalData, + crate::mir::SwitchTargets, + crate::traits::IsConstable, + crate::traits::OverflowError, + crate::ty::abstract_const::NotConstEvaluatable, crate::ty::adjustment::AutoBorrowMutability, + crate::ty::adjustment::PointerCoercion, crate::ty::AdtKind, - crate::ty::BoundRegion, - // Including `BoundRegionKind` is a *bit* dubious, but direct - // references to bound region appear in `ty::Error`, and aren't - // really meant to be folded. In general, we can only fold a fully - // general `Region`. - crate::ty::BoundRegionKind, crate::ty::AssocItem, crate::ty::AssocKind, + crate::ty::BoundRegion, + crate::ty::BoundVar, crate::ty::Placeholder<crate::ty::BoundRegion>, crate::ty::Placeholder<crate::ty::BoundTy>, crate::ty::Placeholder<ty::BoundVar>, - crate::ty::LateParamRegion, - crate::ty::adjustment::PointerCoercion, - ::rustc_span::Ident, - ::rustc_span::Span, - ::rustc_span::Symbol, - ty::BoundVar, - ty::ValTree<'tcx>, + crate::ty::UserTypeAnnotationIndex, + crate::ty::ValTree<'tcx>, + rustc_abi::FieldIdx, + rustc_abi::VariantIdx, + rustc_ast::InlineAsmOptions, + rustc_ast::InlineAsmTemplatePiece, + rustc_hir::CoroutineKind, + rustc_hir::def_id::LocalDefId, + rustc_hir::HirId, + rustc_hir::MatchSource, + rustc_span::Ident, + rustc_span::Span, + rustc_span::Symbol, + rustc_target::asm::InlineAsmRegOrRegClass, + // tidy-alphabetical-end } + // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal // implementation and a lift implementation (the former only for TyCtxt<'_> // interners). TrivialTypeTraversalAndLiftImpls! { - ::rustc_hir::def_id::DefId, - crate::ty::ClosureKind, + // tidy-alphabetical-start + crate::ty::instance::ReifyReason, crate::ty::ParamConst, crate::ty::ParamTy, - crate::ty::instance::ReifyReason, - interpret::AllocId, - interpret::CtfeProvenance, - interpret::Scalar, - rustc_abi::Size, -} - -TrivialLiftImpls! { - ::rustc_hir::Safety, - ::rustc_abi::ExternAbi, + rustc_hir::def_id::DefId, + // tidy-alphabetical-end } /////////////////////////////////////////////////////////////////////////// @@ -436,23 +447,23 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, args) => args.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg, _) => { + ty::Dynamic(trait_ty, reg, _) => { try_visit!(trait_ty.visit_with(visitor)); reg.visit_with(visitor) } ty::Tuple(ts) => ts.visit_with(visitor), ty::FnDef(_, args) => args.visit_with(visitor), - ty::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor), - ty::UnsafeBinder(ref f) => f.visit_with(visitor), + ty::FnPtr(sig_tys, _) => sig_tys.visit_with(visitor), + ty::UnsafeBinder(f) => f.visit_with(visitor), ty::Ref(r, ty, _) => { try_visit!(r.visit_with(visitor)); ty.visit_with(visitor) } - ty::Coroutine(_did, ref args) => args.visit_with(visitor), - ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor), - ty::Closure(_did, ref args) => args.visit_with(visitor), - ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor), - ty::Alias(_, ref data) => data.visit_with(visitor), + ty::Coroutine(_did, args) => args.visit_with(visitor), + ty::CoroutineWitness(_did, args) => args.visit_with(visitor), + ty::Closure(_did, args) => args.visit_with(visitor), + ty::CoroutineClosure(_did, args) => args.visit_with(visitor), + ty::Alias(_, data) => data.visit_with(visitor), ty::Pat(ty, pat) => { try_visit!(ty.visit_with(visitor)); @@ -672,3 +683,39 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Debug + Clone> TypeFoldable<TyCtxt<'t }) } } + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + _folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + _folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<LocalDefId> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + _folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v)) + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a9a47c87a38..d5617adf26b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -9,7 +9,6 @@ use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx}; -use rustc_data_structures::captures::Captures; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::LangItem; @@ -18,7 +17,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate}; use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -105,7 +104,7 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> { self, def_id: DefId, tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> { + ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> { self.variant_range(def_id, tcx).map(move |index| { (index, Discr { val: index.as_usize() as u128, ty: self.discr_ty(tcx) }) }) @@ -139,7 +138,7 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> { self, def_id: DefId, tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { + ) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>>> { let layout = tcx.coroutine_layout(def_id, self.kind_ty()).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { @@ -720,6 +719,34 @@ impl<'tcx> Ty<'tcx> { reg: ty::Region<'tcx>, repr: DynKind, ) -> Ty<'tcx> { + if cfg!(debug_assertions) { + let projection_count = obj.projection_bounds().count(); + let expected_count: usize = obj + .principal_def_id() + .into_iter() + .flat_map(|principal_def_id| { + // NOTE: This should agree with `needed_associated_types` in + // dyn trait lowering, or else we'll have ICEs. + elaborate::supertraits( + tcx, + ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)), + ) + .map(|principal| { + tcx.associated_items(principal.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| !item.is_impl_trait_in_trait()) + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) + .count() + }) + }) + .sum(); + assert_eq!( + projection_count, expected_count, + "expected {obj:?} to have {expected_count} projections, \ + but it has {projection_count}" + ); + } Ty::new(tcx, Dynamic(obj, reg, repr)) } @@ -1121,7 +1148,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_param(self, index: u32) -> bool { match self.kind() { - ty::Param(ref data) => data.index == index, + ty::Param(data) => data.index == index, _ => false, } } @@ -1199,7 +1226,7 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_unsafe_ptr(self) -> bool { + pub fn is_raw_ptr(self) -> bool { matches!(self.kind(), RawPtr(_, _)) } @@ -1207,7 +1234,7 @@ impl<'tcx> Ty<'tcx> { /// `Box` is *not* considered a pointer here! #[inline] pub fn is_any_ptr(self) -> bool { - self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_raw_ptr() || self.is_fn_ptr() } #[inline] @@ -1394,7 +1421,7 @@ impl<'tcx> Ty<'tcx> { /// Returns the type and mutability of `*ty`. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. - /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. + /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(self, explicit: bool) -> Option<Ty<'tcx>> { match *self.kind() { _ if let Some(boxed) = self.boxed_ty() => Some(boxed), diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 743ea33b20a..8fa1c569737 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -188,7 +188,7 @@ impl<'tcx> TyCtxt<'tcx> { self, trait_def_id: DefId, self_ty: Ty<'tcx>, - ) -> impl Iterator<Item = DefId> + 'tcx { + ) -> impl Iterator<Item = DefId> { let impls = self.trait_impls_of(trait_def_id); if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer) @@ -204,7 +204,7 @@ impl<'tcx> TyCtxt<'tcx> { /// 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 { + pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> { 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() @@ -235,7 +235,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } } - for &impl_def_id in tcx.hir().trait_impls(trait_id) { + for &impl_def_id in tcx.hir_trait_impls(trait_id) { let impl_def_id = impl_def_id.to_def_id(); let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); @@ -267,7 +267,7 @@ pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) - pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { let mut traits = Vec::new(); - for id in tcx.hir().items() { + for id in tcx.hir_free_items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { traits.push(id.owner_id.to_def_id()) } @@ -278,7 +278,7 @@ pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { pub(super) fn trait_impls_in_crate_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { let mut trait_impls = Vec::new(); - for id in tcx.hir().items() { + for id in tcx.hir_free_items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) && tcx.impl_trait_ref(id.owner_id).is_some() { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index f94f52e4f61..d4484a16fea 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -14,13 +14,13 @@ use rustc_hir::{ }; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; use super::RvalueScopes; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::Canonical; +use crate::mir::FakeReadCause; use crate::traits::ObligationCause; use crate::ty::{ self, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, GenericArgs, @@ -73,9 +73,9 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap<BindingMode>, - /// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024 - /// migration lint. Problematic subpatterns are stored in the `Vec` for the lint to highlight. - rust_2024_migration_desugared_pats: ItemLocalMap<Vec<(Span, String)>>, + /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated + /// to a form valid in all Editions, either as a lint diagnostic or hard error. + rust_2024_migration_desugared_pats: ItemLocalMap<Rust2024IncompatiblePatInfo>, /// Stores the types which were implicitly dereferenced in pattern binding modes /// for later usage in THIR lowering. For example, @@ -147,9 +147,7 @@ pub struct TypeckResults<'tcx> { coercion_casts: ItemLocalSet, /// Set of trait imports actually used in the method resolution. - /// This is used for warning unused imports. During type - /// checking, this `Lrc` should not be cloned: it must have a ref-count - /// of 1 so that we can insert things into the set mutably. + /// This is used for warning unused imports. pub used_trait_imports: UnordSet<LocalDefId>, /// If any errors occurred while type-checking this body, @@ -420,7 +418,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn rust_2024_migration_desugared_pats( &self, - ) -> LocalTableInContext<'_, Vec<(Span, String)>> { + ) -> LocalTableInContext<'_, Rust2024IncompatiblePatInfo> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.rust_2024_migration_desugared_pats, @@ -429,7 +427,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn rust_2024_migration_desugared_pats_mut( &mut self, - ) -> LocalTableInContextMut<'_, Vec<(Span, String)>> { + ) -> LocalTableInContextMut<'_, Rust2024IncompatiblePatInfo> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.rust_2024_migration_desugared_pats, @@ -577,7 +575,7 @@ impl<'a, V> LocalTableInContext<'a, V> { } pub fn items( - &'a self, + &self, ) -> UnordItems<(hir::ItemLocalId, &'a V), impl Iterator<Item = (hir::ItemLocalId, &'a V)>> { self.data.items().map(|(id, value)| (*id, value)) @@ -811,3 +809,17 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> { } } } + +/// Information on a pattern incompatible with Rust 2024, for use by the error/migration diagnostic +/// emitted during THIR construction. +#[derive(TyEncodable, TyDecodable, Debug, HashStable)] +pub struct Rust2024IncompatiblePatInfo { + /// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024. + pub primary_labels: Vec<(Span, String)>, + /// Whether any binding modifiers occur under a non-`move` default binding mode. + pub bad_modifiers: bool, + /// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode. + pub bad_ref_pats: bool, + /// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers. + pub suggest_eliding_modes: bool, +} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 318bd0c7ec0..88d57498542 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -5,9 +5,10 @@ use std::{fmt, iter}; use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; +use rustc_hashes::Hash128; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; @@ -759,10 +760,11 @@ impl<'tcx> TyCtxt<'tcx> { assert_eq!(re, self.lifetimes.re_erased); let var = ty::BoundVar::from_usize(vars.len()); vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); - ty::Region::new_bound(self, debruijn, ty::BoundRegion { - var, - kind: ty::BoundRegionKind::Anon, - }) + ty::Region::new_bound( + self, + debruijn, + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + ) }); ty::EarlyBinder::bind(ty::Binder::bind_with_vars( ty, @@ -777,7 +779,6 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, args: GenericArgsRef<'tcx>, - inspect_coroutine_fields: InspectCoroutineFields, ) -> Result<Ty<'tcx>, Ty<'tcx>> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), @@ -786,9 +787,7 @@ impl<'tcx> TyCtxt<'tcx> { found_recursion: false, found_any_recursion: false, check_recursion: true, - expand_coroutines: true, tcx: self, - inspect_coroutine_fields, }; let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap(); @@ -951,6 +950,29 @@ impl<'tcx> TyCtxt<'tcx> { ty } + + // Computes the variances for an alias (opaque or RPITIT) that represent + // its (un)captured regions. + pub fn opt_alias_variances( + self, + kind: impl Into<ty::AliasTermKind>, + def_id: DefId, + ) -> Option<&'tcx [ty::Variance]> { + match kind.into() { + ty::AliasTermKind::ProjectionTy => { + if self.is_impl_trait_in_trait(def_id) { + Some(self.variances_of(def_id)) + } else { + None + } + } + ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), + ty::AliasTermKind::InherentTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => None, + } + } } struct OpaqueTypeExpander<'tcx> { @@ -965,19 +987,11 @@ struct OpaqueTypeExpander<'tcx> { primary_def_id: Option<DefId>, found_recursion: bool, found_any_recursion: bool, - expand_coroutines: bool, /// Whether or not to check for recursive opaque types. /// This is `true` when we're explicitly checking for opaque type /// recursion, and 'false' otherwise to avoid unnecessary work. check_recursion: bool, tcx: TyCtxt<'tcx>, - inspect_coroutine_fields: InspectCoroutineFields, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum InspectCoroutineFields { - No, - Yes, } impl<'tcx> OpaqueTypeExpander<'tcx> { @@ -1009,41 +1023,6 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { None } } - - fn expand_coroutine(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) -> Option<Ty<'tcx>> { - if self.found_any_recursion { - return None; - } - let args = args.fold_with(self); - if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { - let expanded_ty = match self.expanded_cache.get(&(def_id, args)) { - Some(expanded_ty) => *expanded_ty, - None => { - if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) { - 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); - } - } - let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args); - self.expanded_cache.insert((def_id, args), expanded_ty); - expanded_ty - } - }; - if self.check_recursion { - self.seen_opaque_tys.remove(&def_id); - } - Some(expanded_ty) - } else { - // If another opaque type that we contain is recursive, then it - // will report the error, so we don't have to. - self.found_any_recursion = true; - self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); - None - } - } } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { @@ -1052,19 +1031,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - let mut t = if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *t.kind() { + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *t.kind() { self.expand_opaque_ty(def_id, args).unwrap_or(t) - } else if t.has_opaque_types() || t.has_coroutines() { + } else if t.has_opaque_types() { t.super_fold_with(self) } else { t - }; - if self.expand_coroutines { - if let ty::CoroutineWitness(def_id, args) = *t.kind() { - t = self.expand_coroutine(def_id, args).unwrap_or(t); - } } - t } fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { @@ -1753,9 +1726,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( found_recursion: false, found_any_recursion: false, check_recursion: false, - expand_coroutines: false, tcx, - inspect_coroutine_fields: InspectCoroutineFields::No, }; val.fold_with(&mut visitor) } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 4efaccefcf7..95256b55bb4 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxIndexSet; use rustc_type_ir::fold::TypeFoldable; -pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +pub use rustc_type_ir::visit::*; use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 8c875007b7f..85519fb0a7d 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -2,9 +2,9 @@ pub mod bug; #[derive(Default, Copy, Clone)] pub struct Providers { - pub queries: rustc_middle::query::Providers, - pub extern_queries: rustc_middle::query::ExternProviders, - pub hooks: rustc_middle::hooks::Providers, + pub queries: crate::query::Providers, + pub extern_queries: crate::query::ExternProviders, + pub hooks: crate::hooks::Providers, } /// Backwards compatibility hack to keep the diff small. This @@ -17,7 +17,7 @@ impl std::ops::DerefMut for Providers { } impl std::ops::Deref for Providers { - type Target = rustc_middle::query::Providers; + type Target = crate::query::Providers; fn deref(&self) -> &Self::Target { &self.queries diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 867f8f63969..9450ce7ec44 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -7,7 +7,6 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_query_system::Value; use rustc_query_system::query::{CycleError, report_cycle}; use rustc_span::def_id::LocalDefId; @@ -15,6 +14,7 @@ use rustc_span::{ErrorGuaranteed, Span}; use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; +use crate::ty::{self, Representability, Ty, TyCtxt}; impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { @@ -53,7 +53,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> { let arity = if let Some(frame) = cycle_error.cycle.get(0) && frame.query.dep_kind == dep_kinds::fn_sig && let Some(def_id) = frame.query.def_id - && let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(node) = tcx.hir_get_if_local(def_id) && let Some(sig) = node.fn_sig() { sig.decl.inputs.len() |
