diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 00493b018c10e..bdfeee37625e8 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 { + 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 0000000000000..11ee5031ca771 --- /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 or the MIT license +// , 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() {()}