mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 20:03:37 +00:00
Rollup merge of #109901 - cjgillot:validate-debuginfo, r=b-naber
Enforce VarDebugInfo::Place in MIR validation.
This commit is contained in:
commit
ed17b599df
@ -165,11 +165,15 @@ fn calculate_debuginfo_offset<
|
|||||||
mir::ProjectionElem::Downcast(_, variant) => {
|
mir::ProjectionElem::Downcast(_, variant) => {
|
||||||
place = place.downcast(bx, variant);
|
place = place.downcast(bx, variant);
|
||||||
}
|
}
|
||||||
_ => span_bug!(
|
_ => {
|
||||||
var.source_info.span,
|
// Sanity check for `can_use_in_debuginfo`.
|
||||||
"unsupported var debuginfo place `{:?}`",
|
debug_assert!(!elem.can_use_in_debuginfo());
|
||||||
mir::Place { local, projection: var.projection },
|
span_bug!(
|
||||||
),
|
var.source_info.span,
|
||||||
|
"unsupported var debuginfo place `{:?}`",
|
||||||
|
mir::Place { local, projection: var.projection },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,13 +5,12 @@ use rustc_index::bit_set::BitSet;
|
|||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::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::VarDebugInfo;
|
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||||
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
|
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
|
||||||
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
||||||
TerminatorKind, UnOp, START_BLOCK,
|
TerminatorKind, UnOp, 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;
|
||||||
@ -419,13 +418,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||||||
self.super_projection_elem(local, proj_base, elem, context, location);
|
self.super_projection_elem(local, proj_base, elem, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
|
||||||
|
let check_place = |place: Place<'_>| {
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match debuginfo.value {
|
||||||
|
VarDebugInfoContents::Const(_) => {}
|
||||||
|
VarDebugInfoContents::Place(place) => check_place(place),
|
||||||
|
VarDebugInfoContents::Composite { ty, ref fragments } => {
|
||||||
|
for f in fragments {
|
||||||
|
check_place(f.contents);
|
||||||
|
if ty.is_union() || ty.is_enum() {
|
||||||
|
self.fail(
|
||||||
|
START_BLOCK.start_location(),
|
||||||
|
format!("invalid type {:?} for composite debuginfo", ty),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.super_var_debug_info(debuginfo);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
|
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
|
||||||
// Set off any `bug!`s in the type computation code
|
// Set off any `bug!`s in the type computation code
|
||||||
let _ = place.ty(&self.body.local_decls, self.tcx);
|
let _ = place.ty(&self.body.local_decls, self.tcx);
|
||||||
|
|
||||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
|
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
|
||||||
&& place.projection.len() > 1
|
&& place.projection.len() > 1
|
||||||
&& cntxt != PlaceContext::NonUse(VarDebugInfo)
|
&& cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
|
||||||
&& place.projection[1..].contains(&ProjectionElem::Deref)
|
&& place.projection[1..].contains(&ProjectionElem::Deref)
|
||||||
{
|
{
|
||||||
self.fail(location, format!("{:?}, has deref at the wrong place", place));
|
self.fail(location, format!("{:?}, has deref at the wrong place", place));
|
||||||
|
@ -1036,8 +1036,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||||||
|
|
||||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub enum VarDebugInfoContents<'tcx> {
|
pub enum VarDebugInfoContents<'tcx> {
|
||||||
/// NOTE(eddyb) There's an unenforced invariant that this `Place` is
|
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||||
/// based on a `Local`, not a `Static`, and contains no indexing.
|
|
||||||
Place(Place<'tcx>),
|
Place(Place<'tcx>),
|
||||||
Const(Constant<'tcx>),
|
Const(Constant<'tcx>),
|
||||||
/// The user variable's data is split across several fragments,
|
/// The user variable's data is split across several fragments,
|
||||||
@ -1047,6 +1046,7 @@ pub enum VarDebugInfoContents<'tcx> {
|
|||||||
/// the underlying debuginfo feature this relies on.
|
/// the underlying debuginfo feature this relies on.
|
||||||
Composite {
|
Composite {
|
||||||
/// Type of the original user variable.
|
/// Type of the original user variable.
|
||||||
|
/// This cannot contain a union or an enum.
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
/// All the parts of the original user variable, which ended
|
/// All the parts of the original user variable, which ended
|
||||||
/// up in disjoint places, due to optimizations.
|
/// up in disjoint places, due to optimizations.
|
||||||
@ -1075,17 +1075,16 @@ pub struct VarDebugInfoFragment<'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.
|
||||||
// NOTE(eddyb) there's an unenforced invariant that this contains
|
///
|
||||||
// only `Field`s, and not into `enum` variants or `union`s.
|
/// This can only contain `PlaceElem::Field`.
|
||||||
// FIXME(eddyb) support this for `enum`s by either using DWARF's
|
// FIXME support this for `enum`s by either using DWARF's
|
||||||
// more advanced control-flow features (unsupported by LLVM?)
|
// more advanced control-flow features (unsupported by LLVM?)
|
||||||
// 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.
|
/// Where the data for this fragment can be found.
|
||||||
// NOTE(eddyb) There's an unenforced invariant that this `Place` is
|
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||||
// contains no indexing (with a non-constant index).
|
|
||||||
pub contents: Place<'tcx>,
|
pub contents: Place<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1538,6 +1537,17 @@ impl<V, T> ProjectionElem<V, T> {
|
|||||||
pub fn is_field_to(&self, f: FieldIdx) -> bool {
|
pub fn is_field_to(&self, f: FieldIdx) -> bool {
|
||||||
matches!(*self, Self::Field(x, _) if x == f)
|
matches!(*self, Self::Field(x, _) if x == f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
|
||||||
|
pub fn can_use_in_debuginfo(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true,
|
||||||
|
Self::ConstantIndex { .. }
|
||||||
|
| Self::Index(_)
|
||||||
|
| Self::OpaqueCast(_)
|
||||||
|
| Self::Subslice { .. } => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alias for projections as they appear in `UserTypeProjection`, where we
|
/// Alias for projections as they appear in `UserTypeProjection`, where we
|
||||||
|
Loading…
Reference in New Issue
Block a user