Auto merge of #45897 - tromey:trait-object-debug, r=michaelwoerister

Trait object debug

This enables better debugging of trait objects.  See the individual commits for explanations.  This required an LLVM bump.
This commit is contained in:
bors 2017-11-16 23:28:00 +00:00
commit d59f66d9b8
6 changed files with 137 additions and 2 deletions

View File

@ -18,6 +18,7 @@ use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align
use super::namespace::mangled_name_of_item;
use super::type_names::compute_debuginfo_type_name;
use super::{CrateDebugContext};
use abi;
use context::SharedCrateContext;
use llvm::{self, ValueRef};
@ -438,11 +439,38 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let trait_llvm_type = type_of::type_of(cx, trait_object_type);
let file_metadata = unknown_file_metadata(cx);
let ptr_type = cx.tcx().mk_ptr(ty::TypeAndMut {
ty: cx.tcx().types.u8,
mutbl: hir::MutImmutable
});
let ptr_type_metadata = type_metadata(cx, ptr_type, syntax_pos::DUMMY_SP);
let llvm_type = type_of::type_of(cx, ptr_type);
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
let member_descriptions = [
MemberDescription {
name: "pointer".to_string(),
llvm_type: llvm_type,
type_metadata: ptr_type_metadata,
offset: ComputedMemberOffset,
flags: DIFlags::FlagArtificial,
},
MemberDescription {
name: "vtable".to_string(),
llvm_type: llvm_type,
type_metadata: ptr_type_metadata,
offset: ComputedMemberOffset,
flags: DIFlags::FlagArtificial,
},
];
composite_type_metadata(cx,
trait_llvm_type,
&trait_type_name[..],
unique_type_id,
&[],
&member_descriptions,
containing_scope,
file_metadata,
syntax_pos::DUMMY_SP)
@ -1858,3 +1886,65 @@ pub fn extend_scope_to_file(ccx: &CrateContext,
file_metadata)
}
}
/// Creates debug information for the given vtable, which is for the
/// given type.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_vtable_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty: ty::Ty<'tcx>,
vtable: ValueRef) {
if cx.dbg_cx().is_none() {
return;
}
let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP);
let llvm_vtable_type = Type::vtable_ptr(cx).element_type();
let (struct_size, struct_align) = size_and_align_of(cx, llvm_vtable_type);
unsafe {
// LLVMRustDIBuilderCreateStructType() wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
// later on in llvm/lib/IR/Value.cpp.
let empty_array = create_DIArray(DIB(cx), &[]);
let name = CString::new("vtable").unwrap();
// Create a new one each time. We don't want metadata caching
// here, because each vtable will refer to a unique containing
// type.
let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
DIB(cx),
NO_SCOPE_METADATA,
name.as_ptr(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
bytes_to_bits(struct_size),
bytes_to_bits(struct_align),
DIFlags::FlagArtificial,
ptr::null_mut(),
empty_array,
0,
type_metadata,
name.as_ptr()
);
llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
NO_SCOPE_METADATA,
name.as_ptr(),
// LLVM 3.9
// doesn't accept
// null here, so
// pass the name
// as the linkage
// name.
name.as_ptr(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
vtable_type,
true,
vtable,
ptr::null_mut(),
0);
}
}

View File

@ -56,6 +56,7 @@ mod source_loc;
pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
pub use self::source_loc::start_emitting_source_locations;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::create_vtable_metadata;
pub use self::metadata::extend_scope_to_file;
pub use self::source_loc::set_source_location;

View File

@ -18,6 +18,7 @@ use monomorphize;
use type_::Type;
use value::Value;
use rustc::ty::{self, Ty};
use debuginfo;
#[derive(Copy, Clone, Debug)]
pub struct VirtualIndex(usize);
@ -99,6 +100,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
debuginfo::create_vtable_metadata(ccx, ty, vtable);
ccx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
vtable
}

@ -1 +1 @@
Subproject commit b48f77c5ed570001957408f4adeec88ae010c4d9
Subproject commit 51f104bf1cc6c3a588a11c90a3b4a4a18ee080ac

View File

@ -0,0 +1,33 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test depends on a patch that was committed to upstream LLVM
// after 5.0, then backported to the Rust LLVM fork.
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
// min-system-llvm-version 5.1
// compile-flags: -g -C no-prepopulate-passes
// CHECK-LABEL: @main
// CHECK: {{.*}}DICompositeType{{.*}}name: "vtable",{{.*}}vtableHolder:{{.*}}
pub trait T {
}
impl T for f64 {
}
pub fn main() {
let d = 23.0f64;
let td = &d as &T;
}

View File

@ -150,6 +150,14 @@ impl EarlyProps {
// Ignore if actual version is smaller the minimum required
// version
&actual_version[..] < min_version
} else if line.starts_with("min-system-llvm-version") {
let min_version = line.trim_right()
.rsplit(' ')
.next()
.expect("Malformed llvm version directive");
// Ignore if using system LLVM and actual version
// is smaller the minimum required version
!(config.system_llvm && &actual_version[..] < min_version)
} else {
false
}