]> git.lizzy.rs Git - rust.git/commitdiff
debuginfo: Support for tuple-style enums (WIP)
authorMichael Woerister <michaelwoerister@gmail>
Tue, 2 Jul 2013 16:10:24 +0000 (18:10 +0200)
committerMichael Woerister <michaelwoerister@gmail>
Fri, 19 Jul 2013 05:55:24 +0000 (07:55 +0200)
src/librustc/lib/llvm.rs
src/librustc/middle/trans/debuginfo.rs
src/rustllvm/RustWrapper.cpp
src/test/debug-info/c-style-enum.rs
src/test/debug-info/nil-enum.rs [new file with mode: 0644]
src/test/debug-info/tuple-style-enum.rs [new file with mode: 0644]

index bfa8d84d5b0b821ff568ed0aca27082cabc35dc2..1ce4108b3b55d87be4a769952e9b49df9f59c0e5 100644 (file)
@@ -2115,7 +2115,21 @@ pub unsafe fn LLVMDIBuilderCreateEnumerationType(
             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 {
index d3878e242f3d29ac695624ba2c3ec6f5534812f0..86bdf509d65831403461ff38e583bd89692af57b 100644 (file)
@@ -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) => {
index 27ba508293e947e48ff482119bfda14b19529e36..2a1f26bf441086903445fb6d32bd9aa64725049a 100644 (file)
@@ -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
index 408e98102663a5af93e0b08ad713b6cf036052b2..3071cb2d326c747da617db597aae9ca63aaf8dca 100644 (file)
 // 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 (file)
index 0000000..09f41ee
--- /dev/null
@@ -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 (file)
index 0000000..00144aa
--- /dev/null
@@ -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