diff options
| author | Wesley Wiser <wesleywiser@microsoft.com> | 2021-04-06 13:34:17 -0400 |
|---|---|---|
| committer | Wesley Wiser <wesleywiser@microsoft.com> | 2021-04-08 14:08:56 -0400 |
| commit | 533002d3a1f7f95f167323174205b57564b576a6 (patch) | |
| tree | 9464f6d5b20dab3db01b9bd190bccae4c61ef733 /compiler | |
| parent | e9cdcccfa8321363999a43ee30a18b3aadbc20de (diff) | |
| download | rust-533002d3a1f7f95f167323174205b57564b576a6.tar.gz rust-533002d3a1f7f95f167323174205b57564b576a6.zip | |
Fix closed over variables not available in debuginfo for Windows MSVC
The issue was that the resulting debuginfo was too complex for LLVM to translate into CodeView records correctly. As a result, it simply ignored the debuginfo which meant Windows debuggers could not display any closed over variables when stepping inside a closure. This fixes that by spilling additional variables to the stack so that the resulting debuginfo is simple (just `*my_variable.dbg.spill`) and LLVM can generate the correct CV records.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/place.rs | 12 |
2 files changed, 51 insertions, 15 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index a3f20abc82d..6bb20545f07 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -265,33 +265,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => continue, }; - let mut layout = base.layout; let mut direct_offset = Size::ZERO; // FIXME(eddyb) use smallvec here. let mut indirect_offsets = vec![]; + let mut place = base; for elem in &var.projection[..] { match *elem { mir::ProjectionElem::Deref => { indirect_offsets.push(Size::ZERO); - layout = bx.cx().layout_of( - layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| { - span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty) - }) - .ty, - ); + place = place.project_deref(bx); } mir::ProjectionElem::Field(field, _) => { let i = field.index(); let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); - *offset += layout.fields.offset(i); - layout = layout.field(bx.cx(), i); + *offset += place.layout.fields.offset(i); + place = place.project_field(bx, i); } mir::ProjectionElem::Downcast(_, variant) => { - layout = layout.for_variant(bx.cx(), variant); + place = place.project_downcast(bx, variant); } _ => span_bug!( var.source_info.span, @@ -301,7 +293,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); + // 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 + // not DWARF and LLVM doesn't support translating the resulting + // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. + // Creating extra allocas on the stack makes the resulting debug info simple enough + // that LLVM can generate correct CodeView records and thus the values appear in the + // debugger. (#83709) + let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc + && self.mir.local_kind(local) == mir::LocalKind::Arg + // LLVM can handle simple things but anything more complex than just a direct + // offset or one indirect offset of 0 is too complex for it to generate CV records + // correctly. + && (direct_offset != Size::ZERO + || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); + + if should_create_individual_allocas { + // Create a variable which will be a pointer to the actual value + let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut { + mutbl: mir::Mutability::Mut, + ty: place.layout.ty, + })); + let ptr_layout = bx.layout_of(ptr_ty); + let alloca = PlaceRef::alloca(bx, ptr_layout); + bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); + + // Write the pointer to the variable + bx.store(place.llval, alloca.llval, alloca.align); + + // Point the debug info to `*alloca` for the current variable + bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]); + } else { + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 66d9d1a1e0c..a9e7ebf6d43 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -402,6 +402,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { downcast } + pub fn project_deref<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) -> Self { + let target_ty = self.layout.ty.builtin_deref(true).expect("failed to deref"); + let layout = bx.layout_of(target_ty.ty); + + PlaceRef { + llval: bx.load(self.llval, self.align), + llextra: None, + layout, + align: layout.align.abi, + } + } + pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { bx.lifetime_start(self.llval, self.layout.size); } |
