authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-10 11:21:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-10 11:21:41-05:00
log434f017aeefc392bcf524732940e2f2b908222f3
treeff7f935dbaca2093a88f4e1a1411c6699157952e
parentc78dc5043bb8f0fa3ff2fec876bcab4ee499972c

codegen nullable void the same way as bool

See #104

3 files changed, 70 insertions(+), 21 deletions(-)

src/analyze.cpp+11-3
...@@ -397,7 +397,10 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -397,7 +397,10 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
397 buf_resize(&entry->name, 0);397 buf_resize(&entry->name, 0);
398 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));398 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
399399
400 if (child_type->id == TypeTableEntryIdPointer ||400 if (child_type->zero_bits) {
401 entry->type_ref = LLVMInt1Type();
402 entry->di_type = g->builtin_types.entry_bool->di_type;
403 } else if (child_type->id == TypeTableEntryIdPointer ||
401 child_type->id == TypeTableEntryIdFn)404 child_type->id == TypeTableEntryIdFn)
402 {405 {
403 // this is an optimization but also is necessary for calling C406 // this is an optimization but also is necessary for calling C
...@@ -2958,7 +2961,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -2958,7 +2961,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
2958 assert(type_entry->data.enumeration.complete);2961 assert(type_entry->data.enumeration.complete);
2959 return type_entry->data.enumeration.gen_field_count != 0;2962 return type_entry->data.enumeration.gen_field_count != 0;
2960 case TypeTableEntryIdMaybe:2963 case TypeTableEntryIdMaybe:
2961 return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&2964 return !type_entry->data.maybe.child_type->zero_bits &&
2965 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
2962 type_entry->data.maybe.child_type->id != TypeTableEntryIdFn;2966 type_entry->data.maybe.child_type->id != TypeTableEntryIdFn;
2963 case TypeTableEntryIdTypeDecl:2967 case TypeTableEntryIdTypeDecl:
2964 return handle_is_ptr(type_entry->data.type_decl.canonical_type);2968 return handle_is_ptr(type_entry->data.type_decl.canonical_type);
...@@ -3632,7 +3636,11 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {...@@ -3632,7 +3636,11 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
3632 case TypeTableEntryIdNullLit:3636 case TypeTableEntryIdNullLit:
3633 zig_panic("TODO");3637 zig_panic("TODO");
3634 case TypeTableEntryIdMaybe:3638 case TypeTableEntryIdMaybe:
3635 zig_panic("TODO");3639 if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) {
3640 return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr);
3641 } else {
3642 return const_values_equal(a->data.x_maybe, b->data.x_maybe);
3643 }
3636 case TypeTableEntryIdErrorUnion:3644 case TypeTableEntryIdErrorUnion:
3637 zig_panic("TODO");3645 zig_panic("TODO");
3638 case TypeTableEntryIdTypeDecl:3646 case TypeTableEntryIdTypeDecl:
src/codegen.cpp+29-12
...@@ -1755,12 +1755,16 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru...@@ -1755,12 +1755,16 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
1755static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {1755static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
1756 assert(maybe_type->id == TypeTableEntryIdMaybe);1756 assert(maybe_type->id == TypeTableEntryIdMaybe);
1757 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;1757 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1758 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);1758 if (child_type->zero_bits) {
1759 if (maybe_is_ptr) {1759 return maybe_handle;
1760 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
1761 } else {1760 } else {
1762 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");1761 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1763 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");1762 if (maybe_is_ptr) {
1763 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
1764 } else {
1765 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
1766 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1767 }
1764 }1768 }
1765}1769}
17661770
...@@ -1779,7 +1783,6 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,...@@ -1779,7 +1783,6 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
1779 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;1783 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
1780 assert(maybe_type->id == TypeTableEntryIdMaybe);1784 assert(maybe_type->id == TypeTableEntryIdMaybe);
1781 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;1785 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1782 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1783 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);1786 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
1784 LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);1787 LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);
1785 if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {1788 if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
...@@ -1793,11 +1796,16 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,...@@ -1793,11 +1796,16 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
17931796
1794 LLVMPositionBuilderAtEnd(g->builder, ok_block);1797 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1795 }1798 }
1796 if (maybe_is_ptr) {1799 if (child_type->zero_bits) {
1797 return maybe_ptr;1800 return nullptr;
1798 } else {1801 } else {
1799 LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);1802 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1800 return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, "");1803 if (maybe_is_ptr) {
1804 return maybe_ptr;
1805 } else {
1806 LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, is_volatile);
1807 return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, "");
1808 }
1801 }1809 }
1802}1810}
18031811
...@@ -2319,6 +2327,10 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -2319,6 +2327,10 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
23192327
2320 TypeTableEntry *child_type = wanted_type->data.maybe.child_type;2328 TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
23212329
2330 if (child_type->zero_bits) {
2331 return LLVMConstInt(LLVMInt1Type(), 1, false);
2332 }
2333
2322 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);2334 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
2323 if (child_type->id == TypeTableEntryIdPointer ||2335 if (child_type->id == TypeTableEntryIdPointer ||
2324 child_type->id == TypeTableEntryIdFn)2336 child_type->id == TypeTableEntryIdFn)
...@@ -2806,7 +2818,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -2806,7 +2818,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
2806 case TypeTableEntryIdMaybe:2818 case TypeTableEntryIdMaybe:
2807 {2819 {
2808 TypeTableEntry *child_type = canon_type->data.maybe.child_type;2820 TypeTableEntry *child_type = canon_type->data.maybe.child_type;
2809 if (child_type->id == TypeTableEntryIdPointer ||2821 if (child_type->zero_bits) {
2822 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
2823 } else if (child_type->id == TypeTableEntryIdPointer ||
2810 child_type->id == TypeTableEntryIdFn)2824 child_type->id == TypeTableEntryIdFn)
2811 {2825 {
2812 if (const_val->data.x_maybe) {2826 if (const_val->data.x_maybe) {
...@@ -4322,7 +4336,10 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {...@@ -4322,7 +4336,10 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
4322 case TypeTableEntryIdMaybe:4336 case TypeTableEntryIdMaybe:
4323 {4337 {
4324 TypeTableEntry *child_type = type_entry->data.maybe.child_type;4338 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
4325 if (child_type->id == TypeTableEntryIdPointer ||4339 if (child_type->zero_bits) {
4340 buf_init_from_str(out_buf, "bool");
4341 return;
4342 } else if (child_type->id == TypeTableEntryIdPointer ||
4326 child_type->id == TypeTableEntryIdFn)4343 child_type->id == TypeTableEntryIdFn)
4327 {4344 {
4328 return get_c_type(g, child_type, out_buf);4345 return get_c_type(g, child_type, out_buf);
test/cases/null.zig+30-6
...@@ -51,11 +51,21 @@ fn rhsMaybeUnwrapReturn() {...@@ -51,11 +51,21 @@ fn rhsMaybeUnwrapReturn() {
51fn maybeReturn() {51fn maybeReturn() {
52 @setFnTest(this);52 @setFnTest(this);
5353
54 maybeReturnImpl();
55 comptime maybeReturnImpl();
56}
57
58fn maybeReturnImpl() {
54 assert(??foo(1235));59 assert(??foo(1235));
55 assert(if (const _ ?= foo(null)) false else true);60 assert(if (const _ ?= foo(null)) false else true);
56 assert(!??foo(1234));61 assert(!??foo(1234));
57}62}
5863
64fn foo(x: ?i32) -> ?bool {
65 const value = ?return x;
66 return value > 1234;
67}
68
5969
60fn ifVarMaybePointer() {70fn ifVarMaybePointer() {
61 @setFnTest(this);71 @setFnTest(this);
...@@ -97,12 +107,6 @@ const here_is_a_null_literal = SillyStruct {...@@ -97,12 +107,6 @@ const here_is_a_null_literal = SillyStruct {
97};107};
98108
99109
100// TODO test static eval maybe return
101fn foo(x: ?i32) -> ?bool {
102 const value = ?return x;
103 return value > 1234;
104}
105
106fn testNullRuntime() {110fn testNullRuntime() {
107 @setFnTest(this);111 @setFnTest(this);
108112
...@@ -112,3 +116,23 @@ fn testTestNullRuntime(x: ?i32) {...@@ -112,3 +116,23 @@ fn testTestNullRuntime(x: ?i32) {
112 assert(x == null);116 assert(x == null);
113 assert(!(x != null));117 assert(!(x != null));
114}118}
119
120fn nullableVoid() {
121 @setFnTest(this);
122
123 nullableVoidImpl();
124 comptime nullableVoidImpl();
125}
126
127fn nullableVoidImpl() {
128 assert(bar(null) == null);
129 assert(bar({}) != null);
130}
131
132fn bar(x: ?void) -> ?void {
133 if (const _ ?= x) {
134 return {};
135 } else {
136 return null;
137 }
138}