Skip to content

Commit ed17b59

Browse files
Rollup merge of #109901 - cjgillot:validate-debuginfo, r=b-naber
Enforce VarDebugInfo::Place in MIR validation.
2 parents 4d32de6 + a84909c commit ed17b59

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,15 @@ fn calculate_debuginfo_offset<
165165
mir::ProjectionElem::Downcast(_, variant) => {
166166
place = place.downcast(bx, variant);
167167
}
168-
_ => span_bug!(
169-
var.source_info.span,
170-
"unsupported var debuginfo place `{:?}`",
171-
mir::Place { local, projection: var.projection },
172-
),
168+
_ => {
169+
// Sanity check for `can_use_in_debuginfo`.
170+
debug_assert!(!elem.can_use_in_debuginfo());
171+
span_bug!(
172+
var.source_info.span,
173+
"unsupported var debuginfo place `{:?}`",
174+
mir::Place { local, projection: var.projection },
175+
)
176+
}
173177
}
174178
}
175179

compiler/rustc_const_eval/src/transform/validate.rs

+39-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ use rustc_index::bit_set::BitSet;
55
use rustc_index::vec::IndexVec;
66
use rustc_infer::traits::Reveal;
77
use rustc_middle::mir::interpret::Scalar;
8-
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
9-
use rustc_middle::mir::visit::{PlaceContext, Visitor};
8+
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
109
use rustc_middle::mir::{
1110
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
1211
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
1312
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
14-
TerminatorKind, UnOp, START_BLOCK,
13+
TerminatorKind, UnOp, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
1514
};
1615
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
1716
use rustc_mir_dataflow::impls::MaybeStorageLive;
@@ -419,13 +418,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
419418
self.super_projection_elem(local, proj_base, elem, context, location);
420419
}
421420

421+
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
422+
let check_place = |place: Place<'_>| {
423+
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
424+
self.fail(
425+
START_BLOCK.start_location(),
426+
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
427+
);
428+
}
429+
};
430+
match debuginfo.value {
431+
VarDebugInfoContents::Const(_) => {}
432+
VarDebugInfoContents::Place(place) => check_place(place),
433+
VarDebugInfoContents::Composite { ty, ref fragments } => {
434+
for f in fragments {
435+
check_place(f.contents);
436+
if ty.is_union() || ty.is_enum() {
437+
self.fail(
438+
START_BLOCK.start_location(),
439+
format!("invalid type {:?} for composite debuginfo", ty),
440+
);
441+
}
442+
if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
443+
self.fail(
444+
START_BLOCK.start_location(),
445+
format!(
446+
"illegal projection {:?} in debuginfo for {:?}",
447+
f.projection, debuginfo.name
448+
),
449+
);
450+
}
451+
}
452+
}
453+
}
454+
self.super_var_debug_info(debuginfo);
455+
}
456+
422457
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
423458
// Set off any `bug!`s in the type computation code
424459
let _ = place.ty(&self.body.local_decls, self.tcx);
425460

426461
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
427462
&& place.projection.len() > 1
428-
&& cntxt != PlaceContext::NonUse(VarDebugInfo)
463+
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
429464
&& place.projection[1..].contains(&ProjectionElem::Deref)
430465
{
431466
self.fail(location, format!("{:?}, has deref at the wrong place", place));

compiler/rustc_middle/src/mir/mod.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -1036,8 +1036,7 @@ impl<'tcx> LocalDecl<'tcx> {
10361036

10371037
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
10381038
pub enum VarDebugInfoContents<'tcx> {
1039-
/// NOTE(eddyb) There's an unenforced invariant that this `Place` is
1040-
/// based on a `Local`, not a `Static`, and contains no indexing.
1039+
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
10411040
Place(Place<'tcx>),
10421041
Const(Constant<'tcx>),
10431042
/// The user variable's data is split across several fragments,
@@ -1047,6 +1046,7 @@ pub enum VarDebugInfoContents<'tcx> {
10471046
/// the underlying debuginfo feature this relies on.
10481047
Composite {
10491048
/// Type of the original user variable.
1049+
/// This cannot contain a union or an enum.
10501050
ty: Ty<'tcx>,
10511051
/// All the parts of the original user variable, which ended
10521052
/// up in disjoint places, due to optimizations.
@@ -1075,17 +1075,16 @@ pub struct VarDebugInfoFragment<'tcx> {
10751075
/// Where in the composite user variable this fragment is,
10761076
/// represented as a "projection" into the composite variable.
10771077
/// At lower levels, this corresponds to a byte/bit range.
1078-
// NOTE(eddyb) there's an unenforced invariant that this contains
1079-
// only `Field`s, and not into `enum` variants or `union`s.
1080-
// FIXME(eddyb) support this for `enum`s by either using DWARF's
1078+
///
1079+
/// This can only contain `PlaceElem::Field`.
1080+
// FIXME support this for `enum`s by either using DWARF's
10811081
// more advanced control-flow features (unsupported by LLVM?)
10821082
// to match on the discriminant, or by using custom type debuginfo
10831083
// with non-overlapping variants for the composite variable.
10841084
pub projection: Vec<PlaceElem<'tcx>>,
10851085

10861086
/// Where the data for this fragment can be found.
1087-
// NOTE(eddyb) There's an unenforced invariant that this `Place` is
1088-
// contains no indexing (with a non-constant index).
1087+
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
10891088
pub contents: Place<'tcx>,
10901089
}
10911090

@@ -1538,6 +1537,17 @@ impl<V, T> ProjectionElem<V, T> {
15381537
pub fn is_field_to(&self, f: FieldIdx) -> bool {
15391538
matches!(*self, Self::Field(x, _) if x == f)
15401539
}
1540+
1541+
/// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
1542+
pub fn can_use_in_debuginfo(&self) -> bool {
1543+
match self {
1544+
Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true,
1545+
Self::ConstantIndex { .. }
1546+
| Self::Index(_)
1547+
| Self::OpaqueCast(_)
1548+
| Self::Subslice { .. } => false,
1549+
}
1550+
}
15411551
}
15421552

15431553
/// Alias for projections as they appear in `UserTypeProjection`, where we

0 commit comments

Comments
 (0)