diff options
| author | Michael Woerister <michaelwoerister@gmail> | 2013-07-02 18:10:24 +0200 |
|---|---|---|
| committer | Michael Woerister <michaelwoerister@gmail> | 2013-07-19 07:55:24 +0200 |
| commit | f389bd8f2a72020c25e37b81757643abd481bc11 (patch) | |
| tree | 670ed90cdb00198a61b731b6e5a721985bf20511 | |
| parent | 739f3eece9c341f4f1e70b8a0417853ed2a09cbc (diff) | |
| download | rust-f389bd8f2a72020c25e37b81757643abd481bc11.tar.gz rust-f389bd8f2a72020c25e37b81757643abd481bc11.zip | |
debuginfo: Support for tuple-style enums (WIP)
| -rw-r--r-- | src/librustc/lib/llvm.rs | 16 | ||||
| -rw-r--r-- | src/librustc/middle/trans/debuginfo.rs | 144 | ||||
| -rw-r--r-- | src/rustllvm/RustWrapper.cpp | 108 | ||||
| -rw-r--r-- | src/test/debug-info/c-style-enum.rs | 12 | ||||
| -rw-r--r-- | src/test/debug-info/nil-enum.rs | 38 | ||||
| -rw-r--r-- | src/test/debug-info/tuple-style-enum.rs | 33 |
6 files changed, 261 insertions, 90 deletions
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,61 +548,117 @@ 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); } - if ty::type_is_c_like_enum(cx.tcx, enum_type) { + // 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 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 enumerators : ~[(~str, int)] = variants - .iter() - .transform(|v| (cx.sess.str_of(v.name).to_owned(), v.disr_val)) - .collect(); + let loc = span_start(cx, span); + let file_metadata = get_or_create_file(cx, loc.file.name); - 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 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) + }}; - let loc = span_start(cx, span); - let file_metadata = get_or_create_file(cx, loc.file.name); + if ty::type_is_c_like_enum(cx.tcx, enum_type) { + return discriminant_type_md; + } - return do enum_name.as_c_str |enum_name| { unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( + 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, - enum_name, + 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) - }}; - } - - cx.sess.bug(""); -} + 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. @@ -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<typename DIT> -DIT unwrapDI(LLVMValueRef ref) { - return DIT(ref ? unwrap<MDNode>(ref) : NULL); +DIT unwrapDI(LLVMValueRef ref) { + return DIT(ref ? unwrap<MDNode>(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<DIFile>(File), + unwrapDI<DIFile>(File), unwrapDI<DIArray>(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<DIScope>(Scope), Name, LinkageName, - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI<DIScope>(Scope), Name, LinkageName, + unwrapDI<DIFile>(File), LineNo, + unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, - unwrap<Function>(Fn), + unwrap<Function>(Fn), unwrapDI<MDNode*>(TParam), unwrapDI<MDNode*>(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<DIDescriptor>(Scope), Name, - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, Flags, - unwrapDI<DIType>(DerivedFrom), - unwrapDI<DIArray>(Elements), RunTimeLang, + unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIFile>(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI<DIType>(DerivedFrom), + unwrapDI<DIArray>(Elements), RunTimeLang, unwrapDI<MDNode*>(VTableHolder))); } @@ -692,12 +692,12 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( unsigned Flags, LLVMValueRef Ty) { return wrap(Builder->createMemberType( - unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, Flags, + SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI<DIType>(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<DIDescriptor>(Scope), + unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(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<DIDescriptor>(Scope), Name, - unwrapDI<DIFile>(File), - LineNo, + return wrap(Builder->createLocalVariable(Tag, + unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIFile>(File), + LineNo, unwrapDI<DIType>(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<DIType>(Ty), + unwrapDI<DIType>(Ty), unwrapDI<DIArray>(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<DIType>(Ty), + unwrapDI<DIType>(Ty), unwrapDI<DIArray>(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<Value*>(reinterpret_cast<Value**>(Ptr), Count))); @@ -770,8 +770,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMValueRef VarInfo, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI<DIVariable>(VarInfo), + unwrap(Val), + unwrapDI<DIVariable>(VarInfo), unwrap(InsertAtEnd))); } @@ -781,8 +781,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMValueRef VarInfo, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI<DIVariable>(VarInfo), + unwrap(Val), + unwrapDI<DIVariable>(VarInfo), unwrap<Instruction>(InsertBefore))); } @@ -814,4 +814,28 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType( AlignInBits, unwrapDI<DIArray>(Elements), unwrapDI<DIType>(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<DIDescriptor>(Scope), + Name, + unwrapDI<DIFile>(File), + LineNumber, + SizeInBits, + AlignInBits, + Flags, + unwrapDI<DIArray>(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 <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. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print first +// check:$1 = {<No data fields>} + +// debugger:print second +// check:$2 = {<No data fields>} + +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 "{<No data fields>}" 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 <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. + +// 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 |
