about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs54
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs12
-rw-r--r--src/test/debuginfo/var-captured-in-nested-closure.rs49
-rw-r--r--src/test/debuginfo/var-captured-in-stack-closure.rs42
4 files changed, 142 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);
     }
diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs
index 8ab6d141731..695cdc4f41f 100644
--- a/src/test/debuginfo/var-captured-in-nested-closure.rs
+++ b/src/test/debuginfo/var-captured-in-nested-closure.rs
@@ -83,6 +83,55 @@
 // lldbr-check:(isize) closure_local = 8
 // lldb-command:continue
 
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_nested_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+// cdb-check:    6 [Type: [...]]
+// cdb-command: dx closure_local
+// cdb-check:closure_local    : 8 [Type: [...]]
+// cdb-command: dx nested_closure
+// cdb-check:nested_closure   [Type: var_captured_in_nested_closure::main::{{closure}}::closure-0]
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_nested_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+// cdb-check:    6 [Type: [...]]
+// cdb-command: dx closure_local
+// cdb-check:closure_local    : 8 [Type: [...]]
+
 #![allow(unused_variables)]
 #![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs
index f53f8aaa670..1bbb79c37a4 100644
--- a/src/test/debuginfo/var-captured-in-stack-closure.rs
+++ b/src/test/debuginfo/var-captured-in-stack-closure.rs
@@ -73,6 +73,48 @@
 // lldbg-check:[...]$9 = 6
 // lldbr-check:(isize) *owned = 6
 
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 1 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_stack_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+
+
+// cdb-command: g
+
+// cdb-command: dx variable
+// cdb-check:variable         : 2 [Type: [...]]
+// cdb-command: dx constant
+// cdb-check:constant         : 2 [Type: [...]]
+// cdb-command: dx a_struct
+// cdb-check:a_struct         [Type: var_captured_in_stack_closure::Struct]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx struct_ref
+// cdb-check:struct_ref       : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
+// cdb-check:    [+0x[...]] a                : -3 [Type: [...]]
+// cdb-check:    [+0x[...]] b                : 4.500000 [Type: [...]]
+// cdb-check:    [+0x[...]] c                : 0x5 [Type: unsigned [...]]
+// cdb-command: dx owned
+// cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
+
 #![feature(box_syntax)]
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]