Commit 899fb14c30

Andrew Kelley <superjoe30@gmail.com>
2016-04-23 22:58:30
fix handling of slice of zero bits type
closes #143
1 parent 55b28ab
Changed files (3)
src/analyze.cpp
@@ -494,18 +494,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
         buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
         entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
 
-        TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
-
-        unsigned element_count = 2;
-        LLVMTypeRef element_types[] = {
-            pointer_type->type_ref,
-            g->builtin_types.entry_isize->type_ref,
-        };
-        LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
-
-        slice_type_common_init(g, child_type, is_const, entry);
-
-
         LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
         LLVMZigDIFile *di_file = nullptr;
         unsigned line = 0;
@@ -513,40 +501,90 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
             LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
             compile_unit_scope, di_file, line);
 
-        uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref);
-        uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref);
-        uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
-        TypeTableEntry *isize_type = g->builtin_types.entry_isize;
-        uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref);
-        uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref);
-        uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
-
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
-
-        LLVMZigDIType *di_element_types[] = {
-            LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                    "ptr", di_file, line,
-                    ptr_debug_size_in_bits,
-                    ptr_debug_align_in_bits,
-                    ptr_offset_in_bits,
-                    0, pointer_type->di_type),
-            LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                    "len", di_file, line,
-                    len_debug_size_in_bits,
-                    len_debug_align_in_bits,
-                    len_offset_in_bits,
-                    0, isize_type->di_type),
-        };
-        LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
-                compile_unit_scope,
-                buf_ptr(&entry->name),
-                di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
-                nullptr, di_element_types, 2, 0, nullptr, "");
-
-        LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
-        entry->di_type = replacement_di_type;
+        if (child_type->zero_bits) {
+            LLVMTypeRef element_types[] = {
+                g->builtin_types.entry_isize->type_ref,
+            };
+            LLVMStructSetBody(entry->type_ref, element_types, 1, false);
+
+            slice_type_common_init(g, child_type, is_const, entry);
+
+            entry->data.structure.gen_field_count = 1;
+            entry->data.structure.fields[0].gen_index = -1;
+            entry->data.structure.fields[1].gen_index = 0;
+
+            TypeTableEntry *isize_type = g->builtin_types.entry_isize;
+            uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref);
+            uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref);
+            uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
+
+            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
+
+            LLVMZigDIType *di_element_types[] = {
+                LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
+                        "len", di_file, line,
+                        len_debug_size_in_bits,
+                        len_debug_align_in_bits,
+                        len_offset_in_bits,
+                        0, isize_type->di_type),
+            };
+            LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
+                    compile_unit_scope,
+                    buf_ptr(&entry->name),
+                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+                    nullptr, di_element_types, 1, 0, nullptr, "");
+
+            LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
+            entry->di_type = replacement_di_type;
+        } else {
+            TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
+
+            unsigned element_count = 2;
+            LLVMTypeRef element_types[] = {
+                pointer_type->type_ref,
+                g->builtin_types.entry_isize->type_ref,
+            };
+            LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
+
+            slice_type_common_init(g, child_type, is_const, entry);
+
+
+            uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref);
+            uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref);
+            uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
+
+            TypeTableEntry *isize_type = g->builtin_types.entry_isize;
+            uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref);
+            uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref);
+            uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
+
+            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
+
+            LLVMZigDIType *di_element_types[] = {
+                LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
+                        "ptr", di_file, line,
+                        ptr_debug_size_in_bits,
+                        ptr_debug_align_in_bits,
+                        ptr_offset_in_bits,
+                        0, pointer_type->di_type),
+                LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
+                        "len", di_file, line,
+                        len_debug_size_in_bits,
+                        len_debug_align_in_bits,
+                        len_offset_in_bits,
+                        0, isize_type->di_type),
+            };
+            LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
+                    compile_unit_scope,
+                    buf_ptr(&entry->name),
+                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+                    nullptr, di_element_types, 2, 0, nullptr, "");
+
+            LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
+            entry->di_type = replacement_di_type;
+        }
 
 
         entry->data.structure.complete = true;
src/codegen.cpp
@@ -714,11 +714,15 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
 
                 add_debug_source_node(g, node);
 
-                LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
-                LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
-                LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
+                int ptr_index = wanted_type->data.structure.fields[0].gen_index;
+                if (ptr_index >= 0) {
+                    LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, ptr_index, "");
+                    LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
+                    LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
+                }
 
-                LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
+                int len_index = wanted_type->data.structure.fields[1].gen_index;
+                LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, len_index, "");
                 LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
                         actual_type->data.array.len, false);
                 LLVMBuildStore(g->builder, len_val, len_ptr);
@@ -884,7 +888,9 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal
         assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
 
         add_debug_source_node(g, source_node);
-        LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, "");
+        int ptr_index = array_type->data.structure.fields[0].gen_index;
+        assert(ptr_index >= 0);
+        LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
         LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
         return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
     } else {
@@ -1002,18 +1008,25 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
             end_val = gen_expr(g, node->data.slice_expr.end);
         } else {
             add_debug_source_node(g, node);
-            LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 1, "");
+            int len_index = array_type->data.structure.fields[1].gen_index;
+            assert(len_index >= 0);
+            LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
             end_val = LLVMBuildLoad(g->builder, src_len_ptr, "");
         }
 
+        int ptr_index = array_type->data.structure.fields[0].gen_index;
+        assert(ptr_index >= 0);
+        int len_index = array_type->data.structure.fields[1].gen_index;
+        assert(len_index >= 0);
+
         add_debug_source_node(g, node);
-        LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, "");
+        LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
         LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
-        LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
-        LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");
+        LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, "");
+        LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, "");
         LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
 
-        LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
+        LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, "");
         LLVMValueRef len_value = LLVMBuildSub(g->builder, end_val, start_val, "");
         LLVMBuildStore(g->builder, len_value, len_field_ptr);
 
@@ -2419,7 +2432,9 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
         TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
         assert(child_ptr_type->id == TypeTableEntryIdPointer);
         child_type = child_ptr_type->data.pointer.child_type;
-        LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, 1, "");
+        int len_index = array_type->data.structure.fields[1].gen_index;
+        assert(len_index >= 0);
+        LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, len_index, "");
         len_val = LLVMBuildLoad(g->builder, len_field_ptr, "");
     } else {
         zig_unreachable();
@@ -2537,14 +2552,19 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
                         LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
                                 size_val, "");
 
+                        int ptr_index = var_type->data.structure.fields[0].gen_index;
+                        assert(ptr_index >= 0);
+                        int len_index = var_type->data.structure.fields[1].gen_index;
+                        assert(len_index >= 0);
+
                         // store the freshly allocated pointer in the unknown size array struct
                         LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
-                                variable->value_ref, 0, "");
+                                variable->value_ref, ptr_index, "");
                         LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
 
                         // store the size in the len field
                         LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
-                                variable->value_ref, 1, "");
+                                variable->value_ref, len_index, "");
                         LLVMBuildStore(g->builder, size_val, len_field_ptr);
 
                         // don't clobber what we just did with debug initialization
test/self_hosted.zig
@@ -1314,3 +1314,11 @@ fn test_return_empty_struct_from_fn() -> EmptyStruct2 {
 fn test_return_empty_struct_from_fn_noeval() -> EmptyStruct2 {
     EmptyStruct2 {}
 }
+
+#attribute("test")
+fn pass_slice_of_empty_struct_to_fn() {
+    assert(test_pass_slice_of_empty_struct_to_fn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
+}
+fn test_pass_slice_of_empty_struct_to_fn(slice: []EmptyStruct2) -> isize {
+    slice.len
+}