@@ -45,6 +45,46 @@ This file consists of three conceptual sections:
45
45
2. Module-internal metadata creation functions
46
46
3. Minor utility functions
47
47
48
+
49
+ ## Recursive Types
50
+ Some kinds of types, such as structs and enums can be recursive. That means that the type definition
51
+ of some type X refers to some other type which in turn (transitively) refers to X. This introduces
52
+ cycles into the type referral graph. A naive algorithm doing an on-demand, depth-first traversal of
53
+ this graph when describing types, can get trapped in an endless loop when it reaches such a cycle.
54
+
55
+ For example, the following simple type for a singly-linked list...
56
+
57
+ ```
58
+ struct List {
59
+ value: int,
60
+ tail: Option<@List>,
61
+ }
62
+ ```
63
+
64
+ will generate the following callstack with a naive DFS algorithm:
65
+
66
+ ```
67
+ describe(t = List)
68
+ describe(t = int)
69
+ describe(t = Option<@List>)
70
+ describe(t = @List)
71
+ describe(t = List) // at the beginning again...
72
+ ...
73
+ ```
74
+
75
+ To break cycles like these, we use "forward declarations". That is, when the algorithm encounters a
76
+ possibly recursive type (any struct or enum), it immediately creates a type description node and
77
+ inserts it into the cache *before* describing the members of the type. This type description is just
78
+ a stub (as type members are not described and added to it yet) but it allows the algorithm to
79
+ already refer to the type. After the stub is inserted into the cache, the algorithm continues as
80
+ before. If it now encounters a recursive reference, it will hit the cache and does not try to
81
+ describe the type anew.
82
+
83
+ This behaviour is encapsulated in the 'RecursiveTypeDescription' enum, which represents a kind of
84
+ continuation, storing all state needed to continue traversal at the type members after the type has
85
+ been registered with the cache. (This implementation approach might be a tad over-engineered and
86
+ may change in the future)
87
+
48
88
*/
49
89
50
90
@@ -561,16 +601,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
561
601
_) => {
562
602
( ident, fn_decl, generics, Some ( top_level_block) , span)
563
603
}
564
- ast_map:: node_foreign_item( @ast:: foreign_item {
565
- ident : ident,
566
- node : ast:: foreign_item_fn( ref fn_decl, ref generics) ,
567
- span : span,
568
- _
569
- } ,
570
- _,
571
- _,
572
- _) => {
573
- //(ident, fn_decl, generics, None, span)
604
+ ast_map:: node_foreign_item( @ast:: foreign_item { _ } , _, _, _) => {
574
605
return FunctionWithoutDebugInfo ;
575
606
}
576
607
ast_map:: node_variant( * ) |
@@ -1062,18 +1093,13 @@ fn prepare_struct_metadata(cx: &mut CrateContext,
1062
1093
span : Span )
1063
1094
-> RecursiveTypeDescription {
1064
1095
let struct_name = ppaux:: ty_to_str ( cx. tcx , struct_type) ;
1065
- println ( fmt ! ( "struct_metadata: %s" , struct_name) ) ;
1066
-
1067
1096
let struct_llvm_type = type_of:: type_of ( cx, struct_type) ;
1097
+
1068
1098
let ( containing_scope, definition_span) = get_namespace_and_span_for_item ( cx, def_id, span) ;
1069
1099
1070
1100
let file_name = span_start ( cx, definition_span) . file . name ;
1071
1101
let file_metadata = file_metadata ( cx, file_name) ;
1072
1102
1073
- let loc = span_start ( cx, definition_span) ;
1074
-
1075
- let ( composite_size, composite_align) = size_and_align_of ( cx, struct_llvm_type) ;
1076
-
1077
1103
let struct_metadata_stub = create_struct_stub ( cx,
1078
1104
struct_llvm_type,
1079
1105
struct_name,
@@ -1142,43 +1168,14 @@ impl RecursiveTypeDescription {
1142
1168
1143
1169
// ... then create the member descriptions
1144
1170
let member_descriptions = member_description_factory ( cx) ;
1145
- let member_metadata: ~[ DIDescriptor ] = member_descriptions
1146
- . iter ( )
1147
- . enumerate ( )
1148
- . map ( |( i, member_description) | {
1149
- let ( member_size,
1150
- member_align) = size_and_align_of ( cx, member_description. llvm_type ) ;
1151
- let member_offset = match member_description. offset {
1152
- FixedMemberOffset { bytes } => bytes,
1153
- ComputedMemberOffset => {
1154
- machine:: llelement_offset ( cx, llvm_type, i)
1155
- }
1156
- } ;
1157
-
1158
- do member_description. name . with_c_str |member_name| {
1159
- unsafe {
1160
- llvm:: LLVMDIBuilderCreateMemberType (
1161
- DIB ( cx) ,
1162
- metadata_stub,
1163
- member_name,
1164
- file_metadata,
1165
- 0 as c_uint ,
1166
- bytes_to_bits ( member_size) ,
1167
- bytes_to_bits ( member_align) ,
1168
- bytes_to_bits ( member_offset) ,
1169
- 0 ,
1170
- member_description. type_metadata )
1171
- }
1172
- }
1173
- } )
1174
- . collect ( ) ;
1175
-
1176
- unsafe {
1177
- let type_array = create_DIArray ( DIB ( cx) , member_metadata) ;
1178
- llvm:: LLVMDICompositeTypeSetTypeArray ( metadata_stub, type_array) ;
1179
- }
1180
1171
1181
- metadata_stub
1172
+ set_members_of_composite_type ( cx,
1173
+ metadata_stub,
1174
+ llvm_type,
1175
+ member_descriptions,
1176
+ file_metadata,
1177
+ codemap:: dummy_sp ( ) ) ;
1178
+ return metadata_stub;
1182
1179
}
1183
1180
}
1184
1181
}
@@ -1469,6 +1466,7 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
1469
1466
1470
1467
enum MemberOffset {
1471
1468
FixedMemberOffset { bytes : uint } ,
1469
+ // For ComputedMemberOffset, the offset is read from the llvm type definition
1472
1470
ComputedMemberOffset
1473
1471
}
1474
1472
@@ -1490,26 +1488,15 @@ fn composite_type_metadata(cx: &mut CrateContext,
1490
1488
file_metadata : DIFile ,
1491
1489
definition_span : Span )
1492
1490
-> DICompositeType {
1493
- let loc = span_start ( cx, definition_span) ;
1494
- let ( composite_size, composite_align) = size_and_align_of ( cx, composite_llvm_type) ;
1495
-
1496
- let composite_type_metadata = do composite_type_name. with_c_str |name| {
1497
- unsafe {
1498
- llvm:: LLVMDIBuilderCreateStructType (
1499
- DIB ( cx) ,
1500
- containing_scope,
1501
- name,
1502
- file_metadata,
1503
- loc. line as c_uint ,
1504
- bytes_to_bits ( composite_size) ,
1505
- bytes_to_bits ( composite_align) ,
1506
- 0 ,
1507
- ptr:: null ( ) ,
1508
- ptr:: null ( ) ,
1509
- 0 ,
1510
- ptr:: null ( ) )
1511
- } } ;
1512
-
1491
+ // Create the (empty) struct metadata node ...
1492
+ let composite_type_metadata = create_struct_stub ( cx,
1493
+ composite_llvm_type,
1494
+ composite_type_name,
1495
+ containing_scope,
1496
+ file_metadata,
1497
+ definition_span) ;
1498
+
1499
+ // ... and immediately create and add the member descriptions.
1513
1500
set_members_of_composite_type ( cx,
1514
1501
composite_type_metadata,
1515
1502
composite_llvm_type,
@@ -1563,7 +1550,7 @@ fn set_members_of_composite_type(cx: &mut CrateContext,
1563
1550
}
1564
1551
1565
1552
// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any caching, does not
1566
- // add any fields to the struct. This can be done later with LLVMDICompositeTypeSetTypeArray ().
1553
+ // add any fields to the struct. This can be done later with set_members_of_composite_type ().
1567
1554
fn create_struct_stub ( cx : & mut CrateContext ,
1568
1555
struct_llvm_type : Type ,
1569
1556
struct_type_name : & str ,
@@ -1576,6 +1563,10 @@ fn create_struct_stub(cx: &mut CrateContext,
1576
1563
1577
1564
return do struct_type_name. with_c_str |name| {
1578
1565
unsafe {
1566
+ // LLVMDIBuilderCreateStructType() wants an empty array. A null pointer will lead to
1567
+ // hard to trace and debug LLVM assertions later on in llvm/lib/IR/Value.cpp
1568
+ let empty_array = create_DIArray ( DIB ( cx) , [ ] ) ;
1569
+
1579
1570
llvm:: LLVMDIBuilderCreateStructType (
1580
1571
DIB ( cx) ,
1581
1572
containing_scope,
@@ -1586,7 +1577,7 @@ fn create_struct_stub(cx: &mut CrateContext,
1586
1577
bytes_to_bits ( struct_align) ,
1587
1578
0 ,
1588
1579
ptr:: null ( ) ,
1589
- ptr :: null ( ) ,
1580
+ empty_array ,
1590
1581
0 ,
1591
1582
ptr:: null ( ) )
1592
1583
} } ;
@@ -1864,7 +1855,7 @@ fn trait_metadata(cx: &mut CrateContext,
1864
1855
substs : & ty:: substs ,
1865
1856
trait_store : ty:: TraitStore ,
1866
1857
mutability : ast:: Mutability ,
1867
- builtinBounds : & ty:: BuiltinBounds ,
1858
+ _ : & ty:: BuiltinBounds ,
1868
1859
usage_site_span : Span )
1869
1860
-> DIType {
1870
1861
// The implementation provided here is a stub. It makes sure that the trait type is
@@ -2120,14 +2111,6 @@ fn DIB(cx: &CrateContext) -> DIBuilderRef {
2120
2111
cx. dbg_cx . get_ref ( ) . builder
2121
2112
}
2122
2113
2123
- fn assert_fcx_has_span ( fcx : & FunctionContext ) {
2124
- if fcx. span . is_none ( ) {
2125
- fcx. ccx . sess . bug ( fmt ! ( "debuginfo: Encountered function %s with invalid source span. \
2126
- This function should have been ignored by debuginfo generation.",
2127
- ast_map:: path_to_str( fcx. path, fcx. ccx. sess. intr( ) ) ) ) ;
2128
- }
2129
- }
2130
-
2131
2114
fn fn_should_be_ignored ( fcx : & FunctionContext ) -> bool {
2132
2115
match fcx. debug_context {
2133
2116
FunctionDebugContext ( _) => false ,
0 commit comments