| author | |
| committer | |
| log | aca9c74e80e106309b9783ff251ab0cdd3fb9626 |
| tree | 16c65995ac6d3b434af61c4cd61a191b81dd93a0 |
| parent | d93edadead45e447e6bc16c0934a3031a06d0fd8 |
| parent | 9bb1104e373dec192fb2a22d48b023330ddbaeae |
| signature |
implement defining C variadic functions26 files changed, 661 insertions(+), 26 deletions(-)
doc/langref.html.in+53-6| ... | @@ -8088,6 +8088,35 @@ test "main" { | ... | @@ -8088,6 +8088,35 @@ test "main" { |
| 8088 | {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} | 8088 | {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} |
| 8089 | {#header_close#} | 8089 | {#header_close#} |
| 8090 | 8090 | ||
| 8091 | {#header_open|@cVaArg#} | ||
| 8092 | <pre>{#syntax#}@cVaArg(operand: *std.builtin.VaList, comptime T: type) T{#endsyntax#}</pre> | ||
| 8093 | <p> | ||
| 8094 | Implements the C macro {#syntax#}va_arg{#endsyntax#}. | ||
| 8095 | </p> | ||
| 8096 | {#see_also|@cVaCopy|@cVaEnd|@cVaStart#} | ||
| 8097 | {#header_close#} | ||
| 8098 | {#header_open|@cVaCopy#} | ||
| 8099 | <pre>{#syntax#}@cVaCopy(src: *std.builtin.VaList) std.builtin.VaList{#endsyntax#}</pre> | ||
| 8100 | <p> | ||
| 8101 | Implements the C macro {#syntax#}va_copy{#endsyntax#}. | ||
| 8102 | </p> | ||
| 8103 | {#see_also|@cVaArg|@cVaEnd|@cVaStart#} | ||
| 8104 | {#header_close#} | ||
| 8105 | {#header_open|@cVaEnd#} | ||
| 8106 | <pre>{#syntax#}@cVaEnd(src: *std.builtin.VaList) void{#endsyntax#}</pre> | ||
| 8107 | <p> | ||
| 8108 | Implements the C macro {#syntax#}va_end{#endsyntax#}. | ||
| 8109 | </p> | ||
| 8110 | {#see_also|@cVaArg|@cVaCopy|@cVaStart#} | ||
| 8111 | {#header_close#} | ||
| 8112 | {#header_open|@cVaStart#} | ||
| 8113 | <pre>{#syntax#}@cVaStart() std.builtin.VaList{#endsyntax#}</pre> | ||
| 8114 | <p> | ||
| 8115 | Implements the C macro {#syntax#}va_start{#endsyntax#}. Only valid inside a variadic function. | ||
| 8116 | </p> | ||
| 8117 | {#see_also|@cVaArg|@cVaCopy|@cVaEnd#} | ||
| 8118 | {#header_close#} | ||
| 8119 | |||
| 8091 | {#header_open|@divExact#} | 8120 | {#header_open|@divExact#} |
| 8092 | <pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre> | 8121 | <pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| 8093 | <p> | 8122 | <p> |
| ... | @@ -10802,14 +10831,32 @@ test "variadic function" { | ... | @@ -10802,14 +10831,32 @@ test "variadic function" { |
| 10802 | } | 10831 | } |
| 10803 | {#code_end#} | 10832 | {#code_end#} |
| 10804 | <p> | 10833 | <p> |
| 10805 | Non extern variadic functions are currently not implemented, but there | 10834 | Variadic functions can be implemented using {#link|@cVaStart#}, {#link|@cVaEnd#}, {#link|@cVaArg#} and {#link|@cVaCopy#} |
| 10806 | is an accepted proposal. See <a href="https://github.com/ziglang/zig/issues/515">#515</a>. | ||
| 10807 | </p> | 10835 | </p> |
| 10808 | {#code_begin|obj_err|non-extern function is variadic#} | 10836 | {#code_begin|test|defining_variadic_function#} |
| 10809 | export fn printf(format: [*:0]const u8, ...) c_int { | 10837 | const std = @import("std"); |
| 10810 | _ = format; | 10838 | const testing = std.testing; |
| 10839 | const builtin = @import("builtin"); | ||
| 10811 | 10840 | ||
| 10812 | return 0; | 10841 | fn add(count: c_int, ...) callconv(.C) c_int { |
| 10842 | var ap = @cVaStart(); | ||
| 10843 | defer @cVaEnd(&ap); | ||
| 10844 | var i: usize = 0; | ||
| 10845 | var sum: c_int = 0; | ||
| 10846 | while (i < count) : (i += 1) { | ||
| 10847 | sum += @cVaArg(&ap, c_int); | ||
| 10848 | } | ||
| 10849 | return sum; | ||
| 10850 | } | ||
| 10851 | |||
| 10852 | test "defining a variadic function" { | ||
| 10853 | // Variadic functions are currently disabled on some targets due to miscompilations. | ||
| 10854 | if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .windows and builtin.os.tag != .macos) return error.SkipZigTest; | ||
| 10855 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; | ||
| 10856 | |||
| 10857 | try std.testing.expectEqual(@as(c_int, 0), add(0)); | ||
| 10858 | try std.testing.expectEqual(@as(c_int, 1), add(1, @as(c_int, 1))); | ||
| 10859 | try std.testing.expectEqual(@as(c_int, 3), add(2, @as(c_int, 1), @as(c_int, 2))); | ||
| 10813 | } | 10860 | } |
| 10814 | {#code_end#} | 10861 | {#code_end#} |
| 10815 | {#header_close#} | 10862 | {#header_close#} |
lib/std/builtin.zig+81| ... | @@ -620,6 +620,87 @@ pub const CallModifier = enum { | ... | @@ -620,6 +620,87 @@ pub const CallModifier = enum { |
| 620 | compile_time, | 620 | compile_time, |
| 621 | }; | 621 | }; |
| 622 | 622 | ||
| 623 | /// This data structure is used by the Zig language code generation and | ||
| 624 | /// therefore must be kept in sync with the compiler implementation. | ||
| 625 | pub const VaListAarch64 = extern struct { | ||
| 626 | __stack: *anyopaque, | ||
| 627 | __gr_top: *anyopaque, | ||
| 628 | __vr_top: *anyopaque, | ||
| 629 | __gr_offs: c_int, | ||
| 630 | __vr_offs: c_int, | ||
| 631 | }; | ||
| 632 | |||
| 633 | /// This data structure is used by the Zig language code generation and | ||
| 634 | /// therefore must be kept in sync with the compiler implementation. | ||
| 635 | pub const VaListHexagon = extern struct { | ||
| 636 | __gpr: c_long, | ||
| 637 | __fpr: c_long, | ||
| 638 | __overflow_arg_area: *anyopaque, | ||
| 639 | __reg_save_area: *anyopaque, | ||
| 640 | }; | ||
| 641 | |||
| 642 | /// This data structure is used by the Zig language code generation and | ||
| 643 | /// therefore must be kept in sync with the compiler implementation. | ||
| 644 | pub const VaListPowerPc = extern struct { | ||
| 645 | gpr: u8, | ||
| 646 | fpr: u8, | ||
| 647 | reserved: c_ushort, | ||
| 648 | overflow_arg_area: *anyopaque, | ||
| 649 | reg_save_area: *anyopaque, | ||
| 650 | }; | ||
| 651 | |||
| 652 | /// This data structure is used by the Zig language code generation and | ||
| 653 | /// therefore must be kept in sync with the compiler implementation. | ||
| 654 | pub const VaListS390x = extern struct { | ||
| 655 | __current_saved_reg_area_pointer: *anyopaque, | ||
| 656 | __saved_reg_area_end_pointer: *anyopaque, | ||
| 657 | __overflow_area_pointer: *anyopaque, | ||
| 658 | }; | ||
| 659 | |||
| 660 | /// This data structure is used by the Zig language code generation and | ||
| 661 | /// therefore must be kept in sync with the compiler implementation. | ||
| 662 | pub const VaListX86_64 = extern struct { | ||
| 663 | gp_offset: c_uint, | ||
| 664 | fp_offset: c_uint, | ||
| 665 | overflow_arg_area: *anyopaque, | ||
| 666 | reg_save_area: *anyopaque, | ||
| 667 | }; | ||
| 668 | |||
| 669 | /// This data structure is used by the Zig language code generation and | ||
| 670 | /// therefore must be kept in sync with the compiler implementation. | ||
| 671 | pub const VaList = switch (builtin.cpu.arch) { | ||
| 672 | .aarch64 => switch (builtin.os.tag) { | ||
| 673 | .windows => *u8, | ||
| 674 | .ios, .macos, .tvos, .watchos => *u8, | ||
| 675 | else => @compileError("disabled due to miscompilations"), // VaListAarch64, | ||
| 676 | }, | ||
| 677 | .arm => switch (builtin.os.tag) { | ||
| 678 | .ios, .macos, .tvos, .watchos => *u8, | ||
| 679 | else => *anyopaque, | ||
| 680 | }, | ||
| 681 | .amdgcn => *u8, | ||
| 682 | .avr => *anyopaque, | ||
| 683 | .bpfel, .bpfeb => *anyopaque, | ||
| 684 | .hexagon => if (builtin.target.isMusl()) VaListHexagon else *u8, | ||
| 685 | .mips, .mipsel, .mips64, .mips64el => *anyopaque, | ||
| 686 | .riscv32, .riscv64 => *anyopaque, | ||
| 687 | .powerpc, .powerpcle => switch (builtin.os.tag) { | ||
| 688 | .ios, .macos, .tvos, .watchos, .aix => *u8, | ||
| 689 | else => VaListPowerPc, | ||
| 690 | }, | ||
| 691 | .powerpc64, .powerpc64le => *u8, | ||
| 692 | .sparc, .sparcel, .sparc64 => *anyopaque, | ||
| 693 | .spirv32, .spirv64 => *anyopaque, | ||
| 694 | .s390x => VaListS390x, | ||
| 695 | .wasm32, .wasm64 => *anyopaque, | ||
| 696 | .x86 => *u8, | ||
| 697 | .x86_64 => switch (builtin.os.tag) { | ||
| 698 | .windows => @compileError("disabled due to miscompilations"), // *u8, | ||
| 699 | else => VaListX86_64, | ||
| 700 | }, | ||
| 701 | else => @compileError("VaList not supported for this target yet"), | ||
| 702 | }; | ||
| 703 | |||
| 623 | /// This data structure is used by the Zig language code generation and | 704 | /// This data structure is used by the Zig language code generation and |
| 624 | /// therefore must be kept in sync with the compiler implementation. | 705 | /// therefore must be kept in sync with the compiler implementation. |
| 625 | pub const PrefetchOptions = struct { | 706 | pub const PrefetchOptions = struct { |
src/Air.zig+17| ... | @@ -741,6 +741,19 @@ pub const Inst = struct { | ... | @@ -741,6 +741,19 @@ pub const Inst = struct { |
| 741 | /// Uses the `vector_store_elem` field. | 741 | /// Uses the `vector_store_elem` field. |
| 742 | vector_store_elem, | 742 | vector_store_elem, |
| 743 | 743 | ||
| 744 | /// Implements @cVaArg builtin. | ||
| 745 | /// Uses the `ty_op` field. | ||
| 746 | c_va_arg, | ||
| 747 | /// Implements @cVaCopy builtin. | ||
| 748 | /// Uses the `ty_op` field. | ||
| 749 | c_va_copy, | ||
| 750 | /// Implements @cVaEnd builtin. | ||
| 751 | /// Uses the `un_op` field. | ||
| 752 | c_va_end, | ||
| 753 | /// Implements @cVaStart builtin. | ||
| 754 | /// Uses the `ty` field. | ||
| 755 | c_va_start, | ||
| 756 | |||
| 744 | pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { | 757 | pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { |
| 745 | switch (op) { | 758 | switch (op) { |
| 746 | .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt, | 759 | .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt, |
| ... | @@ -1092,6 +1105,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1092,6 +1105,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1092 | .ret_ptr, | 1105 | .ret_ptr, |
| 1093 | .arg, | 1106 | .arg, |
| 1094 | .err_return_trace, | 1107 | .err_return_trace, |
| 1108 | .c_va_start, | ||
| 1095 | => return datas[inst].ty, | 1109 | => return datas[inst].ty, |
| 1096 | 1110 | ||
| 1097 | .assembly, | 1111 | .assembly, |
| ... | @@ -1156,6 +1170,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1156,6 +1170,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1156 | .byte_swap, | 1170 | .byte_swap, |
| 1157 | .bit_reverse, | 1171 | .bit_reverse, |
| 1158 | .addrspace_cast, | 1172 | .addrspace_cast, |
| 1173 | .c_va_arg, | ||
| 1174 | .c_va_copy, | ||
| 1159 | => return air.getRefType(datas[inst].ty_op.ty), | 1175 | => return air.getRefType(datas[inst].ty_op.ty), |
| 1160 | 1176 | ||
| 1161 | .loop, | 1177 | .loop, |
| ... | @@ -1187,6 +1203,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1187,6 +1203,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1187 | .prefetch, | 1203 | .prefetch, |
| 1188 | .set_err_return_trace, | 1204 | .set_err_return_trace, |
| 1189 | .vector_store_elem, | 1205 | .vector_store_elem, |
| 1206 | .c_va_end, | ||
| 1190 | => return Type.void, | 1207 | => return Type.void, |
| 1191 | 1208 | ||
| 1192 | .ptrtoint, | 1209 | .ptrtoint, |
src/AstGen.zig+47-6| ... | @@ -42,6 +42,7 @@ string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.d | ... | @@ -42,6 +42,7 @@ string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.d |
| 42 | compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, | 42 | compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, |
| 43 | /// The topmost block of the current function. | 43 | /// The topmost block of the current function. |
| 44 | fn_block: ?*GenZir = null, | 44 | fn_block: ?*GenZir = null, |
| 45 | fn_var_args: bool = false, | ||
| 45 | /// Maps string table indexes to the first `@import` ZIR instruction | 46 | /// Maps string table indexes to the first `@import` ZIR instruction |
| 46 | /// that uses this string as the operand. | 47 | /// that uses this string as the operand. |
| 47 | imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, | 48 | imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, |
| ... | @@ -3892,10 +3893,6 @@ fn fnDecl( | ... | @@ -3892,10 +3893,6 @@ fn fnDecl( |
| 3892 | .noalias_bits = noalias_bits, | 3893 | .noalias_bits = noalias_bits, |
| 3893 | }); | 3894 | }); |
| 3894 | } else func: { | 3895 | } else func: { |
| 3895 | if (is_var_args) { | ||
| 3896 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); | ||
| 3897 | } | ||
| 3898 | |||
| 3899 | // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz | 3896 | // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz |
| 3900 | fn_gz.instructions_top = ret_gz.instructions.items.len; | 3897 | fn_gz.instructions_top = ret_gz.instructions.items.len; |
| 3901 | 3898 | ||
| ... | @@ -3903,6 +3900,10 @@ fn fnDecl( | ... | @@ -3903,6 +3900,10 @@ fn fnDecl( |
| 3903 | astgen.fn_block = &fn_gz; | 3900 | astgen.fn_block = &fn_gz; |
| 3904 | defer astgen.fn_block = prev_fn_block; | 3901 | defer astgen.fn_block = prev_fn_block; |
| 3905 | 3902 | ||
| 3903 | const prev_var_args = astgen.fn_var_args; | ||
| 3904 | astgen.fn_var_args = is_var_args; | ||
| 3905 | defer astgen.fn_var_args = prev_var_args; | ||
| 3906 | |||
| 3906 | astgen.advanceSourceCursorToNode(body_node); | 3907 | astgen.advanceSourceCursorToNode(body_node); |
| 3907 | const lbrace_line = astgen.source_line - decl_gz.decl_line; | 3908 | const lbrace_line = astgen.source_line - decl_gz.decl_line; |
| 3908 | const lbrace_column = astgen.source_column; | 3909 | const lbrace_column = astgen.source_column; |
| ... | @@ -6071,7 +6072,7 @@ fn whileExpr( | ... | @@ -6071,7 +6072,7 @@ fn whileExpr( |
| 6071 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; | 6072 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; |
| 6072 | break :c .{ | 6073 | break :c .{ |
| 6073 | .inst = err_union, | 6074 | .inst = err_union, |
| 6074 | .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.then_expr), | 6075 | .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.cond_expr), |
| 6075 | }; | 6076 | }; |
| 6076 | } else if (while_full.payload_token) |_| { | 6077 | } else if (while_full.payload_token) |_| { |
| 6077 | const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; | 6078 | const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; |
| ... | @@ -6079,7 +6080,7 @@ fn whileExpr( | ... | @@ -6079,7 +6080,7 @@ fn whileExpr( |
| 6079 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; | 6080 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; |
| 6080 | break :c .{ | 6081 | break :c .{ |
| 6081 | .inst = optional, | 6082 | .inst = optional, |
| 6082 | .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.then_expr), | 6083 | .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.cond_expr), |
| 6083 | }; | 6084 | }; |
| 6084 | } else { | 6085 | } else { |
| 6085 | const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr); | 6086 | const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr); |
| ... | @@ -8384,6 +8385,46 @@ fn builtinCall( | ... | @@ -8384,6 +8385,46 @@ fn builtinCall( |
| 8384 | }); | 8385 | }); |
| 8385 | return rvalue(gz, ri, result, node); | 8386 | return rvalue(gz, ri, result, node); |
| 8386 | }, | 8387 | }, |
| 8388 | .c_va_arg => { | ||
| 8389 | if (astgen.fn_block == null) { | ||
| 8390 | return astgen.failNode(node, "'@cVaArg' outside function scope", .{}); | ||
| 8391 | } | ||
| 8392 | const result = try gz.addExtendedPayload(.c_va_arg, Zir.Inst.BinNode{ | ||
| 8393 | .node = gz.nodeIndexToRelative(node), | ||
| 8394 | .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), | ||
| 8395 | .rhs = try typeExpr(gz, scope, params[1]), | ||
| 8396 | }); | ||
| 8397 | return rvalue(gz, ri, result, node); | ||
| 8398 | }, | ||
| 8399 | .c_va_copy => { | ||
| 8400 | if (astgen.fn_block == null) { | ||
| 8401 | return astgen.failNode(node, "'@cVaCopy' outside function scope", .{}); | ||
| 8402 | } | ||
| 8403 | const result = try gz.addExtendedPayload(.c_va_copy, Zir.Inst.UnNode{ | ||
| 8404 | .node = gz.nodeIndexToRelative(node), | ||
| 8405 | .operand = try expr(gz, scope, .{ .rl = .none }, params[0]), | ||
| 8406 | }); | ||
| 8407 | return rvalue(gz, ri, result, node); | ||
| 8408 | }, | ||
| 8409 | .c_va_end => { | ||
| 8410 | if (astgen.fn_block == null) { | ||
| 8411 | return astgen.failNode(node, "'@cVaEnd' outside function scope", .{}); | ||
| 8412 | } | ||
| 8413 | const result = try gz.addExtendedPayload(.c_va_end, Zir.Inst.UnNode{ | ||
| 8414 | .node = gz.nodeIndexToRelative(node), | ||
| 8415 | .operand = try expr(gz, scope, .{ .rl = .none }, params[0]), | ||
| 8416 | }); | ||
| 8417 | return rvalue(gz, ri, result, node); | ||
| 8418 | }, | ||
| 8419 | .c_va_start => { | ||
| 8420 | if (astgen.fn_block == null) { | ||
| 8421 | return astgen.failNode(node, "'@cVaStart' outside function scope", .{}); | ||
| 8422 | } | ||
| 8423 | if (!astgen.fn_var_args) { | ||
| 8424 | return astgen.failNode(node, "'@cVaStart' in a non-variadic function", .{}); | ||
| 8425 | } | ||
| 8426 | return rvalue(gz, ri, try gz.addNodeExtended(.c_va_start, node), node); | ||
| 8427 | }, | ||
| 8387 | } | 8428 | } |
| 8388 | } | 8429 | } |
| 8389 | 8430 |
src/BuiltinFn.zig+28| ... | @@ -30,6 +30,10 @@ pub const Tag = enum { | ... | @@ -30,6 +30,10 @@ pub const Tag = enum { |
| 30 | compile_log, | 30 | compile_log, |
| 31 | ctz, | 31 | ctz, |
| 32 | c_undef, | 32 | c_undef, |
| 33 | c_va_arg, | ||
| 34 | c_va_copy, | ||
| 35 | c_va_end, | ||
| 36 | c_va_start, | ||
| 33 | div_exact, | 37 | div_exact, |
| 34 | div_floor, | 38 | div_floor, |
| 35 | div_trunc, | 39 | div_trunc, |
| ... | @@ -354,6 +358,30 @@ pub const list = list: { | ... | @@ -354,6 +358,30 @@ pub const list = list: { |
| 354 | .param_count = 1, | 358 | .param_count = 1, |
| 355 | }, | 359 | }, |
| 356 | }, | 360 | }, |
| 361 | .{ | ||
| 362 | "@cVaArg", .{ | ||
| 363 | .tag = .c_va_arg, | ||
| 364 | .param_count = 2, | ||
| 365 | }, | ||
| 366 | }, | ||
| 367 | .{ | ||
| 368 | "@cVaCopy", .{ | ||
| 369 | .tag = .c_va_copy, | ||
| 370 | .param_count = 1, | ||
| 371 | }, | ||
| 372 | }, | ||
| 373 | .{ | ||
| 374 | "@cVaEnd", .{ | ||
| 375 | .tag = .c_va_end, | ||
| 376 | .param_count = 1, | ||
| 377 | }, | ||
| 378 | }, | ||
| 379 | .{ | ||
| 380 | "@cVaStart", .{ | ||
| 381 | .tag = .c_va_start, | ||
| 382 | .param_count = 0, | ||
| 383 | }, | ||
| 384 | }, | ||
| 357 | .{ | 385 | .{ |
| 358 | "@divExact", | 386 | "@divExact", |
| 359 | .{ | 387 | .{ |
src/Liveness.zig+8| ... | @@ -238,6 +238,7 @@ pub fn categorizeOperand( | ... | @@ -238,6 +238,7 @@ pub fn categorizeOperand( |
| 238 | .wasm_memory_size, | 238 | .wasm_memory_size, |
| 239 | .err_return_trace, | 239 | .err_return_trace, |
| 240 | .save_err_return_trace_index, | 240 | .save_err_return_trace_index, |
| 241 | .c_va_start, | ||
| 241 | => return .none, | 242 | => return .none, |
| 242 | 243 | ||
| 243 | .fence => return .write, | 244 | .fence => return .write, |
| ... | @@ -279,6 +280,8 @@ pub fn categorizeOperand( | ... | @@ -279,6 +280,8 @@ pub fn categorizeOperand( |
| 279 | .splat, | 280 | .splat, |
| 280 | .error_set_has_value, | 281 | .error_set_has_value, |
| 281 | .addrspace_cast, | 282 | .addrspace_cast, |
| 283 | .c_va_arg, | ||
| 284 | .c_va_copy, | ||
| 282 | => { | 285 | => { |
| 283 | const o = air_datas[inst].ty_op; | 286 | const o = air_datas[inst].ty_op; |
| 284 | if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); | 287 | if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| ... | @@ -322,6 +325,7 @@ pub fn categorizeOperand( | ... | @@ -322,6 +325,7 @@ pub fn categorizeOperand( |
| 322 | .trunc_float, | 325 | .trunc_float, |
| 323 | .neg, | 326 | .neg, |
| 324 | .cmp_lt_errors_len, | 327 | .cmp_lt_errors_len, |
| 328 | .c_va_end, | ||
| 325 | => { | 329 | => { |
| 326 | const o = air_datas[inst].un_op; | 330 | const o = air_datas[inst].un_op; |
| 327 | if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); | 331 | if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| ... | @@ -857,6 +861,7 @@ fn analyzeInst( | ... | @@ -857,6 +861,7 @@ fn analyzeInst( |
| 857 | .wasm_memory_size, | 861 | .wasm_memory_size, |
| 858 | .err_return_trace, | 862 | .err_return_trace, |
| 859 | .save_err_return_trace_index, | 863 | .save_err_return_trace_index, |
| 864 | .c_va_start, | ||
| 860 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), | 865 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 861 | 866 | ||
| 862 | .not, | 867 | .not, |
| ... | @@ -898,6 +903,8 @@ fn analyzeInst( | ... | @@ -898,6 +903,8 @@ fn analyzeInst( |
| 898 | .splat, | 903 | .splat, |
| 899 | .error_set_has_value, | 904 | .error_set_has_value, |
| 900 | .addrspace_cast, | 905 | .addrspace_cast, |
| 906 | .c_va_arg, | ||
| 907 | .c_va_copy, | ||
| 901 | => { | 908 | => { |
| 902 | const o = inst_datas[inst].ty_op; | 909 | const o = inst_datas[inst].ty_op; |
| 903 | return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none }); | 910 | return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none }); |
| ... | @@ -936,6 +943,7 @@ fn analyzeInst( | ... | @@ -936,6 +943,7 @@ fn analyzeInst( |
| 936 | .neg_optimized, | 943 | .neg_optimized, |
| 937 | .cmp_lt_errors_len, | 944 | .cmp_lt_errors_len, |
| 938 | .set_err_return_trace, | 945 | .set_err_return_trace, |
| 946 | .c_va_end, | ||
| 939 | => { | 947 | => { |
| 940 | const operand = inst_datas[inst].un_op; | 948 | const operand = inst_datas[inst].un_op; |
| 941 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); | 949 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
src/Sema.zig+119-1| ... | @@ -1148,6 +1148,10 @@ fn analyzeBodyInner( | ... | @@ -1148,6 +1148,10 @@ fn analyzeBodyInner( |
| 1148 | .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), | 1148 | .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), |
| 1149 | .cmpxchg => try sema.zirCmpxchg( block, extended), | 1149 | .cmpxchg => try sema.zirCmpxchg( block, extended), |
| 1150 | .addrspace_cast => try sema.zirAddrSpaceCast( block, extended), | 1150 | .addrspace_cast => try sema.zirAddrSpaceCast( block, extended), |
| 1151 | .c_va_arg => try sema.zirCVaArg( block, extended), | ||
| 1152 | .c_va_copy => try sema.zirCVaCopy( block, extended), | ||
| 1153 | .c_va_end => try sema.zirCVaEnd( block, extended), | ||
| 1154 | .c_va_start => try sema.zirCVaStart( block, extended), | ||
| 1151 | // zig fmt: on | 1155 | // zig fmt: on |
| 1152 | 1156 | ||
| 1153 | .fence => { | 1157 | .fence => { |
| ... | @@ -6426,6 +6430,11 @@ fn analyzeCall( | ... | @@ -6426,6 +6430,11 @@ fn analyzeCall( |
| 6426 | else => unreachable, | 6430 | else => unreachable, |
| 6427 | }; | 6431 | }; |
| 6428 | if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail; | 6432 | if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail; |
| 6433 | if (func_ty_info.is_var_args) { | ||
| 6434 | return sema.fail(block, call_src, "{s} call of variadic function", .{ | ||
| 6435 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | ||
| 6436 | }); | ||
| 6437 | } | ||
| 6429 | 6438 | ||
| 6430 | // Analyze the ZIR. The same ZIR gets analyzed into a runtime function | 6439 | // Analyze the ZIR. The same ZIR gets analyzed into a runtime function |
| 6431 | // or an inlined call depending on what union tag the `label` field is | 6440 | // or an inlined call depending on what union tag the `label` field is |
| ... | @@ -8407,6 +8416,7 @@ fn funcCommon( | ... | @@ -8407,6 +8416,7 @@ fn funcCommon( |
| 8407 | ) CompileError!Air.Inst.Ref { | 8416 | ) CompileError!Air.Inst.Ref { |
| 8408 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; | 8417 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| 8409 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; | 8418 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; |
| 8419 | const func_src = LazySrcLoc.nodeOffset(src_node_offset); | ||
| 8410 | 8420 | ||
| 8411 | var is_generic = bare_return_type.tag() == .generic_poison or | 8421 | var is_generic = bare_return_type.tag() == .generic_poison or |
| 8412 | alignment == null or | 8422 | alignment == null or |
| ... | @@ -8414,6 +8424,15 @@ fn funcCommon( | ... | @@ -8414,6 +8424,15 @@ fn funcCommon( |
| 8414 | section == .generic or | 8424 | section == .generic or |
| 8415 | cc == null; | 8425 | cc == null; |
| 8416 | 8426 | ||
| 8427 | if (var_args) { | ||
| 8428 | if (is_generic) { | ||
| 8429 | return sema.fail(block, func_src, "generic function cannot be variadic", .{}); | ||
| 8430 | } | ||
| 8431 | if (cc.? != .C) { | ||
| 8432 | return sema.fail(block, cc_src, "variadic function must have 'C' calling convention", .{}); | ||
| 8433 | } | ||
| 8434 | } | ||
| 8435 | |||
| 8417 | var destroy_fn_on_error = false; | 8436 | var destroy_fn_on_error = false; |
| 8418 | const new_func: *Module.Fn = new_func: { | 8437 | const new_func: *Module.Fn = new_func: { |
| 8419 | if (!has_body) break :new_func undefined; | 8438 | if (!has_body) break :new_func undefined; |
| ... | @@ -16353,6 +16372,15 @@ fn finishCondBr( | ... | @@ -16353,6 +16372,15 @@ fn finishCondBr( |
| 16353 | return Air.indexToRef(block_inst); | 16372 | return Air.indexToRef(block_inst); |
| 16354 | } | 16373 | } |
| 16355 | 16374 | ||
| 16375 | fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | ||
| 16376 | switch (ty.zigTypeTag()) { | ||
| 16377 | .Optional, .Null, .Undefined => return, | ||
| 16378 | .Pointer => if (ty.isPtrLikeOptional()) return, | ||
| 16379 | else => {}, | ||
| 16380 | } | ||
| 16381 | return sema.failWithExpectedOptionalType(block, src, ty); | ||
| 16382 | } | ||
| 16383 | |||
| 16356 | fn zirIsNonNull( | 16384 | fn zirIsNonNull( |
| 16357 | sema: *Sema, | 16385 | sema: *Sema, |
| 16358 | block: *Block, | 16386 | block: *Block, |
| ... | @@ -16364,6 +16392,7 @@ fn zirIsNonNull( | ... | @@ -16364,6 +16392,7 @@ fn zirIsNonNull( |
| 16364 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 16392 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16365 | const src = inst_data.src(); | 16393 | const src = inst_data.src(); |
| 16366 | const operand = try sema.resolveInst(inst_data.operand); | 16394 | const operand = try sema.resolveInst(inst_data.operand); |
| 16395 | try sema.checkNullableType(block, src, sema.typeOf(operand)); | ||
| 16367 | return sema.analyzeIsNull(block, src, operand, true); | 16396 | return sema.analyzeIsNull(block, src, operand, true); |
| 16368 | } | 16397 | } |
| 16369 | 16398 | ||
| ... | @@ -16378,6 +16407,7 @@ fn zirIsNonNullPtr( | ... | @@ -16378,6 +16407,7 @@ fn zirIsNonNullPtr( |
| 16378 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 16407 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16379 | const src = inst_data.src(); | 16408 | const src = inst_data.src(); |
| 16380 | const ptr = try sema.resolveInst(inst_data.operand); | 16409 | const ptr = try sema.resolveInst(inst_data.operand); |
| 16410 | try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2()); | ||
| 16381 | if ((try sema.resolveMaybeUndefVal(ptr)) == null) { | 16411 | if ((try sema.resolveMaybeUndefVal(ptr)) == null) { |
| 16382 | return block.addUnOp(.is_non_null_ptr, ptr); | 16412 | return block.addUnOp(.is_non_null_ptr, ptr); |
| 16383 | } | 16413 | } |
| ... | @@ -16385,12 +16415,23 @@ fn zirIsNonNullPtr( | ... | @@ -16385,12 +16415,23 @@ fn zirIsNonNullPtr( |
| 16385 | return sema.analyzeIsNull(block, src, loaded, true); | 16415 | return sema.analyzeIsNull(block, src, loaded, true); |
| 16386 | } | 16416 | } |
| 16387 | 16417 | ||
| 16418 | fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | ||
| 16419 | switch (ty.zigTypeTag()) { | ||
| 16420 | .ErrorSet, .ErrorUnion, .Undefined => return, | ||
| 16421 | else => return sema.fail(block, src, "expected error union type, found '{}'", .{ | ||
| 16422 | ty.fmt(sema.mod), | ||
| 16423 | }), | ||
| 16424 | } | ||
| 16425 | } | ||
| 16426 | |||
| 16388 | fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 16427 | fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 16389 | const tracy = trace(@src()); | 16428 | const tracy = trace(@src()); |
| 16390 | defer tracy.end(); | 16429 | defer tracy.end(); |
| 16391 | 16430 | ||
| 16392 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 16431 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16432 | const src = inst_data.src(); | ||
| 16393 | const operand = try sema.resolveInst(inst_data.operand); | 16433 | const operand = try sema.resolveInst(inst_data.operand); |
| 16434 | try sema.checkErrorType(block, src, sema.typeOf(operand)); | ||
| 16394 | return sema.analyzeIsNonErr(block, inst_data.src(), operand); | 16435 | return sema.analyzeIsNonErr(block, inst_data.src(), operand); |
| 16395 | } | 16436 | } |
| 16396 | 16437 | ||
| ... | @@ -16401,6 +16442,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -16401,6 +16442,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 16401 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 16442 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16402 | const src = inst_data.src(); | 16443 | const src = inst_data.src(); |
| 16403 | const ptr = try sema.resolveInst(inst_data.operand); | 16444 | const ptr = try sema.resolveInst(inst_data.operand); |
| 16445 | try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2()); | ||
| 16404 | const loaded = try sema.analyzeLoad(block, src, ptr, src); | 16446 | const loaded = try sema.analyzeLoad(block, src, ptr, src); |
| 16405 | return sema.analyzeIsNonErr(block, src, loaded); | 16447 | return sema.analyzeIsNonErr(block, src, loaded); |
| 16406 | } | 16448 | } |
| ... | @@ -19020,6 +19062,79 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst | ... | @@ -19020,6 +19062,79 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 19020 | }); | 19062 | }); |
| 19021 | } | 19063 | } |
| 19022 | 19064 | ||
| 19065 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { | ||
| 19066 | const va_list_ty = try sema.getBuiltinType("VaList"); | ||
| 19067 | const va_list_ptr = try Type.ptr(sema.arena, sema.mod, .{ | ||
| 19068 | .pointee_type = va_list_ty, | ||
| 19069 | .mutable = true, | ||
| 19070 | .@"addrspace" = .generic, | ||
| 19071 | }); | ||
| 19072 | |||
| 19073 | const inst = try sema.resolveInst(zir_ref); | ||
| 19074 | return sema.coerce(block, va_list_ptr, inst, src); | ||
| 19075 | } | ||
| 19076 | |||
| 19077 | fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | ||
| 19078 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | ||
| 19079 | const src = LazySrcLoc.nodeOffset(extra.node); | ||
| 19080 | const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | ||
| 19081 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | ||
| 19082 | |||
| 19083 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs); | ||
| 19084 | const arg_ty = try sema.resolveType(block, ty_src, extra.rhs); | ||
| 19085 | |||
| 19086 | if (!try sema.validateExternType(arg_ty, .param_ty)) { | ||
| 19087 | const msg = msg: { | ||
| 19088 | const msg = try sema.errMsg(block, ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.mod)}); | ||
| 19089 | errdefer msg.destroy(sema.gpa); | ||
| 19090 | |||
| 19091 | const src_decl = sema.mod.declPtr(block.src_decl); | ||
| 19092 | try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl), arg_ty, .param_ty); | ||
| 19093 | |||
| 19094 | try sema.addDeclaredHereNote(msg, arg_ty); | ||
| 19095 | break :msg msg; | ||
| 19096 | }; | ||
| 19097 | return sema.failWithOwnedErrorMsg(msg); | ||
| 19098 | } | ||
| 19099 | |||
| 19100 | try sema.requireRuntimeBlock(block, src, null); | ||
| 19101 | return block.addTyOp(.c_va_arg, arg_ty, va_list_ref); | ||
| 19102 | } | ||
| 19103 | |||
| 19104 | fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | ||
| 19105 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | ||
| 19106 | const src = LazySrcLoc.nodeOffset(extra.node); | ||
| 19107 | const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | ||
| 19108 | |||
| 19109 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); | ||
| 19110 | const va_list_ty = try sema.getBuiltinType("VaList"); | ||
| 19111 | |||
| 19112 | try sema.requireRuntimeBlock(block, src, null); | ||
| 19113 | return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref); | ||
| 19114 | } | ||
| 19115 | |||
| 19116 | fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | ||
| 19117 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | ||
| 19118 | const src = LazySrcLoc.nodeOffset(extra.node); | ||
| 19119 | const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | ||
| 19120 | |||
| 19121 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); | ||
| 19122 | |||
| 19123 | try sema.requireRuntimeBlock(block, src, null); | ||
| 19124 | return block.addUnOp(.c_va_end, va_list_ref); | ||
| 19125 | } | ||
| 19126 | |||
| 19127 | fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | ||
| 19128 | const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); | ||
| 19129 | |||
| 19130 | const va_list_ty = try sema.getBuiltinType("VaList"); | ||
| 19131 | try sema.requireRuntimeBlock(block, src, null); | ||
| 19132 | return block.addInst(.{ | ||
| 19133 | .tag = .c_va_start, | ||
| 19134 | .data = .{ .ty = va_list_ty }, | ||
| 19135 | }); | ||
| 19136 | } | ||
| 19137 | |||
| 19023 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 19138 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 19024 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 19139 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 19025 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 19140 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -21524,7 +21639,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -21524,7 +21639,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21524 | else => |e| return e, | 21639 | else => |e| return e, |
| 21525 | }; | 21640 | }; |
| 21526 | break :blk cc_tv.val.toEnum(std.builtin.CallingConvention); | 21641 | break :blk cc_tv.val.toEnum(std.builtin.CallingConvention); |
| 21527 | } else std.builtin.CallingConvention.Unspecified; | 21642 | } else if (sema.owner_decl.is_exported and has_body) |
| 21643 | .C | ||
| 21644 | else | ||
| 21645 | .Unspecified; | ||
| 21528 | 21646 | ||
| 21529 | const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { | 21647 | const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { |
| 21530 | const body_len = sema.code.extra[extra_index]; | 21648 | const body_len = sema.code.extra[extra_index]; |
src/Zir.zig+12| ... | @@ -1993,6 +1993,18 @@ pub const Inst = struct { | ... | @@ -1993,6 +1993,18 @@ pub const Inst = struct { |
| 1993 | /// Implement the builtin `@addrSpaceCast` | 1993 | /// Implement the builtin `@addrSpaceCast` |
| 1994 | /// `Operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand. | 1994 | /// `Operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand. |
| 1995 | addrspace_cast, | 1995 | addrspace_cast, |
| 1996 | /// Implement builtin `@cVaArg`. | ||
| 1997 | /// `operand` is payload index to `BinNode`. | ||
| 1998 | c_va_arg, | ||
| 1999 | /// Implement builtin `@cVaStart`. | ||
| 2000 | /// `operand` is payload index to `UnNode`. | ||
| 2001 | c_va_copy, | ||
| 2002 | /// Implement builtin `@cVaStart`. | ||
| 2003 | /// `operand` is payload index to `UnNode`. | ||
| 2004 | c_va_end, | ||
| 2005 | /// Implement builtin `@cVaStart`. | ||
| 2006 | /// `operand` is `src_node: i32`. | ||
| 2007 | c_va_start, | ||
| 1996 | 2008 | ||
| 1997 | pub const InstData = struct { | 2009 | pub const InstData = struct { |
| 1998 | opcode: Extended, | 2010 | opcode: Extended, |
src/arch/aarch64/CodeGen.zig+5| ... | @@ -875,6 +875,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -875,6 +875,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 875 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | 875 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 876 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), | 876 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 877 | 877 | ||
| 878 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), | ||
| 879 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), | ||
| 880 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), | ||
| 881 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), | ||
| 882 | |||
| 878 | .wasm_memory_size => unreachable, | 883 | .wasm_memory_size => unreachable, |
| 879 | .wasm_memory_grow => unreachable, | 884 | .wasm_memory_grow => unreachable, |
| 880 | // zig fmt: on | 885 | // zig fmt: on |
src/arch/arm/CodeGen.zig+5| ... | @@ -785,6 +785,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -785,6 +785,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 785 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | 785 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 786 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), | 786 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 787 | 787 | ||
| 788 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), | ||
| 789 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), | ||
| 790 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), | ||
| 791 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), | ||
| 792 | |||
| 788 | .wasm_memory_size => unreachable, | 793 | .wasm_memory_size => unreachable, |
| 789 | .wasm_memory_grow => unreachable, | 794 | .wasm_memory_grow => unreachable, |
| 790 | // zig fmt: on | 795 | // zig fmt: on |
src/arch/riscv64/CodeGen.zig+5| ... | @@ -699,6 +699,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -699,6 +699,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 699 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | 699 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 700 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), | 700 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 701 | 701 | ||
| 702 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), | ||
| 703 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), | ||
| 704 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), | ||
| 705 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), | ||
| 706 | |||
| 702 | .wasm_memory_size => unreachable, | 707 | .wasm_memory_size => unreachable, |
| 703 | .wasm_memory_grow => unreachable, | 708 | .wasm_memory_grow => unreachable, |
| 704 | // zig fmt: on | 709 | // zig fmt: on |
src/arch/sparc64/CodeGen.zig+5| ... | @@ -716,6 +716,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -716,6 +716,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 716 | .error_set_has_value => @panic("TODO implement error_set_has_value"), | 716 | .error_set_has_value => @panic("TODO implement error_set_has_value"), |
| 717 | .vector_store_elem => @panic("TODO implement vector_store_elem"), | 717 | .vector_store_elem => @panic("TODO implement vector_store_elem"), |
| 718 | 718 | ||
| 719 | .c_va_arg => @panic("TODO implement c_va_arg"), | ||
| 720 | .c_va_copy => @panic("TODO implement c_va_copy"), | ||
| 721 | .c_va_end => @panic("TODO implement c_va_end"), | ||
| 722 | .c_va_start => @panic("TODO implement c_va_start"), | ||
| 723 | |||
| 719 | .wasm_memory_size => unreachable, | 724 | .wasm_memory_size => unreachable, |
| 720 | .wasm_memory_grow => unreachable, | 725 | .wasm_memory_grow => unreachable, |
| 721 | // zig fmt: on | 726 | // zig fmt: on |
src/arch/wasm/CodeGen.zig+4| ... | @@ -1972,6 +1972,10 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1972,6 +1972,10 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1972 | .error_set_has_value, | 1972 | .error_set_has_value, |
| 1973 | .addrspace_cast, | 1973 | .addrspace_cast, |
| 1974 | .vector_store_elem, | 1974 | .vector_store_elem, |
| 1975 | .c_va_arg, | ||
| 1976 | .c_va_copy, | ||
| 1977 | .c_va_end, | ||
| 1978 | .c_va_start, | ||
| 1975 | => |tag| return func.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), | 1979 | => |tag| return func.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1976 | 1980 | ||
| 1977 | .add_optimized, | 1981 | .add_optimized, |
src/arch/x86_64/CodeGen.zig+5| ... | @@ -787,6 +787,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -787,6 +787,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 787 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | 787 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), |
| 788 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), | 788 | .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), |
| 789 | 789 | ||
| 790 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), | ||
| 791 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), | ||
| 792 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), | ||
| 793 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), | ||
| 794 | |||
| 790 | .wasm_memory_size => unreachable, | 795 | .wasm_memory_size => unreachable, |
| 791 | .wasm_memory_grow => unreachable, | 796 | .wasm_memory_grow => unreachable, |
| 792 | // zig fmt: on | 797 | // zig fmt: on |
src/codegen/c.zig+5| ... | @@ -2909,6 +2909,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2909,6 +2909,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2909 | .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), | 2909 | .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), |
| 2910 | .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), | 2910 | .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), |
| 2911 | .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), | 2911 | .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), |
| 2912 | |||
| 2913 | .c_va_arg => return f.fail("TODO implement c_va_arg", .{}), | ||
| 2914 | .c_va_copy => return f.fail("TODO implement c_va_copy", .{}), | ||
| 2915 | .c_va_end => return f.fail("TODO implement c_va_end", .{}), | ||
| 2916 | .c_va_start => return f.fail("TODO implement c_va_start", .{}), | ||
| 2912 | // zig fmt: on | 2917 | // zig fmt: on |
| 2913 | }; | 2918 | }; |
| 2914 | if (result_value == .local) { | 2919 | if (result_value == .local) { |
src/codegen/llvm.zig+93| ... | @@ -4699,6 +4699,11 @@ pub const FuncGen = struct { | ... | @@ -4699,6 +4699,11 @@ pub const FuncGen = struct { |
| 4699 | .dbg_block_end => try self.airDbgBlockEnd(), | 4699 | .dbg_block_end => try self.airDbgBlockEnd(), |
| 4700 | .dbg_var_ptr => try self.airDbgVarPtr(inst), | 4700 | .dbg_var_ptr => try self.airDbgVarPtr(inst), |
| 4701 | .dbg_var_val => try self.airDbgVarVal(inst), | 4701 | .dbg_var_val => try self.airDbgVarVal(inst), |
| 4702 | |||
| 4703 | .c_va_arg => try self.airCVaArg(inst), | ||
| 4704 | .c_va_copy => try self.airCVaCopy(inst), | ||
| 4705 | .c_va_end => try self.airCVaEnd(inst), | ||
| 4706 | .c_va_start => try self.airCVaStart(inst), | ||
| 4702 | // zig fmt: on | 4707 | // zig fmt: on |
| 4703 | }; | 4708 | }; |
| 4704 | if (opt_value) |val| { | 4709 | if (opt_value) |val| { |
| ... | @@ -5136,6 +5141,94 @@ pub const FuncGen = struct { | ... | @@ -5136,6 +5141,94 @@ pub const FuncGen = struct { |
| 5136 | return null; | 5141 | return null; |
| 5137 | } | 5142 | } |
| 5138 | 5143 | ||
| 5144 | fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | ||
| 5145 | if (self.liveness.isUnused(inst)) return null; | ||
| 5146 | |||
| 5147 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 5148 | const list = try self.resolveInst(ty_op.operand); | ||
| 5149 | const arg_ty = self.air.getRefType(ty_op.ty); | ||
| 5150 | const llvm_arg_ty = try self.dg.lowerType(arg_ty); | ||
| 5151 | |||
| 5152 | return self.builder.buildVAArg(list, llvm_arg_ty, ""); | ||
| 5153 | } | ||
| 5154 | |||
| 5155 | fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | ||
| 5156 | if (self.liveness.isUnused(inst)) return null; | ||
| 5157 | |||
| 5158 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 5159 | const src_list = try self.resolveInst(ty_op.operand); | ||
| 5160 | const va_list_ty = self.air.getRefType(ty_op.ty); | ||
| 5161 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); | ||
| 5162 | |||
| 5163 | const target = self.dg.module.getTarget(); | ||
| 5164 | const result_alignment = va_list_ty.abiAlignment(target); | ||
| 5165 | const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment); | ||
| 5166 | |||
| 5167 | const llvm_fn_name = "llvm.va_copy"; | ||
| 5168 | const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { | ||
| 5169 | const param_types = [_]*llvm.Type{ | ||
| 5170 | self.dg.context.intType(8).pointerType(0), | ||
| 5171 | self.dg.context.intType(8).pointerType(0), | ||
| 5172 | }; | ||
| 5173 | const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False); | ||
| 5174 | break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | ||
| 5175 | }; | ||
| 5176 | |||
| 5177 | const args: [2]*llvm.Value = .{ dest_list, src_list }; | ||
| 5178 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); | ||
| 5179 | |||
| 5180 | if (isByRef(va_list_ty)) { | ||
| 5181 | return dest_list; | ||
| 5182 | } else { | ||
| 5183 | const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, ""); | ||
| 5184 | loaded.setAlignment(result_alignment); | ||
| 5185 | return loaded; | ||
| 5186 | } | ||
| 5187 | } | ||
| 5188 | |||
| 5189 | fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | ||
| 5190 | const un_op = self.air.instructions.items(.data)[inst].un_op; | ||
| 5191 | const list = try self.resolveInst(un_op); | ||
| 5192 | |||
| 5193 | const llvm_fn_name = "llvm.va_end"; | ||
| 5194 | const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { | ||
| 5195 | const param_types = [_]*llvm.Type{self.dg.context.intType(8).pointerType(0)}; | ||
| 5196 | const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False); | ||
| 5197 | break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | ||
| 5198 | }; | ||
| 5199 | const args: [1]*llvm.Value = .{list}; | ||
| 5200 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); | ||
| 5201 | return null; | ||
| 5202 | } | ||
| 5203 | |||
| 5204 | fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | ||
| 5205 | if (self.liveness.isUnused(inst)) return null; | ||
| 5206 | |||
| 5207 | const va_list_ty = self.air.typeOfIndex(inst); | ||
| 5208 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); | ||
| 5209 | |||
| 5210 | const target = self.dg.module.getTarget(); | ||
| 5211 | const result_alignment = va_list_ty.abiAlignment(target); | ||
| 5212 | const list = self.buildAlloca(llvm_va_list_ty, result_alignment); | ||
| 5213 | |||
| 5214 | const llvm_fn_name = "llvm.va_start"; | ||
| 5215 | const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: { | ||
| 5216 | const param_types = [_]*llvm.Type{self.dg.context.intType(8).pointerType(0)}; | ||
| 5217 | const fn_type = llvm.functionType(self.context.voidType(), &param_types, param_types.len, .False); | ||
| 5218 | break :blk self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | ||
| 5219 | }; | ||
| 5220 | const args: [1]*llvm.Value = .{list}; | ||
| 5221 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); | ||
| 5222 | |||
| 5223 | if (isByRef(va_list_ty)) { | ||
| 5224 | return list; | ||
| 5225 | } else { | ||
| 5226 | const loaded = self.builder.buildLoad(llvm_va_list_ty, list, ""); | ||
| 5227 | loaded.setAlignment(result_alignment); | ||
| 5228 | return loaded; | ||
| 5229 | } | ||
| 5230 | } | ||
| 5231 | |||
| 5139 | fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value { | 5232 | fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value { |
| 5140 | if (self.liveness.isUnused(inst)) return null; | 5233 | if (self.liveness.isUnused(inst)) return null; |
| 5141 | self.builder.setFastMath(want_fast_math); | 5234 | self.builder.setFastMath(want_fast_math); |
src/codegen/llvm/bindings.zig+3| ... | @@ -965,6 +965,9 @@ pub const Builder = opaque { | ... | @@ -965,6 +965,9 @@ pub const Builder = opaque { |
| 965 | 965 | ||
| 966 | pub const buildAllocaInAddressSpace = ZigLLVMBuildAllocaInAddressSpace; | 966 | pub const buildAllocaInAddressSpace = ZigLLVMBuildAllocaInAddressSpace; |
| 967 | extern fn ZigLLVMBuildAllocaInAddressSpace(B: *Builder, Ty: *Type, AddressSpace: c_uint, Name: [*:0]const u8) *Value; | 967 | extern fn ZigLLVMBuildAllocaInAddressSpace(B: *Builder, Ty: *Type, AddressSpace: c_uint, Name: [*:0]const u8) *Value; |
| 968 | |||
| 969 | pub const buildVAArg = LLVMBuildVAArg; | ||
| 970 | extern fn LLVMBuildVAArg(*Builder, List: *Value, Ty: *Type, Name: [*:0]const u8) *Value; | ||
| 968 | }; | 971 | }; |
| 969 | 972 | ||
| 970 | pub const MDString = opaque { | 973 | pub const MDString = opaque { |
src/link/MachO/load_commands.zig+1-1| ... | @@ -36,7 +36,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx | ... | @@ -36,7 +36,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx |
| 36 | // LC_DYLD_INFO_ONLY | 36 | // LC_DYLD_INFO_ONLY |
| 37 | sizeofcmds += @sizeOf(macho.dyld_info_command); | 37 | sizeofcmds += @sizeOf(macho.dyld_info_command); |
| 38 | // LC_FUNCTION_STARTS | 38 | // LC_FUNCTION_STARTS |
| 39 | if (has_text_segment and ctx.wants_function_starts) |_| { | 39 | if (has_text_segment and ctx.wants_function_starts) { |
| 40 | sizeofcmds += @sizeOf(macho.linkedit_data_command); | 40 | sizeofcmds += @sizeOf(macho.linkedit_data_command); |
| 41 | } | 41 | } |
| 42 | // LC_DATA_IN_CODE | 42 | // LC_DATA_IN_CODE |
src/print_air.zig+4| ... | @@ -191,6 +191,7 @@ const Writer = struct { | ... | @@ -191,6 +191,7 @@ const Writer = struct { |
| 191 | .neg_optimized, | 191 | .neg_optimized, |
| 192 | .cmp_lt_errors_len, | 192 | .cmp_lt_errors_len, |
| 193 | .set_err_return_trace, | 193 | .set_err_return_trace, |
| 194 | .c_va_end, | ||
| 194 | => try w.writeUnOp(s, inst), | 195 | => try w.writeUnOp(s, inst), |
| 195 | 196 | ||
| 196 | .breakpoint, | 197 | .breakpoint, |
| ... | @@ -205,6 +206,7 @@ const Writer = struct { | ... | @@ -205,6 +206,7 @@ const Writer = struct { |
| 205 | .ret_ptr, | 206 | .ret_ptr, |
| 206 | .arg, | 207 | .arg, |
| 207 | .err_return_trace, | 208 | .err_return_trace, |
| 209 | .c_va_start, | ||
| 208 | => try w.writeTy(s, inst), | 210 | => try w.writeTy(s, inst), |
| 209 | 211 | ||
| 210 | .not, | 212 | .not, |
| ... | @@ -246,6 +248,8 @@ const Writer = struct { | ... | @@ -246,6 +248,8 @@ const Writer = struct { |
| 246 | .bit_reverse, | 248 | .bit_reverse, |
| 247 | .error_set_has_value, | 249 | .error_set_has_value, |
| 248 | .addrspace_cast, | 250 | .addrspace_cast, |
| 251 | .c_va_arg, | ||
| 252 | .c_va_copy, | ||
| 249 | => try w.writeTyOp(s, inst), | 253 | => try w.writeTyOp(s, inst), |
| 250 | 254 | ||
| 251 | .block, | 255 | .block, |
src/print_zir.zig+4| ... | @@ -465,6 +465,7 @@ const Writer = struct { | ... | @@ -465,6 +465,7 @@ const Writer = struct { |
| 465 | .frame, | 465 | .frame, |
| 466 | .frame_address, | 466 | .frame_address, |
| 467 | .breakpoint, | 467 | .breakpoint, |
| 468 | .c_va_start, | ||
| 468 | => try self.writeExtNode(stream, extended), | 469 | => try self.writeExtNode(stream, extended), |
| 469 | 470 | ||
| 470 | .builtin_src => { | 471 | .builtin_src => { |
| ... | @@ -504,6 +505,8 @@ const Writer = struct { | ... | @@ -504,6 +505,8 @@ const Writer = struct { |
| 504 | .error_to_int, | 505 | .error_to_int, |
| 505 | .int_to_error, | 506 | .int_to_error, |
| 506 | .reify, | 507 | .reify, |
| 508 | .c_va_copy, | ||
| 509 | .c_va_end, | ||
| 507 | => { | 510 | => { |
| 508 | const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 511 | const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 509 | const src = LazySrcLoc.nodeOffset(inst_data.node); | 512 | const src = LazySrcLoc.nodeOffset(inst_data.node); |
| ... | @@ -518,6 +521,7 @@ const Writer = struct { | ... | @@ -518,6 +521,7 @@ const Writer = struct { |
| 518 | .wasm_memory_grow, | 521 | .wasm_memory_grow, |
| 519 | .prefetch, | 522 | .prefetch, |
| 520 | .addrspace_cast, | 523 | .addrspace_cast, |
| 524 | .c_va_arg, | ||
| 521 | => { | 525 | => { |
| 522 | const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 526 | const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 523 | const src = LazySrcLoc.nodeOffset(inst_data.node); | 527 | const src = LazySrcLoc.nodeOffset(inst_data.node); |
src/type.zig+8-2| ... | @@ -3489,7 +3489,10 @@ pub const Type = extern union { | ... | @@ -3489,7 +3489,10 @@ pub const Type = extern union { |
| 3489 | return AbiSizeAdvanced{ .scalar = 0 }; | 3489 | return AbiSizeAdvanced{ .scalar = 0 }; |
| 3490 | } | 3490 | } |
| 3491 | 3491 | ||
| 3492 | if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 }; | 3492 | if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { |
| 3493 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | ||
| 3494 | else => |e| return e, | ||
| 3495 | })) return AbiSizeAdvanced{ .scalar = 1 }; | ||
| 3493 | 3496 | ||
| 3494 | if (ty.optionalReprIsPayload()) { | 3497 | if (ty.optionalReprIsPayload()) { |
| 3495 | return abiSizeAdvanced(child_type, target, strat); | 3498 | return abiSizeAdvanced(child_type, target, strat); |
| ... | @@ -3518,7 +3521,10 @@ pub const Type = extern union { | ... | @@ -3518,7 +3521,10 @@ pub const Type = extern union { |
| 3518 | // in abiAlignmentAdvanced. | 3521 | // in abiAlignmentAdvanced. |
| 3519 | const data = ty.castTag(.error_union).?.data; | 3522 | const data = ty.castTag(.error_union).?.data; |
| 3520 | const code_size = abiSize(Type.anyerror, target); | 3523 | const code_size = abiSize(Type.anyerror, target); |
| 3521 | if (!data.payload.hasRuntimeBits()) { | 3524 | if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { |
| 3525 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | ||
| 3526 | else => |e| return e, | ||
| 3527 | })) { | ||
| 3522 | // Same as anyerror. | 3528 | // Same as anyerror. |
| 3523 | return AbiSizeAdvanced{ .scalar = code_size }; | 3529 | return AbiSizeAdvanced{ .scalar = code_size }; |
| 3524 | } | 3530 | } |
test/behavior/sizeof_and_typeof.zig+5| ... | @@ -288,3 +288,8 @@ test "runtime instructions inside typeof in comptime only scope" { | ... | @@ -288,3 +288,8 @@ test "runtime instructions inside typeof in comptime only scope" { |
| 288 | try expect(@TypeOf((T{}).b) == i8); | 288 | try expect(@TypeOf((T{}).b) == i8); |
| 289 | } | 289 | } |
| 290 | } | 290 | } |
| 291 | |||
| 292 | test "@sizeOf optional of previously unresolved union" { | ||
| 293 | const Node = union { a: usize }; | ||
| 294 | try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node)); | ||
| 295 | } |
test/behavior/var_args.zig+108-1| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const expect = @import("std").testing.expect; | 2 | const std = @import("std"); |
| 3 | const expect = std.testing.expect; | ||
| 3 | 4 | ||
| 4 | fn add(args: anytype) i32 { | 5 | fn add(args: anytype) i32 { |
| 5 | var sum = @as(i32, 0); | 6 | var sum = @as(i32, 0); |
| ... | @@ -91,3 +92,109 @@ test "pass zero length array to var args param" { | ... | @@ -91,3 +92,109 @@ test "pass zero length array to var args param" { |
| 91 | fn doNothingWithFirstArg(args: anytype) void { | 92 | fn doNothingWithFirstArg(args: anytype) void { |
| 92 | _ = args[0]; | 93 | _ = args[0]; |
| 93 | } | 94 | } |
| 95 | |||
| 96 | test "simple variadic function" { | ||
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 98 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 99 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 100 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 101 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 102 | if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .windows and builtin.os.tag != .macos) return error.SkipZigTest; // TODO | ||
| 103 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | ||
| 104 | |||
| 105 | const S = struct { | ||
| 106 | fn simple(...) callconv(.C) c_int { | ||
| 107 | var ap = @cVaStart(); | ||
| 108 | defer @cVaEnd(&ap); | ||
| 109 | return @cVaArg(&ap, c_int); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn add(count: c_int, ...) callconv(.C) c_int { | ||
| 113 | var ap = @cVaStart(); | ||
| 114 | defer @cVaEnd(&ap); | ||
| 115 | var i: usize = 0; | ||
| 116 | var sum: c_int = 0; | ||
| 117 | while (i < count) : (i += 1) { | ||
| 118 | sum += @cVaArg(&ap, c_int); | ||
| 119 | } | ||
| 120 | return sum; | ||
| 121 | } | ||
| 122 | }; | ||
| 123 | |||
| 124 | try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0))); | ||
| 125 | try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024))); | ||
| 126 | try std.testing.expectEqual(@as(c_int, 0), S.add(0)); | ||
| 127 | try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1))); | ||
| 128 | try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2))); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "variadic functions" { | ||
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 134 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 135 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 136 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 137 | if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .windows and builtin.os.tag != .macos) return error.SkipZigTest; // TODO | ||
| 138 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | ||
| 139 | |||
| 140 | const S = struct { | ||
| 141 | fn printf(list_ptr: *std.ArrayList(u8), format: [*:0]const u8, ...) callconv(.C) void { | ||
| 142 | var ap = @cVaStart(); | ||
| 143 | defer @cVaEnd(&ap); | ||
| 144 | vprintf(list_ptr, format, &ap); | ||
| 145 | } | ||
| 146 | |||
| 147 | fn vprintf( | ||
| 148 | list: *std.ArrayList(u8), | ||
| 149 | format: [*:0]const u8, | ||
| 150 | ap: *std.builtin.VaList, | ||
| 151 | ) callconv(.C) void { | ||
| 152 | for (std.mem.span(format)) |c| switch (c) { | ||
| 153 | 's' => { | ||
| 154 | const arg = @cVaArg(ap, [*:0]const u8); | ||
| 155 | list.writer().print("{s}", .{arg}) catch return; | ||
| 156 | }, | ||
| 157 | 'd' => { | ||
| 158 | const arg = @cVaArg(ap, c_int); | ||
| 159 | list.writer().print("{d}", .{arg}) catch return; | ||
| 160 | }, | ||
| 161 | else => unreachable, | ||
| 162 | }; | ||
| 163 | } | ||
| 164 | }; | ||
| 165 | |||
| 166 | var list = std.ArrayList(u8).init(std.testing.allocator); | ||
| 167 | defer list.deinit(); | ||
| 168 | S.printf(&list, "dsd", @as(c_int, 1), @as([*:0]const u8, "hello"), @as(c_int, 5)); | ||
| 169 | try std.testing.expectEqualStrings("1hello5", list.items); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "copy VaList" { | ||
| 173 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 174 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 175 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 176 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 177 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 178 | if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .windows and builtin.os.tag != .macos) return error.SkipZigTest; // TODO | ||
| 179 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | ||
| 180 | |||
| 181 | const S = struct { | ||
| 182 | fn add(count: c_int, ...) callconv(.C) c_int { | ||
| 183 | var ap = @cVaStart(); | ||
| 184 | defer @cVaEnd(&ap); | ||
| 185 | var copy = @cVaCopy(&ap); | ||
| 186 | defer @cVaEnd(&copy); | ||
| 187 | var i: usize = 0; | ||
| 188 | var sum: c_int = 0; | ||
| 189 | while (i < count) : (i += 1) { | ||
| 190 | sum += @cVaArg(&ap, c_int); | ||
| 191 | sum += @cVaArg(&copy, c_int) * 2; | ||
| 192 | } | ||
| 193 | return sum; | ||
| 194 | } | ||
| 195 | }; | ||
| 196 | |||
| 197 | try std.testing.expectEqual(@as(c_int, 0), S.add(0)); | ||
| 198 | try std.testing.expectEqual(@as(c_int, 3), S.add(1, @as(c_int, 1))); | ||
| 199 | try std.testing.expectEqual(@as(c_int, 9), S.add(2, @as(c_int, 1), @as(c_int, 2))); | ||
| 200 | } |
test/cases/compile_errors/invalid_capture_type.zig created+24| ... | @@ -0,0 +1,24 @@ | ||
| 1 | export fn f1() void { | ||
| 2 | if (true) |x| { _ = x; } | ||
| 3 | } | ||
| 4 | export fn f2() void { | ||
| 5 | if (@as(usize, 5)) |_| {} | ||
| 6 | } | ||
| 7 | export fn f3() void { | ||
| 8 | if (@as(usize, 5)) |_| {} else |_| {} | ||
| 9 | } | ||
| 10 | export fn f4() void { | ||
| 11 | if (null) |_| {} | ||
| 12 | } | ||
| 13 | export fn f5() void { | ||
| 14 | if (error.Foo) |_| {} else |_| {} | ||
| 15 | } | ||
| 16 | |||
| 17 | // error | ||
| 18 | // backend=stage2 | ||
| 19 | // target=native | ||
| 20 | // | ||
| 21 | // :2:9: error: expected optional type, found 'bool' | ||
| 22 | // :5:9: error: expected optional type, found 'usize' | ||
| 23 | // :8:9: error: expected error union type, found 'usize' | ||
| 24 | // :14:9: error: expected error union type, found 'error{Foo}' | ||
test/cases/compile_errors/invalid_variadic_function.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | fn foo(...) void {} | ||
| 2 | fn bar(a: anytype, ...) callconv(a) void {} | ||
| 3 | |||
| 4 | comptime { _ = foo; } | ||
| 5 | comptime { _ = bar; } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=stage2 | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // :1:1: error: variadic function must have 'C' calling convention | ||
| 12 | // :2:1: error: generic function cannot be variadic | ||
test/cases/compile_errors/stage1/obj/invalid_maybe_type.zig deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | export fn f() void { | ||
| 2 | if (true) |x| { _ = x; } | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=stage1 | ||
| 7 | // target=native | ||
| 8 | // | ||
| 9 | // tmp.zig:2:9: error: expected optional type, found 'bool' | ||