[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::abi;
|
||||||
use crate::common::CodegenCx;
|
use crate::common::CodegenCx;
|
||||||
|
use crate::debuginfo::utils::fat_pointer_kind;
|
||||||
|
use crate::debuginfo::utils::FatPtrKind;
|
||||||
use crate::llvm;
|
use crate::llvm;
|
||||||
use crate::llvm::debuginfo::{
|
use crate::llvm::debuginfo::{
|
||||||
DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
|
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>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
unique_type_id: UniqueTypeId,
|
unique_type_id: UniqueTypeId,
|
||||||
array_or_slice_type: Ty<'tcx>,
|
array_type: Ty<'tcx>,
|
||||||
element_type: Ty<'tcx>,
|
|
||||||
) -> MetadataCreationResult<'ll> {
|
) -> 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);
|
let element_type_metadata = type_metadata(cx, element_type);
|
||||||
|
|
||||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
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() {
|
let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
|
||||||
ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
|
|
||||||
_ => -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let subrange =
|
let subrange =
|
||||||
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
||||||
|
@ -410,55 +414,111 @@ fn fixed_vec_metadata<'ll, 'tcx>(
|
||||||
MetadataCreationResult::new(metadata, false)
|
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>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
slice_ptr_type: Ty<'tcx>,
|
ptr_type: Ty<'tcx>,
|
||||||
element_type: Ty<'tcx>,
|
pointee_type: Ty<'tcx>,
|
||||||
unique_type_id: UniqueTypeId,
|
unique_type_id: UniqueTypeId,
|
||||||
) -> MetadataCreationResult<'ll> {
|
) -> MetadataCreationResult<'ll> {
|
||||||
let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
|
let pointee_type_metadata = type_metadata(cx, pointee_type);
|
||||||
|
|
||||||
let data_ptr_metadata = type_metadata(cx, data_ptr_type);
|
|
||||||
|
|
||||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
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 pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) {
|
||||||
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
|
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![
|
unsafe {
|
||||||
MemberDescription {
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
||||||
name: "data_ptr".to_owned(),
|
DIB(cx),
|
||||||
type_metadata: data_ptr_metadata,
|
pointee_type_metadata,
|
||||||
offset: Size::ZERO,
|
thin_pointer_size.bits(),
|
||||||
size: pointer_size,
|
thin_pointer_align.bits() as u32,
|
||||||
align: pointer_align,
|
0, // Ignore DWARF address space.
|
||||||
flags: DIFlags::FlagZero,
|
ptr_type_debuginfo_name.as_ptr().cast(),
|
||||||
discriminant: None,
|
ptr_type_debuginfo_name.len(),
|
||||||
source_info: None,
|
)
|
||||||
},
|
}
|
||||||
MemberDescription {
|
}
|
||||||
name: "length".to_owned(),
|
Some(fat_pointer_kind) => {
|
||||||
type_metadata: type_metadata(cx, cx.tcx.types.usize),
|
let layout = cx.layout_of(ptr_type);
|
||||||
offset: pointer_size,
|
|
||||||
size: usize_size,
|
|
||||||
align: usize_align,
|
|
||||||
flags: DIFlags::FlagZero,
|
|
||||||
discriminant: None,
|
|
||||||
source_info: None,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
let metadata = composite_type_metadata(
|
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
|
||||||
cx,
|
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
|
||||||
slice_ptr_type,
|
|
||||||
&slice_type_name,
|
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
|
||||||
unique_type_id,
|
FatPtrKind::Dyn => ("pointer", "vtable"),
|
||||||
member_descriptions,
|
FatPtrKind::Slice => ("data_ptr", "length"),
|
||||||
NO_SCOPE_METADATA,
|
};
|
||||||
);
|
|
||||||
MetadataCreationResult::new(metadata, false)
|
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>(
|
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-
|
// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
|
||||||
// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
|
// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
|
||||||
// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
|
fn dyn_type_metadata<'ll, 'tcx>(
|
||||||
// `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>(
|
|
||||||
cx: &CodegenCx<'ll, 'tcx>,
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
trait_type: Ty<'tcx>,
|
dyn_type: Ty<'tcx>,
|
||||||
trait_object_type: Option<Ty<'tcx>>,
|
|
||||||
unique_type_id: UniqueTypeId,
|
unique_type_id: UniqueTypeId,
|
||||||
) -> &'ll DIType {
|
) -> &'ll DIType {
|
||||||
// The implementation provided here is a stub. It makes sure that the trait
|
if let ty::Dynamic(..) = dyn_type.kind() {
|
||||||
// type is assigned the correct name, size, namespace, and source location.
|
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
|
||||||
// However, it does not describe the trait's methods.
|
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 {
|
// Create debuginfo for `[T]` and `str`. These are unsized.
|
||||||
Some(trait_object_type) => match trait_object_type.kind() {
|
//
|
||||||
ty::Adt(def, _) => (
|
// Note: We currently emit just emit the debuginfo for the element type here
|
||||||
Some(get_namespace_for_item(cx, def.did)),
|
// (i.e. `T` for slices and `u8` for `str`), so that we end up with
|
||||||
compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
|
// `*const T` for the `data_ptr` field of the corresponding fat-pointer
|
||||||
),
|
// debuginfo of `&[T]`.
|
||||||
ty::RawPtr(_) | ty::Ref(..) => {
|
//
|
||||||
(NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
|
// 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
|
||||||
bug!(
|
// in an infinite loop when confronted with such a type.
|
||||||
"debuginfo: unexpected trait-object type in \
|
//
|
||||||
trait_pointer_metadata(): {:?}",
|
// As a side effect of the current encoding every instance of a type like
|
||||||
trait_object_type
|
// `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>(
|
||||||
// No object type, use the trait type directly (no scope here since the type
|
cx: &CodegenCx<'ll, 'tcx>,
|
||||||
// will be wrapped in the dyn$ synthetic type).
|
slice_type: Ty<'tcx>,
|
||||||
None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
|
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));
|
let element_type_metadata = type_metadata(cx, element_type);
|
||||||
|
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false }
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
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);
|
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() {
|
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
|
||||||
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
||||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
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() => {
|
ty::Tuple(elements) if elements.is_empty() => {
|
||||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||||
}
|
}
|
||||||
ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
|
ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t),
|
||||||
ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
|
ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id),
|
||||||
ty::Dynamic(..) => {
|
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(..) => {
|
ty::Foreign(..) => {
|
||||||
MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
|
MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
|
||||||
}
|
}
|
||||||
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
|
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
|
||||||
Ok(res) => res,
|
pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
|
||||||
Err(metadata) => return metadata,
|
}
|
||||||
},
|
ty::Adt(def, _) if def.is_box() => {
|
||||||
ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
|
pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
|
||||||
Ok(res) => res,
|
}
|
||||||
Err(metadata) => return metadata,
|
|
||||||
},
|
|
||||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||||
if let Some(metadata) =
|
if let Some(metadata) =
|
||||||
debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
|
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);
|
type_map.borrow_mut().remove_type(t);
|
||||||
|
|
||||||
// This is actually a function pointer, so wrap it in pointer DI.
|
// 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) => {
|
ty::Closure(def_id, substs) => {
|
||||||
let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
|
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)
|
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 {
|
fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
||||||
debug!("param_type_metadata: {:?}", t);
|
debug!("param_type_metadata: {:?}", t);
|
||||||
let name = format!("{:?}", t);
|
let name = format!("{:?}", t);
|
||||||
|
|
|
@ -4,7 +4,9 @@ use super::namespace::item_namespace;
|
||||||
use super::CrateDebugContext;
|
use super::CrateDebugContext;
|
||||||
|
|
||||||
use rustc_hir::def_id::DefId;
|
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::common::CodegenCx;
|
||||||
use crate::llvm;
|
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 {
|
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?"))
|
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(let_else)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
#![feature(let_else)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
use back::write::{create_informational_target_machine, create_target_machine};
|
use back::write::{create_informational_target_machine, create_target_machine};
|
||||||
|
|
|
@ -4,13 +4,36 @@
|
||||||
|
|
||||||
// gdb-command:run
|
// gdb-command:run
|
||||||
|
|
||||||
// gdb-command:print *a
|
// gdb-command:print a
|
||||||
// gdbg-check:$1 = {value = [...] "abc"}
|
// gdbg-check:$1 = {data_ptr: [...], length: 4}
|
||||||
// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]}
|
// gdbr-check:$1 = &unsized::Foo<[u8]> {data_ptr: [...], length: 4}
|
||||||
|
|
||||||
// gdb-command:print *b
|
// gdb-command:print b
|
||||||
// gdbg-check:$2 = {value = {value = [...] "abc"}}
|
// gdbg-check:$2 = {data_ptr: [...], length: 4}
|
||||||
// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}}
|
// 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)]
|
#![feature(omit_gdb_pretty_printer_section)]
|
||||||
|
@ -26,8 +49,13 @@ fn main() {
|
||||||
value: *b"abc\0"
|
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 a: &Foo<[u8]> = &foo.value;
|
||||||
let b: &Foo<Foo<[u8]>> = &foo;
|
let b: &Foo<Foo<[u8]>> = &foo;
|
||||||
|
let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 };
|
||||||
|
|
||||||
zzz(); // #break
|
zzz(); // #break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue