authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-26 03:39:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-26 03:39:18-04:00
log7c53230a61568411e1375e1230df1ceaf1e462de
tree5a92be90eaaf6db480c95ba42e32a4f430fd1da7
parent5c04730534ea7933855429c5fc5dc7b22eba7bc2

introduce copyable concept

closes #103

13 files changed, 115 insertions(+), 65 deletions(-)

src/all_types.hpp+1
...@@ -1037,6 +1037,7 @@ struct TypeTableEntry {...@@ -1037,6 +1037,7 @@ struct TypeTableEntry {
1037 ZigLLVMDIType *di_type;1037 ZigLLVMDIType *di_type;
10381038
1039 bool zero_bits;1039 bool zero_bits;
1040 bool is_copyable;
10401041
1041 union {1042 union {
1042 TypeTableEntryPointer pointer;1043 TypeTableEntryPointer pointer;
src/analyze.cpp+30
...@@ -300,6 +300,18 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {...@@ -300,6 +300,18 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
300 return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref);300 return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref);
301}301}
302302
303static bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry) {
304 type_ensure_zero_bits_known(g, type_entry);
305 if (!type_has_bits(type_entry))
306 return true;
307
308 if (!handle_is_ptr(type_entry))
309 return true;
310
311 ensure_complete_type(g, type_entry);
312 return type_entry->is_copyable;
313}
314
303static bool is_slice(TypeTableEntry *type) {315static bool is_slice(TypeTableEntry *type) {
304 return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;316 return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
305}317}
...@@ -336,6 +348,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type...@@ -336,6 +348,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
336 type_ensure_zero_bits_known(g, child_type);348 type_ensure_zero_bits_known(g, child_type);
337349
338 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);350 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
351 entry->is_copyable = true;
339352
340 const char *const_str = is_const ? "const " : "";353 const char *const_str = is_const ? "const " : "";
341 const char *volatile_str = is_volatile ? "volatile " : "";354 const char *volatile_str = is_volatile ? "volatile " : "";
...@@ -392,6 +405,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -392,6 +405,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
392 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);405 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
393 assert(child_type->type_ref);406 assert(child_type->type_ref);
394 assert(child_type->di_type);407 assert(child_type->di_type);
408 entry->is_copyable = type_is_copyable(g, child_type);
395409
396 buf_resize(&entry->name, 0);410 buf_resize(&entry->name, 0);
397 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));411 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
...@@ -471,6 +485,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -471,6 +485,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
471 return child_type->error_parent;485 return child_type->error_parent;
472486
473 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);487 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
488 entry->is_copyable = true;
474 assert(child_type->type_ref);489 assert(child_type->type_ref);
475 assert(child_type->di_type);490 assert(child_type->di_type);
476 ensure_complete_type(g, child_type);491 ensure_complete_type(g, child_type);
...@@ -557,6 +572,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t...@@ -557,6 +572,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
557572
558 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);573 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
559 entry->zero_bits = (array_size == 0) || child_type->zero_bits;574 entry->zero_bits = (array_size == 0) || child_type->zero_bits;
575 entry->is_copyable = false;
560576
561 buf_resize(&entry->name, 0);577 buf_resize(&entry->name, 0);
562 buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));578 buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
...@@ -614,6 +630,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c...@@ -614,6 +630,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
614 } else if (is_const) {630 } else if (is_const) {
615 TypeTableEntry *var_peer = get_slice_type(g, child_type, false);631 TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
616 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);632 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
633 entry->is_copyable = true;
617634
618 buf_resize(&entry->name, 0);635 buf_resize(&entry->name, 0);
619 buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));636 buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
...@@ -629,6 +646,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c...@@ -629,6 +646,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
629 return entry;646 return entry;
630 } else {647 } else {
631 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);648 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
649 entry->is_copyable = true;
632650
633 // If the child type is []const T then we need to make sure the type ref651 // If the child type is []const T then we need to make sure the type ref
634 // and debug info is the same as if the child type were []T.652 // and debug info is the same as if the child type were []T.
...@@ -752,6 +770,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *...@@ -752,6 +770,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
752770
753 buf_init_from_str(&entry->name, name);771 buf_init_from_str(&entry->name, name);
754772
773 entry->is_copyable = type_is_copyable(g, child_type);
755 entry->type_ref = child_type->type_ref;774 entry->type_ref = child_type->type_ref;
756 entry->di_type = child_type->di_type;775 entry->di_type = child_type->di_type;
757 entry->zero_bits = child_type->zero_bits;776 entry->zero_bits = child_type->zero_bits;
...@@ -768,6 +787,7 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {...@@ -768,6 +787,7 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {
768 return fn_type->data.fn.bound_fn_parent;787 return fn_type->data.fn.bound_fn_parent;
769788
770 TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn);789 TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn);
790 bound_fn_type->is_copyable = false;
771 bound_fn_type->data.bound_fn.fn_type = fn_type;791 bound_fn_type->data.bound_fn.fn_type = fn_type;
772 bound_fn_type->zero_bits = true;792 bound_fn_type->zero_bits = true;
773793
...@@ -786,6 +806,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -786,6 +806,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
786 ensure_complete_type(g, fn_type_id->return_type);806 ensure_complete_type(g, fn_type_id->return_type);
787807
788 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);808 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
809 fn_type->is_copyable = true;
789 fn_type->data.fn.fn_type_id = *fn_type_id;810 fn_type->data.fn.fn_type_id = *fn_type_id;
790811
791 if (fn_type_id->is_cold) {812 if (fn_type_id->is_cold) {
...@@ -972,6 +993,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {...@@ -972,6 +993,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
972993
973static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {994static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
974 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);995 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
996 fn_type->is_copyable = false;
975 buf_init_from_str(&fn_type->name, "fn(");997 buf_init_from_str(&fn_type->name, "fn(");
976 size_t i = 0;998 size_t i = 0;
977 for (; i < fn_type_id->next_param_index; i += 1) {999 for (; i < fn_type_id->next_param_index; i += 1) {
...@@ -1078,6 +1100,12 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1078,6 +1100,12 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1078 case TypeTableEntryIdFn:1100 case TypeTableEntryIdFn:
1079 case TypeTableEntryIdTypeDecl:1101 case TypeTableEntryIdTypeDecl:
1080 case TypeTableEntryIdEnumTag:1102 case TypeTableEntryIdEnumTag:
1103 ensure_complete_type(g, type_entry);
1104 if (!fn_type_id.is_extern && !type_is_copyable(g, type_entry)) {
1105 add_node_error(g, param_node->data.param_decl.type,
1106 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
1107 return g->builtin_types.entry_invalid;
1108 }
1081 break;1109 break;
1082 }1110 }
1083 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];1111 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
...@@ -1159,6 +1187,7 @@ static TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_typ...@@ -1159,6 +1187,7 @@ static TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_typ
1159 buf_resize(&entry->name, 0);1187 buf_resize(&entry->name, 0);
1160 buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name));1188 buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name));
11611189
1190 entry->is_copyable = true;
1162 entry->data.enum_tag.enum_type = enum_type;1191 entry->data.enum_tag.enum_type = enum_type;
1163 entry->data.enum_tag.int_type = int_type;1192 entry->data.enum_tag.int_type = int_type;
1164 entry->type_ref = int_type->type_ref;1193 entry->type_ref = int_type->type_ref;
...@@ -4007,6 +4036,7 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {...@@ -4007,6 +4036,7 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
40074036
4008TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) {4037TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) {
4009 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);4038 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
4039 entry->is_copyable = true;
4010 entry->type_ref = LLVMIntType(size_in_bits);4040 entry->type_ref = LLVMIntType(size_in_bits);
40114041
4012 const char u_or_i = is_signed ? 'i' : 'u';4042 const char u_or_i = is_signed ? 'i' : 'u';
src/codegen.cpp+18-3
...@@ -261,6 +261,13 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha...@@ -261,6 +261,13 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
261 return addLLVMAttr(arg_val, param_index + 1, attr_name);261 return addLLVMAttr(arg_val, param_index + 1, attr_name);
262}262}
263263
264static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
265 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
266 assert(kind_id != 0);
267 LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
268 LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
269}
270
264static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) {271static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) {
265 if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) {272 if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) {
266 return original_name;273 return original_name;
...@@ -1578,11 +1585,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -1578,11 +1585,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
1578 fn_type = instruction->fn_ref->value.type;1585 fn_type = instruction->fn_ref->value.type;
1579 }1586 }
15801587
1581 TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;1588 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
1589 TypeTableEntry *src_return_type = fn_type_id->return_type;
1582 bool ret_has_bits = type_has_bits(src_return_type);1590 bool ret_has_bits = type_has_bits(src_return_type);
1583 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);1591 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
1584 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);1592 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);
1585 bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;1593 bool is_var_args = fn_type_id->is_var_args;
1586 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);1594 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
1587 size_t gen_param_index = 0;1595 size_t gen_param_index = 0;
1588 if (first_arg_ret) {1596 if (first_arg_ret) {
...@@ -1603,6 +1611,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -1603,6 +1611,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
1603 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,1611 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
1604 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");1612 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
16051613
1614 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
1615 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
1616 if (gen_info->is_byval) {
1617 addLLVMCallsiteAttr(result, gen_info->gen_index, "byval");
1618 }
1619 }
1620
1606 if (src_return_type->id == TypeTableEntryIdUnreachable) {1621 if (src_return_type->id == TypeTableEntryIdUnreachable) {
1607 return LLVMBuildUnreachable(g->builder);1622 return LLVMBuildUnreachable(g->builder);
1608 } else if (!ret_has_bits) {1623 } else if (!ret_has_bits) {
...@@ -3376,7 +3391,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3376,7 +3391,7 @@ static void do_code_gen(CodeGen *g) {
3376 addLLVMArgAttr(fn_val, gen_index, "nonnull");3391 addLLVMArgAttr(fn_val, gen_index, "nonnull");
3377 }3392 }
3378 if (is_byval) {3393 if (is_byval) {
3379 // TODO add byval attr?3394 addLLVMArgAttr(fn_val, gen_index, "byval");
3380 }3395 }
3381 }3396 }
33823397
src/ir.cpp+1-1
...@@ -9905,7 +9905,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -9905,7 +9905,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
9905 case TypeTableEntryIdNumLitInt:9905 case TypeTableEntryIdNumLitInt:
9906 case TypeTableEntryIdBoundFn:9906 case TypeTableEntryIdBoundFn:
9907 case TypeTableEntryIdMetaType:9907 case TypeTableEntryIdMetaType:
9908 case TypeTableEntryIdFn:
9909 case TypeTableEntryIdNamespace:9908 case TypeTableEntryIdNamespace:
9910 case TypeTableEntryIdArgTuple:9909 case TypeTableEntryIdArgTuple:
9911 ir_add_error_node(ira, size_of_instruction->base.source_node,9910 ir_add_error_node(ira, size_of_instruction->base.source_node,
...@@ -9925,6 +9924,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -9925,6 +9924,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
9925 case TypeTableEntryIdEnum:9924 case TypeTableEntryIdEnum:
9926 case TypeTableEntryIdUnion:9925 case TypeTableEntryIdUnion:
9927 case TypeTableEntryIdEnumTag:9926 case TypeTableEntryIdEnumTag:
9927 case TypeTableEntryIdFn:
9928 {9928 {
9929 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);9929 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
9930 ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base);9930 ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base);
std/list.zig+2-2
...@@ -34,9 +34,9 @@ pub fn List(comptime T: type) -> type{...@@ -34,9 +34,9 @@ pub fn List(comptime T: type) -> type{
34 return l.items[0...l.len];34 return l.items[0...l.len];
35 }35 }
3636
37 pub fn append(l: &Self, item: T) -> %void {37 pub fn append(l: &Self, item: &const T) -> %void {
38 const new_item_ptr = %return l.addOne();38 const new_item_ptr = %return l.addOne();
39 *new_item_ptr = item;39 *new_item_ptr = *item;
40 }40 }
4141
42 pub fn resize(l: &Self, new_len: usize) -> %void {42 pub fn resize(l: &Self, new_len: usize) -> %void {
test/cases/enum.zig+4-4
...@@ -48,15 +48,15 @@ test "constantEnumWithPayload" {...@@ -48,15 +48,15 @@ test "constantEnumWithPayload" {
48 shouldBeNotEmpty(full);48 shouldBeNotEmpty(full);
49}49}
5050
51fn shouldBeEmpty(x: AnEnumWithPayload) {51fn shouldBeEmpty(x: &const AnEnumWithPayload) {
52 switch (x) {52 switch (*x) {
53 AnEnumWithPayload.Empty => {},53 AnEnumWithPayload.Empty => {},
54 else => @unreachable(),54 else => @unreachable(),
55 }55 }
56}56}
5757
58fn shouldBeNotEmpty(x: AnEnumWithPayload) {58fn shouldBeNotEmpty(x: &const AnEnumWithPayload) {
59 switch (x) {59 switch (*x) {
60 AnEnumWithPayload.Empty => @unreachable(),60 AnEnumWithPayload.Empty => @unreachable(),
61 else => {},61 else => {},
62 }62 }
test/cases/incomplete_struct_param_tld.zig created+32
...@@ -0,0 +1,32 @@
1const assert = @import("std").debug.assert;
2
3const A = struct {
4 b: B,
5};
6
7const B = struct {
8 c: C,
9};
10
11const C = struct {
12 x: i32,
13
14 fn d(c: &const C) -> i32 {
15 return c.x;
16 }
17};
18
19fn foo(a: &const A) -> i32 {
20 return a.b.c.d();
21}
22
23test "incomplete struct param top level declaration" {
24 const a = A {
25 .b = B {
26 .c = C {
27 .x = 13,
28 },
29 },
30 };
31 assert(foo(a) == 13);
32}
test/cases/misc.zig+4-4
...@@ -338,8 +338,8 @@ const Test3Point = struct {...@@ -338,8 +338,8 @@ const Test3Point = struct {
338};338};
339const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}};339const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}};
340const test3_bar = Test3Foo.Two{13};340const test3_bar = Test3Foo.Two{13};
341fn test3_1(f: Test3Foo) {341fn test3_1(f: &const Test3Foo) {
342 switch (f) {342 switch (*f) {
343 Test3Foo.Three => |pt| {343 Test3Foo.Three => |pt| {
344 assert(pt.x == 3);344 assert(pt.x == 3);
345 assert(pt.y == 4);345 assert(pt.y == 4);
...@@ -347,8 +347,8 @@ fn test3_1(f: Test3Foo) {...@@ -347,8 +347,8 @@ fn test3_1(f: Test3Foo) {
347 else => @unreachable(),347 else => @unreachable(),
348 }348 }
349}349}
350fn test3_2(f: Test3Foo) {350fn test3_2(f: &const Test3Foo) {
351 switch (f) {351 switch (*f) {
352 Test3Foo.Two => |x| {352 Test3Foo.Two => |x| {
353 assert(x == 13);353 assert(x == 13);
354 },354 },
test/cases/null.zig+2-2
...@@ -62,8 +62,8 @@ fn foo(x: ?i32) -> ?bool {...@@ -62,8 +62,8 @@ fn foo(x: ?i32) -> ?bool {
62test "ifVarMaybePointer" {62test "ifVarMaybePointer" {
63 assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);63 assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15);
64}64}
65fn shouldBeAPlus1(p: Particle) -> u64 {65fn shouldBeAPlus1(p: &const Particle) -> u64 {
66 var maybe_particle: ?Particle = p;66 var maybe_particle: ?Particle = *p;
67 if (const *particle ?= maybe_particle) {67 if (const *particle ?= maybe_particle) {
68 particle.a += 1;68 particle.a += 1;
69 }69 }
test/cases/struct.zig+4-4
...@@ -53,10 +53,10 @@ const StructFoo = struct {...@@ -53,10 +53,10 @@ const StructFoo = struct {
53 b : bool,53 b : bool,
54 c : f32,54 c : f32,
55};55};
56fn testFoo(foo : StructFoo) {56fn testFoo(foo: &const StructFoo) {
57 assert(foo.b);57 assert(foo.b);
58}58}
59fn testMutation(foo : &StructFoo) {59fn testMutation(foo: &StructFoo) {
60 foo.c = 100;60 foo.c = 100;
61}61}
6262
...@@ -110,7 +110,7 @@ const Foo = struct {...@@ -110,7 +110,7 @@ const Foo = struct {
110110
111fn aFunc() -> i32 { 13 }111fn aFunc() -> i32 { 13 }
112112
113fn callStructField(foo: Foo) -> i32 {113fn callStructField(foo: &const Foo) -> i32 {
114 return foo.ptr();114 return foo.ptr();
115}115}
116116
...@@ -123,7 +123,7 @@ test "storeMemberFunctionInVariable" {...@@ -123,7 +123,7 @@ test "storeMemberFunctionInVariable" {
123}123}
124const MemberFnTestFoo = struct {124const MemberFnTestFoo = struct {
125 x: i32,125 x: i32,
126 fn member(foo: MemberFnTestFoo) -> i32 { foo.x }126 fn member(foo: &const MemberFnTestFoo) -> i32 { foo.x }
127};127};
128128
129129
test/cases/switch.zig+2-2
...@@ -92,8 +92,8 @@ const SwitchProngWithVarEnum = enum {...@@ -92,8 +92,8 @@ const SwitchProngWithVarEnum = enum {
92 Two: f32,92 Two: f32,
93 Meh,93 Meh,
94};94};
95fn switchProngWithVarFn(a: SwitchProngWithVarEnum) {95fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) {
96 switch(a) {96 switch(*a) {
97 SwitchProngWithVarEnum.One => |x| {97 SwitchProngWithVarEnum.One => |x| {
98 if (x != 13) @unreachable();98 if (x != 13) @unreachable();
99 },99 },
test/run_tests.cpp+14-43
...@@ -512,42 +512,6 @@ export fn main(argc: c_int, argv: &&u8) -> c_int {...@@ -512,42 +512,6 @@ export fn main(argc: c_int, argv: &&u8) -> c_int {
512 )SOURCE", "3.25\n3\n3.00\n-0.40\n");512 )SOURCE", "3.25\n3\n3.00\n-0.40\n");
513513
514514
515 add_simple_case("incomplete struct parameter top level decl", R"SOURCE(
516const io = @import("std").io;
517const A = struct {
518 b: B,
519};
520
521const B = struct {
522 c: C,
523};
524
525const C = struct {
526 x: i32,
527
528 fn d(c: &const C) {
529 %%io.stdout.printf("OK\n");
530 }
531};
532
533fn foo(a: A) {
534 a.b.c.d();
535}
536
537pub fn main(args: [][]u8) -> %void {
538 const a = A {
539 .b = B {
540 .c = C {
541 .x = 13,
542 },
543 },
544 };
545 foo(a);
546}
547
548 )SOURCE", "OK\n");
549
550
551 add_simple_case("same named methods in incomplete struct", R"SOURCE(515 add_simple_case("same named methods in incomplete struct", R"SOURCE(
552const io = @import("std").io;516const io = @import("std").io;
553517
...@@ -1037,9 +1001,10 @@ export fn entry() -> usize { @sizeOf(@typeOf(a)) }...@@ -1037,9 +1001,10 @@ export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1037 )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'");1001 )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'");
10381002
1039 add_compile_fail_case("non compile time array concatenation", R"SOURCE(1003 add_compile_fail_case("non compile time array concatenation", R"SOURCE(
1040fn f(s: [10]u8) -> []u8 {1004fn f() -> []u8 {
1041 s ++ "foo"1005 s ++ "foo"
1042}1006}
1007var s: [10]u8 = undefined;
1043export fn entry() -> usize { @sizeOf(@typeOf(f)) }1008export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1044 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to evaluate constant expression");1009 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to evaluate constant expression");
10451010
...@@ -1071,10 +1036,10 @@ const Foo = struct {...@@ -1071,10 +1036,10 @@ const Foo = struct {
1071 a: i32,1036 a: i32,
1072 b: i32,1037 b: i32,
10731038
1074 fn member_a(foo: Foo) -> i32 {1039 fn member_a(foo: &const Foo) -> i32 {
1075 return foo.a;1040 return foo.a;
1076 }1041 }
1077 fn member_b(foo: Foo) -> i32 {1042 fn member_b(foo: &const Foo) -> i32 {
1078 return foo.b;1043 return foo.b;
1079 }1044 }
1080};1045};
...@@ -1085,7 +1050,7 @@ const members = []member_fn_type {...@@ -1085,7 +1050,7 @@ const members = []member_fn_type {
1085 Foo.member_b,1050 Foo.member_b,
1086};1051};
10871052
1088fn f(foo: Foo, index: usize) {1053fn f(foo: &const Foo, index: usize) {
1089 const result = members[index]();1054 const result = members[index]();
1090}1055}
10911056
...@@ -1335,15 +1300,15 @@ const EnumWithData = enum {...@@ -1335,15 +1300,15 @@ const EnumWithData = enum {
1335 One,1300 One,
1336 Two: i32,1301 Two: i32,
1337};1302};
1338fn bad_eql_2(a: EnumWithData, b: EnumWithData) -> bool {1303fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
1339 a == b1304 *a == *b
1340}1305}
13411306
1342export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }1307export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }
1343export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }1308export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }
1344 )SOURCE", 2,1309 )SOURCE", 2,
1345 ".tmp_source.zig:3:7: error: operator not allowed for type '[]u8'",1310 ".tmp_source.zig:3:7: error: operator not allowed for type '[]u8'",
1346 ".tmp_source.zig:10:7: error: operator not allowed for type 'EnumWithData'");1311 ".tmp_source.zig:10:8: error: operator not allowed for type 'EnumWithData'");
13471312
1348 add_compile_fail_case("non-const switch number literal", R"SOURCE(1313 add_compile_fail_case("non-const switch number literal", R"SOURCE(
1349export fn foo() {1314export fn foo() {
...@@ -1845,6 +1810,12 @@ export fn bar() {}...@@ -1845,6 +1810,12 @@ export fn bar() {}
1845pub const baz = 1234;1810pub const baz = 1234;
1846 )SOURCE");1811 )SOURCE");
1847 }1812 }
1813
1814 add_compile_fail_case("pass non-copyable type by value to function", R"SOURCE(
1815const Point = struct { x: i32, y: i32, };
1816fn foo(p: Point) { }
1817export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1818 )SOURCE", 1, ".tmp_source.zig:3:11: error: type 'Point' is not copyable; cannot pass by value");
1848}1819}
18491820
1850//////////////////////////////////////////////////////////////////////////////1821//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+1
...@@ -15,6 +15,7 @@ const test_generics = @import("cases/generics.zig");...@@ -15,6 +15,7 @@ const test_generics = @import("cases/generics.zig");
15const test_goto = @import("cases/goto.zig");15const test_goto = @import("cases/goto.zig");
16const test_if = @import("cases/if.zig");16const test_if = @import("cases/if.zig");
17const test_import = @import("cases/import.zig");17const test_import = @import("cases/import.zig");
18const test_incomplete_struct_param_tld = @import("cases/incomplete_struct_param_tld.zig");
18const test_ir_block_deps = @import("cases/ir_block_deps.zig");19const test_ir_block_deps = @import("cases/ir_block_deps.zig");
19const test_math = @import("cases/math.zig");20const test_math = @import("cases/math.zig");
20const test_misc = @import("cases/misc.zig");21const test_misc = @import("cases/misc.zig");