1use std::collections::hash_map::Entry;
2use std::marker::PhantomData;
3use std::ops::Range;
4
5use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx};
6use rustc_data_structures::fx::FxHashMap;
7use rustc_index::IndexVec;
8use rustc_index::bit_set::DenseBitSet;
9use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
10use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
11use rustc_middle::ty::{Instance, Ty};
12use rustc_middle::{bug, mir, ty};
13use rustc_session::config::DebugInfo;
14use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, hygiene, sym};
15
16use super::operand::{OperandRef, OperandValue};
17use super::place::{PlaceRef, PlaceValue};
18use super::{FunctionCx, LocalRef, PerLocalVarDebugInfoIndexVec};
19use crate::traits::*;
20
21pub struct FunctionDebugContext<'tcx, S, L> {
22 pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
24
25 pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
27}
28
29#[derive(#[automatically_derived]
impl ::core::marker::Copy for VariableKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for VariableKind {
#[inline]
fn clone(&self) -> VariableKind {
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone)]
30pub enum VariableKind {
31 ArgumentVariable(usize ),
32 LocalVariable,
33}
34
35#[derive(#[automatically_derived]
impl<'tcx, D: ::core::clone::Clone> ::core::clone::Clone for
PerLocalVarDebugInfo<'tcx, D> {
#[inline]
fn clone(&self) -> PerLocalVarDebugInfo<'tcx, D> {
PerLocalVarDebugInfo {
name: ::core::clone::Clone::clone(&self.name),
source_info: ::core::clone::Clone::clone(&self.source_info),
dbg_var: ::core::clone::Clone::clone(&self.dbg_var),
fragment: ::core::clone::Clone::clone(&self.fragment),
projection: ::core::clone::Clone::clone(&self.projection),
}
}
}Clone)]
37pub struct PerLocalVarDebugInfo<'tcx, D> {
38 pub name: Symbol,
39 pub source_info: mir::SourceInfo,
40
41 pub dbg_var: Option<D>,
43
44 pub fragment: Option<Range<Size>>,
47
48 pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
50}
51
52pub struct ConstDebugInfo<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
54 pub name: String,
55 pub source_info: mir::SourceInfo,
56 pub operand: OperandRef<'tcx, Bx::Value>,
57 pub dbg_var: Bx::DIVariable,
58 pub dbg_loc: Bx::DILocation,
59 pub fragment: Option<Range<Size>>,
60 pub _phantom: PhantomData<&'a ()>,
61}
62
63#[derive(#[automatically_derived]
impl<S: ::core::clone::Clone, L: ::core::clone::Clone> ::core::clone::Clone
for DebugScope<S, L> {
#[inline]
fn clone(&self) -> DebugScope<S, L> {
DebugScope {
dbg_scope: ::core::clone::Clone::clone(&self.dbg_scope),
inlined_at: ::core::clone::Clone::clone(&self.inlined_at),
file_start_pos: ::core::clone::Clone::clone(&self.file_start_pos),
file_end_pos: ::core::clone::Clone::clone(&self.file_end_pos),
}
}
}Clone, #[automatically_derived]
impl<S: ::core::marker::Copy, L: ::core::marker::Copy> ::core::marker::Copy
for DebugScope<S, L> {
}Copy, #[automatically_derived]
impl<S: ::core::fmt::Debug, L: ::core::fmt::Debug> ::core::fmt::Debug for
DebugScope<S, L> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f, "DebugScope",
"dbg_scope", &self.dbg_scope, "inlined_at", &self.inlined_at,
"file_start_pos", &self.file_start_pos, "file_end_pos",
&&self.file_end_pos)
}
}Debug)]
64pub struct DebugScope<S, L> {
65 pub dbg_scope: S,
66
67 pub inlined_at: Option<L>,
69
70 pub file_start_pos: BytePos,
73 pub file_end_pos: BytePos,
74}
75
76impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
77 pub fn adjust_dbg_scope_for_span<
82 'a,
83 Bx: BuilderMethods<'a, 'tcx, DIScope = S, DILocation = L>,
84 >(
85 &self,
86 bx: &mut Bx,
87 span: Span,
88 ) -> S {
89 let pos = span.lo();
90 if pos < self.file_start_pos || pos >= self.file_end_pos {
91 let sm = bx.sess().source_map();
92 bx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file)
93 } else {
94 self.dbg_scope
95 }
96 }
97}
98
99trait DebugInfoOffsetLocation<'tcx, Bx> {
100 fn deref(&self, bx: &mut Bx) -> Self;
101 fn layout(&self) -> TyAndLayout<'tcx>;
102 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self;
103 fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self;
104 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
105}
106
107impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
108 for PlaceRef<'tcx, Bx::Value>
109{
110 fn deref(&self, bx: &mut Bx) -> Self {
111 bx.load_operand(*self).deref(bx.cx())
112 }
113
114 fn layout(&self) -> TyAndLayout<'tcx> {
115 self.layout
116 }
117
118 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
119 PlaceRef::project_field(*self, bx, field.index())
120 }
121
122 fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self {
123 let lloffset = bx.cx().const_usize(offset);
124 self.project_index(bx, lloffset)
125 }
126
127 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
128 self.project_downcast(bx, variant)
129 }
130}
131
132impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
133 for TyAndLayout<'tcx>
134{
135 fn deref(&self, bx: &mut Bx) -> Self {
136 bx.cx().layout_of(
137 self.ty.builtin_deref(true).unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("cannot deref `{0}`",
self.ty))bug!("cannot deref `{}`", self.ty)),
138 )
139 }
140
141 fn layout(&self) -> TyAndLayout<'tcx> {
142 *self
143 }
144
145 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
146 self.field(bx.cx(), field.index())
147 }
148
149 fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self {
150 self.field(bx.cx(), index as usize)
151 }
152
153 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
154 self.for_variant(bx.cx(), variant)
155 }
156}
157
158struct DebugInfoOffset<T> {
159 direct_offset: Size,
161 indirect_offsets: Vec<Size>,
164 result: T,
166}
167
168fn calculate_debuginfo_offset<
169 'a,
170 'tcx,
171 Bx: BuilderMethods<'a, 'tcx>,
172 L: DebugInfoOffsetLocation<'tcx, Bx>,
173>(
174 bx: &mut Bx,
175 projection: &[mir::PlaceElem<'tcx>],
176 base: L,
177) -> DebugInfoOffset<L> {
178 let mut direct_offset = Size::ZERO;
179 let mut indirect_offsets = ::alloc::vec::Vec::new()vec![];
181 let mut place = base;
182
183 for elem in projection {
184 match *elem {
185 mir::ProjectionElem::Deref => {
186 indirect_offsets.push(Size::ZERO);
187 place = place.deref(bx);
188 }
189 mir::ProjectionElem::Field(field, _) => {
190 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
191 *offset += place.layout().fields.offset(field.index());
192 place = place.project_field(bx, field);
193 }
194 mir::ProjectionElem::Downcast(_, variant) => {
195 place = place.downcast(bx, variant);
196 }
197 mir::ProjectionElem::ConstantIndex {
198 offset: index,
199 min_length: _,
200 from_end: false,
201 } => {
202 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
203 let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
204 ::rustc_middle::util::bug::bug_fmt(format_args!("ConstantIndex on non-array type {0:?}",
place.layout()))bug!("ConstantIndex on non-array type {:?}", place.layout())
205 };
206 *offset += stride * index;
207 place = place.project_constant_index(bx, index);
208 }
209 _ => {
210 if !!elem.can_use_in_debuginfo() {
::core::panicking::panic("assertion failed: !elem.can_use_in_debuginfo()")
};assert!(!elem.can_use_in_debuginfo());
212 ::rustc_middle::util::bug::bug_fmt(format_args!("unsupported var debuginfo projection `{0:?}`",
projection))bug!("unsupported var debuginfo projection `{:?}`", projection)
213 }
214 }
215 }
216
217 DebugInfoOffset { direct_offset, indirect_offsets, result: place }
218}
219
220impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
221 pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
222 bx.set_span(source_info.span);
223 if let Some(dbg_loc) = self.dbg_loc(bx, source_info) {
224 bx.set_dbg_loc(dbg_loc);
225 }
226 }
227
228 fn dbg_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) -> Option<Bx::DILocation> {
229 let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(bx, source_info)?;
230 Some(bx.dbg_loc(dbg_scope, inlined_at, span))
231 }
232
233 fn adjusted_span_and_dbg_scope(
234 &self,
235 bx: &mut Bx,
236 source_info: mir::SourceInfo,
237 ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
238 let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
239 let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
240 Some((scope.adjust_dbg_scope_for_span(bx, span), scope.inlined_at, span))
241 }
242
243 fn spill_operand_to_stack(
244 operand: OperandRef<'tcx, Bx::Value>,
245 name: Option<String>,
246 bx: &mut Bx,
247 ) -> PlaceRef<'tcx, Bx::Value> {
248 let spill_slot = PlaceRef::alloca(bx, operand.layout);
254 if let Some(name) = name {
255 bx.set_var_name(spill_slot.val.llval, &(name + ".dbg.spill"));
256 }
257 operand.val.store(bx, spill_slot);
258 spill_slot
259 }
260
261 fn debug_new_val_to_local(
264 &self,
265 bx: &mut Bx,
266 local: mir::Local,
267 base: PlaceRef<'tcx, Bx::Value>,
268 projection: &[mir::PlaceElem<'tcx>],
269 ) {
270 let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
271 if !full_debug_info {
272 return;
273 }
274
275 let vars = match &self.per_local_var_debug_info {
276 Some(per_local) => &per_local[local],
277 None => return,
278 };
279
280 let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
281 calculate_debuginfo_offset(bx, projection, base.layout);
282 for var in vars.iter() {
283 let Some(dbg_var) = var.dbg_var else {
284 continue;
285 };
286 let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else {
287 continue;
288 };
289 bx.dbg_var_value(
290 dbg_var,
291 dbg_loc,
292 base.val.llval,
293 direct_offset,
294 &indirect_offsets,
295 &var.fragment,
296 );
297 }
298 }
299
300 fn debug_poison_to_local(&self, bx: &mut Bx, local: mir::Local) {
301 let ty = self.monomorphize(self.mir.local_decls[local].ty);
302 let layout = bx.cx().layout_of(ty);
303 let to_backend_ty = bx.cx().immediate_backend_type(layout);
304 let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
305 self.debug_new_val_to_local(bx, local, place_ref, &[]);
306 }
307
308 pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
311 let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
312
313 let vars = match &self.per_local_var_debug_info {
314 Some(per_local) => &per_local[local],
315 None => return,
316 };
317 let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
318 let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
319
320 let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
321 let arg_index = local.index() - 1;
322
323 if arg_index == 0 && has_proj() {
326 None
330 } else if whole_local_var.is_some() {
331 None
337 } else {
338 let name = sym::empty;
339 let decl = &self.mir.local_decls[local];
340 let dbg_var = if full_debug_info {
341 self.adjusted_span_and_dbg_scope(bx, decl.source_info).map(
342 |(dbg_scope, _, span)| {
343 let kind = VariableKind::ArgumentVariable(arg_index + 1);
345
346 let arg_ty = self.monomorphize(decl.ty);
347
348 bx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
349 },
350 )
351 } else {
352 None
353 };
354
355 Some(PerLocalVarDebugInfo {
356 name,
357 source_info: decl.source_info,
358 dbg_var,
359 fragment: None,
360 projection: ty::List::empty(),
361 })
362 }
363 } else {
364 None
365 };
366
367 let local_ref = &self.locals[local];
368
369 let name = if bx.sess().fewer_names() {
370 None
371 } else {
372 Some(match whole_local_var.or_else(|| fallback_var.clone()) {
373 Some(var) if var.name != sym::empty => var.name.to_string(),
374 _ => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", local))
})format!("{local:?}"),
375 })
376 };
377
378 if let Some(name) = &name {
379 match local_ref {
380 LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
381 bx.set_var_name(place.val.llval, name);
382 }
383 LocalRef::Operand(operand) => match operand.val {
384 OperandValue::Ref(PlaceValue { llval: x, .. }) | OperandValue::Immediate(x) => {
385 bx.set_var_name(x, name);
386 }
387 OperandValue::Pair(a, b) => {
388 bx.set_var_name(a, &(name.clone() + ".0"));
391 bx.set_var_name(b, &(name.clone() + ".1"));
392 }
393 OperandValue::ZeroSized => {
394 }
396 },
397 LocalRef::PendingOperand => {}
398 }
399 }
400
401 if !full_debug_info || vars.is_empty() && fallback_var.is_none() {
402 return;
403 }
404
405 let base = match local_ref {
406 LocalRef::PendingOperand => return,
407
408 LocalRef::Operand(operand) => {
409 let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
412 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
413 return;
414 }
415
416 if operand.layout.ty.is_scalable_vector()
444 && bx.sess().target.arch == rustc_target::spec::Arch::AArch64
445 {
446 let (count, element_ty, _) =
447 operand.layout.ty.scalable_vector_parts(bx.tcx()).unwrap();
448 if element_ty.is_bool() && count != 16 {
450 return;
451 }
452 }
453
454 Self::spill_operand_to_stack(*operand, name, bx)
455 }
456
457 LocalRef::Place(place) => *place,
458
459 LocalRef::UnsizedPlace(_) => return,
461 };
462
463 let vars = vars.iter().cloned().chain(fallback_var);
464
465 for var in vars {
466 self.debug_introduce_local_as_var(bx, local, base, var);
467 }
468 }
469
470 fn debug_introduce_local_as_var(
471 &self,
472 bx: &mut Bx,
473 local: mir::Local,
474 base: PlaceRef<'tcx, Bx::Value>,
475 var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
476 ) {
477 let Some(dbg_var) = var.dbg_var else { return };
478 let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else { return };
479
480 let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
481 calculate_debuginfo_offset(bx, var.projection, base.layout);
482
483 let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
491 && self.mir.local_kind(local) == mir::LocalKind::Arg
492 && (direct_offset != Size::ZERO || !#[allow(non_exhaustive_omitted_patterns)] match &indirect_offsets[..] {
[Size::ZERO] | [] => true,
_ => false,
}matches!(&indirect_offsets[..], [Size::ZERO] | []));
496
497 if should_create_individual_allocas {
498 let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
499 calculate_debuginfo_offset(bx, var.projection, base);
500
501 let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
503 let ptr_layout = bx.layout_of(ptr_ty);
504 let alloca = PlaceRef::alloca(bx, ptr_layout);
505 bx.set_var_name(alloca.val.llval, &(var.name.to_string() + ".dbg.spill"));
506
507 bx.store_to_place(place.val.llval, alloca.val);
509
510 bx.dbg_var_addr(
512 dbg_var,
513 dbg_loc,
514 alloca.val.llval,
515 Size::ZERO,
516 &[Size::ZERO],
517 &var.fragment,
518 );
519 } else {
520 bx.dbg_var_addr(
521 dbg_var,
522 dbg_loc,
523 base.val.llval,
524 direct_offset,
525 &indirect_offsets,
526 &var.fragment,
527 );
528 }
529 }
530
531 pub(crate) fn debug_introduce_locals(
532 &self,
533 bx: &mut Bx,
534 consts: Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
535 ) {
536 if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
537 for local in self.locals.indices() {
538 self.debug_introduce_local(bx, local);
539 }
540
541 for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in
542 consts.into_iter()
543 {
544 self.set_debug_loc(bx, source_info);
545 let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
546 bx.clear_dbg_loc();
547
548 bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], &fragment);
549 }
550 }
551 }
552
553 pub(crate) fn compute_per_local_var_debug_info(
555 &self,
556 bx: &mut Bx,
557 ) -> Option<(
558 PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>,
559 Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
560 )> {
561 let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
562
563 let target_is_msvc = self.cx.sess().target.is_like_msvc;
564
565 if !full_debug_info && self.cx.sess().fewer_names() {
566 return None;
567 }
568
569 let mut per_local = IndexVec::from_elem(::alloc::vec::Vec::new()vec![], &self.mir.local_decls);
570 let mut constants = ::alloc::vec::Vec::new()vec![];
571 let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default();
572 for var in &self.mir.var_debug_info {
573 let dbg_scope_and_span = if full_debug_info {
574 self.adjusted_span_and_dbg_scope(bx, var.source_info)
575 } else {
576 None
577 };
578
579 let var_ty = if let Some(ref fragment) = var.composite {
580 self.monomorphize(fragment.ty)
581 } else {
582 match var.value {
583 mir::VarDebugInfoContents::Place(place) => {
584 self.monomorphized_place_ty(place.as_ref())
585 }
586 mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
587 }
588 };
589
590 let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
591 let var_kind = if let Some(arg_index) = var.argument_index
592 && var.composite.is_none()
593 && let mir::VarDebugInfoContents::Place(place) = var.value
594 && place.projection.is_empty()
595 {
596 let arg_index = arg_index as usize;
597 if target_is_msvc {
598 let var_ty_layout = self.cx.layout_of(var_ty);
602 if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
603 var_ty_layout.backend_repr
604 {
605 VariableKind::LocalVariable
606 } else {
607 VariableKind::ArgumentVariable(arg_index)
608 }
609 } else {
610 VariableKind::ArgumentVariable(arg_index)
613 }
614 } else {
615 VariableKind::LocalVariable
616 };
617
618 if let VariableKind::ArgumentVariable(arg_index) = var_kind {
619 match params_seen.entry((dbg_scope, arg_index)) {
620 Entry::Occupied(o) => o.get().clone(),
621 Entry::Vacant(v) => v
622 .insert(bx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span))
623 .clone(),
624 }
625 } else {
626 bx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
627 }
628 });
629
630 let fragment = if let Some(ref fragment) = var.composite {
631 let var_layout = self.cx.layout_of(var_ty);
632
633 let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
634 calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
635 if !indirect_offsets.is_empty() {
::core::panicking::panic("assertion failed: indirect_offsets.is_empty()")
};assert!(indirect_offsets.is_empty());
636
637 if fragment_layout.size == Size::ZERO {
638 continue;
641 } else if fragment_layout.size == var_layout.size {
642 None
645 } else {
646 Some(direct_offset..direct_offset + fragment_layout.size)
647 }
648 } else {
649 None
650 };
651
652 match var.value {
653 mir::VarDebugInfoContents::Place(place) => {
654 per_local[place.local].push(PerLocalVarDebugInfo {
655 name: var.name,
656 source_info: var.source_info,
657 dbg_var,
658 fragment,
659 projection: place.projection,
660 });
661 }
662 mir::VarDebugInfoContents::Const(c) => {
663 if let Some(dbg_var) = dbg_var {
664 let Some(dbg_loc) = self.dbg_loc(bx, var.source_info) else { continue };
665
666 let operand = self.eval_mir_constant_to_operand(bx, &c);
667 constants.push(ConstDebugInfo {
668 name: var.name.to_string(),
669 source_info: var.source_info,
670 operand,
671 dbg_var,
672 dbg_loc,
673 fragment,
674 _phantom: PhantomData,
675 });
676 }
677 }
678 }
679 }
680 Some((per_local, constants))
681 }
682
683 pub(crate) fn codegen_stmt_debuginfo(
684 &mut self,
685 bx: &mut Bx,
686 debuginfo: &mir::StmtDebugInfo<'tcx>,
687 ) {
688 match debuginfo {
689 mir::StmtDebugInfo::AssignRef(dest, place) => {
690 let local_ref = match self.locals[place.local] {
691 LocalRef::Place(place_ref) => Some((place_ref, place.projection.as_slice())),
694 LocalRef::Operand(operand_ref) if place.is_indirect_first_projection() => {
697 Some((operand_ref.deref(bx.cx()), &place.projection[1..]))
698 }
699 LocalRef::Operand(_) => None,
703 LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => None,
704 }
705 .filter(|(_, projection)| {
706 projection.iter().all(|p| p.can_use_in_debuginfo())
708 });
709 if let Some((base, projection)) = local_ref {
710 self.debug_new_val_to_local(bx, *dest, base, projection);
711 } else {
712 self.debug_poison_to_local(bx, *dest);
714 }
715 }
716 mir::StmtDebugInfo::InvalidAssign(local) => {
717 self.debug_poison_to_local(bx, *local);
718 }
719 }
720 }
721
722 pub(crate) fn codegen_stmt_debuginfos(
723 &mut self,
724 bx: &mut Bx,
725 debuginfos: &[mir::StmtDebugInfo<'tcx>],
726 ) {
727 for debuginfo in debuginfos {
728 self.codegen_stmt_debuginfo(bx, debuginfo);
729 }
730 }
731
732 pub(super) fn fill_function_debug_context(&mut self, bx: &mut Bx) {
737 if self.cx.sess().opts.debuginfo == DebugInfo::None {
738 return;
739 }
740
741 self.debug_context = Some(FunctionDebugContext {
743 scopes: IndexVec::with_capacity(self.mir.source_scopes.len()),
744 inlined_function_scopes: Default::default(),
745 });
746
747 let variables = if self.cx.sess().opts.debuginfo == DebugInfo::Full {
749 let mut vars = DenseBitSet::new_empty(self.mir.source_scopes.len());
750 for var_debug_info in &self.mir.var_debug_info {
755 vars.insert(var_debug_info.source_info.scope);
756 }
757 Some(vars)
758 } else {
759 None
761 };
762
763 let mut discriminators = FxHashMap::default();
765 for scope in self.mir.source_scopes.indices() {
766 let scope_data = self.make_mir_scope(bx, &variables, &mut discriminators, scope);
767 let _s = self.debug_context.as_mut().unwrap().scopes.push(scope_data);
768 if true {
{
match (&_s, &scope) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(_s, scope);
769 }
770 }
771
772 fn make_mir_scope(
773 &mut self,
774 bx: &mut Bx,
775 variables: &Option<DenseBitSet<mir::SourceScope>>,
776 discriminators: &mut FxHashMap<BytePos, u32>,
777 scope: mir::SourceScope,
778 ) -> DebugScope<Bx::DIScope, Bx::DILocation> {
779 let scope_data = &self.mir.source_scopes[scope];
780 let parent_scope = if let Some(parent) = scope_data.parent_scope {
781 if true {
if !(parent.as_u32() < scope.as_u32()) {
::core::panicking::panic("assertion failed: parent.as_u32() < scope.as_u32()")
};
};debug_assert!(parent.as_u32() < scope.as_u32());
782 self.debug_context.as_ref().unwrap().scopes[parent]
783 } else {
784 let file = self.cx.sess().source_map().lookup_source_file(self.mir.span.lo());
786 let dbg_scope = bx.dbg_scope_fn(self.instance, self.fn_abi, Some(self.llfn));
787 return DebugScope {
788 dbg_scope,
789 inlined_at: None,
790 file_start_pos: file.start_pos,
791 file_end_pos: file.end_position(),
792 };
793 };
794
795 if let Some(vars) = variables
796 && !vars.contains(scope)
797 && scope_data.inlined.is_none()
798 {
799 return parent_scope;
802 }
803
804 let dbg_scope = match scope_data.inlined {
805 Some((callee, _)) => {
806 let callee = self.monomorphize(callee);
807 *self
808 .debug_context
809 .as_mut()
810 .unwrap()
811 .inlined_function_scopes
812 .entry(callee)
813 .or_insert_with(|| {
814 let callee_fn_abi = self.cx.fn_abi_of_instance(callee, ty::List::empty());
815 bx.dbg_scope_fn(callee, callee_fn_abi, None)
816 })
817 }
818 None => bx.dbg_create_lexical_block(scope_data.span.lo(), parent_scope.dbg_scope),
819 };
820
821 let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
822 let callsite_span = hygiene::walk_chain_collapsed(callsite_span, self.mir.span);
823 let callsite_scope = parent_scope.adjust_dbg_scope_for_span(bx, callsite_span);
824 let loc = bx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
825
826 match discriminators.entry(callsite_span.lo()) {
845 Entry::Occupied(mut o) => {
846 *o.get_mut() += 1;
847 bx.dbg_location_clone_with_discriminator(loc, *o.get()).unwrap_or_else(|| {
851 bx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP)
852 })
853 }
854 Entry::Vacant(v) => {
855 v.insert(0);
856 loc
857 }
858 }
859 });
860
861 let file = self.cx.sess().source_map().lookup_source_file(scope_data.span.lo());
862 DebugScope {
863 dbg_scope,
864 inlined_at: inlined_at.or(parent_scope.inlined_at),
865 file_start_pos: file.start_pos,
866 file_end_pos: file.end_position(),
867 }
868 }
869}