mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-23 02:27:39 +03:00
debuginfo: Generate cross-crate unique type identifiers for debuginfo types.
With this change, rustc creates a unique type identifier for types in debuginfo. These type identifiers are used by LLVM to correctly handle link-time-optimization scenarios but also help rustc with dealing with inlining from other crates. For more information, see the documentation block at the top of librustc/middle/trans/debuginfo.rs. Fixes #13681.
This commit is contained in:
@@ -122,8 +122,36 @@ struct List {
|
||||
`llvm.dbg.declare` instructions to the correct source locations even while source location emission
|
||||
is still disabled, so there is no need to do anything special with source location handling here.
|
||||
|
||||
*/
|
||||
## Unique Type Identification
|
||||
In order for link-time optimization to work properly, LLVM needs a unique type identifier that tells
|
||||
it across compilation units which types are the same as others. This type identifier is created by
|
||||
TypeMap::get_unique_type_id_of_type() using the following algorithm:
|
||||
|
||||
(1) Primitive types have their name as ID
|
||||
(2) Structs, enums and traits have a multipart identifier
|
||||
(1) The first part is the SVH (strict version hash) of the crate they were originally defined in
|
||||
(2) The second part is the ast::NodeId of the definition in their original crate
|
||||
(3) The final part is a concatenation of the type IDs of their concrete type arguments if they
|
||||
are generic types.
|
||||
(3) Tuple-, pointer and function types are structurally identified, which means that they are
|
||||
equivalent if their component types are equivalent (i.e. (int, int) is the same regardless in
|
||||
which crate it is used).
|
||||
|
||||
This algorithm also provides a stable ID for types that are defined in one crate but instantiated
|
||||
from metadata within another crate. We just have to take care to always map crate and node IDs back
|
||||
to the original crate context.
|
||||
|
||||
As a side-effect these unique type IDs also help to solve a problem arising from lifetime
|
||||
parameters. Since lifetime parameters are completely omitted in debuginfo, more than one `ty::t`
|
||||
instance may map to the same debuginfo type metadata, that is, some struct `Struct<'a>` may have N
|
||||
instantiations with different concrete substitutions for `'a`, and thus there will be N `ty::t`
|
||||
instances for the type `Struct<'a>` even though it is not generic otherwise. Unfortunately this
|
||||
means that we cannot use `ty::type_id()` as cheap identifier for type metadata---we have done this
|
||||
in the past, but it led to unnecessary metadata duplication in the best case and LLVM assertions in
|
||||
the worst. However, the unique type ID as described above *can* be used as identifier. Since it is
|
||||
comparatively expensive to construct, though, `ty::type_id()` is still used additionally as an
|
||||
optimization for cases where the exact same type has been seen before (which is most of the time).
|
||||
*/
|
||||
|
||||
use driver::config;
|
||||
use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
|
||||
@@ -152,6 +180,7 @@ struct List {
|
||||
use std::ptr;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::atomics;
|
||||
use syntax::util::interner::Interner;
|
||||
use syntax::codemap::{Span, Pos};
|
||||
use syntax::{abi, ast, codemap, ast_util, ast_map};
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
@@ -166,7 +195,6 @@ struct List {
|
||||
static DW_ATE_boolean: c_uint = 0x02;
|
||||
static DW_ATE_float: c_uint = 0x04;
|
||||
static DW_ATE_signed: c_uint = 0x05;
|
||||
// static DW_ATE_signed_char: c_uint = 0x06;
|
||||
static DW_ATE_unsigned: c_uint = 0x07;
|
||||
static DW_ATE_unsigned_char: c_uint = 0x08;
|
||||
|
||||
@@ -174,15 +202,370 @@ struct List {
|
||||
// Public Interface of debuginfo module
|
||||
//=-------------------------------------------------------------------------------------------------
|
||||
|
||||
#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)]
|
||||
struct UniqueTypeId(ast::Name);
|
||||
|
||||
// The TypeMap is where the CrateDebugContext holds the type metadata nodes created so far. The
|
||||
// metadata nodes are indexed by UniqueTypeId, and, for faster lookup, also by ty::t. The
|
||||
// TypeMap is responsible for creating UniqueTypeIds.
|
||||
struct TypeMap {
|
||||
// The UniqueTypeIds created so far
|
||||
unique_id_interner: Interner<Rc<String>>,
|
||||
// A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
|
||||
unique_id_to_metadata: HashMap<UniqueTypeId, DIType>,
|
||||
// A map from ty::type_id() to debuginfo metadata. This is a N:1 mapping.
|
||||
type_to_metadata: HashMap<uint, DIType>,
|
||||
// A map from ty::type_id() to UniqueTypeId. This is a N:1 mapping.
|
||||
type_to_unique_id: HashMap<uint, UniqueTypeId>
|
||||
}
|
||||
|
||||
impl TypeMap {
|
||||
|
||||
fn new() -> TypeMap {
|
||||
TypeMap {
|
||||
unique_id_interner: Interner::new(),
|
||||
type_to_metadata: HashMap::new(),
|
||||
unique_id_to_metadata: HashMap::new(),
|
||||
type_to_unique_id: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a ty::t to metadata mapping to the TypeMap. The method will fail if the mapping already
|
||||
// exists.
|
||||
fn register_type_with_metadata(&mut self,
|
||||
cx: &CrateContext,
|
||||
type_: ty::t,
|
||||
metadata: DIType) {
|
||||
if !self.type_to_metadata.insert(ty::type_id(type_), metadata) {
|
||||
cx.sess().bug(format!("Type metadata for ty::t '{}' is already in the TypeMap!",
|
||||
ppaux::ty_to_str(cx.tcx(), type_)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will fail if the mapping
|
||||
// already exists.
|
||||
fn register_unique_id_with_metadata(&mut self,
|
||||
cx: &CrateContext,
|
||||
unique_type_id: UniqueTypeId,
|
||||
metadata: DIType) {
|
||||
if !self.unique_id_to_metadata.insert(unique_type_id, metadata) {
|
||||
let unique_type_id_str = self.get_unique_type_id_as_string(unique_type_id);
|
||||
cx.sess().bug(format!("Type metadata for unique id '{}' is already in the TypeMap!",
|
||||
unique_type_id_str.as_slice()).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
fn find_metadata_for_type(&self, type_: ty::t) -> Option<DIType> {
|
||||
self.type_to_metadata.find_copy(&ty::type_id(type_))
|
||||
}
|
||||
|
||||
fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
|
||||
self.unique_id_to_metadata.find_copy(&unique_type_id)
|
||||
}
|
||||
|
||||
// Get the string representation of a UniqueTypeId. This method will fail if the id is unknown.
|
||||
fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc<String> {
|
||||
let UniqueTypeId(interner_key) = unique_type_id;
|
||||
self.unique_id_interner.get(interner_key)
|
||||
}
|
||||
|
||||
// Get the UniqueTypeId for the given type. If the UniqueTypeId for the given type has been
|
||||
// requested before, this is just a table lookup. Otherwise an ID will be generated and stored
|
||||
// for later lookup.
|
||||
fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> UniqueTypeId {
|
||||
|
||||
// basic type -> {:name of the type:}
|
||||
// tuple -> {tuple_(:param-uid:)*}
|
||||
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum variant -> {variant_:variant-name:_:enum-uid:}
|
||||
// reference (&) -> {& :pointee-uid:}
|
||||
// mut reference (&mut) -> {&mut :pointee-uid:}
|
||||
// ptr (*) -> {* :pointee-uid:}
|
||||
// mut ptr (*mut) -> {*mut :pointee-uid:}
|
||||
// unique ptr (~) -> {~ :pointee-uid:}
|
||||
// @-ptr (@) -> {@ :pointee-uid:}
|
||||
// sized vec ([T, ..x]) -> {[:size:] :element-uid:}
|
||||
// vec slice (&[T]) -> {&<mut> [] :element-uid:}
|
||||
// trait (~ | &[mut] T) -> {:sigil: trait_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
|
||||
// :return-type-uid: : (:bounds:)*}
|
||||
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
|
||||
// :return-type-uid:}
|
||||
|
||||
match self.type_to_unique_id.find_copy(&ty::type_id(type_)) {
|
||||
Some(unique_type_id) => return unique_type_id,
|
||||
None => { /* generate one */}
|
||||
};
|
||||
|
||||
let mut unique_type_id = String::with_capacity(256);
|
||||
unique_type_id.push_char('{');
|
||||
|
||||
match ty::get(type_).sty {
|
||||
ty::ty_nil |
|
||||
ty::ty_bot |
|
||||
ty::ty_bool |
|
||||
ty::ty_char |
|
||||
ty::ty_str |
|
||||
ty::ty_int(_) |
|
||||
ty::ty_uint(_) |
|
||||
ty::ty_float(_) => {
|
||||
unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
|
||||
},
|
||||
ty::ty_enum(def_id, ref substs) => {
|
||||
unique_type_id.push_str("enum ");
|
||||
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
|
||||
},
|
||||
ty::ty_struct(def_id, ref substs) => {
|
||||
unique_type_id.push_str("struct ");
|
||||
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
|
||||
},
|
||||
ty::ty_tup(ref component_types) => {
|
||||
unique_type_id.push_str("tuple ");
|
||||
for &component_type in component_types.iter() {
|
||||
let component_type_id = self.get_unique_type_id_of_type(cx, component_type);
|
||||
let component_type_id = self.get_unique_type_id_as_string(component_type_id);
|
||||
unique_type_id.push_str(component_type_id.as_slice());
|
||||
}
|
||||
},
|
||||
ty::ty_box(inner_type) => {
|
||||
unique_type_id.push_char('@');
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_uniq(inner_type) => {
|
||||
unique_type_id.push_char('~');
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
|
||||
unique_type_id.push_char('*');
|
||||
if mutbl == ast::MutMutable {
|
||||
unique_type_id.push_str("mut");
|
||||
}
|
||||
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
|
||||
unique_type_id.push_char('&');
|
||||
if mutbl == ast::MutMutable {
|
||||
unique_type_id.push_str("mut");
|
||||
}
|
||||
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_vec(ty::mt { ty: inner_type, mutbl }, optional_length) => {
|
||||
match optional_length {
|
||||
Some(len) => {
|
||||
unique_type_id.push_str(format!("[{}]", len).as_slice());
|
||||
}
|
||||
None => {
|
||||
unique_type_id.push_char('&');
|
||||
|
||||
if mutbl == ast::MutMutable {
|
||||
unique_type_id.push_str("mut");
|
||||
}
|
||||
|
||||
unique_type_id.push_str("[]");
|
||||
}
|
||||
};
|
||||
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_trait(ref trait_data) => {
|
||||
match trait_data.store {
|
||||
ty::UniqTraitStore => unique_type_id.push_char('~'),
|
||||
ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut"),
|
||||
ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_char('&'),
|
||||
};
|
||||
|
||||
unique_type_id.push_str("trait ");
|
||||
|
||||
from_def_id_and_substs(self,
|
||||
cx,
|
||||
trait_data.def_id,
|
||||
&trait_data.substs,
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
|
||||
if fn_style == ast::UnsafeFn {
|
||||
unique_type_id.push_str("unsafe ");
|
||||
}
|
||||
|
||||
unique_type_id.push_str(abi.name());
|
||||
|
||||
unique_type_id.push_str(" fn(");
|
||||
|
||||
for ¶meter_type in sig.inputs.iter() {
|
||||
let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
|
||||
let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
|
||||
unique_type_id.push_str(parameter_type_id.as_slice());
|
||||
unique_type_id.push_char(',');
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
unique_type_id.push_str("...");
|
||||
}
|
||||
|
||||
unique_type_id.push_str(")->");
|
||||
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
|
||||
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
|
||||
unique_type_id.push_str(return_type_id.as_slice());
|
||||
},
|
||||
ty::ty_closure(box ty::ClosureTy { fn_style,
|
||||
onceness,
|
||||
store,
|
||||
ref bounds,
|
||||
ref sig }) => {
|
||||
if fn_style == ast::UnsafeFn {
|
||||
unique_type_id.push_str("unsafe ");
|
||||
}
|
||||
|
||||
if onceness == ast::Once {
|
||||
unique_type_id.push_str("once ");
|
||||
}
|
||||
|
||||
match store {
|
||||
ty::UniqTraitStore => unique_type_id.push_str("~|"),
|
||||
ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut|"),
|
||||
ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_str("&|"),
|
||||
};
|
||||
|
||||
for ¶meter_type in sig.inputs.iter() {
|
||||
let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type);
|
||||
let parameter_type_id = self.get_unique_type_id_as_string(parameter_type_id);
|
||||
unique_type_id.push_str(parameter_type_id.as_slice());
|
||||
unique_type_id.push_char(',');
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
unique_type_id.push_str("...");
|
||||
}
|
||||
|
||||
unique_type_id.push_str("|->");
|
||||
|
||||
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
|
||||
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
|
||||
unique_type_id.push_str(return_type_id.as_slice());
|
||||
|
||||
unique_type_id.push_char(':');
|
||||
|
||||
for bound in bounds.iter() {
|
||||
match bound {
|
||||
ty::BoundStatic => unique_type_id.push_str("'static"),
|
||||
ty::BoundSend => unique_type_id.push_str("Send"),
|
||||
ty::BoundSized => unique_type_id.push_str("Sized"),
|
||||
ty::BoundCopy => unique_type_id.push_str("Copy"),
|
||||
ty::BoundShare => unique_type_id.push_str("Share"),
|
||||
};
|
||||
unique_type_id.push_char('+');
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
cx.sess().bug(format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
|
||||
ppaux::ty_to_str(cx.tcx(), type_).as_slice(),
|
||||
ty::get(type_).sty).as_slice())
|
||||
}
|
||||
};
|
||||
|
||||
unique_type_id.push_char('}');
|
||||
|
||||
// Trim to size before storing permanently
|
||||
unique_type_id.shrink_to_fit();
|
||||
|
||||
let key = self.unique_id_interner.intern(Rc::new(unique_type_id));
|
||||
self.type_to_unique_id.insert(ty::type_id(type_), UniqueTypeId(key));
|
||||
|
||||
return UniqueTypeId(key);
|
||||
|
||||
fn from_def_id_and_substs(type_map: &mut TypeMap,
|
||||
cx: &CrateContext,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs,
|
||||
output: &mut String) {
|
||||
use std::num::ToStrRadix;
|
||||
|
||||
// First, find out the 'real' def_id of the type. Items inlined from other crates have
|
||||
// to be mapped back to their source.
|
||||
let source_def_id = if def_id.krate == ast::LOCAL_CRATE {
|
||||
match cx.external_srcs.borrow().find_copy(&def_id.node) {
|
||||
Some(source_def_id) => {
|
||||
// The given def_id identifies the inlined copy of a type definition,
|
||||
// let's take the source of the copy
|
||||
source_def_id
|
||||
}
|
||||
None => def_id
|
||||
}
|
||||
} else {
|
||||
def_id
|
||||
};
|
||||
|
||||
// Get the crate hash as first part of the identifier
|
||||
let crate_hash = if source_def_id.krate == ast::LOCAL_CRATE {
|
||||
cx.link_meta.crate_hash.clone()
|
||||
} else {
|
||||
cx.sess().cstore.get_crate_hash(source_def_id.krate)
|
||||
};
|
||||
|
||||
output.push_str(crate_hash.as_str());
|
||||
output.push_str("/");
|
||||
output.push_str(def_id.node.to_str_radix(16).as_slice());
|
||||
|
||||
// Maybe check that there is no self type here
|
||||
|
||||
if substs.tps.len() > 0 {
|
||||
output.push_char('<');
|
||||
|
||||
for &type_parameter in substs.tps.iter() {
|
||||
let param_type_id = type_map.get_unique_type_id_of_type(cx, type_parameter);
|
||||
let param_type_id = type_map.get_unique_type_id_as_string(param_type_id);
|
||||
output.push_str(param_type_id.as_slice());
|
||||
output.push_char(',');
|
||||
}
|
||||
|
||||
output.push_char('>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the UniqueTypeId for an enum variant. Enum variants are not really types of their own,
|
||||
// so they need special handling. We still need a UniqueTypeId for them, since to debuginfo they
|
||||
// *are* real types.
|
||||
fn get_unique_type_id_of_enum_variant(&mut self,
|
||||
cx: &CrateContext,
|
||||
enum_type: ty::t,
|
||||
variant_name: &str)
|
||||
-> UniqueTypeId {
|
||||
let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
|
||||
let enum_variant_type_id = format!("{}::{}",
|
||||
self.get_unique_type_id_as_string(enum_type_id)
|
||||
.as_slice(),
|
||||
variant_name);
|
||||
let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
|
||||
UniqueTypeId(interner_key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A context object for maintaining all state needed by the debuginfo module.
|
||||
pub struct CrateDebugContext {
|
||||
llcontext: ContextRef,
|
||||
builder: DIBuilderRef,
|
||||
current_debug_location: Cell<DebugLocation>,
|
||||
created_files: RefCell<HashMap<String, DIFile>>,
|
||||
created_types: RefCell<HashMap<uint, DIType>>,
|
||||
created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
|
||||
|
||||
type_map: RefCell<TypeMap>,
|
||||
namespace_map: RefCell<HashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
|
||||
|
||||
// This collection is used to assert that composite types (structs, enums, ...) have their
|
||||
// members only set once:
|
||||
composite_types_completed: RefCell<HashSet<DIType>>,
|
||||
@@ -199,8 +582,8 @@ pub fn new(llmod: ModuleRef) -> CrateDebugContext {
|
||||
builder: builder,
|
||||
current_debug_location: Cell::new(UnknownLocation),
|
||||
created_files: RefCell::new(HashMap::new()),
|
||||
created_types: RefCell::new(HashMap::new()),
|
||||
created_enum_disr_types: RefCell::new(HashMap::new()),
|
||||
type_map: RefCell::new(TypeMap::new()),
|
||||
namespace_map: RefCell::new(HashMap::new()),
|
||||
composite_types_completed: RefCell::new(HashSet::new()),
|
||||
};
|
||||
@@ -1255,7 +1638,8 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
|
||||
// more information.
|
||||
enum RecursiveTypeDescription {
|
||||
UnfinishedMetadata {
|
||||
cache_id: uint,
|
||||
unfinished_type: ty::t,
|
||||
unique_type_id: UniqueTypeId,
|
||||
metadata_stub: DICompositeType,
|
||||
llvm_type: Type,
|
||||
file_metadata: DIFile,
|
||||
@@ -1264,6 +1648,31 @@ enum RecursiveTypeDescription {
|
||||
FinalMetadata(DICompositeType)
|
||||
}
|
||||
|
||||
fn create_and_register_recursive_type_forward_declaration(
|
||||
cx: &CrateContext,
|
||||
unfinished_type: ty::t,
|
||||
unique_type_id: UniqueTypeId,
|
||||
metadata_stub: DICompositeType,
|
||||
llvm_type: Type,
|
||||
file_metadata: DIFile,
|
||||
member_description_factory: MemberDescriptionFactory)
|
||||
-> RecursiveTypeDescription {
|
||||
|
||||
// Insert the stub into the TypeMap in order to allow for recursive references
|
||||
let mut type_map = debug_context(cx).type_map.borrow_mut();
|
||||
type_map.register_unique_id_with_metadata(cx, unique_type_id, metadata_stub);
|
||||
type_map.register_type_with_metadata(cx, unfinished_type, metadata_stub);
|
||||
|
||||
UnfinishedMetadata {
|
||||
unfinished_type: unfinished_type,
|
||||
unique_type_id: unique_type_id,
|
||||
metadata_stub: metadata_stub,
|
||||
llvm_type: llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: member_description_factory,
|
||||
}
|
||||
}
|
||||
|
||||
impl RecursiveTypeDescription {
|
||||
// Finishes up the description of the type in question (mostly by providing descriptions of the
|
||||
// fields of the given type) and returns the final type metadata.
|
||||
@@ -1271,15 +1680,27 @@ fn finalize(&self, cx: &CrateContext) -> DICompositeType {
|
||||
match *self {
|
||||
FinalMetadata(metadata) => metadata,
|
||||
UnfinishedMetadata {
|
||||
cache_id,
|
||||
unfinished_type,
|
||||
unique_type_id,
|
||||
metadata_stub,
|
||||
llvm_type,
|
||||
file_metadata,
|
||||
ref member_description_factory
|
||||
} => {
|
||||
// Insert the stub into the cache in order to allow recursive references ...
|
||||
debug_context(cx).created_types.borrow_mut()
|
||||
.insert(cache_id, metadata_stub);
|
||||
// Make sure that we have a forward declaration of the type in the TypeMap so that
|
||||
// recursive references are possible. This will always be the case if the
|
||||
// RecursiveTypeDescription has been properly created through the
|
||||
// create_and_register_recursive_type_forward_declaration() function.
|
||||
{
|
||||
let type_map = debug_context(cx).type_map.borrow();
|
||||
if type_map.find_metadata_for_unique_id(unique_type_id).is_none() ||
|
||||
type_map.find_metadata_for_type(unfinished_type).is_none() {
|
||||
cx.sess().bug(format!("Forward declaration of potentially recursive type \
|
||||
'{}' was not found in TypeMap!",
|
||||
ppaux::ty_to_str(cx.tcx(), unfinished_type))
|
||||
.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
// ... then create the member descriptions ...
|
||||
let member_descriptions = member_description_factory.create_member_descriptions(cx);
|
||||
@@ -1349,6 +1770,7 @@ fn prepare_struct_metadata(cx: &CrateContext,
|
||||
struct_type: ty::t,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> RecursiveTypeDescription {
|
||||
let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
|
||||
@@ -1362,23 +1784,26 @@ fn prepare_struct_metadata(cx: &CrateContext,
|
||||
let struct_metadata_stub = create_struct_stub(cx,
|
||||
struct_llvm_type,
|
||||
struct_name.as_slice(),
|
||||
unique_type_id,
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
definition_span);
|
||||
|
||||
let fields = ty::struct_fields(cx.tcx(), def_id, substs);
|
||||
|
||||
UnfinishedMetadata {
|
||||
cache_id: cache_id_for_type(struct_type),
|
||||
metadata_stub: struct_metadata_stub,
|
||||
llvm_type: struct_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: StructMDF(StructMemberDescriptionFactory {
|
||||
create_and_register_recursive_type_forward_declaration(
|
||||
cx,
|
||||
struct_type,
|
||||
unique_type_id,
|
||||
struct_metadata_stub,
|
||||
struct_llvm_type,
|
||||
file_metadata,
|
||||
StructMDF(StructMemberDescriptionFactory {
|
||||
fields: fields,
|
||||
is_simd: ty::type_is_simd(cx.tcx(), struct_type),
|
||||
span: span,
|
||||
}),
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1409,6 +1834,7 @@ fn create_member_descriptions(&self, cx: &CrateContext)
|
||||
fn prepare_tuple_metadata(cx: &CrateContext,
|
||||
tuple_type: ty::t,
|
||||
component_types: &[ty::t],
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> RecursiveTypeDescription {
|
||||
let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
|
||||
@@ -1417,21 +1843,24 @@ fn prepare_tuple_metadata(cx: &CrateContext,
|
||||
let loc = span_start(cx, span);
|
||||
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
|
||||
|
||||
UnfinishedMetadata {
|
||||
cache_id: cache_id_for_type(tuple_type),
|
||||
metadata_stub: create_struct_stub(cx,
|
||||
tuple_llvm_type,
|
||||
tuple_name.as_slice(),
|
||||
file_metadata,
|
||||
file_metadata,
|
||||
span),
|
||||
llvm_type: tuple_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: TupleMDF(TupleMemberDescriptionFactory {
|
||||
create_and_register_recursive_type_forward_declaration(
|
||||
cx,
|
||||
tuple_type,
|
||||
unique_type_id,
|
||||
create_struct_stub(cx,
|
||||
tuple_llvm_type,
|
||||
tuple_name.as_slice(),
|
||||
unique_type_id,
|
||||
file_metadata,
|
||||
file_metadata,
|
||||
span),
|
||||
tuple_llvm_type,
|
||||
file_metadata,
|
||||
TupleMDF(TupleMemberDescriptionFactory {
|
||||
component_types: Vec::from_slice(component_types),
|
||||
span: span,
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1444,6 +1873,7 @@ fn prepare_tuple_metadata(cx: &CrateContext,
|
||||
// variant of the given enum, this factory will produce one MemberDescription (all with no name and
|
||||
// a fixed offset of zero bytes).
|
||||
struct EnumMemberDescriptionFactory {
|
||||
enum_type: ty::t,
|
||||
type_rep: Rc<adt::Repr>,
|
||||
variants: Rc<Vec<Rc<ty::VariantInfo>>>,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
@@ -1465,6 +1895,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
|
||||
.map(|(i, struct_def)| {
|
||||
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
&**self.variants.get(i),
|
||||
discriminant_info,
|
||||
@@ -1497,6 +1928,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
|
||||
} else {
|
||||
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
&**self.variants.get(0),
|
||||
NoDiscriminant,
|
||||
@@ -1551,11 +1983,19 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
};
|
||||
|
||||
let unique_type_id = debug_context(cx).type_map
|
||||
.borrow_mut()
|
||||
.get_unique_type_id_of_enum_variant(
|
||||
cx,
|
||||
self.enum_type,
|
||||
non_null_variant_name.get());
|
||||
|
||||
// Now we can create the metadata of the artificial struct
|
||||
let artificial_struct_metadata =
|
||||
composite_type_metadata(cx,
|
||||
artificial_struct_llvm_type,
|
||||
non_null_variant_name.get(),
|
||||
unique_type_id,
|
||||
&[sole_struct_member_description],
|
||||
self.containing_scope,
|
||||
self.file_metadata,
|
||||
@@ -1581,6 +2021,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
|
||||
// Create a description of the non-null variant
|
||||
let (variant_type_metadata, variant_llvm_type, member_description_factory) =
|
||||
describe_enum_variant(cx,
|
||||
self.enum_type,
|
||||
struct_def,
|
||||
&**self.variants.get(nndiscr as uint),
|
||||
OptimizedDiscriminant(ptrfield),
|
||||
@@ -1654,6 +2095,7 @@ enum EnumDiscriminantInfo {
|
||||
// (3) a MemberDescriptionFactory for producing the descriptions of the fields of the variant. This
|
||||
// is a rudimentary version of a full RecursiveTypeDescription.
|
||||
fn describe_enum_variant(cx: &CrateContext,
|
||||
enum_type: ty::t,
|
||||
struct_def: &adt::Struct,
|
||||
variant_info: &ty::VariantInfo,
|
||||
discriminant_info: EnumDiscriminantInfo,
|
||||
@@ -1678,9 +2120,19 @@ fn describe_enum_variant(cx: &CrateContext,
|
||||
codemap::DUMMY_SP
|
||||
};
|
||||
|
||||
let variant_name = token::get_ident(variant_info.name);
|
||||
let variant_name = variant_name.get();
|
||||
let unique_type_id = debug_context(cx).type_map
|
||||
.borrow_mut()
|
||||
.get_unique_type_id_of_enum_variant(
|
||||
cx,
|
||||
enum_type,
|
||||
variant_name);
|
||||
|
||||
let metadata_stub = create_struct_stub(cx,
|
||||
variant_llvm_type,
|
||||
token::get_ident(variant_info.name).get(),
|
||||
variant_name,
|
||||
unique_type_id,
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
variant_definition_span);
|
||||
@@ -1724,6 +2176,7 @@ fn describe_enum_variant(cx: &CrateContext,
|
||||
fn prepare_enum_metadata(cx: &CrateContext,
|
||||
enum_type: ty::t,
|
||||
enum_def_id: ast::DefId,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> RecursiveTypeDescription {
|
||||
let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
|
||||
@@ -1804,10 +2257,14 @@ fn prepare_enum_metadata(cx: &CrateContext,
|
||||
|
||||
let enum_llvm_type = type_of::type_of(cx, enum_type);
|
||||
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
|
||||
let unique_id = generate_unique_type_id("DI_ENUM_");
|
||||
|
||||
let unique_type_id_str = debug_context(cx)
|
||||
.type_map
|
||||
.borrow()
|
||||
.get_unique_type_id_as_string(unique_type_id);
|
||||
|
||||
let enum_metadata = enum_name.as_slice().with_c_str(|enum_name| {
|
||||
unique_id.as_slice().with_c_str(|unique_id| {
|
||||
unique_type_id_str.as_slice().with_c_str(|unique_type_id_str| {
|
||||
unsafe {
|
||||
llvm::LLVMDIBuilderCreateUnionType(
|
||||
DIB(cx),
|
||||
@@ -1820,17 +2277,20 @@ fn prepare_enum_metadata(cx: &CrateContext,
|
||||
0, // Flags
|
||||
ptr::null(),
|
||||
0, // RuntimeLang
|
||||
unique_id)
|
||||
unique_type_id_str)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return UnfinishedMetadata {
|
||||
cache_id: cache_id_for_type(enum_type),
|
||||
metadata_stub: enum_metadata,
|
||||
llvm_type: enum_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: EnumMDF(EnumMemberDescriptionFactory {
|
||||
return create_and_register_recursive_type_forward_declaration(
|
||||
cx,
|
||||
enum_type,
|
||||
unique_type_id,
|
||||
enum_metadata,
|
||||
enum_llvm_type,
|
||||
file_metadata,
|
||||
EnumMDF(EnumMemberDescriptionFactory {
|
||||
enum_type: enum_type,
|
||||
type_rep: type_rep.clone(),
|
||||
variants: variants,
|
||||
discriminant_type_metadata: discriminant_type_metadata,
|
||||
@@ -1838,7 +2298,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
|
||||
file_metadata: file_metadata,
|
||||
span: span,
|
||||
}),
|
||||
};
|
||||
);
|
||||
|
||||
fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::InternedString {
|
||||
let name = if def_id.krate == ast::LOCAL_CRATE {
|
||||
@@ -1857,6 +2317,7 @@ fn get_enum_discriminant_name(cx: &CrateContext, def_id: ast::DefId) -> token::I
|
||||
fn composite_type_metadata(cx: &CrateContext,
|
||||
composite_llvm_type: Type,
|
||||
composite_type_name: &str,
|
||||
composite_type_unique_id: UniqueTypeId,
|
||||
member_descriptions: &[MemberDescription],
|
||||
containing_scope: DIScope,
|
||||
file_metadata: DIFile,
|
||||
@@ -1866,10 +2327,10 @@ fn composite_type_metadata(cx: &CrateContext,
|
||||
let composite_type_metadata = create_struct_stub(cx,
|
||||
composite_llvm_type,
|
||||
composite_type_name,
|
||||
composite_type_unique_id,
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
definition_span);
|
||||
|
||||
// ... and immediately create and add the member descriptions.
|
||||
set_members_of_composite_type(cx,
|
||||
composite_type_metadata,
|
||||
@@ -1944,6 +2405,7 @@ fn set_members_of_composite_type(cx: &CrateContext,
|
||||
fn create_struct_stub(cx: &CrateContext,
|
||||
struct_llvm_type: Type,
|
||||
struct_type_name: &str,
|
||||
unique_type_id: UniqueTypeId,
|
||||
containing_scope: DIScope,
|
||||
file_metadata: DIFile,
|
||||
definition_span: Span)
|
||||
@@ -1951,13 +2413,12 @@ fn create_struct_stub(cx: &CrateContext,
|
||||
let loc = span_start(cx, definition_span);
|
||||
let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
|
||||
|
||||
// We assign unique IDs to the type stubs so LLVM metadata uniquing does not reuse instances
|
||||
// where we don't want it.
|
||||
let unique_id = generate_unique_type_id("DI_STRUCT_");
|
||||
|
||||
return unsafe {
|
||||
let unique_type_id_str = debug_context(cx).type_map
|
||||
.borrow()
|
||||
.get_unique_type_id_as_string(unique_type_id);
|
||||
let metadata_stub = unsafe {
|
||||
struct_type_name.with_c_str(|name| {
|
||||
unique_id.as_slice().with_c_str(|unique_id| {
|
||||
unique_type_id_str.as_slice().with_c_str(|unique_type_id| {
|
||||
// LLVMDIBuilderCreateStructType() 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), []);
|
||||
@@ -1975,23 +2436,23 @@ fn create_struct_stub(cx: &CrateContext,
|
||||
empty_array,
|
||||
0,
|
||||
ptr::null(),
|
||||
unique_id)
|
||||
unique_type_id)
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
return metadata_stub;
|
||||
}
|
||||
|
||||
fn boxed_type_metadata(cx: &CrateContext,
|
||||
content_type_name: Option<&str>,
|
||||
content_llvm_type: Type,
|
||||
content_type_metadata: DIType,
|
||||
span: Span)
|
||||
-> DICompositeType {
|
||||
let box_type_name = match content_type_name {
|
||||
Some(content_type_name) => format!("Boxed<{}>", content_type_name),
|
||||
None => "BoxedType".to_string()
|
||||
};
|
||||
fn at_box_metadata(cx: &CrateContext,
|
||||
content_type: ty::t,
|
||||
unique_type_id: UniqueTypeId) -> DIType {
|
||||
let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
|
||||
let content_type_name = content_type_name.as_slice();
|
||||
let content_llvm_type = type_of::type_of(cx, content_type);
|
||||
let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
|
||||
|
||||
let box_type_name = format!("Boxed<{}>", content_type_name);
|
||||
let box_llvm_type = Type::at_box(cx, content_llvm_type);
|
||||
let member_llvm_types = box_llvm_type.field_types();
|
||||
assert!(box_layout_is_correct(cx,
|
||||
@@ -2035,17 +2496,18 @@ fn boxed_type_metadata(cx: &CrateContext,
|
||||
}
|
||||
];
|
||||
|
||||
let loc = span_start(cx, span);
|
||||
let loc = span_start(cx, codemap::DUMMY_SP);
|
||||
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
|
||||
|
||||
return composite_type_metadata(
|
||||
cx,
|
||||
box_llvm_type,
|
||||
box_type_name.as_slice(),
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
file_metadata,
|
||||
file_metadata,
|
||||
span);
|
||||
codemap::DUMMY_SP);
|
||||
|
||||
// Unfortunately, we cannot assert anything but the correct types here---and not whether the
|
||||
// 'next' and 'prev' pointers are in the correct order.
|
||||
@@ -2062,6 +2524,7 @@ fn box_layout_is_correct(cx: &CrateContext,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn fixed_vec_metadata(cx: &CrateContext,
|
||||
element_type: ty::t,
|
||||
len: uint,
|
||||
@@ -2089,18 +2552,19 @@ fn fixed_vec_metadata(cx: &CrateContext,
|
||||
};
|
||||
}
|
||||
|
||||
fn vec_metadata(cx: &CrateContext,
|
||||
element_type: ty::t,
|
||||
span: Span)
|
||||
-> DICompositeType {
|
||||
fn heap_vec_metadata(cx: &CrateContext,
|
||||
vec_type: ty::t,
|
||||
element_type: ty::t,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> DICompositeType {
|
||||
|
||||
let element_type_metadata = type_metadata(cx, element_type, span);
|
||||
let element_llvm_type = type_of::type_of(cx, element_type);
|
||||
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
|
||||
|
||||
let vec_llvm_type = Type::vec(cx, &element_llvm_type);
|
||||
let vec_type_name = format!("[{}]",
|
||||
ppaux::ty_to_str(cx.tcx(), element_type));
|
||||
let vec_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
|
||||
let vec_type_name = vec_type_name.as_slice();
|
||||
|
||||
let member_llvm_types = vec_llvm_type.field_types();
|
||||
@@ -2145,6 +2609,7 @@ fn vec_metadata(cx: &CrateContext,
|
||||
cx,
|
||||
vec_llvm_type,
|
||||
vec_type_name,
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
file_metadata,
|
||||
file_metadata,
|
||||
@@ -2154,6 +2619,7 @@ fn vec_metadata(cx: &CrateContext,
|
||||
fn vec_slice_metadata(cx: &CrateContext,
|
||||
vec_type: ty::t,
|
||||
element_type: ty::t,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> DICompositeType {
|
||||
|
||||
@@ -2196,6 +2662,7 @@ fn vec_slice_metadata(cx: &CrateContext,
|
||||
cx,
|
||||
slice_llvm_type,
|
||||
slice_type_name.as_slice(),
|
||||
unique_type_id,
|
||||
member_descriptions,
|
||||
file_metadata,
|
||||
file_metadata,
|
||||
@@ -2218,8 +2685,7 @@ fn subroutine_type_metadata(cx: &CrateContext,
|
||||
let loc = span_start(cx, span);
|
||||
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
|
||||
|
||||
let mut signature_metadata: Vec<DIType> =
|
||||
Vec::with_capacity(signature.inputs.len() + 1);
|
||||
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
|
||||
|
||||
// return type
|
||||
signature_metadata.push(match ty::get(signature.output).sty {
|
||||
@@ -2245,7 +2711,8 @@ fn trait_metadata(cx: &CrateContext,
|
||||
trait_type: ty::t,
|
||||
substs: &subst::Substs,
|
||||
trait_store: ty::TraitStore,
|
||||
_: &ty::BuiltinBounds)
|
||||
_: &ty::BuiltinBounds,
|
||||
unique_type_id: UniqueTypeId)
|
||||
-> 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. But it does not describe
|
||||
@@ -2272,49 +2739,55 @@ fn trait_metadata(cx: &CrateContext,
|
||||
composite_type_metadata(cx,
|
||||
trait_llvm_type,
|
||||
name.as_slice(),
|
||||
unique_type_id,
|
||||
[],
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
definition_span)
|
||||
}
|
||||
|
||||
|
||||
fn type_metadata(cx: &CrateContext,
|
||||
t: ty::t,
|
||||
usage_site_span: Span)
|
||||
-> DIType {
|
||||
let cache_id = cache_id_for_type(t);
|
||||
|
||||
match debug_context(cx).created_types.borrow().find(&cache_id) {
|
||||
Some(type_metadata) => return *type_metadata,
|
||||
None => ()
|
||||
}
|
||||
|
||||
fn create_pointer_to_box_metadata(cx: &CrateContext,
|
||||
pointer_type: ty::t,
|
||||
type_in_box: ty::t)
|
||||
-> DIType {
|
||||
let content_type_name = ppaux::ty_to_str(cx.tcx(), type_in_box);
|
||||
let content_type_name = content_type_name.as_slice();
|
||||
let content_llvm_type = type_of::type_of(cx, type_in_box);
|
||||
let content_type_metadata = type_metadata(
|
||||
cx,
|
||||
type_in_box,
|
||||
codemap::DUMMY_SP);
|
||||
|
||||
let box_metadata = boxed_type_metadata(
|
||||
cx,
|
||||
Some(content_type_name),
|
||||
content_llvm_type,
|
||||
content_type_metadata,
|
||||
codemap::DUMMY_SP);
|
||||
|
||||
pointer_type_metadata(cx, pointer_type, box_metadata)
|
||||
}
|
||||
// Get the unique type id of this type.
|
||||
let unique_type_id = {
|
||||
let mut type_map = debug_context(cx).type_map.borrow_mut();
|
||||
match type_map.find_metadata_for_type(t) {
|
||||
Some(metadata) => {
|
||||
return metadata;
|
||||
},
|
||||
None => {
|
||||
let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
|
||||
match type_map.find_metadata_for_unique_id(unique_type_id) {
|
||||
Some(metadata) => {
|
||||
type_map.register_type_with_metadata(cx, t, metadata);
|
||||
return metadata;
|
||||
},
|
||||
None => {
|
||||
// There really is no type metadata for this type, so proceed by creating
|
||||
// it
|
||||
unique_type_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
debug!("type_metadata: {:?}", ty::get(t));
|
||||
|
||||
macro_rules! return_if_created_in_meantime(
|
||||
() => (
|
||||
match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
|
||||
Some(metadata) => return metadata,
|
||||
None => { /* proceed normally */ }
|
||||
};
|
||||
)
|
||||
)
|
||||
|
||||
let sty = &ty::get(t).sty;
|
||||
let type_metadata = match *sty {
|
||||
let (type_metadata, should_already_be_stored_in_typemap) = match *sty {
|
||||
ty::ty_nil |
|
||||
ty::ty_bot |
|
||||
ty::ty_bool |
|
||||
@@ -2322,50 +2795,73 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
|
||||
ty::ty_int(_) |
|
||||
ty::ty_uint(_) |
|
||||
ty::ty_float(_) => {
|
||||
basic_type_metadata(cx, t)
|
||||
(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::ty_enum(def_id, _) => {
|
||||
prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
|
||||
let is_c_style_enum = match *adt::represent_type(cx, t) {
|
||||
adt::CEnum(..) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
(prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx),
|
||||
!is_c_style_enum)
|
||||
}
|
||||
ty::ty_box(typ) => {
|
||||
create_pointer_to_box_metadata(cx, t, typ)
|
||||
ty::ty_box(pointee_type) => {
|
||||
let box_content_metadata = at_box_metadata(cx, pointee_type, unique_type_id);
|
||||
return_if_created_in_meantime!();
|
||||
(pointer_type_metadata(cx, t, box_content_metadata), false)
|
||||
}
|
||||
ty::ty_vec(ref mt, Some(len)) => fixed_vec_metadata(cx, mt.ty, len, usage_site_span),
|
||||
ty::ty_uniq(typ) => {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_vec(ref mt, Some(len)) => {
|
||||
(fixed_vec_metadata(cx, mt.ty, len, usage_site_span), false)
|
||||
}
|
||||
ty::ty_uniq(pointee_type) => {
|
||||
(match ty::get(pointee_type).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
|
||||
let vec_metadata = heap_vec_metadata(cx,
|
||||
pointee_type,
|
||||
mt.ty,
|
||||
unique_type_id,
|
||||
usage_site_span);
|
||||
return_if_created_in_meantime!();
|
||||
pointer_type_metadata(cx, t, vec_metadata)
|
||||
}
|
||||
ty::ty_str => {
|
||||
let i8_t = ty::mk_i8();
|
||||
let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
|
||||
let vec_metadata = heap_vec_metadata(cx,
|
||||
pointee_type,
|
||||
i8_t,
|
||||
unique_type_id,
|
||||
usage_site_span);
|
||||
pointer_type_metadata(cx, t, vec_metadata)
|
||||
}
|
||||
_ => {
|
||||
let pointee = type_metadata(cx, typ, usage_site_span);
|
||||
pointer_type_metadata(cx, t, pointee)
|
||||
let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
|
||||
return_if_created_in_meantime!();
|
||||
pointer_type_metadata(cx, t, pointee_metadata)
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ref mt, None) => vec_slice_metadata(cx, t, mt.ty, usage_site_span),
|
||||
(match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_str => {
|
||||
let i8_t = ty::mk_i8();
|
||||
vec_slice_metadata(cx, t, i8_t, usage_site_span)
|
||||
vec_slice_metadata(cx, t, i8_t, unique_type_id, usage_site_span)
|
||||
}
|
||||
_ => {
|
||||
let pointee = type_metadata(cx, mt.ty, usage_site_span);
|
||||
return_if_created_in_meantime!();
|
||||
pointer_type_metadata(cx, t, pointee)
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
ty::ty_bare_fn(ref barefnty) => {
|
||||
subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
|
||||
(subroutine_type_metadata(cx, &barefnty.sig, usage_site_span), false)
|
||||
}
|
||||
ty::ty_closure(ref closurety) => {
|
||||
subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
|
||||
(subroutine_type_metadata(cx, &closurety.sig, usage_site_span), false)
|
||||
}
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
def_id,
|
||||
@@ -2373,25 +2869,60 @@ fn create_pointer_to_box_metadata(cx: &CrateContext,
|
||||
store,
|
||||
ref bounds
|
||||
}) => {
|
||||
trait_metadata(cx, def_id, t, substs, store, bounds)
|
||||
(trait_metadata(cx, def_id, t, substs, store, bounds, unique_type_id), false)
|
||||
}
|
||||
ty::ty_struct(def_id, ref substs) => {
|
||||
prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
|
||||
let struct_metadata = prepare_struct_metadata(cx,
|
||||
t,
|
||||
def_id,
|
||||
substs,
|
||||
unique_type_id,
|
||||
usage_site_span).finalize(cx);
|
||||
(struct_metadata, true)
|
||||
}
|
||||
ty::ty_tup(ref elements) => {
|
||||
prepare_tuple_metadata(cx,
|
||||
t,
|
||||
elements.as_slice(),
|
||||
usage_site_span).finalize(cx)
|
||||
let tuple_metadata = prepare_tuple_metadata(cx,
|
||||
t,
|
||||
elements.as_slice(),
|
||||
unique_type_id,
|
||||
usage_site_span).finalize(cx);
|
||||
(tuple_metadata, true)
|
||||
}
|
||||
_ => {
|
||||
cx.sess().bug(format!("debuginfo: unexpected type in \
|
||||
type_metadata: {:?}",
|
||||
cx.sess().bug(format!("debuginfo: unexpected type in type_metadata: {:?}",
|
||||
sty).as_slice())
|
||||
}
|
||||
};
|
||||
|
||||
debug_context(cx).created_types.borrow_mut().insert(cache_id, type_metadata);
|
||||
{
|
||||
let mut type_map = debug_context(cx).type_map.borrow_mut();
|
||||
|
||||
if should_already_be_stored_in_typemap {
|
||||
// Make sure that we already have a TypeMap entry entry for the ty::t.
|
||||
if type_map.find_metadata_for_type(t).is_none() {
|
||||
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
|
||||
let error_message = format!("Expected type metadata for ty::t '{}' to already be in
|
||||
the TypeMap but it was not (unique type id = {})",
|
||||
ppaux::ty_to_str(cx.tcx(), t),
|
||||
unique_type_id_str.as_slice());
|
||||
cx.sess().span_bug(usage_site_span, error_message.as_slice());
|
||||
}
|
||||
|
||||
// Also make sure that we already have a TypeMap entry entry for the unique type id.
|
||||
if type_map.find_metadata_for_unique_id(unique_type_id).is_none() {
|
||||
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
|
||||
let error_message = format!("Expected type metadata for unique type id '{}' to
|
||||
already be in the TypeMap but it was not. (ty::t = {})",
|
||||
unique_type_id_str.as_slice(),
|
||||
ppaux::ty_to_str(cx.tcx(), t));
|
||||
cx.sess().span_bug(usage_site_span, error_message.as_slice());
|
||||
}
|
||||
} else {
|
||||
type_map.register_type_with_metadata(cx, t, type_metadata);
|
||||
type_map.register_unique_id_with_metadata(cx, unique_type_id, type_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
type_metadata
|
||||
}
|
||||
|
||||
@@ -2446,20 +2977,6 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
|
||||
// Utility Functions
|
||||
//=-------------------------------------------------------------------------------------------------
|
||||
|
||||
fn cache_id_for_type(t: ty::t) -> uint {
|
||||
ty::type_id(t)
|
||||
}
|
||||
|
||||
// Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and
|
||||
// `prepare_enum_metadata()`.
|
||||
fn generate_unique_type_id(prefix: &'static str) -> String {
|
||||
unsafe {
|
||||
static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
|
||||
format!("{}{}", prefix,
|
||||
unique_id_counter.fetch_add(1, atomics::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
/// Return codemap::Loc corresponding to the beginning of the span
|
||||
fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
|
||||
cx.sess().codemap().lookup_char_pos(span.lo)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2013-2014 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.
|
||||
|
||||
// no-prefer-dynamic
|
||||
#![crate_type = "rlib"]
|
||||
// compile-flags:-g
|
||||
|
||||
struct S1;
|
||||
|
||||
impl S1 {
|
||||
fn f(&mut self) { }
|
||||
}
|
||||
|
||||
|
||||
struct S2;
|
||||
|
||||
impl S2 {
|
||||
fn f(&mut self) { }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2013-2014 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.
|
||||
|
||||
// ignore-android: FIXME(#10381)
|
||||
|
||||
// aux-build:cross_crate_debuginfo_type_uniquing.rs
|
||||
extern crate cross_crate_debuginfo_type_uniquing;
|
||||
|
||||
// no-prefer-dynamic
|
||||
// compile-flags:-g -Zlto
|
||||
|
||||
pub struct C;
|
||||
pub fn p() -> C {
|
||||
C
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
Reference in New Issue
Block a user