Skip to content

Commit

Permalink
auto merge of rust-lang#11274 : michaelwoerister/rust/issue11083, r=p…
Browse files Browse the repository at this point in the history
…cwalton

This pull request fixes rust-lang#11083. The problem was that recursive type definitions were not properly handled for enum types, leading to problems with LLVM's metadata "uniquing". This bug has already been fixed for struct types some time ago (rust-lang#9658) but I seem to have forgotten about enums back then. I added the offending code from issue rust-lang#11083 as a test case.
  • Loading branch information
bors committed Jan 2, 2014
2 parents ff578b7 + 645bb32 commit 3249de8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 64 deletions.
3 changes: 2 additions & 1 deletion src/librustc/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1658,7 +1658,8 @@ pub mod llvm {
AlignInBits: c_ulonglong,
Flags: c_uint,
Elements: ValueRef,
RunTimeLang: c_uint)
RunTimeLang: c_uint,
UniqueId: *c_char)
-> ValueRef;

pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
Expand Down
130 changes: 69 additions & 61 deletions src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ use syntax::parse::token::special_idents;
static DW_LANG_RUST: c_uint = 0x9000;

static DW_TAG_auto_variable: c_uint = 0x100;
// static DW_TAG_arg_variable: c_uint = 0x101;
static DW_TAG_arg_variable: c_uint = 0x101;

static DW_ATE_boolean: c_uint = 0x02;
static DW_ATE_float: c_uint = 0x04;
Expand Down Expand Up @@ -980,11 +980,11 @@ fn declare_local(bcx: @Block,
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);

let argument_index = match variable_kind {
ArgumentVariable(index) => index,
let (argument_index, dwarf_tag) = match variable_kind {
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
LocalVariable |
CapturedVariable => 0
} as c_uint;
CapturedVariable => (0, DW_TAG_auto_variable)
};

let (var_alloca, var_metadata) = name.with_c_str(|name| {
match variable_access {
Expand All @@ -993,7 +993,7 @@ fn declare_local(bcx: @Block,
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_auto_variable,
dwarf_tag,
scope_metadata,
name,
file_metadata,
Expand All @@ -1009,7 +1009,7 @@ fn declare_local(bcx: @Block,
unsafe {
llvm::LLVMDIBuilderCreateComplexVariable(
DIB(cx),
DW_TAG_auto_variable,
dwarf_tag,
scope_metadata,
name,
file_metadata,
Expand Down Expand Up @@ -1256,14 +1256,12 @@ impl RecursiveTypeDescription {
} => {
// Insert the stub into the cache in order to allow recursive references ...
{
let mut created_types = debug_context(cx).created_types
.borrow_mut();
let mut created_types = debug_context(cx).created_types.borrow_mut();
created_types.get().insert(cache_id, metadata_stub);
}

// ... then create the member descriptions ...
let member_descriptions = member_description_factory.
create_member_descriptions(cx);
let member_descriptions = member_description_factory.create_member_descriptions(cx);

// ... and attach them to the stub to complete it.
set_members_of_composite_type(cx,
Expand Down Expand Up @@ -1348,13 +1346,13 @@ impl MemberDescriptionFactory for GeneralMemberDescriptionFactory {
.enumerate()
.map(|(i, struct_def)| {
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
describe_variant(cx,
struct_def,
self.variants[i],
Some(self.discriminant_type_metadata),
self.containing_scope,
self.file_metadata,
self.span);
describe_enum_variant(cx,
struct_def,
self.variants[i],
Some(self.discriminant_type_metadata),
self.containing_scope,
self.file_metadata,
self.span);

let member_descriptions =
member_desc_factory.create_member_descriptions(cx);
Expand Down Expand Up @@ -1398,14 +1396,14 @@ impl MemberDescriptionFactory for EnumVariantMemberDescriptionFactory {
}
}

fn describe_variant(cx: &CrateContext,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_type_metadata: Option<DIType>,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, @MemberDescriptionFactory) {
fn describe_enum_variant(cx: &CrateContext,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_type_metadata: Option<DIType>,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, @MemberDescriptionFactory) {
let variant_name = token::ident_to_str(&variant_info.name);
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
struct_def.packed);
Expand Down Expand Up @@ -1538,13 +1536,13 @@ fn prepare_enum_metadata(cx: &CrateContext,
assert!(variants.len() == 1);
let (metadata_stub,
variant_llvm_type,
member_description_factory) = describe_variant(cx,
struct_def,
variants[0],
None,
containing_scope,
file_metadata,
span);
member_description_factory) = describe_enum_variant(cx,
struct_def,
variants[0],
None,
containing_scope,
file_metadata,
span);
UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: metadata_stub,
Expand All @@ -1557,21 +1555,25 @@ fn prepare_enum_metadata(cx: &CrateContext,
let discriminant_type_metadata = discriminant_type_metadata(inttype);
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 enum_metadata = enum_name.with_c_str(|enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
containing_scope,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
0, // Flags
ptr::null(),
0) // RuntimeLang
}
unique_id.with_c_str(|unique_id| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
containing_scope,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
0, // Flags
ptr::null(),
0, // RuntimeLang
unique_id)
}
})
});

UnfinishedMetadata {
Expand All @@ -1592,13 +1594,13 @@ fn prepare_enum_metadata(cx: &CrateContext,
adt::NullablePointer { nonnull: ref struct_def, nndiscr, .. } => {
let (metadata_stub,
variant_llvm_type,
member_description_factory) = describe_variant(cx,
struct_def,
variants[nndiscr],
None,
containing_scope,
file_metadata,
span);
member_description_factory) = describe_enum_variant(cx,
struct_def,
variants[nndiscr],
None,
containing_scope,
file_metadata,
span);
UnfinishedMetadata {
cache_id: cache_id_for_type(enum_type),
metadata_stub: metadata_stub,
Expand Down Expand Up @@ -1725,10 +1727,7 @@ fn create_struct_stub(cx: &CrateContext,

// 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 = unsafe {
static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
format!("DiStructStub{}", unique_id_counter.fetch_add(1, atomics::SeqCst))
};
let unique_id = generate_unique_type_id("DI_STRUCT_");

return unsafe {
struct_type_name.with_c_str(|name| {
Expand Down Expand Up @@ -2059,10 +2058,6 @@ fn trait_metadata(cx: &CrateContext,
definition_span);
}

fn cache_id_for_type(t: ty::t) -> uint {
ty::type_id(t)
}

fn type_metadata(cx: &CrateContext,
t: ty::t,
usage_site_span: Span)
Expand Down Expand Up @@ -2244,6 +2239,19 @@ 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) -> ~str {
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)
Expand Down
6 changes: 4 additions & 2 deletions src/rustllvm/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
uint64_t AlignInBits,
unsigned Flags,
LLVMValueRef Elements,
unsigned RunTimeLang)
unsigned RunTimeLang,
const char* UniqueId)
{
return wrap(Builder->createUnionType(
unwrapDI<DIDescriptor>(Scope),
Expand All @@ -431,7 +432,8 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
AlignInBits,
Flags,
unwrapDI<DIArray>(Elements),
RunTimeLang));
RunTimeLang,
UniqueId));
}

extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
Expand Down
33 changes: 33 additions & 0 deletions src/test/debug-info/recursive-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2013 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.

// xfail-android: FIXME(#10381)

// compile-flags:-Z extra-debug-info
// debugger:run

// Test whether compiling a recursive enum definition crashes debug info generation. The test case
// is taken from issue #11083.

#[allow(unused_variable)];

pub struct Window<'a> {
callbacks: WindowCallbacks<'a>
}

struct WindowCallbacks<'a> {
pos_callback: Option<WindowPosCallback<'a>>,
}

pub type WindowPosCallback<'a> = 'a |&Window, i32, i32|;

fn main() {
let x = WindowCallbacks { pos_callback: None };
}

0 comments on commit 3249de8

Please sign in to comment.