about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-08-22 21:11:22 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-09-03 13:39:35 +0300
commit079c390d5089735b5eaa8b06ddb3beedcddbee7d (patch)
tree0ee26d3362956037a075eab5d8e1a433a0ba34da
parentd9b332bd69770cb716233b6998b11d345f6f184b (diff)
downloadrust-079c390d5089735b5eaa8b06ddb3beedcddbee7d.tar.gz
rust-079c390d5089735b5eaa8b06ddb3beedcddbee7d.zip
Generate debuginfo for unions
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs106
-rw-r--r--src/test/debuginfo/union-smoke.rs49
2 files changed, 153 insertions, 2 deletions
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 00493b018c1..bdfeee37625 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -786,7 +786,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     usage_site_span).finalize(cx)
         }
         ty::TyUnion(..) => {
-            unimplemented!();
+            prepare_union_metadata(cx,
+                                   t,
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
         }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
@@ -1038,6 +1041,7 @@ enum MemberDescriptionFactory<'tcx> {
     StructMDF(StructMemberDescriptionFactory<'tcx>),
     TupleMDF(TupleMemberDescriptionFactory<'tcx>),
     EnumMDF(EnumMemberDescriptionFactory<'tcx>),
+    UnionMDF(UnionMemberDescriptionFactory<'tcx>),
     VariantMDF(VariantMemberDescriptionFactory<'tcx>)
 }
 
@@ -1054,6 +1058,9 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
             EnumMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
+            UnionMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
             VariantMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
@@ -1154,7 +1161,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
-
 //=-----------------------------------------------------------------------------
 // Tuples
 //=-----------------------------------------------------------------------------
@@ -1209,6 +1215,66 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
+//=-----------------------------------------------------------------------------
+// Unions
+//=-----------------------------------------------------------------------------
+
+struct UnionMemberDescriptionFactory<'tcx> {
+    variant: ty::VariantDef<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    span: Span,
+}
+
+impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
+                                      -> Vec<MemberDescription> {
+        self.variant.fields.iter().map(|field| {
+            let fty = monomorphize::field_ty(cx.tcx(), self.substs, field);
+            MemberDescription {
+                name: field.name.to_string(),
+                llvm_type: type_of::type_of(cx, fty),
+                type_metadata: type_metadata(cx, fty, self.span),
+                offset: FixedMemberOffset { bytes: 0 },
+                flags: FLAGS_NONE,
+            }
+        }).collect()
+    }
+}
+
+fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                                    union_type: Ty<'tcx>,
+                                    unique_type_id: UniqueTypeId,
+                                    span: Span)
+                                    -> RecursiveTypeDescription<'tcx> {
+    let union_name = compute_debuginfo_type_name(cx, union_type, false);
+    let union_llvm_type = type_of::in_memory_type_of(cx, union_type);
+
+    let (union_def_id, variant, substs) = match union_type.sty {
+        ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs),
+        _ => bug!("prepare_union_metadata on a non-union")
+    };
+
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id);
+
+    let union_metadata_stub = create_union_stub(cx,
+                                                union_llvm_type,
+                                                &union_name,
+                                                unique_type_id,
+                                                containing_scope);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        union_type,
+        unique_type_id,
+        union_metadata_stub,
+        union_llvm_type,
+        UnionMDF(UnionMemberDescriptionFactory {
+            variant: variant,
+            substs: substs,
+            span: span,
+        })
+    )
+}
 
 //=-----------------------------------------------------------------------------
 // Enums
@@ -1798,6 +1864,42 @@ fn create_struct_stub(cx: &CrateContext,
     return metadata_stub;
 }
 
+fn create_union_stub(cx: &CrateContext,
+                     union_llvm_type: Type,
+                     union_type_name: &str,
+                     unique_type_id: UniqueTypeId,
+                     containing_scope: DIScope)
+                   -> DICompositeType {
+    let (union_size, union_align) = size_and_align_of(cx, union_llvm_type);
+
+    let unique_type_id_str = debug_context(cx).type_map
+                                              .borrow()
+                                              .get_unique_type_id_as_string(unique_type_id);
+    let name = CString::new(union_type_name).unwrap();
+    let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap();
+    let metadata_stub = unsafe {
+        // LLVMRustDIBuilderCreateUnionType() 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), &[]);
+
+        llvm::LLVMRustDIBuilderCreateUnionType(
+            DIB(cx),
+            containing_scope,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            bytes_to_bits(union_size),
+            bytes_to_bits(union_align),
+            0, // Flags
+            empty_array,
+            0, // RuntimeLang
+            unique_type_id.as_ptr())
+    };
+
+    return metadata_stub;
+}
+
 /// Creates debug information for the given global variable.
 ///
 /// Adds the created metadata nodes directly to the crate's IR.
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
new file mode 100644
index 00000000000..11ee5031ca7
--- /dev/null
+++ b/src/test/debuginfo/union-smoke.rs
@@ -0,0 +1,49 @@
+// Copyright 2016 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.
+
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:print u
+// gdb-check:$1 = {a = 11 '\v', b = 11}
+// gdb-command:print union_smoke::SU
+// gdb-check:$2 = {a = 10 '\n', b = 10}
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+// lldb-command:print a
+// lldb-check:[...]$0 = {a = 11 '\v', b = 11}
+// lldb-command:print union_smoke::SU
+// lldb-check:[...]$1 = {a = 10 '\n', b = 10}
+
+#![allow(unused)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+static SU: U = U { a: 10 };
+
+fn main() {
+    let u = U { b: 11 };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}