diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 4f07af9071d..a68390eab7f 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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); + } +} diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1a284292016..15b299674ee 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -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; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 3253a0339a8..e7c5a36838c 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -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 } diff --git a/src/llvm b/src/llvm index b48f77c5ed5..51f104bf1cc 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit b48f77c5ed570001957408f4adeec88ae010c4d9 +Subproject commit 51f104bf1cc6c3a588a11c90a3b4a4a18ee080ac diff --git a/src/test/codegen/vtabletype.rs b/src/test/codegen/vtabletype.rs new file mode 100644 index 00000000000..b6466467548 --- /dev/null +++ b/src/test/codegen/vtabletype.rs @@ -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 or the MIT license +// , 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; +}