Skip to content

Commit 3249de8

Browse files
committed
auto merge of #11274 : michaelwoerister/rust/issue11083, r=pcwalton
This pull request fixes #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 (#9658) but I seem to have forgotten about enums back then. I added the offending code from issue #11083 as a test case.
2 parents ff578b7 + 645bb32 commit 3249de8

File tree

4 files changed

+108
-64
lines changed

4 files changed

+108
-64
lines changed

src/librustc/lib/llvm.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,8 @@ pub mod llvm {
16581658
AlignInBits: c_ulonglong,
16591659
Flags: c_uint,
16601660
Elements: ValueRef,
1661-
RunTimeLang: c_uint)
1661+
RunTimeLang: c_uint,
1662+
UniqueId: *c_char)
16621663
-> ValueRef;
16631664

16641665
pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);

src/librustc/middle/trans/debuginfo.rs

+69-61
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ use syntax::parse::token::special_idents;
157157
static DW_LANG_RUST: c_uint = 0x9000;
158158

159159
static DW_TAG_auto_variable: c_uint = 0x100;
160-
// static DW_TAG_arg_variable: c_uint = 0x101;
160+
static DW_TAG_arg_variable: c_uint = 0x101;
161161

162162
static DW_ATE_boolean: c_uint = 0x02;
163163
static DW_ATE_float: c_uint = 0x04;
@@ -980,11 +980,11 @@ fn declare_local(bcx: @Block,
980980
let loc = span_start(cx, span);
981981
let type_metadata = type_metadata(cx, variable_type, span);
982982

983-
let argument_index = match variable_kind {
984-
ArgumentVariable(index) => index,
983+
let (argument_index, dwarf_tag) = match variable_kind {
984+
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
985985
LocalVariable |
986-
CapturedVariable => 0
987-
} as c_uint;
986+
CapturedVariable => (0, DW_TAG_auto_variable)
987+
};
988988

989989
let (var_alloca, var_metadata) = name.with_c_str(|name| {
990990
match variable_access {
@@ -993,7 +993,7 @@ fn declare_local(bcx: @Block,
993993
unsafe {
994994
llvm::LLVMDIBuilderCreateLocalVariable(
995995
DIB(cx),
996-
DW_TAG_auto_variable,
996+
dwarf_tag,
997997
scope_metadata,
998998
name,
999999
file_metadata,
@@ -1009,7 +1009,7 @@ fn declare_local(bcx: @Block,
10091009
unsafe {
10101010
llvm::LLVMDIBuilderCreateComplexVariable(
10111011
DIB(cx),
1012-
DW_TAG_auto_variable,
1012+
dwarf_tag,
10131013
scope_metadata,
10141014
name,
10151015
file_metadata,
@@ -1256,14 +1256,12 @@ impl RecursiveTypeDescription {
12561256
} => {
12571257
// Insert the stub into the cache in order to allow recursive references ...
12581258
{
1259-
let mut created_types = debug_context(cx).created_types
1260-
.borrow_mut();
1259+
let mut created_types = debug_context(cx).created_types.borrow_mut();
12611260
created_types.get().insert(cache_id, metadata_stub);
12621261
}
12631262

12641263
// ... then create the member descriptions ...
1265-
let member_descriptions = member_description_factory.
1266-
create_member_descriptions(cx);
1264+
let member_descriptions = member_description_factory.create_member_descriptions(cx);
12671265

12681266
// ... and attach them to the stub to complete it.
12691267
set_members_of_composite_type(cx,
@@ -1348,13 +1346,13 @@ impl MemberDescriptionFactory for GeneralMemberDescriptionFactory {
13481346
.enumerate()
13491347
.map(|(i, struct_def)| {
13501348
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
1351-
describe_variant(cx,
1352-
struct_def,
1353-
self.variants[i],
1354-
Some(self.discriminant_type_metadata),
1355-
self.containing_scope,
1356-
self.file_metadata,
1357-
self.span);
1349+
describe_enum_variant(cx,
1350+
struct_def,
1351+
self.variants[i],
1352+
Some(self.discriminant_type_metadata),
1353+
self.containing_scope,
1354+
self.file_metadata,
1355+
self.span);
13581356

13591357
let member_descriptions =
13601358
member_desc_factory.create_member_descriptions(cx);
@@ -1398,14 +1396,14 @@ impl MemberDescriptionFactory for EnumVariantMemberDescriptionFactory {
13981396
}
13991397
}
14001398

1401-
fn describe_variant(cx: &CrateContext,
1402-
struct_def: &adt::Struct,
1403-
variant_info: &ty::VariantInfo,
1404-
discriminant_type_metadata: Option<DIType>,
1405-
containing_scope: DIScope,
1406-
file_metadata: DIFile,
1407-
span: Span)
1408-
-> (DICompositeType, Type, @MemberDescriptionFactory) {
1399+
fn describe_enum_variant(cx: &CrateContext,
1400+
struct_def: &adt::Struct,
1401+
variant_info: &ty::VariantInfo,
1402+
discriminant_type_metadata: Option<DIType>,
1403+
containing_scope: DIScope,
1404+
file_metadata: DIFile,
1405+
span: Span)
1406+
-> (DICompositeType, Type, @MemberDescriptionFactory) {
14091407
let variant_name = token::ident_to_str(&variant_info.name);
14101408
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
14111409
struct_def.packed);
@@ -1538,13 +1536,13 @@ fn prepare_enum_metadata(cx: &CrateContext,
15381536
assert!(variants.len() == 1);
15391537
let (metadata_stub,
15401538
variant_llvm_type,
1541-
member_description_factory) = describe_variant(cx,
1542-
struct_def,
1543-
variants[0],
1544-
None,
1545-
containing_scope,
1546-
file_metadata,
1547-
span);
1539+
member_description_factory) = describe_enum_variant(cx,
1540+
struct_def,
1541+
variants[0],
1542+
None,
1543+
containing_scope,
1544+
file_metadata,
1545+
span);
15481546
UnfinishedMetadata {
15491547
cache_id: cache_id_for_type(enum_type),
15501548
metadata_stub: metadata_stub,
@@ -1557,21 +1555,25 @@ fn prepare_enum_metadata(cx: &CrateContext,
15571555
let discriminant_type_metadata = discriminant_type_metadata(inttype);
15581556
let enum_llvm_type = type_of::type_of(cx, enum_type);
15591557
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
1558+
let unique_id = generate_unique_type_id("DI_ENUM_");
15601559

15611560
let enum_metadata = enum_name.with_c_str(|enum_name| {
1562-
unsafe {
1563-
llvm::LLVMDIBuilderCreateUnionType(
1564-
DIB(cx),
1565-
containing_scope,
1566-
enum_name,
1567-
file_metadata,
1568-
loc.line as c_uint,
1569-
bytes_to_bits(enum_type_size),
1570-
bytes_to_bits(enum_type_align),
1571-
0, // Flags
1572-
ptr::null(),
1573-
0) // RuntimeLang
1574-
}
1561+
unique_id.with_c_str(|unique_id| {
1562+
unsafe {
1563+
llvm::LLVMDIBuilderCreateUnionType(
1564+
DIB(cx),
1565+
containing_scope,
1566+
enum_name,
1567+
file_metadata,
1568+
loc.line as c_uint,
1569+
bytes_to_bits(enum_type_size),
1570+
bytes_to_bits(enum_type_align),
1571+
0, // Flags
1572+
ptr::null(),
1573+
0, // RuntimeLang
1574+
unique_id)
1575+
}
1576+
})
15751577
});
15761578

15771579
UnfinishedMetadata {
@@ -1592,13 +1594,13 @@ fn prepare_enum_metadata(cx: &CrateContext,
15921594
adt::NullablePointer { nonnull: ref struct_def, nndiscr, .. } => {
15931595
let (metadata_stub,
15941596
variant_llvm_type,
1595-
member_description_factory) = describe_variant(cx,
1596-
struct_def,
1597-
variants[nndiscr],
1598-
None,
1599-
containing_scope,
1600-
file_metadata,
1601-
span);
1597+
member_description_factory) = describe_enum_variant(cx,
1598+
struct_def,
1599+
variants[nndiscr],
1600+
None,
1601+
containing_scope,
1602+
file_metadata,
1603+
span);
16021604
UnfinishedMetadata {
16031605
cache_id: cache_id_for_type(enum_type),
16041606
metadata_stub: metadata_stub,
@@ -1725,10 +1727,7 @@ fn create_struct_stub(cx: &CrateContext,
17251727

17261728
// We assign unique IDs to the type stubs so LLVM metadata uniquing does not reuse instances
17271729
// where we don't want it.
1728-
let unique_id = unsafe {
1729-
static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
1730-
format!("DiStructStub{}", unique_id_counter.fetch_add(1, atomics::SeqCst))
1731-
};
1730+
let unique_id = generate_unique_type_id("DI_STRUCT_");
17321731

17331732
return unsafe {
17341733
struct_type_name.with_c_str(|name| {
@@ -2059,10 +2058,6 @@ fn trait_metadata(cx: &CrateContext,
20592058
definition_span);
20602059
}
20612060

2062-
fn cache_id_for_type(t: ty::t) -> uint {
2063-
ty::type_id(t)
2064-
}
2065-
20662061
fn type_metadata(cx: &CrateContext,
20672062
t: ty::t,
20682063
usage_site_span: Span)
@@ -2244,6 +2239,19 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
22442239
// Utility Functions
22452240
//=-------------------------------------------------------------------------------------------------
22462241

2242+
fn cache_id_for_type(t: ty::t) -> uint {
2243+
ty::type_id(t)
2244+
}
2245+
2246+
// Used to avoid LLVM metadata uniquing problems. See `create_struct_stub()` and
2247+
// `prepare_enum_metadata()`.
2248+
fn generate_unique_type_id(prefix: &'static str) -> ~str {
2249+
unsafe {
2250+
static mut unique_id_counter: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
2251+
format!("{}{}", prefix, unique_id_counter.fetch_add(1, atomics::SeqCst))
2252+
}
2253+
}
2254+
22472255
/// Return codemap::Loc corresponding to the beginning of the span
22482256
fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
22492257
cx.sess.codemap.lookup_char_pos(span.lo)

src/rustllvm/RustWrapper.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,8 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
420420
uint64_t AlignInBits,
421421
unsigned Flags,
422422
LLVMValueRef Elements,
423-
unsigned RunTimeLang)
423+
unsigned RunTimeLang,
424+
const char* UniqueId)
424425
{
425426
return wrap(Builder->createUnionType(
426427
unwrapDI<DIDescriptor>(Scope),
@@ -431,7 +432,8 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
431432
AlignInBits,
432433
Flags,
433434
unwrapDI<DIArray>(Elements),
434-
RunTimeLang));
435+
RunTimeLang,
436+
UniqueId));
435437
}
436438

437439
extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {

src/test/debug-info/recursive-enum.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// xfail-android: FIXME(#10381)
12+
13+
// compile-flags:-Z extra-debug-info
14+
// debugger:run
15+
16+
// Test whether compiling a recursive enum definition crashes debug info generation. The test case
17+
// is taken from issue #11083.
18+
19+
#[allow(unused_variable)];
20+
21+
pub struct Window<'a> {
22+
callbacks: WindowCallbacks<'a>
23+
}
24+
25+
struct WindowCallbacks<'a> {
26+
pos_callback: Option<WindowPosCallback<'a>>,
27+
}
28+
29+
pub type WindowPosCallback<'a> = 'a |&Window, i32, i32|;
30+
31+
fn main() {
32+
let x = WindowCallbacks { pos_callback: None };
33+
}

0 commit comments

Comments
 (0)