Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 91d8086

Browse files
committedJan 18, 2022
[debuginfo] Fix and unify handling of fat pointers in debuginfo.
1 parent 7531d2f commit 91d8086

File tree

4 files changed

+273
-180
lines changed

4 files changed

+273
-180
lines changed
 

‎compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

Lines changed: 180 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use super::CrateDebugContext;
1010

1111
use crate::abi;
1212
use crate::common::CodegenCx;
13+
use crate::debuginfo::utils::fat_pointer_kind;
14+
use crate::debuginfo::utils::FatPtrKind;
1315
use crate::llvm;
1416
use crate::llvm::debuginfo::{
1517
DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
@@ -376,22 +378,24 @@ macro_rules! return_if_metadata_created_in_meantime {
376378
};
377379
}
378380

379-
fn fixed_vec_metadata<'ll, 'tcx>(
381+
/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
382+
/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata].
383+
fn fixed_size_array_metadata<'ll, 'tcx>(
380384
cx: &CodegenCx<'ll, 'tcx>,
381385
unique_type_id: UniqueTypeId,
382-
array_or_slice_type: Ty<'tcx>,
383-
element_type: Ty<'tcx>,
386+
array_type: Ty<'tcx>,
384387
) -> MetadataCreationResult<'ll> {
388+
let ty::Array(element_type, len) = array_type.kind() else {
389+
bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type)
390+
};
391+
385392
let element_type_metadata = type_metadata(cx, element_type);
386393

387394
return_if_metadata_created_in_meantime!(cx, unique_type_id);
388395

389-
let (size, align) = cx.size_and_align_of(array_or_slice_type);
396+
let (size, align) = cx.size_and_align_of(array_type);
390397

391-
let upper_bound = match array_or_slice_type.kind() {
392-
ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
393-
_ => -1,
394-
};
398+
let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
395399

396400
let subrange =
397401
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
@@ -410,55 +414,111 @@ fn fixed_vec_metadata<'ll, 'tcx>(
410414
MetadataCreationResult::new(metadata, false)
411415
}
412416

413-
fn vec_slice_metadata<'ll, 'tcx>(
417+
/// Creates debuginfo for built-in pointer-like things:
418+
///
419+
/// - ty::Ref
420+
/// - ty::RawPtr
421+
/// - ty::Adt in the case it's Box
422+
///
423+
/// At some point we might want to remove the special handling of Box
424+
/// and treat it the same as other smart pointers (like Rc, Arc, ...).
425+
fn pointer_or_reference_metadata<'ll, 'tcx>(
414426
cx: &CodegenCx<'ll, 'tcx>,
415-
slice_ptr_type: Ty<'tcx>,
416-
element_type: Ty<'tcx>,
427+
ptr_type: Ty<'tcx>,
428+
pointee_type: Ty<'tcx>,
417429
unique_type_id: UniqueTypeId,
418430
) -> MetadataCreationResult<'ll> {
419-
let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
420-
421-
let data_ptr_metadata = type_metadata(cx, data_ptr_type);
431+
let pointee_type_metadata = type_metadata(cx, pointee_type);
422432

423433
return_if_metadata_created_in_meantime!(cx, unique_type_id);
424434

425-
let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
426-
427-
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
428-
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
429-
430-
let member_descriptions = vec![
431-
MemberDescription {
432-
name: "data_ptr".to_owned(),
433-
type_metadata: data_ptr_metadata,
434-
offset: Size::ZERO,
435-
size: pointer_size,
436-
align: pointer_align,
437-
flags: DIFlags::FlagZero,
438-
discriminant: None,
439-
source_info: None,
440-
},
441-
MemberDescription {
442-
name: "length".to_owned(),
443-
type_metadata: type_metadata(cx, cx.tcx.types.usize),
444-
offset: pointer_size,
445-
size: usize_size,
446-
align: usize_align,
447-
flags: DIFlags::FlagZero,
448-
discriminant: None,
449-
source_info: None,
450-
},
451-
];
435+
let (thin_pointer_size, thin_pointer_align) =
436+
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
437+
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
452438

453-
let metadata = composite_type_metadata(
454-
cx,
455-
slice_ptr_type,
456-
&slice_type_name,
457-
unique_type_id,
458-
member_descriptions,
459-
NO_SCOPE_METADATA,
460-
);
461-
MetadataCreationResult::new(metadata, false)
439+
let pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) {
440+
None => {
441+
// This is a thin pointer. Create a regular pointer type and give it the correct name.
442+
debug_assert_eq!(
443+
(thin_pointer_size, thin_pointer_align),
444+
cx.size_and_align_of(ptr_type)
445+
);
446+
447+
unsafe {
448+
llvm::LLVMRustDIBuilderCreatePointerType(
449+
DIB(cx),
450+
pointee_type_metadata,
451+
thin_pointer_size.bits(),
452+
thin_pointer_align.bits() as u32,
453+
0, // Ignore DWARF address space.
454+
ptr_type_debuginfo_name.as_ptr().cast(),
455+
ptr_type_debuginfo_name.len(),
456+
)
457+
}
458+
}
459+
Some(fat_pointer_kind) => {
460+
let layout = cx.layout_of(ptr_type);
461+
462+
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
463+
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
464+
465+
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
466+
FatPtrKind::Dyn => ("pointer", "vtable"),
467+
FatPtrKind::Slice => ("data_ptr", "length"),
468+
};
469+
470+
debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
471+
debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
472+
473+
// The data pointer type is a regular, thin pointer, regardless of whether this is a slice
474+
// or a trait object.
475+
let data_ptr_type_metadata = unsafe {
476+
llvm::LLVMRustDIBuilderCreatePointerType(
477+
DIB(cx),
478+
pointee_type_metadata,
479+
addr_field.size.bits(),
480+
addr_field.align.abi.bits() as u32,
481+
0, // Ignore DWARF address space.
482+
std::ptr::null(),
483+
0,
484+
)
485+
};
486+
487+
let member_descriptions = vec![
488+
MemberDescription {
489+
name: addr_field_name.into(),
490+
type_metadata: data_ptr_type_metadata,
491+
offset: layout.fields.offset(abi::FAT_PTR_ADDR),
492+
size: addr_field.size,
493+
align: addr_field.align.abi,
494+
flags: DIFlags::FlagArtificial,
495+
discriminant: None,
496+
source_info: None,
497+
},
498+
MemberDescription {
499+
name: extra_field_name.into(),
500+
type_metadata: type_metadata(cx, extra_field.ty),
501+
offset: layout.fields.offset(abi::FAT_PTR_EXTRA),
502+
size: extra_field.size,
503+
align: extra_field.align.abi,
504+
flags: DIFlags::FlagArtificial,
505+
discriminant: None,
506+
source_info: None,
507+
},
508+
];
509+
510+
composite_type_metadata(
511+
cx,
512+
ptr_type,
513+
&ptr_type_debuginfo_name,
514+
unique_type_id,
515+
member_descriptions,
516+
NO_SCOPE_METADATA,
517+
)
518+
}
519+
};
520+
521+
MetadataCreationResult { metadata: pointer_type_metadata, already_stored_in_typemap: false }
462522
}
463523

464524
fn subroutine_type_metadata<'ll, 'tcx>(
@@ -495,83 +555,57 @@ fn subroutine_type_metadata<'ll, 'tcx>(
495555
)
496556
}
497557

498-
// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
499-
// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
500-
// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
501-
// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
502-
// of a DST struct, there is no `trait_object_type` and the results of this
503-
// function will be a little bit weird.
504-
fn trait_pointer_metadata<'ll, 'tcx>(
558+
// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
559+
// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
560+
fn dyn_type_metadata<'ll, 'tcx>(
505561
cx: &CodegenCx<'ll, 'tcx>,
506-
trait_type: Ty<'tcx>,
507-
trait_object_type: Option<Ty<'tcx>>,
562+
dyn_type: Ty<'tcx>,
508563
unique_type_id: UniqueTypeId,
509564
) -> &'ll DIType {
510-
// The implementation provided here is a stub. It makes sure that the trait
511-
// type is assigned the correct name, size, namespace, and source location.
512-
// However, it does not describe the trait's methods.
513-
514-
let (containing_scope, trait_type_name) = match trait_object_type {
515-
Some(trait_object_type) => match trait_object_type.kind() {
516-
ty::Adt(def, _) => (
517-
Some(get_namespace_for_item(cx, def.did)),
518-
compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
519-
),
520-
ty::RawPtr(_) | ty::Ref(..) => {
521-
(NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
522-
}
523-
_ => {
524-
bug!(
525-
"debuginfo: unexpected trait-object type in \
526-
trait_pointer_metadata(): {:?}",
527-
trait_object_type
528-
);
529-
}
530-
},
565+
if let ty::Dynamic(..) = dyn_type.kind() {
566+
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
567+
composite_type_metadata(cx, dyn_type, &type_name, unique_type_id, vec![], NO_SCOPE_METADATA)
568+
} else {
569+
bug!("Only ty::Dynamic is valid for dyn_type_metadata(). Found {:?} instead.", dyn_type)
570+
}
571+
}
531572

532-
// No object type, use the trait type directly (no scope here since the type
533-
// will be wrapped in the dyn$ synthetic type).
534-
None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
573+
// Create debuginfo for `[T]` and `str`. These are unsized.
574+
//
575+
// Note: We currently emit just emit the debuginfo for the element type here
576+
// (i.e. `T` for slices and `u8` for `str`), so that we end up with
577+
// `*const T` for the `data_ptr` field of the corresponding fat-pointer
578+
// debuginfo of `&[T]`.
579+
//
580+
// It would be preferable and more accurate if we emitted a DIArray of T
581+
// without an upper bound instead. That is, LLVM already supports emitting
582+
// debuginfo of arrays of unknown size. But GDB currently seems to end up
583+
// in an infinite loop when confronted with such a type.
584+
//
585+
// As a side effect of the current encoding every instance of a type like
586+
// `struct Foo { unsized_field: [u8] }` will look like
587+
// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
588+
// slice is zero, then accessing `unsized_field` in the debugger would
589+
// result in an out-of-bounds access.
590+
fn slice_type_metadata<'ll, 'tcx>(
591+
cx: &CodegenCx<'ll, 'tcx>,
592+
slice_type: Ty<'tcx>,
593+
unique_type_id: UniqueTypeId,
594+
) -> MetadataCreationResult<'ll> {
595+
let element_type = match slice_type.kind() {
596+
ty::Slice(element_type) => element_type,
597+
ty::Str => cx.tcx.types.u8,
598+
_ => {
599+
bug!(
600+
"Only ty::Slice is valid for slice_type_metadata(). Found {:?} instead.",
601+
slice_type
602+
)
603+
}
535604
};
536605

537-
let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
538-
539-
assert_eq!(abi::FAT_PTR_ADDR, 0);
540-
assert_eq!(abi::FAT_PTR_EXTRA, 1);
541-
542-
let data_ptr_field = layout.field(cx, 0);
543-
let vtable_field = layout.field(cx, 1);
544-
let member_descriptions = vec![
545-
MemberDescription {
546-
name: "pointer".to_owned(),
547-
type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)),
548-
offset: layout.fields.offset(0),
549-
size: data_ptr_field.size,
550-
align: data_ptr_field.align.abi,
551-
flags: DIFlags::FlagArtificial,
552-
discriminant: None,
553-
source_info: None,
554-
},
555-
MemberDescription {
556-
name: "vtable".to_owned(),
557-
type_metadata: type_metadata(cx, vtable_field.ty),
558-
offset: layout.fields.offset(1),
559-
size: vtable_field.size,
560-
align: vtable_field.align.abi,
561-
flags: DIFlags::FlagArtificial,
562-
discriminant: None,
563-
source_info: None,
564-
},
565-
];
566-
567-
composite_type_metadata(
568-
cx,
569-
trait_object_type.unwrap_or(trait_type),
570-
&trait_type_name,
571-
unique_type_id,
572-
member_descriptions,
573-
containing_scope,
574-
)
606+
let element_type_metadata = type_metadata(cx, element_type);
607+
return_if_metadata_created_in_meantime!(cx, unique_type_id);
608+
MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false }
575609
}
576610

577611
pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
@@ -610,49 +644,27 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
610644

611645
debug!("type_metadata: {:?}", t);
612646

613-
let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
614-
ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)),
615-
ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)),
616-
ty::Dynamic(..) => Ok(MetadataCreationResult::new(
617-
trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
618-
false,
619-
)),
620-
_ => {
621-
let pointee_metadata = type_metadata(cx, ty);
622-
623-
if let Some(metadata) =
624-
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
625-
{
626-
return Err(metadata);
627-
}
628-
629-
Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false))
630-
}
631-
};
632-
633647
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
634648
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
635649
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
636650
}
637651
ty::Tuple(elements) if elements.is_empty() => {
638652
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
639653
}
640-
ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
641-
ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
654+
ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t),
655+
ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id),
642656
ty::Dynamic(..) => {
643-
MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
657+
MetadataCreationResult::new(dyn_type_metadata(cx, t, unique_type_id), false)
644658
}
645659
ty::Foreign(..) => {
646660
MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
647661
}
648-
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
649-
Ok(res) => res,
650-
Err(metadata) => return metadata,
651-
},
652-
ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
653-
Ok(res) => res,
654-
Err(metadata) => return metadata,
655-
},
662+
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
663+
pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
664+
}
665+
ty::Adt(def, _) if def.is_box() => {
666+
pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
667+
}
656668
ty::FnDef(..) | ty::FnPtr(_) => {
657669
if let Some(metadata) =
658670
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
@@ -694,7 +706,22 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
694706
type_map.borrow_mut().remove_type(t);
695707

696708
// This is actually a function pointer, so wrap it in pointer DI.
697-
MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
709+
let (pointer_size, pointer_align) =
710+
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit()));
711+
let name = compute_debuginfo_type_name(cx.tcx, t, false);
712+
let md = unsafe {
713+
llvm::LLVMRustDIBuilderCreatePointerType(
714+
DIB(cx),
715+
fn_metadata,
716+
pointer_size.bits(),
717+
pointer_align.bits() as u32,
718+
0, // Ignore DWARF address space.
719+
name.as_ptr().cast(),
720+
name.len(),
721+
)
722+
};
723+
724+
MetadataCreationResult::new(md, false)
698725
}
699726
ty::Closure(def_id, substs) => {
700727
let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
@@ -959,26 +986,6 @@ fn foreign_type_metadata<'ll, 'tcx>(
959986
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
960987
}
961988

962-
fn pointer_type_metadata<'ll, 'tcx>(
963-
cx: &CodegenCx<'ll, 'tcx>,
964-
pointer_type: Ty<'tcx>,
965-
pointee_type_metadata: &'ll DIType,
966-
) -> &'ll DIType {
967-
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
968-
let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
969-
unsafe {
970-
llvm::LLVMRustDIBuilderCreatePointerType(
971-
DIB(cx),
972-
pointee_type_metadata,
973-
pointer_size.bits(),
974-
pointer_align.bits() as u32,
975-
0, // Ignore DWARF address space.
976-
name.as_ptr().cast(),
977-
name.len(),
978-
)
979-
}
980-
}
981-
982989
fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
983990
debug!("param_type_metadata: {:?}", t);
984991
let name = format!("{:?}", t);

‎compiler/rustc_codegen_llvm/src/debuginfo/utils.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use super::namespace::item_namespace;
44
use super::CrateDebugContext;
55

66
use rustc_hir::def_id::DefId;
7-
use rustc_middle::ty::DefIdTree;
7+
use rustc_middle::ty::layout::LayoutOf;
8+
use rustc_middle::ty::{self, DefIdTree, Ty};
9+
use rustc_target::abi::VariantIdx;
810

911
use crate::common::CodegenCx;
1012
use crate::llvm;
@@ -46,3 +48,58 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
4648
pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
4749
item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
4850
}
51+
52+
#[derive(Debug, PartialEq, Eq)]
53+
pub(crate) enum FatPtrKind {
54+
Slice,
55+
Dyn,
56+
}
57+
58+
/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
59+
/// if the second field of the fat pointer is a length or a vtable-pointer.
60+
/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
61+
/// the function returns `None`.
62+
pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
63+
cx: &CodegenCx<'ll, 'tcx>,
64+
pointee_ty: Ty<'tcx>,
65+
) -> Option<FatPtrKind> {
66+
let layout = cx.layout_of(pointee_ty);
67+
68+
if !layout.is_unsized() {
69+
return None;
70+
}
71+
72+
match *pointee_ty.kind() {
73+
ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
74+
ty::Dynamic(..) => Some(FatPtrKind::Dyn),
75+
ty::Adt(adt_def, _) => {
76+
assert!(adt_def.is_struct());
77+
assert!(adt_def.variants.len() == 1);
78+
let variant = &adt_def.variants[VariantIdx::from_usize(0)];
79+
assert!(!variant.fields.is_empty());
80+
let last_field_index = variant.fields.len() - 1;
81+
82+
debug_assert!(
83+
(0..last_field_index)
84+
.all(|field_index| { !layout.field(cx, field_index).is_unsized() })
85+
);
86+
87+
let unsized_field = layout.field(cx, last_field_index);
88+
assert!(unsized_field.is_unsized());
89+
fat_pointer_kind(cx, unsized_field.ty)
90+
}
91+
ty::Foreign(_) => {
92+
// Assert that pointers to foreign types really are thin:
93+
debug_assert_eq!(
94+
cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)),
95+
cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
96+
);
97+
None
98+
}
99+
_ => {
100+
// For all other pointee types we should already have returned None
101+
// at the beginning of the function.
102+
panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty)
103+
}
104+
}
105+
}

‎compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![feature(crate_visibility_modifier)]
1010
#![feature(extern_types)]
1111
#![feature(nll)]
12+
#![feature(let_else)]
1213
#![recursion_limit = "256"]
1314

1415
use back::write::{create_informational_target_machine, create_target_machine};

‎src/test/debuginfo/unsized.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,36 @@
44

55
// gdb-command:run
66

7-
// gdb-command:print *a
8-
// gdbg-check:$1 = {value = [...] "abc"}
9-
// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]}
7+
// gdb-command:print a
8+
// gdbg-check:$1 = {data_ptr: [...], length: 4}
9+
// gdbr-check:$1 = &unsized::Foo<[u8]> {data_ptr: [...], length: 4}
1010

11-
// gdb-command:print *b
12-
// gdbg-check:$2 = {value = {value = [...] "abc"}}
13-
// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}}
11+
// gdb-command:print b
12+
// gdbg-check:$2 = {data_ptr: [...], length: 4}
13+
// gdbr-check:$2 = &unsized::Foo<unsized::Foo<[u8]>> {data_ptr: [...], length: 4}
14+
15+
// gdb-command:print c
16+
// gdbg-check:$3 = {pointer: [...], vtable: [...]}
17+
// gdbr-check:$3 = &unsized::Foo<dyn core::fmt::Debug> {pointer: [...], vtable: [...]}
18+
19+
20+
// === CDB TESTS ===================================================================================
21+
22+
// cdb-command: g
23+
// cdb-command:dx a
24+
// cdb-check:a [Type: ref$<unsized::Foo<slice$<u8> > >]
25+
// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<slice$<u8> > *]
26+
// cdb-check: [+0x008] length : 0x4 [Type: unsigned __int64]
27+
28+
// cdb-command:dx b
29+
// cdb-check:b [Type: ref$<unsized::Foo<unsized::Foo<slice$<u8> > > >]
30+
// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<unsized::Foo<slice$<u8> > > *]
31+
// cdb-check: [+0x008] length : 0x4 [Type: unsigned __int64]
32+
33+
// cdb-command:dx c
34+
// cdb-check:c [Type: ref$<unsized::Foo<dyn$<core::fmt::Debug> > >]
35+
// cdb-check: [+0x000] pointer : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *]
36+
// cdb-check: [+0x008] vtable : 0x[...] [Type: unsigned __int64 (*)[3]]
1437

1538

1639
#![feature(omit_gdb_pretty_printer_section)]
@@ -26,8 +49,13 @@ fn main() {
2649
value: *b"abc\0"
2750
}
2851
};
52+
53+
// We expect `a`, `b`, and `c` to all be fat pointers.
54+
// `a` and `b` should be slice-like and thus have a `data_ptr` and `length` field.
55+
// `c` should be trait-object-like and thus have a `pointer` and `vtable` field.
2956
let a: &Foo<[u8]> = &foo.value;
3057
let b: &Foo<Foo<[u8]>> = &foo;
58+
let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 };
3159

3260
zzz(); // #break
3361
}

0 commit comments

Comments
 (0)
Please sign in to comment.