mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #115252 - cjgillot:mir-composite, r=davidtwco
Represent MIR composite debuginfo as projections instead of aggregates Composite debuginfo for MIR is currently represented as ``` debug name => Type { projection1 => place1, projection2 => place2 }; ``` ie. a single `VarDebugInfo` object with that name, and its value a `VarDebugInfoContents::Composite`. This PR proposes to reverse the representation to be ``` debug name.projection1 => place1; debug name.projection2 => place2; ``` ie. multiple `VarDebugInfo` objects with each their projection. This simplifies the handling of composite debuginfo by the compiler by avoiding weird nesting. Based on https://github.com/rust-lang/rust/pull/115139
This commit is contained in:
commit
a5b2ac6906
@ -484,54 +484,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
|
let var_ty = if let Some(ref fragment) = var.composite {
|
||||||
let (var_ty, var_kind) = match var.value {
|
self.monomorphize(fragment.ty)
|
||||||
|
} else {
|
||||||
|
match var.value {
|
||||||
mir::VarDebugInfoContents::Place(place) => {
|
mir::VarDebugInfoContents::Place(place) => {
|
||||||
let var_ty = self.monomorphized_place_ty(place.as_ref());
|
self.monomorphized_place_ty(place.as_ref())
|
||||||
let var_kind = if let Some(arg_index) = var.argument_index
|
}
|
||||||
&& place.projection.is_empty()
|
mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
|
||||||
{
|
}
|
||||||
let arg_index = arg_index as usize;
|
};
|
||||||
if target_is_msvc {
|
|
||||||
// ScalarPair parameters are spilled to the stack so they need to
|
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
|
||||||
// be marked as a `LocalVariable` for MSVC debuggers to visualize
|
let var_kind = if let Some(arg_index) = var.argument_index
|
||||||
// their data correctly. (See #81894 & #88625)
|
&& var.composite.is_none()
|
||||||
let var_ty_layout = self.cx.layout_of(var_ty);
|
&& let mir::VarDebugInfoContents::Place(place) = var.value
|
||||||
if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
|
&& place.projection.is_empty()
|
||||||
VariableKind::LocalVariable
|
{
|
||||||
} else {
|
let arg_index = arg_index as usize;
|
||||||
VariableKind::ArgumentVariable(arg_index)
|
if target_is_msvc {
|
||||||
}
|
// ScalarPair parameters are spilled to the stack so they need to
|
||||||
} else {
|
// be marked as a `LocalVariable` for MSVC debuggers to visualize
|
||||||
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
|
// their data correctly. (See #81894 & #88625)
|
||||||
// offset in closures to account for the hidden environment?
|
let var_ty_layout = self.cx.layout_of(var_ty);
|
||||||
VariableKind::ArgumentVariable(arg_index)
|
if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VariableKind::LocalVariable
|
VariableKind::LocalVariable
|
||||||
};
|
} else {
|
||||||
(var_ty, var_kind)
|
VariableKind::ArgumentVariable(arg_index)
|
||||||
}
|
}
|
||||||
mir::VarDebugInfoContents::Const(c) => {
|
} else {
|
||||||
let ty = self.monomorphize(c.ty());
|
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
|
||||||
(ty, VariableKind::LocalVariable)
|
// offset in closures to account for the hidden environment?
|
||||||
}
|
VariableKind::ArgumentVariable(arg_index)
|
||||||
mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
|
|
||||||
let ty = self.monomorphize(ty);
|
|
||||||
(ty, VariableKind::LocalVariable)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
VariableKind::LocalVariable
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
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 {
|
match var.value {
|
||||||
mir::VarDebugInfoContents::Place(place) => {
|
mir::VarDebugInfoContents::Place(place) => {
|
||||||
per_local[place.local].push(PerLocalVarDebugInfo {
|
per_local[place.local].push(PerLocalVarDebugInfo {
|
||||||
name: var.name,
|
name: var.name,
|
||||||
source_info: var.source_info,
|
source_info: var.source_info,
|
||||||
dbg_var,
|
dbg_var,
|
||||||
fragment: None,
|
fragment,
|
||||||
projection: place.projection,
|
projection: place.projection,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -547,53 +582,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
bx,
|
bx,
|
||||||
);
|
);
|
||||||
|
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
|
bx.dbg_var_addr(
|
||||||
|
dbg_var,
|
||||||
|
dbg_loc,
|
||||||
|
base.llval,
|
||||||
|
Size::ZERO,
|
||||||
|
&[],
|
||||||
|
fragment,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(per_local)
|
Some(per_local)
|
||||||
|
@ -6,13 +6,7 @@ use rustc_index::IndexVec;
|
|||||||
use rustc_infer::traits::Reveal;
|
use rustc_infer::traits::Reveal;
|
||||||
use rustc_middle::mir::interpret::Scalar;
|
use rustc_middle::mir::interpret::Scalar;
|
||||||
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::{
|
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::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
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>) {
|
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
|
||||||
let check_place = |this: &mut Self, place: Place<'_>| {
|
if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite {
|
||||||
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
|
if ty.is_union() || ty.is_enum() {
|
||||||
this.fail(
|
self.fail(
|
||||||
START_BLOCK.start_location(),
|
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 {
|
match debuginfo.value {
|
||||||
VarDebugInfoContents::Const(_) => {}
|
VarDebugInfoContents::Const(_) => {}
|
||||||
VarDebugInfoContents::Place(place) => {
|
VarDebugInfoContents::Place(place) => {
|
||||||
check_place(self, place);
|
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
|
||||||
}
|
self.fail(
|
||||||
VarDebugInfoContents::Composite { ty, ref fragments } => {
|
START_BLOCK.start_location(),
|
||||||
for f in fragments {
|
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
|
||||||
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
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1028,19 +1028,6 @@ pub enum VarDebugInfoContents<'tcx> {
|
|||||||
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||||
Place(Place<'tcx>),
|
Place(Place<'tcx>),
|
||||||
Const(Constant<'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>>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
@ -1048,19 +1035,16 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
|||||||
match self {
|
match self {
|
||||||
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
|
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
|
||||||
VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
|
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> {
|
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,
|
/// Where in the composite user variable this fragment is,
|
||||||
/// represented as a "projection" into the composite variable.
|
/// represented as a "projection" into the composite variable.
|
||||||
/// At lower levels, this corresponds to a byte/bit range.
|
/// 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
|
// to match on the discriminant, or by using custom type debuginfo
|
||||||
// with non-overlapping variants for the composite variable.
|
// with non-overlapping variants for the composite variable.
|
||||||
pub projection: Vec<PlaceElem<'tcx>>,
|
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.
|
/// 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 struct VarDebugInfo<'tcx> {
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
|
|
||||||
@ -1102,6 +1067,13 @@ pub struct VarDebugInfo<'tcx> {
|
|||||||
/// (see `LocalDecl`'s `source_info` field for more details).
|
/// (see `LocalDecl`'s `source_info` field for more details).
|
||||||
pub source_info: SourceInfo,
|
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.
|
/// Where the data for this user variable is to be found.
|
||||||
pub value: VarDebugInfoContents<'tcx>,
|
pub value: VarDebugInfoContents<'tcx>,
|
||||||
|
|
||||||
@ -1111,6 +1083,20 @@ pub struct VarDebugInfo<'tcx> {
|
|||||||
pub argument_index: Option<u16>,
|
pub argument_index: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// BasicBlock
|
||||||
|
|
||||||
@ -1575,7 +1561,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||||||
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
|
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
|
||||||
pub type ProjectionKind = ProjectionElem<(), ()>;
|
pub type ProjectionKind = ProjectionElem<(), ()>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct PlaceRef<'tcx> {
|
pub struct PlaceRef<'tcx> {
|
||||||
pub local: Local,
|
pub local: Local,
|
||||||
pub projection: &'tcx [PlaceElem<'tcx>],
|
pub projection: &'tcx [PlaceElem<'tcx>],
|
||||||
@ -1753,69 +1739,83 @@ impl<'tcx> PlaceRef<'tcx> {
|
|||||||
|
|
||||||
impl Debug for Place<'_> {
|
impl Debug for Place<'_> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
for elem in self.projection.iter().rev() {
|
self.as_ref().fmt(fmt)
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::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::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
|
// Scopes
|
||||||
|
|
||||||
@ -3056,6 +3056,6 @@ mod size_asserts {
|
|||||||
static_assert_size!(StatementKind<'_>, 16);
|
static_assert_size!(StatementKind<'_>, 16);
|
||||||
static_assert_size!(Terminator<'_>, 104);
|
static_assert_size!(Terminator<'_>, 104);
|
||||||
static_assert_size!(TerminatorKind<'_>, 88);
|
static_assert_size!(TerminatorKind<'_>, 88);
|
||||||
static_assert_size!(VarDebugInfo<'_>, 80);
|
static_assert_size!(VarDebugInfo<'_>, 88);
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
@ -554,10 +554,7 @@ fn write_scope_tree(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let indented_debug_info = format!(
|
let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info);
|
||||||
"{0:1$}debug {2} => {3:?};",
|
|
||||||
INDENT, indent, var_debug_info.name, var_debug_info.value,
|
|
||||||
);
|
|
||||||
|
|
||||||
if tcx.sess.opts.unstable_opts.mir_include_spans {
|
if tcx.sess.opts.unstable_opts.mir_include_spans {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -838,12 +838,20 @@ macro_rules! make_mir_visitor {
|
|||||||
let VarDebugInfo {
|
let VarDebugInfo {
|
||||||
name: _,
|
name: _,
|
||||||
source_info,
|
source_info,
|
||||||
|
composite,
|
||||||
value,
|
value,
|
||||||
argument_index: _,
|
argument_index: _,
|
||||||
} = var_debug_info;
|
} = var_debug_info;
|
||||||
|
|
||||||
self.visit_source_info(source_info);
|
self.visit_source_info(source_info);
|
||||||
let location = Location::START;
|
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 {
|
match value {
|
||||||
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
|
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
|
||||||
VarDebugInfoContents::Place(place) =>
|
VarDebugInfoContents::Place(place) =>
|
||||||
@ -852,17 +860,6 @@ macro_rules! make_mir_visitor {
|
|||||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
location
|
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +241,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||||||
let dbginfo = VarDebugInfo {
|
let dbginfo = VarDebugInfo {
|
||||||
name,
|
name,
|
||||||
source_info: SourceInfo { span, scope: self.source_scope },
|
source_info: SourceInfo { span, scope: self.source_scope },
|
||||||
|
composite: None,
|
||||||
argument_index: None,
|
argument_index: None,
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
|
@ -2287,6 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
name,
|
name,
|
||||||
source_info: debug_source_info,
|
source_info: debug_source_info,
|
||||||
value: VarDebugInfoContents::Place(for_arm_body.into()),
|
value: VarDebugInfoContents::Place(for_arm_body.into()),
|
||||||
|
composite: None,
|
||||||
argument_index: None,
|
argument_index: None,
|
||||||
});
|
});
|
||||||
let locals = if has_guard.0 {
|
let locals = if has_guard.0 {
|
||||||
@ -2306,6 +2307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
name,
|
name,
|
||||||
source_info: debug_source_info,
|
source_info: debug_source_info,
|
||||||
value: VarDebugInfoContents::Place(ref_for_guard.into()),
|
value: VarDebugInfoContents::Place(ref_for_guard.into()),
|
||||||
|
composite: None,
|
||||||
argument_index: None,
|
argument_index: None,
|
||||||
});
|
});
|
||||||
LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
|
LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
|
||||||
|
@ -823,6 +823,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
name,
|
name,
|
||||||
source_info: SourceInfo::outermost(captured_place.var_ident.span),
|
source_info: SourceInfo::outermost(captured_place.var_ident.span),
|
||||||
value: VarDebugInfoContents::Place(use_place),
|
value: VarDebugInfoContents::Place(use_place),
|
||||||
|
composite: None,
|
||||||
argument_index: None,
|
argument_index: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -852,6 +853,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
name,
|
name,
|
||||||
source_info,
|
source_info,
|
||||||
value: VarDebugInfoContents::Place(arg_local.into()),
|
value: VarDebugInfoContents::Place(arg_local.into()),
|
||||||
|
composite: None,
|
||||||
argument_index: Some(argument_index as u16 + 1),
|
argument_index: Some(argument_index as u16 + 1),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
|||||||
var_debug_info.value = VarDebugInfoContents::Const(self.make_zst(place_ty))
|
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
|
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||||
use rustc_index::bit_set::{BitSet, GrowableBitSet};
|
use rustc_index::bit_set::{BitSet, GrowableBitSet};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir::patch::MirPatch;
|
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
|
// We ignore anything that happens in debuginfo, since we expand it using
|
||||||
// `VarDebugInfoContents::Composite`.
|
// `VarDebugInfoFragment`.
|
||||||
fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {}
|
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() {
|
for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() {
|
||||||
visitor.visit_user_type_annotation(index, annotation);
|
visitor.visit_user_type_annotation(index, annotation);
|
||||||
}
|
}
|
||||||
for var_debug_info in &mut body.var_debug_info {
|
visitor.expand_var_debug_info(&mut body.var_debug_info);
|
||||||
visitor.visit_var_debug_info(var_debug_info);
|
|
||||||
}
|
|
||||||
let ReplacementVisitor { patch, all_dead_locals, .. } = visitor;
|
let ReplacementVisitor { patch, all_dead_locals, .. } = visitor;
|
||||||
patch.apply(body);
|
patch.apply(body);
|
||||||
all_dead_locals
|
all_dead_locals
|
||||||
@ -256,7 +255,7 @@ fn replace_flattened_locals<'tcx>(
|
|||||||
|
|
||||||
struct ReplacementVisitor<'tcx, 'll> {
|
struct ReplacementVisitor<'tcx, 'll> {
|
||||||
tcx: TyCtxt<'tcx>,
|
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>,
|
local_decls: &'ll LocalDecls<'tcx>,
|
||||||
/// Work to do.
|
/// Work to do.
|
||||||
replacements: &'ll ReplacementMap<'tcx>,
|
replacements: &'ll ReplacementMap<'tcx>,
|
||||||
@ -266,16 +265,38 @@ struct ReplacementVisitor<'tcx, 'll> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ReplacementVisitor<'tcx, '_> {
|
impl<'tcx> ReplacementVisitor<'tcx, '_> {
|
||||||
fn gather_debug_info_fragments(&self, local: Local) -> Option<Vec<VarDebugInfoFragment<'tcx>>> {
|
#[instrument(level = "trace", skip(self))]
|
||||||
let mut fragments = Vec::new();
|
fn expand_var_debug_info(&mut self, var_debug_info: &mut Vec<VarDebugInfo<'tcx>>) {
|
||||||
let parts = self.replacements.place_fragments(local.into())?;
|
var_debug_info.flat_map_in_place(|mut var_debug_info| {
|
||||||
for (field, ty, replacement_local) in parts {
|
let place = match var_debug_info.value {
|
||||||
fragments.push(VarDebugInfoFragment {
|
VarDebugInfoContents::Const(_) => return vec![var_debug_info],
|
||||||
projection: vec![PlaceElem::Field(field, ty)],
|
VarDebugInfoContents::Place(ref mut place) => place,
|
||||||
contents: Place::from(replacement_local),
|
};
|
||||||
});
|
|
||||||
}
|
if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) {
|
||||||
Some(fragments)
|
*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)
|
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) {
|
fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
|
||||||
assert!(!self.all_dead_locals.contains(*local));
|
assert!(!self.all_dead_locals.contains(*local));
|
||||||
}
|
}
|
||||||
|
@ -33,14 +33,22 @@
|
|||||||
let _15: bool;
|
let _15: bool;
|
||||||
let _16: u32;
|
let _16: u32;
|
||||||
scope 6 {
|
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<u16>;
|
let _10: std::option::Option<u16>;
|
||||||
scope 7 {
|
scope 7 {
|
||||||
debug o => _10;
|
debug o => _10;
|
||||||
let _17: u32;
|
let _17: u32;
|
||||||
let _18: u32;
|
let _18: u32;
|
||||||
scope 8 {
|
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;
|
let _11: u32;
|
||||||
scope 9 {
|
scope 9 {
|
||||||
- debug a => _11;
|
- debug a => _11;
|
||||||
|
@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
|
|||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
|
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
|
||||||
debug self => _1;
|
debug self => _1;
|
||||||
debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
|
debug ((index: std::ops::Range<usize>).0: usize) => _3;
|
||||||
|
debug ((index: std::ops::Range<usize>).1: usize) => _4;
|
||||||
let mut _5: *mut [u32];
|
let mut _5: *mut [u32];
|
||||||
let mut _13: *mut [u32];
|
let mut _13: *mut [u32];
|
||||||
scope 2 {
|
scope 2 {
|
||||||
scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
|
scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
|
||||||
debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
|
debug ((self: std::ops::Range<usize>).0: usize) => _3;
|
||||||
|
debug ((self: std::ops::Range<usize>).1: usize) => _4;
|
||||||
debug slice => _5;
|
debug slice => _5;
|
||||||
let mut _7: *mut u32;
|
let mut _7: *mut u32;
|
||||||
let mut _8: *mut u32;
|
let mut _8: *mut u32;
|
||||||
let _15: usize;
|
let _15: usize;
|
||||||
let _16: usize;
|
let _16: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
|
debug ((this: std::ops::Range<usize>).0: usize) => _15;
|
||||||
|
debug ((this: std::ops::Range<usize>).1: usize) => _16;
|
||||||
scope 5 {
|
scope 5 {
|
||||||
let _6: usize;
|
let _6: usize;
|
||||||
scope 6 {
|
scope 6 {
|
||||||
@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
|
scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
|
||||||
debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
|
debug ((this: std::ops::Range<usize>).0: usize) => _15;
|
||||||
|
debug ((this: std::ops::Range<usize>).1: usize) => _16;
|
||||||
debug slice => _5;
|
debug slice => _5;
|
||||||
scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
|
scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
|
||||||
debug self => _5;
|
debug self => _5;
|
||||||
|
@ -8,19 +8,22 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
|
|||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
|
scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
|
||||||
debug self => _1;
|
debug self => _1;
|
||||||
debug index => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
|
debug ((index: std::ops::Range<usize>).0: usize) => _3;
|
||||||
|
debug ((index: std::ops::Range<usize>).1: usize) => _4;
|
||||||
let mut _5: *mut [u32];
|
let mut _5: *mut [u32];
|
||||||
let mut _13: *mut [u32];
|
let mut _13: *mut [u32];
|
||||||
scope 2 {
|
scope 2 {
|
||||||
scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
|
scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
|
||||||
debug self => std::ops::Range<usize>{ .0 => _3, .1 => _4, };
|
debug ((self: std::ops::Range<usize>).0: usize) => _3;
|
||||||
|
debug ((self: std::ops::Range<usize>).1: usize) => _4;
|
||||||
debug slice => _5;
|
debug slice => _5;
|
||||||
let mut _7: *mut u32;
|
let mut _7: *mut u32;
|
||||||
let mut _8: *mut u32;
|
let mut _8: *mut u32;
|
||||||
let _15: usize;
|
let _15: usize;
|
||||||
let _16: usize;
|
let _16: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
|
debug ((this: std::ops::Range<usize>).0: usize) => _15;
|
||||||
|
debug ((this: std::ops::Range<usize>).1: usize) => _16;
|
||||||
scope 5 {
|
scope 5 {
|
||||||
let _6: usize;
|
let _6: usize;
|
||||||
scope 6 {
|
scope 6 {
|
||||||
@ -53,7 +56,8 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
|
scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) {
|
||||||
debug this => std::ops::Range<usize>{ .0 => _15, .1 => _16, };
|
debug ((this: std::ops::Range<usize>).0: usize) => _15;
|
||||||
|
debug ((this: std::ops::Range<usize>).1: usize) => _16;
|
||||||
debug slice => _5;
|
debug slice => _5;
|
||||||
scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
|
scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) {
|
||||||
debug self => _5;
|
debug self => _5;
|
||||||
|
@ -33,7 +33,8 @@
|
|||||||
+ let _32: u32;
|
+ let _32: u32;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
- debug foo => _1;
|
- debug foo => _1;
|
||||||
+ debug foo => Foo<T>{ .0 => _31, .1 => _32, };
|
+ debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _31;
|
||||||
|
+ debug ((foo: Foo<T>).1: u32) => _32;
|
||||||
let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
|
let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug x => _5;
|
debug x => _5;
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
+ let _5: u8;
|
+ let _5: u8;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
- debug y => _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;
|
let _2: usize;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug t => _2;
|
debug t => _2;
|
||||||
|
@ -11,7 +11,10 @@
|
|||||||
+ let _14: std::option::Option<isize>;
|
+ let _14: std::option::Option<isize>;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
- debug y => _2;
|
- 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<isize>) => _14;
|
||||||
let _3: u8;
|
let _3: u8;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug t => _3;
|
debug t => _3;
|
||||||
@ -25,7 +28,10 @@
|
|||||||
+ let _10: std::option::Option<isize>;
|
+ let _10: std::option::Option<isize>;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
- debug z => _5;
|
- 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<isize>) => _10;
|
||||||
let _6: ();
|
let _6: ();
|
||||||
scope 5 {
|
scope 5 {
|
||||||
debug a => _6;
|
debug a => _6;
|
||||||
|
@ -11,7 +11,10 @@
|
|||||||
+ let _8: std::option::Option<isize>;
|
+ let _8: std::option::Option<isize>;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
- debug y => _2;
|
- 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<isize>) => _8;
|
||||||
let _3: u8;
|
let _3: u8;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug t => _3;
|
debug t => _3;
|
||||||
|
Loading…
Reference in New Issue
Block a user