[debuginfo] Fix and unify handling of fat pointers in debuginfo.
This commit is contained in:
parent
ef119d704d
commit
d253e6e473
4 changed files with 271 additions and 178 deletions
|
@ -10,6 +10,8 @@ use super::CrateDebugContext;
|
|||
|
||||
use crate::abi;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::debuginfo::utils::fat_pointer_kind;
|
||||
use crate::debuginfo::utils::FatPtrKind;
|
||||
use crate::llvm;
|
||||
use crate::llvm::debuginfo::{
|
||||
DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
|
||||
|
@ -376,22 +378,24 @@ macro_rules! return_if_metadata_created_in_meantime {
|
|||
};
|
||||
}
|
||||
|
||||
fn fixed_vec_metadata<'ll, 'tcx>(
|
||||
/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
|
||||
/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata].
|
||||
fn fixed_size_array_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
array_or_slice_type: Ty<'tcx>,
|
||||
element_type: Ty<'tcx>,
|
||||
array_type: Ty<'tcx>,
|
||||
) -> MetadataCreationResult<'ll> {
|
||||
let ty::Array(element_type, len) = array_type.kind() else {
|
||||
bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type)
|
||||
};
|
||||
|
||||
let element_type_metadata = type_metadata(cx, element_type);
|
||||
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let (size, align) = cx.size_and_align_of(array_or_slice_type);
|
||||
let (size, align) = cx.size_and_align_of(array_type);
|
||||
|
||||
let upper_bound = match array_or_slice_type.kind() {
|
||||
ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
|
||||
_ => -1,
|
||||
};
|
||||
let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
|
||||
|
||||
let subrange =
|
||||
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
||||
|
@ -410,55 +414,111 @@ fn fixed_vec_metadata<'ll, 'tcx>(
|
|||
MetadataCreationResult::new(metadata, false)
|
||||
}
|
||||
|
||||
fn vec_slice_metadata<'ll, 'tcx>(
|
||||
/// Creates debuginfo for built-in pointer-like things:
|
||||
///
|
||||
/// - ty::Ref
|
||||
/// - ty::RawPtr
|
||||
/// - ty::Adt in the case it's Box
|
||||
///
|
||||
/// At some point we might want to remove the special handling of Box
|
||||
/// and treat it the same as other smart pointers (like Rc, Arc, ...).
|
||||
fn pointer_or_reference_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
slice_ptr_type: Ty<'tcx>,
|
||||
element_type: Ty<'tcx>,
|
||||
ptr_type: Ty<'tcx>,
|
||||
pointee_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
) -> MetadataCreationResult<'ll> {
|
||||
let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
|
||||
|
||||
let data_ptr_metadata = type_metadata(cx, data_ptr_type);
|
||||
let pointee_type_metadata = type_metadata(cx, pointee_type);
|
||||
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
|
||||
let (thin_pointer_size, thin_pointer_align) =
|
||||
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
|
||||
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
|
||||
|
||||
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
|
||||
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
|
||||
let pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) {
|
||||
None => {
|
||||
// This is a thin pointer. Create a regular pointer type and give it the correct name.
|
||||
debug_assert_eq!(
|
||||
(thin_pointer_size, thin_pointer_align),
|
||||
cx.size_and_align_of(ptr_type)
|
||||
);
|
||||
|
||||
let member_descriptions = vec![
|
||||
MemberDescription {
|
||||
name: "data_ptr".to_owned(),
|
||||
type_metadata: data_ptr_metadata,
|
||||
offset: Size::ZERO,
|
||||
size: pointer_size,
|
||||
align: pointer_align,
|
||||
flags: DIFlags::FlagZero,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "length".to_owned(),
|
||||
type_metadata: type_metadata(cx, cx.tcx.types.usize),
|
||||
offset: pointer_size,
|
||||
size: usize_size,
|
||||
align: usize_align,
|
||||
flags: DIFlags::FlagZero,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
];
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||
DIB(cx),
|
||||
pointee_type_metadata,
|
||||
thin_pointer_size.bits(),
|
||||
thin_pointer_align.bits() as u32,
|
||||
0, // Ignore DWARF address space.
|
||||
ptr_type_debuginfo_name.as_ptr().cast(),
|
||||
ptr_type_debuginfo_name.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Some(fat_pointer_kind) => {
|
||||
let layout = cx.layout_of(ptr_type);
|
||||
|
||||
let metadata = composite_type_metadata(
|
||||
cx,
|
||||
slice_ptr_type,
|
||||
&slice_type_name,
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
NO_SCOPE_METADATA,
|
||||
);
|
||||
MetadataCreationResult::new(metadata, false)
|
||||
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
|
||||
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
|
||||
|
||||
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
|
||||
FatPtrKind::Dyn => ("pointer", "vtable"),
|
||||
FatPtrKind::Slice => ("data_ptr", "length"),
|
||||
};
|
||||
|
||||
debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
|
||||
// The data pointer type is a regular, thin pointer, regardless of whether this is a slice
|
||||
// or a trait object.
|
||||
let data_ptr_type_metadata = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||
DIB(cx),
|
||||
pointee_type_metadata,
|
||||
addr_field.size.bits(),
|
||||
addr_field.align.abi.bits() as u32,
|
||||
0, // Ignore DWARF address space.
|
||||
std::ptr::null(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
let member_descriptions = vec![
|
||||
MemberDescription {
|
||||
name: addr_field_name.into(),
|
||||
type_metadata: data_ptr_type_metadata,
|
||||
offset: layout.fields.offset(abi::FAT_PTR_ADDR),
|
||||
size: addr_field.size,
|
||||
align: addr_field.align.abi,
|
||||
flags: DIFlags::FlagArtificial,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
MemberDescription {
|
||||
name: extra_field_name.into(),
|
||||
type_metadata: type_metadata(cx, extra_field.ty),
|
||||
offset: layout.fields.offset(abi::FAT_PTR_EXTRA),
|
||||
size: extra_field.size,
|
||||
align: extra_field.align.abi,
|
||||
flags: DIFlags::FlagArtificial,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
];
|
||||
|
||||
composite_type_metadata(
|
||||
cx,
|
||||
ptr_type,
|
||||
&ptr_type_debuginfo_name,
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
NO_SCOPE_METADATA,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
MetadataCreationResult { metadata: pointer_type_metadata, already_stored_in_typemap: false }
|
||||
}
|
||||
|
||||
fn subroutine_type_metadata<'ll, 'tcx>(
|
||||
|
@ -495,83 +555,57 @@ fn subroutine_type_metadata<'ll, 'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
|
||||
// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
|
||||
// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
|
||||
// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
|
||||
// of a DST struct, there is no `trait_object_type` and the results of this
|
||||
// function will be a little bit weird.
|
||||
fn trait_pointer_metadata<'ll, 'tcx>(
|
||||
// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
|
||||
// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
|
||||
fn dyn_type_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
trait_type: Ty<'tcx>,
|
||||
trait_object_type: Option<Ty<'tcx>>,
|
||||
dyn_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
) -> &'ll DIType {
|
||||
// The implementation provided here is a stub. It makes sure that the trait
|
||||
// type is assigned the correct name, size, namespace, and source location.
|
||||
// However, it does not describe the trait's methods.
|
||||
if let ty::Dynamic(..) = dyn_type.kind() {
|
||||
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
|
||||
composite_type_metadata(cx, dyn_type, &type_name, unique_type_id, vec![], NO_SCOPE_METADATA)
|
||||
} else {
|
||||
bug!("Only ty::Dynamic is valid for dyn_type_metadata(). Found {:?} instead.", dyn_type)
|
||||
}
|
||||
}
|
||||
|
||||
let (containing_scope, trait_type_name) = match trait_object_type {
|
||||
Some(trait_object_type) => match trait_object_type.kind() {
|
||||
ty::Adt(def, _) => (
|
||||
Some(get_namespace_for_item(cx, def.did)),
|
||||
compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
|
||||
),
|
||||
ty::RawPtr(_) | ty::Ref(..) => {
|
||||
(NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"debuginfo: unexpected trait-object type in \
|
||||
trait_pointer_metadata(): {:?}",
|
||||
trait_object_type
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// No object type, use the trait type directly (no scope here since the type
|
||||
// will be wrapped in the dyn$ synthetic type).
|
||||
None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
|
||||
// Create debuginfo for `[T]` and `str`. These are unsized.
|
||||
//
|
||||
// Note: We currently emit just emit the debuginfo for the element type here
|
||||
// (i.e. `T` for slices and `u8` for `str`), so that we end up with
|
||||
// `*const T` for the `data_ptr` field of the corresponding fat-pointer
|
||||
// debuginfo of `&[T]`.
|
||||
//
|
||||
// It would be preferable and more accurate if we emitted a DIArray of T
|
||||
// without an upper bound instead. That is, LLVM already supports emitting
|
||||
// debuginfo of arrays of unknown size. But GDB currently seems to end up
|
||||
// in an infinite loop when confronted with such a type.
|
||||
//
|
||||
// As a side effect of the current encoding every instance of a type like
|
||||
// `struct Foo { unsized_field: [u8] }` will look like
|
||||
// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
|
||||
// slice is zero, then accessing `unsized_field` in the debugger would
|
||||
// result in an out-of-bounds access.
|
||||
fn slice_type_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
slice_type: Ty<'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
) -> MetadataCreationResult<'ll> {
|
||||
let element_type = match slice_type.kind() {
|
||||
ty::Slice(element_type) => element_type,
|
||||
ty::Str => cx.tcx.types.u8,
|
||||
_ => {
|
||||
bug!(
|
||||
"Only ty::Slice is valid for slice_type_metadata(). Found {:?} instead.",
|
||||
slice_type
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
|
||||
|
||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
|
||||
let data_ptr_field = layout.field(cx, 0);
|
||||
let vtable_field = layout.field(cx, 1);
|
||||
let member_descriptions = vec![
|
||||
MemberDescription {
|
||||
name: "pointer".to_owned(),
|
||||
type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)),
|
||||
offset: layout.fields.offset(0),
|
||||
size: data_ptr_field.size,
|
||||
align: data_ptr_field.align.abi,
|
||||
flags: DIFlags::FlagArtificial,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "vtable".to_owned(),
|
||||
type_metadata: type_metadata(cx, vtable_field.ty),
|
||||
offset: layout.fields.offset(1),
|
||||
size: vtable_field.size,
|
||||
align: vtable_field.align.abi,
|
||||
flags: DIFlags::FlagArtificial,
|
||||
discriminant: None,
|
||||
source_info: None,
|
||||
},
|
||||
];
|
||||
|
||||
composite_type_metadata(
|
||||
cx,
|
||||
trait_object_type.unwrap_or(trait_type),
|
||||
&trait_type_name,
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
containing_scope,
|
||||
)
|
||||
let element_type_metadata = type_metadata(cx, element_type);
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false }
|
||||
}
|
||||
|
||||
pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
||||
|
@ -610,26 +644,6 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
|
|||
|
||||
debug!("type_metadata: {:?}", t);
|
||||
|
||||
let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
|
||||
ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)),
|
||||
ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)),
|
||||
ty::Dynamic(..) => Ok(MetadataCreationResult::new(
|
||||
trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
|
||||
false,
|
||||
)),
|
||||
_ => {
|
||||
let pointee_metadata = type_metadata(cx, ty);
|
||||
|
||||
if let Some(metadata) =
|
||||
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
|
||||
{
|
||||
return Err(metadata);
|
||||
}
|
||||
|
||||
Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false))
|
||||
}
|
||||
};
|
||||
|
||||
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
|
||||
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
|
@ -637,22 +651,20 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
|
|||
ty::Tuple(elements) if elements.is_empty() => {
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
|
||||
ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
|
||||
ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t),
|
||||
ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id),
|
||||
ty::Dynamic(..) => {
|
||||
MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
|
||||
MetadataCreationResult::new(dyn_type_metadata(cx, t, unique_type_id), false)
|
||||
}
|
||||
ty::Foreign(..) => {
|
||||
MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
|
||||
}
|
||||
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
|
||||
Ok(res) => res,
|
||||
Err(metadata) => return metadata,
|
||||
},
|
||||
ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
|
||||
Ok(res) => res,
|
||||
Err(metadata) => return metadata,
|
||||
},
|
||||
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
|
||||
pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
|
||||
}
|
||||
ty::Adt(def, _) if def.is_box() => {
|
||||
pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
|
||||
}
|
||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||
if let Some(metadata) =
|
||||
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
|
|||
type_map.borrow_mut().remove_type(t);
|
||||
|
||||
// This is actually a function pointer, so wrap it in pointer DI.
|
||||
MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
|
||||
let (pointer_size, pointer_align) =
|
||||
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit()));
|
||||
let name = compute_debuginfo_type_name(cx.tcx, t, false);
|
||||
let md = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||
DIB(cx),
|
||||
fn_metadata,
|
||||
pointer_size.bits(),
|
||||
pointer_align.bits() as u32,
|
||||
0, // Ignore DWARF address space.
|
||||
name.as_ptr().cast(),
|
||||
name.len(),
|
||||
)
|
||||
};
|
||||
|
||||
MetadataCreationResult::new(md, false)
|
||||
}
|
||||
ty::Closure(def_id, substs) => {
|
||||
let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
|
||||
|
@ -959,26 +986,6 @@ fn foreign_type_metadata<'ll, 'tcx>(
|
|||
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
|
||||
}
|
||||
|
||||
fn pointer_type_metadata<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
pointer_type: Ty<'tcx>,
|
||||
pointee_type_metadata: &'ll DIType,
|
||||
) -> &'ll DIType {
|
||||
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
|
||||
let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||
DIB(cx),
|
||||
pointee_type_metadata,
|
||||
pointer_size.bits(),
|
||||
pointer_align.bits() as u32,
|
||||
0, // Ignore DWARF address space.
|
||||
name.as_ptr().cast(),
|
||||
name.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
||||
debug!("param_type_metadata: {:?}", t);
|
||||
let name = format!("{:?}", t);
|
||||
|
|
|
@ -4,7 +4,9 @@ use super::namespace::item_namespace;
|
|||
use super::CrateDebugContext;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::llvm;
|
||||
|
@ -46,3 +48,58 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
|
|||
pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
|
||||
item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) enum FatPtrKind {
|
||||
Slice,
|
||||
Dyn,
|
||||
}
|
||||
|
||||
/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
|
||||
/// if the second field of the fat pointer is a length or a vtable-pointer.
|
||||
/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
|
||||
/// the function returns `None`.
|
||||
pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
) -> Option<FatPtrKind> {
|
||||
let layout = cx.layout_of(pointee_ty);
|
||||
|
||||
if !layout.is_unsized() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match *pointee_ty.kind() {
|
||||
ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
|
||||
ty::Dynamic(..) => Some(FatPtrKind::Dyn),
|
||||
ty::Adt(adt_def, _) => {
|
||||
assert!(adt_def.is_struct());
|
||||
assert!(adt_def.variants.len() == 1);
|
||||
let variant = &adt_def.variants[VariantIdx::from_usize(0)];
|
||||
assert!(!variant.fields.is_empty());
|
||||
let last_field_index = variant.fields.len() - 1;
|
||||
|
||||
debug_assert!(
|
||||
(0..last_field_index)
|
||||
.all(|field_index| { !layout.field(cx, field_index).is_unsized() })
|
||||
);
|
||||
|
||||
let unsized_field = layout.field(cx, last_field_index);
|
||||
assert!(unsized_field.is_unsized());
|
||||
fat_pointer_kind(cx, unsized_field.ty)
|
||||
}
|
||||
ty::Foreign(_) => {
|
||||
// Assert that pointers to foreign types really are thin:
|
||||
debug_assert_eq!(
|
||||
cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)),
|
||||
cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
|
||||
);
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
// For all other pointee types we should already have returned None
|
||||
// at the beginning of the function.
|
||||
panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#![feature(let_else)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(nll)]
|
||||
#![feature(let_else)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use back::write::{create_informational_target_machine, create_target_machine};
|
||||
|
|
|
@ -4,13 +4,36 @@
|
|||
|
||||
// gdb-command:run
|
||||
|
||||
// gdb-command:print *a
|
||||
// gdbg-check:$1 = {value = [...] "abc"}
|
||||
// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]}
|
||||
// gdb-command:print a
|
||||
// gdbg-check:$1 = {data_ptr: [...], length: 4}
|
||||
// gdbr-check:$1 = &unsized::Foo<[u8]> {data_ptr: [...], length: 4}
|
||||
|
||||
// gdb-command:print *b
|
||||
// gdbg-check:$2 = {value = {value = [...] "abc"}}
|
||||
// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}}
|
||||
// gdb-command:print b
|
||||
// gdbg-check:$2 = {data_ptr: [...], length: 4}
|
||||
// gdbr-check:$2 = &unsized::Foo<unsized::Foo<[u8]>> {data_ptr: [...], length: 4}
|
||||
|
||||
// gdb-command:print c
|
||||
// gdbg-check:$3 = {pointer: [...], vtable: [...]}
|
||||
// gdbr-check:$3 = &unsized::Foo<dyn core::fmt::Debug> {pointer: [...], vtable: [...]}
|
||||
|
||||
|
||||
// === CDB TESTS ===================================================================================
|
||||
|
||||
// cdb-command: g
|
||||
// cdb-command:dx a
|
||||
// cdb-check:a [Type: ref$<unsized::Foo<slice$<u8> > >]
|
||||
// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<slice$<u8> > *]
|
||||
// cdb-check: [+0x008] length : 0x4 [Type: unsigned __int64]
|
||||
|
||||
// cdb-command:dx b
|
||||
// cdb-check:b [Type: ref$<unsized::Foo<unsized::Foo<slice$<u8> > > >]
|
||||
// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<unsized::Foo<slice$<u8> > > *]
|
||||
// cdb-check: [+0x008] length : 0x4 [Type: unsigned __int64]
|
||||
|
||||
// cdb-command:dx c
|
||||
// cdb-check:c [Type: ref$<unsized::Foo<dyn$<core::fmt::Debug> > >]
|
||||
// cdb-check: [+0x000] pointer : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *]
|
||||
// cdb-check: [+0x008] vtable : 0x[...] [Type: unsigned __int64 (*)[3]]
|
||||
|
||||
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
|
@ -26,8 +49,13 @@ fn main() {
|
|||
value: *b"abc\0"
|
||||
}
|
||||
};
|
||||
|
||||
// We expect `a`, `b`, and `c` to all be fat pointers.
|
||||
// `a` and `b` should be slice-like and thus have a `data_ptr` and `length` field.
|
||||
// `c` should be trait-object-like and thus have a `pointer` and `vtable` field.
|
||||
let a: &Foo<[u8]> = &foo.value;
|
||||
let b: &Foo<Foo<[u8]>> = &foo;
|
||||
let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 };
|
||||
|
||||
zzz(); // #break
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue