From 429a9258f10936c3b36b8b265175efbcbdfba1d5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 31 Aug 2023 18:56:34 +0000 Subject: [PATCH 1/2] Refactor projection debug. --- compiler/rustc_middle/src/mir/mod.rs | 124 +++++++++++++++------------ 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6484c30167cb3..18ae6bbc7a155 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1575,7 +1575,7 @@ impl ProjectionElem { /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct PlaceRef<'tcx> { pub local: Local, pub projection: &'tcx [PlaceElem<'tcx>], @@ -1753,67 +1753,81 @@ impl<'tcx> PlaceRef<'tcx> { 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 { .. } => {} - } - } + 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) + } +} - 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:?}]")?; - } +fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result { + for &elem in 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 { .. } => {} } + } - Ok(()) + 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::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(()) } /////////////////////////////////////////////////////////////////////////// From 26c48e6f95c4075951a21d54cf1e61af68cbb5e0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Aug 2023 16:58:42 +0000 Subject: [PATCH 2/2] Refactor how MIR represents composite debuginfo. --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 155 +++++++++--------- .../src/transform/validate.rs | 58 +++---- compiler/rustc_middle/src/mir/mod.rs | 70 ++++---- compiler/rustc_middle/src/mir/pretty.rs | 5 +- compiler/rustc_middle/src/mir/visit.rs | 19 +-- .../rustc_mir_build/src/build/custom/parse.rs | 1 + .../rustc_mir_build/src/build/matches/mod.rs | 2 + compiler/rustc_mir_build/src/build/mod.rs | 2 + .../rustc_mir_transform/src/remove_zsts.rs | 5 - compiler/rustc_mir_transform/src/sroa.rs | 93 ++++------- .../const_debuginfo.main.ConstDebugInfo.diff | 12 +- ...mut_range.PreCodegen.after.panic-abort.mir | 12 +- ...ut_range.PreCodegen.after.panic-unwind.mir | 12 +- ...mes.foo.ScalarReplacementOfAggregates.diff | 3 +- ...onstant.ScalarReplacementOfAggregates.diff | 3 +- ....copies.ScalarReplacementOfAggregates.diff | 10 +- ..._copies.ScalarReplacementOfAggregates.diff | 5 +- 17 files changed, 223 insertions(+), 244 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 526c16a59ded0..7cd9efe3ee2d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -484,54 +484,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None }; - let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let var_ty = if let Some(ref fragment) = var.composite { + self.monomorphize(fragment.ty) + } else { + match var.value { mir::VarDebugInfoContents::Place(place) => { - let var_ty = self.monomorphized_place_ty(place.as_ref()); - let var_kind = if let Some(arg_index) = var.argument_index - && place.projection.is_empty() - { - let arg_index = arg_index as usize; - if target_is_msvc { - // ScalarPair parameters are spilled to the stack so they need to - // be marked as a `LocalVariable` for MSVC debuggers to visualize - // their data correctly. (See #81894 & #88625) - let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { - VariableKind::LocalVariable - } else { - VariableKind::ArgumentVariable(arg_index) - } - } else { - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - VariableKind::ArgumentVariable(arg_index) - } - } else { - VariableKind::LocalVariable - }; - (var_ty, var_kind) + self.monomorphized_place_ty(place.as_ref()) } - mir::VarDebugInfoContents::Const(c) => { - let ty = self.monomorphize(c.ty()); - (ty, VariableKind::LocalVariable) - } - mir::VarDebugInfoContents::Composite { ty, fragments: _ } => { - let ty = self.monomorphize(ty); - (ty, VariableKind::LocalVariable) + mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()), + } + }; + + let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { + let var_kind = if let Some(arg_index) = var.argument_index + && var.composite.is_none() + && let mir::VarDebugInfoContents::Place(place) = var.value + && place.projection.is_empty() + { + let arg_index = arg_index as usize; + if target_is_msvc { + // ScalarPair parameters are spilled to the stack so they need to + // be marked as a `LocalVariable` for MSVC debuggers to visualize + // their data correctly. (See #81894 & #88625) + let var_ty_layout = self.cx.layout_of(var_ty); + if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + VariableKind::LocalVariable + } else { + VariableKind::ArgumentVariable(arg_index) + } + } else { + // FIXME(eddyb) shouldn't `ArgumentVariable` indices be + // offset in closures to account for the hidden environment? + VariableKind::ArgumentVariable(arg_index) } + } else { + VariableKind::LocalVariable }; self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); + let fragment = if let Some(ref fragment) = var.composite { + let var_layout = self.cx.layout_of(var_ty); + + let mut fragment_start = Size::ZERO; + let mut fragment_layout = var_layout; + + for elem in &fragment.projection { + match *elem { + mir::ProjectionElem::Field(field, _) => { + let i = field.index(); + fragment_start += fragment_layout.fields.offset(i); + fragment_layout = fragment_layout.field(self.cx, i); + } + _ => span_bug!( + var.source_info.span, + "unsupported fragment projection `{:?}`", + elem, + ), + } + } + + if fragment_layout.size == Size::ZERO { + // Fragment is a ZST, so does not represent anything. Avoid generating anything + // as this may conflict with a fragment that covers the entire variable. + continue; + } else if fragment_layout.size == var_layout.size { + // Fragment covers entire variable, so as far as + // DWARF is concerned, it's not really a fragment. + None + } else { + Some(fragment_start..fragment_start + fragment_layout.size) + } + } else { + None + }; + match var.value { mir::VarDebugInfoContents::Place(place) => { per_local[place.local].push(PerLocalVarDebugInfo { name: var.name, source_info: var.source_info, dbg_var, - fragment: None, + fragment, projection: place.projection, }); } @@ -547,51 +582,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, ); - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None); - } - } - } - mir::VarDebugInfoContents::Composite { ty, ref fragments } => { - let var_ty = self.monomorphize(ty); - let var_layout = self.cx.layout_of(var_ty); - for fragment in fragments { - let mut fragment_start = Size::ZERO; - let mut fragment_layout = var_layout; - - for elem in &fragment.projection { - match *elem { - mir::ProjectionElem::Field(field, _) => { - let i = field.index(); - fragment_start += fragment_layout.fields.offset(i); - fragment_layout = fragment_layout.field(self.cx, i); - } - _ => span_bug!( - var.source_info.span, - "unsupported fragment projection `{:?}`", - elem, - ), - } + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.llval, + Size::ZERO, + &[], + fragment, + ); } - - let place = fragment.contents; - let fragment = if fragment_layout.size == Size::ZERO { - // Fragment is a ZST, so does not represent anything. - continue; - } else if fragment_layout.size == var_layout.size { - // Fragment covers entire variable, so as far as - // DWARF is concerned, it's not really a fragment. - None - } else { - Some(fragment_start..fragment_start + fragment_layout.size) - }; - - per_local[place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - fragment, - projection: place.projection, - }); } } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 770c3f7f02c01..2f5f2ad6534ad 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -6,13 +6,7 @@ use rustc_index::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{ - traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, - MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef, - ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, - Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo, - VarDebugInfoContents, START_BLOCK, -}; +use rustc_middle::mir::*; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -757,37 +751,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { - let check_place = |this: &mut Self, place: Place<'_>| { - if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { - this.fail( + if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite { + if ty.is_union() || ty.is_enum() { + self.fail( START_BLOCK.start_location(), - format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name), ); } - }; + if projection.is_empty() { + self.fail( + START_BLOCK.start_location(), + format!("invalid empty projection in debuginfo for {:?}", debuginfo.name), + ); + } + if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { + self.fail( + START_BLOCK.start_location(), + format!( + "illegal projection {:?} in debuginfo for {:?}", + projection, debuginfo.name + ), + ); + } + } match debuginfo.value { VarDebugInfoContents::Const(_) => {} VarDebugInfoContents::Place(place) => { - check_place(self, place); - } - VarDebugInfoContents::Composite { ty, ref fragments } => { - for f in fragments { - check_place(self, f.contents); - if ty.is_union() || ty.is_enum() { - self.fail( - START_BLOCK.start_location(), - format!("invalid type {ty:?} for composite debuginfo"), - ); - } - if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { - self.fail( - START_BLOCK.start_location(), - format!( - "illegal projection {:?} in debuginfo for {:?}", - f.projection, debuginfo.name - ), - ); - } + if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { + self.fail( + START_BLOCK.start_location(), + format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + ); } } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 18ae6bbc7a155..239d20ae1b09c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1028,19 +1028,6 @@ 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>, - }, } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { @@ -1048,19 +1035,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 +1055,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>, - - /// 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 +1067,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>>, + /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents<'tcx>, @@ -1111,6 +1083,20 @@ pub struct VarDebugInfo<'tcx> { pub argument_index: Option, } +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) + } +} + /////////////////////////////////////////////////////////////////////////// // BasicBlock @@ -3070,6 +3056,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/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 773056e8a1799..488526edb430d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -554,10 +554,7 @@ fn write_scope_tree( continue; } - let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, - ); + let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info); if tcx.sess.opts.unstable_opts.mir_include_spans { writeln!( diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 87b04aabe6a39..61244b942893e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -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, - ); - } - } } } diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index f83c62fd580b8..e2ab2cb90c72f 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -241,6 +241,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { let dbginfo = VarDebugInfo { name, source_info: SourceInfo { span, scope: self.source_scope }, + composite: None, argument_index: None, value, }; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5ec216cea616b..7e81c8b50c2d0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2287,6 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(for_arm_body.into()), + composite: None, argument_index: None, }); let locals = if has_guard.0 { @@ -2306,6 +2307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: debug_source_info, value: VarDebugInfoContents::Place(ref_for_guard.into()), + composite: None, argument_index: None, }); LocalsForNode::ForGuard { ref_for_guard, for_arm_body } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e614046e83e71..4e10916ad61ef 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -823,6 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), + composite: None, argument_index: None, }); @@ -852,6 +853,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info, value: VarDebugInfoContents::Place(arg_local.into()), + composite: None, argument_index: Some(argument_index as u16 + 1), }); } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 9c6c55b0811f7..c13bafa9fbb5b 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -87,11 +87,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty)) } } - VarDebugInfoContents::Composite { ty, fragments: _ } => { - if self.known_to_be_zst(ty) { - var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(ty)) - } - } } } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index e66ae8ff8845f..c21b1724cbb67 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,4 +1,5 @@ use crate::MirPass; +use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; use rustc_middle::mir::patch::MirPatch; @@ -147,7 +148,7 @@ fn escaping_locals<'tcx>( } // We ignore anything that happens in debuginfo, since we expand it using - // `VarDebugInfoContents::Composite`. + // `VarDebugInfoFragment`. fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {} } } @@ -246,9 +247,7 @@ fn replace_flattened_locals<'tcx>( for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() { visitor.visit_user_type_annotation(index, annotation); } - for var_debug_info in &mut body.var_debug_info { - visitor.visit_var_debug_info(var_debug_info); - } + visitor.expand_var_debug_info(&mut body.var_debug_info); let ReplacementVisitor { patch, all_dead_locals, .. } = visitor; patch.apply(body); all_dead_locals @@ -256,7 +255,7 @@ fn replace_flattened_locals<'tcx>( struct ReplacementVisitor<'tcx, 'll> { tcx: TyCtxt<'tcx>, - /// This is only used to compute the type for `VarDebugInfoContents::Composite`. + /// This is only used to compute the type for `VarDebugInfoFragment`. local_decls: &'ll LocalDecls<'tcx>, /// Work to do. replacements: &'ll ReplacementMap<'tcx>, @@ -266,16 +265,38 @@ struct ReplacementVisitor<'tcx, 'll> { } impl<'tcx> ReplacementVisitor<'tcx, '_> { - fn gather_debug_info_fragments(&self, local: Local) -> Option>> { - let mut fragments = Vec::new(); - let parts = self.replacements.place_fragments(local.into())?; - for (field, ty, replacement_local) in parts { - fragments.push(VarDebugInfoFragment { - projection: vec![PlaceElem::Field(field, ty)], - contents: Place::from(replacement_local), - }); - } - Some(fragments) + #[instrument(level = "trace", skip(self))] + fn expand_var_debug_info(&mut self, var_debug_info: &mut Vec>) { + var_debug_info.flat_map_in_place(|mut var_debug_info| { + let place = match var_debug_info.value { + VarDebugInfoContents::Const(_) => return vec![var_debug_info], + VarDebugInfoContents::Place(ref mut place) => place, + }; + + if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { + *place = repl; + return vec![var_debug_info]; + } + + let Some(parts) = self.replacements.place_fragments(*place) else { + return vec![var_debug_info]; + }; + + let ty = place.ty(self.local_decls, self.tcx).ty; + + parts + .map(|(field, field_ty, replacement_local)| { + let mut var_debug_info = var_debug_info.clone(); + let composite = var_debug_info.composite.get_or_insert_with(|| { + Box::new(VarDebugInfoFragment { ty, projection: Vec::new() }) + }); + composite.projection.push(PlaceElem::Field(field, field_ty)); + + var_debug_info.value = VarDebugInfoContents::Place(replacement_local.into()); + var_debug_info + }) + .collect() + }); } } @@ -422,48 +443,6 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.super_statement(statement, location) } - #[instrument(level = "trace", skip(self))] - fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { - match &mut var_debug_info.value { - VarDebugInfoContents::Place(ref mut place) => { - if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { - *place = repl; - } else if let Some(local) = place.as_local() - && let Some(fragments) = self.gather_debug_info_fragments(local) - { - let ty = place.ty(self.local_decls, self.tcx).ty; - var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; - } - } - VarDebugInfoContents::Composite { ty: _, ref mut fragments } => { - let mut new_fragments = Vec::new(); - debug!(?fragments); - fragments.retain_mut(|fragment| { - if let Some(repl) = - self.replacements.replace_place(self.tcx, fragment.contents.as_ref()) - { - fragment.contents = repl; - true - } else if let Some(local) = fragment.contents.as_local() - && let Some(frg) = self.gather_debug_info_fragments(local) - { - new_fragments.extend(frg.into_iter().map(|mut f| { - f.projection.splice(0..0, fragment.projection.iter().copied()); - f - })); - false - } else { - true - } - }); - debug!(?fragments); - debug!(?new_fragments); - fragments.extend(new_fragments); - } - VarDebugInfoContents::Const(_) => {} - } - } - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { assert!(!self.all_dead_locals.contains(*local)); } diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index 255ec94816c3e..ed47baa67daba 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -33,14 +33,22 @@ let _15: bool; let _16: u32; scope 6 { - debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; +- debug ((f: (bool, bool, u32)).0: bool) => _14; +- debug ((f: (bool, bool, u32)).1: bool) => _15; +- debug ((f: (bool, bool, u32)).2: u32) => _16; ++ debug ((f: (bool, bool, u32)).0: bool) => const true; ++ debug ((f: (bool, bool, u32)).1: bool) => const false; ++ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; let _10: std::option::Option; scope 7 { debug o => _10; let _17: u32; let _18: u32; scope 8 { - debug p => Point{ .0 => _17, .1 => _18, }; +- debug ((p: Point).0: u32) => _17; +- debug ((p: Point).1: u32) => _18; ++ debug ((p: Point).0: u32) => const 32_u32; ++ debug ((p: Point).1: u32) => const 32_u32; let _11: u32; scope 9 { - debug a => _11; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 8dd2cd7900f3f..2fd669aeeb61d 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { debug self => _1; - debug index => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range).0: usize) => _3; + debug ((index: std::ops::Range).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range).0: usize) => _3; + debug ((self: std::ops::Range).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::::len) { debug self => _5; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 8dd2cd7900f3f..2fd669aeeb61d 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { debug self => _1; - debug index => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((index: std::ops::Range).0: usize) => _3; + debug ((index: std::ops::Range).1: usize) => _4; let mut _5: *mut [u32]; let mut _13: *mut [u32]; scope 2 { scope 3 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { - debug self => std::ops::Range{ .0 => _3, .1 => _4, }; + debug ((self: std::ops::Range).0: usize) => _3; + debug ((self: std::ops::Range).1: usize) => _4; debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; let _15: usize; let _16: usize; scope 4 { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; scope 5 { let _6: usize; scope 6 { @@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } } scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug this => std::ops::Range{ .0 => _15, .1 => _16, }; + debug ((this: std::ops::Range).0: usize) => _15; + debug ((this: std::ops::Range).1: usize) => _16; debug slice => _5; scope 8 (inlined ptr::mut_ptr::::len) { debug self => _5; diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index bb14b909a956c..b020d1baafa16 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -33,7 +33,8 @@ + let _32: u32; scope 1 { - debug foo => _1; -+ debug foo => Foo{ .0 => _31, .1 => _32, }; ++ debug ((foo: Foo).0: std::result::Result, ::Err>) => _31; ++ debug ((foo: Foo).1: u32) => _32; let _5: std::result::Result, ::Err>; scope 2 { debug x => _5; diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff index 7ee0431692c1d..1330f9b3ac80d 100644 --- a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff @@ -8,7 +8,8 @@ + let _5: u8; scope 1 { - debug y => _1; -+ debug y => (usize, u8){ .0 => _4, .1 => _5, }; ++ debug ((y: (usize, u8)).0: usize) => _4; ++ debug ((y: (usize, u8)).1: u8) => _5; let _2: usize; scope 2 { debug t => _2; diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff index 0a1de891aee42..3621338635ed7 100644 --- a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _14: std::option::Option; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; ++ debug ((y: Foo).0: u8) => _11; ++ debug ((y: Foo).1: ()) => _12; ++ debug ((y: Foo).2: &str) => _13; ++ debug ((y: Foo).3: std::option::Option) => _14; let _3: u8; scope 2 { debug t => _3; @@ -25,7 +28,10 @@ + let _10: std::option::Option; scope 4 { - debug z => _5; -+ debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; ++ debug ((z: Foo).0: u8) => _7; ++ debug ((z: Foo).1: ()) => _8; ++ debug ((z: Foo).2: &str) => _9; ++ debug ((z: Foo).3: std::option::Option) => _10; let _6: (); scope 5 { debug a => _6; diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff index d7c57c293c4a9..304bf2fb1a765 100644 --- a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff @@ -11,7 +11,10 @@ + let _8: std::option::Option; scope 1 { - debug y => _2; -+ debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; ++ debug ((y: Foo).0: u8) => _5; ++ debug ((y: Foo).1: ()) => _6; ++ debug ((y: Foo).2: &str) => _7; ++ debug ((y: Foo).3: std::option::Option) => _8; let _3: u8; scope 2 { debug t => _3;