diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index bfa8d84d5b0..1ce4108b3b5 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2115,7 +2115,21 @@ pub mod llvm { AlignInBits: c_ulonglong, Elements: ValueRef, ClassType: ValueRef) -> ValueRef; -}} + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateUnionType( + Builder: DIBuilderRef, + Scope: ValueRef, + Name: *c_char, + File: ValueRef, + LineNumber: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Flags: c_uint , + Elements: ValueRef, + RunTimeLang : c_uint) -> ValueRef; + } +} pub fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) { unsafe { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index d3878e242f3..86bdf509d65 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -501,9 +501,9 @@ fn create_struct(cx: &mut CrateContext, fields: ~[ty::field], span: span) -> DICompositeType { - debug!("create_struct: %?", ty::get(struct_type)); - let struct_name = ty_to_str(cx.tcx, struct_type); + debug!("create_struct: %s", struct_name); + let struct_llvm_type = type_of::type_of(cx, struct_type); let field_llvm_types = fields.map(|field| type_of::type_of(cx, field.mt.ty)); @@ -526,7 +526,7 @@ fn create_tuple(cx: &mut CrateContext, span: span) -> DICompositeType { - let tuple_name = "tuple"; // this should have a better name + let tuple_name = ty_to_str(cx.tcx, tuple_type); let tuple_llvm_type = type_of::type_of(cx, tuple_type); // Create a vec of empty strings. A vec::build_n() function would be nice for this. let mut component_names : ~[~str] = vec::with_capacity(component_types.len()); @@ -548,63 +548,119 @@ fn create_tuple(cx: &mut CrateContext, fn create_enum_md(cx: &mut CrateContext, enum_type: ty::t, enum_def_id: ast::def_id, - span: span) -> DIType { + substs: &ty::substs, + span: span) + -> DIType { let enum_name = ty_to_str(cx.tcx, enum_type); - let discriminator_llvm_type = Type::enum_discrim(cx); - let discriminator_size = machine::llsize_of_alloc(cx, discriminator_llvm_type); - let discriminator_align = machine::llalign_of_min(cx, discriminator_llvm_type); - - assert!(Type::enum_discrim(cx) == cx.int_type); - let discriminator_type_md = get_or_create_type(cx, ty::mk_int(), span); + // For empty enums there is an early exit. Just describe it as an empty struct with the + // appropriate name if ty::type_is_empty(cx.tcx, enum_type) { - // XXX: This should not "rename" the type to nil - return get_or_create_type(cx, ty::mk_nil(), span); + return create_composite_type(cx, Type::nil(), enum_name, &[], &[], &[], span); } + // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be + // needed in all of the following cases. + let discriminant_llvm_type = Type::enum_discrim(cx); + let discriminant_size = machine::llsize_of_alloc(cx, discriminant_llvm_type); + let discriminant_align = machine::llalign_of_min(cx, discriminant_llvm_type); + assert!(Type::enum_discrim(cx) == cx.int_type); + let discriminant_type_md = get_or_create_type(cx, ty::mk_int(), span); + + + let variants : &[ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id); + + let enumerators : ~[(~str, int)] = variants + .iter() + .transform(|v| (cx.sess.str_of(v.name).to_owned(), v.disr_val)) + .collect(); + + let enumerators_md : ~[DIDescriptor] = + do enumerators.iter().transform |&(name,value)| { + do name.as_c_str |name| { unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name, + value as c_ulonglong) + }} + }.collect(); + + let loc = span_start(cx, span); + let file_metadata = get_or_create_file(cx, loc.file.name); + + let discriminant_type_md = do enum_name.as_c_str |enum_name| { unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_md), + discriminant_type_md) + }}; + if ty::type_is_c_like_enum(cx.tcx, enum_type) { - - let variants : &[ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id); - - let enumerators : ~[(~str, int)] = variants - .iter() - .transform(|v| (cx.sess.str_of(v.name).to_owned(), v.disr_val)) - .collect(); - - let enumerators_md : ~[DIDescriptor] = - do enumerators.iter().transform |&(name,value)| { - do name.as_c_str |name| { unsafe { - llvm::LLVMDIBuilderCreateEnumerator( - DIB(cx), - name, - value as c_ulonglong) - }} - }.collect(); - - let loc = span_start(cx, span); - let file_metadata = get_or_create_file(cx, loc.file.name); - - return do enum_name.as_c_str |enum_name| { unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( - DIB(cx), - file_metadata, - enum_name, - file_metadata, - loc.line as c_uint, - bytes_to_bits(discriminator_size), - bytes_to_bits(discriminator_align), - create_DIArray(DIB(cx), enumerators_md), - discriminator_type_md) - }}; + return discriminant_type_md; } - cx.sess.bug(""); + let variants_md = do variants.map |&vi| { + + let raw_types : &[ty::t] = vi.args; + let arg_types = do raw_types.map |&raw_type| { ty::subst(cx.tcx, substs, raw_type) }; + let arg_llvm_types = ~[discriminant_llvm_type] + do arg_types.map |&ty| { type_of::type_of(cx, ty) }; + let arg_names = ~[~""] + arg_types.map(|_| ~""); + let arg_md = ~[discriminant_type_md] + do arg_types.map |&ty| { get_or_create_type(cx, ty, span) }; + + let variant_llvm_type = Type::struct_(arg_llvm_types, false); + let variant_type_size = machine::llsize_of_alloc(cx, variant_llvm_type); + let variant_type_align = machine::llalign_of_min(cx, variant_llvm_type); + + let variant_type_md = create_composite_type( + cx, + variant_llvm_type, + &"", + arg_llvm_types, + arg_names, + arg_md, + span); + + do "".as_c_str |name| { unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + file_metadata, + name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(variant_type_size), + bytes_to_bits(variant_type_align), + bytes_to_bits(0), + 0, + variant_type_md) + }} + }; + + let enum_llvm_type = type_of::type_of(cx, enum_type); + let enum_type_size = machine::llsize_of_alloc(cx, enum_llvm_type); + let enum_type_align = machine::llalign_of_min(cx, enum_llvm_type); + + return do "".as_c_str |enum_name| { unsafe { llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + create_DIArray(DIB(cx), variants_md), + 0) // RuntimeLang + }}; } - - /// Creates debug information for a composite type, that is, anything that results in a LLVM struct. /// /// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums. @@ -899,10 +955,8 @@ fn get_or_create_type(cx: &mut CrateContext, t: ty::t, span: span) -> DIType { } } }, - ty::ty_enum(def_id, ref _substs) => { - //cx.sess.span_note(span, "debuginfo for enum NYI"); - //create_unimpl_ty(cx, t) - create_enum_md(cx, t, def_id, span) + ty::ty_enum(def_id, ref substs) => { + create_enum_md(cx, t, def_id, substs, span) }, ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 27ba508293e..2a1f26bf441 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -565,8 +565,8 @@ extern "C" bool LLVMRustStartMultithreading() { typedef DIBuilder* DIBuilderRef; template -DIT unwrapDI(LLVMValueRef ref) { - return DIT(ref ? unwrap(ref) : NULL); +DIT unwrapDI(LLVMValueRef ref) { + return DIT(ref ? unwrap(ref) : NULL); } extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) { @@ -604,21 +604,21 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFile( extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType( DIBuilderRef Builder, - LLVMValueRef File, + LLVMValueRef File, LLVMValueRef ParameterTypes) { return wrap(Builder->createSubroutineType( - unwrapDI(File), + unwrapDI(File), unwrapDI(ParameterTypes))); } extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( DIBuilderRef Builder, - LLVMValueRef Scope, + LLVMValueRef Scope, const char* Name, const char* LinkageName, - LLVMValueRef File, + LLVMValueRef File, unsigned LineNo, - LLVMValueRef Ty, + LLVMValueRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, @@ -628,11 +628,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( LLVMValueRef TParam, LLVMValueRef Decl) { return wrap(Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, - unwrapDI(File), LineNo, - unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI(Scope), Name, LinkageName, + unwrapDI(File), LineNo, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, - unwrap(Fn), + unwrap(Fn), unwrapDI(TParam), unwrapDI(Decl))); } @@ -644,10 +644,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType( uint64_t AlignInBits, unsigned Encoding) { return wrap(Builder->createBasicType( - Name, SizeInBits, + Name, SizeInBits, AlignInBits, Encoding)); } - + extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType( DIBuilderRef Builder, LLVMValueRef PointeeTy, @@ -672,11 +672,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateStructType( unsigned RunTimeLang, LLVMValueRef VTableHolder) { return wrap(Builder->createStructType( - unwrapDI(Scope), Name, - unwrapDI(File), LineNumber, - SizeInBits, AlignInBits, Flags, - unwrapDI(DerivedFrom), - unwrapDI(Elements), RunTimeLang, + unwrapDI(Scope), Name, + unwrapDI(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI(DerivedFrom), + unwrapDI(Elements), RunTimeLang, unwrapDI(VTableHolder))); } @@ -692,12 +692,12 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( unsigned Flags, LLVMValueRef Ty) { return wrap(Builder->createMemberType( - unwrapDI(Scope), Name, + unwrapDI(Scope), Name, unwrapDI(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, Flags, + SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI(Ty))); } - + extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( DIBuilderRef Builder, LLVMValueRef Scope, @@ -705,10 +705,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock( - unwrapDI(Scope), + unwrapDI(Scope), unwrapDI(File), Line, Col)); } - + extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( DIBuilderRef Builder, unsigned Tag, @@ -720,45 +720,45 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( bool AlwaysPreserve, unsigned Flags, unsigned ArgNo) { - return wrap(Builder->createLocalVariable(Tag, - unwrapDI(Scope), Name, - unwrapDI(File), - LineNo, + return wrap(Builder->createLocalVariable(Tag, + unwrapDI(Scope), Name, + unwrapDI(File), + LineNo, unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); } extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType( DIBuilderRef Builder, - uint64_t Size, - uint64_t AlignInBits, - LLVMValueRef Ty, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, - unwrapDI(Ty), + unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType( DIBuilderRef Builder, - uint64_t Size, - uint64_t AlignInBits, - LLVMValueRef Ty, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, - unwrapDI(Ty), + unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange( - DIBuilderRef Builder, - int64_t Lo, + DIBuilderRef Builder, + int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray( DIBuilderRef Builder, - LLVMValueRef* Ptr, + LLVMValueRef* Ptr, unsigned Count) { return wrap(Builder->getOrCreateArray( ArrayRef(reinterpret_cast(Ptr), Count))); @@ -770,8 +770,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMValueRef VarInfo, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI(VarInfo), + unwrap(Val), + unwrapDI(VarInfo), unwrap(InsertAtEnd))); } @@ -781,8 +781,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMValueRef VarInfo, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI(VarInfo), + unwrap(Val), + unwrapDI(VarInfo), unwrap(InsertBefore))); } @@ -814,4 +814,28 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType( AlignInBits, unwrapDI(Elements), unwrapDI(ClassType))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Flags, + LLVMValueRef Elements, + unsigned RunTimeLang) +{ + return wrap(Builder->createUnionType( + unwrapDI(Scope), + Name, + unwrapDI(File), + LineNumber, + SizeInBits, + AlignInBits, + Flags, + unwrapDI(Elements), + RunTimeLang)); } \ No newline at end of file diff --git a/src/test/debug-info/c-style-enum.rs b/src/test/debug-info/c-style-enum.rs index 408e9810266..3071cb2d326 100644 --- a/src/test/debug-info/c-style-enum.rs +++ b/src/test/debug-info/c-style-enum.rs @@ -31,19 +31,25 @@ // debugger:print manual_one_million // check:$6 = OneMillion +// debugger:print single_variant +// check:$7 = TheOnlyVariant -enum AutoDiscriminator { +enum AutoDiscriminant { One, Two, Three } -enum ManualDiscriminator { +enum ManualDiscriminant { OneHundred = 100, OneThousand = 1000, OneMillion = 1000000 } +enum SingleVariant { + TheOnlyVariant +} + fn main() { let auto_one = One; @@ -54,6 +60,8 @@ fn main() { let manual_one_thousand = OneThousand; let manual_one_million = OneMillion; + let single_variant = TheOnlyVariant; + zzz(); } diff --git a/src/test/debug-info/nil-enum.rs b/src/test/debug-info/nil-enum.rs new file mode 100644 index 00000000000..09f41ee9f42 --- /dev/null +++ b/src/test/debug-info/nil-enum.rs @@ -0,0 +1,38 @@ +// Copyright 2013 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. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print first +// check:$1 = {} + +// debugger:print second +// check:$2 = {} + +enum ANilEnum {} +enum AnotherNilEnum {} + +// I (mw) am not sure this test case makes much sense... +// Also, it relies on some implementation details: +// 1. That empty enums as well as '()' are represented as empty structs +// 2. That gdb prints the string "{}" for empty structs (which may change some time) +fn main() { + unsafe { + let first : ANilEnum = std::cast::transmute(()); + let second : AnotherNilEnum = std::cast::transmute(()); + + zzz(); + } +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/tuple-style-enum.rs b/src/test/debug-info/tuple-style-enum.rs new file mode 100644 index 00000000000..00144aa1bb5 --- /dev/null +++ b/src/test/debug-info/tuple-style-enum.rs @@ -0,0 +1,33 @@ +// Copyright 2013 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. + +// compile-flags:-Z extra-debug-info +// debugger:set print union on +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print case2 +// check:$1 = {Case1, 0, 1} + +enum Test { + Case1(i32, i64), + Case2(bool, i16, i32) +} + +fn main() { + + let case1 = Case1(110, 220); + let case2 = Case2(false, 2, 3); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file