summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/messages.ftl2
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs53
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs50
-rw-r--r--compiler/rustc_middle/src/error.rs7
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs29
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs65
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs67
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs2
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs50
-rw-r--r--compiler/rustc_middle/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/lint.rs12
-rw-r--r--compiler/rustc_middle/src/macros.rs4
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs21
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs522
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs91
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs19
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs18
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs134
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs1612
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs8
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs27
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs1251
-rw-r--r--compiler/rustc_middle/src/mir/query.rs8
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs45
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs464
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs118
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs13
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs421
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs110
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs58
-rw-r--r--compiler/rustc_middle/src/query/erase.rs29
-rw-r--r--compiler/rustc_middle/src/query/keys.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs49
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs9
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs14
-rw-r--r--compiler/rustc_middle/src/thir.rs26
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs42
-rw-r--r--compiler/rustc_middle/src/traits/query.rs21
-rw-r--r--compiler/rustc_middle/src/traits/select.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs63
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs137
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs118
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs8
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs6
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs2
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs254
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs5
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs45
-rw-r--r--compiler/rustc_middle/src/ty/context.rs111
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs10
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs4
-rw-r--r--compiler/rustc_middle/src/ty/error.rs9
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs13
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs24
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs2
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs20
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs12
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs18
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs15
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs97
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs24
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs4
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs110
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs170
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs84
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs89
-rw-r--r--compiler/rustc_middle/src/ty/util.rs34
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs36
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs6
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs5
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs4
-rw-r--r--compiler/rustc_middle/src/util/mod.rs24
-rw-r--r--compiler/rustc_middle/src/values.rs56
84 files changed, 3821 insertions, 3329 deletions
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 108a10b50..82162fd85 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -52,6 +52,8 @@ middle_drop_check_overflow =
overflow while adding drop-check rules for {$ty}
.note = overflowed on {$overflow_ty}
+middle_erroneous_constant = erroneous constant encountered
+
middle_layout_references_error =
the type has an unknown layout
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 04c09d334..39d82c489 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -65,9 +65,9 @@ use rustc_hir::definitions::DefPathHash;
use rustc_hir::{HirId, ItemLocalId, OwnerId};
use rustc_query_system::dep_graph::FingerprintStyle;
use rustc_span::symbol::Symbol;
-use std::hash::Hash;
-pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
+pub use rustc_query_system::dep_graph::dep_node::DepKind;
+pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams};
macro_rules! define_dep_nodes {
(
@@ -80,15 +80,43 @@ macro_rules! define_dep_nodes {
}
/// This enum serves as an index into arrays built by `make_dep_kind_array`.
- #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+ // This enum has more than u8::MAX variants so we need some kind of multi-byte
+ // encoding. The derived Encodable/Decodable uses leb128 encoding which is
+ // dense when only considering this enum. But DepKind is encoded in a larger
+ // struct, and there we can take advantage of the unused bits in the u16.
#[allow(non_camel_case_types)]
- pub enum DepKind {
+ #[repr(u16)] // Must be kept in sync with the inner type of `DepKind`.
+ enum DepKindDefs {
$( $( #[$attr] )* $variant),*
}
+ #[allow(non_upper_case_globals)]
+ pub mod dep_kinds {
+ use super::*;
+
+ $(
+ // The `as u16` cast must be kept in sync with the inner type of `DepKind`.
+ pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16);
+ )*
+ }
+
+ // This checks that the discriminants of the variants have been assigned consecutively
+ // from 0 so that they can be used as a dense index.
+ pub const DEP_KIND_VARIANTS: u16 = {
+ let deps = &[$(dep_kinds::$variant,)*];
+ let mut i = 0;
+ while i < deps.len() {
+ if i != deps[i].as_usize() {
+ panic!();
+ }
+ i += 1;
+ }
+ deps.len() as u16
+ };
+
pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
match label {
- $(stringify!($variant) => Ok(DepKind::$variant),)*
+ $(stringify!($variant) => Ok(dep_kinds::$variant),)*
_ => Err(()),
}
}
@@ -117,7 +145,7 @@ rustc_query_append!(define_dep_nodes![
// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
// Be very careful changing this type signature!
pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
- DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
+ DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name)
}
// WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
@@ -126,20 +154,9 @@ pub(crate) fn make_compile_mono_item<'tcx>(
tcx: TyCtxt<'tcx>,
mono_item: &MonoItem<'tcx>,
) -> DepNode {
- DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item)
+ DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
}
-pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
-
-// We keep a lot of `DepNode`s in memory during compilation. It's not
-// required that their size stay the same, but we don't want to change
-// it inadvertently. This assert just ensures we're aware of any change.
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 18);
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-static_assert_size!(DepNode, 24);
-
pub trait DepNodeExt: Sized {
/// Extracts the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index f79ce08b8..76ef62f9f 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -6,48 +6,24 @@ use rustc_session::Session;
#[macro_use]
mod dep_node;
+pub use rustc_query_system::dep_graph::debug::EdgeFilter;
pub use rustc_query_system::dep_graph::{
- debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex,
- SerializedDepNodeIndex, WorkProduct, WorkProductId, WorkProductMap,
+ debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeColor, DepNodeIndex, Deps,
+ SerializedDepGraph, SerializedDepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductId,
+ WorkProductMap,
};
-pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
+pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt};
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
-pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
-pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
-pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
-pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
-pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
-impl rustc_query_system::dep_graph::DepKind for DepKind {
- const NULL: Self = DepKind::Null;
- const RED: Self = DepKind::Red;
-
- fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}(", node.kind)?;
-
- ty::tls::with_opt(|opt_tcx| {
- if let Some(tcx) = opt_tcx {
- if let Some(def_id) = node.extract_def_id(tcx) {
- write!(f, "{}", tcx.def_path_debug_str(def_id))?;
- } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) {
- write!(f, "{s}")?;
- } else {
- write!(f, "{}", node.hash)?;
- }
- } else {
- write!(f, "{}", node.hash)?;
- }
- Ok(())
- })?;
-
- write!(f, ")")
- }
+#[derive(Clone)]
+pub struct DepsType;
+impl Deps for DepsType {
fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
where
OP: FnOnce() -> R,
@@ -68,10 +44,14 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
op(icx.task_deps)
})
}
+
+ const DEP_KIND_NULL: DepKind = dep_kinds::Null;
+ const DEP_KIND_RED: DepKind = dep_kinds::Red;
+ const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
}
impl<'tcx> DepContext for TyCtxt<'tcx> {
- type DepKind = DepKind;
+ type Deps = DepsType;
#[inline]
fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R {
@@ -95,6 +75,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
#[inline]
fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> {
- &self.query_kinds[dk as usize]
+ &self.query_kinds[dk.as_usize()]
}
}
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index b346cd453..3c5536570 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
pub abi: &'static str,
}
+#[derive(Diagnostic)]
+#[diag(middle_erroneous_constant)]
+pub struct ErroneousConstant {
+ #[primary_span]
+ pub span: Span,
+}
+
/// Used by `rustc_const_eval`
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 467962b39..4af2d83e9 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -196,9 +196,7 @@ impl<'hir> Map<'hir> {
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
ItemKind::Mod(..) => DefKind::Mod,
ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
- ItemKind::TyAlias(..) => {
- DefKind::TyAlias { lazy: self.tcx.features().lazy_type_alias }
- }
+ ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Enum(..) => DefKind::Enum,
ItemKind::Struct(..) => DefKind::Struct,
ItemKind::Union(..) => DefKind::Union,
@@ -442,9 +440,10 @@ impl<'hir> Map<'hir> {
/// Panics if `LocalDefId` does not have an associated body.
pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
match self.tcx.def_kind(def_id) {
- DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
- BodyOwnerKind::Const
+ DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
+ BodyOwnerKind::Const { inline: false }
}
+ DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
@@ -461,7 +460,7 @@ impl<'hir> Map<'hir> {
/// just that it has to be checked as if it were.
pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
let ccx = match self.body_owner_kind(def_id) {
- BodyOwnerKind::Const => ConstContext::Const,
+ BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
@@ -701,6 +700,8 @@ impl<'hir> Map<'hir> {
// expressions.
ignore_tail = true;
}
+
+ let mut prev_hir_id = None;
while let Some((hir_id, node)) = iter.next() {
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
match next_node {
@@ -715,7 +716,14 @@ impl<'hir> Map<'hir> {
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
- | Node::ImplItem(_) => return Some(hir_id),
+ | Node::ImplItem(_)
+ // The input node `id` must be enclosed in the method's body as opposed
+ // to some other place such as its return type (fixes #114918).
+ // We verify that indirectly by checking that the previous node is the
+ // current node's body
+ if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
+ return Some(hir_id)
+ }
// Ignore `return`s on the first iteration
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
| Node::Local(_) => {
@@ -723,6 +731,8 @@ impl<'hir> Map<'hir> {
}
_ => {}
}
+
+ prev_hir_id = Some(hir_id);
}
None
}
@@ -1195,8 +1205,8 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
- if tcx.sess.opts.incremental_relative_spans() {
- let definitions = tcx.definitions_untracked();
+ if tcx.sess.opts.incremental.is_some() {
+ let definitions = tcx.untracked().definitions.freeze();
let mut owner_spans: Vec<_> = krate
.owners
.iter_enumerated()
@@ -1215,7 +1225,6 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
tcx.stable_crate_id(LOCAL_CRATE).hash_stable(&mut hcx, &mut stable_hasher);
// Hash visibility information since it does not appear in HIR.
resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
- resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
stable_hasher.finish()
});
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
new file mode 100644
index 000000000..12aeae177
--- /dev/null
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -0,0 +1,65 @@
+use crate::mir;
+use crate::query::TyCtxtAt;
+use crate::ty::{Ty, TyCtxt};
+use rustc_span::DUMMY_SP;
+
+macro_rules! declare_hooks {
+ ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
+
+ impl<'tcx> TyCtxt<'tcx> {
+ $(
+ $(#[$attr])*
+ #[inline(always)]
+ #[must_use]
+ pub fn $name(self, $($arg: $K,)*) -> $V
+ {
+ self.at(DUMMY_SP).$name($($arg,)*)
+ }
+ )*
+ }
+
+ impl<'tcx> TyCtxtAt<'tcx> {
+ $(
+ $(#[$attr])*
+ #[inline(always)]
+ #[must_use]
+ #[instrument(level = "debug", skip(self), ret)]
+ pub fn $name(self, $($arg: $K,)*) -> $V
+ {
+ (self.tcx.hooks.$name)(self, $($arg,)*)
+ }
+ )*
+ }
+
+ pub struct Providers {
+ $(pub $name: for<'tcx> fn(
+ TyCtxtAt<'tcx>,
+ $($arg: $K,)*
+ ) -> $V,)*
+ }
+
+ impl Default for Providers {
+ fn default() -> Self {
+ Providers {
+ $($name: |_, $($arg,)*| bug!(
+ "`tcx.{}{:?}` cannot be called as `{}` was never assigned to a provider function.\n",
+ stringify!($name),
+ ($($arg,)*),
+ stringify!($name),
+ ),)*
+ }
+ }
+ }
+
+ impl Copy for Providers {}
+ impl Clone for Providers {
+ fn clone(&self) -> Self { *self }
+ }
+ };
+}
+
+declare_hooks! {
+ /// Tries to destructure an `mir::Const` ADT or array into its variant index
+ /// and its field values. This should only be used for pretty printing.
+ hook try_destructure_mir_constant_for_diagnostics(val: mir::ConstValue<'tcx>, ty: Ty<'tcx>) -> Option<mir::DestructuredConstant<'tcx>>;
+}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 81823118a..41beca072 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -27,19 +27,30 @@ use crate::ty::GenericArg;
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
use rustc_macros::HashStable;
use smallvec::SmallVec;
+use std::fmt::Display;
use std::ops::Index;
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct Canonical<'tcx, V> {
pub value: V,
pub max_universe: ty::UniverseIndex,
pub variables: CanonicalVarInfos<'tcx>,
}
+impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
+ self.value, self.max_universe, self.variables
+ )
+ }
+}
+
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
@@ -61,7 +72,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: ty::GenericArgsRef<'tcx>,
}
@@ -173,6 +184,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(..) => true,
CanonicalVarKind::PlaceholderConst(_, _) => false,
+ CanonicalVarKind::Effect => true,
}
}
@@ -182,7 +194,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
CanonicalVarKind::Ty(_)
| CanonicalVarKind::PlaceholderTy(_)
| CanonicalVarKind::Const(_, _)
- | CanonicalVarKind::PlaceholderConst(_, _) => false,
+ | CanonicalVarKind::PlaceholderConst(_, _)
+ | CanonicalVarKind::Effect => false,
}
}
@@ -190,7 +203,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
match self.kind {
CanonicalVarKind::Ty(_)
| CanonicalVarKind::Region(_)
- | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"),
+ | CanonicalVarKind::Const(_, _)
+ | CanonicalVarKind::Effect => bug!("expected placeholder: {self:?}"),
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
@@ -222,6 +236,9 @@ pub enum CanonicalVarKind<'tcx> {
/// Some kind of const inference variable.
Const(ty::UniverseIndex, Ty<'tcx>),
+ /// Effect variable `'?E`.
+ Effect,
+
/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
}
@@ -229,11 +246,11 @@ pub enum CanonicalVarKind<'tcx> {
impl<'tcx> CanonicalVarKind<'tcx> {
pub fn universe(self) -> ty::UniverseIndex {
match self {
- CanonicalVarKind::Ty(kind) => match kind {
- CanonicalTyVarKind::General(ui) => ui,
- CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
- },
-
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
+ ty::UniverseIndex::ROOT
+ }
+ CanonicalVarKind::Effect => ty::UniverseIndex::ROOT,
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
@@ -248,15 +265,14 @@ impl<'tcx> CanonicalVarKind<'tcx> {
/// the updated universe is not the root.
pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
match self {
- CanonicalVarKind::Ty(kind) => match kind {
- CanonicalTyVarKind::General(_) => {
- CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
- }
- CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
- assert_eq!(ui, ty::UniverseIndex::ROOT);
- CanonicalVarKind::Ty(kind)
- }
- },
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
+ }
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
+ | CanonicalVarKind::Effect => {
+ assert_eq!(ui, ty::UniverseIndex::ROOT);
+ self
+ }
CanonicalVarKind::PlaceholderTy(placeholder) => {
CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
}
@@ -295,7 +311,7 @@ pub enum CanonicalTyVarKind {
/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
-#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
@@ -310,7 +326,7 @@ pub struct QueryResponse<'tcx, R> {
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct QueryRegionConstraints<'tcx> {
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
pub member_constraints: Vec<MemberConstraint<'tcx>>,
@@ -416,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
pub type QueryOutlivesConstraint<'tcx> =
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
-TrivialTypeTraversalAndLiftImpls! {
+TrivialTypeTraversalImpls! {
crate::infer::canonical::Certainty,
crate::infer::canonical::CanonicalTyVarKind,
}
@@ -439,10 +455,17 @@ impl<'tcx> CanonicalVarValues<'tcx> {
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(i),
- kind: ty::BrAnon(None),
+ kind: ty::BrAnon,
};
ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
}
+ CanonicalVarKind::Effect => ty::Const::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundVar::from_usize(i),
+ tcx.types.bool,
+ )
+ .into(),
CanonicalVarKind::Const(_, ty)
| CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
tcx,
diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
index 493bb8a68..1384611e1 100644
--- a/compiler/rustc_middle/src/infer/mod.rs
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -13,7 +13,7 @@ use rustc_span::Span;
/// R0 member of [O1..On]
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct MemberConstraint<'tcx> {
/// The `DefId` and args of the opaque type causing this constraint.
/// Used for error reporting.
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 85fb9214d..7ca964759 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -188,3 +188,53 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
})
}
}
+
+/// values for the effect inference variable
+#[derive(Clone, Copy, Debug)]
+pub enum EffectVarValue<'tcx> {
+ /// The host effect is on, enabling access to syscalls, filesystem access, etc.
+ Host,
+ /// The host effect is off. Execution is restricted to const operations only.
+ NoHost,
+ Const(ty::Const<'tcx>),
+}
+
+impl<'tcx> EffectVarValue<'tcx> {
+ pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
+ match self {
+ EffectVarValue::Host => tcx.consts.true_,
+ EffectVarValue::NoHost => tcx.consts.false_,
+ EffectVarValue::Const(c) => c,
+ }
+ }
+}
+
+impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
+ type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
+ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
+ match (value1, value2) {
+ (EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
+ (EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
+ (EffectVarValue::NoHost | EffectVarValue::Host, _)
+ | (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
+ (EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
+ bug!("equating two const variables, both of which have known values")
+ }
+ }
+ }
+}
+
+impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
+ type Value = Option<EffectVarValue<'tcx>>;
+ #[inline]
+ fn index(&self) -> u32 {
+ self.index
+ }
+ #[inline]
+ fn from_index(i: u32) -> Self {
+ ty::EffectVid { index: i, phantom: PhantomData }
+ }
+ fn tag() -> &'static str {
+ "EffectVid"
+ }
+}
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index d3fc1b285..fe4fc3761 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -63,7 +63,7 @@
#![feature(macro_metavar_expr)]
#![recursion_limit = "512"]
#![allow(rustc::potential_query_instability)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#[macro_use]
extern crate bitflags;
@@ -89,6 +89,7 @@ mod macros;
pub mod arena;
pub mod error;
pub mod hir;
+pub mod hooks;
pub mod infer;
pub mod lint;
pub mod metadata;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index f62e40669..59849e8eb 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -225,6 +225,9 @@ pub fn explain_lint_level_source(
err.note_once(format!(
"`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`"
));
+ err.help_once(format!(
+ "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
+ ));
}
}
LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
@@ -311,7 +314,10 @@ pub fn struct_lint_level(
// Default allow lints trigger too often for testing.
sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
|incompat| {
- matches!(incompat.reason, FutureIncompatibilityReason::FutureReleaseErrorReportNow)
+ matches!(
+ incompat.reason,
+ FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
+ )
},
);
@@ -401,8 +407,8 @@ pub fn struct_lint_level(
if let Some(future_incompatible) = future_incompatible {
let explanation = match future_incompatible.reason {
- FutureIncompatibilityReason::FutureReleaseError
- | FutureIncompatibilityReason::FutureReleaseErrorReportNow => {
+ FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+ | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => {
"this was previously accepted by the compiler but is being phased out; \
it will become a hard error in a future release!"
.to_owned()
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index fca16d8e5..c1884bb80 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -42,7 +42,7 @@ macro_rules! span_bug {
// the impls for you.
#[macro_export]
-macro_rules! CloneLiftImpls {
+macro_rules! TrivialLiftImpls {
($($ty:ty),+ $(,)?) => {
$(
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
@@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls {
macro_rules! TrivialTypeTraversalAndLiftImpls {
($($t:tt)*) => {
TrivialTypeTraversalImpls! { $($t)* }
- CloneLiftImpls! { $($t)* }
+ TrivialLiftImpls! { $($t)* }
}
}
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 02fd6ed7b..4e5725876 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -87,7 +87,7 @@ bitflags! {
/// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
/// function as an entry function from Non-Secure code.
const CMSE_NONSECURE_ENTRY = 1 << 14;
- /// `#[no_coverage]`: indicates that the function should be ignored by
+ /// `#[coverage(off)]`: indicates that the function should be ignored by
/// the MIR `InstrumentCoverage` pass and not added to the coverage map
/// during codegen.
const NO_COVERAGE = 1 << 15;
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 0ad17e819..3ecd5b9cd 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceCell;
+use rustc_data_structures::sync::OnceLock;
use rustc_index::{IndexSlice, IndexVec};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use smallvec::SmallVec;
@@ -23,11 +23,11 @@ pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u1
#[derive(Clone, Default, Debug)]
struct Cache {
- predecessors: OnceCell<Predecessors>,
- switch_sources: OnceCell<SwitchSources>,
- is_cyclic: OnceCell<bool>,
- reverse_postorder: OnceCell<Vec<BasicBlock>>,
- dominators: OnceCell<Dominators<BasicBlock>>,
+ predecessors: OnceLock<Predecessors>,
+ switch_sources: OnceLock<SwitchSources>,
+ is_cyclic: OnceLock<bool>,
+ reverse_postorder: OnceLock<Vec<BasicBlock>>,
+ dominators: OnceLock<Dominators<BasicBlock>>,
}
impl<'tcx> BasicBlocks<'tcx> {
@@ -63,11 +63,14 @@ impl<'tcx> BasicBlocks<'tcx> {
}
/// Returns basic blocks in a reverse postorder.
+ ///
+ /// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal.
+ ///
+ /// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder
#[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).map(|(bb, _)| bb).collect();
+ let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect();
rpo.reverse();
rpo
})
@@ -178,7 +181,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
}
}
-TrivialTypeTraversalAndLiftImpls! { Cache }
+TrivialTypeTraversalImpls! { Cache }
impl<S: Encoder> Encodable<S> for Cache {
#[inline]
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
new file mode 100644
index 000000000..7c8a57b84
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -0,0 +1,522 @@
+use std::fmt::{self, Debug, Display, Formatter};
+
+use rustc_hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir};
+use rustc_span::Span;
+use rustc_target::abi::{HasDataLayout, Size};
+
+use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar};
+use crate::mir::{pretty_print_const_value, Promoted};
+use crate::ty::ScalarInt;
+use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt};
+use crate::ty::{GenericArgs, GenericArgsRef};
+
+///////////////////////////////////////////////////////////////////////////
+/// Evaluated Constants
+
+/// Represents the result of const evaluation via the `eval_to_allocation` query.
+/// Not to be confused with `ConstAllocation`, which directly refers to the underlying data!
+/// Here we indirect via an `AllocId`.
+#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
+pub struct ConstAlloc<'tcx> {
+ /// The value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
+ /// (so you can use `AllocMap::unwrap_memory`).
+ pub alloc_id: AllocId,
+ pub ty: Ty<'tcx>,
+}
+
+/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
+/// array length computations, enum discriminants and the pattern matching logic.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable, Lift)]
+pub enum ConstValue<'tcx> {
+ /// Used for types with `layout::abi::Scalar` ABI.
+ ///
+ /// Not using the enum `Value` to encode that this must not be `Uninit`.
+ Scalar(Scalar),
+
+ /// Only for ZSTs.
+ ZeroSized,
+
+ /// Used for references to unsized types with slice tail.
+ ///
+ /// This is worth an optimized representation since Rust has literals of type `&str` and
+ /// `&[u8]`. Not having to indirect those through an `AllocId` (or two, if we used `Indirect`)
+ /// has shown measurable performance improvements on stress tests. We then reuse this
+ /// optimization for slice-tail types more generally during valtree-to-constval conversion.
+ Slice {
+ /// The allocation storing the slice contents.
+ /// This always points to the beginning of the allocation.
+ data: ConstAllocation<'tcx>,
+ /// The metadata field of the reference.
+ /// This is a "target usize", so we use `u64` as in the interpreter.
+ meta: u64,
+ },
+
+ /// A value not representable by the other variants; needs to be stored in-memory.
+ ///
+ /// Must *not* be used for scalars or ZST, but having `&str` or other slices in this variant is fine.
+ Indirect {
+ /// The backing memory of the value. May contain more memory than needed for just the value
+ /// if this points into some other larger ConstValue.
+ ///
+ /// We use an `AllocId` here instead of a `ConstAllocation<'tcx>` to make sure that when a
+ /// raw constant (which is basically just an `AllocId`) is turned into a `ConstValue` and
+ /// back, we can preserve the original `AllocId`.
+ alloc_id: AllocId,
+ /// Offset into `alloc`
+ offset: Size,
+ },
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ConstValue<'_>, 24);
+
+impl<'tcx> ConstValue<'tcx> {
+ #[inline]
+ pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
+ match *self {
+ ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
+ ConstValue::Scalar(val) => Some(val),
+ }
+ }
+
+ pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
+ self.try_to_scalar()?.try_to_int().ok()
+ }
+
+ pub fn try_to_bits(&self, size: Size) -> Option<u128> {
+ self.try_to_scalar_int()?.to_bits(size).ok()
+ }
+
+ pub fn try_to_bool(&self) -> Option<bool> {
+ self.try_to_scalar_int()?.try_into().ok()
+ }
+
+ pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+ self.try_to_scalar_int()?.try_to_target_usize(tcx).ok()
+ }
+
+ pub fn try_to_bits_for_ty(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> Option<u128> {
+ let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+ self.try_to_bits(size)
+ }
+
+ pub fn from_bool(b: bool) -> Self {
+ ConstValue::Scalar(Scalar::from_bool(b))
+ }
+
+ pub fn from_u64(i: u64) -> Self {
+ ConstValue::Scalar(Scalar::from_u64(i))
+ }
+
+ pub fn from_u128(i: u128) -> Self {
+ ConstValue::Scalar(Scalar::from_u128(i))
+ }
+
+ pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
+ ConstValue::Scalar(Scalar::from_target_usize(i, cx))
+ }
+
+ /// Must only be called on constants of type `&str` or `&[u8]`!
+ pub fn try_get_slice_bytes_for_diagnostics(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> {
+ let (data, start, end) = match self {
+ ConstValue::Scalar(_) | ConstValue::ZeroSized => {
+ bug!("`try_get_slice_bytes` on non-slice constant")
+ }
+ &ConstValue::Slice { data, meta } => (data, 0, meta),
+ &ConstValue::Indirect { alloc_id, offset } => {
+ // The reference itself is stored behind an indirection.
+ // Load the reference, and then load the actual slice contents.
+ let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
+ let ptr_size = tcx.data_layout.pointer_size;
+ if a.size() < offset + 2 * ptr_size {
+ // (partially) dangling reference
+ return None;
+ }
+ // Read the wide pointer components.
+ let ptr = a
+ .read_scalar(
+ &tcx,
+ alloc_range(offset, ptr_size),
+ /* read_provenance */ true,
+ )
+ .ok()?;
+ let ptr = ptr.to_pointer(&tcx).ok()?;
+ let len = a
+ .read_scalar(
+ &tcx,
+ alloc_range(offset + ptr_size, ptr_size),
+ /* read_provenance */ false,
+ )
+ .ok()?;
+ let len = len.to_target_usize(&tcx).ok()?;
+ if len == 0 {
+ return Some(&[]);
+ }
+ // Non-empty slice, must have memory. We know this is a relative pointer.
+ let (inner_alloc_id, offset) = ptr.into_parts();
+ let data = tcx.global_alloc(inner_alloc_id?).unwrap_memory();
+ (data, offset.bytes(), offset.bytes() + len)
+ }
+ };
+
+ // This is for diagnostics only, so we are okay to use `inspect_with_uninit_and_ptr_outside_interpreter`.
+ let start = start.try_into().unwrap();
+ let end = end.try_into().unwrap();
+ Some(data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// Constants
+
+#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum Const<'tcx> {
+ /// This constant came from the type system.
+ ///
+ /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
+ /// this ensures that we consistently produce "clean" values without data in the padding or
+ /// anything like that.
+ Ty(ty::Const<'tcx>),
+
+ /// An unevaluated mir constant which is not part of the type system.
+ ///
+ /// Note that `Ty(ty::ConstKind::Unevaluated)` and this variant are *not* identical! `Ty` will
+ /// always flow through a valtree, so all data not captured in the valtree is lost. This variant
+ /// directly uses the evaluated result of the given constant, including e.g. data stored in
+ /// padding.
+ Unevaluated(UnevaluatedConst<'tcx>, Ty<'tcx>),
+
+ /// This constant cannot go back into the type system, as it represents
+ /// something the type system cannot handle (e.g. pointers).
+ Val(ConstValue<'tcx>, Ty<'tcx>),
+}
+
+impl<'tcx> Const<'tcx> {
+ #[inline(always)]
+ pub fn ty(&self) -> Ty<'tcx> {
+ match self {
+ Const::Ty(c) => c.ty(),
+ Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
+ }
+ }
+
+ #[inline]
+ pub fn try_to_scalar(self) -> Option<Scalar> {
+ match self {
+ Const::Ty(c) => match c.kind() {
+ ty::ConstKind::Value(valtree) => match valtree {
+ ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
+ ty::ValTree::Branch(_) => None,
+ },
+ _ => None,
+ },
+ Const::Val(val, _) => val.try_to_scalar(),
+ Const::Unevaluated(..) => None,
+ }
+ }
+
+ #[inline]
+ pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+ self.try_to_scalar()?.try_to_int().ok()
+ }
+
+ #[inline]
+ pub fn try_to_bits(self, size: Size) -> Option<u128> {
+ self.try_to_scalar_int()?.to_bits(size).ok()
+ }
+
+ #[inline]
+ pub fn try_to_bool(self) -> Option<bool> {
+ self.try_to_scalar_int()?.try_into().ok()
+ }
+
+ #[inline]
+ pub fn eval(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Option<Span>,
+ ) -> Result<ConstValue<'tcx>, ErrorHandled> {
+ match self {
+ Const::Ty(c) => {
+ // We want to consistently have a "clean" value for type system constants (i.e., no
+ // data hidden in the padding), so we always go through a valtree here.
+ let val = c.eval(tcx, param_env, span)?;
+ Ok(tcx.valtree_to_const_val((self.ty(), val)))
+ }
+ Const::Unevaluated(uneval, _) => {
+ // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
+ tcx.const_eval_resolve(param_env, uneval, span)
+ }
+ Const::Val(val, _) => Ok(val),
+ }
+ }
+
+ /// Normalizes the constant to a value or an error if possible.
+ #[inline]
+ pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ match self.eval(tcx, param_env, None) {
+ Ok(val) => Self::Val(val, self.ty()),
+ Err(ErrorHandled::Reported(guar, _span)) => {
+ Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
+ }
+ Err(ErrorHandled::TooGeneric(_span)) => self,
+ }
+ }
+
+ #[inline]
+ pub fn try_eval_scalar(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<Scalar> {
+ self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+ }
+
+ #[inline]
+ pub fn try_eval_scalar_int(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<ScalarInt> {
+ self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
+ }
+
+ #[inline]
+ pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> {
+ let int = self.try_eval_scalar_int(tcx, param_env)?;
+ let size =
+ tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
+ int.to_bits(size).ok()
+ }
+
+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+ #[inline]
+ pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
+ self.try_eval_bits(tcx, param_env)
+ .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
+ }
+
+ #[inline]
+ pub fn try_eval_target_usize(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<u64> {
+ self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
+ }
+
+ #[inline]
+ /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
+ pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 {
+ self.try_eval_target_usize(tcx, param_env)
+ .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
+ }
+
+ #[inline]
+ pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
+ self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
+ }
+
+ #[inline]
+ pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
+ Self::Val(val, ty)
+ }
+
+ pub fn from_bits(
+ tcx: TyCtxt<'tcx>,
+ bits: u128,
+ param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+ ) -> Self {
+ let size = tcx
+ .layout_of(param_env_ty)
+ .unwrap_or_else(|e| {
+ bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
+ })
+ .size;
+ let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
+
+ Self::Val(cv, param_env_ty.value)
+ }
+
+ #[inline]
+ pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+ let cv = ConstValue::from_bool(v);
+ Self::Val(cv, tcx.types.bool)
+ }
+
+ #[inline]
+ pub fn zero_sized(ty: Ty<'tcx>) -> Self {
+ let cv = ConstValue::ZeroSized;
+ Self::Val(cv, ty)
+ }
+
+ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+ let ty = tcx.types.usize;
+ Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
+ }
+
+ #[inline]
+ pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
+ let val = ConstValue::Scalar(s);
+ Self::Val(val, ty)
+ }
+
+ /// Literals are converted to `Const::Val`, const generic parameters are eagerly
+ /// converted to a constant, everything else becomes `Unevaluated`.
+ #[instrument(skip(tcx), level = "debug", ret)]
+ pub fn from_anon_const(
+ tcx: TyCtxt<'tcx>,
+ def: LocalDefId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Self {
+ let body_id = match tcx.hir().get_by_def_id(def) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => {
+ span_bug!(tcx.def_span(def), "from_anon_const can only process anonymous constants")
+ }
+ };
+
+ let expr = &tcx.hir().body(body_id).value;
+ debug!(?expr);
+
+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+ let expr = match &expr.kind {
+ hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+ block.expr.as_ref().unwrap()
+ }
+ _ => expr,
+ };
+ debug!("expr.kind: {:?}", expr.kind);
+
+ let ty = tcx.type_of(def).instantiate_identity();
+ debug!(?ty);
+
+ // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
+ // does not provide the parents generics to anonymous constants. We still allow generic const
+ // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
+ // ever try to substitute the generic parameters in their bodies.
+ //
+ // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
+ // cause issues if we were to remove that special-case and try to evaluate the constant instead.
+ use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+ match expr.kind {
+ ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+ // Find the name and index of the const parameter by indexing the generics of
+ // the parent item and construct a `ParamConst`.
+ let item_def_id = tcx.parent(def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = tcx.item_name(def_id);
+ let ty_const = ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty);
+ debug!(?ty_const);
+
+ return Self::Ty(ty_const);
+ }
+ _ => {}
+ }
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
+ let parent_args = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id)
+ && let Some(parent_did) = parent_hir_id.as_owner()
+ {
+ GenericArgs::identity_for_item(tcx, parent_did)
+ } else {
+ List::empty()
+ };
+ debug!(?parent_args);
+
+ let did = def.to_def_id();
+ let child_args = GenericArgs::identity_for_item(tcx, did);
+ let args = tcx.mk_args_from_iter(parent_args.into_iter().chain(child_args.into_iter()));
+ debug!(?args);
+
+ let span = tcx.def_span(def);
+ let uneval = UnevaluatedConst::new(did, args);
+ debug!(?span, ?param_env);
+
+ match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
+ Ok(val) => {
+ debug!("evaluated const value");
+ Self::Val(val, ty)
+ }
+ Err(_) => {
+ debug!("error encountered during evaluation");
+ // Error was handled in `const_eval_resolve`. Here we just create a
+ // new unevaluated const and error hard later in codegen
+ Self::Unevaluated(
+ UnevaluatedConst {
+ def: did,
+ args: GenericArgs::identity_for_item(tcx, did),
+ promoted: None,
+ },
+ ty,
+ )
+ }
+ }
+ }
+
+ pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+ match c.kind() {
+ ty::ConstKind::Value(valtree) => {
+ // Make sure that if `c` is normalized, then the return value is normalized.
+ let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
+ Self::Val(const_val, c.ty())
+ }
+ _ => Self::Ty(c),
+ }
+ }
+}
+
+/// An unevaluated (potentially generic) constant used in MIR.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub struct UnevaluatedConst<'tcx> {
+ pub def: DefId,
+ pub args: GenericArgsRef<'tcx>,
+ pub promoted: Option<Promoted>,
+}
+
+impl<'tcx> UnevaluatedConst<'tcx> {
+ #[inline]
+ pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
+ assert_eq!(self.promoted, None);
+ ty::UnevaluatedConst { def: self.def, args: self.args }
+ }
+}
+
+impl<'tcx> UnevaluatedConst<'tcx> {
+ #[inline]
+ pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
+ UnevaluatedConst { def, args, promoted: Default::default() }
+ }
+
+ #[inline]
+ pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
+ UnevaluatedConst::new(instance.def_id(), instance.args)
+ }
+}
+
+impl<'tcx> Display for Const<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ match *self {
+ Const::Ty(c) => pretty_print_const(c, fmt, true),
+ Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
+ // FIXME(valtrees): Correctly print mir constants.
+ Const::Unevaluated(..) => {
+ fmt.write_str("_")?;
+ Ok(())
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 1efb54bdb..9ef673922 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -45,16 +45,6 @@ impl ExpressionId {
}
}
-rustc_index::newtype_index! {
- /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
- /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
- /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
- #[derive(HashStable)]
- #[max = 0xFFFF_FFFF]
- #[debug_format = "MappedExpressionIndex({})"]
- pub struct MappedExpressionIndex {}
-}
-
/// Operand of a coverage-counter expression.
///
/// Operands can be a constant zero value, an actual coverage counter, or another
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e6ef5a41e..bc464aca5 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,8 +1,9 @@
-use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
+use super::{AllocId, AllocRange, Pointer, Scalar};
-use crate::mir::interpret::ConstValue;
+use crate::error;
+use crate::mir::{ConstAlloc, ConstValue};
use crate::query::TyCtxtAt;
-use crate::ty::{layout, tls, Ty, ValTree};
+use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{
@@ -11,7 +12,7 @@ use rustc_errors::{
};
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
-use rustc_span::def_id::DefId;
+use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
use std::borrow::Cow;
@@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
pub enum ErrorHandled {
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
- Reported(ReportedErrorInfo),
+ Reported(ReportedErrorInfo, Span),
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the args didn't fully monomorphize it.
- TooGeneric,
+ TooGeneric(Span),
}
impl From<ErrorGuaranteed> for ErrorHandled {
#[inline]
fn from(error: ErrorGuaranteed) -> ErrorHandled {
- ErrorHandled::Reported(error.into())
+ ErrorHandled::Reported(error.into(), DUMMY_SP)
+ }
+}
+
+impl ErrorHandled {
+ pub fn with_span(self, span: Span) -> Self {
+ match self {
+ ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
+ ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
+ }
+ }
+
+ pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
+ match self {
+ &ErrorHandled::Reported(err, span) => {
+ if !err.is_tainted_by_errors && !span.is_dummy() {
+ tcx.sess.emit_err(error::ErroneousConstant { span });
+ }
+ err.error
+ }
+ &ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
+ span,
+ "encountered TooGeneric error when monomorphic data was expected",
+ ),
+ }
+ }
+
+ pub fn emit_note(&self, tcx: TyCtxt<'_>) {
+ match self {
+ &ErrorHandled::Reported(err, span) => {
+ if !err.is_tainted_by_errors && !span.is_dummy() {
+ tcx.sess.emit_note(error::ErroneousConstant { span });
+ }
+ }
+ &ErrorHandled::TooGeneric(_) => {}
+ }
}
}
@@ -45,12 +81,6 @@ impl ReportedErrorInfo {
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
ReportedErrorInfo { is_tainted_by_errors: true, error }
}
-
- /// Returns true if evaluation failed because MIR was tainted by errors.
- #[inline]
- pub fn is_tainted_by_errors(self) -> bool {
- self.is_tainted_by_errors
- }
}
impl From<ErrorGuaranteed> for ReportedErrorInfo {
@@ -67,10 +97,12 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
}
}
-TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
+TrivialTypeTraversalImpls! { ErrorHandled }
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
+/// This is needed in `thir::pattern::lower_inline_const`.
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
pub fn struct_error<'tcx>(
@@ -160,6 +192,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
}
}
+impl From<ErrorHandled> for InterpErrorInfo<'_> {
+ fn from(err: ErrorHandled) -> Self {
+ InterpError::InvalidProgram(match err {
+ ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
+ ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
+ })
+ .into()
+ }
+}
+
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
InterpErrorInfo(Box::new(InterpErrorInfoInner {
@@ -255,9 +297,16 @@ impl_into_diagnostic_arg_through_debug! {
/// Error information for when the program caused Undefined Behavior.
#[derive(Debug)]
-pub enum UndefinedBehaviorInfo<'a> {
+pub enum UndefinedBehaviorInfo<'tcx> {
/// Free-form case. Only for errors that are never caught! Used by miri
Ub(String),
+ // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
+ // dispatched
+ /// A custom (free-form) fluent-translated error, created by `err_ub_custom!`.
+ Custom(crate::error::CustomSubdiagnostic<'tcx>),
+ /// Validation error.
+ ValidationError(ValidationErrorInfo<'tcx>),
+
/// Unreachable code was executed.
Unreachable,
/// A slice/array index projection went out-of-bounds.
@@ -319,12 +368,10 @@ pub enum UndefinedBehaviorInfo<'a> {
UninhabitedEnumVariantWritten(VariantIdx),
/// An uninhabited enum variant is projected.
UninhabitedEnumVariantRead(VariantIdx),
- /// Validation error.
- ValidationError(ValidationErrorInfo<'a>),
- // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
- // dispatched
- /// A custom (free-form) error, created by `err_ub_custom!`.
- Custom(crate::error::CustomSubdiagnostic<'a>),
+ /// ABI-incompatible argument types.
+ AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+ /// ABI-incompatible return types.
+ AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
}
#[derive(Debug, Clone, Copy)]
@@ -415,6 +462,8 @@ pub enum UnsupportedOpInfo {
/// Free-form case. Only for errors that are never caught!
// FIXME still use translatable diagnostics
Unsupported(String),
+ /// Unsized local variables.
+ UnsizedLocal,
//
// The variants below are only reachable from CTFE/const prop, miri will never emit them.
//
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 3543158bf..d21f82f04 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -149,7 +149,7 @@ pub use self::error::{
UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
};
-pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
+pub use self::value::Scalar;
pub use self::allocation::{
alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation,
@@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
/// - A constant
/// - A static
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct GlobalId<'tcx> {
/// For a constant or static, the `Instance` of the item itself.
/// For a promoted global, the `Instance` of the function they belong to.
@@ -389,7 +389,7 @@ impl<'s> AllocDecodingSession<'s> {
trace!("creating fn alloc ID");
let instance = ty::Instance::decode(decoder);
trace!("decoded fn alloc instance: {:?}", instance);
- let alloc_id = decoder.interner().create_fn_alloc(instance);
+ let alloc_id = decoder.interner().reserve_and_set_fn_alloc(instance);
alloc_id
}
AllocDiscriminant::VTable => {
@@ -399,7 +399,8 @@ impl<'s> AllocDecodingSession<'s> {
let poly_trait_ref =
<Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
- let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
+ let alloc_id =
+ decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref);
alloc_id
}
AllocDiscriminant::Static => {
@@ -407,7 +408,7 @@ impl<'s> AllocDecodingSession<'s> {
trace!("creating extern static alloc ID");
let did = <DefId as Decodable<D>>::decode(decoder);
trace!("decoded static def-ID: {:?}", did);
- let alloc_id = decoder.interner().create_static_alloc(did);
+ let alloc_id = decoder.interner().reserve_and_set_static_alloc(did);
alloc_id
}
}
@@ -544,13 +545,13 @@ impl<'tcx> TyCtxt<'tcx> {
/// Generates an `AllocId` for a static or return a cached one in case this function has been
/// called on the same static before.
- pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
+ pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId {
self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
}
/// Generates an `AllocId` for a function. Depending on the function type,
/// this might get deduplicated or assigned a new ID each time.
- pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
+ pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
// duplicated across crates.
@@ -575,7 +576,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
/// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
- pub fn create_vtable_alloc(
+ pub fn reserve_and_set_vtable_alloc(
self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
@@ -588,7 +589,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Statics with identical content will still point to the same `Allocation`, i.e.,
/// their data will be deduplicated through `Allocation` interning -- but they
/// are different places in memory and as such need different IDs.
- pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
+ pub fn reserve_and_set_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
let id = self.reserve_alloc_id();
self.set_alloc_id_memory(id, mem);
id
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 65d049193..1c9ce1cb1 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -103,7 +103,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
/// some global state.
/// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`.
-pub trait Provenance: Copy + fmt::Debug {
+pub trait Provenance: Copy + fmt::Debug + 'static {
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
/// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are
/// different from what the Abstract Machine prescribes, so the interpreter must prevent any
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index fc659ce18..fbf6403ea 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
}
- Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(err) => Err(ErrorHandled::Reported(err.into())),
+ // For errors during resolution, we deliberately do not point at the usage site of the constant,
+ // since for these errors the place the constant is used shouldn't matter.
+ Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+ Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> {
}
})
}
- Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(err) => Err(ErrorHandled::Reported(err.into())),
+ // For errors during resolution, we deliberately do not point at the usage site of the constant,
+ // since for these errors the place the constant is used shouldn't matter.
+ Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+ Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> {
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
if let Some(span) = span {
- self.at(span).eval_to_const_value_raw(inputs)
+ // The query doesn't know where it is being invoked, so we need to fix the span.
+ self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_const_value_raw(inputs)
}
@@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
let inputs = self.erase_regions(param_env.and(cid));
debug!(?inputs);
if let Some(span) = span {
- self.at(span).eval_to_valtree(inputs)
+ // The query doesn't know where it is being invoked, so we need to fix the span.
+ self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_valtree(inputs)
}
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 5345a6588..0d548f886 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -9,102 +9,9 @@ use rustc_apfloat::{
use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};
-use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
+use crate::ty::ScalarInt;
-use super::{
- AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
- ScalarSizeMismatch,
-};
-
-/// Represents the result of const evaluation via the `eval_to_allocation` query.
-#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
-pub struct ConstAlloc<'tcx> {
- /// The value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
- /// (so you can use `AllocMap::unwrap_memory`).
- pub alloc_id: AllocId,
- pub ty: Ty<'tcx>,
-}
-
-/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
-/// array length computations, enum discriminants and the pattern matching logic.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
-#[derive(HashStable, Lift)]
-pub enum ConstValue<'tcx> {
- /// Used only for types with `layout::abi::Scalar` ABI.
- ///
- /// Not using the enum `Value` to encode that this must not be `Uninit`.
- Scalar(Scalar),
-
- /// Only used for ZSTs.
- ZeroSized,
-
- /// Used only for `&[u8]` and `&str`
- Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
-
- /// A value not represented/representable by `Scalar` or `Slice`
- ByRef {
- /// The backing memory of the value, may contain more memory than needed for just the value
- /// in order to share `ConstAllocation`s between values
- alloc: ConstAllocation<'tcx>,
- /// Offset into `alloc`
- offset: Size,
- },
-}
-
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ConstValue<'_>, 32);
-
-impl<'tcx> ConstValue<'tcx> {
- #[inline]
- pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
- match *self {
- ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
- ConstValue::Scalar(val) => Some(val),
- }
- }
-
- pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
- self.try_to_scalar()?.try_to_int().ok()
- }
-
- pub fn try_to_bits(&self, size: Size) -> Option<u128> {
- self.try_to_scalar_int()?.to_bits(size).ok()
- }
-
- pub fn try_to_bool(&self) -> Option<bool> {
- self.try_to_scalar_int()?.try_into().ok()
- }
-
- pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
- self.try_to_scalar_int()?.try_to_target_usize(tcx).ok()
- }
-
- pub fn try_to_bits_for_ty(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- ) -> Option<u128> {
- let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
- self.try_to_bits(size)
- }
-
- pub fn from_bool(b: bool) -> Self {
- ConstValue::Scalar(Scalar::from_bool(b))
- }
-
- pub fn from_u64(i: u64) -> Self {
- ConstValue::Scalar(Scalar::from_u64(i))
- }
-
- pub fn from_u128(i: u128) -> Self {
- ConstValue::Scalar(Scalar::from_u128(i))
- }
-
- pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
- ConstValue::Scalar(Scalar::from_target_usize(i, cx))
- }
-}
+use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, ScalarSizeMismatch};
/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in
@@ -267,6 +174,16 @@ impl<Prov> Scalar<Prov> {
}
#[inline]
+ pub fn from_i8(i: i8) -> Self {
+ Self::from_int(i, Size::from_bits(8))
+ }
+
+ #[inline]
+ pub fn from_i16(i: i16) -> Self {
+ Self::from_int(i, Size::from_bits(16))
+ }
+
+ #[inline]
pub fn from_i32(i: i32) -> Self {
Self::from_int(i, Size::from_bits(32))
}
@@ -494,29 +411,18 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
}
#[inline]
- pub fn to_f32(self) -> InterpResult<'tcx, Single> {
- // Going through `u32` to check size and truncation.
- Ok(Single::from_bits(self.to_u32()?.into()))
+ pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
+ // Going through `to_uint` to check size and truncation.
+ Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?))
}
#[inline]
- pub fn to_f64(self) -> InterpResult<'tcx, Double> {
- // Going through `u64` to check size and truncation.
- Ok(Double::from_bits(self.to_u64()?.into()))
+ pub fn to_f32(self) -> InterpResult<'tcx, Single> {
+ self.to_float()
}
-}
-/// Gets the bytes of a constant slice value.
-pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
- if let ConstValue::Slice { data, start, end } = val {
- let len = end - start;
- data.inner()
- .get_bytes_strip_provenance(
- cx,
- AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
- )
- .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
- } else {
- bug!("expected const slice, but found another const value");
+ #[inline]
+ pub fn to_f64(self) -> InterpResult<'tcx, Double> {
+ self.to_float()
}
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 9ef3a1b30..0bb1c66da 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2,29 +2,29 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
-use crate::mir::interpret::{
- AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
-};
+use crate::mir::interpret::{AllocRange, ConstAllocation, ErrorHandled, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::visit::TypeVisitableExt;
use crate::ty::{self, List, Ty, TyCtxt};
-use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
-use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
+use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
+use crate::ty::{GenericArg, GenericArgsRef};
use rustc_data_structures::captures::Captures;
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::{self, GeneratorKind, ImplicitSelfKind};
use rustc_hir::{self as hir, HirId};
use rustc_session::Session;
-use rustc_target::abi::{FieldIdx, Size, VariantIdx};
+use rustc_target::abi::{FieldIdx, VariantIdx};
use polonius_engine::Atom;
pub use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -35,7 +35,9 @@ use rustc_span::{Span, DUMMY_SP};
use either::Either;
use std::borrow::Cow;
-use std::fmt::{self, Debug, Display, Formatter, Write};
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+use std::fmt::{self, Debug, Formatter};
use std::ops::{Index, IndexMut};
use std::{iter, mem};
@@ -43,6 +45,7 @@ pub use self::query::*;
pub use basic_blocks::BasicBlocks;
mod basic_blocks;
+mod consts;
pub mod coverage;
mod generic_graph;
pub mod generic_graphviz;
@@ -53,11 +56,10 @@ pub mod patch;
pub mod pretty;
mod query;
pub mod spanview;
+mod statement;
mod syntax;
-pub use syntax::*;
pub mod tcx;
-pub mod terminator;
-pub use terminator::*;
+mod terminator;
pub mod traversal;
mod type_foldable;
@@ -68,6 +70,11 @@ pub use self::graphviz::write_mir_graphviz;
pub use self::pretty::{
create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
};
+pub use consts::*;
+use pretty::pretty_print_const_value;
+pub use statement::*;
+pub use syntax::*;
+pub use terminator::*;
/// Types for locals
pub type LocalDecls<'tcx> = IndexSlice<Local, LocalDecl<'tcx>>;
@@ -97,6 +104,36 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
}
}
+thread_local! {
+ static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
+ RefCell::new(FxHashMap::default())
+ };
+}
+
+/// Converts a MIR pass name into a snake case form to match the profiling naming style.
+fn to_profiler_name(type_name: &'static str) -> &'static str {
+ PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
+ Entry::Occupied(e) => *e.get(),
+ Entry::Vacant(e) => {
+ let snake_case: String = type_name
+ .chars()
+ .flat_map(|c| {
+ if c.is_ascii_uppercase() {
+ vec!['_', c.to_ascii_lowercase()]
+ } else if c == '-' {
+ vec!['_']
+ } else {
+ vec![c]
+ }
+ })
+ .collect();
+ let result = &*String::leak(format!("mir_pass{}", snake_case));
+ e.insert(result);
+ result
+ }
+ })
+}
+
/// A streamlined trait that you can implement to create a pass; the
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
@@ -106,6 +143,10 @@ pub trait MirPass<'tcx> {
if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
}
+ fn profiler_name(&self) -> &'static str {
+ to_profiler_name(self.name())
+ }
+
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
fn is_enabled(&self, _sess: &Session) -> bool {
true
@@ -277,7 +318,7 @@ pub struct Body<'tcx> {
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
/// We hold in this field all the constants we are not able to evaluate yet.
- pub required_consts: Vec<Constant<'tcx>>,
+ pub required_consts: Vec<ConstOperand<'tcx>>,
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
///
@@ -527,6 +568,34 @@ impl<'tcx> Body<'tcx> {
pub fn is_custom_mir(&self) -> bool {
self.injection_phase.is_some()
}
+
+ /// *Must* be called once the full substitution for this body is known, to ensure that the body
+ /// is indeed fit for code generation or consumption more generally.
+ ///
+ /// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
+ /// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
+ /// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
+ /// functions makes it seem like exposing the generic args is not the intended strategy.)
+ ///
+ /// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
+ /// so we cannot just immediately ICE on TooGeneric.
+ ///
+ /// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
+ pub fn post_mono_checks(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>,
+ ) -> Result<(), ErrorHandled> {
+ // For now, the only thing we have to check is is to ensure that all the constants used in
+ // the body successfully evaluate.
+ for &const_ in &self.required_consts {
+ let c = normalize_const(const_.const_)?;
+ c.eval(tcx, param_env, Some(const_.span))?;
+ }
+
+ Ok(())
+ }
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -706,7 +775,7 @@ pub enum BindingForm<'tcx> {
RefForGuard,
}
-TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
+TrivialTypeTraversalImpls! { BindingForm<'tcx> }
mod binding_form_impl {
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -1027,20 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> {
pub enum VarDebugInfoContents<'tcx> {
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
Place(Place<'tcx>),
- Const(Constant<'tcx>),
- /// The user variable's data is split across several fragments,
- /// each described by a `VarDebugInfoFragment`.
- /// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
- /// and LLVM's `DW_OP_LLVM_fragment` for more details on
- /// the underlying debuginfo feature this relies on.
- Composite {
- /// Type of the original user variable.
- /// This cannot contain a union or an enum.
- ty: Ty<'tcx>,
- /// All the parts of the original user variable, which ended
- /// up in disjoint places, due to optimizations.
- fragments: Vec<VarDebugInfoFragment<'tcx>>,
- },
+ Const(ConstOperand<'tcx>),
}
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
@@ -1048,19 +1104,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
match self {
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
- VarDebugInfoContents::Composite { ty, fragments } => {
- write!(fmt, "{ty:?}{{ ")?;
- for f in fragments.iter() {
- write!(fmt, "{f:?}, ")?;
- }
- write!(fmt, "}}")
- }
}
}
}
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct VarDebugInfoFragment<'tcx> {
+ /// Type of the original user variable.
+ /// This cannot contain a union or an enum.
+ pub ty: Ty<'tcx>,
+
/// Where in the composite user variable this fragment is,
/// represented as a "projection" into the composite variable.
/// At lower levels, this corresponds to a byte/bit range.
@@ -1071,29 +1124,10 @@ pub struct VarDebugInfoFragment<'tcx> {
// to match on the discriminant, or by using custom type debuginfo
// with non-overlapping variants for the composite variable.
pub projection: Vec<PlaceElem<'tcx>>,
-
- /// Where the data for this fragment can be found.
- /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
- pub contents: Place<'tcx>,
-}
-
-impl Debug for VarDebugInfoFragment<'_> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- for elem in self.projection.iter() {
- match elem {
- ProjectionElem::Field(field, _) => {
- write!(fmt, ".{:?}", field.index())?;
- }
- _ => bug!("unsupported fragment projection `{:?}`", elem),
- }
- }
-
- write!(fmt, " => {:?}", self.contents)
- }
}
/// Debug information pertaining to a user variable.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct VarDebugInfo<'tcx> {
pub name: Symbol,
@@ -1102,6 +1136,13 @@ pub struct VarDebugInfo<'tcx> {
/// (see `LocalDecl`'s `source_info` field for more details).
pub source_info: SourceInfo,
+ /// The user variable's data is split across several fragments,
+ /// each described by a `VarDebugInfoFragment`.
+ /// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
+ /// and LLVM's `DW_OP_LLVM_fragment` for more details on
+ /// the underlying debuginfo feature this relies on.
+ pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>,
+
/// Where the data for this user variable is to be found.
pub value: VarDebugInfoContents<'tcx>,
@@ -1267,542 +1308,6 @@ impl<'tcx> BasicBlockData<'tcx> {
}
}
-impl<O> AssertKind<O> {
- /// Returns true if this an overflow checking assertion controlled by -C overflow-checks.
- pub fn is_optional_overflow_check(&self) -> bool {
- use AssertKind::*;
- use BinOp::*;
- matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
- }
-
- /// Getting a description does not require `O` to be printable, and does not
- /// require allocation.
- /// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` separately.
- pub fn description(&self) -> &'static str {
- use AssertKind::*;
- match self {
- Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
- Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
- Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
- Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
- Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
- OverflowNeg(_) => "attempt to negate with overflow",
- Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
- Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
- Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
- DivisionByZero(_) => "attempt to divide by zero",
- RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
- ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
- ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
- ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
- ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
- BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
- bug!("Unexpected AssertKind")
- }
- }
- }
-
- /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
- pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
- where
- O: Debug,
- {
- use AssertKind::*;
- match self {
- BoundsCheck { ref len, ref index } => write!(
- f,
- "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
- ),
-
- OverflowNeg(op) => {
- write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
- }
- DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
- RemainderByZero(op) => write!(
- f,
- "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
- ),
- Overflow(BinOp::Add, l, r) => write!(
- f,
- "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
- ),
- Overflow(BinOp::Sub, l, r) => write!(
- f,
- "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
- ),
- Overflow(BinOp::Mul, l, r) => write!(
- f,
- "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
- ),
- Overflow(BinOp::Div, l, r) => write!(
- f,
- "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
- ),
- Overflow(BinOp::Rem, l, r) => write!(
- f,
- "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
- ),
- Overflow(BinOp::Shr, _, r) => {
- write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {r:?}")
- }
- Overflow(BinOp::Shl, _, r) => {
- write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
- }
- MisalignedPointerDereference { required, found } => {
- write!(
- f,
- "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
- )
- }
- _ => write!(f, "\"{}\"", self.description()),
- }
- }
-
- pub fn diagnostic_message(&self) -> DiagnosticMessage {
- use crate::fluent_generated::*;
- use AssertKind::*;
-
- match self {
- BoundsCheck { .. } => middle_bounds_check,
- Overflow(BinOp::Shl, _, _) => middle_assert_shl_overflow,
- Overflow(BinOp::Shr, _, _) => middle_assert_shr_overflow,
- Overflow(_, _, _) => middle_assert_op_overflow,
- OverflowNeg(_) => middle_assert_overflow_neg,
- DivisionByZero(_) => middle_assert_divide_by_zero,
- RemainderByZero(_) => middle_assert_remainder_by_zero,
- ResumedAfterReturn(GeneratorKind::Async(_)) => middle_assert_async_resume_after_return,
- ResumedAfterReturn(GeneratorKind::Gen) => middle_assert_generator_resume_after_return,
- ResumedAfterPanic(GeneratorKind::Async(_)) => middle_assert_async_resume_after_panic,
- ResumedAfterPanic(GeneratorKind::Gen) => middle_assert_generator_resume_after_panic,
-
- MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref,
- }
- }
-
- pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>))
- where
- O: fmt::Debug,
- {
- use AssertKind::*;
-
- macro_rules! add {
- ($name: expr, $value: expr) => {
- adder($name.into(), $value.into_diagnostic_arg());
- };
- }
-
- match self {
- BoundsCheck { len, index } => {
- add!("len", format!("{len:?}"));
- add!("index", format!("{index:?}"));
- }
- Overflow(BinOp::Shl | BinOp::Shr, _, val)
- | DivisionByZero(val)
- | RemainderByZero(val)
- | OverflowNeg(val) => {
- add!("val", format!("{val:#?}"));
- }
- Overflow(binop, left, right) => {
- add!("op", binop.to_hir_binop().as_str());
- add!("left", format!("{left:#?}"));
- add!("right", format!("{right:#?}"));
- }
- ResumedAfterReturn(_) | ResumedAfterPanic(_) => {}
- MisalignedPointerDereference { required, found } => {
- add!("required", format!("{required:#?}"));
- add!("found", format!("{found:#?}"));
- }
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Statements
-
-/// A statement in a basic block, including information about its source code.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
-pub struct Statement<'tcx> {
- pub source_info: SourceInfo,
- pub kind: StatementKind<'tcx>,
-}
-
-impl Statement<'_> {
- /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
- /// invalidating statement indices in `Location`s.
- 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 Debug for Statement<'_> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- use self::StatementKind::*;
- match self.kind {
- Assign(box (ref place, ref rv)) => write!(fmt, "{place:?} = {rv:?}"),
- FakeRead(box (ref cause, ref place)) => {
- write!(fmt, "FakeRead({cause:?}, {place:?})")
- }
- Retag(ref kind, ref place) => write!(
- fmt,
- "Retag({}{:?})",
- match kind {
- RetagKind::FnEntry => "[fn entry] ",
- RetagKind::TwoPhase => "[2phase] ",
- RetagKind::Raw => "[raw] ",
- RetagKind::Default => "",
- },
- place,
- ),
- StorageLive(ref place) => write!(fmt, "StorageLive({place:?})"),
- StorageDead(ref place) => write!(fmt, "StorageDead({place:?})"),
- SetDiscriminant { ref place, variant_index } => {
- write!(fmt, "discriminant({place:?}) = {variant_index:?}")
- }
- Deinit(ref place) => write!(fmt, "Deinit({place:?})"),
- PlaceMention(ref place) => {
- write!(fmt, "PlaceMention({place:?})")
- }
- AscribeUserType(box (ref place, ref c_ty), ref variance) => {
- write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
- }
- Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
- write!(fmt, "Coverage::{kind:?} for {rgn:?}")
- }
- Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
- Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
- ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
- Nop => write!(fmt, "nop"),
- }
- }
-}
-
-impl<'tcx> StatementKind<'tcx> {
- pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
- match self {
- StatementKind::Assign(x) => Some(x),
- _ => None,
- }
- }
-
- pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> {
- match self {
- StatementKind::Assign(x) => Some(x),
- _ => None,
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Places
-
-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.
- fn is_indirect(&self) -> bool {
- match self {
- Self::Deref => true,
-
- Self::Field(_, _)
- | Self::Index(_)
- | Self::OpaqueCast(_)
- | Self::ConstantIndex { .. }
- | Self::Subslice { .. }
- | Self::Downcast(_, _) => false,
- }
- }
-
- /// Returns `true` if the target of this projection always refers to the same memory region
- /// whatever the state of the program.
- pub fn is_stable_offset(&self) -> bool {
- match self {
- Self::Deref | Self::Index(_) => false,
- Self::Field(_, _)
- | Self::OpaqueCast(_)
- | Self::ConstantIndex { .. }
- | Self::Subslice { .. }
- | Self::Downcast(_, _) => true,
- }
- }
-
- /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
- pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
- matches!(*self, Self::Downcast(_, x) if x == v)
- }
-
- /// Returns `true` if this is a `Field` projection with the given index.
- pub fn is_field_to(&self, f: FieldIdx) -> bool {
- matches!(*self, Self::Field(x, _) if x == f)
- }
-
- /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
- pub fn can_use_in_debuginfo(&self) -> bool {
- match self {
- Self::ConstantIndex { from_end: false, .. }
- | Self::Deref
- | Self::Downcast(_, _)
- | Self::Field(_, _) => true,
- Self::ConstantIndex { from_end: true, .. }
- | Self::Index(_)
- | Self::OpaqueCast(_)
- | Self::Subslice { .. } => false,
- }
- }
-}
-
-/// Alias for projections as they appear in `UserTypeProjection`, where we
-/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
-pub type ProjectionKind = ProjectionElem<(), ()>;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct PlaceRef<'tcx> {
- pub local: Local,
- pub projection: &'tcx [PlaceElem<'tcx>],
-}
-
-// Once we stop implementing `Ord` for `DefId`,
-// this impl will be unnecessary. Until then, we'll
-// leave this impl in place to prevent re-adding a
-// dependency on the `Ord` impl for `DefId`
-impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
-
-impl<'tcx> Place<'tcx> {
- // FIXME change this to a const fn by also making List::empty a const fn.
- pub fn return_place() -> Place<'tcx> {
- Place { local: RETURN_PLACE, projection: List::empty() }
- }
-
- /// Returns `true` if this `Place` contains a `Deref` projection.
- ///
- /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
- /// same region of memory as its base.
- pub fn is_indirect(&self) -> bool {
- self.projection.iter().any(|elem| elem.is_indirect())
- }
-
- /// Returns `true` if this `Place`'s first projection is `Deref`.
- ///
- /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
- /// `Deref` projections can only occur as the first projection. In that case this method
- /// is equivalent to `is_indirect`, but faster.
- pub fn is_indirect_first_projection(&self) -> bool {
- self.as_ref().is_indirect_first_projection()
- }
-
- /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
- /// a single deref of a local.
- #[inline(always)]
- pub fn local_or_deref_local(&self) -> Option<Local> {
- self.as_ref().local_or_deref_local()
- }
-
- /// If this place represents a local variable like `_X` with no
- /// projections, return `Some(_X)`.
- #[inline(always)]
- pub fn as_local(&self) -> Option<Local> {
- self.as_ref().as_local()
- }
-
- #[inline]
- pub fn as_ref(&self) -> PlaceRef<'tcx> {
- PlaceRef { local: self.local, projection: &self.projection }
- }
-
- /// Iterate over the projections in evaluation order, i.e., the first element is the base with
- /// its projection and then subsequently more projections are added.
- /// As a concrete example, given the place a.b.c, this would yield:
- /// - (a, .b)
- /// - (a.b, .c)
- ///
- /// Given a place without projections, the iterator is empty.
- #[inline]
- pub fn iter_projections(
- self,
- ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
- self.as_ref().iter_projections()
- }
-
- /// Generates a new place by appending `more_projections` to the existing ones
- /// and interning the result.
- pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
- if more_projections.is_empty() {
- return self;
- }
-
- self.as_ref().project_deeper(more_projections, tcx)
- }
-}
-
-impl From<Local> for Place<'_> {
- #[inline]
- fn from(local: Local) -> Self {
- Place { local, projection: List::empty() }
- }
-}
-
-impl<'tcx> PlaceRef<'tcx> {
- /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
- /// a single deref of a local.
- pub fn local_or_deref_local(&self) -> Option<Local> {
- match *self {
- PlaceRef { local, projection: [] }
- | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
- _ => None,
- }
- }
-
- /// Returns `true` if this `Place` contains a `Deref` projection.
- ///
- /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
- /// same region of memory as its base.
- pub fn is_indirect(&self) -> bool {
- self.projection.iter().any(|elem| elem.is_indirect())
- }
-
- /// Returns `true` if this `Place`'s first projection is `Deref`.
- ///
- /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
- /// `Deref` projections can only occur as the first projection. In that case this method
- /// is equivalent to `is_indirect`, but faster.
- pub fn is_indirect_first_projection(&self) -> bool {
- // To make sure this is not accidentally used in wrong mir phase
- debug_assert!(
- self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
- );
- self.projection.first() == Some(&PlaceElem::Deref)
- }
-
- /// If this place represents a local variable like `_X` with no
- /// projections, return `Some(_X)`.
- #[inline]
- pub fn as_local(&self) -> Option<Local> {
- match *self {
- PlaceRef { local, projection: [] } => Some(local),
- _ => None,
- }
- }
-
- #[inline]
- pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
- if let &[ref proj_base @ .., elem] = self.projection {
- Some((PlaceRef { local: self.local, projection: proj_base }, elem))
- } else {
- None
- }
- }
-
- /// Iterate over the projections in evaluation order, i.e., the first element is the base with
- /// its projection and then subsequently more projections are added.
- /// As a concrete example, given the place a.b.c, this would yield:
- /// - (a, .b)
- /// - (a.b, .c)
- ///
- /// Given a place without projections, the iterator is empty.
- #[inline]
- pub fn iter_projections(
- self,
- ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
- self.projection.iter().enumerate().map(move |(i, proj)| {
- let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
- (base, *proj)
- })
- }
-
- /// Generates a new place by appending `more_projections` to the existing ones
- /// and interning the result.
- pub fn project_deeper(
- self,
- more_projections: &[PlaceElem<'tcx>],
- tcx: TyCtxt<'tcx>,
- ) -> Place<'tcx> {
- let mut v: Vec<PlaceElem<'tcx>>;
-
- let new_projections = if self.projection.is_empty() {
- more_projections
- } else {
- v = Vec::with_capacity(self.projection.len() + more_projections.len());
- v.extend(self.projection);
- v.extend(more_projections);
- &v
- };
-
- Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
- }
-}
-
-impl Debug for Place<'_> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- for elem in self.projection.iter().rev() {
- match elem {
- ProjectionElem::OpaqueCast(_)
- | ProjectionElem::Downcast(_, _)
- | ProjectionElem::Field(_, _) => {
- write!(fmt, "(").unwrap();
- }
- ProjectionElem::Deref => {
- write!(fmt, "(*").unwrap();
- }
- ProjectionElem::Index(_)
- | ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Subslice { .. } => {}
- }
- }
-
- write!(fmt, "{:?}", self.local)?;
-
- for elem in self.projection.iter() {
- match elem {
- ProjectionElem::OpaqueCast(ty) => {
- write!(fmt, " as {ty})")?;
- }
- ProjectionElem::Downcast(Some(name), _index) => {
- write!(fmt, " as {name})")?;
- }
- ProjectionElem::Downcast(None, index) => {
- write!(fmt, " as variant#{index:?})")?;
- }
- ProjectionElem::Deref => {
- write!(fmt, ")")?;
- }
- ProjectionElem::Field(field, ty) => {
- write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
- }
- ProjectionElem::Index(ref index) => {
- write!(fmt, "[{index:?}]")?;
- }
- ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
- write!(fmt, "[{offset:?} of {min_length:?}]")?;
- }
- ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
- write!(fmt, "[-{offset:?} of {min_length:?}]")?;
- }
- ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => {
- write!(fmt, "[{from:?}:]")?;
- }
- ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => {
- write!(fmt, "[:-{to:?}]")?;
- }
- ProjectionElem::Subslice { from, to, from_end: true } => {
- write!(fmt, "[{from:?}:-{to:?}]")?;
- }
- ProjectionElem::Subslice { from, to, from_end: false } => {
- write!(fmt, "[{from:?}..{to:?}]")?;
- }
- }
- }
-
- Ok(())
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// Scopes
@@ -1881,719 +1386,12 @@ pub struct SourceScopeLocalData {
pub safety: Safety,
}
-///////////////////////////////////////////////////////////////////////////
-// Operands
-
-impl<'tcx> Debug for Operand<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- use self::Operand::*;
- match *self {
- Constant(ref a) => write!(fmt, "{a:?}"),
- Copy(ref place) => write!(fmt, "{place:?}"),
- Move(ref place) => write!(fmt, "move {place:?}"),
- }
- }
-}
-
-impl<'tcx> Operand<'tcx> {
- /// Convenience helper to make a constant that refers to the fn
- /// with given `DefId` and args. Since this is used to synthesize
- /// MIR, assumes `user_ty` is None.
- pub fn function_handle(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- args: impl IntoIterator<Item = GenericArg<'tcx>>,
- span: Span,
- ) -> Self {
- let ty = Ty::new_fn_def(tcx, def_id, args);
- Operand::Constant(Box::new(Constant {
- span,
- user_ty: None,
- literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
- }))
- }
-
- pub fn is_move(&self) -> bool {
- matches!(self, Operand::Move(..))
- }
-
- /// Convenience helper to make a literal-like constant from a given scalar value.
- /// Since this is used to synthesize MIR, assumes `user_ty` is None.
- pub fn const_from_scalar(
- tcx: TyCtxt<'tcx>,
- ty: Ty<'tcx>,
- val: Scalar,
- span: Span,
- ) -> Operand<'tcx> {
- debug_assert!({
- let param_env_and_ty = ty::ParamEnv::empty().and(ty);
- let type_size = tcx
- .layout_of(param_env_and_ty)
- .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
- .size;
- let scalar_size = match val {
- Scalar::Int(int) => int.size(),
- _ => panic!("Invalid scalar type {val:?}"),
- };
- scalar_size == type_size
- });
- Operand::Constant(Box::new(Constant {
- span,
- user_ty: None,
- literal: ConstantKind::Val(ConstValue::Scalar(val), ty),
- }))
- }
-
- pub fn to_copy(&self) -> Self {
- match *self {
- Operand::Copy(_) | Operand::Constant(_) => self.clone(),
- Operand::Move(place) => Operand::Copy(place),
- }
- }
-
- /// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a
- /// constant.
- pub fn place(&self) -> Option<Place<'tcx>> {
- match self {
- Operand::Copy(place) | Operand::Move(place) => Some(*place),
- Operand::Constant(_) => None,
- }
- }
-
- /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
- /// place.
- pub fn constant(&self) -> Option<&Constant<'tcx>> {
- match self {
- Operand::Constant(x) => Some(&**x),
- Operand::Copy(_) | Operand::Move(_) => None,
- }
- }
-
- /// Gets the `ty::FnDef` from an operand if it's a constant function item.
- ///
- /// While this is unlikely in general, it's the normal case of what you'll
- /// find as the `func` in a [`TerminatorKind::Call`].
- pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
- let const_ty = self.constant()?.literal.ty();
- if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-/// Rvalues
-
-impl<'tcx> Rvalue<'tcx> {
- /// Returns true if rvalue can be safely removed when the result is unused.
- #[inline]
- pub fn is_safe_to_remove(&self) -> bool {
- match self {
- // Pointer to int casts may be side-effects due to exposing the provenance.
- // While the model is undecided, we should be conservative. See
- // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
- Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
-
- Rvalue::Use(_)
- | Rvalue::CopyForDeref(_)
- | Rvalue::Repeat(_, _)
- | Rvalue::Ref(_, _, _)
- | Rvalue::ThreadLocalRef(_)
- | Rvalue::AddressOf(_, _)
- | Rvalue::Len(_)
- | Rvalue::Cast(
- CastKind::IntToInt
- | CastKind::FloatToInt
- | CastKind::FloatToFloat
- | CastKind::IntToFloat
- | CastKind::FnPtrToPtr
- | CastKind::PtrToPtr
- | CastKind::PointerCoercion(_)
- | CastKind::PointerFromExposedAddress
- | CastKind::DynStar
- | CastKind::Transmute,
- _,
- _,
- )
- | Rvalue::BinaryOp(_, _)
- | Rvalue::CheckedBinaryOp(_, _)
- | Rvalue::NullaryOp(_, _)
- | Rvalue::UnaryOp(_, _)
- | Rvalue::Discriminant(_)
- | Rvalue::Aggregate(_, _)
- | Rvalue::ShallowInitBox(_, _) => true,
- }
- }
-}
-
-impl BorrowKind {
- pub fn mutability(&self) -> Mutability {
- match *self {
- BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not,
- BorrowKind::Mut { .. } => Mutability::Mut,
- }
- }
-
- pub fn allows_two_phase_borrow(&self) -> bool {
- match *self {
- BorrowKind::Shared
- | BorrowKind::Shallow
- | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
- false
- }
- BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
- }
- }
-}
-
-impl<'tcx> Debug for Rvalue<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- use self::Rvalue::*;
-
- match *self {
- Use(ref place) => write!(fmt, "{place:?}"),
- Repeat(ref a, b) => {
- write!(fmt, "[{a:?}; ")?;
- pretty_print_const(b, fmt, false)?;
- write!(fmt, "]")
- }
- Len(ref a) => write!(fmt, "Len({a:?})"),
- Cast(ref kind, ref place, ref ty) => {
- write!(fmt, "{place:?} as {ty:?} ({kind:?})")
- }
- BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
- CheckedBinaryOp(ref op, box (ref a, ref b)) => {
- write!(fmt, "Checked{op:?}({a:?}, {b:?})")
- }
- UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
- Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
- NullaryOp(ref op, ref t) => match op {
- NullOp::SizeOf => write!(fmt, "SizeOf({t:?})"),
- NullOp::AlignOf => write!(fmt, "AlignOf({t:?})"),
- NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t:?}, {fields:?})"),
- },
- ThreadLocalRef(did) => ty::tls::with(|tcx| {
- let muta = tcx.static_mutability(did).unwrap().prefix_str();
- write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
- }),
- Ref(region, borrow_kind, ref place) => {
- let kind_str = match borrow_kind {
- BorrowKind::Shared => "",
- BorrowKind::Shallow => "shallow ",
- BorrowKind::Mut { .. } => "mut ",
- };
-
- // When printing regions, add trailing space if necessary.
- let print_region = ty::tls::with(|tcx| {
- tcx.sess.verbose() || tcx.sess.opts.unstable_opts.identify_regions
- });
- let region = if print_region {
- let mut region = region.to_string();
- if !region.is_empty() {
- region.push(' ');
- }
- region
- } else {
- // Do not even print 'static
- String::new()
- };
- write!(fmt, "&{region}{kind_str}{place:?}")
- }
-
- CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"),
-
- AddressOf(mutability, ref place) => {
- let kind_str = match mutability {
- Mutability::Mut => "mut",
- Mutability::Not => "const",
- };
-
- write!(fmt, "&raw {kind_str} {place:?}")
- }
-
- Aggregate(ref kind, ref places) => {
- let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| {
- let mut tuple_fmt = fmt.debug_tuple(name);
- for place in places {
- tuple_fmt.field(place);
- }
- tuple_fmt.finish()
- };
-
- match **kind {
- AggregateKind::Array(_) => write!(fmt, "{places:?}"),
-
- AggregateKind::Tuple => {
- if places.is_empty() {
- write!(fmt, "()")
- } else {
- fmt_tuple(fmt, "")
- }
- }
-
- AggregateKind::Adt(adt_did, variant, args, _user_ty, _) => {
- ty::tls::with(|tcx| {
- let variant_def = &tcx.adt_def(adt_did).variant(variant);
- let args = tcx.lift(args).expect("could not lift for printing");
- let name = FmtPrinter::new(tcx, Namespace::ValueNS)
- .print_def_path(variant_def.def_id, args)?
- .into_buffer();
-
- match variant_def.ctor_kind() {
- Some(CtorKind::Const) => fmt.write_str(&name),
- Some(CtorKind::Fn) => fmt_tuple(fmt, &name),
- None => {
- let mut struct_fmt = fmt.debug_struct(&name);
- for (field, place) in iter::zip(&variant_def.fields, places) {
- struct_fmt.field(field.name.as_str(), place);
- }
- struct_fmt.finish()
- }
- }
- })
- }
-
- AggregateKind::Closure(def_id, args) => ty::tls::with(|tcx| {
- let name = if tcx.sess.opts.unstable_opts.span_free_formats {
- let args = tcx.lift(args).unwrap();
- format!("[closure@{}]", tcx.def_path_str_with_args(def_id, args),)
- } else {
- let span = tcx.def_span(def_id);
- format!(
- "[closure@{}]",
- tcx.sess.source_map().span_to_diagnostic_string(span)
- )
- };
- let mut struct_fmt = fmt.debug_struct(&name);
-
- // FIXME(project-rfc-2229#48): This should be a list of capture names/places
- if let Some(def_id) = def_id.as_local()
- && let Some(upvars) = tcx.upvars_mentioned(def_id)
- {
- for (&var_id, place) in iter::zip(upvars.keys(), places) {
- let var_name = tcx.hir().name(var_id);
- struct_fmt.field(var_name.as_str(), place);
- }
- } else {
- for (index, place) in places.iter().enumerate() {
- struct_fmt.field(&format!("{index}"), place);
- }
- }
-
- struct_fmt.finish()
- }),
-
- AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| {
- let name = format!("[generator@{:?}]", tcx.def_span(def_id));
- let mut struct_fmt = fmt.debug_struct(&name);
-
- // FIXME(project-rfc-2229#48): This should be a list of capture names/places
- if let Some(def_id) = def_id.as_local()
- && let Some(upvars) = tcx.upvars_mentioned(def_id)
- {
- for (&var_id, place) in iter::zip(upvars.keys(), places) {
- let var_name = tcx.hir().name(var_id);
- struct_fmt.field(var_name.as_str(), place);
- }
- } else {
- for (index, place) in places.iter().enumerate() {
- struct_fmt.field(&format!("{index}"), place);
- }
- }
-
- struct_fmt.finish()
- }),
- }
- }
-
- ShallowInitBox(ref place, ref ty) => {
- write!(fmt, "ShallowInitBox({place:?}, {ty:?})")
- }
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-/// Constants
-///
-/// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are `==` in Rust. In
-/// particular, one must be wary of `NaN`!
-
-#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct Constant<'tcx> {
- pub span: Span,
-
- /// Optional user-given type: for something like
- /// `collect::<Vec<_>>`, this would be present and would
- /// indicate that `Vec<_>` was explicitly specified.
- ///
- /// Needed for NLL to impose user-given type constraints.
- pub user_ty: Option<UserTypeAnnotationIndex>,
-
- pub literal: ConstantKind<'tcx>,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
-#[derive(Lift, TypeFoldable, TypeVisitable)]
-pub enum ConstantKind<'tcx> {
- /// This constant came from the type system
- Ty(ty::Const<'tcx>),
-
- /// An unevaluated mir constant which is not part of the type system.
- Unevaluated(UnevaluatedConst<'tcx>, Ty<'tcx>),
-
- /// This constant cannot go back into the type system, as it represents
- /// something the type system cannot handle (e.g. pointers).
- Val(interpret::ConstValue<'tcx>, Ty<'tcx>),
-}
-
-impl<'tcx> Constant<'tcx> {
- pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
- match self.literal.try_to_scalar() {
- Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
- GlobalAlloc::Static(def_id) => {
- assert!(!tcx.is_thread_local_static(def_id));
- Some(def_id)
- }
- _ => None,
- },
- _ => None,
- }
- }
- #[inline]
- pub fn ty(&self) -> Ty<'tcx> {
- self.literal.ty()
- }
-}
-
-impl<'tcx> ConstantKind<'tcx> {
- #[inline(always)]
- pub fn ty(&self) -> Ty<'tcx> {
- match self {
- ConstantKind::Ty(c) => c.ty(),
- ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty,
- }
- }
-
- #[inline]
- pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
- match self {
- ConstantKind::Ty(c) => match c.kind() {
- ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
- _ => None,
- },
- ConstantKind::Val(val, _) => Some(val),
- ConstantKind::Unevaluated(..) => None,
- }
- }
-
- #[inline]
- pub fn try_to_scalar(self) -> Option<Scalar> {
- match self {
- ConstantKind::Ty(c) => match c.kind() {
- ty::ConstKind::Value(valtree) => match valtree {
- ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
- ty::ValTree::Branch(_) => None,
- },
- _ => None,
- },
- ConstantKind::Val(val, _) => val.try_to_scalar(),
- ConstantKind::Unevaluated(..) => None,
- }
- }
-
- #[inline]
- pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
- Some(self.try_to_scalar()?.assert_int())
- }
-
- #[inline]
- pub fn try_to_bits(self, size: Size) -> Option<u128> {
- self.try_to_scalar_int()?.to_bits(size).ok()
- }
-
- #[inline]
- pub fn try_to_bool(self) -> Option<bool> {
- self.try_to_scalar_int()?.try_into().ok()
- }
-
- #[inline]
- pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
- match self {
- Self::Ty(c) => {
- if let Some(val) = c.try_eval_for_mir(tcx, param_env) {
- match val {
- Ok(val) => Self::Val(val, c.ty()),
- Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())),
- }
- } else {
- self
- }
- }
- Self::Val(_, _) => self,
- Self::Unevaluated(uneval, ty) => {
- // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
- match tcx.const_eval_resolve(param_env, uneval, None) {
- Ok(val) => Self::Val(val, ty),
- Err(ErrorHandled::TooGeneric) => self,
- Err(ErrorHandled::Reported(guar)) => {
- Self::Ty(ty::Const::new_error(tcx, guar.into(), ty))
- }
- }
- }
- }
- }
-
- /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
- #[inline]
- pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
- self.try_eval_bits(tcx, param_env, ty)
- .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
- }
-
- #[inline]
- pub fn try_eval_bits(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- ) -> Option<u128> {
- match self {
- Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty),
- Self::Val(val, t) => {
- assert_eq!(*t, ty);
- let size =
- tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
- val.try_to_bits(size)
- }
- Self::Unevaluated(uneval, ty) => {
- match tcx.const_eval_resolve(param_env, *uneval, None) {
- Ok(val) => {
- let size = tcx
- .layout_of(param_env.with_reveal_all_normalized(tcx).and(*ty))
- .ok()?
- .size;
- val.try_to_bits(size)
- }
- Err(_) => None,
- }
- }
- }
- }
-
- #[inline]
- pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
- match self {
- Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
- Self::Val(val, _) => val.try_to_bool(),
- Self::Unevaluated(uneval, _) => {
- match tcx.const_eval_resolve(param_env, *uneval, None) {
- Ok(val) => val.try_to_bool(),
- Err(_) => None,
- }
- }
- }
- }
-
- #[inline]
- pub fn try_eval_target_usize(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> Option<u64> {
- match self {
- Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
- Self::Val(val, _) => val.try_to_target_usize(tcx),
- Self::Unevaluated(uneval, _) => {
- match tcx.const_eval_resolve(param_env, *uneval, None) {
- Ok(val) => val.try_to_target_usize(tcx),
- Err(_) => None,
- }
- }
- }
- }
-
- #[inline]
- pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
- Self::Val(val, ty)
- }
-
- pub fn from_bits(
- tcx: TyCtxt<'tcx>,
- bits: u128,
- param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
- ) -> Self {
- let size = tcx
- .layout_of(param_env_ty)
- .unwrap_or_else(|e| {
- bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
- })
- .size;
- let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
-
- Self::Val(cv, param_env_ty.value)
- }
-
- #[inline]
- pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
- let cv = ConstValue::from_bool(v);
- Self::Val(cv, tcx.types.bool)
- }
-
- #[inline]
- pub fn zero_sized(ty: Ty<'tcx>) -> Self {
- let cv = ConstValue::ZeroSized;
- Self::Val(cv, ty)
- }
-
- pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
- let ty = tcx.types.usize;
- Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
- }
-
- #[inline]
- pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
- let val = ConstValue::Scalar(s);
- Self::Val(val, ty)
- }
-
- /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
- /// converted to a constant, everything else becomes `Unevaluated`.
- #[instrument(skip(tcx), level = "debug", ret)]
- pub fn from_anon_const(
- tcx: TyCtxt<'tcx>,
- def: LocalDefId,
- param_env: ty::ParamEnv<'tcx>,
- ) -> Self {
- let body_id = match tcx.hir().get_by_def_id(def) {
- hir::Node::AnonConst(ac) => ac.body,
- _ => {
- span_bug!(tcx.def_span(def), "from_anon_const can only process anonymous constants")
- }
- };
-
- let expr = &tcx.hir().body(body_id).value;
- debug!(?expr);
-
- // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
- // currently have to be wrapped in curly brackets, so it's necessary to special-case.
- let expr = match &expr.kind {
- hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
- block.expr.as_ref().unwrap()
- }
- _ => expr,
- };
- debug!("expr.kind: {:?}", expr.kind);
-
- let ty = tcx.type_of(def).instantiate_identity();
- debug!(?ty);
-
- // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
- // does not provide the parents generics to anonymous constants. We still allow generic const
- // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
- // ever try to substitute the generic parameters in their bodies.
- //
- // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
- // cause issues if we were to remove that special-case and try to evaluate the constant instead.
- use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
- match expr.kind {
- ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
- // Find the name and index of the const parameter by indexing the generics of
- // the parent item and construct a `ParamConst`.
- let item_def_id = tcx.parent(def_id);
- let generics = tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&def_id];
- let name = tcx.item_name(def_id);
- let ty_const = ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty);
- debug!(?ty_const);
-
- return Self::Ty(ty_const);
- }
- _ => {}
- }
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def);
- let parent_args = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id)
- && let Some(parent_did) = parent_hir_id.as_owner()
- {
- GenericArgs::identity_for_item(tcx, parent_did)
- } else {
- List::empty()
- };
- debug!(?parent_args);
-
- let did = def.to_def_id();
- let child_args = GenericArgs::identity_for_item(tcx, did);
- let args = tcx.mk_args_from_iter(parent_args.into_iter().chain(child_args.into_iter()));
- debug!(?args);
-
- let span = tcx.def_span(def);
- let uneval = UnevaluatedConst::new(did, args);
- debug!(?span, ?param_env);
-
- match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
- Ok(val) => {
- debug!("evaluated const value");
- Self::Val(val, ty)
- }
- Err(_) => {
- debug!("error encountered during evaluation");
- // Error was handled in `const_eval_resolve`. Here we just create a
- // new unevaluated const and error hard later in codegen
- Self::Unevaluated(
- UnevaluatedConst {
- def: did,
- args: GenericArgs::identity_for_item(tcx, did),
- promoted: None,
- },
- ty,
- )
- }
- }
- }
-
- pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
- match c.kind() {
- ty::ConstKind::Value(valtree) => {
- let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
- Self::Val(const_val, c.ty())
- }
- ty::ConstKind::Unevaluated(uv) => Self::Unevaluated(uv.expand(), c.ty()),
- _ => Self::Ty(c),
- }
- }
-}
-
-/// An unevaluated (potentially generic) constant used in MIR.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct UnevaluatedConst<'tcx> {
- pub def: DefId,
- pub args: GenericArgsRef<'tcx>,
- pub promoted: Option<Promoted>,
-}
-
-impl<'tcx> UnevaluatedConst<'tcx> {
- #[inline]
- pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
- assert_eq!(self.promoted, None);
- ty::UnevaluatedConst { def: self.def, args: self.args }
- }
-}
-
-impl<'tcx> UnevaluatedConst<'tcx> {
- #[inline]
- pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
- UnevaluatedConst { def, args, promoted: Default::default() }
- }
-}
-
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
/// parent pattern that has been ascribed a type.
///
-/// Its a collection because there can be multiple type ascriptions on
+/// It's a collection because there can be multiple type ascriptions on
/// the path from the root of the pattern down to the binding itself.
///
/// An example:
@@ -2747,220 +1545,6 @@ rustc_index::newtype_index! {
pub struct Promoted {}
}
-impl<'tcx> Debug for Constant<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- write!(fmt, "{self}")
- }
-}
-
-impl<'tcx> Display for Constant<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- match self.ty().kind() {
- ty::FnDef(..) => {}
- _ => write!(fmt, "const ")?,
- }
- Display::fmt(&self.literal, fmt)
- }
-}
-
-impl<'tcx> Display for ConstantKind<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- match *self {
- ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
- ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
- // FIXME(valtrees): Correctly print mir constants.
- ConstantKind::Unevaluated(..) => {
- fmt.write_str("_")?;
- Ok(())
- }
- }
- }
-}
-
-fn pretty_print_const<'tcx>(
- c: ty::Const<'tcx>,
- fmt: &mut Formatter<'_>,
- print_types: bool,
-) -> fmt::Result {
- use crate::ty::print::PrettyPrinter;
- ty::tls::with(|tcx| {
- let literal = tcx.lift(c).unwrap();
- let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
- cx.print_alloc_ids = true;
- let cx = cx.pretty_print_const(literal, print_types)?;
- fmt.write_str(&cx.into_buffer())?;
- Ok(())
- })
-}
-
-fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result {
- write!(fmt, "b\"{}\"", byte_str.escape_ascii())
-}
-
-fn comma_sep<'tcx>(
- fmt: &mut Formatter<'_>,
- elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>,
-) -> fmt::Result {
- let mut first = true;
- for (ct, ty) in elems {
- if !first {
- fmt.write_str(", ")?;
- }
- pretty_print_const_value(ct, ty, fmt)?;
- first = false;
- }
- Ok(())
-}
-
-// FIXME: Move that into `mir/pretty.rs`.
-fn pretty_print_const_value<'tcx>(
- ct: ConstValue<'tcx>,
- ty: Ty<'tcx>,
- fmt: &mut Formatter<'_>,
-) -> fmt::Result {
- use crate::ty::print::PrettyPrinter;
-
- ty::tls::with(|tcx| {
- let ct = tcx.lift(ct).unwrap();
- let ty = tcx.lift(ty).unwrap();
-
- if tcx.sess.verbose() {
- fmt.write_str(&format!("ConstValue({ct:?}: {ty})"))?;
- return Ok(());
- }
-
- let u8_type = tcx.types.u8;
- match (ct, ty.kind()) {
- // Byte/string slices, printed as (byte) string literals.
- (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
- match inner.kind() {
- ty::Slice(t) => {
- if *t == u8_type {
- // The `inspect` here is okay since we checked the bounds, and `u8` carries
- // no provenance (we have an active slice reference here). We don't use
- // this result to affect interpreter execution.
- let byte_str = data
- .inner()
- .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
- pretty_print_byte_str(fmt, byte_str)?;
- return Ok(());
- }
- }
- ty::Str => {
- // The `inspect` here is okay since we checked the bounds, and `str` carries
- // no provenance (we have an active `str` reference here). We don't use this
- // result to affect interpreter execution.
- let slice = data
- .inner()
- .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
- fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?;
- return Ok(());
- }
- _ => {}
- }
- }
- (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
- let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap();
- // cast is ok because we already checked for pointer size (32 or 64 bit) above
- let range = AllocRange { start: offset, size: Size::from_bytes(n) };
- let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
- fmt.write_str("*")?;
- pretty_print_byte_str(fmt, byte_str)?;
- return Ok(());
- }
- // Aggregates, printed as array/tuple/struct/variant construction syntax.
- //
- // NB: the `has_non_region_param` check ensures that we can use
- // the `destructure_const` query with an empty `ty::ParamEnv` without
- // introducing ICEs (e.g. via `layout_of`) from missing bounds.
- // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
- // to be able to destructure the tuple into `(0u8, *mut T)`
- (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => {
- let ct = tcx.lift(ct).unwrap();
- let ty = tcx.lift(ty).unwrap();
- if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) {
- let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec();
- match *ty.kind() {
- ty::Array(..) => {
- fmt.write_str("[")?;
- comma_sep(fmt, fields)?;
- fmt.write_str("]")?;
- }
- ty::Tuple(..) => {
- fmt.write_str("(")?;
- comma_sep(fmt, fields)?;
- if contents.fields.len() == 1 {
- fmt.write_str(",")?;
- }
- fmt.write_str(")")?;
- }
- ty::Adt(def, _) if def.variants().is_empty() => {
- fmt.write_str(&format!("{{unreachable(): {ty}}}"))?;
- }
- ty::Adt(def, args) => {
- let variant_idx = contents
- .variant
- .expect("destructed mir constant of adt without variant idx");
- let variant_def = &def.variant(variant_idx);
- let args = tcx.lift(args).unwrap();
- let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
- cx.print_alloc_ids = true;
- let cx = cx.print_value_path(variant_def.def_id, args)?;
- fmt.write_str(&cx.into_buffer())?;
-
- match variant_def.ctor_kind() {
- Some(CtorKind::Const) => {}
- Some(CtorKind::Fn) => {
- fmt.write_str("(")?;
- comma_sep(fmt, fields)?;
- fmt.write_str(")")?;
- }
- None => {
- fmt.write_str(" {{ ")?;
- let mut first = true;
- for (field_def, (ct, ty)) in
- iter::zip(&variant_def.fields, fields)
- {
- if !first {
- fmt.write_str(", ")?;
- }
- write!(fmt, "{}: ", field_def.name)?;
- pretty_print_const_value(ct, ty, fmt)?;
- first = false;
- }
- fmt.write_str(" }}")?;
- }
- }
- }
- _ => unreachable!(),
- }
- return Ok(());
- }
- }
- (ConstValue::Scalar(scalar), _) => {
- let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
- cx.print_alloc_ids = true;
- let ty = tcx.lift(ty).unwrap();
- cx = cx.pretty_print_const_scalar(scalar, ty)?;
- fmt.write_str(&cx.into_buffer())?;
- return Ok(());
- }
- (ConstValue::ZeroSized, ty::FnDef(d, s)) => {
- let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
- cx.print_alloc_ids = true;
- let cx = cx.print_value_path(*d, s)?;
- fmt.write_str(&cx.into_buffer())?;
- return Ok(());
- }
- // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
- // their fields instead of just dumping the memory.
- _ => {}
- }
- // Fall back to debug pretty printing for invalid constants.
- write!(fmt, "{ct:?}: {ty}")
- })
-}
-
/// `Location` represents the position of the start of the statement; or, if
/// `statement_index` equals the number of statements, then the start of the
/// terminator.
@@ -3043,6 +1627,6 @@ mod size_asserts {
static_assert_size!(StatementKind<'_>, 16);
static_assert_size!(Terminator<'_>, 104);
static_assert_size!(TerminatorKind<'_>, 88);
- static_assert_size!(VarDebugInfo<'_>, 80);
+ static_assert_size!(VarDebugInfo<'_>, 88);
// tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 8fd980d5a..403e80bd3 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -78,9 +78,11 @@ impl<'tcx> MonoItem<'tcx> {
}
}
- pub fn is_generic_fn(&self) -> bool {
- match *self {
- MonoItem::Fn(ref instance) => instance.args.non_erasable_generics().next().is_some(),
+ pub fn is_generic_fn(&self, tcx: TyCtxt<'tcx>) -> bool {
+ match self {
+ MonoItem::Fn(instance) => {
+ instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some()
+ }
MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false,
}
}
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
index c4c3341f8..da486c346 100644
--- a/compiler/rustc_middle/src/mir/patch.rs
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -14,7 +14,8 @@ pub struct MirPatch<'tcx> {
resume_block: Option<BasicBlock>,
// Only for unreachable in cleanup path.
unreachable_cleanup_block: Option<BasicBlock>,
- terminate_block: Option<BasicBlock>,
+ // Cached block for UnwindTerminate (with reason)
+ terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
body_span: Span,
next_local: usize,
}
@@ -35,13 +36,15 @@ impl<'tcx> MirPatch<'tcx> {
for (bb, block) in body.basic_blocks.iter_enumerated() {
// Check if we already have a resume block
- if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
+ 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 let TerminatorKind::Unreachable = block.terminator().kind
+ if matches!(block.terminator().kind, TerminatorKind::Unreachable)
&& block.statements.is_empty()
&& block.is_cleanup
{
@@ -50,8 +53,10 @@ impl<'tcx> MirPatch<'tcx> {
}
// Check if we already have a terminate block
- if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() {
- result.terminate_block = Some(bb);
+ if let TerminatorKind::UnwindTerminate(reason) = block.terminator().kind
+ && block.statements.is_empty()
+ {
+ result.terminate_block = Some((bb, reason));
continue;
}
}
@@ -68,7 +73,7 @@ impl<'tcx> MirPatch<'tcx> {
statements: vec![],
terminator: Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
- kind: TerminatorKind::Resume,
+ kind: TerminatorKind::UnwindResume,
}),
is_cleanup: true,
});
@@ -93,20 +98,20 @@ impl<'tcx> MirPatch<'tcx> {
bb
}
- pub fn terminate_block(&mut self) -> BasicBlock {
- if let Some(bb) = self.terminate_block {
- return 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::Terminate,
+ kind: TerminatorKind::UnwindTerminate(reason),
}),
is_cleanup: true,
});
- self.terminate_block = Some(bb);
+ self.terminate_block = Some((bb, reason));
bb
}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 773056e8a..f032fd29d 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1,19 +1,19 @@
use std::collections::BTreeSet;
-use std::fmt::Display;
-use std::fmt::Write as _;
+use std::fmt::{self, Debug, Display, Write as _};
use std::fs;
-use std::io::{self, Write};
+use std::io::{self, Write as _};
use std::path::{Path, PathBuf};
use super::graphviz::write_mir_fn_graphviz;
use super::spanview::write_mir_fn_spanview;
use either::Either;
+use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_index::Idx;
use rustc_middle::mir::interpret::{
- alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, ConstValue,
- GlobalAlloc, Pointer, Provenance,
+ alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, GlobalAlloc,
+ Pointer, Provenance,
};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
@@ -79,7 +79,7 @@ pub fn dump_mir<'tcx, F>(
body: &Body<'tcx>,
extra_data: F,
) where
- F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+ F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
{
if !dump_enabled(tcx, pass_name, body.source.def_id()) {
return;
@@ -116,7 +116,7 @@ fn dump_matched_mir_node<'tcx, F>(
body: &Body<'tcx>,
mut extra_data: F,
) where
- F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+ F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
{
let _: io::Result<()> = try {
let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?;
@@ -260,11 +260,14 @@ pub fn create_dump_file<'tcx>(
)
}
+///////////////////////////////////////////////////////////////////////////
+// Whole MIR bodies
+
/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'tcx>(
tcx: TyCtxt<'tcx>,
single: Option<DefId>,
- w: &mut dyn Write,
+ w: &mut dyn io::Write,
) -> io::Result<()> {
writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;
@@ -278,7 +281,7 @@ pub fn write_mir_pretty<'tcx>(
writeln!(w)?;
}
- let render_body = |w: &mut dyn Write, body| -> io::Result<()> {
+ let render_body = |w: &mut dyn io::Write, body| -> io::Result<()> {
write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
for body in tcx.promoted_mir(def_id) {
@@ -309,10 +312,10 @@ pub fn write_mir_fn<'tcx, F>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
extra_data: &mut F,
- w: &mut dyn Write,
+ w: &mut dyn io::Write,
) -> io::Result<()>
where
- F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+ F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
{
write_mir_intro(tcx, body, w)?;
for block in body.basic_blocks.indices() {
@@ -330,16 +333,267 @@ where
Ok(())
}
+/// Prints local variables in a scope tree.
+fn write_scope_tree(
+ tcx: TyCtxt<'_>,
+ body: &Body<'_>,
+ scope_tree: &FxHashMap<SourceScope, Vec<SourceScope>>,
+ w: &mut dyn io::Write,
+ parent: SourceScope,
+ depth: usize,
+) -> io::Result<()> {
+ let indent = depth * INDENT.len();
+
+ // Local variable debuginfo.
+ for var_debug_info in &body.var_debug_info {
+ if var_debug_info.source_info.scope != parent {
+ // Not declared in this scope.
+ continue;
+ }
+
+ let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info);
+
+ if tcx.sess.opts.unstable_opts.mir_include_spans {
+ writeln!(
+ w,
+ "{0:1$} // in {2}",
+ indented_debug_info,
+ ALIGN,
+ comment(tcx, var_debug_info.source_info),
+ )?;
+ } else {
+ writeln!(w, "{indented_debug_info}")?;
+ }
+ }
+
+ // Local variable types.
+ for (local, local_decl) in body.local_decls.iter_enumerated() {
+ if (1..body.arg_count + 1).contains(&local.index()) {
+ // Skip over argument locals, they're printed in the signature.
+ continue;
+ }
+
+ if local_decl.source_info.scope != parent {
+ // Not declared in this scope.
+ continue;
+ }
+
+ let mut_str = local_decl.mutability.prefix_str();
+
+ let mut indented_decl = ty::print::with_no_trimmed_paths!(format!(
+ "{0:1$}let {2}{3:?}: {4}",
+ INDENT, indent, mut_str, local, local_decl.ty
+ ));
+ if let Some(user_ty) = &local_decl.user_ty {
+ for user_ty in user_ty.projections() {
+ write!(indented_decl, " as {user_ty:?}").unwrap();
+ }
+ }
+ indented_decl.push(';');
+
+ let local_name = if local == RETURN_PLACE { " return place" } else { "" };
+
+ if tcx.sess.opts.unstable_opts.mir_include_spans {
+ writeln!(
+ w,
+ "{0:1$} //{2} in {3}",
+ indented_decl,
+ ALIGN,
+ local_name,
+ comment(tcx, local_decl.source_info),
+ )?;
+ } else {
+ writeln!(w, "{indented_decl}",)?;
+ }
+ }
+
+ let Some(children) = scope_tree.get(&parent) else {
+ return Ok(());
+ };
+
+ for &child in children {
+ let child_data = &body.source_scopes[child];
+ assert_eq!(child_data.parent_scope, Some(parent));
+
+ let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined {
+ (
+ format!(
+ " (inlined {}{})",
+ if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" },
+ callee
+ ),
+ Some(callsite_span),
+ )
+ } else {
+ (String::new(), None)
+ };
+
+ let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special);
+
+ if tcx.sess.opts.unstable_opts.mir_include_spans {
+ if let Some(span) = span {
+ writeln!(
+ w,
+ "{0:1$} // at {2}",
+ indented_header,
+ ALIGN,
+ tcx.sess.source_map().span_to_embeddable_string(span),
+ )?;
+ } else {
+ writeln!(w, "{indented_header}")?;
+ }
+ } else {
+ writeln!(w, "{indented_header}")?;
+ }
+
+ write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?;
+ writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
+ }
+
+ Ok(())
+}
+
+impl Debug for VarDebugInfo<'_> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite {
+ pre_fmt_projection(&projection[..], fmt)?;
+ write!(fmt, "({}: {})", self.name, ty)?;
+ post_fmt_projection(&projection[..], fmt)?;
+ } else {
+ write!(fmt, "{}", self.name)?;
+ }
+
+ write!(fmt, " => {:?}", self.value)
+ }
+}
+
+/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
+/// local variables (both user-defined bindings and compiler temporaries).
+pub fn write_mir_intro<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'_>,
+ w: &mut dyn io::Write,
+) -> io::Result<()> {
+ write_mir_sig(tcx, body, w)?;
+ writeln!(w, "{{")?;
+
+ // construct a scope tree and write it out
+ let mut scope_tree: FxHashMap<SourceScope, Vec<SourceScope>> = Default::default();
+ for (index, scope_data) in body.source_scopes.iter().enumerate() {
+ if let Some(parent) = scope_data.parent_scope {
+ scope_tree.entry(parent).or_default().push(SourceScope::new(index));
+ } else {
+ // Only the argument scope has no parent, because it's the root.
+ assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index());
+ }
+ }
+
+ write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?;
+
+ // Add an empty line before the first block is printed.
+ writeln!(w)?;
+
+ Ok(())
+}
+
+fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io::Result<()> {
+ use rustc_hir::def::DefKind;
+
+ trace!("write_mir_sig: {:?}", body.source.instance);
+ let def_id = body.source.def_id();
+ let kind = tcx.def_kind(def_id);
+ let is_function = match kind {
+ DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+ _ => tcx.is_closure(def_id),
+ };
+ match (kind, body.source.promoted) {
+ (_, Some(i)) => write!(w, "{i:?} in ")?,
+ (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
+ (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
+ (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
+ (_, _) if is_function => write!(w, "fn ")?,
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
+ _ => bug!("Unexpected def kind {:?}", kind),
+ }
+
+ ty::print::with_forced_impl_filename_line! {
+ // see notes on #41697 elsewhere
+ write!(w, "{}", tcx.def_path_str(def_id))?
+ }
+
+ if body.source.promoted.is_none() && is_function {
+ write!(w, "(")?;
+
+ // fn argument types.
+ for (i, arg) in body.args_iter().enumerate() {
+ if i != 0 {
+ write!(w, ", ")?;
+ }
+ write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?;
+ }
+
+ write!(w, ") -> {}", body.return_ty())?;
+ } else {
+ assert_eq!(body.arg_count, 0);
+ write!(w, ": {} =", body.return_ty())?;
+ }
+
+ if let Some(yield_ty) = body.yield_ty() {
+ writeln!(w)?;
+ writeln!(w, "yields {yield_ty}")?;
+ }
+
+ write!(w, " ")?;
+ // Next thing that gets printed is the opening {
+
+ Ok(())
+}
+
+fn write_user_type_annotations(
+ tcx: TyCtxt<'_>,
+ body: &Body<'_>,
+ w: &mut dyn io::Write,
+) -> io::Result<()> {
+ if !body.user_type_annotations.is_empty() {
+ writeln!(w, "| User Type Annotations")?;
+ }
+ for (index, annotation) in body.user_type_annotations.iter_enumerated() {
+ writeln!(
+ w,
+ "| {:?}: user_ty: {}, span: {}, inferred_ty: {}",
+ index.index(),
+ annotation.user_ty,
+ tcx.sess.source_map().span_to_embeddable_string(annotation.span),
+ with_no_trimmed_paths!(format!("{}", annotation.inferred_ty)),
+ )?;
+ }
+ if !body.user_type_annotations.is_empty() {
+ writeln!(w, "|")?;
+ }
+ Ok(())
+}
+
+pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> {
+ if let Some(i) = single {
+ vec![i]
+ } else {
+ tcx.mir_keys(()).iter().map(|def_id| def_id.to_def_id()).collect()
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Basic blocks and their parts (statements, terminators, ...)
+
/// Write out a human-readable textual representation for the given basic block.
pub fn write_basic_block<'tcx, F>(
tcx: TyCtxt<'tcx>,
block: BasicBlock,
body: &Body<'tcx>,
extra_data: &mut F,
- w: &mut dyn Write,
+ w: &mut dyn io::Write,
) -> io::Result<()>
where
- F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+ F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>,
{
let data = &body[block];
@@ -400,10 +654,528 @@ where
writeln!(w, "{INDENT}}}")
}
+impl Debug for Statement<'_> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ use self::StatementKind::*;
+ match self.kind {
+ Assign(box (ref place, ref rv)) => write!(fmt, "{place:?} = {rv:?}"),
+ FakeRead(box (ref cause, ref place)) => {
+ write!(fmt, "FakeRead({cause:?}, {place:?})")
+ }
+ Retag(ref kind, ref place) => write!(
+ fmt,
+ "Retag({}{:?})",
+ match kind {
+ RetagKind::FnEntry => "[fn entry] ",
+ RetagKind::TwoPhase => "[2phase] ",
+ RetagKind::Raw => "[raw] ",
+ RetagKind::Default => "",
+ },
+ place,
+ ),
+ StorageLive(ref place) => write!(fmt, "StorageLive({place:?})"),
+ StorageDead(ref place) => write!(fmt, "StorageDead({place:?})"),
+ SetDiscriminant { ref place, variant_index } => {
+ write!(fmt, "discriminant({place:?}) = {variant_index:?}")
+ }
+ Deinit(ref place) => write!(fmt, "Deinit({place:?})"),
+ PlaceMention(ref place) => {
+ write!(fmt, "PlaceMention({place:?})")
+ }
+ AscribeUserType(box (ref place, ref c_ty), ref variance) => {
+ write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})")
+ }
+ Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
+ write!(fmt, "Coverage::{kind:?} for {rgn:?}")
+ }
+ Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
+ Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
+ ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
+ Nop => write!(fmt, "nop"),
+ }
+ }
+}
+
+impl Display for NonDivergingIntrinsic<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Assume(op) => write!(f, "assume({op:?})"),
+ Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+ write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+ }
+ }
+ }
+}
+
+impl<'tcx> Debug for TerminatorKind<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ self.fmt_head(fmt)?;
+ let successor_count = self.successors().count();
+ let labels = self.fmt_successor_labels();
+ assert_eq!(successor_count, labels.len());
+
+ // `Cleanup` is already included in successors
+ let show_unwind = !matches!(self.unwind(), None | Some(UnwindAction::Cleanup(_)));
+ let fmt_unwind = |fmt: &mut Formatter<'_>| -> fmt::Result {
+ write!(fmt, "unwind ")?;
+ match self.unwind() {
+ // Not needed or included in successors
+ None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
+ Some(UnwindAction::Continue) => write!(fmt, "continue"),
+ Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
+ Some(UnwindAction::Terminate(reason)) => {
+ write!(fmt, "terminate({})", reason.as_short_str())
+ }
+ }
+ };
+
+ match (successor_count, show_unwind) {
+ (0, false) => Ok(()),
+ (0, true) => {
+ write!(fmt, " -> ")?;
+ fmt_unwind(fmt)
+ }
+ (1, false) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
+ _ => {
+ write!(fmt, " -> [")?;
+ for (i, target) in self.successors().enumerate() {
+ if i > 0 {
+ write!(fmt, ", ")?;
+ }
+ write!(fmt, "{}: {:?}", labels[i], target)?;
+ }
+ if show_unwind {
+ write!(fmt, ", ")?;
+ fmt_unwind(fmt)?;
+ }
+ write!(fmt, "]")
+ }
+ }
+ }
+}
+
+impl<'tcx> TerminatorKind<'tcx> {
+ /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
+ /// successor basic block, if any. The only information not included is the list of possible
+ /// successors, which may be rendered differently between the text and the graphviz format.
+ pub fn fmt_head<W: fmt::Write>(&self, fmt: &mut W) -> fmt::Result {
+ use self::TerminatorKind::*;
+ match self {
+ Goto { .. } => write!(fmt, "goto"),
+ SwitchInt { discr, .. } => write!(fmt, "switchInt({discr:?})"),
+ Return => write!(fmt, "return"),
+ GeneratorDrop => write!(fmt, "generator_drop"),
+ UnwindResume => write!(fmt, "resume"),
+ UnwindTerminate(reason) => {
+ write!(fmt, "abort({})", reason.as_short_str())
+ }
+ Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
+ Unreachable => write!(fmt, "unreachable"),
+ Drop { place, .. } => write!(fmt, "drop({place:?})"),
+ Call { func, args, destination, .. } => {
+ write!(fmt, "{destination:?} = ")?;
+ write!(fmt, "{func:?}(")?;
+ for (index, arg) in args.iter().enumerate() {
+ if index > 0 {
+ write!(fmt, ", ")?;
+ }
+ write!(fmt, "{arg:?}")?;
+ }
+ write!(fmt, ")")
+ }
+ Assert { cond, expected, msg, .. } => {
+ write!(fmt, "assert(")?;
+ if !expected {
+ write!(fmt, "!")?;
+ }
+ write!(fmt, "{cond:?}, ")?;
+ msg.fmt_assert_args(fmt)?;
+ write!(fmt, ")")
+ }
+ FalseEdge { .. } => write!(fmt, "falseEdge"),
+ FalseUnwind { .. } => write!(fmt, "falseUnwind"),
+ InlineAsm { template, ref operands, options, .. } => {
+ write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
+ for op in operands {
+ write!(fmt, ", ")?;
+ let print_late = |&late| if late { "late" } else { "" };
+ match op {
+ InlineAsmOperand::In { reg, value } => {
+ write!(fmt, "in({reg}) {value:?}")?;
+ }
+ InlineAsmOperand::Out { reg, late, place: Some(place) } => {
+ write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
+ }
+ InlineAsmOperand::Out { reg, late, place: None } => {
+ write!(fmt, "{}out({}) _", print_late(late), reg)?;
+ }
+ InlineAsmOperand::InOut {
+ reg,
+ late,
+ in_value,
+ out_place: Some(out_place),
+ } => {
+ write!(
+ fmt,
+ "in{}out({}) {:?} => {:?}",
+ print_late(late),
+ reg,
+ in_value,
+ out_place
+ )?;
+ }
+ InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
+ write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
+ }
+ InlineAsmOperand::Const { value } => {
+ write!(fmt, "const {value:?}")?;
+ }
+ InlineAsmOperand::SymFn { value } => {
+ write!(fmt, "sym_fn {value:?}")?;
+ }
+ InlineAsmOperand::SymStatic { def_id } => {
+ write!(fmt, "sym_static {def_id:?}")?;
+ }
+ }
+ }
+ write!(fmt, ", options({options:?}))")
+ }
+ }
+ }
+
+ /// Returns the list of labels for the edges to the successor basic blocks.
+ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
+ use self::TerminatorKind::*;
+ match *self {
+ Return | UnwindResume | UnwindTerminate(_) | Unreachable | GeneratorDrop => vec![],
+ Goto { .. } => vec!["".into()],
+ SwitchInt { ref targets, .. } => targets
+ .values
+ .iter()
+ .map(|&u| Cow::Owned(u.to_string()))
+ .chain(iter::once("otherwise".into()))
+ .collect(),
+ Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ Call { target: Some(_), unwind: _, .. } => vec!["return".into()],
+ Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
+ Call { target: None, unwind: _, .. } => vec![],
+ Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
+ Yield { drop: None, .. } => vec!["resume".into()],
+ Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
+ Drop { unwind: _, .. } => vec!["return".into()],
+ Assert { unwind: UnwindAction::Cleanup(_), .. } => {
+ vec!["success".into(), "unwind".into()]
+ }
+ Assert { unwind: _, .. } => vec!["success".into()],
+ FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
+ FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => {
+ vec!["real".into(), "unwind".into()]
+ }
+ FalseUnwind { unwind: _, .. } => vec!["real".into()],
+ InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ InlineAsm { destination: Some(_), unwind: _, .. } => {
+ vec!["return".into()]
+ }
+ InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
+ vec!["unwind".into()]
+ }
+ InlineAsm { destination: None, unwind: _, .. } => vec![],
+ }
+ }
+}
+
+impl<'tcx> Debug for Rvalue<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ use self::Rvalue::*;
+
+ match *self {
+ Use(ref place) => write!(fmt, "{place:?}"),
+ Repeat(ref a, b) => {
+ write!(fmt, "[{a:?}; ")?;
+ pretty_print_const(b, fmt, false)?;
+ write!(fmt, "]")
+ }
+ Len(ref a) => write!(fmt, "Len({a:?})"),
+ Cast(ref kind, ref place, ref ty) => {
+ with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
+ }
+ BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
+ CheckedBinaryOp(ref op, box (ref a, ref b)) => {
+ write!(fmt, "Checked{op:?}({a:?}, {b:?})")
+ }
+ UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
+ Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
+ NullaryOp(ref op, ref t) => {
+ let t = with_no_trimmed_paths!(format!("{}", t));
+ match op {
+ NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
+ NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
+ NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
+ }
+ }
+ ThreadLocalRef(did) => ty::tls::with(|tcx| {
+ let muta = tcx.static_mutability(did).unwrap().prefix_str();
+ write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
+ }),
+ Ref(region, borrow_kind, ref place) => {
+ let kind_str = match borrow_kind {
+ BorrowKind::Shared => "",
+ BorrowKind::Fake => "fake ",
+ BorrowKind::Mut { .. } => "mut ",
+ };
+
+ // When printing regions, add trailing space if necessary.
+ let print_region = ty::tls::with(|tcx| {
+ tcx.sess.verbose() || tcx.sess.opts.unstable_opts.identify_regions
+ });
+ let region = if print_region {
+ let mut region = region.to_string();
+ if !region.is_empty() {
+ region.push(' ');
+ }
+ region
+ } else {
+ // Do not even print 'static
+ String::new()
+ };
+ write!(fmt, "&{region}{kind_str}{place:?}")
+ }
+
+ CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"),
+
+ AddressOf(mutability, ref place) => {
+ let kind_str = match mutability {
+ Mutability::Mut => "mut",
+ Mutability::Not => "const",
+ };
+
+ write!(fmt, "&raw {kind_str} {place:?}")
+ }
+
+ Aggregate(ref kind, ref places) => {
+ let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| {
+ let mut tuple_fmt = fmt.debug_tuple(name);
+ for place in places {
+ tuple_fmt.field(place);
+ }
+ tuple_fmt.finish()
+ };
+
+ match **kind {
+ AggregateKind::Array(_) => write!(fmt, "{places:?}"),
+
+ AggregateKind::Tuple => {
+ if places.is_empty() {
+ write!(fmt, "()")
+ } else {
+ fmt_tuple(fmt, "")
+ }
+ }
+
+ AggregateKind::Adt(adt_did, variant, args, _user_ty, _) => {
+ ty::tls::with(|tcx| {
+ let variant_def = &tcx.adt_def(adt_did).variant(variant);
+ let args = tcx.lift(args).expect("could not lift for printing");
+ let name = FmtPrinter::new(tcx, Namespace::ValueNS)
+ .print_def_path(variant_def.def_id, args)?
+ .into_buffer();
+
+ match variant_def.ctor_kind() {
+ Some(CtorKind::Const) => fmt.write_str(&name),
+ Some(CtorKind::Fn) => fmt_tuple(fmt, &name),
+ None => {
+ let mut struct_fmt = fmt.debug_struct(&name);
+ for (field, place) in iter::zip(&variant_def.fields, places) {
+ struct_fmt.field(field.name.as_str(), place);
+ }
+ struct_fmt.finish()
+ }
+ }
+ })
+ }
+
+ AggregateKind::Closure(def_id, args) => ty::tls::with(|tcx| {
+ let name = if tcx.sess.opts.unstable_opts.span_free_formats {
+ let args = tcx.lift(args).unwrap();
+ format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),)
+ } else {
+ let span = tcx.def_span(def_id);
+ format!(
+ "{{closure@{}}}",
+ tcx.sess.source_map().span_to_diagnostic_string(span)
+ )
+ };
+ let mut struct_fmt = fmt.debug_struct(&name);
+
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
+ if let Some(def_id) = def_id.as_local()
+ && let Some(upvars) = tcx.upvars_mentioned(def_id)
+ {
+ for (&var_id, place) in iter::zip(upvars.keys(), places) {
+ let var_name = tcx.hir().name(var_id);
+ struct_fmt.field(var_name.as_str(), place);
+ }
+ } else {
+ for (index, place) in places.iter().enumerate() {
+ struct_fmt.field(&format!("{index}"), place);
+ }
+ }
+
+ struct_fmt.finish()
+ }),
+
+ AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| {
+ let name = format!("{{generator@{:?}}}", tcx.def_span(def_id));
+ let mut struct_fmt = fmt.debug_struct(&name);
+
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
+ if let Some(def_id) = def_id.as_local()
+ && let Some(upvars) = tcx.upvars_mentioned(def_id)
+ {
+ for (&var_id, place) in iter::zip(upvars.keys(), places) {
+ let var_name = tcx.hir().name(var_id);
+ struct_fmt.field(var_name.as_str(), place);
+ }
+ } else {
+ for (index, place) in places.iter().enumerate() {
+ struct_fmt.field(&format!("{index}"), place);
+ }
+ }
+
+ struct_fmt.finish()
+ }),
+ }
+ }
+
+ ShallowInitBox(ref place, ref ty) => {
+ with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
+ }
+ }
+ }
+}
+
+impl<'tcx> Debug for Operand<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ use self::Operand::*;
+ match *self {
+ Constant(ref a) => write!(fmt, "{a:?}"),
+ Copy(ref place) => write!(fmt, "{place:?}"),
+ Move(ref place) => write!(fmt, "move {place:?}"),
+ }
+ }
+}
+
+impl<'tcx> Debug for ConstOperand<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ write!(fmt, "{self}")
+ }
+}
+
+impl<'tcx> Display for ConstOperand<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ match self.ty().kind() {
+ ty::FnDef(..) => {}
+ _ => write!(fmt, "const ")?,
+ }
+ Display::fmt(&self.const_, fmt)
+ }
+}
+
+impl Debug for Place<'_> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ self.as_ref().fmt(fmt)
+ }
+}
+
+impl Debug for PlaceRef<'_> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ pre_fmt_projection(self.projection, fmt)?;
+ write!(fmt, "{:?}", self.local)?;
+ post_fmt_projection(self.projection, fmt)
+ }
+}
+
+fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
+ for &elem in projection.iter().rev() {
+ match elem {
+ ProjectionElem::OpaqueCast(_)
+ | ProjectionElem::Subtype(_)
+ | ProjectionElem::Downcast(_, _)
+ | ProjectionElem::Field(_, _) => {
+ write!(fmt, "(").unwrap();
+ }
+ ProjectionElem::Deref => {
+ write!(fmt, "(*").unwrap();
+ }
+ ProjectionElem::Index(_)
+ | ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. } => {}
+ }
+ }
+
+ Ok(())
+}
+
+fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
+ for &elem in projection.iter() {
+ match elem {
+ ProjectionElem::OpaqueCast(ty) => {
+ write!(fmt, " as {ty})")?;
+ }
+ ProjectionElem::Subtype(ty) => {
+ write!(fmt, " as subtype {ty})")?;
+ }
+ ProjectionElem::Downcast(Some(name), _index) => {
+ write!(fmt, " as {name})")?;
+ }
+ ProjectionElem::Downcast(None, index) => {
+ write!(fmt, " as variant#{index:?})")?;
+ }
+ ProjectionElem::Deref => {
+ write!(fmt, ")")?;
+ }
+ ProjectionElem::Field(field, ty) => {
+ with_no_trimmed_paths!(write!(fmt, ".{:?}: {})", field.index(), ty)?);
+ }
+ ProjectionElem::Index(ref index) => {
+ write!(fmt, "[{index:?}]")?;
+ }
+ ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
+ write!(fmt, "[{offset:?} of {min_length:?}]")?;
+ }
+ ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
+ write!(fmt, "[-{offset:?} of {min_length:?}]")?;
+ }
+ ProjectionElem::Subslice { from, to: 0, from_end: true } => {
+ write!(fmt, "[{from:?}:]")?;
+ }
+ ProjectionElem::Subslice { from: 0, to, from_end: true } => {
+ write!(fmt, "[:-{to:?}]")?;
+ }
+ ProjectionElem::Subslice { from, to, from_end: true } => {
+ write!(fmt, "[{from:?}:-{to:?}]")?;
+ }
+ ProjectionElem::Subslice { from, to, from_end: false } => {
+ write!(fmt, "[{from:?}..{to:?}]")?;
+ }
+ }
+ }
+
+ Ok(())
+}
+
/// After we print the main statement, we sometimes dump extra
/// information. There's often a lot of little things "nuzzled up" in
/// a statement.
-fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: F) -> io::Result<()>
+fn write_extra<'tcx, F>(
+ tcx: TyCtxt<'tcx>,
+ write: &mut dyn io::Write,
+ mut visit_op: F,
+) -> io::Result<()>
where
F: FnMut(&mut ExtraComments<'tcx>),
{
@@ -443,10 +1215,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool {
}
impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
- fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
- let Constant { span, user_ty, literal } = constant;
- if use_verbose(literal.ty(), true) {
- self.push("mir::Constant");
+ fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) {
+ let ConstOperand { span, user_ty, const_ } = constant;
+ if use_verbose(const_.ty(), true) {
+ self.push("mir::ConstOperand");
self.push(&format!(
"+ span: {}",
self.tcx.sess.source_map().span_to_embeddable_string(*span)
@@ -455,34 +1227,35 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
self.push(&format!("+ user_ty: {user_ty:?}"));
}
- // FIXME: this is a poor version of `pretty_print_const_value`.
- let fmt_val = |val: &ConstValue<'tcx>| match val {
- ConstValue::ZeroSized => "<ZST>".to_string(),
- ConstValue::Scalar(s) => format!("Scalar({s:?})"),
- ConstValue::Slice { .. } => "Slice(..)".to_string(),
- ConstValue::ByRef { .. } => "ByRef(..)".to_string(),
+ let fmt_val = |val: ConstValue<'tcx>, ty: Ty<'tcx>| {
+ let tcx = self.tcx;
+ rustc_data_structures::make_display(move |fmt| {
+ pretty_print_const_value_tcx(tcx, val, ty, fmt)
+ })
};
+ // FIXME: call pretty_print_const_valtree?
let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
- ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({leaf:?})"),
- ty::ValTree::Branch(_) => "ValTree::Branch(..)".to_string(),
+ ty::ValTree::Leaf(leaf) => format!("Leaf({leaf:?})"),
+ ty::ValTree::Branch(_) => "Branch(..)".to_string(),
};
- let val = match literal {
- ConstantKind::Ty(ct) => match ct.kind() {
- ty::ConstKind::Param(p) => format!("Param({p})"),
+ let val = match const_ {
+ Const::Ty(ct) => match ct.kind() {
+ ty::ConstKind::Param(p) => format!("ty::Param({p})"),
ty::ConstKind::Unevaluated(uv) => {
- format!("Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
+ format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
}
- ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
+ ty::ConstKind::Value(val) => format!("ty::Valtree({})", fmt_valtree(&val)),
+ // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
ty::ConstKind::Error(_) => "Error".to_string(),
// These variants shouldn't exist in the MIR.
ty::ConstKind::Placeholder(_)
| ty::ConstKind::Infer(_)
| ty::ConstKind::Expr(_)
- | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal),
+ | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_),
},
- ConstantKind::Unevaluated(uv, _) => {
+ Const::Unevaluated(uv, _) => {
format!(
"Unevaluated({}, {:?}, {:?})",
self.tcx.def_path_str(uv.def),
@@ -490,16 +1263,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
uv.promoted,
)
}
- // To keep the diffs small, we render this like we render `ty::Const::Value`.
- //
- // This changes once `ty::Const::Value` is represented using valtrees.
- ConstantKind::Val(val, _) => format!("Value({})", fmt_val(&val)),
+ Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
};
// This reflects what `Const` looked liked before `val` was renamed
// as `kind`. We print it like this to avoid having to update
// expected output in a lot of tests.
- self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
+ self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val));
}
}
@@ -536,162 +1306,15 @@ fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String {
format!("scope {} at {}", scope.index(), location,)
}
-/// Prints local variables in a scope tree.
-fn write_scope_tree(
- tcx: TyCtxt<'_>,
- body: &Body<'_>,
- scope_tree: &FxHashMap<SourceScope, Vec<SourceScope>>,
- w: &mut dyn Write,
- parent: SourceScope,
- depth: usize,
-) -> io::Result<()> {
- let indent = depth * INDENT.len();
-
- // Local variable debuginfo.
- for var_debug_info in &body.var_debug_info {
- if var_debug_info.source_info.scope != parent {
- // Not declared in this scope.
- continue;
- }
-
- let indented_debug_info = format!(
- "{0:1$}debug {2} => {3:?};",
- INDENT, indent, var_debug_info.name, var_debug_info.value,
- );
-
- if tcx.sess.opts.unstable_opts.mir_include_spans {
- writeln!(
- w,
- "{0:1$} // in {2}",
- indented_debug_info,
- ALIGN,
- comment(tcx, var_debug_info.source_info),
- )?;
- } else {
- writeln!(w, "{indented_debug_info}")?;
- }
- }
-
- // Local variable types.
- for (local, local_decl) in body.local_decls.iter_enumerated() {
- if (1..body.arg_count + 1).contains(&local.index()) {
- // Skip over argument locals, they're printed in the signature.
- continue;
- }
-
- if local_decl.source_info.scope != parent {
- // Not declared in this scope.
- continue;
- }
-
- let mut_str = local_decl.mutability.prefix_str();
-
- let mut indented_decl =
- format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
- if let Some(user_ty) = &local_decl.user_ty {
- for user_ty in user_ty.projections() {
- write!(indented_decl, " as {user_ty:?}").unwrap();
- }
- }
- indented_decl.push(';');
-
- let local_name = if local == RETURN_PLACE { " return place" } else { "" };
-
- if tcx.sess.opts.unstable_opts.mir_include_spans {
- writeln!(
- w,
- "{0:1$} //{2} in {3}",
- indented_decl,
- ALIGN,
- local_name,
- comment(tcx, local_decl.source_info),
- )?;
- } else {
- writeln!(w, "{indented_decl}",)?;
- }
- }
-
- let Some(children) = scope_tree.get(&parent) else {
- return Ok(());
- };
-
- for &child in children {
- let child_data = &body.source_scopes[child];
- assert_eq!(child_data.parent_scope, Some(parent));
-
- let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined {
- (
- format!(
- " (inlined {}{})",
- if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" },
- callee
- ),
- Some(callsite_span),
- )
- } else {
- (String::new(), None)
- };
-
- let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special);
-
- if tcx.sess.opts.unstable_opts.mir_include_spans {
- if let Some(span) = span {
- writeln!(
- w,
- "{0:1$} // at {2}",
- indented_header,
- ALIGN,
- tcx.sess.source_map().span_to_embeddable_string(span),
- )?;
- } else {
- writeln!(w, "{indented_header}")?;
- }
- } else {
- writeln!(w, "{indented_header}")?;
- }
-
- write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?;
- writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
- }
-
- Ok(())
-}
-
-/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
-/// local variables (both user-defined bindings and compiler temporaries).
-pub fn write_mir_intro<'tcx>(
- tcx: TyCtxt<'tcx>,
- body: &Body<'_>,
- w: &mut dyn Write,
-) -> io::Result<()> {
- write_mir_sig(tcx, body, w)?;
- writeln!(w, "{{")?;
-
- // construct a scope tree and write it out
- let mut scope_tree: FxHashMap<SourceScope, Vec<SourceScope>> = Default::default();
- for (index, scope_data) in body.source_scopes.iter().enumerate() {
- if let Some(parent) = scope_data.parent_scope {
- scope_tree.entry(parent).or_default().push(SourceScope::new(index));
- } else {
- // Only the argument scope has no parent, because it's the root.
- assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index());
- }
- }
-
- write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?;
-
- // Add an empty line before the first block is printed.
- writeln!(w)?;
-
- Ok(())
-}
+///////////////////////////////////////////////////////////////////////////
+// Allocations
/// Find all `AllocId`s mentioned (recursively) in the MIR body and print their corresponding
/// allocations.
pub fn write_allocations<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'_>,
- w: &mut dyn Write,
+ w: &mut dyn io::Write,
) -> io::Result<()> {
fn alloc_ids_from_alloc(
alloc: ConstAllocation<'_>,
@@ -702,24 +1325,28 @@ pub fn write_allocations<'tcx>(
fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
- Either::Left(Either::Left(std::iter::once(ptr.provenance)))
+ Either::Left(std::iter::once(ptr.provenance))
}
- ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
- Either::Left(Either::Right(std::iter::empty()))
+ ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
+ ConstValue::ZeroSized => Either::Right(std::iter::empty()),
+ ConstValue::Slice { .. } => {
+ // `u8`/`str` slices, shouldn't contain pointers that we want to print.
+ Either::Right(std::iter::empty())
}
- ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())),
- ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
- Either::Right(alloc_ids_from_alloc(alloc))
+ ConstValue::Indirect { alloc_id, .. } => {
+ // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
+ // Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
+ Either::Left(std::iter::once(alloc_id))
}
}
}
struct CollectAllocIds(BTreeSet<AllocId>);
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
- fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) {
- match c.literal {
- ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {}
- ConstantKind::Val(val, _) => {
+ fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
+ match c.const_ {
+ Const::Ty(_) | Const::Unevaluated(..) => {}
+ Const::Val(val, _) => {
self.0.extend(alloc_ids_from_const_val(val));
}
}
@@ -736,7 +1363,7 @@ pub fn write_allocations<'tcx>(
let mut todo: Vec<_> = seen.iter().copied().collect();
while let Some(id) = todo.pop() {
let mut write_allocation_track_relocs =
- |w: &mut dyn Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
+ |w: &mut dyn io::Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
// `.rev()` because we are popping them from the back of the `todo` vector.
for id in alloc_ids_from_alloc(alloc).rev() {
if seen.insert(id) {
@@ -997,91 +1624,173 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>(
Ok(())
}
-fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> {
- use rustc_hir::def::DefKind;
-
- trace!("write_mir_sig: {:?}", body.source.instance);
- let def_id = body.source.def_id();
- let kind = tcx.def_kind(def_id);
- let is_function = match kind {
- DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
- _ => tcx.is_closure(def_id),
- };
- match (kind, body.source.promoted) {
- (_, Some(i)) => write!(w, "{i:?} in ")?,
- (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
- (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
- (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
- (_, _) if is_function => write!(w, "fn ")?,
- (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
- _ => bug!("Unexpected def kind {:?}", kind),
- }
-
- ty::print::with_forced_impl_filename_line! {
- // see notes on #41697 elsewhere
- write!(w, "{}", tcx.def_path_str(def_id))?
- }
+///////////////////////////////////////////////////////////////////////////
+// Constants
- if body.source.promoted.is_none() && is_function {
- write!(w, "(")?;
+fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result {
+ write!(fmt, "b\"{}\"", byte_str.escape_ascii())
+}
- // fn argument types.
- for (i, arg) in body.args_iter().enumerate() {
- if i != 0 {
- write!(w, ", ")?;
- }
- write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?;
+fn comma_sep<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fmt: &mut Formatter<'_>,
+ elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>,
+) -> fmt::Result {
+ let mut first = true;
+ for (ct, ty) in elems {
+ if !first {
+ fmt.write_str(", ")?;
}
-
- write!(w, ") -> {}", body.return_ty())?;
- } else {
- assert_eq!(body.arg_count, 0);
- write!(w, ": {} =", body.return_ty())?;
+ pretty_print_const_value_tcx(tcx, ct, ty, fmt)?;
+ first = false;
}
-
- if let Some(yield_ty) = body.yield_ty() {
- writeln!(w)?;
- writeln!(w, "yields {yield_ty}")?;
- }
-
- write!(w, " ")?;
- // Next thing that gets printed is the opening {
-
Ok(())
}
-fn write_user_type_annotations(
- tcx: TyCtxt<'_>,
- body: &Body<'_>,
- w: &mut dyn Write,
-) -> io::Result<()> {
- if !body.user_type_annotations.is_empty() {
- writeln!(w, "| User Type Annotations")?;
- }
- for (index, annotation) in body.user_type_annotations.iter_enumerated() {
- writeln!(
- w,
- "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
- index.index(),
- annotation.user_ty,
- tcx.sess.source_map().span_to_embeddable_string(annotation.span),
- annotation.inferred_ty,
- )?;
+fn pretty_print_const_value_tcx<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ct: ConstValue<'tcx>,
+ ty: Ty<'tcx>,
+ fmt: &mut Formatter<'_>,
+) -> fmt::Result {
+ use crate::ty::print::PrettyPrinter;
+
+ if tcx.sess.verbose() {
+ fmt.write_str(&format!("ConstValue({ct:?}: {ty})"))?;
+ return Ok(());
}
- if !body.user_type_annotations.is_empty() {
- writeln!(w, "|")?;
+
+ let u8_type = tcx.types.u8;
+ match (ct, ty.kind()) {
+ // Byte/string slices, printed as (byte) string literals.
+ (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
+ if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) {
+ fmt.write_str(&format!("{:?}", String::from_utf8_lossy(data)))?;
+ return Ok(());
+ }
+ }
+ (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(t) if *t == u8_type) => {
+ if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) {
+ pretty_print_byte_str(fmt, data)?;
+ return Ok(());
+ }
+ }
+ (ConstValue::Indirect { alloc_id, offset }, ty::Array(t, n)) if *t == u8_type => {
+ let n = n.try_to_target_usize(tcx).unwrap();
+ let alloc = tcx.global_alloc(alloc_id).unwrap_memory();
+ // cast is ok because we already checked for pointer size (32 or 64 bit) above
+ let range = AllocRange { start: offset, size: Size::from_bytes(n) };
+ let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
+ fmt.write_str("*")?;
+ pretty_print_byte_str(fmt, byte_str)?;
+ return Ok(());
+ }
+ // Aggregates, printed as array/tuple/struct/variant construction syntax.
+ //
+ // NB: the `has_non_region_param` check ensures that we can use
+ // the `destructure_const` query with an empty `ty::ParamEnv` without
+ // introducing ICEs (e.g. via `layout_of`) from missing bounds.
+ // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
+ // to be able to destructure the tuple into `(0u8, *mut T)`
+ (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => {
+ let ct = tcx.lift(ct).unwrap();
+ let ty = tcx.lift(ty).unwrap();
+ if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics(ct, ty) {
+ let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec();
+ match *ty.kind() {
+ ty::Array(..) => {
+ fmt.write_str("[")?;
+ comma_sep(tcx, fmt, fields)?;
+ fmt.write_str("]")?;
+ }
+ ty::Tuple(..) => {
+ fmt.write_str("(")?;
+ comma_sep(tcx, fmt, fields)?;
+ if contents.fields.len() == 1 {
+ fmt.write_str(",")?;
+ }
+ fmt.write_str(")")?;
+ }
+ ty::Adt(def, _) if def.variants().is_empty() => {
+ fmt.write_str(&format!("{{unreachable(): {ty}}}"))?;
+ }
+ ty::Adt(def, args) => {
+ let variant_idx = contents
+ .variant
+ .expect("destructed mir constant of adt without variant idx");
+ let variant_def = &def.variant(variant_idx);
+ let args = tcx.lift(args).unwrap();
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.print_value_path(variant_def.def_id, args)?;
+ fmt.write_str(&cx.into_buffer())?;
+
+ match variant_def.ctor_kind() {
+ Some(CtorKind::Const) => {}
+ Some(CtorKind::Fn) => {
+ fmt.write_str("(")?;
+ comma_sep(tcx, fmt, fields)?;
+ fmt.write_str(")")?;
+ }
+ None => {
+ fmt.write_str(" {{ ")?;
+ let mut first = true;
+ for (field_def, (ct, ty)) in iter::zip(&variant_def.fields, fields)
+ {
+ if !first {
+ fmt.write_str(", ")?;
+ }
+ write!(fmt, "{}: ", field_def.name)?;
+ pretty_print_const_value_tcx(tcx, ct, ty, fmt)?;
+ first = false;
+ }
+ fmt.write_str(" }}")?;
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+ return Ok(());
+ }
+ }
+ (ConstValue::Scalar(scalar), _) => {
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let ty = tcx.lift(ty).unwrap();
+ cx = cx.pretty_print_const_scalar(scalar, ty)?;
+ fmt.write_str(&cx.into_buffer())?;
+ return Ok(());
+ }
+ (ConstValue::ZeroSized, ty::FnDef(d, s)) => {
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.print_value_path(*d, s)?;
+ fmt.write_str(&cx.into_buffer())?;
+ return Ok(());
+ }
+ // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
+ // their fields instead of just dumping the memory.
+ _ => {}
}
- Ok(())
+ // Fall back to debug pretty printing for invalid constants.
+ write!(fmt, "{ct:?}: {ty}")
}
-pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> {
- if let Some(i) = single {
- vec![i]
- } else {
- tcx.mir_keys(()).iter().map(|def_id| def_id.to_def_id()).collect()
- }
+pub(crate) fn pretty_print_const_value<'tcx>(
+ ct: ConstValue<'tcx>,
+ ty: Ty<'tcx>,
+ fmt: &mut Formatter<'_>,
+) -> fmt::Result {
+ ty::tls::with(|tcx| {
+ let ct = tcx.lift(ct).unwrap();
+ let ty = tcx.lift(ty).unwrap();
+ pretty_print_const_value_tcx(tcx, ct, ty, fmt)
+ })
}
+///////////////////////////////////////////////////////////////////////////
+// Miscellaneous
+
/// Calc converted u64 decimal into hex and return it's length in chars
///
/// ```ignore (cannot-test-private-function)
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 71bec49af..c74a9536b 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,6 +1,5 @@
//! Values computed by queries that use MIR.
-use crate::mir::interpret::ConstValue;
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
@@ -16,7 +15,7 @@ use smallvec::SmallVec;
use std::cell::Cell;
use std::fmt::{self, Debug};
-use super::SourceInfo;
+use super::{ConstValue, SourceInfo};
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
@@ -334,7 +333,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
///
/// See also `rustc_const_eval::borrow_check::constraints`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ConstraintCategory<'tcx> {
Return(ReturnConstraint),
Yield,
@@ -415,8 +414,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
ty::ReVar(vid) => {
- let br =
- ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) };
+ let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon };
ty::Region::new_late_bound(tcx, depth, br)
}
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 20a9e6889..a5358687c 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -238,45 +238,6 @@ pub fn source_range_no_file(tcx: TyCtxt<'_>, span: Span) -> String {
format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1)
}
-pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
- use StatementKind::*;
- match statement.kind {
- Assign(..) => "Assign",
- FakeRead(..) => "FakeRead",
- SetDiscriminant { .. } => "SetDiscriminant",
- Deinit(..) => "Deinit",
- StorageLive(..) => "StorageLive",
- StorageDead(..) => "StorageDead",
- Retag(..) => "Retag",
- PlaceMention(..) => "PlaceMention",
- AscribeUserType(..) => "AscribeUserType",
- Coverage(..) => "Coverage",
- Intrinsic(..) => "Intrinsic",
- ConstEvalCounter => "ConstEvalCounter",
- Nop => "Nop",
- }
-}
-
-pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
- use TerminatorKind::*;
- match term.kind {
- Goto { .. } => "Goto",
- SwitchInt { .. } => "SwitchInt",
- Resume => "Resume",
- Terminate => "Terminate",
- Return => "Return",
- Unreachable => "Unreachable",
- Drop { .. } => "Drop",
- Call { .. } => "Call",
- Assert { .. } => "Assert",
- Yield { .. } => "Yield",
- GeneratorDrop => "GeneratorDrop",
- FalseEdge { .. } => "FalseEdge",
- FalseUnwind { .. } => "FalseUnwind",
- InlineAsm { .. } => "InlineAsm",
- }
-}
-
fn statement_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
@@ -304,7 +265,7 @@ fn terminator_span_viewable<'tcx>(
if !body_span.contains(span) {
return None;
}
- let id = format!("{}:{}", bb.index(), terminator_kind_name(term));
+ let id = format!("{}:{}", bb.index(), term.kind.name());
let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator);
Some(SpanViewable { bb, span, id, tooltip })
}
@@ -631,7 +592,7 @@ fn tooltip<'tcx>(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
- statement_kind_name(&statement),
+ statement.kind.name(),
statement
));
}
@@ -641,7 +602,7 @@ fn tooltip<'tcx>(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
- terminator_kind_name(term),
+ term.kind.name(),
term.kind
));
}
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
new file mode 100644
index 000000000..3471d620e
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -0,0 +1,464 @@
+/// Functionality for statements, operands, places, and things that appear in them.
+use super::{interpret::GlobalAlloc, *};
+
+///////////////////////////////////////////////////////////////////////////
+// Statements
+
+/// A statement in a basic block, including information about its source code.
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct Statement<'tcx> {
+ pub source_info: SourceInfo,
+ pub kind: StatementKind<'tcx>,
+}
+
+impl Statement<'_> {
+ /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
+ /// invalidating statement indices in `Location`s.
+ 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> {
+ pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
+ match self {
+ StatementKind::Assign(x) => Some(x),
+ _ => None,
+ }
+ }
+
+ pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> {
+ match self {
+ StatementKind::Assign(x) => Some(x),
+ _ => None,
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Places
+
+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.
+ fn is_indirect(&self) -> bool {
+ match self {
+ Self::Deref => true,
+
+ Self::Field(_, _)
+ | Self::Index(_)
+ | Self::OpaqueCast(_)
+ | Self::Subtype(_)
+ | Self::ConstantIndex { .. }
+ | Self::Subslice { .. }
+ | Self::Downcast(_, _) => false,
+ }
+ }
+
+ /// Returns `true` if the target of this projection always refers to the same memory region
+ /// whatever the state of the program.
+ pub fn is_stable_offset(&self) -> bool {
+ match self {
+ Self::Deref | Self::Index(_) => false,
+ Self::Field(_, _)
+ | Self::OpaqueCast(_)
+ | Self::Subtype(_)
+ | Self::ConstantIndex { .. }
+ | Self::Subslice { .. }
+ | Self::Downcast(_, _) => true,
+ }
+ }
+
+ /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
+ pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
+ matches!(*self, Self::Downcast(_, x) if x == v)
+ }
+
+ /// Returns `true` if this is a `Field` projection with the given index.
+ pub fn is_field_to(&self, f: FieldIdx) -> bool {
+ matches!(*self, Self::Field(x, _) if x == f)
+ }
+
+ /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
+ pub fn can_use_in_debuginfo(&self) -> bool {
+ match self {
+ Self::ConstantIndex { from_end: false, .. }
+ | Self::Deref
+ | Self::Downcast(_, _)
+ | Self::Field(_, _) => true,
+ Self::ConstantIndex { from_end: true, .. }
+ | Self::Index(_)
+ | Self::Subtype(_)
+ | Self::OpaqueCast(_)
+ | Self::Subslice { .. } => false,
+ }
+ }
+}
+
+/// Alias for projections as they appear in `UserTypeProjection`, where we
+/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
+pub type ProjectionKind = ProjectionElem<(), ()>;
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct PlaceRef<'tcx> {
+ pub local: Local,
+ pub projection: &'tcx [PlaceElem<'tcx>],
+}
+
+// Once we stop implementing `Ord` for `DefId`,
+// this impl will be unnecessary. Until then, we'll
+// leave this impl in place to prevent re-adding a
+// dependency on the `Ord` impl for `DefId`
+impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
+
+impl<'tcx> Place<'tcx> {
+ // FIXME change this to a const fn by also making List::empty a const fn.
+ pub fn return_place() -> Place<'tcx> {
+ Place { local: RETURN_PLACE, projection: List::empty() }
+ }
+
+ /// Returns `true` if this `Place` contains a `Deref` projection.
+ ///
+ /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
+ /// same region of memory as its base.
+ pub fn is_indirect(&self) -> bool {
+ self.projection.iter().any(|elem| elem.is_indirect())
+ }
+
+ /// Returns `true` if this `Place`'s first projection is `Deref`.
+ ///
+ /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
+ /// `Deref` projections can only occur as the first projection. In that case this method
+ /// is equivalent to `is_indirect`, but faster.
+ pub fn is_indirect_first_projection(&self) -> bool {
+ self.as_ref().is_indirect_first_projection()
+ }
+
+ /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
+ /// a single deref of a local.
+ #[inline(always)]
+ pub fn local_or_deref_local(&self) -> Option<Local> {
+ self.as_ref().local_or_deref_local()
+ }
+
+ /// If this place represents a local variable like `_X` with no
+ /// projections, return `Some(_X)`.
+ #[inline(always)]
+ pub fn as_local(&self) -> Option<Local> {
+ self.as_ref().as_local()
+ }
+
+ #[inline]
+ pub fn as_ref(&self) -> PlaceRef<'tcx> {
+ PlaceRef { local: self.local, projection: &self.projection }
+ }
+
+ /// Iterate over the projections in evaluation order, i.e., the first element is the base with
+ /// its projection and then subsequently more projections are added.
+ /// As a concrete example, given the place a.b.c, this would yield:
+ /// - (a, .b)
+ /// - (a.b, .c)
+ ///
+ /// Given a place without projections, the iterator is empty.
+ #[inline]
+ pub fn iter_projections(
+ self,
+ ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
+ self.as_ref().iter_projections()
+ }
+
+ /// Generates a new place by appending `more_projections` to the existing ones
+ /// and interning the result.
+ pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
+ if more_projections.is_empty() {
+ return self;
+ }
+
+ self.as_ref().project_deeper(more_projections, tcx)
+ }
+}
+
+impl From<Local> for Place<'_> {
+ #[inline]
+ fn from(local: Local) -> Self {
+ Place { local, projection: List::empty() }
+ }
+}
+
+impl<'tcx> PlaceRef<'tcx> {
+ /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
+ /// a single deref of a local.
+ pub fn local_or_deref_local(&self) -> Option<Local> {
+ match *self {
+ PlaceRef { local, projection: [] }
+ | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
+ _ => None,
+ }
+ }
+
+ /// Returns `true` if this `Place` contains a `Deref` projection.
+ ///
+ /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
+ /// same region of memory as its base.
+ pub fn is_indirect(&self) -> bool {
+ self.projection.iter().any(|elem| elem.is_indirect())
+ }
+
+ /// Returns `true` if this `Place`'s first projection is `Deref`.
+ ///
+ /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
+ /// `Deref` projections can only occur as the first projection. In that case this method
+ /// is equivalent to `is_indirect`, but faster.
+ pub fn is_indirect_first_projection(&self) -> bool {
+ // To make sure this is not accidentally used in wrong mir phase
+ debug_assert!(
+ self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
+ );
+ self.projection.first() == Some(&PlaceElem::Deref)
+ }
+
+ /// If this place represents a local variable like `_X` with no
+ /// projections, return `Some(_X)`.
+ #[inline]
+ pub fn as_local(&self) -> Option<Local> {
+ match *self {
+ PlaceRef { local, projection: [] } => Some(local),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
+ if let &[ref proj_base @ .., elem] = self.projection {
+ Some((PlaceRef { local: self.local, projection: proj_base }, elem))
+ } else {
+ None
+ }
+ }
+
+ /// Iterate over the projections in evaluation order, i.e., the first element is the base with
+ /// its projection and then subsequently more projections are added.
+ /// As a concrete example, given the place a.b.c, this would yield:
+ /// - (a, .b)
+ /// - (a.b, .c)
+ ///
+ /// Given a place without projections, the iterator is empty.
+ #[inline]
+ pub fn iter_projections(
+ self,
+ ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
+ self.projection.iter().enumerate().map(move |(i, proj)| {
+ let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
+ (base, *proj)
+ })
+ }
+
+ /// Generates a new place by appending `more_projections` to the existing ones
+ /// and interning the result.
+ pub fn project_deeper(
+ self,
+ more_projections: &[PlaceElem<'tcx>],
+ tcx: TyCtxt<'tcx>,
+ ) -> Place<'tcx> {
+ let mut v: Vec<PlaceElem<'tcx>>;
+
+ let new_projections = if self.projection.is_empty() {
+ more_projections
+ } else {
+ v = Vec::with_capacity(self.projection.len() + more_projections.len());
+ v.extend(self.projection);
+ v.extend(more_projections);
+ &v
+ };
+
+ Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
+ }
+}
+
+impl From<Local> for PlaceRef<'_> {
+ #[inline]
+ fn from(local: Local) -> Self {
+ PlaceRef { local, projection: &[] }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Operands
+
+impl<'tcx> Operand<'tcx> {
+ /// Convenience helper to make a constant that refers to the fn
+ /// with given `DefId` and args. Since this is used to synthesize
+ /// MIR, assumes `user_ty` is None.
+ pub fn function_handle(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ args: impl IntoIterator<Item = GenericArg<'tcx>>,
+ span: Span,
+ ) -> Self {
+ let ty = Ty::new_fn_def(tcx, def_id, args);
+ Operand::Constant(Box::new(ConstOperand {
+ span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::ZeroSized, ty),
+ }))
+ }
+
+ pub fn is_move(&self) -> bool {
+ matches!(self, Operand::Move(..))
+ }
+
+ /// Convenience helper to make a literal-like constant from a given scalar value.
+ /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+ pub fn const_from_scalar(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ val: Scalar,
+ span: Span,
+ ) -> Operand<'tcx> {
+ debug_assert!({
+ let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+ let type_size = tcx
+ .layout_of(param_env_and_ty)
+ .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
+ .size;
+ let scalar_size = match val {
+ Scalar::Int(int) => int.size(),
+ _ => panic!("Invalid scalar type {val:?}"),
+ };
+ scalar_size == type_size
+ });
+ Operand::Constant(Box::new(ConstOperand {
+ span,
+ user_ty: None,
+ const_: Const::Val(ConstValue::Scalar(val), ty),
+ }))
+ }
+
+ pub fn to_copy(&self) -> Self {
+ match *self {
+ Operand::Copy(_) | Operand::Constant(_) => self.clone(),
+ Operand::Move(place) => Operand::Copy(place),
+ }
+ }
+
+ /// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is a
+ /// constant.
+ pub fn place(&self) -> Option<Place<'tcx>> {
+ match self {
+ Operand::Copy(place) | Operand::Move(place) => Some(*place),
+ Operand::Constant(_) => None,
+ }
+ }
+
+ /// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a
+ /// place.
+ pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
+ match self {
+ Operand::Constant(x) => Some(&**x),
+ Operand::Copy(_) | Operand::Move(_) => None,
+ }
+ }
+
+ /// Gets the `ty::FnDef` from an operand if it's a constant function item.
+ ///
+ /// While this is unlikely in general, it's the normal case of what you'll
+ /// find as the `func` in a [`TerminatorKind::Call`].
+ pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
+ let const_ty = self.constant()?.const_.ty();
+ if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
+ }
+}
+
+impl<'tcx> ConstOperand<'tcx> {
+ pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.const_.try_to_scalar() {
+ Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
+ GlobalAlloc::Static(def_id) => {
+ assert!(!tcx.is_thread_local_static(def_id));
+ Some(def_id)
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn ty(&self) -> Ty<'tcx> {
+ self.const_.ty()
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// Rvalues
+
+impl<'tcx> Rvalue<'tcx> {
+ /// Returns true if rvalue can be safely removed when the result is unused.
+ #[inline]
+ pub fn is_safe_to_remove(&self) -> bool {
+ match self {
+ // Pointer to int casts may be side-effects due to exposing the provenance.
+ // While the model is undecided, we should be conservative. See
+ // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
+ Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+
+ Rvalue::Use(_)
+ | Rvalue::CopyForDeref(_)
+ | Rvalue::Repeat(_, _)
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::Len(_)
+ | Rvalue::Cast(
+ CastKind::IntToInt
+ | CastKind::FloatToInt
+ | CastKind::FloatToFloat
+ | CastKind::IntToFloat
+ | CastKind::FnPtrToPtr
+ | CastKind::PtrToPtr
+ | CastKind::PointerCoercion(_)
+ | CastKind::PointerFromExposedAddress
+ | CastKind::DynStar
+ | CastKind::Transmute,
+ _,
+ _,
+ )
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, _)
+ | Rvalue::Discriminant(_)
+ | Rvalue::Aggregate(_, _)
+ | Rvalue::ShallowInitBox(_, _) => true,
+ }
+ }
+}
+
+impl BorrowKind {
+ pub fn mutability(&self) -> Mutability {
+ match *self {
+ BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
+ BorrowKind::Mut { .. } => Mutability::Mut,
+ }
+ }
+
+ pub fn allows_two_phase_borrow(&self) -> bool {
+ match *self {
+ BorrowKind::Shared
+ | BorrowKind::Fake
+ | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
+ false
+ }
+ BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index be27bf75d..0b95fdfa1 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -3,7 +3,7 @@
//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
//! The intention is that this file only contains datatype declarations, no code.
-use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection};
+use super::{BasicBlock, Const, Local, UserTypeProjection};
use crate::mir::coverage::{CodeRegion, CoverageKind};
use crate::traits::Reveal;
@@ -24,6 +24,7 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::asm::InlineAsmRegOrRegClass;
+use smallvec::SmallVec;
/// Represents the "flavors" of MIR.
///
@@ -122,7 +123,7 @@ pub enum AnalysisPhase {
/// * [`TerminatorKind::FalseEdge`]
/// * [`StatementKind::FakeRead`]
/// * [`StatementKind::AscribeUserType`]
- /// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
+ /// * [`Rvalue::Ref`] with `BorrowKind::Fake`
///
/// Furthermore, `Deref` projections must be the first projection within any place (if they
/// appear at all)
@@ -138,6 +139,7 @@ pub enum RuntimePhase {
/// * [`TerminatorKind::Yield`]
/// * [`TerminatorKind::GeneratorDrop`]
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
+ /// * [`PlaceElem::OpaqueCast`]
///
/// And the following variants are allowed:
/// * [`StatementKind::Retag`]
@@ -180,7 +182,7 @@ pub enum BorrowKind {
/// should not prevent `if let None = x { ... }`, for example, because the
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
/// We can also report errors with this kind of borrow differently.
- Shallow,
+ Fake,
/// Data is mutable and not aliasable.
Mut { kind: MutBorrowKind },
@@ -380,6 +382,28 @@ pub enum StatementKind<'tcx> {
Nop,
}
+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",
+ }
+ }
+}
+
#[derive(
Clone,
TyEncodable,
@@ -416,17 +440,6 @@ pub enum NonDivergingIntrinsic<'tcx> {
CopyNonOverlapping(CopyNonOverlapping<'tcx>),
}
-impl std::fmt::Display for NonDivergingIntrinsic<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Self::Assume(op) => write!(f, "assume({op:?})"),
- Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
- write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
- }
- }
- }
-}
-
/// Describes what kind of retag is to be performed.
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
@@ -593,13 +606,13 @@ pub enum TerminatorKind<'tcx> {
///
/// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
/// deaggregation runs.
- Resume,
+ UnwindResume,
/// Indicates that the landing pad is finished and that the process should terminate.
///
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
/// cleanup blocks.
- Terminate,
+ UnwindTerminate(UnwindTerminateReason),
/// Returns from the function.
///
@@ -790,8 +803,8 @@ impl TerminatorKind<'_> {
match self {
TerminatorKind::Goto { .. } => "Goto",
TerminatorKind::SwitchInt { .. } => "SwitchInt",
- TerminatorKind::Resume => "Resume",
- TerminatorKind::Terminate => "Terminate",
+ TerminatorKind::UnwindResume => "UnwindResume",
+ TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
TerminatorKind::Return => "Return",
TerminatorKind::Unreachable => "Unreachable",
TerminatorKind::Drop { .. } => "Drop",
@@ -806,6 +819,27 @@ impl TerminatorKind<'_> {
}
}
+#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+pub struct SwitchTargets {
+ /// Possible values. The locations to branch to in each case
+ /// are found in the corresponding indices from the `targets` vector.
+ pub(super) values: SmallVec<[u128; 1]>,
+
+ /// Possible branch sites. The last element of this vector is used
+ /// for the otherwise branch, so targets.len() == values.len() + 1
+ /// should hold.
+ //
+ // This invariant is quite non-obvious and also could be improved.
+ // One way to make this invariant is to have something like this instead:
+ //
+ // branches: Vec<(ConstInt, BasicBlock)>,
+ // otherwise: Option<BasicBlock> // exhaustive if None
+ //
+ // 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.
+ pub(super) targets: SmallVec<[BasicBlock; 2]>,
+}
+
/// Action to be taken when a stack unwind happens.
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
@@ -820,11 +854,22 @@ pub enum UnwindAction {
/// Terminates the execution if unwind happens.
///
/// Depending on the platform and situation this may cause a non-unwindable panic or abort.
- Terminate,
+ Terminate(UnwindTerminateReason),
/// Cleanups to be done.
Cleanup(BasicBlock),
}
+/// The reason we are terminating the process during unwinding.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum UnwindTerminateReason {
+ /// Unwinding is just not possible given the ABI of this function.
+ Abi,
+ /// We were already cleaning up for an ongoing unwind, and a *second*, *nested* unwind was
+ /// triggered by the drop glue.
+ InCleanup,
+}
+
/// Information about an assertion failure.
#[derive(Clone, Hash, HashStable, PartialEq, Debug)]
#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
@@ -858,10 +903,10 @@ pub enum InlineAsmOperand<'tcx> {
out_place: Option<Place<'tcx>>,
},
Const {
- value: Box<Constant<'tcx>>,
+ value: Box<ConstOperand<'tcx>>,
},
SymFn {
- value: Box<Constant<'tcx>>,
+ value: Box<ConstOperand<'tcx>>,
},
SymStatic {
def_id: DefId,
@@ -1030,6 +1075,18 @@ pub enum ProjectionElem<V, T> {
/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
OpaqueCast(T),
+
+ /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
+ /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
+ /// explicit during optimizations and codegen.
+ ///
+ /// This projection doesn't impact the runtime behavior of the program except for potentially changing
+ /// some type metadata of the interpreter or codegen backend.
+ ///
+ /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
+ /// borrowchecker, as we only care about subtyping that can affect trait selection and
+ /// `TypeId`.
+ Subtype(T),
}
/// Alias for projections as they appear in places, where the base is a place
@@ -1081,7 +1138,22 @@ pub enum Operand<'tcx> {
Move(Place<'tcx>),
/// Constants are already semantically values, and remain unchanged.
- Constant(Box<Constant<'tcx>>),
+ Constant(Box<ConstOperand<'tcx>>),
+}
+
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ConstOperand<'tcx> {
+ pub span: Span,
+
+ /// Optional user-given type: for something like
+ /// `collect::<Vec<_>>`, this would be present and would
+ /// indicate that `Vec<_>` was explicitly specified.
+ ///
+ /// Needed for NLL to impose user-given type constraints.
+ pub user_ty: Option<UserTypeAnnotationIndex>,
+
+ pub const_: Const<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
@@ -1274,7 +1346,7 @@ pub enum AggregateKind<'tcx> {
Generator(DefId, GenericArgsRef<'tcx>, hir::Movability),
}
-#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum NullOp<'tcx> {
/// Returns the size of a value of that type
SizeOf,
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index f79697936..7df25fc5c 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -69,7 +69,7 @@ impl<'tcx> PlaceTy<'tcx> {
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
- mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
+ mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
@@ -110,7 +110,12 @@ impl<'tcx> PlaceTy<'tcx> {
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(&self, ty)),
+ 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))
+ }
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
@@ -227,7 +232,7 @@ impl<'tcx> Operand<'tcx> {
{
match self {
&Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
- Operand::Constant(c) => c.literal.ty(),
+ Operand::Constant(c) => c.const_.ty(),
}
}
}
@@ -273,7 +278,7 @@ impl BorrowKind {
// We have no type corresponding to a shallow borrow, so use
// `&` as an approximation.
- BorrowKind::Shallow => hir::Mutability::Not,
+ BorrowKind::Fake => hir::Mutability::Not,
}
}
}
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 1f878d23b..02aab4a89 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -1,38 +1,16 @@
+/// Functionality for terminators and helper types that appear in terminators.
+use rustc_hir::LangItem;
use smallvec::SmallVec;
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
-use rustc_ast::InlineAsmTemplatePiece;
pub use rustc_ast::Mutability;
use rustc_macros::HashStable;
-use std::borrow::Cow;
-use std::fmt::{self, Debug, Formatter, Write};
use std::iter;
use std::slice;
pub use super::query::*;
use super::*;
-#[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.
- values: SmallVec<[u128; 1]>,
-
- /// Possible branch sites. The last element of this vector is used
- /// for the otherwise branch, so targets.len() == values.len() + 1
- /// should hold.
- //
- // This invariant is quite non-obvious and also could be improved.
- // One way to make this invariant is to have something like this instead:
- //
- // branches: Vec<(ConstInt, BasicBlock)>,
- // otherwise: Option<BasicBlock> // exhaustive if None
- //
- // 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.
- targets: SmallVec<[BasicBlock; 2]>,
-}
-
impl SwitchTargets {
/// Creates switch targets from an iterator of values and target blocks.
///
@@ -100,6 +78,202 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
+impl UnwindAction {
+ fn cleanup_block(self) -> Option<BasicBlock> {
+ match self {
+ UnwindAction::Cleanup(bb) => Some(bb),
+ UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
+ }
+ }
+}
+
+impl UnwindTerminateReason {
+ pub fn as_str(self) -> &'static str {
+ // Keep this in sync with the messages in `core/src/panicking.rs`.
+ match self {
+ UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
+ UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
+ }
+ }
+
+ /// A short representation of this used for MIR printing.
+ pub fn as_short_str(self) -> &'static str {
+ match self {
+ UnwindTerminateReason::Abi => "abi",
+ UnwindTerminateReason::InCleanup => "cleanup",
+ }
+ }
+
+ pub fn lang_item(self) -> LangItem {
+ match self {
+ UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
+ UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
+ }
+ }
+}
+
+impl<O> AssertKind<O> {
+ /// Returns true if this an overflow checking assertion controlled by -C overflow-checks.
+ pub fn is_optional_overflow_check(&self) -> bool {
+ use AssertKind::*;
+ use BinOp::*;
+ matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
+ }
+
+ /// Get the message that is printed at runtime when this assertion fails.
+ ///
+ /// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` by
+ /// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
+ /// instead of printing a static message.
+ pub fn description(&self) -> &'static str {
+ use AssertKind::*;
+ match self {
+ Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
+ Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
+ Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
+ Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
+ Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
+ OverflowNeg(_) => "attempt to negate with overflow",
+ Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
+ Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
+ Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
+ DivisionByZero(_) => "attempt to divide by zero",
+ RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
+ ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
+ ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
+ ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
+ ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
+ BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
+ bug!("Unexpected AssertKind")
+ }
+ }
+ }
+
+ /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
+ ///
+ /// Needs to be kept in sync with the run-time behavior (which is defined by
+ /// `AssertKind::description` and the lang items mentioned in its docs).
+ /// Note that we deliberately show more details here than we do at runtime, such as the actual
+ /// numbers that overflowed -- it is much easier to do so here than at runtime.
+ pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
+ where
+ O: Debug,
+ {
+ use AssertKind::*;
+ match self {
+ BoundsCheck { ref len, ref index } => write!(
+ f,
+ "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
+ ),
+
+ OverflowNeg(op) => {
+ write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
+ }
+ DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
+ RemainderByZero(op) => write!(
+ f,
+ "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
+ ),
+ Overflow(BinOp::Add, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
+ ),
+ Overflow(BinOp::Sub, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
+ ),
+ Overflow(BinOp::Mul, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
+ ),
+ Overflow(BinOp::Div, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
+ ),
+ Overflow(BinOp::Rem, l, r) => write!(
+ f,
+ "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
+ ),
+ Overflow(BinOp::Shr, _, r) => {
+ write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {r:?}")
+ }
+ Overflow(BinOp::Shl, _, r) => {
+ write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
+ }
+ MisalignedPointerDereference { required, found } => {
+ write!(
+ f,
+ "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
+ )
+ }
+ _ => write!(f, "\"{}\"", self.description()),
+ }
+ }
+
+ /// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval).
+ ///
+ /// Needs to be kept in sync with the run-time behavior (which is defined by
+ /// `AssertKind::description` and the lang items mentioned in its docs).
+ /// Note that we deliberately show more details here than we do at runtime, such as the actual
+ /// numbers that overflowed -- it is much easier to do so here than at runtime.
+ pub fn diagnostic_message(&self) -> DiagnosticMessage {
+ use crate::fluent_generated::*;
+ use AssertKind::*;
+
+ match self {
+ BoundsCheck { .. } => middle_bounds_check,
+ Overflow(BinOp::Shl, _, _) => middle_assert_shl_overflow,
+ Overflow(BinOp::Shr, _, _) => middle_assert_shr_overflow,
+ Overflow(_, _, _) => middle_assert_op_overflow,
+ OverflowNeg(_) => middle_assert_overflow_neg,
+ DivisionByZero(_) => middle_assert_divide_by_zero,
+ RemainderByZero(_) => middle_assert_remainder_by_zero,
+ ResumedAfterReturn(GeneratorKind::Async(_)) => middle_assert_async_resume_after_return,
+ ResumedAfterReturn(GeneratorKind::Gen) => middle_assert_generator_resume_after_return,
+ ResumedAfterPanic(GeneratorKind::Async(_)) => middle_assert_async_resume_after_panic,
+ ResumedAfterPanic(GeneratorKind::Gen) => middle_assert_generator_resume_after_panic,
+
+ MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref,
+ }
+ }
+
+ pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>))
+ where
+ O: fmt::Debug,
+ {
+ use AssertKind::*;
+
+ macro_rules! add {
+ ($name: expr, $value: expr) => {
+ adder($name.into(), $value.into_diagnostic_arg());
+ };
+ }
+
+ match self {
+ BoundsCheck { len, index } => {
+ add!("len", format!("{len:?}"));
+ add!("index", format!("{index:?}"));
+ }
+ Overflow(BinOp::Shl | BinOp::Shr, _, val)
+ | DivisionByZero(val)
+ | RemainderByZero(val)
+ | OverflowNeg(val) => {
+ add!("val", format!("{val:#?}"));
+ }
+ Overflow(binop, left, right) => {
+ add!("op", binop.to_hir_binop().as_str());
+ add!("left", format!("{left:#?}"));
+ add!("right", format!("{right:#?}"));
+ }
+ ResumedAfterReturn(_) | ResumedAfterPanic(_) => {}
+ MisalignedPointerDereference { required, found } => {
+ add!("required", format!("{required:#?}"));
+ add!("found", format!("{found:#?}"));
+ }
+ }
+ }
+}
+
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct Terminator<'tcx> {
pub source_info: SourceInfo,
@@ -155,8 +329,8 @@ impl<'tcx> TerminatorKind<'tcx> {
| InlineAsm { destination: Some(t), unwind: _, .. } => {
Some(t).into_iter().chain((&[]).into_iter().copied())
}
- Resume
- | Terminate
+ UnwindResume
+ | UnwindTerminate(_)
| GeneratorDrop
| Return
| Unreachable
@@ -197,8 +371,8 @@ impl<'tcx> TerminatorKind<'tcx> {
| InlineAsm { destination: Some(ref mut t), unwind: _, .. } => {
Some(t).into_iter().chain(&mut [])
}
- Resume
- | Terminate
+ UnwindResume
+ | UnwindTerminate(_)
| GeneratorDrop
| Return
| Unreachable
@@ -214,8 +388,8 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn unwind(&self) -> Option<&UnwindAction> {
match *self {
TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindResume
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::GeneratorDrop
@@ -233,8 +407,8 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
match *self {
TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindResume
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::GeneratorDrop
@@ -264,174 +438,6 @@ impl<'tcx> TerminatorKind<'tcx> {
}
}
-impl<'tcx> Debug for TerminatorKind<'tcx> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- self.fmt_head(fmt)?;
- let successor_count = self.successors().count();
- let labels = self.fmt_successor_labels();
- assert_eq!(successor_count, labels.len());
-
- let unwind = match self.unwind() {
- // Not needed or included in successors
- None | Some(UnwindAction::Cleanup(_)) => None,
- Some(UnwindAction::Continue) => Some("unwind continue"),
- Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
- Some(UnwindAction::Terminate) => Some("unwind terminate"),
- };
-
- match (successor_count, unwind) {
- (0, None) => Ok(()),
- (0, Some(unwind)) => write!(fmt, " -> {unwind}"),
- (1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
- _ => {
- write!(fmt, " -> [")?;
- for (i, target) in self.successors().enumerate() {
- if i > 0 {
- write!(fmt, ", ")?;
- }
- write!(fmt, "{}: {:?}", labels[i], target)?;
- }
- if let Some(unwind) = unwind {
- write!(fmt, ", {unwind}")?;
- }
- write!(fmt, "]")
- }
- }
- }
-}
-
-impl<'tcx> TerminatorKind<'tcx> {
- /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
- /// successor basic block, if any. The only information not included is the list of possible
- /// successors, which may be rendered differently between the text and the graphviz format.
- pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
- use self::TerminatorKind::*;
- match self {
- Goto { .. } => write!(fmt, "goto"),
- SwitchInt { discr, .. } => write!(fmt, "switchInt({discr:?})"),
- Return => write!(fmt, "return"),
- GeneratorDrop => write!(fmt, "generator_drop"),
- Resume => write!(fmt, "resume"),
- Terminate => write!(fmt, "abort"),
- Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
- Unreachable => write!(fmt, "unreachable"),
- Drop { place, .. } => write!(fmt, "drop({place:?})"),
- Call { func, args, destination, .. } => {
- write!(fmt, "{destination:?} = ")?;
- write!(fmt, "{func:?}(")?;
- for (index, arg) in args.iter().enumerate() {
- if index > 0 {
- write!(fmt, ", ")?;
- }
- write!(fmt, "{arg:?}")?;
- }
- write!(fmt, ")")
- }
- Assert { cond, expected, msg, .. } => {
- write!(fmt, "assert(")?;
- if !expected {
- write!(fmt, "!")?;
- }
- write!(fmt, "{cond:?}, ")?;
- msg.fmt_assert_args(fmt)?;
- write!(fmt, ")")
- }
- FalseEdge { .. } => write!(fmt, "falseEdge"),
- FalseUnwind { .. } => write!(fmt, "falseUnwind"),
- InlineAsm { template, ref operands, options, .. } => {
- write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
- for op in operands {
- write!(fmt, ", ")?;
- let print_late = |&late| if late { "late" } else { "" };
- match op {
- InlineAsmOperand::In { reg, value } => {
- write!(fmt, "in({reg}) {value:?}")?;
- }
- InlineAsmOperand::Out { reg, late, place: Some(place) } => {
- write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
- }
- InlineAsmOperand::Out { reg, late, place: None } => {
- write!(fmt, "{}out({}) _", print_late(late), reg)?;
- }
- InlineAsmOperand::InOut {
- reg,
- late,
- in_value,
- out_place: Some(out_place),
- } => {
- write!(
- fmt,
- "in{}out({}) {:?} => {:?}",
- print_late(late),
- reg,
- in_value,
- out_place
- )?;
- }
- InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
- write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
- }
- InlineAsmOperand::Const { value } => {
- write!(fmt, "const {value:?}")?;
- }
- InlineAsmOperand::SymFn { value } => {
- write!(fmt, "sym_fn {value:?}")?;
- }
- InlineAsmOperand::SymStatic { def_id } => {
- write!(fmt, "sym_static {def_id:?}")?;
- }
- }
- }
- write!(fmt, ", options({options:?}))")
- }
- }
- }
-
- /// Returns the list of labels for the edges to the successor basic blocks.
- pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
- use self::TerminatorKind::*;
- match *self {
- Return | Resume | Terminate | Unreachable | GeneratorDrop => vec![],
- Goto { .. } => vec!["".into()],
- SwitchInt { ref targets, .. } => targets
- .values
- .iter()
- .map(|&u| Cow::Owned(u.to_string()))
- .chain(iter::once("otherwise".into()))
- .collect(),
- Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
- vec!["return".into(), "unwind".into()]
- }
- Call { target: Some(_), unwind: _, .. } => vec!["return".into()],
- Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
- Call { target: None, unwind: _, .. } => vec![],
- Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
- Yield { drop: None, .. } => vec!["resume".into()],
- Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
- Drop { unwind: _, .. } => vec!["return".into()],
- Assert { unwind: UnwindAction::Cleanup(_), .. } => {
- vec!["success".into(), "unwind".into()]
- }
- Assert { unwind: _, .. } => vec!["success".into()],
- FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
- FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => {
- vec!["real".into(), "unwind".into()]
- }
- FalseUnwind { unwind: _, .. } => vec!["real".into()],
- InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
- vec!["return".into(), "unwind".into()]
- }
- InlineAsm { destination: Some(_), unwind: _, .. } => {
- vec!["return".into()]
- }
- InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
- vec!["unwind".into()]
- }
- InlineAsm { destination: None, unwind: _, .. } => vec![],
- }
- }
-}
-
#[derive(Copy, Clone, Debug)]
pub enum TerminatorEdges<'mir, 'tcx> {
/// For terminators that have no successor, like `return`.
@@ -443,7 +449,8 @@ pub enum TerminatorEdges<'mir, 'tcx> {
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
AssignOnReturn {
return_: Option<BasicBlock>,
- unwind: UnwindAction,
+ /// The cleanup block, if it exists.
+ cleanup: Option<BasicBlock>,
place: CallReturnPlaces<'mir, 'tcx>,
},
/// Special edge for `SwitchInt`.
@@ -486,7 +493,9 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
use TerminatorKind::*;
match *self {
- Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges::None,
+ Return | UnwindResume | UnwindTerminate(_) | GeneratorDrop | Unreachable => {
+ TerminatorEdges::None
+ }
Goto { target } => TerminatorEdges::Single(target),
@@ -494,7 +503,7 @@ impl<'tcx> TerminatorKind<'tcx> {
| Drop { target, unwind, place: _, replace: _ }
| FalseUnwind { real_target: target, unwind } => match unwind {
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
- UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => {
+ UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
TerminatorEdges::Single(target)
}
},
@@ -506,7 +515,7 @@ impl<'tcx> TerminatorKind<'tcx> {
Yield { resume: target, drop, resume_arg, value: _ } => {
TerminatorEdges::AssignOnReturn {
return_: Some(target),
- unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup),
+ cleanup: drop,
place: CallReturnPlaces::Yield(resume_arg),
}
}
@@ -514,7 +523,7 @@ impl<'tcx> TerminatorKind<'tcx> {
Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
TerminatorEdges::AssignOnReturn {
return_: target,
- unwind,
+ cleanup: unwind.cleanup_block(),
place: CallReturnPlaces::Call(destination),
}
}
@@ -528,7 +537,7 @@ impl<'tcx> TerminatorKind<'tcx> {
unwind,
} => TerminatorEdges::AssignOnReturn {
return_: destination,
- unwind,
+ cleanup: unwind.cleanup_block(),
place: CallReturnPlaces::InlineAsm(operands),
},
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index ec16a8470..a1ff8410e 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -41,6 +41,12 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> {
}
}
+/// Preorder traversal of a graph.
+///
+/// This function creates an iterator over the `Body`'s basic blocks, that
+/// returns basic blocks in a preorder.
+///
+/// See [`Preorder`]'s docs to learn what is preorder traversal.
pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
Preorder::new(body, START_BLOCK)
}
@@ -178,7 +184,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
// When we yield `C` and call `traverse_successor`, we push `B` to the stack, but
// since we've already visited `E`, that child isn't added to the stack. The last
// two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
- while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() {
+ while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) {
if self.visited.insert(bb) {
if let Some(term) = &self.basic_blocks[bb].terminator {
self.visit_stack.push((bb, term.successors()));
@@ -188,16 +194,14 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
}
}
-impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
- type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
+impl<'tcx> Iterator for Postorder<'_, 'tcx> {
+ type Item = BasicBlock;
- fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
- let next = self.visit_stack.pop();
- if next.is_some() {
- self.traverse_successor();
- }
+ fn next(&mut self) -> Option<BasicBlock> {
+ let (bb, _) = self.visit_stack.pop()?;
+ self.traverse_successor();
- next.map(|(bb, _)| (bb, &self.basic_blocks[bb]))
+ Some(bb)
}
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -215,10 +219,14 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
}
}
-/// Creates an iterator over the `Body`'s basic blocks, that:
+/// Postorder traversal of a graph.
+///
+/// This function creates an iterator over the `Body`'s basic blocks, that:
/// - returns basic blocks in a postorder,
/// - traverses the `BasicBlocks` CFG cache's reverse postorder backwards, and does not cache the
/// postorder itself.
+///
+/// See [`Postorder`]'s docs to learn what is postorder traversal.
pub fn postorder<'a, 'tcx>(
body: &'a Body<'tcx>,
) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator
@@ -226,7 +234,28 @@ pub fn postorder<'a, 'tcx>(
reverse_postorder(body).rev()
}
-/// Reverse postorder traversal of a graph
+/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular
+/// order.
+///
+/// This is clearer than writing `preorder` in cases where the order doesn't matter.
+pub fn reachable<'a, 'tcx>(
+ body: &'a Body<'tcx>,
+) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
+ preorder(body)
+}
+
+/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
+pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> {
+ let mut iter = preorder(body);
+ iter.by_ref().for_each(drop);
+ iter.visited
+}
+
+/// Reverse postorder traversal of a graph.
+///
+/// This function creates an iterator over the `Body`'s basic blocks, that:
+/// - returns basic blocks in a reverse postorder,
+/// - makes use of the `BasicBlocks` CFG cache's reverse postorder.
///
/// Reverse postorder is the reverse order of a postorder traversal.
/// This is different to a preorder traversal and represents a natural
@@ -246,65 +275,6 @@ pub fn postorder<'a, 'tcx>(
/// A reverse postorder traversal of this graph is either `A B C D` or `A C B D`
/// Note that for a graph containing no loops (i.e., A DAG), this is equivalent to
/// a topological sort.
-///
-/// Construction of a `ReversePostorder` traversal requires doing a full
-/// postorder traversal of the graph, therefore this traversal should be
-/// constructed as few times as possible. Use the `reset` method to be able
-/// to re-use the traversal
-#[derive(Clone)]
-pub struct ReversePostorder<'a, 'tcx> {
- body: &'a Body<'tcx>,
- blocks: Vec<BasicBlock>,
- idx: usize,
-}
-
-impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
- pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
- let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect();
- let len = blocks.len();
- ReversePostorder { body, blocks, idx: len }
- }
-}
-
-impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
- type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
-
- fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
- if self.idx == 0 {
- return None;
- }
- self.idx -= 1;
-
- self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb]))
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.idx, Some(self.idx))
- }
-}
-
-impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
-
-/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular
-/// order.
-///
-/// This is clearer than writing `preorder` in cases where the order doesn't matter.
-pub fn reachable<'a, 'tcx>(
- body: &'a Body<'tcx>,
-) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
- preorder(body)
-}
-
-/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
-pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> {
- let mut iter = preorder(body);
- (&mut iter).for_each(drop);
- iter.visited
-}
-
-/// Creates an iterator over the `Body`'s basic blocks, that:
-/// - returns basic blocks in a reverse postorder,
-/// - makes use of the `BasicBlocks` CFG cache's reverse postorder.
pub fn reverse_postorder<'a, 'tcx>(
body: &'a Body<'tcx>,
) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 06874741b..8d427fdb6 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece;
use super::*;
use crate::ty;
-TrivialTypeTraversalAndLiftImpls! {
+TrivialTypeTraversalImpls! {
BlockTailInfo,
MirPhase,
SourceInfo,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 069b38591..f2745b32c 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -186,7 +186,7 @@ macro_rules! make_mir_visitor {
fn visit_constant(
&mut self,
- constant: & $($mutability)? Constant<'tcx>,
+ constant: & $($mutability)? ConstOperand<'tcx>,
location: Location,
) {
self.super_constant(constant, location);
@@ -469,8 +469,8 @@ macro_rules! make_mir_visitor {
self.visit_source_info(source_info);
match kind {
TerminatorKind::Goto { .. } |
- TerminatorKind::Resume |
- TerminatorKind::Terminate |
+ TerminatorKind::UnwindResume |
+ TerminatorKind::UnwindTerminate(_) |
TerminatorKind::GeneratorDrop |
TerminatorKind::Unreachable |
TerminatorKind::FalseEdge { .. } |
@@ -647,8 +647,8 @@ macro_rules! make_mir_visitor {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
),
- BorrowKind::Shallow => PlaceContext::NonMutatingUse(
- NonMutatingUseContext::ShallowBorrow
+ BorrowKind::Fake => PlaceContext::NonMutatingUse(
+ NonMutatingUseContext::FakeBorrow
),
BorrowKind::Mut { .. } =>
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
@@ -838,12 +838,20 @@ macro_rules! make_mir_visitor {
let VarDebugInfo {
name: _,
source_info,
+ composite,
value,
argument_index: _,
} = var_debug_info;
self.visit_source_info(source_info);
let location = Location::START;
+ if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+ for elem in projection {
+ let ProjectionElem::Field(_, ty) = elem else { bug!() };
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+ }
+ }
match value {
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
VarDebugInfoContents::Place(place) =>
@@ -852,17 +860,6 @@ macro_rules! make_mir_visitor {
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
location
),
- VarDebugInfoContents::Composite { ty, fragments } => {
- // FIXME(eddyb) use a better `TyContext` here.
- self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
- for VarDebugInfoFragment { projection: _, contents } in fragments {
- self.visit_place(
- contents,
- PlaceContext::NonUse(NonUseContext::VarDebugInfo),
- location,
- );
- }
- }
}
}
@@ -873,20 +870,20 @@ macro_rules! make_mir_visitor {
fn super_constant(
&mut self,
- constant: & $($mutability)? Constant<'tcx>,
+ constant: & $($mutability)? ConstOperand<'tcx>,
location: Location
) {
- let Constant {
+ let ConstOperand {
span,
user_ty: _, // no visit method for this
- literal,
+ const_,
} = constant;
self.visit_span($(& $mutability)? *span);
- match literal {
- ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
- ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
- ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
+ 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)),
}
}
@@ -1112,6 +1109,11 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
}
+ PlaceElem::Subtype(ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
+ }
PlaceElem::Deref
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
@@ -1178,7 +1180,9 @@ macro_rules! visit_place_fns {
location: Location,
) {
match elem {
- ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
+ ProjectionElem::OpaqueCast(ty)
+ | ProjectionElem::Subtype(ty)
+ | ProjectionElem::Field(_, ty) => {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(local) => {
@@ -1256,8 +1260,8 @@ pub enum NonMutatingUseContext {
Move,
/// Shared borrow.
SharedBorrow,
- /// Shallow borrow.
- ShallowBorrow,
+ /// A fake borrow.
+ FakeBorrow,
/// AddressOf for *const pointer.
AddressOf,
/// PlaceMention statement.
@@ -1336,7 +1340,7 @@ impl PlaceContext {
matches!(
self,
PlaceContext::NonMutatingUse(
- NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
+ NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
)
}
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 348f79ed6..8ba3764bc 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -1,4 +1,5 @@
use crate::mir;
+use crate::query::CyclePlaceholder;
use crate::traits;
use crate::ty::{self, Ty};
use std::mem::{size_of, transmute_copy, MaybeUninit};
@@ -115,21 +116,16 @@ impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
}
-impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> {
- type Result =
- [u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()];
+impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
+ type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
}
-impl EraseType for Result<mir::interpret::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
- type Result = [u8; size_of::<
- Result<mir::interpret::ConstAlloc<'static>, mir::interpret::ErrorHandled>,
- >()];
+impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
+ type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
}
-impl EraseType for Result<mir::interpret::ConstValue<'_>, mir::interpret::ErrorHandled> {
- type Result = [u8; size_of::<
- Result<mir::interpret::ConstValue<'static>, mir::interpret::ErrorHandled>,
- >()];
+impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
+ type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
}
impl EraseType for Result<Option<ty::ValTree<'_>>, mir::interpret::ErrorHandled> {
@@ -142,6 +138,10 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
}
+impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+ type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
+}
+
impl<T> EraseType for Option<&'_ T> {
type Result = [u8; size_of::<Option<&'static ()>>()];
}
@@ -265,6 +265,7 @@ trivial! {
rustc_middle::ty::adjustment::CoerceUnsizedInfo,
rustc_middle::ty::AssocItem,
rustc_middle::ty::AssocItemContainer,
+ rustc_middle::ty::Asyncness,
rustc_middle::ty::BoundVariableKind,
rustc_middle::ty::DeducedParamAttrs,
rustc_middle::ty::Destructor,
@@ -310,10 +311,10 @@ macro_rules! tcx_lifetime {
tcx_lifetime! {
rustc_middle::hir::Owner,
rustc_middle::middle::exported_symbols::ExportedSymbol,
- rustc_middle::mir::ConstantKind,
+ rustc_middle::mir::Const,
rustc_middle::mir::DestructuredConstant,
- rustc_middle::mir::interpret::ConstAlloc,
- rustc_middle::mir::interpret::ConstValue,
+ rustc_middle::mir::ConstAlloc,
+ rustc_middle::mir::ConstValue,
rustc_middle::mir::interpret::GlobalId,
rustc_middle::mir::interpret::LitToConstInput,
rustc_middle::traits::query::MethodAutoderefStepsResult,
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 01bdc4c99..b1f837968 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -2,7 +2,6 @@
use crate::infer::canonical::Canonical;
use crate::mir;
-use crate::mir::interpret::ConstValue;
use crate::traits;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
@@ -369,7 +368,7 @@ impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) {
}
}
-impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) {
+impl<'tcx> Key for (mir::ConstValue<'tcx>, Ty<'tcx>) {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, _: TyCtxt<'_>) -> Span {
@@ -377,7 +376,7 @@ impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) {
}
}
-impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
+impl<'tcx> Key for mir::ConstAlloc<'tcx> {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, _: TyCtxt<'_>) -> Span {
@@ -417,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> {
}
}
-impl<'tcx> Key for mir::ConstantKind<'tcx> {
+impl<'tcx> Key for mir::Const<'tcx> {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, _: TyCtxt<'_>) -> Span {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 94ae0dcb5..340c5a769 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -7,7 +7,6 @@
#![allow(unused_parens)]
use crate::dep_graph;
-use crate::dep_graph::DepKind;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintExpectation;
use crate::metadata::ModChild;
@@ -21,12 +20,12 @@ use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::{
- ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+ EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
};
use crate::mir::interpret::{LitToConstError, LitToConstInput};
use crate::mir::mono::CodegenUnit;
use crate::query::erase::{erase, restore, Erase};
-use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
+use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery};
use crate::thir;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@@ -45,7 +44,6 @@ use crate::traits::{
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::ValidityRequirement;
use crate::ty::util::AlwaysRequiresDrop;
-use crate::ty::GeneratorDiagnosticData;
use crate::ty::TyCtxtFeed;
use crate::ty::{
self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt,
@@ -231,7 +229,7 @@ rustc_queries! {
action = {
use rustc_hir::def::DefKind;
match tcx.def_kind(key) {
- DefKind::TyAlias { .. } => "expanding type alias",
+ DefKind::TyAlias => "expanding type alias",
DefKind::TraitAlias => "expanding trait alias",
_ => "computing type of",
}
@@ -243,6 +241,24 @@ rustc_queries! {
feedable
}
+ /// Specialized instance of `type_of` that detects cycles that are due to
+ /// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
+ /// to be handled separately, call `type_of` instead.
+ query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
+ desc { |tcx|
+ "computing type of opaque `{path}`",
+ path = tcx.def_path_str(key),
+ }
+ }
+
+ query type_alias_is_lazy(key: DefId) -> bool {
+ desc { |tcx|
+ "computing whether `{path}` is a lazy type alias",
+ path = tcx.def_path_str(key),
+ }
+ separate_provide_extern
+ }
+
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{
@@ -721,7 +737,7 @@ rustc_queries! {
separate_provide_extern
}
- query asyncness(key: DefId) -> hir::IsAsync {
+ query asyncness(key: DefId) -> ty::Asyncness {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
separate_provide_extern
}
@@ -1081,7 +1097,7 @@ rustc_queries! {
}
/// Converts a type level constant value into `ConstValue`
- query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
+ query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> mir::ConstValue<'tcx> {
desc { "converting type-level constant value to mir constant value"}
}
@@ -1091,17 +1107,7 @@ rustc_queries! {
desc { "destructuring type level constant"}
}
- /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
- /// and its field values. This should only be used for pretty printing.
- query try_destructure_mir_constant_for_diagnostics(
- key: (ConstValue<'tcx>, Ty<'tcx>)
- ) -> Option<mir::DestructuredConstant<'tcx>> {
- desc { "destructuring MIR constant"}
- no_hash
- eval_always
- }
-
- query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
+ query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> mir::ConstValue<'tcx> {
desc { "getting a &core::panic::Location referring to a span" }
}
@@ -1130,6 +1136,7 @@ rustc_queries! {
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
arena_cache
desc { "reachability" }
+ cache_on_disk_if { true }
}
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
@@ -2149,12 +2156,6 @@ rustc_queries! {
desc { "computing the backend features for CLI flags" }
}
- query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> {
- arena_cache
- desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
- separate_provide_extern
- }
-
query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
}
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 995b2140f..280f5d0a8 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -22,7 +22,7 @@ use rustc_span::hygiene::{
ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
};
use rustc_span::source_map::{SourceMap, StableSourceFileId};
-use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
+use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span};
use rustc_span::{CachingSourceMapView, Symbol};
use std::collections::hash_map::Entry;
use std::io;
@@ -688,11 +688,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
let file_lo_index = SourceFileIndex::decode(decoder);
let line_lo = usize::decode(decoder);
- let col_lo = BytePos::decode(decoder);
+ let col_lo = RelativeBytePos::decode(decoder);
let len = BytePos::decode(decoder);
let file_lo = decoder.file_index_to_file(file_lo_index);
- let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
+ let lo = file_lo.lines()[line_lo - 1] + col_lo;
+ let lo = file_lo.absolute_position(lo);
let hi = lo + len;
Span::new(lo, hi, ctxt, parent)
@@ -895,7 +896,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
}
if let Some(parent) = span_data.parent {
- let enclosing = s.tcx.source_span(parent).data_untracked();
+ let enclosing = s.tcx.source_span_untracked(parent).data_untracked();
if enclosing.contains(span_data) {
TAG_RELATIVE_SPAN.encode(s);
(span_data.lo - enclosing.lo).to_u32().encode(s);
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index a1aac2846..34e5b02ba 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -19,7 +19,7 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex;
pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*;
use rustc_query_system::HandleCycleError;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
use std::ops::Deref;
pub struct QueryKeyStringCache {
@@ -37,7 +37,7 @@ 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, DepKind>>,
+ pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>,
pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
@@ -52,7 +52,8 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
pub loadable_from_disk:
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
pub hash_result: HashResult<C::Value>,
- pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value,
+ pub value_from_cycle_error:
+ fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value,
pub format_value: fn(&C::Value) -> String,
}
@@ -401,7 +402,7 @@ macro_rules! define_callbacks {
#[derive(Default)]
pub struct QueryStates<'tcx> {
$(
- pub $name: QueryState<$($K)*, DepKind>,
+ pub $name: QueryState<$($K)*>,
)*
}
@@ -515,7 +516,7 @@ macro_rules! define_feedable {
}
}
None => {
- let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
+ let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key);
let dep_node_index = tcx.dep_graph.with_feed_task(
dep_node,
tcx,
@@ -629,3 +630,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
}
}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct CyclePlaceholder(pub ErrorGuaranteed);
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index ebc1c1190..89934e435 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> {
out_expr: Option<ExprId>,
},
Const {
- value: mir::ConstantKind<'tcx>,
+ value: mir::Const<'tcx>,
span: Span,
},
SymFn {
- value: mir::ConstantKind<'tcx>,
+ value: mir::Const<'tcx>,
span: Span,
},
SymStatic {
@@ -732,14 +732,18 @@ pub enum PatKind<'tcx> {
},
/// One of the following:
- /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
- /// checking will detect if you use the same string twice in different patterns.
- /// * integer, bool, char or float, which will be handled by exhaustiveness to cover exactly
- /// its own value, similar to `&str`, but these values are much simpler.
- /// * Opaque constants, that must not be matched structurally. So anything that does not derive
- /// `PartialEq` and `Eq`.
+ /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
+ /// exhaustiveness checking will detect if you use the same string twice in different
+ /// patterns.
+ /// * integer, bool, char or float (represented as a valtree), which will be handled by
+ /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
+ /// much simpler.
+ /// * Opaque constants (represented as `mir::ConstValue`), that must not be matched
+ /// structurally. So anything that does not derive `PartialEq` and `Eq`.
+ ///
+ /// These are always compared with the matched place using (the semantics of) `PartialEq`.
Constant {
- value: mir::ConstantKind<'tcx>,
+ value: mir::Const<'tcx>,
},
Range(Box<PatRange<'tcx>>),
@@ -769,8 +773,8 @@ pub enum PatKind<'tcx> {
#[derive(Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
- pub lo: mir::ConstantKind<'tcx>,
- pub hi: mir::ConstantKind<'tcx>,
+ pub lo: mir::Const<'tcx>,
+ pub hi: mir::Const<'tcx>,
pub end: RangeEnd,
}
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 681400dbb..b84e15688 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
walk_pat(self, pat);
}
- // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
+ // Note: We don't have visitors for `ty::Const` and `mir::Const`
// (even though these types occur in THIR) for consistency and to reduce confusion,
// since the lazy creation of constants during thir construction causes most
- // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
+ // 'constants' to not be of type `ty::Const` or `mir::Const` at that
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
- // You have to manually visit `ty::Const` and `mir::ConstantKind` through the
+ // You have to manually visit `ty::Const` and `mir::Const` through the
// other `visit*` functions.
}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 3465759b9..99b750c9a 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical;
use crate::mir::ConstraintCategory;
use crate::ty::abstract_const::NotConstEvaluatable;
use crate::ty::GenericArgsRef;
-use crate::ty::{self, AdtKind, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, Ty};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
@@ -86,7 +86,7 @@ pub enum Reveal {
///
/// We do not want to intern this as there are a lot of obligation causes which
/// only live for a short period of time.
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ObligationCause<'tcx> {
pub span: Span,
@@ -194,7 +194,7 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct UnifyReceiverContext<'tcx> {
pub assoc_item: ty::AssocItem,
@@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> {
pub args: GenericArgsRef<'tcx>,
}
-#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
+#[derive(Clone, PartialEq, Eq, Default, HashStable)]
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
pub struct InternedObligationCauseCode<'tcx> {
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
@@ -238,7 +238,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
@@ -299,6 +299,10 @@ pub enum ObligationCauseCode<'tcx> {
SizedYieldType,
/// Inline asm operand type must be `Sized`.
InlineAsmSized,
+ /// Captured closure type must be `Sized`.
+ SizedClosureCapture(LocalDefId),
+ /// Types live across generator yields must be `Sized`.
+ SizedGeneratorInterior(LocalDefId),
/// `[expr; N]` requires `type_of(expr): Copy`.
RepeatElementCopy {
/// If element is a `const fn` we display a help message suggesting to move the
@@ -378,6 +382,9 @@ pub enum ObligationCauseCode<'tcx> {
/// `start` has wrong type
StartFunctionType,
+ /// language function has wrong type
+ LangFunctionType(Symbol),
+
/// Intrinsic has wrong type
IntrinsicType,
@@ -470,7 +477,7 @@ pub enum WellFormedLoc {
},
}
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedObligationCause<'tcx> {
pub derived: DerivedObligationCause<'tcx>,
@@ -524,14 +531,7 @@ pub enum StatementAsExpression {
NeedsBoxing,
}
-impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
- type Lifted = StatementAsExpression;
- fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
- Some(self)
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_block_id: Option<hir::HirId>,
@@ -547,7 +547,7 @@ pub struct MatchExpressionArmCause<'tcx> {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
pub struct IfExpressionCause<'tcx> {
pub then_id: hir::HirId,
pub else_id: hir::HirId,
@@ -557,7 +557,7 @@ pub struct IfExpressionCause<'tcx> {
pub opt_suggest_box_span: Option<Span>,
}
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct DerivedObligationCause<'tcx> {
/// The trait predicate of the parent obligation that led to the
@@ -570,7 +570,7 @@ pub struct DerivedObligationCause<'tcx> {
pub parent_code: InternedObligationCauseCode<'tcx>,
}
-#[derive(Clone, Debug, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TypeVisitable)]
pub enum SelectionError<'tcx> {
/// The trait is not implemented.
Unimplemented,
@@ -593,7 +593,7 @@ pub enum SelectionError<'tcx> {
OpaqueTypeAutoTraitLeakageUnknown(DefId),
}
-#[derive(Clone, Debug, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TypeVisitable)]
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
pub found_trait_ref: ty::PolyTraitRef<'tcx>,
pub expected_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -638,7 +638,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
/// ### The type parameter `N`
///
/// See explanation on `ImplSourceUserDefinedData`.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum ImplSource<'tcx, N> {
/// ImplSource identifying a particular impl.
@@ -704,7 +704,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
/// is `Obligation`, as one might expect. During codegen, however, this
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceUserDefinedData<'tcx, N> {
pub impl_def_id: DefId,
@@ -736,7 +736,7 @@ pub enum BuiltinImplSource {
TupleUnsizing,
}
-TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
+TrivialTypeTraversalImpls! { BuiltinImplSource }
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum ObjectSafetyViolation {
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 950a59e96..975e3e3ac 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -17,8 +17,7 @@ pub mod type_op {
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
use std::fmt;
- #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
- #[derive(TypeFoldable, TypeVisitable)]
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub user_ty: UserType<'tcx>,
@@ -30,22 +29,19 @@ pub mod type_op {
}
}
- #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
- #[derive(TypeFoldable, TypeVisitable)]
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Eq<'tcx> {
pub a: Ty<'tcx>,
pub b: Ty<'tcx>,
}
- #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
- #[derive(TypeFoldable, TypeVisitable)]
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Subtype<'tcx> {
pub sub: Ty<'tcx>,
pub sup: Ty<'tcx>,
}
- #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
- #[derive(TypeFoldable, TypeVisitable)]
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct ProvePredicate<'tcx> {
pub predicate: Predicate<'tcx>,
}
@@ -56,8 +52,7 @@ pub mod type_op {
}
}
- #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
- #[derive(TypeFoldable, TypeVisitable)]
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Normalize<T> {
pub value: T,
}
@@ -101,7 +96,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
}
}
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)]
pub struct DropckOutlivesResult<'tcx> {
pub kinds: Vec<GenericArg<'tcx>>,
pub overflows: Vec<Ty<'tcx>>,
@@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
}
/// Result from the `normalize_projection_ty` query.
-#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
pub normalized_ty: Ty<'tcx>,
@@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> {
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ffae35798..90bc5dd8f 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -305,7 +305,7 @@ impl From<ErrorGuaranteed> for OverflowError {
}
}
-TrivialTypeTraversalAndLiftImpls! { OverflowError }
+TrivialTypeTraversalImpls! { OverflowError }
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 9d63d2918..27a1e64a7 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -9,6 +9,9 @@ use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
TypeVisitor,
};
+use rustc_span::def_id::DefId;
+
+use super::BuiltinImplSource;
mod cache;
pub mod inspect;
@@ -235,3 +238,63 @@ pub enum IsNormalizesToHack {
Yes,
No,
}
+
+/// Possible ways the given goal can be proven.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CandidateSource {
+ /// A user written impl.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust
+ /// fn main() {
+ /// let x: Vec<u32> = Vec::new();
+ /// // This uses the impl from the standard library to prove `Vec<T>: Clone`.
+ /// let y = x.clone();
+ /// }
+ /// ```
+ Impl(DefId),
+ /// A builtin impl generated by the compiler. When adding a new special
+ /// trait, try to use actual impls whenever possible. Builtin impls should
+ /// only be used in cases where the impl cannot be manually be written.
+ ///
+ /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
+ /// For a list of all traits with builtin impls, check out the
+ /// `EvalCtxt::assemble_builtin_impl_candidates` method.
+ BuiltinImpl(BuiltinImplSource),
+ /// An assumption from the environment.
+ ///
+ /// More precisely we've used the `n-th` assumption in the `param_env`.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust
+ /// fn is_clone<T: Clone>(x: T) -> (T, T) {
+ /// // This uses the assumption `T: Clone` from the `where`-bounds
+ /// // to prove `T: Clone`.
+ /// (x.clone(), x)
+ /// }
+ /// ```
+ ParamEnv(usize),
+ /// If the self type is an alias type, e.g. an opaque type or a projection,
+ /// we know the bounds on that alias to hold even without knowing its concrete
+ /// underlying type.
+ ///
+ /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
+ /// the self type.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust
+ /// trait Trait {
+ /// type Assoc: Clone;
+ /// }
+ ///
+ /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
+ /// // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
+ /// // in the trait definition.
+ /// let _y = x.clone();
+ /// }
+ /// ```
+ AliasBound,
+}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 4e2af3816..e7e40bee6 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -1,32 +1,83 @@
+//! Data structure used to inspect trait solver behavior.
+//!
+//! During trait solving we optionally build "proof trees", the root of
+//! which is a [GoalEvaluation] with [GoalEvaluationKind::Root]. These
+//! trees are used to improve the debug experience and are also used by
+//! the compiler itself to provide necessary context for error messages.
+//!
+//! Because each nested goal in the solver gets [canonicalized] separately
+//! and we discard inference progress via "probes", we cannot mechanically
+//! use proof trees without somehow "lifting up" data local to the current
+//! `InferCtxt`. Any data used mechanically is therefore canonicalized and
+//! stored as [CanonicalState]. As printing canonicalized data worsens the
+//! debugging dumps, we do not simply canonicalize everything.
+//!
+//! This means proof trees contain inference variables and placeholders
+//! local to a different `InferCtxt` which must not be used with the
+//! current one.
+//!
+//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
+
use super::{
- CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult,
+ CandidateSource, Canonical, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution,
+ QueryInput, QueryResult,
};
-use crate::ty;
+use crate::{infer::canonical::CanonicalVarValues, ty};
use format::ProofTreeFormatter;
use std::fmt::{Debug, Write};
mod format;
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
+/// Some `data` together with information about how they relate to the input
+/// of the canonical query.
+///
+/// This is only ever used as [CanonicalState]. Any type information in proof
+/// trees used mechanically has to be canonicalized as we otherwise leak
+/// inference variables from a nested `InferCtxt`.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, TypeFoldable, TypeVisitable)]
+pub struct State<'tcx, T> {
+ pub var_values: CanonicalVarValues<'tcx>,
+ pub data: T,
+}
+
+pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;
+
+#[derive(Debug, Eq, PartialEq)]
pub enum CacheHit {
Provisional,
Global,
}
-#[derive(Eq, PartialEq, Hash, HashStable)]
+/// When evaluating the root goals we also store the
+/// original values for the `CanonicalVarValues` of the
+/// canonicalized goal. We use this to map any [CanonicalState]
+/// from the local `InferCtxt` of the solver query to
+/// the `InferCtxt` of the caller.
+#[derive(Eq, PartialEq)]
+pub enum GoalEvaluationKind<'tcx> {
+ Root { orig_values: Vec<ty::GenericArg<'tcx>> },
+ Nested { is_normalizes_to_hack: IsNormalizesToHack },
+}
+
+#[derive(Eq, PartialEq)]
pub struct GoalEvaluation<'tcx> {
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
- pub canonicalized_goal: CanonicalInput<'tcx>,
-
pub kind: GoalEvaluationKind<'tcx>,
- pub is_normalizes_to_hack: IsNormalizesToHack,
+ pub evaluation: CanonicalGoalEvaluation<'tcx>,
+ /// The nested goals from instantiating the query response.
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+}
+#[derive(Eq, PartialEq)]
+pub struct CanonicalGoalEvaluation<'tcx> {
+ pub goal: CanonicalInput<'tcx>,
+ pub kind: CanonicalGoalEvaluationKind<'tcx>,
pub result: QueryResult<'tcx>,
}
-#[derive(Eq, PartialEq, Hash, HashStable)]
-pub enum GoalEvaluationKind<'tcx> {
+#[derive(Eq, PartialEq)]
+pub enum CanonicalGoalEvaluationKind<'tcx> {
+ Overflow,
CacheHit(CacheHit),
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
}
@@ -36,55 +87,69 @@ impl Debug for GoalEvaluation<'_> {
}
}
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
pub struct AddedGoalsEvaluation<'tcx> {
pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
pub result: Result<Certainty, NoSolution>,
}
-impl Debug for AddedGoalsEvaluation<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- ProofTreeFormatter::new(f).format_nested_goal_evaluation(self)
- }
-}
-#[derive(Eq, PartialEq, Hash, HashStable)]
+#[derive(Eq, PartialEq)]
pub struct GoalEvaluationStep<'tcx> {
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
- pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
- pub candidates: Vec<GoalCandidate<'tcx>>,
+ /// The actual evaluation of the goal, always `ProbeKind::Root`.
+ pub evaluation: Probe<'tcx>,
+}
- pub result: QueryResult<'tcx>,
+/// A self-contained computation during trait solving. This either
+/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
+/// of a goal.
+#[derive(Eq, PartialEq)]
+pub struct Probe<'tcx> {
+ /// What happened inside of this probe in chronological order.
+ pub steps: Vec<ProbeStep<'tcx>>,
+ pub kind: ProbeKind<'tcx>,
}
-impl Debug for GoalEvaluationStep<'_> {
+
+impl Debug for Probe<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- ProofTreeFormatter::new(f).format_evaluation_step(self)
+ ProofTreeFormatter::new(f).format_probe(self)
}
}
-#[derive(Eq, PartialEq, Hash, HashStable)]
-pub struct GoalCandidate<'tcx> {
- pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
- pub candidates: Vec<GoalCandidate<'tcx>>,
- pub kind: CandidateKind<'tcx>,
+#[derive(Eq, PartialEq)]
+pub enum ProbeStep<'tcx> {
+ /// We added a goal to the `EvalCtxt` which will get proven
+ /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
+ AddGoal(CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+ /// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
+ EvaluateGoals(AddedGoalsEvaluation<'tcx>),
+ /// A call to `probe` while proving the current goal. This is
+ /// used whenever there are multiple candidates to prove the
+ /// current goalby .
+ NestedProbe(Probe<'tcx>),
}
-#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
-pub enum CandidateKind<'tcx> {
+/// What kind of probe we're in. In case the probe represents a candidate, or
+/// the final result of the current goal - via [ProbeKind::Root] - we also
+/// store the [QueryResult].
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum ProbeKind<'tcx> {
+ /// The root inference context while proving a goal.
+ Root { result: QueryResult<'tcx> },
/// Probe entered when normalizing the self ty during candidate assembly
NormalizedSelfTyAssembly,
- /// A normal candidate for proving a goal
- Candidate { name: String, result: QueryResult<'tcx> },
+ /// Some candidate to prove the current goal.
+ ///
+ /// FIXME: Remove this in favor of always using more strongly typed variants.
+ MiscCandidate { name: &'static str, result: QueryResult<'tcx> },
+ /// A candidate for proving a trait or alias-relate goal.
+ TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly,
/// During upcasting from some source object to target object type, used to
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
- UpcastProbe,
-}
-impl Debug for GoalCandidate<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- ProofTreeFormatter::new(f).format_candidate(self)
- }
+ UpcastProjectionCompatibility,
}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 8759fecb0..5733be00a 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -39,44 +39,55 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
func(&mut ProofTreeFormatter { f: &mut Indentor { f: self.f, on_newline: true } })
}
- pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result {
- let goal_text = match goal.is_normalizes_to_hack {
- IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
- IsNormalizesToHack::No => "GOAL",
+ pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
+ let goal_text = match eval.kind {
+ GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL",
+ GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack {
+ IsNormalizesToHack::No => "GOAL",
+ IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
+ },
};
-
- writeln!(self.f, "{}: {:?}", goal_text, goal.uncanonicalized_goal)?;
- writeln!(self.f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;
-
- match &goal.kind {
- GoalEvaluationKind::CacheHit(CacheHit::Global) => {
- writeln!(self.f, "GLOBAL CACHE HIT: {:?}", goal.result)
- }
- GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
- writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", goal.result)
- }
- GoalEvaluationKind::Uncached { revisions } => {
- for (n, step) in revisions.iter().enumerate() {
- writeln!(self.f, "REVISION {n}: {:?}", step.result)?;
- self.nested(|this| this.format_evaluation_step(step))?;
- }
- writeln!(self.f, "RESULT: {:?}", goal.result)
- }
- }?;
-
- if goal.returned_goals.len() > 0 {
+ writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
+ self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
+ if eval.returned_goals.len() > 0 {
writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
self.nested(|this| {
- for goal in goal.returned_goals.iter() {
+ for goal in eval.returned_goals.iter() {
writeln!(this.f, "ADDED GOAL: {goal:?},")?;
}
Ok(())
})?;
- writeln!(self.f, "]")?;
+ writeln!(self.f, "]")
+ } else {
+ Ok(())
}
+ }
- Ok(())
+ pub(super) fn format_canonical_goal_evaluation(
+ &mut self,
+ eval: &CanonicalGoalEvaluation<'_>,
+ ) -> std::fmt::Result {
+ writeln!(self.f, "GOAL: {:?}", eval.goal)?;
+
+ match &eval.kind {
+ CanonicalGoalEvaluationKind::Overflow => {
+ writeln!(self.f, "OVERFLOW: {:?}", eval.result)
+ }
+ CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
+ writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
+ }
+ CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
+ writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
+ }
+ CanonicalGoalEvaluationKind::Uncached { revisions } => {
+ for (n, step) in revisions.iter().enumerate() {
+ writeln!(self.f, "REVISION {n}")?;
+ self.nested(|this| this.format_evaluation_step(step))?;
+ }
+ writeln!(self.f, "RESULT: {:?}", eval.result)
+ }
+ }
}
pub(super) fn format_evaluation_step(
@@ -84,54 +95,53 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
evaluation_step: &GoalEvaluationStep<'_>,
) -> std::fmt::Result {
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
-
- for candidate in &evaluation_step.candidates {
- self.nested(|this| this.format_candidate(candidate))?;
- }
- for nested in &evaluation_step.nested_goal_evaluations {
- self.nested(|this| this.format_nested_goal_evaluation(nested))?;
- }
-
- Ok(())
+ self.format_probe(&evaluation_step.evaluation)
}
- pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
- match &candidate.kind {
- CandidateKind::NormalizedSelfTyAssembly => {
+ pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
+ match &probe.kind {
+ ProbeKind::Root { result } => {
+ writeln!(self.f, "ROOT RESULT: {result:?}")
+ }
+ ProbeKind::NormalizedSelfTyAssembly => {
writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
}
- CandidateKind::UnsizeAssembly => {
+ ProbeKind::UnsizeAssembly => {
writeln!(self.f, "ASSEMBLING CANDIDATES FOR UNSIZING:")
}
- CandidateKind::UpcastProbe => {
+ ProbeKind::UpcastProjectionCompatibility => {
writeln!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
}
- CandidateKind::Candidate { name, result } => {
+ ProbeKind::MiscCandidate { name, result } => {
writeln!(self.f, "CANDIDATE {name}: {result:?}")
}
+ ProbeKind::TraitCandidate { source, result } => {
+ writeln!(self.f, "CANDIDATE {source:?}: {result:?}")
+ }
}?;
self.nested(|this| {
- for candidate in &candidate.candidates {
- this.format_candidate(candidate)?;
- }
- for nested in &candidate.nested_goal_evaluations {
- this.format_nested_goal_evaluation(nested)?;
+ for step in &probe.steps {
+ match step {
+ ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
+ ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
+ ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
+ }
}
Ok(())
})
}
- pub(super) fn format_nested_goal_evaluation(
+ pub(super) fn format_added_goals_evaluation(
&mut self,
- nested_goal_evaluation: &AddedGoalsEvaluation<'_>,
+ added_goals_evaluation: &AddedGoalsEvaluation<'_>,
) -> std::fmt::Result {
- writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?;
+ writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?;
- for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() {
- writeln!(self.f, "REVISION {n}")?;
+ for (n, iterations) in added_goals_evaluation.evaluations.iter().enumerate() {
+ writeln!(self.f, "ITERATION {n}")?;
self.nested(|this| {
- for goal_evaluation in revision {
+ for goal_evaluation in iterations {
this.format_goal_evaluation(goal_evaluation)?;
}
Ok(())
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index cdd835149..570f896ba 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -27,7 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
}
}
-TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
+TrivialTypeTraversalImpls! { NotConstEvaluatable }
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 76931ceaa..c3e8991c6 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -76,7 +76,7 @@ pub enum PointerCoercion {
/// At some point, of course, `Box` should move out of the compiler, in which
/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct Adjustment<'tcx> {
pub kind: Adjust<'tcx>,
pub target: Ty<'tcx>,
@@ -88,7 +88,7 @@ impl<'tcx> Adjustment<'tcx> {
}
}
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub enum Adjust<'tcx> {
/// Go from ! to any type.
NeverToAny,
@@ -110,7 +110,7 @@ pub enum Adjust<'tcx> {
/// The target type is `U` in both cases, with the region and mutability
/// being those shared by both the receiver and the returned reference.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
pub struct OverloadedDeref<'tcx> {
pub region: ty::Region<'tcx>,
pub mutbl: hir::Mutability,
@@ -182,7 +182,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
}
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
pub enum AutoBorrow<'tcx> {
/// Converts from T to &T.
Ref(ty::Region<'tcx>, AutoBorrowMutability),
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index b4c6e0d97..f50969dd9 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -448,7 +448,7 @@ impl<'tcx> AdtDef<'tcx> {
Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid),
Res::Def(DefKind::Struct, _)
| Res::Def(DefKind::Union, _)
- | Res::Def(DefKind::TyAlias { .. }, _)
+ | Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
| Res::SelfTyParam { .. }
| Res::SelfTyAlias { .. }
@@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
}
Err(err) => {
let msg = match err {
- ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
- ErrorHandled::TooGeneric => "enum discriminant depends on generics",
+ ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
+ ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
};
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
None
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index 2fec8ac90..af594bc5f 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -6,7 +6,7 @@ pub enum BindingMode {
BindByValue(Mutability),
}
-TrivialTypeTraversalAndLiftImpls! { BindingMode }
+TrivialTypeTraversalImpls! { BindingMode }
impl BindingMode {
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 7c05deae9..dff7ff8c6 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -566,6 +566,5 @@ impl_binder_encode_decode! {
ty::TraitPredicate<'tcx>,
ty::ExistentialPredicate<'tcx>,
ty::TraitRef<'tcx>,
- Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
ty::ExistentialTraitRef<'tcx>,
}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index cce10417e..2518f0cf2 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,5 +1,5 @@
use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
+use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
@@ -14,9 +14,8 @@ mod valtree;
pub use int::*;
pub use kind::*;
-use rustc_span::ErrorGuaranteed;
+use rustc_span::Span;
use rustc_span::DUMMY_SP;
-use rustc_target::abi::Size;
pub use valtree::*;
use super::sty::ConstKind;
@@ -36,16 +35,6 @@ pub struct ConstData<'tcx> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ConstData<'_>, 40);
-enum EvalMode {
- Typeck,
- Mir,
-}
-
-enum EvalResult<'tcx> {
- ValTree(ty::ValTree<'tcx>),
- ConstVal(ConstValue<'tcx>),
-}
-
impl<'tcx> Const<'tcx> {
#[inline]
pub fn ty(self) -> Ty<'tcx> {
@@ -165,7 +154,7 @@ impl<'tcx> Const<'tcx> {
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
- match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ match Self::try_from_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => ty::Const::new_unevaluated(
tcx,
@@ -179,7 +168,7 @@ impl<'tcx> Const<'tcx> {
}
#[instrument(skip(tcx), level = "debug")]
- fn try_eval_lit_or_param(
+ fn try_from_lit_or_param(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
@@ -254,14 +243,6 @@ impl<'tcx> Const<'tcx> {
}
}
- /// Panics if self.kind != ty::ConstKind::Value
- pub fn to_valtree(self) -> ty::ValTree<'tcx> {
- match self.kind() {
- ty::ConstKind::Value(valtree) => valtree,
- _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
- }
- }
-
#[inline]
/// Creates a constant with the given integer value and interns it.
pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
@@ -294,33 +275,83 @@ impl<'tcx> Const<'tcx> {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}
- /// Attempts to convert to a `ValTree`
- pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
+ /// Returns the evaluated constant
+ #[inline]
+ pub fn eval(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ span: Option<Span>,
+ ) -> Result<ValTree<'tcx>, ErrorHandled> {
+ assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
match self.kind() {
- ty::ConstKind::Value(valtree) => Some(valtree),
- _ => None,
+ ConstKind::Unevaluated(unevaluated) => {
+ // FIXME(eddyb) maybe the `const_eval_*` methods should take
+ // `ty::ParamEnvAnd` instead of having them separate.
+ let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
+ // try to resolve e.g. associated constants to their definition on an impl, and then
+ // evaluate the const.
+ let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?;
+ Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type"))
+ }
+ ConstKind::Value(val) => Ok(val),
+ ConstKind::Error(g) => Err(g.into()),
+ ConstKind::Param(_)
+ | ConstKind::Infer(_)
+ | ConstKind::Bound(_, _)
+ | ConstKind::Placeholder(_)
+ | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
}
}
+ /// Normalizes the constant to a value or an error if possible.
+ #[inline]
+ pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
+ match self.eval(tcx, param_env, None) {
+ Ok(val) => Self::new_value(tcx, val, self.ty()),
+ Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
+ Err(ErrorHandled::TooGeneric(_span)) => self,
+ }
+ }
+
+ #[inline]
+ pub fn try_eval_scalar(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<Scalar> {
+ self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+ }
+
#[inline]
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
/// contains const generic parameters or pointers).
- pub fn try_eval_bits(
+ pub fn try_eval_scalar_int(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- ) -> Option<u128> {
- assert_eq!(self.ty(), ty);
- let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+ ) -> Option<ScalarInt> {
+ self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
+ }
+
+ #[inline]
+ /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+ /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+ /// contains const generic parameters or pointers).
+ pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
+ let int = self.try_eval_scalar_int(tcx, param_env)?;
+ let size =
+ tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
- self.eval(tcx, param_env).try_to_bits(size)
+ int.to_bits(size).ok()
}
#[inline]
- pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
- self.eval(tcx, param_env).try_to_bool()
+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+ pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
+ self.try_eval_bits(tcx, param_env)
+ .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
}
#[inline]
@@ -329,29 +360,12 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<u64> {
- self.eval(tcx, param_env).try_to_target_usize(tcx)
- }
-
- #[inline]
- /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
- /// unevaluated constant.
- pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
- if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
- match val {
- Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
- Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
- }
- } else {
- // Either the constant isn't evaluatable or ValTree creation failed.
- self
- }
+ self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok()
}
#[inline]
- /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
- pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
- self.try_eval_bits(tcx, param_env, ty)
- .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+ pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+ self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
}
#[inline]
@@ -361,136 +375,30 @@ impl<'tcx> Const<'tcx> {
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
- #[inline]
- /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
- /// return `None`.
- // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
- pub fn try_eval_for_mir(
- self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
- match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
- Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
- Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
- Some(Err(e)) => Some(Err(e)),
- None => None,
- }
- }
-
- #[inline]
- /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
- /// return `None`.
- // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
- pub fn try_eval_for_typeck(
- self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
- match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
- Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
- Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
- Some(Err(e)) => Some(Err(e)),
- None => None,
+ /// Panics if self.kind != ty::ConstKind::Value
+ pub fn to_valtree(self) -> ty::ValTree<'tcx> {
+ match self.kind() {
+ ty::ConstKind::Value(valtree) => valtree,
+ _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
}
}
- #[inline]
- fn try_eval_inner(
- self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- eval_mode: EvalMode,
- ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
- assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
- if let ConstKind::Unevaluated(unevaluated) = self.kind() {
- use crate::mir::interpret::ErrorHandled;
-
- // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
- // also does later, but we want to do it before checking for
- // inference variables.
- // Note that we erase regions *before* calling `with_reveal_all_normalized`,
- // so that we don't try to invoke this query with
- // any region variables.
-
- // HACK(eddyb) when the query key would contain inference variables,
- // attempt using identity args and `ParamEnv` instead, that will succeed
- // when the expression doesn't depend on any parameters.
- // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
- // we can call `infcx.const_eval_resolve` which handles inference variables.
- let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
- tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
- def: unevaluated.def,
- args: GenericArgs::identity_for_item(tcx, unevaluated.def),
- })
- } else {
- tcx.erase_regions(param_env)
- .with_reveal_all_normalized(tcx)
- .and(tcx.erase_regions(unevaluated))
- };
-
- // FIXME(eddyb) maybe the `const_eval_*` methods should take
- // `ty::ParamEnvAnd` instead of having them separate.
- let (param_env, unevaluated) = param_env_and.into_parts();
- // try to resolve e.g. associated constants to their definition on an impl, and then
- // evaluate the const.
- match eval_mode {
- EvalMode::Typeck => {
- match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
- // NOTE(eddyb) `val` contains no lifetimes/types/consts,
- // and we use the original type, so nothing from `args`
- // (which may be identity args, see above),
- // can leak through `val` into the const we return.
- Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
- Err(ErrorHandled::TooGeneric) => None,
- Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
- }
- }
- EvalMode::Mir => {
- match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
- // NOTE(eddyb) `val` contains no lifetimes/types/consts,
- // and we use the original type, so nothing from `args`
- // (which may be identity args, see above),
- // can leak through `val` into the const we return.
- Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
- Err(ErrorHandled::TooGeneric) => None,
- Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
- }
- }
- }
- } else {
- None
+ /// Attempts to convert to a `ValTree`
+ pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> {
+ match self.kind() {
+ ty::ConstKind::Value(valtree) => Some(valtree),
+ _ => None,
}
}
#[inline]
- pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
- if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
- }
-
- #[inline]
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
- self.try_to_value()?.try_to_scalar()
- }
-
- #[inline]
- pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
- self.try_to_value()?.try_to_scalar_int()
- }
-
- #[inline]
- pub fn try_to_bits(self, size: Size) -> Option<u128> {
- self.try_to_scalar_int()?.to_bits(size).ok()
- }
-
- #[inline]
- pub fn try_to_bool(self) -> Option<bool> {
- self.try_to_scalar_int()?.try_into().ok()
+ self.try_to_valtree()?.try_to_scalar()
}
#[inline]
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
- self.try_to_value()?.try_to_target_usize(tcx)
+ self.try_to_valtree()?.try_to_target_usize(tcx)
}
pub fn is_ct_infer(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index b16163edf..9d99344d5 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -227,6 +227,11 @@ impl ScalarInt {
}
#[inline]
+ pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
+ Self::try_from_uint(i, tcx.data_layout.pointer_size)
+ }
+
+ #[inline]
pub fn assert_bits(self, target_size: Size) -> u128 {
self.to_bits(target_size).unwrap_or_else(|size| {
bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index db4a15fbe..749b54ca0 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -2,13 +2,13 @@ use super::Const;
use crate::mir;
use crate::ty::abstract_const::CastKind;
use crate::ty::GenericArgsRef;
-use crate::ty::{self, List, Ty};
+use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
/// An unevaluated (potentially generic) constant used in the type-system.
-#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
pub def: DefId,
@@ -22,9 +22,37 @@ impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> {
}
impl<'tcx> UnevaluatedConst<'tcx> {
+ /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
+ /// hurts performance.
#[inline]
- pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
- mir::UnevaluatedConst { def: self.def, args: self.args, promoted: None }
+ pub(crate) fn prepare_for_eval(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> (ty::ParamEnv<'tcx>, Self) {
+ // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
+ // also does later, but we want to do it before checking for
+ // inference variables.
+ // Note that we erase regions *before* calling `with_reveal_all_normalized`,
+ // so that we don't try to invoke this query with
+ // any region variables.
+
+ // HACK(eddyb) when the query key would contain inference variables,
+ // attempt using identity args and `ParamEnv` instead, that will succeed
+ // when the expression doesn't depend on any parameters.
+ // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+ // we can call `infcx.const_eval_resolve` which handles inference variables.
+ if (param_env, self).has_non_region_infer() {
+ (
+ tcx.param_env(self.def),
+ ty::UnevaluatedConst {
+ def: self.def,
+ args: ty::GenericArgs::identity_for_item(tcx, self.def),
+ },
+ )
+ } else {
+ (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
+ }
}
}
@@ -55,6 +83,11 @@ static_assert_size!(super::ConstKind<'_>, 32);
pub enum InferConst<'tcx> {
/// Infer the value of the const.
Var(ty::ConstVid<'tcx>),
+ /// Infer the value of the effect.
+ ///
+ /// For why this is separate from the `Var` variant above, see the
+ /// documentation on `EffectVid`.
+ EffectVar(ty::EffectVid<'tcx>),
/// A fresh const variable. See `infer::freshen` for more details.
Fresh(u32),
}
@@ -62,7 +95,9 @@ pub enum InferConst<'tcx> {
impl<CTX> HashStable<CTX> for InferConst<'_> {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
match self {
- InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+ InferConst::Var(_) | InferConst::EffectVar(_) => {
+ panic!("const variables should not be hashed: {self:?}")
+ }
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
}
}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index be839e03c..c06b8b2df 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -39,7 +39,7 @@ use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{self, Lock, Lrc, MappedReadGuard, ReadGuard, WorkerLocal};
+use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::{
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
@@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Constness, HirId, Node, TraitCandidate};
+use rustc_hir::{HirId, Node, TraitCandidate};
use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::dep_graph::DepNodeIndex;
@@ -82,6 +82,7 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> {
type AdtDef = ty::AdtDef<'tcx>;
type GenericArgsRef = ty::GenericArgsRef<'tcx>;
+ type GenericArg = ty::GenericArg<'tcx>;
type DefId = DefId;
type Binder<T> = Binder<'tcx, T>;
type Ty = Ty<'tcx>;
@@ -317,7 +318,7 @@ pub struct CommonLifetimes<'tcx> {
pub re_vars: Vec<Region<'tcx>>,
/// Pre-interned values of the form:
- /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(None) })`
+ /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon })`
/// for small values of `i` and `v`.
pub re_late_bounds: Vec<Vec<Region<'tcx>>>,
}
@@ -394,7 +395,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
.map(|v| {
mk(ty::ReLateBound(
ty::DebruijnIndex::from(i),
- ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon(None) },
+ ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon },
))
})
.collect()
@@ -553,6 +554,10 @@ pub struct GlobalCtxt<'tcx> {
/// Common consts, pre-interned for your convenience.
pub consts: CommonConsts<'tcx>,
+ /// Hooks to be able to register functions in other crates that can then still
+ /// be called from rustc_middle.
+ pub(crate) hooks: crate::hooks::Providers,
+
untracked: Untracked,
pub query_system: QuerySystem<'tcx>,
@@ -647,7 +652,7 @@ impl<'tcx> TyCtxt<'tcx> {
// Create an allocation that just contains these bytes.
let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
let alloc = self.mk_const_alloc(alloc);
- self.create_memory_alloc(alloc)
+ self.reserve_and_set_memory_alloc(alloc)
}
/// Returns a range of the start/end indices specified with the
@@ -702,6 +707,7 @@ impl<'tcx> TyCtxt<'tcx> {
dep_graph: DepGraph,
query_kinds: &'tcx [DepKindStruct<'tcx>],
query_system: QuerySystem<'tcx>,
+ hooks: crate::hooks::Providers,
) -> GlobalCtxt<'tcx> {
let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
s.emit_fatal(err);
@@ -720,6 +726,7 @@ impl<'tcx> TyCtxt<'tcx> {
hir_arena,
interners,
dep_graph,
+ hooks,
prof: s.prof.clone(),
types: common_types,
lifetimes: common_lifetimes,
@@ -964,8 +971,8 @@ impl<'tcx> TyCtxt<'tcx> {
i += 1;
}
- // Leak a read lock once we finish iterating on definitions, to prevent adding new ones.
- definitions.leak();
+ // Freeze definitions once we finish iterating on them, to prevent adding new ones.
+ definitions.freeze();
})
}
@@ -974,10 +981,9 @@ impl<'tcx> TyCtxt<'tcx> {
// definitions change.
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
- // Leak a read lock once we start iterating on definitions, to prevent adding new ones
+ // Freeze definitions once we start iterating on them, to prevent adding new ones
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
- let definitions = self.untracked.definitions.leak();
- definitions.def_path_table()
+ self.untracked.definitions.freeze().def_path_table()
}
pub fn def_path_hash_to_def_index_map(
@@ -986,17 +992,16 @@ impl<'tcx> TyCtxt<'tcx> {
// Create a dependency to the crate to be sure we re-execute this when the amount of
// definitions change.
self.ensure().hir_crate(());
- // Leak a read lock once we start iterating on definitions, to prevent adding new ones
+ // Freeze definitions once we start iterating on them, to prevent adding new ones
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
- let definitions = self.untracked.definitions.leak();
- definitions.def_path_hash_to_def_index_map()
+ self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
}
/// Note that this is *untracked* and should only be used within the query
/// system if the result is otherwise tracked through queries
#[inline]
- pub fn cstore_untracked(self) -> MappedReadGuard<'tcx, CrateStoreDyn> {
- ReadGuard::map(self.untracked.cstore.read(), |c| &**c)
+ pub fn cstore_untracked(self) -> FreezeReadGuard<'tcx, CrateStoreDyn> {
+ FreezeReadGuard::map(self.untracked.cstore.read(), |c| &**c)
}
/// Give out access to the untracked data without any sanity checks.
@@ -1006,7 +1011,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Note that this is *untracked* and should only be used within the query
/// system if the result is otherwise tracked through queries
#[inline]
- pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> {
+ pub fn definitions_untracked(self) -> FreezeReadGuard<'tcx, Definitions> {
self.untracked.definitions.read()
}
@@ -1109,7 +1114,7 @@ impl<'tcx> TyCtxt<'tcx> {
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
+ hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind
&& let Some(local_id) = def_id.as_local()
&& let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias
&& let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics()
@@ -1216,6 +1221,25 @@ macro_rules! nop_lift {
impl<'a, 'tcx> Lift<'tcx> for $ty {
type Lifted = $lifted;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ // Assert that the set has the right type.
+ // Given an argument that has an interned type, the return type has the type of
+ // the corresponding interner set. This won't actually return anything, we're
+ // just doing this to compute said type!
+ fn _intern_set_ty_from_interned_ty<'tcx, Inner>(
+ _x: Interned<'tcx, Inner>,
+ ) -> InternedSet<'tcx, Inner> {
+ unreachable!()
+ }
+ fn _type_eq<T>(_x: &T, _y: &T) {}
+ fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) {
+ // If `x` is a newtype around an `Interned<T>`, then `interner` is an
+ // interner of appropriate type. (Ideally we'd also check that `x` is a
+ // newtype with just that one field. Not sure how to do that.)
+ let interner = _intern_set_ty_from_interned_ty(x.0);
+ // Now check that this is the same type as `interners.$set`.
+ _type_eq(&interner, &tcx.interners.$set);
+ }
+
tcx.interners
.$set
.contains_pointer_to(&InternedInSet(&*self.0.0))
@@ -1232,6 +1256,11 @@ macro_rules! nop_list_lift {
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
type Lifted = &'tcx List<$lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ // Assert that the set has the right type.
+ if false {
+ let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set;
+ }
+
if self.is_empty() {
return Some(List::empty());
}
@@ -1253,19 +1282,13 @@ nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
-nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
-nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
-nop_list_lift! {projs; ProjectionKind => ProjectionKind}
nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
// This is the impl for `&'a GenericArgs<'a>`.
nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
-CloneLiftImpls! {
- Constness,
- traits::WellFormedLoc,
+TrivialLiftImpls! {
ImplPolarity,
- crate::mir::ReturnConstraint,
}
macro_rules! sty_debug_print {
@@ -1296,25 +1319,26 @@ macro_rules! sty_debug_print {
};
$(let mut $variant = total;)*
- let shards = tcx.interners.type_.lock_shards();
- let types = shards.iter().flat_map(|shard| shard.keys());
- for &InternedInSet(t) in types {
- let variant = match t.internee {
- ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
- ty::Float(..) | ty::Str | ty::Never => continue,
- ty::Error(_) => /* unimportant */ continue,
- $(ty::$variant(..) => &mut $variant,)*
- };
- let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
- let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
- let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
-
- variant.total += 1;
- total.total += 1;
- if lt { total.lt_infer += 1; variant.lt_infer += 1 }
- if ty { total.ty_infer += 1; variant.ty_infer += 1 }
- if ct { total.ct_infer += 1; variant.ct_infer += 1 }
- if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
+ for shard in tcx.interners.type_.lock_shards() {
+ let types = shard.keys();
+ for &InternedInSet(t) in types {
+ let variant = match t.internee {
+ ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
+ ty::Float(..) | ty::Str | ty::Never => continue,
+ ty::Error(_) => /* unimportant */ continue,
+ $(ty::$variant(..) => &mut $variant,)*
+ };
+ let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
+ let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
+ let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
+
+ variant.total += 1;
+ total.total += 1;
+ if lt { total.lt_infer += 1; variant.lt_infer += 1 }
+ if ty { total.ty_infer += 1; variant.ty_infer += 1 }
+ if ct { total.ct_infer += 1; variant.ct_infer += 1 }
+ if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
+ }
}
writeln!(fmt, "Ty interner total ty lt ct all")?;
$(writeln!(fmt, " {:18}: {uses:6} {usespc:4.1}%, \
@@ -1360,7 +1384,6 @@ impl<'tcx> TyCtxt<'tcx> {
Placeholder,
Generator,
GeneratorWitness,
- GeneratorWitnessMIR,
Dynamic,
Closure,
Tuple,
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 5db9b775a..f03813a45 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -70,10 +70,10 @@ impl<'tcx> Ty<'tcx> {
/// description in error messages. This is used in the primary span label. Beyond what
/// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
/// ADTs with no type arguments.
- pub fn is_simple_text(self) -> bool {
+ pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
- Adt(_, args) => args.non_erasable_generics().next().is_none(),
- Ref(_, ty, _) => ty.is_simple_text(),
+ Adt(def, args) => args.non_erasable_generics(tcx, def.did()).next().is_none(),
+ Ref(_, ty, _) => ty.is_simple_text(tcx),
_ => self.is_simple_ty(),
}
}
@@ -493,7 +493,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
Alias(Opaque, AliasTy { def_id, .. }) => {
let parent = self.tcx.parent(def_id);
let parent_ty = self.tcx.type_of(parent).instantiate_identity();
- if let DefKind::TyAlias { .. } | DefKind::AssocTy = self.tcx.def_kind(parent)
+ if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
&& parent_opaque_def_id == def_id
{
@@ -577,7 +577,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
Alias(Opaque, AliasTy { def_id, .. }) => {
let parent = self.tcx.parent(def_id);
let parent_ty = self.tcx.type_of(parent).instantiate_identity();
- if let hir::def::DefKind::TyAlias { .. } | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
+ if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
&& let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
&& parent_opaque_def_id == def_id
{
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 7895993cc..3371ea3be 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -20,8 +20,8 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- // If there's nothing to erase avoid performing the query at all
- if !value.has_type_flags(TypeFlags::HAS_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
+ // If there's nothing to erase or anonymize, avoid performing the query at all
+ if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
return value;
}
debug!("erase_regions({:?})", value);
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index bf6f082c2..459c8dfb5 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
pub struct ExpectedFound<T> {
pub expected: T,
pub found: T,
@@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
}
// Data structures used in type unification
-#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)]
#[rustc_pass_by_value]
pub enum TypeError<'tcx> {
Mismatch,
@@ -242,8 +242,7 @@ impl<'tcx> Ty<'tcx> {
ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
- ty::GeneratorWitness(..) |
- ty::GeneratorWitnessMIR(..) => "generator witness".into(),
+ ty::GeneratorWitness(..) => "generator witness".into(),
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
ty::Infer(ty::IntVar(_)) => "integer".into(),
ty::Infer(ty::FloatVar(_)) => "floating-point number".into(),
@@ -295,7 +294,7 @@ impl<'tcx> Ty<'tcx> {
ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
- ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(),
+ ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(),
ty::Bound(..) => "bound type variable".into(),
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 668aa4521..16935d5b3 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -29,8 +29,7 @@ pub enum SimplifiedType {
Trait(DefId),
Closure(DefId),
Generator(DefId),
- GeneratorWitness(usize),
- GeneratorWitnessMIR(DefId),
+ GeneratorWitness(DefId),
Function(usize),
Placeholder,
}
@@ -130,10 +129,7 @@ pub fn simplify_type<'tcx>(
ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)),
ty::Generator(def_id, _, _) => Some(SimplifiedType::Generator(def_id)),
- ty::GeneratorWitness(tys) => {
- Some(SimplifiedType::GeneratorWitness(tys.skip_binder().len()))
- }
- ty::GeneratorWitnessMIR(def_id, _) => Some(SimplifiedType::GeneratorWitnessMIR(def_id)),
+ ty::GeneratorWitness(def_id, _) => Some(SimplifiedType::GeneratorWitness(def_id)),
ty::Never => Some(SimplifiedType::Never),
ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())),
@@ -169,7 +165,7 @@ impl SimplifiedType {
| SimplifiedType::Trait(d)
| SimplifiedType::Closure(d)
| SimplifiedType::Generator(d)
- | SimplifiedType::GeneratorWitnessMIR(d) => Some(d),
+ | SimplifiedType::GeneratorWitness(d) => Some(d),
_ => None,
}
}
@@ -240,7 +236,6 @@ impl DeepRejectCtxt {
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
@@ -342,7 +337,7 @@ impl DeepRejectCtxt {
ty::Error(_) => true,
- ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => {
+ ty::GeneratorWitness(..) => {
bug!("unexpected obligation type: {:?}", obligation_ty)
}
}
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index bbd4a6233..c23d553d9 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -59,18 +59,8 @@ impl FlagComputation {
{
let mut computation = FlagComputation::new();
- for bv in value.bound_vars() {
- match bv {
- ty::BoundVariableKind::Ty(_) => {
- computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
- }
- ty::BoundVariableKind::Region(_) => {
- computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
- }
- ty::BoundVariableKind::Const => {
- computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
- }
- }
+ if !value.bound_vars().is_empty() {
+ computation.add_flags(TypeFlags::HAS_BINDER_VARS);
}
f(&mut computation, value.skip_binder());
@@ -121,11 +111,7 @@ impl FlagComputation {
self.add_ty(args.tupled_upvars_ty());
}
- &ty::GeneratorWitness(ts) => {
- self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
- }
-
- ty::GeneratorWitnessMIR(_, args) => {
+ ty::GeneratorWitness(_, args) => {
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_args(args);
@@ -324,7 +310,9 @@ impl FlagComputation {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
- InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
+ InferConst::Var(_) | InferConst::EffectVar(_) => {
+ self.add_flags(TypeFlags::HAS_CT_INFER)
+ }
}
}
ty::ConstKind::Bound(debruijn, _) => {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 77cf6bee7..00529a1e0 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -385,7 +385,7 @@ impl<'tcx> TyCtxt<'tcx> {
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let kind = entry
- .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None)))
+ .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon))
.expect_region();
let br = ty::BoundRegion { var, kind };
ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br)
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 97dab5cb4..72390e4bb 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -379,12 +379,17 @@ impl<'tcx> GenericArgs<'tcx> {
self.iter().filter_map(|k| k.as_const())
}
+ /// Returns generic arguments that are not lifetimes or host effect params.
#[inline]
pub fn non_erasable_generics(
&'tcx self,
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx {
- self.iter().filter_map(|k| match k.unpack() {
- GenericArgKind::Lifetime(_) => None,
+ let generics = tcx.generics_of(def_id);
+ self.iter().enumerate().filter_map(|(i, k)| match k.unpack() {
+ _ if Some(i) == generics.host_effect_index => None,
+ ty::GenericArgKind::Lifetime(_) => None,
generic => Some(generic),
})
}
@@ -440,7 +445,7 @@ impl<'tcx> GenericArgs<'tcx> {
target_args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
let defs = tcx.generics_of(source_ancestor);
- tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.params.len())))
+ tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count())))
}
pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> {
@@ -450,6 +455,11 @@ impl<'tcx> GenericArgs<'tcx> {
pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> {
self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
}
+
+ pub fn print_as_list(&self) -> String {
+ let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>();
+ format!("[{}]", v.join(", "))
+ }
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
@@ -1019,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
/// Stores the user-given args to reach some fully qualified path
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct UserArgs<'tcx> {
/// The args for the item as given by the user.
pub args: GenericArgsRef<'tcx>,
@@ -1046,7 +1056,7 @@ pub struct UserArgs<'tcx> {
/// the self type, giving `Foo<?A>`. Finally, we unify that with
/// the self type here, which contains `?A` to be `&'static u32`
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct UserSelfTy<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 70a35f137..8e6c1cd4b 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -12,7 +12,7 @@ use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamT
pub enum GenericParamDefKind {
Lifetime,
Type { has_default: bool, synthetic: bool },
- Const { has_default: bool },
+ Const { has_default: bool, is_host_effect: bool },
}
impl GenericParamDefKind {
@@ -87,7 +87,7 @@ impl GenericParamDef {
GenericParamDefKind::Type { has_default, .. } if has_default => {
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
}
- GenericParamDefKind::Const { has_default } if has_default => {
+ GenericParamDefKind::Const { has_default, .. } if has_default => {
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
}
_ => None,
@@ -187,7 +187,7 @@ impl<'tcx> Generics {
GenericParamDefKind::Type { has_default, .. } => {
own_defaults.types += has_default as usize;
}
- GenericParamDefKind::Const { has_default } => {
+ GenericParamDefKind::Const { has_default, .. } => {
own_defaults.consts += has_default as usize;
}
}
@@ -212,10 +212,12 @@ impl<'tcx> Generics {
pub fn own_requires_monomorphization(&self) -> bool {
for param in &self.params {
match param.kind {
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { is_host_effect: false, .. } => {
return true;
}
- GenericParamDefKind::Lifetime => {}
+ GenericParamDefKind::Lifetime
+ | GenericParamDefKind::Const { is_host_effect: true, .. } => {}
}
}
false
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 8913bf76d..0b0a708e4 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -18,6 +18,9 @@ use std::fmt;
/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
/// will do all required substitution as they run.
+///
+/// Note: the `Lift` impl is currently not used by rustc, but is used by
+/// rustc_codegen_cranelift when the `jit` feature is enabled.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
pub struct Instance<'tcx> {
@@ -115,7 +118,7 @@ impl<'tcx> Instance<'tcx> {
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let ty = tcx.type_of(self.def.def_id());
- tcx.subst_and_normalize_erasing_regions(self.args, param_env, ty)
+ tcx.instantiate_and_normalize_erasing_regions(self.args, param_env, ty)
}
/// Finds a crate that contains a monomorphization of this instance that
@@ -139,7 +142,7 @@ impl<'tcx> Instance<'tcx> {
}
// If this a non-generic instance, it cannot be a shared monomorphization.
- self.args.non_erasable_generics().next()?;
+ self.args.non_erasable_generics(tcx, self.def_id()).next()?;
match self.def {
InstanceDef::Item(def) => tcx
@@ -344,6 +347,7 @@ impl<'tcx> Instance<'tcx> {
pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
let args = GenericArgs::for_item(tcx, def_id, |param, _| match param.kind {
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ ty::GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(),
ty::GenericParamDefKind::Type { .. } => {
bug!("Instance::mono: {:?} has type parameters", def_id)
}
@@ -576,7 +580,7 @@ impl<'tcx> Instance<'tcx> {
self.def.has_polymorphic_mir_body().then_some(self.args)
}
- pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
+ pub fn instantiate_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
@@ -589,7 +593,7 @@ impl<'tcx> Instance<'tcx> {
}
#[inline(always)]
- pub fn subst_mir_and_normalize_erasing_regions<T>(
+ pub fn instantiate_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -599,14 +603,14 @@ impl<'tcx> Instance<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
{
if let Some(args) = self.args_for_mir_body() {
- tcx.subst_and_normalize_erasing_regions(args, param_env, v)
+ tcx.instantiate_and_normalize_erasing_regions(args, param_env, v)
} else {
tcx.normalize_erasing_regions(param_env, v.skip_binder())
}
}
#[inline(always)]
- pub fn try_subst_mir_and_normalize_erasing_regions<T>(
+ pub fn try_instantiate_mir_and_normalize_erasing_regions<T>(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -616,7 +620,7 @@ impl<'tcx> Instance<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
{
if let Some(args) = self.args_for_mir_body() {
- tcx.try_subst_and_normalize_erasing_regions(args, param_env, v)
+ tcx.try_instantiate_and_normalize_erasing_regions(args, param_env, v)
} else {
tcx.try_normalize_erasing_regions(param_env, v.skip_binder())
}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index e362b3477..bccf5e839 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,9 @@ use crate::query::TyCtxtAt;
use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::{self, ConstKind, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
use rustc_error_messages::DiagnosticMessage;
-use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
+use rustc_errors::{
+ DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
+};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::IndexVec;
@@ -265,6 +267,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
}
}
+impl<'tcx> IntoDiagnosticArg for LayoutError<'tcx> {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
#[derive(Clone, Copy)]
pub struct LayoutCx<'tcx, C> {
pub tcx: C,
@@ -802,7 +810,6 @@ where
| ty::Never
| ty::FnDef(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Foreign(..)
| ty::Dynamic(_, _, ty::Dyn) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
@@ -1110,6 +1117,10 @@ where
fn is_unit(this: TyAndLayout<'tcx>) -> bool {
matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
}
+
+ fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
+ }
}
/// Calculates whether a function's ABI can unwind or not.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1274f427e..aa1e7f216 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -98,17 +98,16 @@ pub use self::sty::BoundRegionKind::*;
pub use self::sty::{
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
- EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
- FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs, InlineConstArgsParts,
- ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
+ EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
+ FnSig, FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs,
+ InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
};
pub use self::trait_def::TraitDef;
pub use self::typeck_results::{
- CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType,
- UserTypeAnnotationIndex,
+ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
+ UserType, UserTypeAnnotationIndex,
};
pub mod _match;
@@ -162,8 +161,6 @@ pub struct ResolverOutputs {
#[derive(Debug)]
pub struct ResolverGlobalCtxt {
pub visibilities: FxHashMap<LocalDefId, Visibility>,
- /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
- pub has_pub_restricted: bool,
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
pub effective_visibilities: EffectiveVisibilities,
@@ -238,7 +235,7 @@ pub struct ImplHeader<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,
pub trait_ref: Option<TraitRef<'tcx>>,
- pub predicates: Vec<(Predicate<'tcx>, Span)>,
+ pub predicates: Vec<Predicate<'tcx>>,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
@@ -282,6 +279,19 @@ impl fmt::Display for ImplPolarity {
}
}
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum Asyncness {
+ Yes,
+ No,
+}
+
+impl Asyncness {
+ pub fn is_async(self) -> bool {
+ matches!(self, Asyncness::Yes)
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
pub enum Visibility<Id = LocalDefId> {
/// Visible everywhere (including in other crates).
@@ -568,6 +578,11 @@ impl rustc_errors::IntoDiagnosticArg for Clause<'_> {
pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>);
impl<'tcx> Clause<'tcx> {
+ pub fn from_projection_clause(tcx: TyCtxt<'tcx>, pred: PolyProjectionPredicate<'tcx>) -> Self {
+ let pred: Predicate<'tcx> = pred.to_predicate(tcx);
+ pred.expect_clause()
+ }
+
pub fn as_predicate(self) -> Predicate<'tcx> {
Predicate(self.0)
}
@@ -1255,14 +1270,6 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
}
}
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
- #[inline(always)]
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
- let p: Predicate<'tcx> = self.to_predicate(tcx);
- p.expect_clause()
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@@ -1289,18 +1296,6 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
}
}
-impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitRef<'tcx> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
- ty::Binder::dummy(self).to_predicate(tcx)
- }
-}
-
-impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> {
- fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
- ty::Binder::dummy(self)
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx)
@@ -1314,12 +1309,6 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
}
}
-impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(self))).to_predicate(tcx)
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx)
@@ -1332,12 +1321,6 @@ impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
}
}
-impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.map_bound(|p| PredicateKind::Clause(ClauseKind::TypeOutlives(p))).to_predicate(tcx)
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
@@ -1357,13 +1340,6 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
}
}
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
- let p: Predicate<'tcx> = self.to_predicate(tcx);
- p.expect_clause()
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
@@ -1512,7 +1488,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct OpaqueTypeKey<'tcx> {
pub def_id: LocalDefId,
@@ -1795,7 +1771,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
-#[derive(HashStable, Lift)]
+#[derive(HashStable)]
pub struct ParamEnvAnd<'tcx, T> {
pub param_env: ParamEnv<'tcx>,
pub value: T,
@@ -2150,6 +2126,7 @@ impl<'tcx> TyCtxt<'tcx> {
for attr in self.get_attrs(did, sym::repr) {
for r in attr::parse_repr_attr(&self.sess, attr) {
flags.insert(match r {
+ attr::ReprRust => ReprFlags::empty(),
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked(pack) => {
let pack = Align::from_bytes(pack as u64).unwrap();
@@ -2215,10 +2192,6 @@ impl<'tcx> TyCtxt<'tcx> {
// The name of a constructor is that of its parent.
rustc_hir::definitions::DefPathData::Ctor => self
.opt_item_name(DefId { krate: def_id.krate, index: def_key.parent.unwrap() }),
- // The name of opaque types only exists in HIR.
- rustc_hir::definitions::DefPathData::ImplTrait
- if let Some(def_id) = def_id.as_local() =>
- self.hir().opt_name(self.hir().local_def_id_to_hir_id(def_id)),
_ => def_key.get_opt_name(),
}
}
@@ -2409,6 +2382,22 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
+ pub fn get_attrs_by_path<'attr>(
+ self,
+ did: DefId,
+ attr: &'attr [Symbol],
+ ) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr
+ where
+ 'tcx: 'attr,
+ {
+ let filter_fn = move |a: &&ast::Attribute| a.path_matches(&attr);
+ if let Some(did) = did.as_local() {
+ self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+ } else {
+ self.item_attrs(did).iter().filter(filter_fn)
+ }
+ }
+
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
let did: DefId = did.into();
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 2415d50b2..fd125af20 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -134,8 +134,9 @@ impl<'tcx> TyCtxt<'tcx> {
/// in-scope substitutions and then normalizing any associated
/// types.
/// Panics if normalization fails. In case normalization might fail
- /// use `try_subst_and_normalize_erasing_regions` instead.
- pub fn subst_and_normalize_erasing_regions<T>(
+ /// use `try_instantiate_and_normalize_erasing_regions` instead.
+ #[instrument(level = "debug", skip(self))]
+ pub fn instantiate_and_normalize_erasing_regions<T>(
self,
param_args: GenericArgsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -144,22 +145,16 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- debug!(
- "subst_and_normalize_erasing_regions(\
- param_args={:?}, \
- value={:?}, \
- param_env={:?})",
- param_args, value, param_env,
- );
let substituted = value.instantiate(self, param_args);
self.normalize_erasing_regions(param_env, substituted)
}
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then trying to normalize any associated
- /// types. Contrary to `subst_and_normalize_erasing_regions` this does
+ /// types. Contrary to `instantiate_and_normalize_erasing_regions` this does
/// not assume that normalization succeeds.
- pub fn try_subst_and_normalize_erasing_regions<T>(
+ #[instrument(level = "debug", skip(self))]
+ pub fn try_instantiate_and_normalize_erasing_regions<T>(
self,
param_args: GenericArgsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -168,13 +163,6 @@ impl<'tcx> TyCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- debug!(
- "subst_and_normalize_erasing_regions(\
- param_args={:?}, \
- value={:?}, \
- param_env={:?})",
- param_args, value, param_env,
- );
let substituted = value.instantiate(self, param_args);
self.try_normalize_erasing_regions(param_env, substituted)
}
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 0ff5ac903..6491936c2 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -157,9 +157,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
Ty::new_generator(self.tcx, def_id, args, movability)
}
- ty::GeneratorWitnessMIR(def_id, args) => {
+ ty::GeneratorWitness(def_id, args) => {
let args = self.fold_closure_args(def_id, args);
- Ty::new_generator_witness_mir(self.tcx, def_id, args)
+ Ty::new_generator_witness(self.tcx, def_id, args)
}
ty::Param(param) => {
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index f1c389842..9aa673e44 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -62,6 +62,7 @@ trivially_parameterized_over_tcx! {
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
ty::AssocItemContainer,
+ ty::Asyncness,
ty::DeducedParamAttrs,
ty::Generics,
ty::ImplPolarity,
@@ -131,5 +132,4 @@ parameterized_over_tcx! {
ty::Predicate,
ty::Clause,
ty::ClauseKind,
- ty::GeneratorDiagnosticData,
}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 05871d0bc..aa8e2e307 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -271,7 +271,7 @@ fn characteristic_def_id_of_type_cached<'a>(
ty::FnDef(def_id, _)
| ty::Closure(def_id, _)
| ty::Generator(def_id, _, _)
- | ty::GeneratorWitnessMIR(def_id, _)
+ | ty::GeneratorWitness(def_id, _)
| ty::Foreign(def_id) => Some(def_id),
ty::Bool
@@ -286,7 +286,6 @@ fn characteristic_def_id_of_type_cached<'a>(
| ty::Infer(_)
| ty::Bound(..)
| ty::Error(_)
- | ty::GeneratorWitness(..)
| ty::Never
| ty::Float(_) => None,
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ac0c88468..2d7350387 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -136,10 +136,8 @@ define_helper!(
///
/// Regions not selected by the region highlight mode are presently
/// unaffected.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
pub struct RegionHighlightMode<'tcx> {
- tcx: TyCtxt<'tcx>,
-
/// If enabled, when we see the selected region, use "`'N`"
/// instead of the ordinary behavior.
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
@@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> {
}
impl<'tcx> RegionHighlightMode<'tcx> {
- pub fn new(tcx: TyCtxt<'tcx>) -> Self {
- Self {
- tcx,
- highlight_regions: Default::default(),
- highlight_bound_region: Default::default(),
- }
- }
-
/// If `region` and `number` are both `Some`, invokes
/// `highlighting_region`.
pub fn maybe_highlighting_region(
@@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> {
}
/// Convenience wrapper for `highlighting_region`.
- pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
- self.highlighting_region(ty::Region::new_var(self.tcx, vid), number)
+ pub fn highlighting_region_vid(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ vid: ty::RegionVid,
+ number: usize,
+ ) {
+ self.highlighting_region(ty::Region::new_var(tcx, vid), number)
}
/// Returns `Some(n)` with the number to use for the given region, if any.
@@ -365,7 +360,7 @@ pub trait PrettyPrinter<'tcx>:
self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?;
self.write_str("::")?;
} else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait
- | DefKind::TyAlias { .. } | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
+ | DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
{
} else {
// If not covered above, like for example items out of `impl` blocks, fallback.
@@ -760,15 +755,18 @@ pub trait PrettyPrinter<'tcx>:
// only affect certain debug messages (e.g. messages printed
// from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
// and should have no effect on any compiler output.
+ // [Unless `-Zverbose` is used, e.g. in the output of
+ // `tests/ui/nll/ty-outlives/impl-trait-captures.rs`, for
+ // example.]
if self.should_print_verbose() {
// FIXME(eddyb) print this with `print_def_path`.
- p!(write("Opaque({:?}, {:?})", def_id, args));
+ p!(write("Opaque({:?}, {})", def_id, args.print_as_list()));
return Ok(self);
}
let parent = self.tcx().parent(def_id);
match self.tcx().def_kind(parent) {
- DefKind::TyAlias { .. } | DefKind::AssocTy => {
+ DefKind::TyAlias | DefKind::AssocTy => {
// NOTE: I know we should check for NO_QUERIES here, but it's alright.
// `type_of` on a type alias or assoc type should never cause a cycle.
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
@@ -797,7 +795,7 @@ pub trait PrettyPrinter<'tcx>:
}
ty::Str => p!("str"),
ty::Generator(did, args, movability) => {
- p!(write("["));
+ p!(write("{{"));
let generator_kind = self.tcx().generator_kind(did).unwrap();
let should_print_movability =
self.should_print_verbose() || generator_kind == hir::GeneratorKind::Gen;
@@ -838,13 +836,10 @@ pub trait PrettyPrinter<'tcx>:
}
}
- p!("]")
- }
- ty::GeneratorWitness(types) => {
- p!(in_binder(&types));
+ p!("}}")
}
- ty::GeneratorWitnessMIR(did, args) => {
- p!(write("["));
+ ty::GeneratorWitness(did, args) => {
+ p!(write("{{"));
if !self.tcx().sess.verbose() {
p!("generator witness");
// FIXME(eddyb) should use `def_span`.
@@ -863,10 +858,10 @@ pub trait PrettyPrinter<'tcx>:
p!(print_def_path(did, args));
}
- p!("]")
+ p!("}}")
}
ty::Closure(did, args) => {
- p!(write("["));
+ p!(write("{{"));
if !self.should_print_verbose() {
p!(write("closure"));
// FIXME(eddyb) should use `def_span`.
@@ -894,7 +889,7 @@ pub trait PrettyPrinter<'tcx>:
p!(print_def_path(did, args));
if !args.as_closure().is_valid() {
p!(" closure_args=(unavailable)");
- p!(write(" args={:?}", args));
+ p!(write(" args={}", args.print_as_list()));
} else {
p!(" closure_kind_ty=", print(args.as_closure().kind_ty()));
p!(
@@ -906,7 +901,7 @@ pub trait PrettyPrinter<'tcx>:
p!(")");
}
}
- p!("]");
+ p!("}}");
}
ty::Array(ty, sz) => p!("[", print(ty), "; ", print(sz), "]"),
ty::Slice(ty) => p!("[", print(ty), "]"),
@@ -1063,7 +1058,7 @@ pub trait PrettyPrinter<'tcx>:
}
for (assoc_item_def_id, term) in assoc_items {
- // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
+ // Skip printing `<{generator@} as Generator<_>>::Return` from async blocks,
// unless we can find out what generator return type it comes from.
let term = if let Some(ty) = term.skip_binder().ty()
&& let ty::Alias(ty::Projection, proj) = ty.kind()
@@ -1123,6 +1118,17 @@ pub trait PrettyPrinter<'tcx>:
}
}
+ if self.tcx().features().return_type_notation
+ && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id)
+ && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
+ && alias_ty.def_id == def_id
+ {
+ let num_args = self.tcx().generics_of(fn_def_id).count();
+ write!(self, " {{ ")?;
+ self = self.print_def_path(fn_def_id, &args[..num_args])?;
+ write!(self, "() }}")?;
+ }
+
Ok(self)
}
@@ -1239,21 +1245,18 @@ pub trait PrettyPrinter<'tcx>:
.generics_of(principal.def_id)
.own_args_no_defaults(cx.tcx(), principal.args);
- let mut projections = predicates.projection_bounds();
-
- let mut args = args.iter().cloned();
- let arg0 = args.next();
- let projection0 = projections.next();
- if arg0.is_some() || projection0.is_some() {
- let args = arg0.into_iter().chain(args);
- let projections = projection0.into_iter().chain(projections);
+ let mut projections: Vec<_> = predicates.projection_bounds().collect();
+ projections.sort_by_cached_key(|proj| {
+ cx.tcx().item_name(proj.item_def_id()).to_string()
+ });
+ if !args.is_empty() || !projections.is_empty() {
p!(generic_delimiters(|mut cx| {
- cx = cx.comma_sep(args)?;
- if arg0.is_some() && projection0.is_some() {
+ cx = cx.comma_sep(args.iter().copied())?;
+ if !args.is_empty() && !projections.is_empty() {
write!(cx, ", ")?;
}
- cx.comma_sep(projections)
+ cx.comma_sep(projections.iter().copied())
}));
}
}
@@ -1707,6 +1710,21 @@ pub trait PrettyPrinter<'tcx>:
}
}
+pub(crate) fn pretty_print_const<'tcx>(
+ c: ty::Const<'tcx>,
+ fmt: &mut fmt::Formatter<'_>,
+ print_types: bool,
+) -> fmt::Result {
+ ty::tls::with(|tcx| {
+ let literal = tcx.lift(c).unwrap();
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.pretty_print_const(literal, print_types)?;
+ fmt.write_str(&cx.into_buffer())?;
+ Ok(())
+ })
+}
+
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
pub struct FmtPrinter<'a, 'tcx>(Box<FmtPrinterData<'a, 'tcx>>);
@@ -1767,7 +1785,7 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
printed_type_count: 0,
type_length_limit,
truncated: false,
- region_highlight_mode: RegionHighlightMode::new(tcx),
+ region_highlight_mode: RegionHighlightMode::default(),
ty_infer_name_resolver: None,
const_infer_name_resolver: None,
}))
@@ -2312,7 +2330,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
match kind {
- ty::BrAnon(..) | ty::BrEnv => r,
+ ty::BrAnon | ty::BrEnv => r,
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
@@ -2433,7 +2451,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
binder_level_idx: ty::DebruijnIndex,
br: ty::BoundRegion| {
let (name, kind) = match br.kind {
- ty::BrAnon(..) | ty::BrEnv => {
+ ty::BrAnon | ty::BrEnv => {
let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx {
@@ -2735,20 +2753,14 @@ forward_display_to_print! {
// HACK(eddyb) these are exhaustive instead of generic,
// because `for<'tcx>` isn't possible yet.
- ty::PolyExistentialPredicate<'tcx>,
ty::PolyExistentialProjection<'tcx>,
ty::PolyExistentialTraitRef<'tcx>,
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
- ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
ty::Binder<'tcx, ty::FnSig<'tcx>>,
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
- ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
- ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
- ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>,
-
ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
}
@@ -2986,7 +2998,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
match child.res {
def::Res::Def(DefKind::AssocTy, _) => {}
- def::Res::Def(DefKind::TyAlias { .. }, _) => {}
+ def::Res::Def(DefKind::TyAlias, _) => {}
def::Res::Def(defkind, def_id) => {
if let Some(ns) = defkind.ns() {
collect_fn(&child.ident, ns, def_id);
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 47512d350..e9d763afa 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -453,24 +453,14 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(Ty::new_generator(tcx, a_id, args, movability))
}
- (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
- // Wrap our types with a temporary GeneratorWitness struct
- // inside the binder so we can related them
- let a_types = a_types.map_bound(GeneratorWitness);
- let b_types = b_types.map_bound(GeneratorWitness);
- // Then remove the GeneratorWitness for the result
- let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0);
- Ok(Ty::new_generator_witness(tcx, types))
- }
-
- (&ty::GeneratorWitnessMIR(a_id, a_args), &ty::GeneratorWitnessMIR(b_id, b_args))
+ (&ty::GeneratorWitness(a_id, a_args), &ty::GeneratorWitness(b_id, b_args))
if a_id == b_id =>
{
// All GeneratorWitness types with the same id represent
// the (anonymous) type of the same generator expression. So
// all of their regions should be equated.
let args = relation.relate(a_args, b_args)?;
- Ok(Ty::new_generator_witness_mir(tcx, a_id, args))
+ Ok(Ty::new_generator_witness(tcx, a_id, args))
}
(&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f979ddd00..2adbe9e03 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -9,15 +9,13 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace;
-use rustc_index::{Idx, IndexVec};
use rustc_target::abi::TyAndLayout;
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
use std::fmt::{self, Debug};
use std::ops::ControlFlow;
-use std::rc::Rc;
-use std::sync::Arc;
+use super::print::PrettyPrinter;
use super::{GenericArg, GenericArgKind, Region};
impl fmt::Debug for ty::TraitDef {
@@ -70,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
- ty::BrAnon(span) => write!(f, "BrAnon({span:?})"),
+ ty::BrAnon => write!(f, "BrAnon"),
ty::BrNamed(did, name) => {
if did.is_crate_root() {
write!(f, "BrNamed({name})")
@@ -138,6 +136,12 @@ impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
}
}
+impl fmt::Debug for ty::EffectVid<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "?{}e", self.index)
+ }
+}
+
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@@ -154,7 +158,7 @@ impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
}
impl<'tcx> fmt::Debug for Ty<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- with_no_trimmed_paths!(fmt::Display::fmt(self, f))
+ with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
}
}
@@ -253,6 +257,7 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InferConst::Var(var) => write!(f, "{var:?}"),
+ InferConst::EffectVar(var) => write!(f, "{var:?}"),
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
}
}
@@ -267,6 +272,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data {
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
+ EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
Fresh(_) => {
unreachable!()
}
@@ -335,14 +341,27 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
- // This reflects what `Const` looked liked before `Interned` was
- // introduced. We print it like this to avoid having to update expected
- // output in a lot of tests.
+ // If this is a value, we spend some effort to make it look nice.
+ if let ConstKind::Value(_) = this.data.kind() {
+ return ty::tls::with(move |tcx| {
+ // Somehow trying to lift the valtree results in lifetime errors, so we lift the
+ // entire constant.
+ let lifted = tcx.lift(*this.data).unwrap();
+ let ConstKind::Value(valtree) = lifted.kind() else {
+ bug!("we checked that this is a valtree")
+ };
+ let cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ let cx =
+ cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?;
+ f.write_str(&cx.into_buffer())
+ });
+ }
+ // Fall back to something verbose.
write!(
f,
- "Const {{ ty: {:?}, kind: {:?} }}",
- &this.map(|data| data.ty()),
- &this.map(|data| data.kind())
+ "{kind:?}: {ty:?}",
+ ty = &this.map(|data| data.ty()),
+ kind = &this.map(|data| data.kind())
)
}
}
@@ -434,22 +453,17 @@ impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty:
// For things for which the type library provides traversal implementations
// for all Interners, we only need to provide a Lift implementation:
-CloneLiftImpls! {
- (),
- bool,
- usize,
- u16,
- u32,
- u64,
- String,
- rustc_type_ir::DebruijnIndex,
-}
-
-// For things about which the type library does not know, or does not
-// provide any traversal implementations, we need to provide both a Lift
-// implementation and traversal implementations (the latter only for
-// TyCtxt<'_> interners).
-TrivialTypeTraversalAndLiftImpls! {
+TrivialLiftImpls! {
+ (),
+ bool,
+ usize,
+ u64,
+}
+
+// For some things about which the type library does not know, or does not
+// provide any traversal implementations, we need to provide a traversal
+// implementation (only for TyCtxt<'_> interners).
+TrivialTypeTraversalImpls! {
::rustc_target::abi::FieldIdx,
::rustc_target::abi::VariantIdx,
crate::middle::region::Scope,
@@ -459,17 +473,12 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_ast::NodeId,
::rustc_span::symbol::Symbol,
::rustc_hir::def::Res,
- ::rustc_hir::def_id::DefId,
::rustc_hir::def_id::LocalDefId,
::rustc_hir::HirId,
::rustc_hir::MatchSource,
- ::rustc_hir::Mutability,
- ::rustc_hir::Unsafety,
::rustc_target::asm::InlineAsmRegOrRegClass,
- ::rustc_target::spec::abi::Abi,
crate::mir::coverage::CounterId,
crate::mir::coverage::ExpressionId,
- crate::mir::coverage::MappedExpressionIndex,
crate::mir::Local,
crate::mir::Promoted,
crate::traits::Reveal,
@@ -484,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! {
crate::ty::AssocItem,
crate::ty::AssocKind,
crate::ty::AliasKind,
- crate::ty::AliasRelationDirection,
crate::ty::Placeholder<crate::ty::BoundRegion>,
crate::ty::Placeholder<crate::ty::BoundTy>,
crate::ty::Placeholder<ty::BoundVar>,
- crate::ty::ClosureKind,
crate::ty::FreeRegion,
crate::ty::InferTy,
crate::ty::IntVarValue,
- crate::ty::ParamConst,
- crate::ty::ParamTy,
crate::ty::adjustment::PointerCoercion,
crate::ty::RegionVid,
crate::ty::UniverseIndex,
@@ -501,32 +506,30 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_span::Span,
::rustc_span::symbol::Ident,
::rustc_errors::ErrorGuaranteed,
- interpret::Scalar,
- rustc_target::abi::Size,
ty::BoundVar,
+ ty::ValTree<'tcx>,
}
-
+// For some things about which the type library does not know, or does not
+// provide any traversal implementations, we need to provide a traversal
+// implementation and a lift implementation (the former only for TyCtxt<'_>
+// interners).
TrivialTypeTraversalAndLiftImpls! {
- ty::ValTree<'tcx>,
+ ::rustc_hir::def_id::DefId,
+ ::rustc_hir::Mutability,
+ ::rustc_hir::Unsafety,
+ ::rustc_target::spec::abi::Abi,
+ crate::ty::AliasRelationDirection,
+ crate::ty::ClosureKind,
+ crate::ty::ParamConst,
+ crate::ty::ParamTy,
+ interpret::Scalar,
+ interpret::AllocId,
+ rustc_target::abi::Size,
}
///////////////////////////////////////////////////////////////////////////
// Lift implementations
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
- type Lifted = (A::Lifted, B::Lifted);
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
- }
-}
-
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) {
- type Lifted = (A::Lifted, B::Lifted, C::Lifted);
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
- }
-}
-
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
type Lifted = Option<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -537,50 +540,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
}
}
-impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
- type Lifted = Result<T::Lifted, E::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- match self {
- Ok(x) => tcx.lift(x).map(Ok),
- Err(e) => tcx.lift(e).map(Err),
- }
- }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
- type Lifted = Box<T::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some(Box::new(tcx.lift(*self)?))
- }
-}
-
-impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
- type Lifted = Rc<T::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some(Rc::new(tcx.lift(self.as_ref().clone())?))
- }
-}
-
-impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
- type Lifted = Arc<T::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- Some(Arc::new(tcx.lift(self.as_ref().clone())?))
- }
-}
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
- type Lifted = Vec<T::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- self.into_iter().map(|v| tcx.lift(v)).collect()
- }
-}
-
-impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
- type Lifted = IndexVec<I, T::Lifted>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- self.into_iter().map(|e| tcx.lift(e)).collect()
- }
-}
-
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
type Lifted = ty::Term<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -593,13 +552,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
)
}
}
-impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
- type Lifted = ty::ParamEnv<'tcx>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(self.caller_bounds())
- .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
- }
-}
///////////////////////////////////////////////////////////////////////////
// Traversal implementations.
@@ -705,9 +657,8 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Generator(did, args, movability) => {
ty::Generator(did, args.try_fold_with(folder)?, movability)
}
- ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
- ty::GeneratorWitnessMIR(did, args) => {
- ty::GeneratorWitnessMIR(did, args.try_fold_with(folder)?)
+ ty::GeneratorWitness(did, args) => {
+ ty::GeneratorWitness(did, args.try_fold_with(folder)?)
}
ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?),
ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
@@ -756,8 +707,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
ty.visit_with(visitor)
}
ty::Generator(_did, ref args, _) => args.visit_with(visitor),
- ty::GeneratorWitness(ref types) => types.visit_with(visitor),
- ty::GeneratorWitnessMIR(_did, ref args) => args.visit_with(visitor),
+ ty::GeneratorWitness(_did, ref args) => args.visit_with(visitor),
ty::Closure(_did, ref args) => args.visit_with(visitor),
ty::Alias(_, ref data) => data.visit_with(visitor),
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 0291cdd6c..1e57392e0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -69,7 +69,7 @@ pub struct FreeRegion {
#[derive(HashStable)]
pub enum BoundRegionKind {
/// An anonymous region parameter for a given fn (&T)
- BrAnon(Option<Span>),
+ BrAnon,
/// Named region parameters for functions (a in &'a T)
///
@@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> {
}
/// Similar to `ClosureArgs`; see the above documentation for more.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
pub struct GeneratorArgs<'tcx> {
pub args: GenericArgsRef<'tcx>,
}
@@ -725,7 +725,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
}
ExistentialPredicate::Projection(p) => {
- self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
+ ty::Clause::from_projection_clause(tcx, self.rebind(p.with_self_ty(tcx, self_ty)))
}
ExistentialPredicate::AutoTrait(did) => {
let generics = tcx.generics_of(did);
@@ -1223,7 +1223,7 @@ impl<'tcx> AliasTy<'tcx> {
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
DefKind::AssocTy => ty::Projection,
DefKind::OpaqueTy => ty::Opaque,
- DefKind::TyAlias { .. } => ty::Weak,
+ DefKind::TyAlias => ty::Weak,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}
@@ -1305,7 +1305,7 @@ impl<'tcx> AliasTy<'tcx> {
}
}
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct GenSig<'tcx> {
pub resume_ty: Ty<'tcx>,
pub yield_ty: Ty<'tcx>,
@@ -1465,7 +1465,7 @@ impl<'tcx> Region<'tcx> {
bound_region: ty::BoundRegion,
) -> Region<'tcx> {
// Use a pre-interned one when possible.
- if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region
+ if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region
&& let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize())
&& let Some(re) = inner.get(var.as_usize()).copied()
{
@@ -1577,6 +1577,20 @@ pub struct ConstVid<'tcx> {
pub phantom: PhantomData<&'tcx ()>,
}
+/// An **effect** **v**ariable **ID**.
+///
+/// Handling effect infer variables happens separately from const infer variables
+/// because we do not want to reuse any of the const infer machinery. If we try to
+/// relate an effect variable with a normal one, we would ICE, which can catch bugs
+/// where we are not correctly using the effect var for an effect param. Fallback
+/// is also implemented on top of having separate effect and normal const variables.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable)]
+pub struct EffectVid<'tcx> {
+ pub index: u32,
+ pub phantom: PhantomData<&'tcx ()>,
+}
+
rustc_index::newtype_index! {
/// A **region** (lifetime) **v**ariable **ID**.
#[derive(HashStable)]
@@ -1945,7 +1959,7 @@ impl<'tcx> Ty<'tcx> {
(kind, tcx.def_kind(alias_ty.def_id)),
(ty::Opaque, DefKind::OpaqueTy)
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
- | (ty::Weak, DefKind::TyAlias { .. })
+ | (ty::Weak, DefKind::TyAlias)
);
Ty::new(tcx, Alias(kind, alias_ty))
}
@@ -2151,18 +2165,10 @@ impl<'tcx> Ty<'tcx> {
#[inline]
pub fn new_generator_witness(
tcx: TyCtxt<'tcx>,
- types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>,
- ) -> Ty<'tcx> {
- Ty::new(tcx, GeneratorWitness(types))
- }
-
- #[inline]
- pub fn new_generator_witness_mir(
- tcx: TyCtxt<'tcx>,
id: DefId,
args: GenericArgsRef<'tcx>,
) -> Ty<'tcx> {
- Ty::new(tcx, GeneratorWitnessMIR(id, args))
+ Ty::new(tcx, GeneratorWitness(id, args))
}
// misc
@@ -2536,7 +2542,7 @@ impl<'tcx> Ty<'tcx> {
/// Checks whether a type recursively contains any closure
///
- /// Example: `Option<[closure@file.rs:4:20]>` returns true
+ /// Example: `Option<{closure@file.rs:4:20}>` returns true
pub fn contains_closure(self) -> bool {
struct ContainsClosureVisitor;
@@ -2692,7 +2698,6 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..)
| ty::Closure(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Never
| ty::Tuple(_)
| ty::Error(_)
@@ -2728,13 +2733,14 @@ impl<'tcx> Ty<'tcx> {
| ty::Ref(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
| ty::Error(_)
// Extern types have metadata = ().
| ty::Foreign(..)
+ // `dyn*` has no metadata
+ | ty::Dynamic(_, _, DynKind::DynStar)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
@@ -2743,7 +2749,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Tuple(..) => (tcx.types.unit, false),
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
- ty::Dynamic(..) => {
+ ty::Dynamic(_, _, DynKind::Dyn) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
},
@@ -2815,7 +2821,6 @@ impl<'tcx> Ty<'tcx> {
| ty::Ref(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
@@ -2857,7 +2862,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Uint(..)
| ty::Float(..) => true,
- // The voldemort ZSTs are fine.
+ // ZST which can't be named are fine.
ty::FnDef(..) => true,
ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
@@ -2878,7 +2883,7 @@ impl<'tcx> Ty<'tcx> {
// anything with custom metadata it might be more complicated.
ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
- ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => false,
+ ty::Generator(..) | ty::GeneratorWitness(..) => false,
// Might be, but not "trivial" so just giving the safe answer.
ty::Adt(..) | ty::Closure(..) => false,
@@ -2929,6 +2934,37 @@ impl<'tcx> Ty<'tcx> {
_ => false,
}
}
+
+ /// Returns `true` when the outermost type cannot be further normalized,
+ /// resolved, or substituted. This includes all primitive types, but also
+ /// things like ADTs and trait objects, sice even if their arguments or
+ /// nested types may be further simplified, the outermost [`TyKind`] or
+ /// type constructor remains the same.
+ pub fn is_known_rigid(self) -> bool {
+ match self.kind() {
+ Bool
+ | Char
+ | Int(_)
+ | Uint(_)
+ | Float(_)
+ | Adt(_, _)
+ | Foreign(_)
+ | Str
+ | Array(_, _)
+ | Slice(_)
+ | RawPtr(_)
+ | Ref(_, _, _)
+ | FnDef(_, _)
+ | FnPtr(_)
+ | Dynamic(_, _, _)
+ | Closure(_, _)
+ | Generator(_, _, _)
+ | GeneratorWitness(..)
+ | Never
+ | Tuple(_) => true,
+ Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false,
+ }
+ }
}
/// Extra information about why we ended up with a particular variance.
@@ -2974,7 +3010,7 @@ mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
// tidy-alphabetical-start
- static_assert_size!(RegionKind<'_>, 28);
+ static_assert_size!(RegionKind<'_>, 24);
static_assert_size!(TyKind<'_>, 32);
// tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6e55e7915..bf9b24493 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -90,6 +90,10 @@ pub struct TraitImpls {
}
impl TraitImpls {
+ pub fn is_empty(&self) -> bool {
+ self.blanket_impls.is_empty() && self.non_blanket_impls.is_empty()
+ }
+
pub fn blanket_impls(&self) -> &[DefId] {
self.blanket_impls.as_slice()
}
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 327cd0a5d..a44224e4d 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -165,7 +165,7 @@ pub struct TypeckResults<'tcx> {
/// reading places that are mentioned in a closure (because of _ patterns). However,
/// to ensure the places are initialized, we introduce fake reads.
/// Consider these two examples:
- /// ``` (discriminant matching with only wildcard arm)
+ /// ```ignore (discriminant matching with only wildcard arm)
/// let x: u8;
/// let c = || match x { _ => () };
/// ```
@@ -173,7 +173,7 @@ pub struct TypeckResults<'tcx> {
/// want to capture it. However, we do still want an error here, because `x` should have
/// to be initialized at the point where c is created. Therefore, we add a "fake read"
/// instead.
- /// ``` (destructured assignments)
+ /// ```ignore (destructured assignments)
/// let c = || {
/// let (t1, t2) = t;
/// }
@@ -189,10 +189,6 @@ pub struct TypeckResults<'tcx> {
/// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
pub rvalue_scopes: RvalueScopes,
- /// Stores the type, expression, span and optional scope span of all types
- /// that are live across the yield of this generator (if a generator).
- pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-
/// Stores the predicates that apply on generator witness types.
/// formatting modified file tests/ui/generator/retain-resume-ref.rs
pub generator_interior_predicates:
@@ -212,49 +208,6 @@ pub struct TypeckResults<'tcx> {
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
}
-/// Whenever a value may be live across a generator yield, the type of that value winds up in the
-/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
-/// captured types that can be useful for diagnostics. In particular, it stores the span that
-/// caused a given type to be recorded, along with the scope that enclosed the value (which can
-/// be used to find the await that the value is live across).
-///
-/// For example:
-///
-/// ```ignore (pseudo-Rust)
-/// async move {
-/// let x: T = expr;
-/// foo.await
-/// ...
-/// }
-/// ```
-///
-/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
-/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
-#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct GeneratorInteriorTypeCause<'tcx> {
- /// Type of the captured binding.
- pub ty: Ty<'tcx>,
- /// Span of the binding that was captured.
- pub span: Span,
- /// Span of the scope of the captured binding.
- pub scope_span: Option<Span>,
- /// Span of `.await` or `yield` expression.
- pub yield_span: Span,
- /// Expr which the type evaluated from.
- pub expr: Option<hir::HirId>,
-}
-
-// This type holds diagnostic information on generators and async functions across crate boundaries
-// and is used to provide better error messages
-#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
-pub struct GeneratorDiagnosticData<'tcx> {
- pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
- pub hir_owner: DefId,
- pub nodes_types: ItemLocalMap<Ty<'tcx>>,
- pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-}
-
impl<'tcx> TypeckResults<'tcx> {
pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
TypeckResults {
@@ -278,7 +231,6 @@ impl<'tcx> TypeckResults<'tcx> {
closure_min_captures: Default::default(),
closure_fake_reads: Default::default(),
rvalue_scopes: Default::default(),
- generator_interior_types: ty::Binder::dummy(Default::default()),
generator_interior_predicates: Default::default(),
treat_byte_string_as_slice: Default::default(),
closure_size_eval: Default::default(),
@@ -351,28 +303,6 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
}
- pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
- let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
- vec.iter()
- .map(|item| {
- GeneratorInteriorTypeCause {
- ty: item.ty,
- span: item.span,
- scope_span: item.scope_span,
- yield_span: item.yield_span,
- expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
- }
- })
- .collect::<Vec<_>>()
- });
- GeneratorDiagnosticData {
- generator_interior_types: generator_interior_type,
- hir_owner: self.hir_owner.to_def_id(),
- nodes_types: self.node_types.clone(),
- adjustments: self.adjustments.clone(),
- }
- }
-
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
self.node_type_opt(id).unwrap_or_else(|| {
bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id)))
@@ -654,7 +584,7 @@ rustc_index::newtype_index! {
pub type CanonicalUserTypeAnnotations<'tcx> =
IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct CanonicalUserTypeAnnotation<'tcx> {
pub user_ty: Box<CanonicalUserType<'tcx>>,
pub span: Span,
@@ -714,7 +644,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum UserType<'tcx> {
Ty(Ty<'tcx>),
@@ -722,3 +652,14 @@ pub enum UserType<'tcx> {
/// given substitutions applied.
TypeOf(DefId, UserArgs<'tcx>),
}
+
+impl<'tcx> std::fmt::Display for UserType<'tcx> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Ty(arg0) => {
+ ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0))
+ }
+ Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1),
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 564f982f8..964f38a65 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -156,7 +156,7 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::Enum
| DefKind::Trait
| DefKind::OpaqueTy
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
@@ -855,7 +855,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
let hidden_ty = bty.instantiate(self.tcx, args);
self.fold_ty(hidden_ty);
}
- let expanded_ty = Ty::new_generator_witness_mir(self.tcx, def_id, args);
+ let expanded_ty = Ty::new_generator_witness(self.tcx, def_id, args);
self.expanded_cache.insert((def_id, args), expanded_ty);
expanded_ty
}
@@ -888,7 +888,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
t
};
if self.expand_generators {
- if let ty::GeneratorWitnessMIR(def_id, args) = *t.kind() {
+ if let ty::GeneratorWitness(def_id, args) = *t.kind() {
t = self.expand_generator(def_id, args).unwrap_or(t);
}
}
@@ -1025,8 +1025,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..)
| ty::Foreign(_)
| ty::Generator(..)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..)
+ | ty::GeneratorWitness(..)
| ty::Infer(_)
| ty::Alias(..)
| ty::Param(_)
@@ -1065,8 +1064,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Dynamic(..)
| ty::Foreign(_)
| ty::Generator(..)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..)
+ | ty::GeneratorWitness(..)
| ty::Infer(_)
| ty::Alias(..)
| ty::Param(_)
@@ -1099,8 +1097,10 @@ impl<'tcx> Ty<'tcx> {
// This doesn't depend on regions, so try to minimize distinct
// query keys used.
// If normalization fails, we just use `query_ty`.
- let query_ty =
- tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
+ debug_assert!(!param_env.has_infer());
+ let query_ty = tcx
+ .try_normalize_erasing_regions(param_env, query_ty)
+ .unwrap_or_else(|_| tcx.erase_regions(query_ty));
tcx.needs_drop_raw(param_env.and(query_ty))
}
@@ -1194,10 +1194,7 @@ impl<'tcx> Ty<'tcx> {
false
}
- ty::Foreign(_)
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
- | ty::Error(_) => false,
+ ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
}
}
@@ -1292,8 +1289,6 @@ pub fn needs_drop_components<'tcx>(
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Char
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str => Ok(SmallVec::new()),
@@ -1333,7 +1328,8 @@ pub fn needs_drop_components<'tcx>(
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Closure(..)
- | ty::Generator(..) => Ok(smallvec![ty]),
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..) => Ok(smallvec![ty]),
}
}
@@ -1364,11 +1360,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
// Not trivial because they have components, and instead of looking inside,
// we'll just perform trait selection.
- ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..)
- | ty::Adt(..) => false,
+ ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | ty::Adt(..) => false,
ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 156eda477..95ba6c471 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -33,14 +33,6 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
- // N.B. Even though this uses a visitor, the visitor does not actually
- // recurse through the whole `TypeVisitable` implementor type.
- //
- // Instead it stops on the first "level", visiting types, regions,
- // consts and predicates just fetches their type flags.
- //
- // Thus this is a lot faster than it might seem and should be
- // optimized to a simple field access.
let res =
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
trace!(?self, ?flags, ?res, "has_type_flags");
@@ -485,11 +477,36 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
}
}
+// Note: this visitor traverses values down to the level of
+// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
+// type flags at the outer layer are enough. So it's faster than it first
+// looks, particular for `Ty`/`Predicate` where it's just a field access.
+//
+// N.B. The only case where this isn't totally true is binders, which also
+// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
+// are present, regardless of whether those bound variables are used. This
+// is important for anonymization of binders in `TyCtxt::erase_regions`. We
+// specifically detect this case in `visit_binder`.
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
type BreakTy = FoundFlags;
+ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ // If we're looking for the HAS_BINDER_VARS flag, check if the
+ // binder has vars. This won't be present in the binder's bound
+ // value, so we need to check here too.
+ if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
+ return ControlFlow::Break(FoundFlags);
+ }
+
+ t.super_visit_with(self)
+ }
+
#[inline]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // Note: no `super_visit_with` call.
let flags = t.flags();
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
@@ -500,6 +517,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
#[inline]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // Note: no `super_visit_with` call, as usual for `Region`.
let flags = r.type_flags();
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
@@ -510,6 +528,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
#[inline]
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // Note: no `super_visit_with` call.
let flags = FlagComputation::for_const(c);
trace!(r.flags=?flags);
if flags.intersects(self.flags) {
@@ -521,6 +540,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // Note: no `super_visit_with` call.
if predicate.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 97402caa0..62f41921d 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -84,7 +84,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
let scalar = match entry {
VtblEntry::MetadataDropInPlace => {
let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
- let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
let fn_ptr = Pointer::from(fn_alloc_id);
Scalar::from_pointer(fn_ptr, &tcx)
}
@@ -94,7 +94,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
VtblEntry::Method(instance) => {
// Prepare the fn ptr we write into the vtable.
let instance = instance.polymorphize(tcx);
- let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
let fn_ptr = Pointer::from(fn_alloc_id);
Scalar::from_pointer(fn_ptr, &tcx)
}
@@ -112,5 +112,5 @@ pub(super) fn vtable_allocation_provider<'tcx>(
}
vtable.mutability = Mutability::Not;
- tcx.create_memory_alloc(tcx.mk_const_alloc(vtable))
+ tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(vtable))
}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 7c3d9ed39..a86ff64bd 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -190,14 +190,11 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
ty::Adt(_, args)
| ty::Closure(_, args)
| ty::Generator(_, args, _)
- | ty::GeneratorWitnessMIR(_, args)
+ | ty::GeneratorWitness(_, args)
| ty::FnDef(_, args) => {
stack.extend(args.iter().rev());
}
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
- ty::GeneratorWitness(ts) => {
- stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into()));
- }
ty::FnPtr(sig) => {
stack.push(sig.skip_binder().output().into());
stack.extend(sig.skip_binder().inputs().iter().copied().rev().map(|ty| ty.into()));
diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
index 1b845334c..9f1e4ac11 100644
--- a/compiler/rustc_middle/src/util/find_self_call.rs
+++ b/compiler/rustc_middle/src/util/find_self_call.rs
@@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>(
&body[block].terminator
{
debug!("find_self_call: func={:?}", func);
- if let Operand::Constant(box Constant { literal, .. }) = func {
- if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() {
+ if let Operand::Constant(box ConstOperand { const_, .. }) = func {
+ if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() {
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
{
diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs
index 53b425789..8c9598847 100644
--- a/compiler/rustc_middle/src/util/mod.rs
+++ b/compiler/rustc_middle/src/util/mod.rs
@@ -5,3 +5,27 @@ pub mod find_self_call;
pub use call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use find_self_call::find_self_call;
+
+#[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,
+}
+
+/// Backwards compatibility hack to keep the diff small. This
+/// gives direct access to the `queries` field's fields, which
+/// are what almost everything wants access to.
+impl std::ops::DerefMut for Providers {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.queries
+ }
+}
+
+impl std::ops::Deref for Providers {
+ type Target = rustc_middle::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 384a36843..578d8e7a9 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -1,4 +1,5 @@
-use crate::dep_graph::DepKind;
+use crate::dep_graph::dep_kinds;
+use crate::query::plumbing::CyclePlaceholder;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir as hir;
@@ -8,20 +9,26 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_query_system::query::QueryInfo;
use rustc_query_system::Value;
use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
use std::fmt::Write;
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
- unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) }
+ unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
}
}
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+ fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
+ Err(CyclePlaceholder(guar))
+ }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
@@ -32,12 +39,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
}
}
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
- let err = Ty::new_misc_error(tcx);
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
+ let err = Ty::new_error(tcx, guar);
let arity = if let Some(frame) = stack.get(0)
- && frame.query.dep_kind == DepKind::fn_sig
+ && 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(sig) = node.fn_sig()
@@ -62,12 +69,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
}
}
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
let mut item_and_field_ids = Vec::new();
let mut representable_ids = FxHashSet::default();
for info in cycle {
- if info.query.dep_kind == DepKind::representability
+ if info.query.dep_kind == dep_kinds::representability
&& let Some(field_id) = info.query.def_id
&& let Some(field_id) = field_id.as_local()
&& let Some(DefKind::Field) = info.query.def_kind
@@ -81,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
}
}
for info in cycle {
- if info.query.dep_kind == DepKind::representability_adt_ty
+ if info.query.dep_kind == dep_kinds::representability_adt_ty
&& let Some(def_id) = info.query.ty_adt_id
&& let Some(def_id) = def_id.as_local()
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
@@ -94,23 +101,24 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
}
}
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
- ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle))
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
+ ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
}
}
-impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
- ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle))
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
+ ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
}
}
-impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
- fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
+impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
+ fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
// tcx.arena.alloc is pretty much equal to leaking).
+ // FIXME: `Cycle` should carry the ErrorGuaranteed
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
}
}
@@ -209,7 +217,7 @@ fn find_item_ty_spans(
match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
if let Res::Def(kind, def_id) = path.res
- && !matches!(kind, DefKind::TyAlias { .. }) {
+ && !matches!(kind, DefKind::TyAlias) {
let check_params = def_id.as_local().map_or(true, |def_id| {
if def_id == needle {
spans.push(ty.span);