@@ -45,6 +45,46 @@ This file consists of three conceptual sections:
45452. Module-internal metadata creation functions
46463. Minor utility functions
4747
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+
4888*/
4989
5090
@@ -561,16 +601,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
561601 _) => {
562602 ( ident, fn_decl, generics, Some ( top_level_block) , span)
563603 }
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 { _ } , _, _, _) => {
574605 return FunctionWithoutDebugInfo ;
575606 }
576607 ast_map:: node_variant( * ) |
@@ -1062,18 +1093,13 @@ fn prepare_struct_metadata(cx: &mut CrateContext,
10621093 span : Span )
10631094 -> RecursiveTypeDescription {
10641095 let struct_name = ppaux:: ty_to_str ( cx. tcx , struct_type) ;
1065- println ( fmt ! ( "struct_metadata: %s" , struct_name) ) ;
1066-
10671096 let struct_llvm_type = type_of:: type_of ( cx, struct_type) ;
1097+
10681098 let ( containing_scope, definition_span) = get_namespace_and_span_for_item ( cx, def_id, span) ;
10691099
10701100 let file_name = span_start ( cx, definition_span) . file . name ;
10711101 let file_metadata = file_metadata ( cx, file_name) ;
10721102
1073- let loc = span_start ( cx, definition_span) ;
1074-
1075- let ( composite_size, composite_align) = size_and_align_of ( cx, struct_llvm_type) ;
1076-
10771103 let struct_metadata_stub = create_struct_stub ( cx,
10781104 struct_llvm_type,
10791105 struct_name,
@@ -1142,43 +1168,14 @@ impl RecursiveTypeDescription {
11421168
11431169 // ... then create the member descriptions
11441170 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- }
11801171
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;
11821179 }
11831180 }
11841181 }
@@ -1469,6 +1466,7 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
14691466
14701467enum MemberOffset {
14711468 FixedMemberOffset { bytes : uint } ,
1469+ // For ComputedMemberOffset, the offset is read from the llvm type definition
14721470 ComputedMemberOffset
14731471}
14741472
@@ -1490,26 +1488,15 @@ fn composite_type_metadata(cx: &mut CrateContext,
14901488 file_metadata : DIFile ,
14911489 definition_span : Span )
14921490 -> 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.
15131500 set_members_of_composite_type ( cx,
15141501 composite_type_metadata,
15151502 composite_llvm_type,
@@ -1563,7 +1550,7 @@ fn set_members_of_composite_type(cx: &mut CrateContext,
15631550}
15641551
15651552// 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 ().
15671554fn create_struct_stub ( cx : & mut CrateContext ,
15681555 struct_llvm_type : Type ,
15691556 struct_type_name : & str ,
@@ -1576,6 +1563,10 @@ fn create_struct_stub(cx: &mut CrateContext,
15761563
15771564 return do struct_type_name. with_c_str |name| {
15781565 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+
15791570 llvm:: LLVMDIBuilderCreateStructType (
15801571 DIB ( cx) ,
15811572 containing_scope,
@@ -1586,7 +1577,7 @@ fn create_struct_stub(cx: &mut CrateContext,
15861577 bytes_to_bits ( struct_align) ,
15871578 0 ,
15881579 ptr:: null ( ) ,
1589- ptr :: null ( ) ,
1580+ empty_array ,
15901581 0 ,
15911582 ptr:: null ( ) )
15921583 } } ;
@@ -1864,7 +1855,7 @@ fn trait_metadata(cx: &mut CrateContext,
18641855 substs : & ty:: substs ,
18651856 trait_store : ty:: TraitStore ,
18661857 mutability : ast:: Mutability ,
1867- builtinBounds : & ty:: BuiltinBounds ,
1858+ _ : & ty:: BuiltinBounds ,
18681859 usage_site_span : Span )
18691860 -> DIType {
18701861 // The implementation provided here is a stub. It makes sure that the trait type is
@@ -2120,14 +2111,6 @@ fn DIB(cx: &CrateContext) -> DIBuilderRef {
21202111 cx. dbg_cx . get_ref ( ) . builder
21212112}
21222113
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-
21312114fn fn_should_be_ignored ( fcx : & FunctionContext ) -> bool {
21322115 match fcx. debug_context {
21332116 FunctionDebugContext ( _) => false ,
0 commit comments