diff options
Diffstat (limited to 'compiler/rustc_middle')
65 files changed, 1519 insertions, 1949 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 69b2f92f716..aef56ea46e9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -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/lib.rs b/compiler/rustc_middle/src/lib.rs index 95128a5d903..48ea7df5c23 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -45,7 +44,6 @@ #![feature(decl_macro)] #![feature(discriminant_kind)] #![feature(extern_types)] -#![feature(extract_if)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] 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/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 c32cf5f8253..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 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/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 1222ba052cc..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 { @@ -216,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 63e20fb0d64..ea0bb5feb12 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,9 +29,7 @@ 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::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; @@ -49,12 +46,10 @@ 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; @@ -101,24 +96,28 @@ 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) - } + pub fn name(&self) -> &'static str { + match *self { + MirPhase::Built => "built", + MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", + MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", + MirPhase::Runtime(RuntimePhase::Initial) => "runtime", + MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", + MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", } } - /// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason. + /// 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 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" => { @@ -483,7 +482,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]; @@ -493,9 +492,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]; @@ -525,7 +522,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..) } @@ -542,17 +539,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> { @@ -794,7 +780,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, @@ -951,7 +937,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. @@ -975,7 +961,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. @@ -985,7 +970,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 @@ -1093,7 +1077,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 @@ -1108,7 +1091,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 @@ -1366,70 +1349,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 { @@ -1561,7 +1480,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 { @@ -1573,26 +1492,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 d4a9aac3733..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, } 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..f05a798949b 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,18 +22,29 @@ 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> { + /// Returns a simple string representation of a `StatementKind` variant, independent of any + /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). + pub const fn name(&self) -> &'static str { + match self { + StatementKind::Assign(..) => "Assign", + StatementKind::FakeRead(..) => "FakeRead", + StatementKind::SetDiscriminant { .. } => "SetDiscriminant", + StatementKind::Deinit(..) => "Deinit", + StatementKind::StorageLive(..) => "StorageLive", + StatementKind::StorageDead(..) => "StorageDead", + StatementKind::Retag(..) => "Retag", + StatementKind::PlaceMention(..) => "PlaceMention", + StatementKind::AscribeUserType(..) => "AscribeUserType", + StatementKind::Coverage(..) => "Coverage", + StatementKind::Intrinsic(..) => "Intrinsic", + StatementKind::ConstEvalCounter => "ConstEvalCounter", + StatementKind::Nop => "Nop", + StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", + } + } pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { match self { StatementKind::Assign(x) => Some(x), @@ -49,6 +63,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 +362,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 +483,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 +584,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 +631,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 +675,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 +761,161 @@ 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, + }) + } +} + +impl From<Mutability> for RawPtrKind { + fn from(other: Mutability) -> Self { + match other { + Mutability::Mut => RawPtrKind::Mut, + Mutability::Not => RawPtrKind::Const, + } + } +} + +impl RawPtrKind { + pub fn is_fake(self) -> bool { + match self { + RawPtrKind::Mut | RawPtrKind::Const => false, + RawPtrKind::FakeForPtrMetadata => true, + } + } + + pub fn to_mutbl_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + + // We have no type corresponding to a fake borrow, so use + // `*const` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } + + pub fn ptr_str(self) -> &'static str { + match self { + RawPtrKind::Mut => "mut", + RawPtrKind::Const => "const", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } + } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9cec8d832dd..4f86703e953 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -23,84 +23,80 @@ 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), } -impl MirPhase { - pub fn name(&self) -> &'static str { - match *self { - MirPhase::Built => "built", - MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", - MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", - MirPhase::Runtime(RuntimePhase::Initial) => "runtime", - MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", - MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", - } - } -} - /// See [`MirPhase::Analysis`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] @@ -111,7 +107,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`] @@ -196,43 +193,6 @@ pub enum RawPtrKind { FakeForPtrMetadata, } -impl From<Mutability> for RawPtrKind { - fn from(other: Mutability) -> Self { - match other { - Mutability::Mut => RawPtrKind::Mut, - Mutability::Not => RawPtrKind::Const, - } - } -} - -impl RawPtrKind { - pub fn is_fake(self) -> bool { - match self { - RawPtrKind::Mut | RawPtrKind::Const => false, - RawPtrKind::FakeForPtrMetadata => true, - } - } - - pub fn to_mutbl_lossy(self) -> Mutability { - match self { - RawPtrKind::Mut => Mutability::Mut, - RawPtrKind::Const => Mutability::Not, - - // We have no type corresponding to a fake borrow, so use - // `*const` as an approximation. - RawPtrKind::FakeForPtrMetadata => Mutability::Not, - } - } - - pub fn ptr_str(self) -> &'static str { - match self { - RawPtrKind::Mut => "mut", - RawPtrKind::Const => "const", - RawPtrKind::FakeForPtrMetadata => "const (fake)", - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] pub enum MutBorrowKind { @@ -505,29 +465,6 @@ pub enum StatementKind<'tcx> { }, } -impl StatementKind<'_> { - /// Returns a simple string representation of a `StatementKind` variant, independent of any - /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). - pub const fn name(&self) -> &'static str { - match self { - StatementKind::Assign(..) => "Assign", - StatementKind::FakeRead(..) => "FakeRead", - StatementKind::SetDiscriminant { .. } => "SetDiscriminant", - StatementKind::Deinit(..) => "Deinit", - StatementKind::StorageLive(..) => "StorageLive", - StatementKind::StorageDead(..) => "StorageDead", - StatementKind::Retag(..) => "Retag", - StatementKind::PlaceMention(..) => "PlaceMention", - StatementKind::AscribeUserType(..) => "AscribeUserType", - StatementKind::Coverage(..) => "Coverage", - StatementKind::Intrinsic(..) => "Intrinsic", - StatementKind::ConstEvalCounter => "ConstEvalCounter", - StatementKind::Nop => "Nop", - StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", - } - } -} - #[derive( Clone, TyEncodable, @@ -663,12 +600,6 @@ pub enum CallSource { Normal, } -impl CallSource { - pub fn from_hir_call(self) -> bool { - matches!(self, CallSource::Normal) - } -} - #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] #[derive(TypeFoldable, TypeVisitable)] /// The macro that an inline assembly block was created by @@ -679,15 +610,6 @@ pub enum InlineAsmMacro { NakedAsm, } -impl InlineAsmMacro { - pub const fn diverges(self, options: InlineAsmOptions) -> bool { - match self { - InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), - InlineAsmMacro::NakedAsm => true, - } - } -} - /////////////////////////////////////////////////////////////////////////// // Terminators @@ -989,48 +911,32 @@ pub enum BackwardIncompatibleDropReason { Edition2024, } -impl TerminatorKind<'_> { - /// Returns a simple string representation of a `TerminatorKind` variant, independent of any - /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). - pub const fn name(&self) -> &'static str { - match self { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::UnwindResume => "UnwindResume", - TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::TailCall { .. } => "TailCall", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::CoroutineDrop => "CoroutineDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } - } -} - #[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 +1031,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 9357e19f7c5..b887370fd69 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -2,12 +2,13 @@ use std::slice; +use rustc_ast::InlineAsmOptions; use rustc_data_structures::packed::Pu128; use rustc_hir::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use smallvec::{SmallVec, smallvec}; -use super::{TerminatorKind, *}; +use super::*; impl SwitchTargets { /// Creates switch targets from an iterator of values and target blocks. @@ -86,7 +87,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 +227,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:?}" ), @@ -414,6 +415,28 @@ impl<'tcx> Terminator<'tcx> { } impl<'tcx> TerminatorKind<'tcx> { + /// Returns a simple string representation of a `TerminatorKind` variant, independent of any + /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). + pub const fn name(&self) -> &'static str { + match self { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::UnwindResume => "UnwindResume", + TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::TailCall { .. } => "TailCall", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::CoroutineDrop => "CoroutineDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } + } + #[inline] pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } @@ -698,3 +721,18 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + +impl InlineAsmMacro { + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + InlineAsmMacro::NakedAsm => true, + } + } +} 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/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 d94efe2d7d6..7c4ea06a746 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -116,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 { @@ -163,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 @@ -614,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> { @@ -764,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 { @@ -795,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) } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 3247bdbf105..d9035efaf56 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -11,12 +11,6 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, LocalDefId, Stab 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}; @@ -30,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` @@ -563,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 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 4dc8f279553..e5592de81cd 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -20,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 { @@ -93,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. @@ -375,7 +377,6 @@ pub enum ExprKind<'tcx> { /// A `match` expression. Match { scrutinee: ExprId, - scrutinee_hir_id: HirId, arms: Box<[ArmId]>, match_source: MatchSource, }, @@ -605,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - value: mir::Const<'tcx>, - span: Span, + value: ExprId, }, SymStatic { def_id: DefId, @@ -678,8 +678,7 @@ 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 } => { + 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)) } } 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 f039da772fd..d033ecc75db 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -12,7 +12,7 @@ use std::borrow::Cow; use std::hash::{Hash, Hasher}; use std::sync::Arc; -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<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 { + 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. @@ -514,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> { @@ -584,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)] @@ -592,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>, @@ -611,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)] @@ -790,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 { @@ -1000,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 b7cd545d02d..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 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/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index ed7c98ee0e0..9ce5373b031 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -75,7 +75,7 @@ impl OverlapMode { tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id)) }) .find(|attr| attr.has_name(sym::rustc_strict_coherence)) - .map(|attr| attr.span); + .map(|attr| attr.span()); tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence { span: tcx.def_span(trait_id), attr_span, 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 2566081cf5d..62a384af12f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -80,7 +80,7 @@ use crate::ty::{ GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - Visibility, + ValTree, ValTreeKind, Visibility, }; #[allow(rustc::usage_of_ty_tykind)] @@ -690,6 +690,7 @@ bidirectional_lang_item_map! { AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, + BikeshedGuaranteedNoDrop, CallOnceFuture, CallRefFuture, Clone, @@ -806,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> { @@ -835,6 +837,7 @@ impl<'tcx> CtxtInterners<'tcx> { local_def_ids: Default::default(), captures: Default::default(), offset_of: Default::default(), + valtree: Default::default(), } } @@ -1026,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> { @@ -1129,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, } } } @@ -1301,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<'_>>(); @@ -1357,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. @@ -1460,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 { @@ -1526,7 +1542,7 @@ impl<'tcx> TyCtxt<'tcx> { Bound::Included(a.get()) } else { self.dcx().span_delayed_bug( - attr.span, + attr.span(), "invalid rustc_layout_scalar_valid_range attribute", ); Bound::Unbounded @@ -1588,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(), @@ -1928,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); @@ -2066,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![]; }; @@ -2086,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 @@ -2155,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)); @@ -2262,6 +2281,7 @@ 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! { @@ -2272,26 +2292,6 @@ nop_list_lift! { bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariabl // 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_slice_lift! { ty::ValTree<'a> => ty::ValTree<'tcx> } - macro_rules! sty_debug_print { ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{ // Curious inner module to allow variant names to be used as @@ -2367,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, @@ -2536,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>, @@ -3020,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()); } @@ -3298,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/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 e5015ea3c3d..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), } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6fe1502c66d..9208c2a65a1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,7 @@ 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_attr_parsing::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -60,7 +60,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, @@ -179,7 +180,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 +1470,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 +1487,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 @@ -1496,9 +1496,10 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - for attr in self.get_attrs(did, sym::repr) { - for r in attr::parse_repr_attr(self.sess, attr) { - flags.insert(match r { + if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) + { + for (r, _) in reprs { + flags.insert(match *r { attr::ReprRust => ReprFlags::empty(), attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { @@ -1536,6 +1537,10 @@ impl<'tcx> TyCtxt<'tcx> { max_align = max_align.max(Some(align)); ReprFlags::empty() } + attr::ReprEmpty => { + /* skip these, they're just for diagnostics */ + ReprFlags::empty() + } }); } } @@ -1758,13 +1763,21 @@ impl<'tcx> TyCtxt<'tcx> { did: impl Into<DefId>, attr: Symbol, ) -> impl Iterator<Item = &'tcx hir::Attribute> { + self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr)) + } + + /// Gets all attributes. + /// + /// To see if an item has a specific attribute, you should use [`rustc_attr_parsing::find_attr!`] so you can use matching. + pub fn get_all_attrs( + self, + did: impl Into<DefId>, + ) -> impl Iterator<Item = &'tcx hir::Attribute> { let did: DefId = did.into(); - let filter_fn = move |a: &&hir::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir().attrs(self.local_def_id_to_hir_id(did)).iter() } else { - debug_assert!(rustc_feature::encode_cross_crate(attr)); - self.attrs_for_def(did).iter().filter(filter_fn) + self.attrs_for_def(did).iter() } } @@ -1799,14 +1812,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 +2177,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 feae8ea312e..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) @@ -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 c33f952fc86..db9e9fbc643 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,13 +7,12 @@ use std::fmt::{self, Debug}; use rustc_abi::TyAndLayout; use rustc_ast::InlineAsmTemplatePiece; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; 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}; @@ -165,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()) @@ -452,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)); 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 49bdb5e9dc3..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, @@ -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 `Arc` 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, @@ -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)) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 94bd359f6eb..c153f6bb7d7 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}; @@ -1754,13 +1755,12 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi && (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic) || tcx.has_attr(def_id, sym::rustc_intrinsic)) { - let must_be_overridden = tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) - || match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => { - !has_body - } - _ => true, - }; + let must_be_overridden = match tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => { + !has_body + } + _ => true, + }; Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), must_be_overridden, 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() |
