]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::traits::*; |
dfeec247 | 2 | use rustc_index::vec::IndexVec; |
3dfed10e | 3 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
ba9703b0 XL |
4 | use rustc_middle::mir; |
5 | use rustc_middle::ty; | |
9c376795 | 6 | use rustc_middle::ty::layout::TyAndLayout; |
f2b60f7d | 7 | use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; |
ba9703b0 | 8 | use rustc_session::config::DebugInfo; |
74b04a01 | 9 | use rustc_span::symbol::{kw, Symbol}; |
dfeec247 | 10 | use rustc_span::{BytePos, Span}; |
9c376795 | 11 | use rustc_target::abi::{Abi, Size, VariantIdx}; |
e74abb32 | 12 | |
fc512014 | 13 | use super::operand::{OperandRef, OperandValue}; |
74b04a01 | 14 | use super::place::PlaceRef; |
dfeec247 | 15 | use super::{FunctionCx, LocalRef}; |
e74abb32 | 16 | |
487cf647 FG |
17 | use std::ops::Range; |
18 | ||
29967ef6 XL |
19 | pub struct FunctionDebugContext<S, L> { |
20 | pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, | |
e74abb32 XL |
21 | } |
22 | ||
23 | #[derive(Copy, Clone)] | |
24 | pub enum VariableKind { | |
25 | ArgumentVariable(usize /*index*/), | |
26 | LocalVariable, | |
27 | } | |
28 | ||
74b04a01 | 29 | /// Like `mir::VarDebugInfo`, but within a `mir::Local`. |
487cf647 | 30 | #[derive(Clone)] |
74b04a01 XL |
31 | pub struct PerLocalVarDebugInfo<'tcx, D> { |
32 | pub name: Symbol, | |
33 | pub source_info: mir::SourceInfo, | |
34 | ||
35 | /// `DIVariable` returned by `create_dbg_var`. | |
36 | pub dbg_var: Option<D>, | |
37 | ||
487cf647 FG |
38 | /// Byte range in the `dbg_var` covered by this fragment, |
39 | /// if this is a fragment of a composite `VarDebugInfo`. | |
40 | pub fragment: Option<Range<Size>>, | |
41 | ||
74b04a01 XL |
42 | /// `.place.projection` from `mir::VarDebugInfo`. |
43 | pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, | |
44 | } | |
45 | ||
e74abb32 | 46 | #[derive(Clone, Copy, Debug)] |
29967ef6 | 47 | pub struct DebugScope<S, L> { |
04454e1e | 48 | pub dbg_scope: S, |
29967ef6 XL |
49 | |
50 | /// Call site location, if this scope was inlined from another function. | |
51 | pub inlined_at: Option<L>, | |
52 | ||
e74abb32 XL |
53 | // Start and end offsets of the file to which this DIScope belongs. |
54 | // These are used to quickly determine whether some span refers to the same file. | |
55 | pub file_start_pos: BytePos, | |
56 | pub file_end_pos: BytePos, | |
57 | } | |
58 | ||
29967ef6 | 59 | impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> { |
9c376795 | 60 | /// DILocations inherit source file name from the parent DIScope. Due to macro expansions |
29967ef6 | 61 | /// it may so happen that the current span belongs to a different file than the DIScope |
9c376795 | 62 | /// corresponding to span's containing source scope. If so, we need to create a DIScope |
29967ef6 XL |
63 | /// "extension" into that file. |
64 | pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>( | |
65 | &self, | |
66 | cx: &Cx, | |
67 | span: Span, | |
68 | ) -> S { | |
29967ef6 XL |
69 | let pos = span.lo(); |
70 | if pos < self.file_start_pos || pos >= self.file_end_pos { | |
71 | let sm = cx.sess().source_map(); | |
04454e1e | 72 | cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file) |
29967ef6 | 73 | } else { |
04454e1e | 74 | self.dbg_scope |
29967ef6 | 75 | } |
e74abb32 XL |
76 | } |
77 | } | |
78 | ||
9c376795 FG |
79 | trait DebugInfoOffsetLocation<'tcx, Bx> { |
80 | fn deref(&self, bx: &mut Bx) -> Self; | |
81 | fn layout(&self) -> TyAndLayout<'tcx>; | |
82 | fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self; | |
83 | fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self; | |
84 | } | |
85 | ||
86 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> | |
87 | for PlaceRef<'tcx, Bx::Value> | |
88 | { | |
89 | fn deref(&self, bx: &mut Bx) -> Self { | |
90 | bx.load_operand(*self).deref(bx.cx()) | |
91 | } | |
92 | ||
93 | fn layout(&self) -> TyAndLayout<'tcx> { | |
94 | self.layout | |
95 | } | |
96 | ||
97 | fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self { | |
98 | PlaceRef::project_field(*self, bx, field.index()) | |
99 | } | |
100 | ||
101 | fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { | |
102 | self.project_downcast(bx, variant) | |
103 | } | |
104 | } | |
105 | ||
106 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> | |
107 | for TyAndLayout<'tcx> | |
108 | { | |
109 | fn deref(&self, bx: &mut Bx) -> Self { | |
110 | bx.cx().layout_of( | |
111 | self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, | |
112 | ) | |
113 | } | |
114 | ||
115 | fn layout(&self) -> TyAndLayout<'tcx> { | |
116 | *self | |
117 | } | |
118 | ||
119 | fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self { | |
120 | self.field(bx.cx(), field.index()) | |
121 | } | |
122 | ||
123 | fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { | |
124 | self.for_variant(bx.cx(), variant) | |
125 | } | |
126 | } | |
127 | ||
128 | struct DebugInfoOffset<T> { | |
129 | /// Offset from the `base` used to calculate the debuginfo offset. | |
130 | direct_offset: Size, | |
131 | /// Each offset in this vector indicates one level of indirection from the base or previous | |
132 | /// indirect offset plus a dereference. | |
133 | indirect_offsets: Vec<Size>, | |
134 | /// The final location debuginfo should point to. | |
135 | result: T, | |
136 | } | |
137 | ||
138 | fn calculate_debuginfo_offset< | |
139 | 'a, | |
140 | 'tcx, | |
141 | Bx: BuilderMethods<'a, 'tcx>, | |
142 | L: DebugInfoOffsetLocation<'tcx, Bx>, | |
143 | >( | |
144 | bx: &mut Bx, | |
145 | local: mir::Local, | |
146 | var: &PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, | |
147 | base: L, | |
148 | ) -> DebugInfoOffset<L> { | |
149 | let mut direct_offset = Size::ZERO; | |
150 | // FIXME(eddyb) use smallvec here. | |
151 | let mut indirect_offsets = vec![]; | |
152 | let mut place = base; | |
153 | ||
154 | for elem in &var.projection[..] { | |
155 | match *elem { | |
156 | mir::ProjectionElem::Deref => { | |
157 | indirect_offsets.push(Size::ZERO); | |
158 | place = place.deref(bx); | |
159 | } | |
160 | mir::ProjectionElem::Field(field, _) => { | |
161 | let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); | |
162 | *offset += place.layout().fields.offset(field.index()); | |
163 | place = place.project_field(bx, field); | |
164 | } | |
165 | mir::ProjectionElem::Downcast(_, variant) => { | |
166 | place = place.downcast(bx, variant); | |
167 | } | |
168 | _ => span_bug!( | |
169 | var.source_info.span, | |
170 | "unsupported var debuginfo place `{:?}`", | |
171 | mir::Place { local, projection: var.projection }, | |
172 | ), | |
173 | } | |
174 | } | |
175 | ||
176 | DebugInfoOffset { direct_offset, indirect_offsets, result: place } | |
177 | } | |
178 | ||
e74abb32 | 179 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
74b04a01 | 180 | pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) { |
29967ef6 XL |
181 | bx.set_span(source_info.span); |
182 | if let Some(dbg_loc) = self.dbg_loc(source_info) { | |
183 | bx.set_dbg_loc(dbg_loc); | |
e74abb32 XL |
184 | } |
185 | } | |
186 | ||
29967ef6 XL |
187 | fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> { |
188 | let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?; | |
189 | Some(self.cx.dbg_loc(dbg_scope, inlined_at, span)) | |
190 | } | |
191 | ||
192 | fn adjusted_span_and_dbg_scope( | |
193 | &self, | |
194 | source_info: mir::SourceInfo, | |
195 | ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> { | |
196 | let span = self.adjust_span_for_debugging(source_info.span); | |
197 | let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; | |
198 | Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) | |
199 | } | |
200 | ||
201 | /// In order to have a good line stepping behavior in debugger, we overwrite debug | |
f2b60f7d FG |
202 | /// locations of macro expansions with that of the outermost expansion site (when the macro is |
203 | /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). | |
29967ef6 | 204 | fn adjust_span_for_debugging(&self, mut span: Span) -> Span { |
e74abb32 | 205 | // Bail out if debug info emission is not enabled. |
29967ef6 XL |
206 | if self.debug_context.is_none() { |
207 | return span; | |
e74abb32 XL |
208 | } |
209 | ||
f2b60f7d | 210 | if self.cx.tcx().should_collapse_debuginfo(span) { |
e74abb32 XL |
211 | // Walk up the macro expansion chain until we reach a non-expanded span. |
212 | // We also stop at the function body level because no line stepping can occur | |
213 | // at the level above that. | |
e74abb32 | 214 | // Use span of the outermost expansion site, while keeping the original lexical scope. |
29967ef6 | 215 | span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt()); |
e74abb32 | 216 | } |
e74abb32 | 217 | |
29967ef6 | 218 | span |
e74abb32 XL |
219 | } |
220 | ||
fc512014 XL |
221 | fn spill_operand_to_stack( |
222 | operand: &OperandRef<'tcx, Bx::Value>, | |
223 | name: Option<String>, | |
224 | bx: &mut Bx, | |
225 | ) -> PlaceRef<'tcx, Bx::Value> { | |
226 | // "Spill" the value onto the stack, for debuginfo, | |
227 | // without forcing non-debuginfo uses of the local | |
228 | // to also load from the stack every single time. | |
229 | // FIXME(#68817) use `llvm.dbg.value` instead, | |
230 | // at least for the cases which LLVM handles correctly. | |
231 | let spill_slot = PlaceRef::alloca(bx, operand.layout); | |
232 | if let Some(name) = name { | |
233 | bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); | |
234 | } | |
235 | operand.val.store(bx, spill_slot); | |
236 | spill_slot | |
237 | } | |
238 | ||
e74abb32 XL |
239 | /// Apply debuginfo and/or name, after creating the `alloca` for a local, |
240 | /// or initializing the local with an operand (whichever applies). | |
e74abb32 | 241 | pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { |
74b04a01 XL |
242 | let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; |
243 | ||
e74abb32 | 244 | // FIXME(eddyb) maybe name the return place as `_0` or `return`? |
f9f354fc XL |
245 | if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable() |
246 | { | |
e74abb32 XL |
247 | return; |
248 | } | |
249 | ||
250 | let vars = match &self.per_local_var_debug_info { | |
251 | Some(per_local) => &per_local[local], | |
252 | None => return, | |
253 | }; | |
487cf647 | 254 | let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned(); |
74b04a01 | 255 | let has_proj = || vars.iter().any(|var| !var.projection.is_empty()); |
e74abb32 | 256 | |
74b04a01 | 257 | let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg { |
e74abb32 XL |
258 | let arg_index = local.index() - 1; |
259 | ||
260 | // Add debuginfo even to unnamed arguments. | |
261 | // FIXME(eddyb) is this really needed? | |
74b04a01 | 262 | if arg_index == 0 && has_proj() { |
e74abb32 XL |
263 | // Hide closure environments from debuginfo. |
264 | // FIXME(eddyb) shouldn't `ArgumentVariable` indices | |
265 | // be offset to account for the hidden environment? | |
266 | None | |
74b04a01 XL |
267 | } else if whole_local_var.is_some() { |
268 | // No need to make up anything, there is a `mir::VarDebugInfo` | |
269 | // covering the whole local. | |
270 | // FIXME(eddyb) take `whole_local_var.source_info.scope` into | |
271 | // account, just in case it doesn't use `ArgumentVariable` | |
272 | // (after #67586 gets fixed). | |
273 | None | |
e74abb32 | 274 | } else { |
5869c6ff | 275 | let name = kw::Empty; |
74b04a01 | 276 | let decl = &self.mir.local_decls[local]; |
29967ef6 XL |
277 | let dbg_var = if full_debug_info { |
278 | self.adjusted_span_and_dbg_scope(decl.source_info).map( | |
279 | |(dbg_scope, _, span)| { | |
280 | // FIXME(eddyb) is this `+ 1` needed at all? | |
281 | let kind = VariableKind::ArgumentVariable(arg_index + 1); | |
282 | ||
fc512014 | 283 | let arg_ty = self.monomorphize(decl.ty); |
29967ef6 XL |
284 | |
285 | self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) | |
286 | }, | |
287 | ) | |
74b04a01 | 288 | } else { |
29967ef6 | 289 | None |
74b04a01 | 290 | }; |
74b04a01 XL |
291 | |
292 | Some(PerLocalVarDebugInfo { | |
293 | name, | |
294 | source_info: decl.source_info, | |
295 | dbg_var, | |
487cf647 | 296 | fragment: None, |
74b04a01 | 297 | projection: ty::List::empty(), |
e74abb32 | 298 | }) |
74b04a01 | 299 | } |
e74abb32 | 300 | } else { |
74b04a01 | 301 | None |
e74abb32 XL |
302 | }; |
303 | ||
304 | let local_ref = &self.locals[local]; | |
305 | ||
74b04a01 XL |
306 | let name = if bx.sess().fewer_names() { |
307 | None | |
308 | } else { | |
487cf647 | 309 | Some(match whole_local_var.or(fallback_var.clone()) { |
5869c6ff | 310 | Some(var) if var.name != kw::Empty => var.name.to_string(), |
e74abb32 | 311 | _ => format!("{:?}", local), |
74b04a01 XL |
312 | }) |
313 | }; | |
314 | ||
315 | if let Some(name) = &name { | |
e74abb32 | 316 | match local_ref { |
dfeec247 | 317 | LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { |
74b04a01 | 318 | bx.set_var_name(place.llval, name); |
e74abb32 XL |
319 | } |
320 | LocalRef::Operand(Some(operand)) => match operand.val { | |
dfeec247 | 321 | OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { |
74b04a01 | 322 | bx.set_var_name(x, name); |
e74abb32 XL |
323 | } |
324 | OperandValue::Pair(a, b) => { | |
325 | // FIXME(eddyb) these are scalar components, | |
326 | // maybe extract the high-level fields? | |
327 | bx.set_var_name(a, &(name.clone() + ".0")); | |
74b04a01 | 328 | bx.set_var_name(b, &(name.clone() + ".1")); |
e74abb32 | 329 | } |
dfeec247 | 330 | }, |
e74abb32 XL |
331 | LocalRef::Operand(None) => {} |
332 | } | |
333 | } | |
334 | ||
74b04a01 | 335 | if !full_debug_info || vars.is_empty() && fallback_var.is_none() { |
e74abb32 XL |
336 | return; |
337 | } | |
338 | ||
e74abb32 | 339 | let base = match local_ref { |
74b04a01 XL |
340 | LocalRef::Operand(None) => return, |
341 | ||
342 | LocalRef::Operand(Some(operand)) => { | |
3dfed10e XL |
343 | // Don't spill operands onto the stack in naked functions. |
344 | // See: https://github.com/rust-lang/rust/issues/42779 | |
345 | let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); | |
346 | if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { | |
347 | return; | |
348 | } | |
349 | ||
fc512014 | 350 | Self::spill_operand_to_stack(operand, name, bx) |
74b04a01 XL |
351 | } |
352 | ||
353 | LocalRef::Place(place) => *place, | |
354 | ||
355 | // FIXME(eddyb) add debuginfo for unsized places too. | |
356 | LocalRef::UnsizedPlace(_) => return, | |
e74abb32 XL |
357 | }; |
358 | ||
487cf647 | 359 | let vars = vars.iter().cloned().chain(fallback_var); |
e74abb32 XL |
360 | |
361 | for var in vars { | |
5e7ed085 FG |
362 | let Some(dbg_var) = var.dbg_var else { continue }; |
363 | let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; | |
29967ef6 | 364 | |
9c376795 FG |
365 | let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = |
366 | calculate_debuginfo_offset(bx, local, &var, base.layout); | |
e74abb32 | 367 | |
cdc7bbd5 XL |
368 | // When targeting MSVC, create extra allocas for arguments instead of pointing multiple |
369 | // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records | |
370 | // not DWARF and LLVM doesn't support translating the resulting | |
371 | // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. | |
372 | // Creating extra allocas on the stack makes the resulting debug info simple enough | |
373 | // that LLVM can generate correct CodeView records and thus the values appear in the | |
374 | // debugger. (#83709) | |
375 | let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc | |
376 | && self.mir.local_kind(local) == mir::LocalKind::Arg | |
377 | // LLVM can handle simple things but anything more complex than just a direct | |
378 | // offset or one indirect offset of 0 is too complex for it to generate CV records | |
379 | // correctly. | |
380 | && (direct_offset != Size::ZERO | |
381 | || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); | |
382 | ||
383 | if should_create_individual_allocas { | |
9c376795 FG |
384 | let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = |
385 | calculate_debuginfo_offset(bx, local, &var, base); | |
386 | ||
cdc7bbd5 | 387 | // Create a variable which will be a pointer to the actual value |
9ffffee4 FG |
388 | let ptr_ty = bx |
389 | .tcx() | |
390 | .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); | |
cdc7bbd5 XL |
391 | let ptr_layout = bx.layout_of(ptr_ty); |
392 | let alloca = PlaceRef::alloca(bx, ptr_layout); | |
393 | bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); | |
394 | ||
395 | // Write the pointer to the variable | |
396 | bx.store(place.llval, alloca.llval, alloca.align); | |
397 | ||
398 | // Point the debug info to `*alloca` for the current variable | |
487cf647 | 399 | bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); |
cdc7bbd5 | 400 | } else { |
487cf647 FG |
401 | bx.dbg_var_addr( |
402 | dbg_var, | |
403 | dbg_loc, | |
404 | base.llval, | |
405 | direct_offset, | |
406 | &indirect_offsets, | |
407 | None, | |
408 | ); | |
cdc7bbd5 | 409 | } |
e74abb32 XL |
410 | } |
411 | } | |
412 | ||
413 | pub fn debug_introduce_locals(&self, bx: &mut Bx) { | |
414 | if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { | |
415 | for local in self.locals.indices() { | |
416 | self.debug_introduce_local(bx, local); | |
417 | } | |
418 | } | |
419 | } | |
e74abb32 | 420 | |
74b04a01 XL |
421 | /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. |
422 | pub fn compute_per_local_var_debug_info( | |
423 | &self, | |
fc512014 | 424 | bx: &mut Bx, |
74b04a01 XL |
425 | ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> { |
426 | let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; | |
427 | ||
6a06907d XL |
428 | let target_is_msvc = self.cx.sess().target.is_like_msvc; |
429 | ||
74b04a01 XL |
430 | if !full_debug_info && self.cx.sess().fewer_names() { |
431 | return None; | |
432 | } | |
433 | ||
434 | let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls); | |
435 | for var in &self.mir.var_debug_info { | |
29967ef6 XL |
436 | let dbg_scope_and_span = if full_debug_info { |
437 | self.adjusted_span_and_dbg_scope(var.source_info) | |
74b04a01 | 438 | } else { |
29967ef6 | 439 | None |
74b04a01 | 440 | }; |
fc512014 | 441 | |
29967ef6 | 442 | let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { |
fc512014 XL |
443 | let (var_ty, var_kind) = match var.value { |
444 | mir::VarDebugInfoContents::Place(place) => { | |
445 | let var_ty = self.monomorphized_place_ty(place.as_ref()); | |
446 | let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg | |
447 | && place.projection.is_empty() | |
448 | && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE | |
449 | { | |
450 | let arg_index = place.local.index() - 1; | |
6a06907d | 451 | if target_is_msvc { |
c295e0f8 XL |
452 | // ScalarPair parameters are spilled to the stack so they need to |
453 | // be marked as a `LocalVariable` for MSVC debuggers to visualize | |
454 | // their data correctly. (See #81894 & #88625) | |
455 | let var_ty_layout = self.cx.layout_of(var_ty); | |
456 | if let Abi::ScalarPair(_, _) = var_ty_layout.abi { | |
457 | VariableKind::LocalVariable | |
458 | } else { | |
459 | VariableKind::ArgumentVariable(arg_index + 1) | |
6a06907d XL |
460 | } |
461 | } else { | |
462 | // FIXME(eddyb) shouldn't `ArgumentVariable` indices be | |
463 | // offset in closures to account for the hidden environment? | |
464 | // Also, is this `+ 1` needed at all? | |
465 | VariableKind::ArgumentVariable(arg_index + 1) | |
466 | } | |
fc512014 XL |
467 | } else { |
468 | VariableKind::LocalVariable | |
469 | }; | |
470 | (var_ty, var_kind) | |
471 | } | |
472 | mir::VarDebugInfoContents::Const(c) => { | |
6a06907d | 473 | let ty = self.monomorphize(c.ty()); |
fc512014 XL |
474 | (ty, VariableKind::LocalVariable) |
475 | } | |
487cf647 FG |
476 | mir::VarDebugInfoContents::Composite { ty, fragments: _ } => { |
477 | let ty = self.monomorphize(ty); | |
478 | (ty, VariableKind::LocalVariable) | |
479 | } | |
74b04a01 | 480 | }; |
fc512014 | 481 | |
29967ef6 | 482 | self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) |
74b04a01 XL |
483 | }); |
484 | ||
fc512014 XL |
485 | match var.value { |
486 | mir::VarDebugInfoContents::Place(place) => { | |
487 | per_local[place.local].push(PerLocalVarDebugInfo { | |
488 | name: var.name, | |
489 | source_info: var.source_info, | |
490 | dbg_var, | |
487cf647 | 491 | fragment: None, |
fc512014 XL |
492 | projection: place.projection, |
493 | }); | |
494 | } | |
495 | mir::VarDebugInfoContents::Const(c) => { | |
496 | if let Some(dbg_var) = dbg_var { | |
5e7ed085 | 497 | let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; |
fc512014 XL |
498 | |
499 | if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { | |
500 | let base = Self::spill_operand_to_stack( | |
501 | &operand, | |
502 | Some(var.name.to_string()), | |
503 | bx, | |
504 | ); | |
505 | ||
487cf647 | 506 | bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None); |
fc512014 XL |
507 | } |
508 | } | |
509 | } | |
487cf647 FG |
510 | mir::VarDebugInfoContents::Composite { ty, ref fragments } => { |
511 | let var_ty = self.monomorphize(ty); | |
512 | let var_layout = self.cx.layout_of(var_ty); | |
513 | for fragment in fragments { | |
514 | let mut fragment_start = Size::ZERO; | |
515 | let mut fragment_layout = var_layout; | |
516 | ||
517 | for elem in &fragment.projection { | |
518 | match *elem { | |
519 | mir::ProjectionElem::Field(field, _) => { | |
520 | let i = field.index(); | |
521 | fragment_start += fragment_layout.fields.offset(i); | |
522 | fragment_layout = fragment_layout.field(self.cx, i); | |
523 | } | |
524 | _ => span_bug!( | |
525 | var.source_info.span, | |
526 | "unsupported fragment projection `{:?}`", | |
527 | elem, | |
528 | ), | |
529 | } | |
530 | } | |
531 | ||
532 | let place = fragment.contents; | |
533 | per_local[place.local].push(PerLocalVarDebugInfo { | |
534 | name: var.name, | |
535 | source_info: var.source_info, | |
536 | dbg_var, | |
537 | fragment: if fragment_layout.size == var_layout.size { | |
538 | // Fragment covers entire variable, so as far as | |
539 | // DWARF is concerned, it's not really a fragment. | |
540 | None | |
541 | } else { | |
542 | Some(fragment_start..fragment_start + fragment_layout.size) | |
543 | }, | |
544 | projection: place.projection, | |
545 | }); | |
546 | } | |
547 | } | |
fc512014 | 548 | } |
e74abb32 | 549 | } |
e74abb32 | 550 | Some(per_local) |
e74abb32 XL |
551 | } |
552 | } |