diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
commit | 5363f350887b1e5b5dd21a86f88c8af9d7fea6da (patch) | |
tree | 35ca005eb6e0e9a1ba3bb5dbc033209ad445dc17 /compiler/rustc_middle/src/mir/mod.rs | |
parent | Adding debian version 1.66.0+dfsg1-1. (diff) | |
download | rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.tar.xz rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/mir/mod.rs')
-rw-r--r-- | compiler/rustc_middle/src/mir/mod.rs | 178 |
1 files changed, 130 insertions, 48 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 79db35a76..a513444e1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -10,7 +10,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; -use crate::ty::{self, List, Ty, TyCtxt}; +use crate::ty::{self, DefIdTree, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; @@ -100,13 +100,9 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { /// 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`. pub trait MirPass<'tcx> { - fn name(&self) -> Cow<'_, str> { + fn name(&self) -> &str { let name = std::any::type_name::<Self>(); - if let Some(tail) = name.rfind(':') { - Cow::from(&name[tail + 1..]) - } else { - Cow::from(name) - } + if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } /// Returns `true` if this pass is enabled with the current combination of compiler flags. @@ -138,33 +134,46 @@ impl MirPhase { } } } -} -impl Display for MirPhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - MirPhase::Built => write!(f, "built"), - MirPhase::Analysis(p) => write!(f, "analysis-{}", p), - MirPhase::Runtime(p) => write!(f, "runtime-{}", p), + /// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason. + pub fn parse(dialect: String, phase: Option<String>) -> Self { + match &*dialect.to_ascii_lowercase() { + "built" => { + assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR"); + MirPhase::Built + } + "analysis" => Self::Analysis(AnalysisPhase::parse(phase)), + "runtime" => Self::Runtime(RuntimePhase::parse(phase)), + _ => panic!("Unknown MIR dialect {}", dialect), } } } -impl Display for AnalysisPhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - AnalysisPhase::Initial => write!(f, "initial"), - AnalysisPhase::PostCleanup => write!(f, "post_cleanup"), +impl AnalysisPhase { + pub fn parse(phase: Option<String>) -> Self { + let Some(phase) = phase else { + return Self::Initial; + }; + + match &*phase.to_ascii_lowercase() { + "initial" => Self::Initial, + "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, + _ => panic!("Unknown analysis phase {}", phase), } } } -impl Display for RuntimePhase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - RuntimePhase::Initial => write!(f, "initial"), - RuntimePhase::PostCleanup => write!(f, "post_cleanup"), - RuntimePhase::Optimized => write!(f, "optimized"), +impl RuntimePhase { + pub fn parse(phase: Option<String>) -> Self { + let Some(phase) = phase else { + return Self::Initial; + }; + + match &*phase.to_ascii_lowercase() { + "initial" => Self::Initial, + "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, + "optimized" => Self::Optimized, + _ => panic!("Unknown runtime phase {}", phase), } } } @@ -293,6 +302,13 @@ pub struct Body<'tcx> { /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this. pub is_polymorphic: bool, + /// The phase at which this MIR should be "injected" into the compilation process. + /// + /// Everything that comes before this `MirPhase` should be skipped. + /// + /// This is only `Some` if the function that this body comes from was annotated with `rustc_custom_mir`. + pub injection_phase: Option<MirPhase>, + pub tainted_by_errors: Option<ErrorGuaranteed>, } @@ -319,7 +335,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, - pass_count: 1, + pass_count: 0, source, basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, @@ -339,6 +355,7 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), is_polymorphic: false, + injection_phase: None, tainted_by_errors, }; body.is_polymorphic = body.has_non_region_param(); @@ -353,7 +370,7 @@ impl<'tcx> Body<'tcx> { pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { let mut body = Body { phase: MirPhase::Built, - pass_count: 1, + pass_count: 0, source: MirSource::item(CRATE_DEF_ID.to_def_id()), basic_blocks: BasicBlocks::new(basic_blocks), source_scopes: IndexVec::new(), @@ -366,6 +383,7 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), var_debug_info: Vec::new(), is_polymorphic: false, + injection_phase: None, tainted_by_errors: None, }; body.is_polymorphic = body.has_non_region_param(); @@ -508,6 +526,14 @@ impl<'tcx> Body<'tcx> { pub fn generator_kind(&self) -> Option<GeneratorKind> { self.generator.as_ref().map(|generator| generator.generator_kind) } + + #[inline] + pub fn should_skip(&self) -> bool { + let Some(injection_phase) = self.injection_phase else { + return false; + }; + injection_phase > self.phase + } } #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] @@ -1012,6 +1038,18 @@ pub enum VarDebugInfoContents<'tcx> { /// based on a `Local`, not a `Static`, and contains no indexing. 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. + ty: Ty<'tcx>, + /// All the parts of the original user variable, which ended + /// up in disjoint places, due to optimizations. + fragments: Vec<VarDebugInfoFragment<'tcx>>, + }, } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { @@ -1019,7 +1057,48 @@ 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)] +pub struct VarDebugInfoFragment<'tcx> { + /// Where in the composite user variable this fragment is, + /// represented as a "projection" into the composite variable. + /// At lower levels, this corresponds to a byte/bit range. + // NOTE(eddyb) there's an unenforced invariant that this contains + // only `Field`s, and not into `enum` variants or `union`s. + // FIXME(eddyb) support this for `enum`s by either using DWARF's + // more advanced control-flow features (unsupported by LLVM?) + // to match on the discriminant, or by using custom type debuginfo + // with non-overlapping variants for the composite variable. + pub projection: Vec<PlaceElem<'tcx>>, + + /// Where the data for this fragment can be found. + // NOTE(eddyb) There's an unenforced invariant that this `Place` is + // contains no indexing (with a non-constant index). + 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) } } @@ -1186,6 +1265,11 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { if index < self.statements.len() { &self.statements[index] } else { &self.terminator } } + + /// Does the block have no statements and an unreachable terminator? + pub fn is_empty_unreachable(&self) -> bool { + self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) + } } impl<O> AssertKind<O> { @@ -1477,7 +1561,7 @@ impl<'tcx> Place<'tcx> { /// If MirPhase >= Derefered and if projection contains Deref, /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { - // To make sure this is not accidently used in wrong mir phase + // To make sure this is not accidentally used in wrong mir phase debug_assert!( self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) ); @@ -1767,7 +1851,7 @@ impl<'tcx> Operand<'tcx> { substs: SubstsRef<'tcx>, span: Span, ) -> Self { - let ty = tcx.bound_type_of(def_id).subst(tcx, substs); + let ty = tcx.mk_fn_def(def_id, substs); Operand::Constant(Box::new(Constant { span, user_ty: None, @@ -1893,6 +1977,7 @@ impl BorrowKind { } } + // FIXME: won't be used after diagnostic migration pub fn describe_mutability(&self) -> &str { match *self { BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", @@ -1997,10 +2082,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { .print_def_path(variant_def.def_id, substs)? .into_buffer(); - match variant_def.ctor_kind { - CtorKind::Const => fmt.write_str(&name), - CtorKind::Fn => fmt_tuple(fmt, &name), - CtorKind::Fictive => { + 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); @@ -2186,8 +2271,10 @@ impl<'tcx> ConstantKind<'tcx> { // 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 | ErrorHandled::Linted) => self, - Err(_) => Self::Ty(tcx.const_error(ty)), + Err(ErrorHandled::TooGeneric) => self, + Err(ErrorHandled::Reported(guar)) => { + Self::Ty(tcx.const_error_with_guaranteed(ty, guar)) + } } } } @@ -2403,16 +2490,11 @@ impl<'tcx> ConstantKind<'tcx> { 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 hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id.to_def_id()); + 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.hir().name(hir_id); - let ty_const = tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)), - ty, - }); + let name = tcx.item_name(def_id); + let ty_const = tcx.mk_const(ty::ParamConst::new(index, name), ty); debug!(?ty_const); return Self::Ty(ty_const); @@ -2839,14 +2921,14 @@ fn pretty_print_const_value<'tcx>( let cx = cx.print_value_path(variant_def.def_id, substs)?; fmt.write_str(&cx.into_buffer())?; - match variant_def.ctor_kind { - CtorKind::Const => {} - CtorKind::Fn => { + match variant_def.ctor_kind() { + Some(CtorKind::Const) => {} + Some(CtorKind::Fn) => { fmt.write_str("(")?; comma_sep(fmt, fields)?; fmt.write_str(")")?; } - CtorKind::Fictive => { + None => { fmt.write_str(" {{ ")?; let mut first = true; for (field_def, field) in iter::zip(&variant_def.fields, fields) |