Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
err: &mut Diag<'infcx>,
) {
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
VarDebugInfoContents::Place(ref p) => p == place,
VarDebugInfoContents::Place(ref p) => {
// This will become a simple == when Derefer is moved before borrowck
place.local == p.local
&& p.iter_projection_elems()
.enumerate()
.all(|(i, elem)| place.projection.get(i) == Some(&elem))
}
_ => false,
});
let arg_name = if let Some(var_info) = var_info {
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_infer::infer::{
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, ProjectionBase, Visitor};
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::adjustment::PointerCoercion;
Expand Down Expand Up @@ -1807,13 +1807,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}

fn visit_projection_elem(
fn visit_projection_elem<P>(
&mut self,
place: PlaceRef<'tcx>,
place: P,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
) where
P: ProjectionBase<'tcx>,
{
let tcx = self.tcx();
let base_ty = place.ty(self.body(), tcx);
match elem {
Expand Down
116 changes: 80 additions & 36 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
/// if this is a fragment of a composite `VarDebugInfo`.
pub fragment: Option<Range<Size>>,

/// `.place.projection` from `mir::VarDebugInfo`.
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
/// `.place.direct_projection` from `mir::VarDebugInfo`.
pub direct_projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,

/// `.place.projection_chain` from `mir::VarDebugInfo`.
pub projection_chain: &'tcx ty::List<mir::ProjectionFragment<'tcx>>,
}

/// Information needed to emit a constant.
Expand Down Expand Up @@ -168,46 +171,68 @@ fn calculate_debuginfo_offset<
L: DebugInfoOffsetLocation<'tcx, Bx>,
>(
bx: &mut Bx,
projection: &[mir::PlaceElem<'tcx>],
direct_projection: &[mir::PlaceElem<'tcx>],
projection_chain: &[mir::ProjectionFragment<'tcx>],
base: L,
) -> DebugInfoOffset<L> {
let mut direct_offset = Size::ZERO;
// FIXME(eddyb) use smallvec here.
let mut indirect_offsets = vec![];
let mut place = base;

for elem in projection {
match *elem {
mir::ProjectionElem::Deref => {
indirect_offsets.push(Size::ZERO);
place = place.deref(bx);
}
let project_direct = |bx: &mut Bx, place: L, offset, elem| {
let (new_place, new_offset) = match elem {
mir::ProjectionElem::Field(field, _) => {
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
*offset += place.layout().fields.offset(field.index());
place = place.project_field(bx, field);
}
mir::ProjectionElem::Downcast(_, variant) => {
place = place.downcast(bx, variant);
let offset = place.layout().fields.offset(field.index());
let place = place.project_field(bx, field);

(place, offset)
}
mir::ProjectionElem::Downcast(_, variant) => (place.downcast(bx, variant), Size::ZERO),
mir::ProjectionElem::ConstantIndex {
offset: index,
min_length: _,
from_end: false,
} => {
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
bug!("ConstantIndex on non-array type {:?}", place.layout())
};
*offset += stride * index;
place = place.project_constant_index(bx, index);
let offset = stride * index;
let place = place.project_constant_index(bx, index);

(place, offset)
}

mir::ProjectionElem::Deref => {
// derefs handled separately
bug!(
"unexpected deref in var debuginfo projection `{direct_projection:?} {projection_chain:?}`"
)
}
_ => {
// Sanity check for `can_use_in_debuginfo`.
assert!(!elem.can_use_in_debuginfo());
bug!("unsupported var debuginfo projection `{:?}`", projection)
bug!(
"unsupported var debuginfo projection `{direct_projection:?} {projection_chain:?}`"
)
}
}
};
(new_place, offset + new_offset)
};

let (mut place, direct_offset) = direct_projection
.iter()
.fold((base, Size::ZERO), |(place, offset), &elem| project_direct(bx, place, offset, elem));

// FIXME(eddyb) use smallvec here.
let mut indirect_offsets = vec![];

for projection in projection_chain {
debug_assert_eq!(projection[0], mir::ProjectionElem::Deref);
let pointee = place.deref(bx);

let (projected, offset) =
projection[1..].iter().fold((pointee, Size::ZERO), |(place, offset), &elem| {
project_direct(bx, place, offset, elem)
});

place = projected;
indirect_offsets.push(offset);
}

DebugInfoOffset { direct_offset, indirect_offsets, result: place }
Expand Down Expand Up @@ -262,8 +287,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(per_local) => &per_local[local],
None => return,
};
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
let whole_local_var = vars
.iter()
.find(|var| var.direct_projection.is_empty() && var.projection_chain.is_empty())
.cloned();
let has_proj = || {
vars.iter()
.any(|var| !var.direct_projection.is_empty() || !var.projection_chain.is_empty())
};

let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
let arg_index = local.index() - 1;
Expand Down Expand Up @@ -305,7 +336,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
source_info: decl.source_info,
dbg_var,
fragment: None,
projection: ty::List::empty(),
direct_projection: ty::List::empty(),
projection_chain: ty::List::empty(),
})
}
} else {
Expand Down Expand Up @@ -388,7 +420,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };

let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
calculate_debuginfo_offset(bx, var.projection, base.layout);
calculate_debuginfo_offset(
bx,
var.direct_projection,
var.projection_chain,
base.layout,
);

// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
Expand All @@ -406,7 +443,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

if should_create_individual_allocas {
let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
calculate_debuginfo_offset(bx, var.projection, base);
calculate_debuginfo_offset(bx, var.direct_projection, var.projection_chain, base);

// Create a variable which will be a pointer to the actual value
let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
Expand Down Expand Up @@ -491,7 +528,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
match var.value {
mir::VarDebugInfoContents::Place(place) => {
self.monomorphized_place_ty(place.as_ref())
let tcx = bx.tcx();
let place_ty = place.ty(self.mir, tcx);
self.monomorphize(place_ty.ty)
}
mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
}
Expand All @@ -501,7 +540,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
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()
&& place.as_local().is_some()
{
let arg_index = arg_index as usize;
if target_is_msvc {
Expand Down Expand Up @@ -541,7 +580,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let var_layout = self.cx.layout_of(var_ty);

let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
calculate_debuginfo_offset(bx, &fragment.projection, &[], var_layout);
assert!(indirect_offsets.is_empty());

if fragment_layout.size == Size::ZERO {
Expand All @@ -560,13 +599,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};

match var.value {
mir::VarDebugInfoContents::Place(place) => {
per_local[place.local].push(PerLocalVarDebugInfo {
mir::VarDebugInfoContents::Place(mir::CompoundPlace {
local,
direct_projection,
projection_chain,
}) => {
per_local[local].push(PerLocalVarDebugInfo {
name: var.name,
source_info: var.source_info,
dbg_var,
fragment,
projection: place.projection,
direct_projection,
projection_chain,
});
}
mir::VarDebugInfoContents::Const(c) => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,8 +1187,8 @@ impl<'tcx> LocalDecl<'tcx> {

#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub enum VarDebugInfoContents<'tcx> {
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
Place(Place<'tcx>),
/// This `CompoundPlace` only contains projection which satisfy `can_use_in_debuginfo`.
Place(CompoundPlace<'tcx>),
Const(ConstOperand<'tcx>),
}

Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,34 @@ impl Debug for PlaceRef<'_> {
}
}

impl Debug for CompoundPlace<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(fmt)
}
}

impl Debug for CompoundPlaceRef<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
let (stem, suffix) = self.projection_chain.unwrap_or_default();

pre_fmt_projection(suffix, fmt)?;
for projection in stem.iter().rev() {
pre_fmt_projection(projection, fmt)?;
}
pre_fmt_projection(self.direct_projection, fmt)?;

write!(fmt, "{:?}", self.local)?;

post_fmt_projection(self.direct_projection, fmt)?;
for projection in stem {
post_fmt_projection(projection, fmt)?;
}
post_fmt_projection(suffix, fmt)?;

Ok(())
}
}

fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fmt::Result {
for &elem in projection.iter().rev() {
match elem {
Expand Down
Loading
Loading