| author | |
| committer | |
| log | 7c53230a61568411e1375e1230df1ceaf1e462de |
| tree | 5a92be90eaaf6db480c95ba42e32a4f430fd1da7 |
| parent | 5c04730534ea7933855429c5fc5dc7b22eba7bc2 |
closes #10313 files changed, 115 insertions(+), 65 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -1037,6 +1037,7 @@ struct TypeTableEntry { |
| 1037 | 1037 | ZigLLVMDIType *di_type; |
| 1038 | 1038 | |
| 1039 | 1039 | bool zero_bits; |
| 1040 | bool is_copyable; | |
| 1040 | 1041 | |
| 1041 | 1042 | union { |
| 1042 | 1043 | TypeTableEntryPointer pointer; |
src/analyze.cpp+30| ... | ... | @@ -300,6 +300,18 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) { |
| 300 | 300 | return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref); |
| 301 | 301 | } |
| 302 | 302 | |
| 303 | static 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 | ||
| 303 | 315 | static bool is_slice(TypeTableEntry *type) { |
| 304 | 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 | 348 | type_ensure_zero_bits_known(g, child_type); |
| 337 | 349 | |
| 338 | 350 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); |
| 351 | entry->is_copyable = true; | |
| 339 | 352 | |
| 340 | 353 | const char *const_str = is_const ? "const " : ""; |
| 341 | 354 | const char *volatile_str = is_volatile ? "volatile " : ""; |
| ... | ... | @@ -392,6 +405,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 392 | 405 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe); |
| 393 | 406 | assert(child_type->type_ref); |
| 394 | 407 | assert(child_type->di_type); |
| 408 | entry->is_copyable = type_is_copyable(g, child_type); | |
| 395 | 409 | |
| 396 | 410 | buf_resize(&entry->name, 0); |
| 397 | 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 | 485 | return child_type->error_parent; |
| 472 | 486 | |
| 473 | 487 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); |
| 488 | entry->is_copyable = true; | |
| 474 | 489 | assert(child_type->type_ref); |
| 475 | 490 | assert(child_type->di_type); |
| 476 | 491 | ensure_complete_type(g, child_type); |
| ... | ... | @@ -557,6 +572,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t |
| 557 | 572 | |
| 558 | 573 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); |
| 559 | 574 | entry->zero_bits = (array_size == 0) || child_type->zero_bits; |
| 575 | entry->is_copyable = false; | |
| 560 | 576 | |
| 561 | 577 | buf_resize(&entry->name, 0); |
| 562 | 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 | 630 | } else if (is_const) { |
| 615 | 631 | TypeTableEntry *var_peer = get_slice_type(g, child_type, false); |
| 616 | 632 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); |
| 633 | entry->is_copyable = true; | |
| 617 | 634 | |
| 618 | 635 | buf_resize(&entry->name, 0); |
| 619 | 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 | 646 | return entry; |
| 630 | 647 | } else { |
| 631 | 648 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); |
| 649 | entry->is_copyable = true; | |
| 632 | 650 | |
| 633 | 651 | // If the child type is []const T then we need to make sure the type ref |
| 634 | 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 | 770 | |
| 753 | 771 | buf_init_from_str(&entry->name, name); |
| 754 | 772 | |
| 773 | entry->is_copyable = type_is_copyable(g, child_type); | |
| 755 | 774 | entry->type_ref = child_type->type_ref; |
| 756 | 775 | entry->di_type = child_type->di_type; |
| 757 | 776 | entry->zero_bits = child_type->zero_bits; |
| ... | ... | @@ -768,6 +787,7 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) { |
| 768 | 787 | return fn_type->data.fn.bound_fn_parent; |
| 769 | 788 | |
| 770 | 789 | TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn); |
| 790 | bound_fn_type->is_copyable = false; | |
| 771 | 791 | bound_fn_type->data.bound_fn.fn_type = fn_type; |
| 772 | 792 | bound_fn_type->zero_bits = true; |
| 773 | 793 | |
| ... | ... | @@ -786,6 +806,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 786 | 806 | ensure_complete_type(g, fn_type_id->return_type); |
| 787 | 807 | |
| 788 | 808 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); |
| 809 | fn_type->is_copyable = true; | |
| 789 | 810 | fn_type->data.fn.fn_type_id = *fn_type_id; |
| 790 | 811 | |
| 791 | 812 | if (fn_type_id->is_cold) { |
| ... | ... | @@ -972,6 +993,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { |
| 972 | 993 | |
| 973 | 994 | static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 974 | 995 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); |
| 996 | fn_type->is_copyable = false; | |
| 975 | 997 | buf_init_from_str(&fn_type->name, "fn("); |
| 976 | 998 | size_t i = 0; |
| 977 | 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 | 1100 | case TypeTableEntryIdFn: |
| 1079 | 1101 | case TypeTableEntryIdTypeDecl: |
| 1080 | 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 | 1109 | break; |
| 1082 | 1110 | } |
| 1083 | 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 | 1187 | buf_resize(&entry->name, 0); |
| 1160 | 1188 | buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name)); |
| 1161 | 1189 | |
| 1190 | entry->is_copyable = true; | |
| 1162 | 1191 | entry->data.enum_tag.enum_type = enum_type; |
| 1163 | 1192 | entry->data.enum_tag.int_type = int_type; |
| 1164 | 1193 | entry->type_ref = int_type->type_ref; |
| ... | ... | @@ -4007,6 +4036,7 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 4007 | 4036 | |
| 4008 | 4037 | TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) { |
| 4009 | 4038 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 4039 | entry->is_copyable = true; | |
| 4010 | 4040 | entry->type_ref = LLVMIntType(size_in_bits); |
| 4011 | 4041 | |
| 4012 | 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 | 261 | return addLLVMAttr(arg_val, param_index + 1, attr_name); |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | static 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 | ||
| 264 | 271 | static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) { |
| 265 | 272 | if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) { |
| 266 | 273 | return original_name; |
| ... | ... | @@ -1578,11 +1585,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 1578 | 1585 | fn_type = instruction->fn_ref->value.type; |
| 1579 | 1586 | } |
| 1580 | 1587 | |
| 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 | 1590 | bool ret_has_bits = type_has_bits(src_return_type); |
| 1583 | 1591 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); |
| 1584 | 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 | 1594 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); |
| 1587 | 1595 | size_t gen_param_index = 0; |
| 1588 | 1596 | if (first_arg_ret) { |
| ... | ... | @@ -1603,6 +1611,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 1603 | 1611 | LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, |
| 1604 | 1612 | gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); |
| 1605 | 1613 | |
| 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 | 1621 | if (src_return_type->id == TypeTableEntryIdUnreachable) { |
| 1607 | 1622 | return LLVMBuildUnreachable(g->builder); |
| 1608 | 1623 | } else if (!ret_has_bits) { |
| ... | ... | @@ -3376,7 +3391,7 @@ static void do_code_gen(CodeGen *g) { |
| 3376 | 3391 | addLLVMArgAttr(fn_val, gen_index, "nonnull"); |
| 3377 | 3392 | } |
| 3378 | 3393 | if (is_byval) { |
| 3379 | // TODO add byval attr? | |
| 3394 | addLLVMArgAttr(fn_val, gen_index, "byval"); | |
| 3380 | 3395 | } |
| 3381 | 3396 | } |
| 3382 | 3397 |
src/ir.cpp+1-1| ... | ... | @@ -9905,7 +9905,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 9905 | 9905 | case TypeTableEntryIdNumLitInt: |
| 9906 | 9906 | case TypeTableEntryIdBoundFn: |
| 9907 | 9907 | case TypeTableEntryIdMetaType: |
| 9908 | case TypeTableEntryIdFn: | |
| 9909 | 9908 | case TypeTableEntryIdNamespace: |
| 9910 | 9909 | case TypeTableEntryIdArgTuple: |
| 9911 | 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 | 9924 | case TypeTableEntryIdEnum: |
| 9926 | 9925 | case TypeTableEntryIdUnion: |
| 9927 | 9926 | case TypeTableEntryIdEnumTag: |
| 9927 | case TypeTableEntryIdFn: | |
| 9928 | 9928 | { |
| 9929 | 9929 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| 9930 | 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 | 34 | return l.items[0...l.len]; |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | pub fn append(l: &Self, item: T) -> %void { | |
| 37 | pub fn append(l: &Self, item: &const T) -> %void { | |
| 38 | 38 | const new_item_ptr = %return l.addOne(); |
| 39 | *new_item_ptr = item; | |
| 39 | *new_item_ptr = *item; | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | pub fn resize(l: &Self, new_len: usize) -> %void { |
test/cases/enum.zig+4-4| ... | ... | @@ -48,15 +48,15 @@ test "constantEnumWithPayload" { |
| 48 | 48 | shouldBeNotEmpty(full); |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | fn shouldBeEmpty(x: AnEnumWithPayload) { | |
| 52 | switch (x) { | |
| 51 | fn shouldBeEmpty(x: &const AnEnumWithPayload) { | |
| 52 | switch (*x) { | |
| 53 | 53 | AnEnumWithPayload.Empty => {}, |
| 54 | 54 | else => @unreachable(), |
| 55 | 55 | } |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | fn shouldBeNotEmpty(x: AnEnumWithPayload) { | |
| 59 | switch (x) { | |
| 58 | fn shouldBeNotEmpty(x: &const AnEnumWithPayload) { | |
| 59 | switch (*x) { | |
| 60 | 60 | AnEnumWithPayload.Empty => @unreachable(), |
| 61 | 61 | else => {}, |
| 62 | 62 | } |
test/cases/incomplete_struct_param_tld.zig created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 2 | ||
| 3 | const A = struct { | |
| 4 | b: B, | |
| 5 | }; | |
| 6 | ||
| 7 | const B = struct { | |
| 8 | c: C, | |
| 9 | }; | |
| 10 | ||
| 11 | const C = struct { | |
| 12 | x: i32, | |
| 13 | ||
| 14 | fn d(c: &const C) -> i32 { | |
| 15 | return c.x; | |
| 16 | } | |
| 17 | }; | |
| 18 | ||
| 19 | fn foo(a: &const A) -> i32 { | |
| 20 | return a.b.c.d(); | |
| 21 | } | |
| 22 | ||
| 23 | test "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 | 338 | }; |
| 339 | 339 | const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}}; |
| 340 | 340 | const test3_bar = Test3Foo.Two{13}; |
| 341 | fn test3_1(f: Test3Foo) { | |
| 342 | switch (f) { | |
| 341 | fn test3_1(f: &const Test3Foo) { | |
| 342 | switch (*f) { | |
| 343 | 343 | Test3Foo.Three => |pt| { |
| 344 | 344 | assert(pt.x == 3); |
| 345 | 345 | assert(pt.y == 4); |
| ... | ... | @@ -347,8 +347,8 @@ fn test3_1(f: Test3Foo) { |
| 347 | 347 | else => @unreachable(), |
| 348 | 348 | } |
| 349 | 349 | } |
| 350 | fn test3_2(f: Test3Foo) { | |
| 351 | switch (f) { | |
| 350 | fn test3_2(f: &const Test3Foo) { | |
| 351 | switch (*f) { | |
| 352 | 352 | Test3Foo.Two => |x| { |
| 353 | 353 | assert(x == 13); |
| 354 | 354 | }, |
test/cases/null.zig+2-2| ... | ... | @@ -62,8 +62,8 @@ fn foo(x: ?i32) -> ?bool { |
| 62 | 62 | test "ifVarMaybePointer" { |
| 63 | 63 | assert(shouldBeAPlus1(Particle {.a = 14, .b = 1, .c = 1, .d = 1}) == 15); |
| 64 | 64 | } |
| 65 | fn shouldBeAPlus1(p: Particle) -> u64 { | |
| 66 | var maybe_particle: ?Particle = p; | |
| 65 | fn shouldBeAPlus1(p: &const Particle) -> u64 { | |
| 66 | var maybe_particle: ?Particle = *p; | |
| 67 | 67 | if (const *particle ?= maybe_particle) { |
| 68 | 68 | particle.a += 1; |
| 69 | 69 | } |
test/cases/struct.zig+4-4| ... | ... | @@ -53,10 +53,10 @@ const StructFoo = struct { |
| 53 | 53 | b : bool, |
| 54 | 54 | c : f32, |
| 55 | 55 | }; |
| 56 | fn testFoo(foo : StructFoo) { | |
| 56 | fn testFoo(foo: &const StructFoo) { | |
| 57 | 57 | assert(foo.b); |
| 58 | 58 | } |
| 59 | fn testMutation(foo : &StructFoo) { | |
| 59 | fn testMutation(foo: &StructFoo) { | |
| 60 | 60 | foo.c = 100; |
| 61 | 61 | } |
| 62 | 62 | |
| ... | ... | @@ -110,7 +110,7 @@ const Foo = struct { |
| 110 | 110 | |
| 111 | 111 | fn aFunc() -> i32 { 13 } |
| 112 | 112 | |
| 113 | fn callStructField(foo: Foo) -> i32 { | |
| 113 | fn callStructField(foo: &const Foo) -> i32 { | |
| 114 | 114 | return foo.ptr(); |
| 115 | 115 | } |
| 116 | 116 | |
| ... | ... | @@ -123,7 +123,7 @@ test "storeMemberFunctionInVariable" { |
| 123 | 123 | } |
| 124 | 124 | const MemberFnTestFoo = struct { |
| 125 | 125 | x: i32, |
| 126 | fn member(foo: MemberFnTestFoo) -> i32 { foo.x } | |
| 126 | fn member(foo: &const MemberFnTestFoo) -> i32 { foo.x } | |
| 127 | 127 | }; |
| 128 | 128 | |
| 129 | 129 |
test/cases/switch.zig+2-2| ... | ... | @@ -92,8 +92,8 @@ const SwitchProngWithVarEnum = enum { |
| 92 | 92 | Two: f32, |
| 93 | 93 | Meh, |
| 94 | 94 | }; |
| 95 | fn switchProngWithVarFn(a: SwitchProngWithVarEnum) { | |
| 96 | switch(a) { | |
| 95 | fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) { | |
| 96 | switch(*a) { | |
| 97 | 97 | SwitchProngWithVarEnum.One => |x| { |
| 98 | 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 | 512 | )SOURCE", "3.25\n3\n3.00\n-0.40\n"); |
| 513 | 513 | |
| 514 | 514 | |
| 515 | add_simple_case("incomplete struct parameter top level decl", R"SOURCE( | |
| 516 | const io = @import("std").io; | |
| 517 | const A = struct { | |
| 518 | b: B, | |
| 519 | }; | |
| 520 | ||
| 521 | const B = struct { | |
| 522 | c: C, | |
| 523 | }; | |
| 524 | ||
| 525 | const C = struct { | |
| 526 | x: i32, | |
| 527 | ||
| 528 | fn d(c: &const C) { | |
| 529 | %%io.stdout.printf("OK\n"); | |
| 530 | } | |
| 531 | }; | |
| 532 | ||
| 533 | fn foo(a: A) { | |
| 534 | a.b.c.d(); | |
| 535 | } | |
| 536 | ||
| 537 | pub 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 | 515 | add_simple_case("same named methods in incomplete struct", R"SOURCE( |
| 552 | 516 | const io = @import("std").io; |
| 553 | 517 | |
| ... | ... | @@ -1037,9 +1001,10 @@ export fn entry() -> usize { @sizeOf(@typeOf(a)) } |
| 1037 | 1001 | )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'"); |
| 1038 | 1002 | |
| 1039 | 1003 | add_compile_fail_case("non compile time array concatenation", R"SOURCE( |
| 1040 | fn f(s: [10]u8) -> []u8 { | |
| 1004 | fn f() -> []u8 { | |
| 1041 | 1005 | s ++ "foo" |
| 1042 | 1006 | } |
| 1007 | var s: [10]u8 = undefined; | |
| 1043 | 1008 | export fn entry() -> usize { @sizeOf(@typeOf(f)) } |
| 1044 | 1009 | )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to evaluate constant expression"); |
| 1045 | 1010 | |
| ... | ... | @@ -1071,10 +1036,10 @@ const Foo = struct { |
| 1071 | 1036 | a: i32, |
| 1072 | 1037 | b: i32, |
| 1073 | 1038 | |
| 1074 | fn member_a(foo: Foo) -> i32 { | |
| 1039 | fn member_a(foo: &const Foo) -> i32 { | |
| 1075 | 1040 | return foo.a; |
| 1076 | 1041 | } |
| 1077 | fn member_b(foo: Foo) -> i32 { | |
| 1042 | fn member_b(foo: &const Foo) -> i32 { | |
| 1078 | 1043 | return foo.b; |
| 1079 | 1044 | } |
| 1080 | 1045 | }; |
| ... | ... | @@ -1085,7 +1050,7 @@ const members = []member_fn_type { |
| 1085 | 1050 | Foo.member_b, |
| 1086 | 1051 | }; |
| 1087 | 1052 | |
| 1088 | fn f(foo: Foo, index: usize) { | |
| 1053 | fn f(foo: &const Foo, index: usize) { | |
| 1089 | 1054 | const result = members[index](); |
| 1090 | 1055 | } |
| 1091 | 1056 | |
| ... | ... | @@ -1335,15 +1300,15 @@ const EnumWithData = enum { |
| 1335 | 1300 | One, |
| 1336 | 1301 | Two: i32, |
| 1337 | 1302 | }; |
| 1338 | fn bad_eql_2(a: EnumWithData, b: EnumWithData) -> bool { | |
| 1339 | a == b | |
| 1303 | fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { | |
| 1304 | *a == *b | |
| 1340 | 1305 | } |
| 1341 | 1306 | |
| 1342 | 1307 | export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } |
| 1343 | 1308 | export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } |
| 1344 | 1309 | )SOURCE", 2, |
| 1345 | 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'"); | |
| 1347 | 1312 | |
| 1348 | 1313 | add_compile_fail_case("non-const switch number literal", R"SOURCE( |
| 1349 | 1314 | export fn foo() { |
| ... | ... | @@ -1845,6 +1810,12 @@ export fn bar() {} |
| 1845 | 1810 | pub const baz = 1234; |
| 1846 | 1811 | )SOURCE"); |
| 1847 | 1812 | } |
| 1813 | ||
| 1814 | add_compile_fail_case("pass non-copyable type by value to function", R"SOURCE( | |
| 1815 | const Point = struct { x: i32, y: i32, }; | |
| 1816 | fn foo(p: Point) { } | |
| 1817 | export 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 | } |
| 1849 | 1820 | |
| 1850 | 1821 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+1| ... | ... | @@ -15,6 +15,7 @@ const test_generics = @import("cases/generics.zig"); |
| 15 | 15 | const test_goto = @import("cases/goto.zig"); |
| 16 | 16 | const test_if = @import("cases/if.zig"); |
| 17 | 17 | const test_import = @import("cases/import.zig"); |
| 18 | const test_incomplete_struct_param_tld = @import("cases/incomplete_struct_param_tld.zig"); | |
| 18 | 19 | const test_ir_block_deps = @import("cases/ir_block_deps.zig"); |
| 19 | 20 | const test_math = @import("cases/math.zig"); |
| 20 | 21 | const test_misc = @import("cases/misc.zig"); |