Skip to content

Commit 26c48e6

Browse files
committed
Refactor how MIR represents composite debuginfo.
1 parent 429a925 commit 26c48e6

17 files changed

+223
-244
lines changed

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+77-78
Original file line numberDiff line numberDiff line change
@@ -484,54 +484,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
484484
None
485485
};
486486

487-
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
488-
let (var_ty, var_kind) = match var.value {
487+
let var_ty = if let Some(ref fragment) = var.composite {
488+
self.monomorphize(fragment.ty)
489+
} else {
490+
match var.value {
489491
mir::VarDebugInfoContents::Place(place) => {
490-
let var_ty = self.monomorphized_place_ty(place.as_ref());
491-
let var_kind = if let Some(arg_index) = var.argument_index
492-
&& place.projection.is_empty()
493-
{
494-
let arg_index = arg_index as usize;
495-
if target_is_msvc {
496-
// ScalarPair parameters are spilled to the stack so they need to
497-
// be marked as a `LocalVariable` for MSVC debuggers to visualize
498-
// their data correctly. (See #81894 & #88625)
499-
let var_ty_layout = self.cx.layout_of(var_ty);
500-
if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
501-
VariableKind::LocalVariable
502-
} else {
503-
VariableKind::ArgumentVariable(arg_index)
504-
}
505-
} else {
506-
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
507-
// offset in closures to account for the hidden environment?
508-
VariableKind::ArgumentVariable(arg_index)
509-
}
510-
} else {
511-
VariableKind::LocalVariable
512-
};
513-
(var_ty, var_kind)
492+
self.monomorphized_place_ty(place.as_ref())
514493
}
515-
mir::VarDebugInfoContents::Const(c) => {
516-
let ty = self.monomorphize(c.ty());
517-
(ty, VariableKind::LocalVariable)
518-
}
519-
mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
520-
let ty = self.monomorphize(ty);
521-
(ty, VariableKind::LocalVariable)
494+
mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
495+
}
496+
};
497+
498+
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
499+
let var_kind = if let Some(arg_index) = var.argument_index
500+
&& var.composite.is_none()
501+
&& let mir::VarDebugInfoContents::Place(place) = var.value
502+
&& place.projection.is_empty()
503+
{
504+
let arg_index = arg_index as usize;
505+
if target_is_msvc {
506+
// ScalarPair parameters are spilled to the stack so they need to
507+
// be marked as a `LocalVariable` for MSVC debuggers to visualize
508+
// their data correctly. (See #81894 & #88625)
509+
let var_ty_layout = self.cx.layout_of(var_ty);
510+
if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
511+
VariableKind::LocalVariable
512+
} else {
513+
VariableKind::ArgumentVariable(arg_index)
514+
}
515+
} else {
516+
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
517+
// offset in closures to account for the hidden environment?
518+
VariableKind::ArgumentVariable(arg_index)
522519
}
520+
} else {
521+
VariableKind::LocalVariable
523522
};
524523

525524
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
526525
});
527526

527+
let fragment = if let Some(ref fragment) = var.composite {
528+
let var_layout = self.cx.layout_of(var_ty);
529+
530+
let mut fragment_start = Size::ZERO;
531+
let mut fragment_layout = var_layout;
532+
533+
for elem in &fragment.projection {
534+
match *elem {
535+
mir::ProjectionElem::Field(field, _) => {
536+
let i = field.index();
537+
fragment_start += fragment_layout.fields.offset(i);
538+
fragment_layout = fragment_layout.field(self.cx, i);
539+
}
540+
_ => span_bug!(
541+
var.source_info.span,
542+
"unsupported fragment projection `{:?}`",
543+
elem,
544+
),
545+
}
546+
}
547+
548+
if fragment_layout.size == Size::ZERO {
549+
// Fragment is a ZST, so does not represent anything. Avoid generating anything
550+
// as this may conflict with a fragment that covers the entire variable.
551+
continue;
552+
} else if fragment_layout.size == var_layout.size {
553+
// Fragment covers entire variable, so as far as
554+
// DWARF is concerned, it's not really a fragment.
555+
None
556+
} else {
557+
Some(fragment_start..fragment_start + fragment_layout.size)
558+
}
559+
} else {
560+
None
561+
};
562+
528563
match var.value {
529564
mir::VarDebugInfoContents::Place(place) => {
530565
per_local[place.local].push(PerLocalVarDebugInfo {
531566
name: var.name,
532567
source_info: var.source_info,
533568
dbg_var,
534-
fragment: None,
569+
fragment,
535570
projection: place.projection,
536571
});
537572
}
@@ -547,51 +582,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
547582
bx,
548583
);
549584

550-
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
551-
}
552-
}
553-
}
554-
mir::VarDebugInfoContents::Composite { ty, ref fragments } => {
555-
let var_ty = self.monomorphize(ty);
556-
let var_layout = self.cx.layout_of(var_ty);
557-
for fragment in fragments {
558-
let mut fragment_start = Size::ZERO;
559-
let mut fragment_layout = var_layout;
560-
561-
for elem in &fragment.projection {
562-
match *elem {
563-
mir::ProjectionElem::Field(field, _) => {
564-
let i = field.index();
565-
fragment_start += fragment_layout.fields.offset(i);
566-
fragment_layout = fragment_layout.field(self.cx, i);
567-
}
568-
_ => span_bug!(
569-
var.source_info.span,
570-
"unsupported fragment projection `{:?}`",
571-
elem,
572-
),
573-
}
585+
bx.dbg_var_addr(
586+
dbg_var,
587+
dbg_loc,
588+
base.llval,
589+
Size::ZERO,
590+
&[],
591+
fragment,
592+
);
574593
}
575-
576-
let place = fragment.contents;
577-
let fragment = if fragment_layout.size == Size::ZERO {
578-
// Fragment is a ZST, so does not represent anything.
579-
continue;
580-
} else if fragment_layout.size == var_layout.size {
581-
// Fragment covers entire variable, so as far as
582-
// DWARF is concerned, it's not really a fragment.
583-
None
584-
} else {
585-
Some(fragment_start..fragment_start + fragment_layout.size)
586-
};
587-
588-
per_local[place.local].push(PerLocalVarDebugInfo {
589-
name: var.name,
590-
source_info: var.source_info,
591-
dbg_var,
592-
fragment,
593-
projection: place.projection,
594-
});
595594
}
596595
}
597596
}

compiler/rustc_const_eval/src/transform/validate.rs

+26-32
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@ use rustc_index::IndexVec;
66
use rustc_infer::traits::Reveal;
77
use rustc_middle::mir::interpret::Scalar;
88
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
9-
use rustc_middle::mir::{
10-
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
11-
MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
12-
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
13-
Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo,
14-
VarDebugInfoContents, START_BLOCK,
15-
};
9+
use rustc_middle::mir::*;
1610
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
1711
use rustc_mir_dataflow::impls::MaybeStorageLive;
1812
use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -757,37 +751,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
757751
}
758752

759753
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
760-
let check_place = |this: &mut Self, place: Place<'_>| {
761-
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
762-
this.fail(
754+
if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite {
755+
if ty.is_union() || ty.is_enum() {
756+
self.fail(
763757
START_BLOCK.start_location(),
764-
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
758+
format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name),
765759
);
766760
}
767-
};
761+
if projection.is_empty() {
762+
self.fail(
763+
START_BLOCK.start_location(),
764+
format!("invalid empty projection in debuginfo for {:?}", debuginfo.name),
765+
);
766+
}
767+
if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
768+
self.fail(
769+
START_BLOCK.start_location(),
770+
format!(
771+
"illegal projection {:?} in debuginfo for {:?}",
772+
projection, debuginfo.name
773+
),
774+
);
775+
}
776+
}
768777
match debuginfo.value {
769778
VarDebugInfoContents::Const(_) => {}
770779
VarDebugInfoContents::Place(place) => {
771-
check_place(self, place);
772-
}
773-
VarDebugInfoContents::Composite { ty, ref fragments } => {
774-
for f in fragments {
775-
check_place(self, f.contents);
776-
if ty.is_union() || ty.is_enum() {
777-
self.fail(
778-
START_BLOCK.start_location(),
779-
format!("invalid type {ty:?} for composite debuginfo"),
780-
);
781-
}
782-
if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
783-
self.fail(
784-
START_BLOCK.start_location(),
785-
format!(
786-
"illegal projection {:?} in debuginfo for {:?}",
787-
f.projection, debuginfo.name
788-
),
789-
);
790-
}
780+
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
781+
self.fail(
782+
START_BLOCK.start_location(),
783+
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
784+
);
791785
}
792786
}
793787
}

compiler/rustc_middle/src/mir/mod.rs

+28-42
Original file line numberDiff line numberDiff line change
@@ -1028,39 +1028,23 @@ pub enum VarDebugInfoContents<'tcx> {
10281028
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
10291029
Place(Place<'tcx>),
10301030
Const(Constant<'tcx>),
1031-
/// The user variable's data is split across several fragments,
1032-
/// each described by a `VarDebugInfoFragment`.
1033-
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
1034-
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
1035-
/// the underlying debuginfo feature this relies on.
1036-
Composite {
1037-
/// Type of the original user variable.
1038-
/// This cannot contain a union or an enum.
1039-
ty: Ty<'tcx>,
1040-
/// All the parts of the original user variable, which ended
1041-
/// up in disjoint places, due to optimizations.
1042-
fragments: Vec<VarDebugInfoFragment<'tcx>>,
1043-
},
10441031
}
10451032

10461033
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
10471034
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
10481035
match self {
10491036
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
10501037
VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
1051-
VarDebugInfoContents::Composite { ty, fragments } => {
1052-
write!(fmt, "{ty:?}{{ ")?;
1053-
for f in fragments.iter() {
1054-
write!(fmt, "{f:?}, ")?;
1055-
}
1056-
write!(fmt, "}}")
1057-
}
10581038
}
10591039
}
10601040
}
10611041

1062-
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
1042+
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
10631043
pub struct VarDebugInfoFragment<'tcx> {
1044+
/// Type of the original user variable.
1045+
/// This cannot contain a union or an enum.
1046+
pub ty: Ty<'tcx>,
1047+
10641048
/// Where in the composite user variable this fragment is,
10651049
/// represented as a "projection" into the composite variable.
10661050
/// At lower levels, this corresponds to a byte/bit range.
@@ -1071,29 +1055,10 @@ pub struct VarDebugInfoFragment<'tcx> {
10711055
// to match on the discriminant, or by using custom type debuginfo
10721056
// with non-overlapping variants for the composite variable.
10731057
pub projection: Vec<PlaceElem<'tcx>>,
1074-
1075-
/// Where the data for this fragment can be found.
1076-
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
1077-
pub contents: Place<'tcx>,
1078-
}
1079-
1080-
impl Debug for VarDebugInfoFragment<'_> {
1081-
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1082-
for elem in self.projection.iter() {
1083-
match elem {
1084-
ProjectionElem::Field(field, _) => {
1085-
write!(fmt, ".{:?}", field.index())?;
1086-
}
1087-
_ => bug!("unsupported fragment projection `{:?}`", elem),
1088-
}
1089-
}
1090-
1091-
write!(fmt, " => {:?}", self.contents)
1092-
}
10931058
}
10941059

10951060
/// Debug information pertaining to a user variable.
1096-
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
1061+
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
10971062
pub struct VarDebugInfo<'tcx> {
10981063
pub name: Symbol,
10991064

@@ -1102,6 +1067,13 @@ pub struct VarDebugInfo<'tcx> {
11021067
/// (see `LocalDecl`'s `source_info` field for more details).
11031068
pub source_info: SourceInfo,
11041069

1070+
/// The user variable's data is split across several fragments,
1071+
/// each described by a `VarDebugInfoFragment`.
1072+
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
1073+
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
1074+
/// the underlying debuginfo feature this relies on.
1075+
pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>,
1076+
11051077
/// Where the data for this user variable is to be found.
11061078
pub value: VarDebugInfoContents<'tcx>,
11071079

@@ -1111,6 +1083,20 @@ pub struct VarDebugInfo<'tcx> {
11111083
pub argument_index: Option<u16>,
11121084
}
11131085

1086+
impl Debug for VarDebugInfo<'_> {
1087+
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1088+
if let Some(box VarDebugInfoFragment { ty, ref projection }) = self.composite {
1089+
pre_fmt_projection(&projection[..], fmt)?;
1090+
write!(fmt, "({}: {})", self.name, ty)?;
1091+
post_fmt_projection(&projection[..], fmt)?;
1092+
} else {
1093+
write!(fmt, "{}", self.name)?;
1094+
}
1095+
1096+
write!(fmt, " => {:?}", self.value)
1097+
}
1098+
}
1099+
11141100
///////////////////////////////////////////////////////////////////////////
11151101
// BasicBlock
11161102

@@ -3070,6 +3056,6 @@ mod size_asserts {
30703056
static_assert_size!(StatementKind<'_>, 16);
30713057
static_assert_size!(Terminator<'_>, 104);
30723058
static_assert_size!(TerminatorKind<'_>, 88);
3073-
static_assert_size!(VarDebugInfo<'_>, 80);
3059+
static_assert_size!(VarDebugInfo<'_>, 88);
30743060
// tidy-alphabetical-end
30753061
}

compiler/rustc_middle/src/mir/pretty.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -554,10 +554,7 @@ fn write_scope_tree(
554554
continue;
555555
}
556556

557-
let indented_debug_info = format!(
558-
"{0:1$}debug {2} => {3:?};",
559-
INDENT, indent, var_debug_info.name, var_debug_info.value,
560-
);
557+
let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info);
561558

562559
if tcx.sess.opts.unstable_opts.mir_include_spans {
563560
writeln!(

0 commit comments

Comments
 (0)