| author | |
| committer | |
| log | 6435750c99e705eb40bbdf75e51a3493d683e951 |
| tree | 2f1ab1dc537ba8804ae6d1e0bdd094d646625e53 |
| parent | d228d86059cf16f4b37b2853cc1323bf98d242cf |
| parent | 667236668f865de4c854a047d65017140317e7e9 |
| signature |
Stage2 whole file astgen508 files changed, 40200 insertions(+), 32931 deletions(-)
CMakeLists.txt+1-2| ... | @@ -550,7 +550,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -550,7 +550,6 @@ set(ZIG_STAGE2_SOURCES |
| 550 | "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig" | 550 | "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig" |
| 551 | "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig" | 551 | "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig" |
| 552 | "${CMAKE_SOURCE_DIR}/src/codegen/riscv64.zig" | 552 | "${CMAKE_SOURCE_DIR}/src/codegen/riscv64.zig" |
| 553 | "${CMAKE_SOURCE_DIR}/src/codegen/spu-mk2.zig" | ||
| 554 | "${CMAKE_SOURCE_DIR}/src/codegen/wasm.zig" | 553 | "${CMAKE_SOURCE_DIR}/src/codegen/wasm.zig" |
| 555 | "${CMAKE_SOURCE_DIR}/src/codegen/x86_64.zig" | 554 | "${CMAKE_SOURCE_DIR}/src/codegen/x86_64.zig" |
| 556 | "${CMAKE_SOURCE_DIR}/src/glibc.zig" | 555 | "${CMAKE_SOURCE_DIR}/src/glibc.zig" |
| ... | @@ -595,7 +594,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -595,7 +594,7 @@ set(ZIG_STAGE2_SOURCES |
| 595 | "${CMAKE_SOURCE_DIR}/src/type.zig" | 594 | "${CMAKE_SOURCE_DIR}/src/type.zig" |
| 596 | "${CMAKE_SOURCE_DIR}/src/value.zig" | 595 | "${CMAKE_SOURCE_DIR}/src/value.zig" |
| 597 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig" | 596 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig" |
| 598 | "${CMAKE_SOURCE_DIR}/src/zir.zig" | 597 | "${CMAKE_SOURCE_DIR}/src/Zir.zig" |
| 599 | "${CMAKE_SOURCE_DIR}/src/Sema.zig" | 598 | "${CMAKE_SOURCE_DIR}/src/Sema.zig" |
| 600 | ) | 599 | ) |
| 601 | 600 |
build.zig+28-15| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | ||
| 3 | const Builder = std.build.Builder; | 3 | const Builder = std.build.Builder; |
| 4 | const tests = @import("test/tests.zig"); | 4 | const tests = @import("test/tests.zig"); |
| 5 | const BufMap = std.BufMap; | 5 | const BufMap = std.BufMap; |
| ... | @@ -54,6 +54,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -54,6 +54,7 @@ pub fn build(b: *Builder) !void { |
| 54 | const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false; | 54 | const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false; |
| 55 | const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false; | 55 | const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false; |
| 56 | const skip_stage2_tests = b.option(bool, "skip-stage2-tests", "Main test suite skips self-hosted compiler tests") orelse false; | 56 | const skip_stage2_tests = b.option(bool, "skip-stage2-tests", "Main test suite skips self-hosted compiler tests") orelse false; |
| 57 | const skip_install_lib_files = b.option(bool, "skip-install-lib-files", "Do not copy lib/ files to installation prefix") orelse false; | ||
| 57 | 58 | ||
| 58 | const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; | 59 | const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; |
| 59 | const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false; | 60 | const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false; |
| ... | @@ -62,19 +63,23 @@ pub fn build(b: *Builder) !void { | ... | @@ -62,19 +63,23 @@ pub fn build(b: *Builder) !void { |
| 62 | const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm); | 63 | const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm); |
| 63 | const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); | 64 | const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); |
| 64 | 65 | ||
| 65 | b.installDirectory(InstallDirectoryOptions{ | 66 | if (!skip_install_lib_files) { |
| 66 | .source_dir = "lib", | 67 | b.installDirectory(InstallDirectoryOptions{ |
| 67 | .install_dir = .Lib, | 68 | .source_dir = "lib", |
| 68 | .install_subdir = "zig", | 69 | .install_dir = .Lib, |
| 69 | .exclude_extensions = &[_][]const u8{ | 70 | .install_subdir = "zig", |
| 70 | "test.zig", | 71 | .exclude_extensions = &[_][]const u8{ |
| 71 | "README.md", | 72 | "README.md", |
| 72 | ".z.0", | 73 | ".z.0", |
| 73 | ".z.9", | 74 | ".z.9", |
| 74 | ".gz", | 75 | ".gz", |
| 75 | "rfc1951.txt", | 76 | "rfc1951.txt", |
| 76 | }, | 77 | }, |
| 77 | }); | 78 | .blank_extensions = &[_][]const u8{ |
| 79 | "test.zig", | ||
| 80 | }, | ||
| 81 | }); | ||
| 82 | } | ||
| 78 | 83 | ||
| 79 | if (only_install_lib_files) | 84 | if (only_install_lib_files) |
| 80 | return; | 85 | return; |
| ... | @@ -83,6 +88,12 @@ pub fn build(b: *Builder) !void { | ... | @@ -83,6 +88,12 @@ pub fn build(b: *Builder) !void { |
| 83 | const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm; | 88 | const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm; |
| 84 | const strip = b.option(bool, "strip", "Omit debug information") orelse false; | 89 | const strip = b.option(bool, "strip", "Omit debug information") orelse false; |
| 85 | 90 | ||
| 91 | const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { | ||
| 92 | if (strip) break :blk @as(u32, 0); | ||
| 93 | if (mode != .Debug) break :blk 0; | ||
| 94 | break :blk 4; | ||
| 95 | }; | ||
| 96 | |||
| 86 | const main_file = if (is_stage1) "src/stage1.zig" else "src/main.zig"; | 97 | const main_file = if (is_stage1) "src/stage1.zig" else "src/main.zig"; |
| 87 | 98 | ||
| 88 | var exe = b.addExecutable("zig", main_file); | 99 | var exe = b.addExecutable("zig", main_file); |
| ... | @@ -93,6 +104,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -93,6 +104,7 @@ pub fn build(b: *Builder) !void { |
| 93 | toolchain_step.dependOn(&exe.step); | 104 | toolchain_step.dependOn(&exe.step); |
| 94 | b.default_step.dependOn(&exe.step); | 105 | b.default_step.dependOn(&exe.step); |
| 95 | 106 | ||
| 107 | exe.addBuildOption(u32, "mem_leak_frames", mem_leak_frames); | ||
| 96 | exe.addBuildOption(bool, "skip_non_native", skip_non_native); | 108 | exe.addBuildOption(bool, "skip_non_native", skip_non_native); |
| 97 | exe.addBuildOption(bool, "have_llvm", enable_llvm); | 109 | exe.addBuildOption(bool, "have_llvm", enable_llvm); |
| 98 | if (enable_llvm) { | 110 | if (enable_llvm) { |
| ... | @@ -228,6 +240,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -228,6 +240,7 @@ pub fn build(b: *Builder) !void { |
| 228 | test_stage2.addBuildOption(bool, "enable_qemu", is_qemu_enabled); | 240 | test_stage2.addBuildOption(bool, "enable_qemu", is_qemu_enabled); |
| 229 | test_stage2.addBuildOption(bool, "enable_wine", is_wine_enabled); | 241 | test_stage2.addBuildOption(bool, "enable_wine", is_wine_enabled); |
| 230 | test_stage2.addBuildOption(bool, "enable_wasmtime", is_wasmtime_enabled); | 242 | test_stage2.addBuildOption(bool, "enable_wasmtime", is_wasmtime_enabled); |
| 243 | test_stage2.addBuildOption(u32, "mem_leak_frames", mem_leak_frames * 2); | ||
| 231 | test_stage2.addBuildOption(bool, "enable_darling", is_darling_enabled); | 244 | test_stage2.addBuildOption(bool, "enable_darling", is_darling_enabled); |
| 232 | test_stage2.addBuildOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir); | 245 | test_stage2.addBuildOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir); |
| 233 | test_stage2.addBuildOption([]const u8, "version", version); | 246 | test_stage2.addBuildOption([]const u8, "version", version); |
| ... | @@ -266,7 +279,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -266,7 +279,7 @@ pub fn build(b: *Builder) !void { |
| 266 | toolchain_step.dependOn(tests.addPkgTests( | 279 | toolchain_step.dependOn(tests.addPkgTests( |
| 267 | b, | 280 | b, |
| 268 | test_filter, | 281 | test_filter, |
| 269 | "test/stage1/behavior.zig", | 282 | "test/behavior.zig", |
| 270 | "behavior", | 283 | "behavior", |
| 271 | "Run the behavior tests", | 284 | "Run the behavior tests", |
| 272 | modes, | 285 | modes, |
doc/langref.html.in+16-36| ... | @@ -1099,7 +1099,6 @@ const nan = std.math.nan(f128); | ... | @@ -1099,7 +1099,6 @@ const nan = std.math.nan(f128); |
| 1099 | {#code_release_fast#} | 1099 | {#code_release_fast#} |
| 1100 | {#code_disable_cache#} | 1100 | {#code_disable_cache#} |
| 1101 | const std = @import("std"); | 1101 | const std = @import("std"); |
| 1102 | const builtin = std.builtin; | ||
| 1103 | const big = @as(f64, 1 << 40); | 1102 | const big = @as(f64, 1 << 40); |
| 1104 | 1103 | ||
| 1105 | export fn foo_strict(x: f64) f64 { | 1104 | export fn foo_strict(x: f64) f64 { |
| ... | @@ -2589,7 +2588,7 @@ test "default struct initialization fields" { | ... | @@ -2589,7 +2588,7 @@ test "default struct initialization fields" { |
| 2589 | exactly their bit width. | 2588 | exactly their bit width. |
| 2590 | </li> | 2589 | </li> |
| 2591 | <li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li> | 2590 | <li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li> |
| 2592 | <li>A {#link|packed enum#} field uses exactly the bit width of its integer tag type.</li> | 2591 | <li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li> |
| 2593 | <li>A {#link|packed union#} field uses exactly the bit width of the union field with | 2592 | <li>A {#link|packed union#} field uses exactly the bit width of the union field with |
| 2594 | the largest bit width.</li> | 2593 | the largest bit width.</li> |
| 2595 | <li>Non-ABI-aligned fields are packed into the smallest possible | 2594 | <li>Non-ABI-aligned fields are packed into the smallest possible |
| ... | @@ -2603,7 +2602,7 @@ test "default struct initialization fields" { | ... | @@ -2603,7 +2602,7 @@ test "default struct initialization fields" { |
| 2603 | </p> | 2602 | </p> |
| 2604 | {#code_begin|test#} | 2603 | {#code_begin|test#} |
| 2605 | const std = @import("std"); | 2604 | const std = @import("std"); |
| 2606 | const builtin = std.builtin; | 2605 | const native_endian = @import("builtin").target.cpu.arch.endian(); |
| 2607 | const expect = std.testing.expect; | 2606 | const expect = std.testing.expect; |
| 2608 | 2607 | ||
| 2609 | const Full = packed struct { | 2608 | const Full = packed struct { |
| ... | @@ -2625,7 +2624,7 @@ fn doTheTest() !void { | ... | @@ -2625,7 +2624,7 @@ fn doTheTest() !void { |
| 2625 | try expect(@sizeOf(Divided) == 2); | 2624 | try expect(@sizeOf(Divided) == 2); |
| 2626 | var full = Full{ .number = 0x1234 }; | 2625 | var full = Full{ .number = 0x1234 }; |
| 2627 | var divided = @bitCast(Divided, full); | 2626 | var divided = @bitCast(Divided, full); |
| 2628 | switch (builtin.endian) { | 2627 | switch (native_endian) { |
| 2629 | .Big => { | 2628 | .Big => { |
| 2630 | try expect(divided.half1 == 0x12); | 2629 | try expect(divided.half1 == 0x12); |
| 2631 | try expect(divided.quarter3 == 0x3); | 2630 | try expect(divided.quarter3 == 0x3); |
| ... | @@ -3015,25 +3014,6 @@ export fn entry(foo: Foo) void { } | ... | @@ -3015,25 +3014,6 @@ export fn entry(foo: Foo) void { } |
| 3015 | {#code_end#} | 3014 | {#code_end#} |
| 3016 | {#header_close#} | 3015 | {#header_close#} |
| 3017 | 3016 | ||
| 3018 | {#header_open|packed enum#} | ||
| 3019 | <p>By default, the size of enums is not guaranteed.</p> | ||
| 3020 | <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the | ||
| 3021 | integer tag type of the enum:</p> | ||
| 3022 | {#code_begin|test#} | ||
| 3023 | const std = @import("std"); | ||
| 3024 | |||
| 3025 | test "packed enum" { | ||
| 3026 | const Number = packed enum(u8) { | ||
| 3027 | one, | ||
| 3028 | two, | ||
| 3029 | three, | ||
| 3030 | }; | ||
| 3031 | try std.testing.expect(@sizeOf(Number) == @sizeOf(u8)); | ||
| 3032 | } | ||
| 3033 | {#code_end#} | ||
| 3034 | <p>This makes the enum eligible to be in a {#link|packed struct#}.</p> | ||
| 3035 | {#header_close#} | ||
| 3036 | |||
| 3037 | {#header_open|Enum Literals#} | 3017 | {#header_open|Enum Literals#} |
| 3038 | <p> | 3018 | <p> |
| 3039 | Enum literals allow specifying the name of an enum field without specifying the enum type: | 3019 | Enum literals allow specifying the name of an enum field without specifying the enum type: |
| ... | @@ -4255,7 +4235,7 @@ test "noreturn" { | ... | @@ -4255,7 +4235,7 @@ test "noreturn" { |
| 4255 | <p>Another use case for {#syntax#}noreturn{#endsyntax#} is the {#syntax#}exit{#endsyntax#} function:</p> | 4235 | <p>Another use case for {#syntax#}noreturn{#endsyntax#} is the {#syntax#}exit{#endsyntax#} function:</p> |
| 4256 | {#code_begin|test#} | 4236 | {#code_begin|test#} |
| 4257 | {#target_windows#} | 4237 | {#target_windows#} |
| 4258 | pub extern "kernel32" fn ExitProcess(exit_code: c_uint) callconv(if (@import("builtin").arch == .i386) .Stdcall else .C) noreturn; | 4238 | pub extern "kernel32" fn ExitProcess(exit_code: c_uint) callconv(if (@import("builtin").target.cpu.arch == .i386) .Stdcall else .C) noreturn; |
| 4259 | 4239 | ||
| 4260 | test "foo" { | 4240 | test "foo" { |
| 4261 | const value = bar() catch ExitProcess(1); | 4241 | const value = bar() catch ExitProcess(1); |
| ... | @@ -4290,7 +4270,7 @@ export fn sub(a: i8, b: i8) i8 { return a - b; } | ... | @@ -4290,7 +4270,7 @@ export fn sub(a: i8, b: i8) i8 { return a - b; } |
| 4290 | // at link time, when linking statically, or at runtime, when linking | 4270 | // at link time, when linking statically, or at runtime, when linking |
| 4291 | // dynamically. | 4271 | // dynamically. |
| 4292 | // The callconv specifier changes the calling convention of the function. | 4272 | // The callconv specifier changes the calling convention of the function. |
| 4293 | extern "kernel32" fn ExitProcess(exit_code: u32) callconv(if (@import("builtin").arch == .i386) .Stdcall else .C) noreturn; | 4273 | extern "kernel32" fn ExitProcess(exit_code: u32) callconv(if (@import("builtin").target.cpu.arch == .i386) .Stdcall else .C) noreturn; |
| 4294 | extern "c" fn atan2(a: f64, b: f64) f64; | 4274 | extern "c" fn atan2(a: f64, b: f64) f64; |
| 4295 | 4275 | ||
| 4296 | // The @setCold builtin tells the optimizer that a function is rarely called. | 4276 | // The @setCold builtin tells the optimizer that a function is rarely called. |
| ... | @@ -7596,7 +7576,7 @@ export fn @"A function name that is a complete sentence."() void {} | ... | @@ -7596,7 +7576,7 @@ export fn @"A function name that is a complete sentence."() void {} |
| 7596 | The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations. | 7576 | The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations. |
| 7597 | </p> | 7577 | </p> |
| 7598 | <p> | 7578 | <p> |
| 7599 | {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}. | 7579 | {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}. |
| 7600 | </p> | 7580 | </p> |
| 7601 | {#see_also|Compile Variables#} | 7581 | {#see_also|Compile Variables#} |
| 7602 | {#header_close#} | 7582 | {#header_close#} |
| ... | @@ -7799,8 +7779,8 @@ test "@hasDecl" { | ... | @@ -7799,8 +7779,8 @@ test "@hasDecl" { |
| 7799 | </p> | 7779 | </p> |
| 7800 | <ul> | 7780 | <ul> |
| 7801 | <li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li> | 7781 | <li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li> |
| 7802 | <li>{#syntax#}@import("builtin"){#endsyntax#} - Compiler-provided types and variables. | 7782 | <li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information |
| 7803 | The command <code>zig builtin</code> outputs the source to stdout for reference. | 7783 | The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference. |
| 7804 | </li> | 7784 | </li> |
| 7805 | </ul> | 7785 | </ul> |
| 7806 | {#see_also|Compile Variables|@embedFile#} | 7786 | {#see_also|Compile Variables|@embedFile#} |
| ... | @@ -7931,11 +7911,11 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> | ... | @@ -7931,11 +7911,11 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> |
| 7931 | </p> | 7911 | </p> |
| 7932 | {#code_begin|test#} | 7912 | {#code_begin|test#} |
| 7933 | const std = @import("std"); | 7913 | const std = @import("std"); |
| 7934 | const builtin = @import("builtin"); | 7914 | const native_arch = @import("builtin").target.cpu.arch; |
| 7935 | const expect = std.testing.expect; | 7915 | const expect = std.testing.expect; |
| 7936 | 7916 | ||
| 7937 | test "@wasmMemoryGrow" { | 7917 | test "@wasmMemoryGrow" { |
| 7938 | if (builtin.arch != .wasm32) return error.SkipZigTest; | 7918 | if (native_arch != .wasm32) return error.SkipZigTest; |
| 7939 | 7919 | ||
| 7940 | var prev = @wasmMemorySize(0); | 7920 | var prev = @wasmMemorySize(0); |
| 7941 | try expect(prev == @wasmMemoryGrow(0, 1)); | 7921 | try expect(prev == @wasmMemoryGrow(0, 1)); |
| ... | @@ -8103,7 +8083,7 @@ test "foo" { | ... | @@ -8103,7 +8083,7 @@ test "foo" { |
| 8103 | {#header_close#} | 8083 | {#header_close#} |
| 8104 | 8084 | ||
| 8105 | {#header_open|@setFloatMode#} | 8085 | {#header_open|@setFloatMode#} |
| 8106 | <pre>{#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}</pre> | 8086 | <pre>{#syntax#}@setFloatMode(mode: @import("std").builtin.FloatMode){#endsyntax#}</pre> |
| 8107 | <p> | 8087 | <p> |
| 8108 | Sets the floating point mode of the current scope. Possible values are: | 8088 | Sets the floating point mode of the current scope. Possible values are: |
| 8109 | </p> | 8089 | </p> |
| ... | @@ -8292,7 +8272,7 @@ test "vector @splat" { | ... | @@ -8292,7 +8272,7 @@ test "vector @splat" { |
| 8292 | {#header_close#} | 8272 | {#header_close#} |
| 8293 | 8273 | ||
| 8294 | {#header_open|@reduce#} | 8274 | {#header_open|@reduce#} |
| 8295 | <pre>{#syntax#}@reduce(comptime op: builtin.ReduceOp, value: anytype) std.meta.Child(value){#endsyntax#}</pre> | 8275 | <pre>{#syntax#}@reduce(comptime op: std.builtin.ReduceOp, value: anytype) std.meta.Child(value){#endsyntax#}</pre> |
| 8296 | <p> | 8276 | <p> |
| 8297 | Transforms a {#link|vector|Vectors#} into a scalar value by performing a | 8277 | Transforms a {#link|vector|Vectors#} into a scalar value by performing a |
| 8298 | sequential horizontal reduction of its elements using the specified operator {#syntax#}op{#endsyntax#}. | 8278 | sequential horizontal reduction of its elements using the specified operator {#syntax#}op{#endsyntax#}. |
| ... | @@ -8584,7 +8564,7 @@ test "integer truncation" { | ... | @@ -8584,7 +8564,7 @@ test "integer truncation" { |
| 8584 | {#header_close#} | 8564 | {#header_close#} |
| 8585 | 8565 | ||
| 8586 | {#header_open|@Type#} | 8566 | {#header_open|@Type#} |
| 8587 | <pre>{#syntax#}@Type(comptime info: @import("builtin").TypeInfo) type{#endsyntax#}</pre> | 8567 | <pre>{#syntax#}@Type(comptime info: std.builtin.TypeInfo) type{#endsyntax#}</pre> |
| 8588 | <p> | 8568 | <p> |
| 8589 | This function is the inverse of {#link|@typeInfo#}. It reifies type information | 8569 | This function is the inverse of {#link|@typeInfo#}. It reifies type information |
| 8590 | into a {#syntax#}type{#endsyntax#}. | 8570 | into a {#syntax#}type{#endsyntax#}. |
| ... | @@ -8626,7 +8606,7 @@ test "integer truncation" { | ... | @@ -8626,7 +8606,7 @@ test "integer truncation" { |
| 8626 | </ul> | 8606 | </ul> |
| 8627 | {#header_close#} | 8607 | {#header_close#} |
| 8628 | {#header_open|@typeInfo#} | 8608 | {#header_open|@typeInfo#} |
| 8629 | <pre>{#syntax#}@typeInfo(comptime T: type) @import("std").builtin.TypeInfo{#endsyntax#}</pre> | 8609 | <pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.TypeInfo{#endsyntax#}</pre> |
| 8630 | <p> | 8610 | <p> |
| 8631 | Provides type reflection. | 8611 | Provides type reflection. |
| 8632 | </p> | 8612 | </p> |
| ... | @@ -9647,7 +9627,7 @@ test "string literal to constant slice" { | ... | @@ -9647,7 +9627,7 @@ test "string literal to constant slice" { |
| 9647 | </p> | 9627 | </p> |
| 9648 | {#code_begin|syntax#} | 9628 | {#code_begin|syntax#} |
| 9649 | const builtin = @import("builtin"); | 9629 | const builtin = @import("builtin"); |
| 9650 | const separator = if (builtin.os == builtin.Os.windows) '\\' else '/'; | 9630 | const separator = if (builtin.os.tag == builtin.Os.windows) '\\' else '/'; |
| 9651 | {#code_end#} | 9631 | {#code_end#} |
| 9652 | <p> | 9632 | <p> |
| 9653 | Example of what is imported with {#syntax#}@import("builtin"){#endsyntax#}: | 9633 | Example of what is imported with {#syntax#}@import("builtin"){#endsyntax#}: |
| ... | @@ -9672,7 +9652,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/'; | ... | @@ -9672,7 +9652,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/'; |
| 9672 | </p> | 9652 | </p> |
| 9673 | {#code_begin|test|detect_test#} | 9653 | {#code_begin|test|detect_test#} |
| 9674 | const std = @import("std"); | 9654 | const std = @import("std"); |
| 9675 | const builtin = std.builtin; | 9655 | const builtin = @import("builtin"); |
| 9676 | const expect = std.testing.expect; | 9656 | const expect = std.testing.expect; |
| 9677 | 9657 | ||
| 9678 | test "builtin.is_test" { | 9658 | test "builtin.is_test" { |
lib/std/Thread/AutoResetEvent.zig+1-1| ... | @@ -32,7 +32,7 @@ | ... | @@ -32,7 +32,7 @@ |
| 32 | state: usize = UNSET, | 32 | state: usize = UNSET, |
| 33 | 33 | ||
| 34 | const std = @import("../std.zig"); | 34 | const std = @import("../std.zig"); |
| 35 | const builtin = @import("builtin"); | 35 | const builtin = std.builtin; |
| 36 | const testing = std.testing; | 36 | const testing = std.testing; |
| 37 | const assert = std.debug.assert; | 37 | const assert = std.debug.assert; |
| 38 | const StaticResetEvent = std.Thread.StaticResetEvent; | 38 | const StaticResetEvent = std.Thread.StaticResetEvent; |
lib/std/Thread/StaticResetEvent.zig+2-2| ... | @@ -262,7 +262,7 @@ pub const AtomicEvent = struct { | ... | @@ -262,7 +262,7 @@ pub const AtomicEvent = struct { |
| 262 | while (true) { | 262 | while (true) { |
| 263 | if (waiting == WAKE) { | 263 | if (waiting == WAKE) { |
| 264 | rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null); | 264 | rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null); |
| 265 | assert(rc == .WAIT_0); | 265 | assert(rc == windows.NTSTATUS.WAIT_0); |
| 266 | break; | 266 | break; |
| 267 | } else { | 267 | } else { |
| 268 | waiting = @cmpxchgWeak(u32, waiters, waiting, waiting - WAIT, .Acquire, .Monotonic) orelse break; | 268 | waiting = @cmpxchgWeak(u32, waiters, waiting, waiting - WAIT, .Acquire, .Monotonic) orelse break; |
| ... | @@ -271,7 +271,7 @@ pub const AtomicEvent = struct { | ... | @@ -271,7 +271,7 @@ pub const AtomicEvent = struct { |
| 271 | } | 271 | } |
| 272 | return error.TimedOut; | 272 | return error.TimedOut; |
| 273 | }, | 273 | }, |
| 274 | .WAIT_0 => {}, | 274 | windows.NTSTATUS.WAIT_0 => {}, |
| 275 | else => unreachable, | 275 | else => unreachable, |
| 276 | } | 276 | } |
| 277 | } | 277 | } |
lib/std/array_hash_map.zig+30-6| ... | @@ -14,7 +14,7 @@ const trait = meta.trait; | ... | @@ -14,7 +14,7 @@ const trait = meta.trait; |
| 14 | const autoHash = std.hash.autoHash; | 14 | const autoHash = std.hash.autoHash; |
| 15 | const Wyhash = std.hash.Wyhash; | 15 | const Wyhash = std.hash.Wyhash; |
| 16 | const Allocator = mem.Allocator; | 16 | const Allocator = mem.Allocator; |
| 17 | const builtin = @import("builtin"); | 17 | const builtin = std.builtin; |
| 18 | const hash_map = @This(); | 18 | const hash_map = @This(); |
| 19 | 19 | ||
| 20 | pub fn AutoArrayHashMap(comptime K: type, comptime V: type) type { | 20 | pub fn AutoArrayHashMap(comptime K: type, comptime V: type) type { |
| ... | @@ -158,10 +158,20 @@ pub fn ArrayHashMap( | ... | @@ -158,10 +158,20 @@ pub fn ArrayHashMap( |
| 158 | return self.unmanaged.getOrPutValue(self.allocator, key, value); | 158 | return self.unmanaged.getOrPutValue(self.allocator, key, value); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`. | ||
| 162 | pub const ensureCapacity = ensureTotalCapacity; | ||
| 163 | |||
| 161 | /// Increases capacity, guaranteeing that insertions up until the | 164 | /// Increases capacity, guaranteeing that insertions up until the |
| 162 | /// `expected_count` will not cause an allocation, and therefore cannot fail. | 165 | /// `expected_count` will not cause an allocation, and therefore cannot fail. |
| 163 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { | 166 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { |
| 164 | return self.unmanaged.ensureCapacity(self.allocator, new_capacity); | 167 | return self.unmanaged.ensureTotalCapacity(self.allocator, new_capacity); |
| 168 | } | ||
| 169 | |||
| 170 | /// Increases capacity, guaranteeing that insertions up until | ||
| 171 | /// `additional_count` **more** items will not cause an allocation, and | ||
| 172 | /// therefore cannot fail. | ||
| 173 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void { | ||
| 174 | return self.unmanaged.ensureUnusedCapacity(self.allocator, additional_count); | ||
| 165 | } | 175 | } |
| 166 | 176 | ||
| 167 | /// Returns the number of total elements which may be present before it is | 177 | /// Returns the number of total elements which may be present before it is |
| ... | @@ -472,10 +482,13 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -472,10 +482,13 @@ pub fn ArrayHashMapUnmanaged( |
| 472 | return res.entry; | 482 | return res.entry; |
| 473 | } | 483 | } |
| 474 | 484 | ||
| 485 | /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`. | ||
| 486 | pub const ensureCapacity = ensureTotalCapacity; | ||
| 487 | |||
| 475 | /// Increases capacity, guaranteeing that insertions up until the | 488 | /// Increases capacity, guaranteeing that insertions up until the |
| 476 | /// `expected_count` will not cause an allocation, and therefore cannot fail. | 489 | /// `expected_count` will not cause an allocation, and therefore cannot fail. |
| 477 | pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { | 490 | pub fn ensureTotalCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { |
| 478 | try self.entries.ensureCapacity(allocator, new_capacity); | 491 | try self.entries.ensureTotalCapacity(allocator, new_capacity); |
| 479 | if (new_capacity <= linear_scan_max) return; | 492 | if (new_capacity <= linear_scan_max) return; |
| 480 | 493 | ||
| 481 | // Ensure that the indexes will be at most 60% full if | 494 | // Ensure that the indexes will be at most 60% full if |
| ... | @@ -501,6 +514,17 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -501,6 +514,17 @@ pub fn ArrayHashMapUnmanaged( |
| 501 | } | 514 | } |
| 502 | } | 515 | } |
| 503 | 516 | ||
| 517 | /// Increases capacity, guaranteeing that insertions up until | ||
| 518 | /// `additional_count` **more** items will not cause an allocation, and | ||
| 519 | /// therefore cannot fail. | ||
| 520 | pub fn ensureUnusedCapacity( | ||
| 521 | self: *Self, | ||
| 522 | allocator: *Allocator, | ||
| 523 | additional_capacity: usize, | ||
| 524 | ) !void { | ||
| 525 | return self.ensureTotalCapacity(allocator, self.count() + additional_capacity); | ||
| 526 | } | ||
| 527 | |||
| 504 | /// Returns the number of total elements which may be present before it is | 528 | /// Returns the number of total elements which may be present before it is |
| 505 | /// no longer guaranteed that no allocations will be performed. | 529 | /// no longer guaranteed that no allocations will be performed. |
| 506 | pub fn capacity(self: Self) usize { | 530 | pub fn capacity(self: Self) usize { |
| ... | @@ -1310,7 +1334,7 @@ test "reIndex" { | ... | @@ -1310,7 +1334,7 @@ test "reIndex" { |
| 1310 | } | 1334 | } |
| 1311 | 1335 | ||
| 1312 | test "fromOwnedArrayList" { | 1336 | test "fromOwnedArrayList" { |
| 1313 | comptime const array_hash_map_type = AutoArrayHashMap(i32, i32); | 1337 | const array_hash_map_type = AutoArrayHashMap(i32, i32); |
| 1314 | var al = std.ArrayListUnmanaged(array_hash_map_type.Entry){}; | 1338 | var al = std.ArrayListUnmanaged(array_hash_map_type.Entry){}; |
| 1315 | const hash = getAutoHashFn(i32); | 1339 | const hash = getAutoHashFn(i32); |
| 1316 | 1340 |
lib/std/array_list.zig+60-14| ... | @@ -131,7 +131,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -131,7 +131,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 131 | /// Insert `item` at index `n` by moving `list[n .. list.len]` to make room. | 131 | /// Insert `item` at index `n` by moving `list[n .. list.len]` to make room. |
| 132 | /// This operation is O(N). | 132 | /// This operation is O(N). |
| 133 | pub fn insert(self: *Self, n: usize, item: T) !void { | 133 | pub fn insert(self: *Self, n: usize, item: T) !void { |
| 134 | try self.ensureCapacity(self.items.len + 1); | 134 | try self.ensureUnusedCapacity(1); |
| 135 | self.items.len += 1; | 135 | self.items.len += 1; |
| 136 | 136 | ||
| 137 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); | 137 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); |
| ... | @@ -141,7 +141,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -141,7 +141,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 141 | /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. | 141 | /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. |
| 142 | /// This operation is O(N). | 142 | /// This operation is O(N). |
| 143 | pub fn insertSlice(self: *Self, i: usize, items: []const T) !void { | 143 | pub fn insertSlice(self: *Self, i: usize, items: []const T) !void { |
| 144 | try self.ensureCapacity(self.items.len + items.len); | 144 | try self.ensureUnusedCapacity(items.len); |
| 145 | self.items.len += items.len; | 145 | self.items.len += items.len; |
| 146 | 146 | ||
| 147 | mem.copyBackwards(T, self.items[i + items.len .. self.items.len], self.items[i .. self.items.len - items.len]); | 147 | mem.copyBackwards(T, self.items[i + items.len .. self.items.len], self.items[i .. self.items.len - items.len]); |
| ... | @@ -220,7 +220,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -220,7 +220,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 220 | /// Append the slice of items to the list. Allocates more | 220 | /// Append the slice of items to the list. Allocates more |
| 221 | /// memory as necessary. | 221 | /// memory as necessary. |
| 222 | pub fn appendSlice(self: *Self, items: []const T) !void { | 222 | pub fn appendSlice(self: *Self, items: []const T) !void { |
| 223 | try self.ensureCapacity(self.items.len + items.len); | 223 | try self.ensureUnusedCapacity(items.len); |
| 224 | self.appendSliceAssumeCapacity(items); | 224 | self.appendSliceAssumeCapacity(items); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| ... | @@ -269,7 +269,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -269,7 +269,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 269 | /// Adjust the list's length to `new_len`. | 269 | /// Adjust the list's length to `new_len`. |
| 270 | /// Does not initialize added items if any. | 270 | /// Does not initialize added items if any. |
| 271 | pub fn resize(self: *Self, new_len: usize) !void { | 271 | pub fn resize(self: *Self, new_len: usize) !void { |
| 272 | try self.ensureCapacity(new_len); | 272 | try self.ensureTotalCapacity(new_len); |
| 273 | self.items.len = new_len; | 273 | self.items.len = new_len; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| ... | @@ -294,9 +294,24 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -294,9 +294,24 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 294 | self.items.len = new_len; | 294 | self.items.len = new_len; |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | /// Invalidates all element pointers. | ||
| 298 | pub fn clearRetainingCapacity(self: *Self) void { | ||
| 299 | self.items.len = 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | /// Invalidates all element pointers. | ||
| 303 | pub fn clearAndFree(self: *Self) void { | ||
| 304 | self.allocator.free(self.allocatedSlice()); | ||
| 305 | self.items.len = 0; | ||
| 306 | self.capacity = 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`. | ||
| 310 | pub const ensureCapacity = ensureTotalCapacity; | ||
| 311 | |||
| 297 | /// Modify the array so that it can hold at least `new_capacity` items. | 312 | /// Modify the array so that it can hold at least `new_capacity` items. |
| 298 | /// Invalidates pointers if additional memory is needed. | 313 | /// Invalidates pointers if additional memory is needed. |
| 299 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { | 314 | pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { |
| 300 | var better_capacity = self.capacity; | 315 | var better_capacity = self.capacity; |
| 301 | if (better_capacity >= new_capacity) return; | 316 | if (better_capacity >= new_capacity) return; |
| 302 | 317 | ||
| ... | @@ -311,6 +326,12 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -311,6 +326,12 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 311 | self.capacity = new_memory.len; | 326 | self.capacity = new_memory.len; |
| 312 | } | 327 | } |
| 313 | 328 | ||
| 329 | /// Modify the array so that it can hold at least `additional_count` **more** items. | ||
| 330 | /// Invalidates pointers if additional memory is needed. | ||
| 331 | pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void { | ||
| 332 | return self.ensureTotalCapacity(self.items.len + additional_count); | ||
| 333 | } | ||
| 334 | |||
| 314 | /// Increases the array's length to match the full capacity that is already allocated. | 335 | /// Increases the array's length to match the full capacity that is already allocated. |
| 315 | /// The new elements have `undefined` values. **Does not** invalidate pointers. | 336 | /// The new elements have `undefined` values. **Does not** invalidate pointers. |
| 316 | pub fn expandToCapacity(self: *Self) void { | 337 | pub fn expandToCapacity(self: *Self) void { |
| ... | @@ -321,7 +342,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -321,7 +342,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 321 | /// The returned pointer becomes invalid when the list resized. | 342 | /// The returned pointer becomes invalid when the list resized. |
| 322 | pub fn addOne(self: *Self) !*T { | 343 | pub fn addOne(self: *Self) !*T { |
| 323 | const newlen = self.items.len + 1; | 344 | const newlen = self.items.len + 1; |
| 324 | try self.ensureCapacity(newlen); | 345 | try self.ensureTotalCapacity(newlen); |
| 325 | return self.addOneAssumeCapacity(); | 346 | return self.addOneAssumeCapacity(); |
| 326 | } | 347 | } |
| 327 | 348 | ||
| ... | @@ -471,7 +492,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -471,7 +492,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 471 | /// to higher indices to make room. | 492 | /// to higher indices to make room. |
| 472 | /// This operation is O(N). | 493 | /// This operation is O(N). |
| 473 | pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void { | 494 | pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void { |
| 474 | try self.ensureCapacity(allocator, self.items.len + 1); | 495 | try self.ensureUnusedCapacity(allocator, 1); |
| 475 | self.items.len += 1; | 496 | self.items.len += 1; |
| 476 | 497 | ||
| 477 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); | 498 | mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]); |
| ... | @@ -482,7 +503,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -482,7 +503,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 482 | /// higher indicices make room. | 503 | /// higher indicices make room. |
| 483 | /// This operation is O(N). | 504 | /// This operation is O(N). |
| 484 | pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: []const T) !void { | 505 | pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: []const T) !void { |
| 485 | try self.ensureCapacity(allocator, self.items.len + items.len); | 506 | try self.ensureUnusedCapacity(allocator, items.len); |
| 486 | self.items.len += items.len; | 507 | self.items.len += items.len; |
| 487 | 508 | ||
| 488 | mem.copyBackwards(T, self.items[i + items.len .. self.items.len], self.items[i .. self.items.len - items.len]); | 509 | mem.copyBackwards(T, self.items[i + items.len .. self.items.len], self.items[i .. self.items.len - items.len]); |
| ... | @@ -542,7 +563,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -542,7 +563,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 542 | /// Append the slice of items to the list. Allocates more | 563 | /// Append the slice of items to the list. Allocates more |
| 543 | /// memory as necessary. | 564 | /// memory as necessary. |
| 544 | pub fn appendSlice(self: *Self, allocator: *Allocator, items: []const T) !void { | 565 | pub fn appendSlice(self: *Self, allocator: *Allocator, items: []const T) !void { |
| 545 | try self.ensureCapacity(allocator, self.items.len + items.len); | 566 | try self.ensureUnusedCapacity(allocator, items.len); |
| 546 | self.appendSliceAssumeCapacity(items); | 567 | self.appendSliceAssumeCapacity(items); |
| 547 | } | 568 | } |
| 548 | 569 | ||
| ... | @@ -577,7 +598,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -577,7 +598,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 577 | /// Adjust the list's length to `new_len`. | 598 | /// Adjust the list's length to `new_len`. |
| 578 | /// Does not initialize added items, if any. | 599 | /// Does not initialize added items, if any. |
| 579 | pub fn resize(self: *Self, allocator: *Allocator, new_len: usize) !void { | 600 | pub fn resize(self: *Self, allocator: *Allocator, new_len: usize) !void { |
| 580 | try self.ensureCapacity(allocator, new_len); | 601 | try self.ensureTotalCapacity(allocator, new_len); |
| 581 | self.items.len = new_len; | 602 | self.items.len = new_len; |
| 582 | } | 603 | } |
| 583 | 604 | ||
| ... | @@ -602,9 +623,24 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -602,9 +623,24 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 602 | self.items.len = new_len; | 623 | self.items.len = new_len; |
| 603 | } | 624 | } |
| 604 | 625 | ||
| 626 | /// Invalidates all element pointers. | ||
| 627 | pub fn clearRetainingCapacity(self: *Self) void { | ||
| 628 | self.items.len = 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | /// Invalidates all element pointers. | ||
| 632 | pub fn clearAndFree(self: *Self, allocator: *Allocator) void { | ||
| 633 | allocator.free(self.allocatedSlice()); | ||
| 634 | self.items.len = 0; | ||
| 635 | self.capacity = 0; | ||
| 636 | } | ||
| 637 | |||
| 638 | /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`. | ||
| 639 | pub const ensureCapacity = ensureTotalCapacity; | ||
| 640 | |||
| 605 | /// Modify the array so that it can hold at least `new_capacity` items. | 641 | /// Modify the array so that it can hold at least `new_capacity` items. |
| 606 | /// Invalidates pointers if additional memory is needed. | 642 | /// Invalidates pointers if additional memory is needed. |
| 607 | pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { | 643 | pub fn ensureTotalCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void { |
| 608 | var better_capacity = self.capacity; | 644 | var better_capacity = self.capacity; |
| 609 | if (better_capacity >= new_capacity) return; | 645 | if (better_capacity >= new_capacity) return; |
| 610 | 646 | ||
| ... | @@ -618,6 +654,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -618,6 +654,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 618 | self.capacity = new_memory.len; | 654 | self.capacity = new_memory.len; |
| 619 | } | 655 | } |
| 620 | 656 | ||
| 657 | /// Modify the array so that it can hold at least `additional_count` **more** items. | ||
| 658 | /// Invalidates pointers if additional memory is needed. | ||
| 659 | pub fn ensureUnusedCapacity( | ||
| 660 | self: *Self, | ||
| 661 | allocator: *Allocator, | ||
| 662 | additional_count: usize, | ||
| 663 | ) !void { | ||
| 664 | return self.ensureTotalCapacity(allocator, self.items.len + additional_count); | ||
| 665 | } | ||
| 666 | |||
| 621 | /// Increases the array's length to match the full capacity that is already allocated. | 667 | /// Increases the array's length to match the full capacity that is already allocated. |
| 622 | /// The new elements have `undefined` values. | 668 | /// The new elements have `undefined` values. |
| 623 | /// **Does not** invalidate pointers. | 669 | /// **Does not** invalidate pointers. |
| ... | @@ -629,7 +675,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -629,7 +675,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 629 | /// The returned pointer becomes invalid when the list resized. | 675 | /// The returned pointer becomes invalid when the list resized. |
| 630 | pub fn addOne(self: *Self, allocator: *Allocator) !*T { | 676 | pub fn addOne(self: *Self, allocator: *Allocator) !*T { |
| 631 | const newlen = self.items.len + 1; | 677 | const newlen = self.items.len + 1; |
| 632 | try self.ensureCapacity(allocator, newlen); | 678 | try self.ensureTotalCapacity(allocator, newlen); |
| 633 | return self.addOneAssumeCapacity(); | 679 | return self.addOneAssumeCapacity(); |
| 634 | } | 680 | } |
| 635 | 681 | ||
| ... | @@ -1188,7 +1234,7 @@ test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" { | ... | @@ -1188,7 +1234,7 @@ test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" { |
| 1188 | defer list.deinit(); | 1234 | defer list.deinit(); |
| 1189 | 1235 | ||
| 1190 | (try list.addManyAsArray(4)).* = "aoeu".*; | 1236 | (try list.addManyAsArray(4)).* = "aoeu".*; |
| 1191 | try list.ensureCapacity(8); | 1237 | try list.ensureTotalCapacity(8); |
| 1192 | list.addManyAsArrayAssumeCapacity(4).* = "asdf".*; | 1238 | list.addManyAsArrayAssumeCapacity(4).* = "asdf".*; |
| 1193 | 1239 | ||
| 1194 | try testing.expectEqualSlices(u8, list.items, "aoeuasdf"); | 1240 | try testing.expectEqualSlices(u8, list.items, "aoeuasdf"); |
| ... | @@ -1198,7 +1244,7 @@ test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" { | ... | @@ -1198,7 +1244,7 @@ test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" { |
| 1198 | defer list.deinit(a); | 1244 | defer list.deinit(a); |
| 1199 | 1245 | ||
| 1200 | (try list.addManyAsArray(a, 4)).* = "aoeu".*; | 1246 | (try list.addManyAsArray(a, 4)).* = "aoeu".*; |
| 1201 | try list.ensureCapacity(a, 8); | 1247 | try list.ensureTotalCapacity(a, 8); |
| 1202 | list.addManyAsArrayAssumeCapacity(4).* = "asdf".*; | 1248 | list.addManyAsArrayAssumeCapacity(4).* = "asdf".*; |
| 1203 | 1249 | ||
| 1204 | try testing.expectEqualSlices(u8, list.items, "aoeuasdf"); | 1250 | try testing.expectEqualSlices(u8, list.items, "aoeuasdf"); |
lib/std/atomic/queue.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const expect = std.testing.expect; | 9 | const expect = std.testing.expect; |
| 10 | 10 |
lib/std/atomic/stack.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const expect = std.testing.expect; | 8 | const expect = std.testing.expect; |
| 9 | 9 | ||
| 10 | /// Many reader, many writer, non-allocating, thread-safe | 10 | /// Many reader, many writer, non-allocating, thread-safe |
lib/std/build.zig+46-11| ... | @@ -1019,6 +1019,23 @@ pub const Builder = struct { | ... | @@ -1019,6 +1019,23 @@ pub const Builder = struct { |
| 1019 | }; | 1019 | }; |
| 1020 | } | 1020 | } |
| 1021 | 1021 | ||
| 1022 | pub fn truncateFile(self: *Builder, dest_path: []const u8) !void { | ||
| 1023 | if (self.verbose) { | ||
| 1024 | warn("truncate {s}\n", .{dest_path}); | ||
| 1025 | } | ||
| 1026 | const cwd = fs.cwd(); | ||
| 1027 | var src_file = cwd.createFile(dest_path, .{}) catch |err| switch (err) { | ||
| 1028 | error.FileNotFound => blk: { | ||
| 1029 | if (fs.path.dirname(dest_path)) |dirname| { | ||
| 1030 | try cwd.makePath(dirname); | ||
| 1031 | } | ||
| 1032 | break :blk try cwd.createFile(dest_path, .{}); | ||
| 1033 | }, | ||
| 1034 | else => |e| return e, | ||
| 1035 | }; | ||
| 1036 | src_file.close(); | ||
| 1037 | } | ||
| 1038 | |||
| 1022 | pub fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { | 1039 | pub fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 { |
| 1023 | return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable; | 1040 | return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable; |
| 1024 | } | 1041 | } |
| ... | @@ -1415,7 +1432,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1415,7 +1432,7 @@ pub const LibExeObjStep = struct { |
| 1415 | 1432 | ||
| 1416 | red_zone: ?bool = null, | 1433 | red_zone: ?bool = null, |
| 1417 | 1434 | ||
| 1418 | subsystem: ?builtin.SubSystem = null, | 1435 | subsystem: ?std.Target.SubSystem = null, |
| 1419 | 1436 | ||
| 1420 | /// Overrides the default stack size | 1437 | /// Overrides the default stack size |
| 1421 | stack_size: ?u64 = null, | 1438 | stack_size: ?u64 = null, |
| ... | @@ -1967,7 +1984,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1967,7 +1984,7 @@ pub const LibExeObjStep = struct { |
| 1967 | }, | 1984 | }, |
| 1968 | std.builtin.Version => { | 1985 | std.builtin.Version => { |
| 1969 | out.print( | 1986 | out.print( |
| 1970 | \\pub const {}: @import("builtin").Version = .{{ | 1987 | \\pub const {}: @import("std").builtin.Version = .{{ |
| 1971 | \\ .major = {d}, | 1988 | \\ .major = {d}, |
| 1972 | \\ .minor = {d}, | 1989 | \\ .minor = {d}, |
| 1973 | \\ .patch = {d}, | 1990 | \\ .patch = {d}, |
| ... | @@ -2791,17 +2808,23 @@ pub const InstallDirectoryOptions = struct { | ... | @@ -2791,17 +2808,23 @@ pub const InstallDirectoryOptions = struct { |
| 2791 | source_dir: []const u8, | 2808 | source_dir: []const u8, |
| 2792 | install_dir: InstallDir, | 2809 | install_dir: InstallDir, |
| 2793 | install_subdir: []const u8, | 2810 | install_subdir: []const u8, |
| 2794 | exclude_extensions: ?[]const []const u8 = null, | 2811 | /// File paths which end in any of these suffixes will be excluded |
| 2812 | /// from being installed. | ||
| 2813 | exclude_extensions: []const []const u8 = &.{}, | ||
| 2814 | /// File paths which end in any of these suffixes will result in | ||
| 2815 | /// empty files being installed. This is mainly intended for large | ||
| 2816 | /// test.zig files in order to prevent needless installation bloat. | ||
| 2817 | /// However if the files were not present at all, then | ||
| 2818 | /// `@import("test.zig")` would be a compile error. | ||
| 2819 | blank_extensions: []const []const u8 = &.{}, | ||
| 2795 | 2820 | ||
| 2796 | fn dupe(self: InstallDirectoryOptions, b: *Builder) InstallDirectoryOptions { | 2821 | fn dupe(self: InstallDirectoryOptions, b: *Builder) InstallDirectoryOptions { |
| 2797 | return .{ | 2822 | return .{ |
| 2798 | .source_dir = b.dupe(self.source_dir), | 2823 | .source_dir = b.dupe(self.source_dir), |
| 2799 | .install_dir = self.install_dir.dupe(b), | 2824 | .install_dir = self.install_dir.dupe(b), |
| 2800 | .install_subdir = b.dupe(self.install_subdir), | 2825 | .install_subdir = b.dupe(self.install_subdir), |
| 2801 | .exclude_extensions = if (self.exclude_extensions) |extensions| | 2826 | .exclude_extensions = b.dupeStrings(self.exclude_extensions), |
| 2802 | b.dupeStrings(extensions) | 2827 | .blank_extensions = b.dupeStrings(self.blank_extensions), |
| 2803 | else | ||
| 2804 | null, | ||
| 2805 | }; | 2828 | }; |
| 2806 | } | 2829 | } |
| 2807 | }; | 2830 | }; |
| ... | @@ -2829,17 +2852,29 @@ pub const InstallDirStep = struct { | ... | @@ -2829,17 +2852,29 @@ pub const InstallDirStep = struct { |
| 2829 | const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); | 2852 | const full_src_dir = self.builder.pathFromRoot(self.options.source_dir); |
| 2830 | var it = try fs.walkPath(self.builder.allocator, full_src_dir); | 2853 | var it = try fs.walkPath(self.builder.allocator, full_src_dir); |
| 2831 | next_entry: while (try it.next()) |entry| { | 2854 | next_entry: while (try it.next()) |entry| { |
| 2832 | if (self.options.exclude_extensions) |ext_list| for (ext_list) |ext| { | 2855 | for (self.options.exclude_extensions) |ext| { |
| 2833 | if (mem.endsWith(u8, entry.path, ext)) { | 2856 | if (mem.endsWith(u8, entry.path, ext)) { |
| 2834 | continue :next_entry; | 2857 | continue :next_entry; |
| 2835 | } | 2858 | } |
| 2836 | }; | 2859 | } |
| 2837 | 2860 | ||
| 2838 | const rel_path = entry.path[full_src_dir.len + 1 ..]; | 2861 | const rel_path = entry.path[full_src_dir.len + 1 ..]; |
| 2839 | const dest_path = try fs.path.join(self.builder.allocator, &[_][]const u8{ dest_prefix, rel_path }); | 2862 | const dest_path = try fs.path.join(self.builder.allocator, &[_][]const u8{ |
| 2863 | dest_prefix, rel_path, | ||
| 2864 | }); | ||
| 2865 | |||
| 2840 | switch (entry.kind) { | 2866 | switch (entry.kind) { |
| 2841 | .Directory => try fs.cwd().makePath(dest_path), | 2867 | .Directory => try fs.cwd().makePath(dest_path), |
| 2842 | .File => try self.builder.updateFile(entry.path, dest_path), | 2868 | .File => { |
| 2869 | for (self.options.blank_extensions) |ext| { | ||
| 2870 | if (mem.endsWith(u8, entry.path, ext)) { | ||
| 2871 | try self.builder.truncateFile(dest_path); | ||
| 2872 | continue :next_entry; | ||
| 2873 | } | ||
| 2874 | } | ||
| 2875 | |||
| 2876 | try self.builder.updateFile(entry.path, dest_path); | ||
| 2877 | }, | ||
| 2843 | else => continue, | 2878 | else => continue, |
| 2844 | } | 2879 | } |
| 2845 | } | 2880 | } |
lib/std/builtin.zig+29-28| ... | @@ -3,39 +3,40 @@ | ... | @@ -3,39 +3,40 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | pub usingnamespace @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | /// Deprecated: use `std.Target`. | 8 | // These are all deprecated. |
| 9 | pub const Target = std.Target; | 9 | pub const zig_version = builtin.zig_version; |
| 10 | 10 | pub const zig_is_stage2 = builtin.zig_is_stage2; | |
| 11 | /// Deprecated: use `std.Target.Os`. | 11 | pub const output_mode = builtin.output_mode; |
| 12 | pub const Os = std.Target.Os; | 12 | pub const link_mode = builtin.link_mode; |
| 13 | 13 | pub const is_test = builtin.is_test; | |
| 14 | /// Deprecated: use `std.Target.Cpu.Arch`. | 14 | pub const single_threaded = builtin.single_threaded; |
| 15 | pub const Arch = std.Target.Cpu.Arch; | 15 | pub const abi = builtin.abi; |
| 16 | 16 | pub const cpu = builtin.cpu; | |
| 17 | /// Deprecated: use `std.Target.Abi`. | 17 | pub const os = builtin.os; |
| 18 | pub const Abi = std.Target.Abi; | 18 | pub const target = builtin.target; |
| 19 | 19 | pub const object_format = builtin.object_format; | |
| 20 | /// Deprecated: use `std.Target.ObjectFormat`. | 20 | pub const mode = builtin.mode; |
| 21 | pub const ObjectFormat = std.Target.ObjectFormat; | 21 | pub const link_libc = builtin.link_libc; |
| 22 | 22 | pub const link_libcpp = builtin.link_libcpp; | |
| 23 | /// Deprecated: use `std.Target.SubSystem`. | 23 | pub const have_error_return_tracing = builtin.have_error_return_tracing; |
| 24 | pub const SubSystem = std.Target.SubSystem; | 24 | pub const valgrind_support = builtin.valgrind_support; |
| 25 | 25 | pub const position_independent_code = builtin.position_independent_code; | |
| 26 | /// Deprecated: use `std.Target.Cpu`. | 26 | pub const position_independent_executable = builtin.position_independent_executable; |
| 27 | pub const Cpu = std.Target.Cpu; | 27 | pub const strip_debug_info = builtin.strip_debug_info; |
| 28 | pub const code_model = builtin.code_model; | ||
| 28 | 29 | ||
| 29 | /// `explicit_subsystem` is missing when the subsystem is automatically detected, | 30 | /// `explicit_subsystem` is missing when the subsystem is automatically detected, |
| 30 | /// so Zig standard library has the subsystem detection logic here. This should generally be | 31 | /// so Zig standard library has the subsystem detection logic here. This should generally be |
| 31 | /// used rather than `explicit_subsystem`. | 32 | /// used rather than `explicit_subsystem`. |
| 32 | /// On non-Windows targets, this is `null`. | 33 | /// On non-Windows targets, this is `null`. |
| 33 | pub const subsystem: ?SubSystem = blk: { | 34 | pub const subsystem: ?std.Target.SubSystem = blk: { |
| 34 | if (@hasDecl(@This(), "explicit_subsystem")) break :blk explicit_subsystem; | 35 | if (@hasDecl(builtin, "explicit_subsystem")) break :blk explicit_subsystem; |
| 35 | switch (os.tag) { | 36 | switch (os.tag) { |
| 36 | .windows => { | 37 | .windows => { |
| 37 | if (is_test) { | 38 | if (is_test) { |
| 38 | break :blk SubSystem.Console; | 39 | break :blk std.Target.SubSystem.Console; |
| 39 | } | 40 | } |
| 40 | if (@hasDecl(root, "main") or | 41 | if (@hasDecl(root, "main") or |
| 41 | @hasDecl(root, "WinMain") or | 42 | @hasDecl(root, "WinMain") or |
| ... | @@ -43,9 +44,9 @@ pub const subsystem: ?SubSystem = blk: { | ... | @@ -43,9 +44,9 @@ pub const subsystem: ?SubSystem = blk: { |
| 43 | @hasDecl(root, "WinMainCRTStartup") or | 44 | @hasDecl(root, "WinMainCRTStartup") or |
| 44 | @hasDecl(root, "wWinMainCRTStartup")) | 45 | @hasDecl(root, "wWinMainCRTStartup")) |
| 45 | { | 46 | { |
| 46 | break :blk SubSystem.Windows; | 47 | break :blk std.Target.SubSystem.Windows; |
| 47 | } else { | 48 | } else { |
| 48 | break :blk SubSystem.Console; | 49 | break :blk std.Target.SubSystem.Console; |
| 49 | } | 50 | } |
| 50 | }, | 51 | }, |
| 51 | else => break :blk null, | 52 | else => break :blk null, |
| ... | @@ -262,7 +263,7 @@ pub const TypeInfo = union(enum) { | ... | @@ -262,7 +263,7 @@ pub const TypeInfo = union(enum) { |
| 262 | 263 | ||
| 263 | /// This data structure is used by the Zig language code generation and | 264 | /// This data structure is used by the Zig language code generation and |
| 264 | /// therefore must be kept in sync with the compiler implementation. | 265 | /// therefore must be kept in sync with the compiler implementation. |
| 265 | pub const ContainerLayout = enum { | 266 | pub const ContainerLayout = enum(u2) { |
| 266 | Auto, | 267 | Auto, |
| 267 | Extern, | 268 | Extern, |
| 268 | Packed, | 269 | Packed, |
lib/std/c/darwin.zig+4-3| ... | @@ -7,6 +7,7 @@ const std = @import("../std.zig"); | ... | @@ -7,6 +7,7 @@ const std = @import("../std.zig"); |
| 7 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const builtin = @import("builtin"); | 8 | const builtin = @import("builtin"); |
| 9 | const macho = std.macho; | 9 | const macho = std.macho; |
| 10 | const native_arch = builtin.target.cpu.arch; | ||
| 10 | 11 | ||
| 11 | usingnamespace @import("../os/bits.zig"); | 12 | usingnamespace @import("../os/bits.zig"); |
| 12 | 13 | ||
| ... | @@ -34,13 +35,13 @@ extern "c" fn fstat(fd: fd_t, buf: *libc_stat) c_int; | ... | @@ -34,13 +35,13 @@ extern "c" fn fstat(fd: fd_t, buf: *libc_stat) c_int; |
| 34 | /// On x86_64 Darwin, fstat has to be manully linked with $INODE64 suffix to force 64bit version. | 35 | /// On x86_64 Darwin, fstat has to be manully linked with $INODE64 suffix to force 64bit version. |
| 35 | /// Note that this is fixed on aarch64 and no longer necessary. | 36 | /// Note that this is fixed on aarch64 and no longer necessary. |
| 36 | extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *libc_stat) c_int; | 37 | extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *libc_stat) c_int; |
| 37 | pub const _fstat = if (builtin.arch == .aarch64) fstat else @"fstat$INODE64"; | 38 | pub const _fstat = if (native_arch == .aarch64) fstat else @"fstat$INODE64"; |
| 38 | 39 | ||
| 39 | extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int; | 40 | extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int; |
| 40 | /// On x86_64 Darwin, fstatat has to be manully linked with $INODE64 suffix to force 64bit version. | 41 | /// On x86_64 Darwin, fstatat has to be manully linked with $INODE64 suffix to force 64bit version. |
| 41 | /// Note that this is fixed on aarch64 and no longer necessary. | 42 | /// Note that this is fixed on aarch64 and no longer necessary. |
| 42 | extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *libc_stat, flags: u32) c_int; | 43 | extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *libc_stat, flags: u32) c_int; |
| 43 | pub const _fstatat = if (builtin.arch == .aarch64) fstatat else @"fstatat$INODE64"; | 44 | pub const _fstatat = if (native_arch == .aarch64) fstatat else @"fstatat$INODE64"; |
| 44 | 45 | ||
| 45 | pub extern "c" fn mach_absolute_time() u64; | 46 | pub extern "c" fn mach_absolute_time() u64; |
| 46 | pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; | 47 | pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; |
| ... | @@ -121,7 +122,7 @@ pub const AI_NUMERICHOST = 0x00000004; | ... | @@ -121,7 +122,7 @@ pub const AI_NUMERICHOST = 0x00000004; |
| 121 | /// prevent service name resolution | 122 | /// prevent service name resolution |
| 122 | pub const AI_NUMERICSERV = 0x00001000; | 123 | pub const AI_NUMERICSERV = 0x00001000; |
| 123 | 124 | ||
| 124 | pub const EAI = extern enum(c_int) { | 125 | pub const EAI = enum(c_int) { |
| 125 | /// address family for hostname not supported | 126 | /// address family for hostname not supported |
| 126 | ADDRFAMILY = 1, | 127 | ADDRFAMILY = 1, |
| 127 | 128 |
lib/std/c/freebsd.zig+1-1| ... | @@ -62,7 +62,7 @@ pub const sem_t = extern struct { | ... | @@ -62,7 +62,7 @@ pub const sem_t = extern struct { |
| 62 | _padding: u32, | 62 | _padding: u32, |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | pub const EAI = extern enum(c_int) { | 65 | pub const EAI = enum(c_int) { |
| 66 | /// address family for hostname not supported | 66 | /// address family for hostname not supported |
| 67 | ADDRFAMILY = 1, | 67 | ADDRFAMILY = 1, |
| 68 | 68 |
lib/std/c/haiku.zig+1-1| ... | @@ -70,7 +70,7 @@ pub const pthread_rwlock_t = extern struct { | ... | @@ -70,7 +70,7 @@ pub const pthread_rwlock_t = extern struct { |
| 70 | waiters: [2]?*c_void = [_]?*c_void{ null, null }, | 70 | waiters: [2]?*c_void = [_]?*c_void{ null, null }, |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | pub const EAI = extern enum(c_int) { | 73 | pub const EAI = enum(c_int) { |
| 74 | /// address family for hostname not supported | 74 | /// address family for hostname not supported |
| 75 | ADDRFAMILY = 1, | 75 | ADDRFAMILY = 1, |
| 76 | 76 |
lib/std/c/linux.zig+9-7| ... | @@ -3,12 +3,14 @@ | ... | @@ -3,12 +3,14 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | ||
| 7 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 8 | const maxInt = std.math.maxInt; | 7 | const maxInt = std.math.maxInt; |
| 8 | const abi = std.Target.current.abi; | ||
| 9 | const arch = std.Target.current.cpu.arch; | ||
| 10 | const os_tag = std.Target.current.os.tag; | ||
| 9 | usingnamespace std.c; | 11 | usingnamespace std.c; |
| 10 | 12 | ||
| 11 | pub const _errno = switch (builtin.abi) { | 13 | pub const _errno = switch (abi) { |
| 12 | .android => struct { | 14 | .android => struct { |
| 13 | extern "c" var __errno: c_int; | 15 | extern "c" var __errno: c_int; |
| 14 | fn getErrno() *c_int { | 16 | fn getErrno() *c_int { |
| ... | @@ -37,7 +39,7 @@ pub const NI_NAMEREQD = 0x08; | ... | @@ -37,7 +39,7 @@ pub const NI_NAMEREQD = 0x08; |
| 37 | pub const NI_DGRAM = 0x10; | 39 | pub const NI_DGRAM = 0x10; |
| 38 | pub const NI_NUMERICSCOPE = 0x100; | 40 | pub const NI_NUMERICSCOPE = 0x100; |
| 39 | 41 | ||
| 40 | pub const EAI = extern enum(c_int) { | 42 | pub const EAI = enum(c_int) { |
| 41 | BADFLAGS = -1, | 43 | BADFLAGS = -1, |
| 42 | NONAME = -2, | 44 | NONAME = -2, |
| 43 | AGAIN = -3, | 45 | AGAIN = -3, |
| ... | @@ -139,7 +141,7 @@ pub const pthread_mutex_t = extern struct { | ... | @@ -139,7 +141,7 @@ pub const pthread_mutex_t = extern struct { |
| 139 | pub const pthread_cond_t = extern struct { | 141 | pub const pthread_cond_t = extern struct { |
| 140 | size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T, | 142 | size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T, |
| 141 | }; | 143 | }; |
| 142 | pub const pthread_rwlock_t = switch (std.builtin.abi) { | 144 | pub const pthread_rwlock_t = switch (abi) { |
| 143 | .android => switch (@sizeOf(usize)) { | 145 | .android => switch (@sizeOf(usize)) { |
| 144 | 4 => extern struct { | 146 | 4 => extern struct { |
| 145 | lock: std.c.pthread_mutex_t = std.c.PTHREAD_MUTEX_INITIALIZER, | 147 | lock: std.c.pthread_mutex_t = std.c.PTHREAD_MUTEX_INITIALIZER, |
| ... | @@ -170,11 +172,11 @@ pub const sem_t = extern struct { | ... | @@ -170,11 +172,11 @@ pub const sem_t = extern struct { |
| 170 | }; | 172 | }; |
| 171 | 173 | ||
| 172 | const __SIZEOF_PTHREAD_COND_T = 48; | 174 | const __SIZEOF_PTHREAD_COND_T = 48; |
| 173 | const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) { | 175 | const __SIZEOF_PTHREAD_MUTEX_T = if (os_tag == .fuchsia) 40 else switch (abi) { |
| 174 | .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24, | 176 | .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24, |
| 175 | .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) { | 177 | .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (arch) { |
| 176 | .aarch64 => 48, | 178 | .aarch64 => 48, |
| 177 | .x86_64 => if (builtin.abi == .gnux32) 40 else 32, | 179 | .x86_64 => if (abi == .gnux32) 40 else 32, |
| 178 | .mips64, .powerpc64, .powerpc64le, .sparcv9 => 40, | 180 | .mips64, .powerpc64, .powerpc64le, .sparcv9 => 40, |
| 179 | else => if (@sizeOf(usize) == 8) 40 else 24, | 181 | else => if (@sizeOf(usize) == 8) 40 else 24, |
| 180 | }, | 182 | }, |
lib/std/child_process.zig+1-1| ... | @@ -15,7 +15,7 @@ const windows = os.windows; | ... | @@ -15,7 +15,7 @@ const windows = os.windows; |
| 15 | const mem = std.mem; | 15 | const mem = std.mem; |
| 16 | const debug = std.debug; | 16 | const debug = std.debug; |
| 17 | const BufMap = std.BufMap; | 17 | const BufMap = std.BufMap; |
| 18 | const builtin = @import("builtin"); | 18 | const builtin = std.builtin; |
| 19 | const Os = builtin.Os; | 19 | const Os = builtin.Os; |
| 20 | const TailQueue = std.TailQueue; | 20 | const TailQueue = std.TailQueue; |
| 21 | const maxInt = std.math.maxInt; | 21 | const maxInt = std.math.maxInt; |
lib/std/coff.zig+1-1| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | const std = @import("std.zig"); | 7 | const std = @import("std.zig"); |
| 8 | const io = std.io; | 8 | const io = std.io; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
lib/std/crypto/25519/curve25519.zig+1-1| ... | @@ -102,7 +102,7 @@ pub const Curve25519 = struct { | ... | @@ -102,7 +102,7 @@ pub const Curve25519 = struct { |
| 102 | /// key is a low-order point. | 102 | /// key is a low-order point. |
| 103 | pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 { | 103 | pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 { |
| 104 | const cofactor = [_]u8{8} ++ [_]u8{0} ** 31; | 104 | const cofactor = [_]u8{8} ++ [_]u8{0} ** 31; |
| 105 | _ = ladder(p, cofactor, 4) catch |_| return error.WeakPublicKey; | 105 | _ = ladder(p, cofactor, 4) catch return error.WeakPublicKey; |
| 106 | return try ladder(p, s, 256); | 106 | return try ladder(p, s, 256); |
| 107 | } | 107 | } |
| 108 | 108 |
lib/std/crypto/25519/edwards25519.zig+4-4| ... | @@ -226,12 +226,12 @@ pub const Edwards25519 = struct { | ... | @@ -226,12 +226,12 @@ pub const Edwards25519 = struct { |
| 226 | return pc; | 226 | return pc; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | const basePointPc = comptime pc: { | 229 | const basePointPc = pc: { |
| 230 | @setEvalBranchQuota(10000); | 230 | @setEvalBranchQuota(10000); |
| 231 | break :pc precompute(Edwards25519.basePoint, 15); | 231 | break :pc precompute(Edwards25519.basePoint, 15); |
| 232 | }; | 232 | }; |
| 233 | 233 | ||
| 234 | const basePointPc8 = comptime pc: { | 234 | const basePointPc8 = pc: { |
| 235 | @setEvalBranchQuota(10000); | 235 | @setEvalBranchQuota(10000); |
| 236 | break :pc precompute(Edwards25519.basePoint, 8); | 236 | break :pc precompute(Edwards25519.basePoint, 8); |
| 237 | }; | 237 | }; |
| ... | @@ -255,7 +255,7 @@ pub const Edwards25519 = struct { | ... | @@ -255,7 +255,7 @@ pub const Edwards25519 = struct { |
| 255 | return pcMul16(basePointPc, s, true); | 255 | return pcMul16(basePointPc, s, true); |
| 256 | } else { | 256 | } else { |
| 257 | const pc = precompute(p, 8); | 257 | const pc = precompute(p, 8); |
| 258 | pc[4].rejectIdentity() catch |_| return error.WeakPublicKey; | 258 | pc[4].rejectIdentity() catch return error.WeakPublicKey; |
| 259 | return pcMul(pc, s, true); | 259 | return pcMul(pc, s, true); |
| 260 | } | 260 | } |
| 261 | } | 261 | } |
| ... | @@ -306,7 +306,7 @@ pub const Edwards25519 = struct { | ... | @@ -306,7 +306,7 @@ pub const Edwards25519 = struct { |
| 306 | pcs[i] = basePointPc8; | 306 | pcs[i] = basePointPc8; |
| 307 | } else { | 307 | } else { |
| 308 | pcs[i] = precompute(p, 8); | 308 | pcs[i] = precompute(p, 8); |
| 309 | pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey; | 309 | pcs[i][4].rejectIdentity() catch return error.WeakPublicKey; |
| 310 | } | 310 | } |
| 311 | } | 311 | } |
| 312 | var es: [count][2 * 32]i8 = undefined; | 312 | var es: [count][2 * 32]i8 = undefined; |
lib/std/crypto/aes.zig+3-3| ... | @@ -8,9 +8,9 @@ const std = @import("../std.zig"); | ... | @@ -8,9 +8,9 @@ const std = @import("../std.zig"); |
| 8 | const testing = std.testing; | 8 | const testing = std.testing; |
| 9 | const builtin = std.builtin; | 9 | const builtin = std.builtin; |
| 10 | 10 | ||
| 11 | const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes); | 11 | const has_aesni = std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes); |
| 12 | const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx); | 12 | const has_avx = std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx); |
| 13 | const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); | 13 | const has_armaes = std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); |
| 14 | const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) impl: { | 14 | const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) impl: { |
| 15 | break :impl @import("aes/aesni.zig"); | 15 | break :impl @import("aes/aesni.zig"); |
| 16 | } else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) | 16 | } else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) |
lib/std/crypto/aes_ocb.zig+2-2| ... | @@ -106,8 +106,8 @@ fn AesOcb(comptime Aes: anytype) type { | ... | @@ -106,8 +106,8 @@ fn AesOcb(comptime Aes: anytype) type { |
| 106 | return offset; | 106 | return offset; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes); | 109 | const has_aesni = std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes); |
| 110 | const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); | 110 | const has_armaes = std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); |
| 111 | const wb: usize = if ((std.Target.current.cpu.arch == .x86_64 and has_aesni) or (std.Target.current.cpu.arch == .aarch64 and has_armaes)) 4 else 0; | 111 | const wb: usize = if ((std.Target.current.cpu.arch == .x86_64 and has_aesni) or (std.Target.current.cpu.arch == .aarch64 and has_armaes)) 4 else 0; |
| 112 | 112 | ||
| 113 | /// c: ciphertext: output buffer should be of size m.len | 113 | /// c: ciphertext: output buffer should be of size m.len |
lib/std/crypto/ghash.zig+3-3| ... | @@ -137,9 +137,9 @@ pub const Ghash = struct { | ... | @@ -137,9 +137,9 @@ pub const Ghash = struct { |
| 137 | return z0 | z1 | z2 | z3; | 137 | return z0 | z1 | z2 | z3; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul); | 140 | const has_pclmul = std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul); |
| 141 | const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx); | 141 | const has_avx = std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx); |
| 142 | const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); | 142 | const has_armaes = std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); |
| 143 | const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) impl: { | 143 | const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) impl: { |
| 144 | break :impl clmul_pclmul; | 144 | break :impl clmul_pclmul; |
| 145 | } else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) impl: { | 145 | } else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) impl: { |
lib/std/crypto/modes.zig+1-1| ... | @@ -16,7 +16,7 @@ const debug = std.debug; | ... | @@ -16,7 +16,7 @@ const debug = std.debug; |
| 16 | /// | 16 | /// |
| 17 | /// Important: the counter mode doesn't provide authenticated encryption: the ciphertext can be trivially modified without this being detected. | 17 | /// Important: the counter mode doesn't provide authenticated encryption: the ciphertext can be trivially modified without this being detected. |
| 18 | /// As a result, applications should generally never use it directly, but only in a construction that includes a MAC. | 18 | /// As a result, applications should generally never use it directly, but only in a construction that includes a MAC. |
| 19 | pub fn ctr(comptime BlockCipher: anytype, block_cipher: BlockCipher, dst: []u8, src: []const u8, iv: [BlockCipher.block_length]u8, endian: comptime builtin.Endian) void { | 19 | pub fn ctr(comptime BlockCipher: anytype, block_cipher: BlockCipher, dst: []u8, src: []const u8, iv: [BlockCipher.block_length]u8, endian: builtin.Endian) void { |
| 20 | debug.assert(dst.len >= src.len); | 20 | debug.assert(dst.len >= src.len); |
| 21 | const block_length = BlockCipher.block_length; | 21 | const block_length = BlockCipher.block_length; |
| 22 | var counter: [BlockCipher.block_length]u8 = undefined; | 22 | var counter: [BlockCipher.block_length]u8 = undefined; |
lib/std/crypto/pcurves/common.zig+1-1| ... | @@ -43,7 +43,7 @@ pub fn Field(comptime params: FieldParams) type { | ... | @@ -43,7 +43,7 @@ pub fn Field(comptime params: FieldParams) type { |
| 43 | pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) }; | 43 | pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) }; |
| 44 | 44 | ||
| 45 | /// One. | 45 | /// One. |
| 46 | pub const one = comptime one: { | 46 | pub const one = one: { |
| 47 | var fe: Fe = undefined; | 47 | var fe: Fe = undefined; |
| 48 | fiat.setOne(&fe.limbs); | 48 | fiat.setOne(&fe.limbs); |
| 49 | break :one fe; | 49 | break :one fe; |
lib/std/crypto/pcurves/p256.zig+5-5| ... | @@ -30,8 +30,8 @@ pub const P256 = struct { | ... | @@ -30,8 +30,8 @@ pub const P256 = struct { |
| 30 | 30 | ||
| 31 | /// The P256 base point. | 31 | /// The P256 base point. |
| 32 | pub const basePoint = P256{ | 32 | pub const basePoint = P256{ |
| 33 | .x = try Fe.fromInt(48439561293906451759052585252797914202762949526041747995844080717082404635286), | 33 | .x = Fe.fromInt(48439561293906451759052585252797914202762949526041747995844080717082404635286) catch unreachable, |
| 34 | .y = try Fe.fromInt(36134250956749795798585127919587881956611106672985015071877198253568414405109), | 34 | .y = Fe.fromInt(36134250956749795798585127919587881956611106672985015071877198253568414405109) catch unreachable, |
| 35 | .z = Fe.one, | 35 | .z = Fe.one, |
| 36 | .is_base = true, | 36 | .is_base = true, |
| 37 | }; | 37 | }; |
| ... | @@ -39,7 +39,7 @@ pub const P256 = struct { | ... | @@ -39,7 +39,7 @@ pub const P256 = struct { |
| 39 | /// The P256 neutral element. | 39 | /// The P256 neutral element. |
| 40 | pub const identityElement = P256{ .x = Fe.zero, .y = Fe.one, .z = Fe.zero }; | 40 | pub const identityElement = P256{ .x = Fe.zero, .y = Fe.one, .z = Fe.zero }; |
| 41 | 41 | ||
| 42 | pub const B = try Fe.fromInt(41058363725152142129326129780047268409114441015993725554835256314039467401291); | 42 | pub const B = Fe.fromInt(41058363725152142129326129780047268409114441015993725554835256314039467401291) catch unreachable; |
| 43 | 43 | ||
| 44 | /// Reject the neutral element. | 44 | /// Reject the neutral element. |
| 45 | pub fn rejectIdentity(p: P256) IdentityElementError!void { | 45 | pub fn rejectIdentity(p: P256) IdentityElementError!void { |
| ... | @@ -390,12 +390,12 @@ pub const P256 = struct { | ... | @@ -390,12 +390,12 @@ pub const P256 = struct { |
| 390 | return pc; | 390 | return pc; |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | const basePointPc = comptime pc: { | 393 | const basePointPc = pc: { |
| 394 | @setEvalBranchQuota(50000); | 394 | @setEvalBranchQuota(50000); |
| 395 | break :pc precompute(P256.basePoint, 15); | 395 | break :pc precompute(P256.basePoint, 15); |
| 396 | }; | 396 | }; |
| 397 | 397 | ||
| 398 | const basePointPc8 = comptime pc: { | 398 | const basePointPc8 = pc: { |
| 399 | @setEvalBranchQuota(50000); | 399 | @setEvalBranchQuota(50000); |
| 400 | break :pc precompute(P256.basePoint, 8); | 400 | break :pc precompute(P256.basePoint, 8); |
| 401 | }; | 401 | }; |
lib/std/crypto/tlcsprng.zig+1-1| ... | @@ -111,7 +111,7 @@ fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void { | ... | @@ -111,7 +111,7 @@ fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void { |
| 111 | wipe_mem.ptr, | 111 | wipe_mem.ptr, |
| 112 | wipe_mem.len, | 112 | wipe_mem.len, |
| 113 | os.MADV_WIPEONFORK, | 113 | os.MADV_WIPEONFORK, |
| 114 | ) catch |_| { | 114 | ) catch { |
| 115 | return initAndFill(buffer); | 115 | return initAndFill(buffer); |
| 116 | }; | 116 | }; |
| 117 | } | 117 | } |
lib/std/crypto/utils.zig+7-7| ... | @@ -20,9 +20,9 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { | ... | @@ -20,9 +20,9 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { |
| 20 | for (a) |x, i| { | 20 | for (a) |x, i| { |
| 21 | acc |= x ^ b[i]; | 21 | acc |= x ^ b[i]; |
| 22 | } | 22 | } |
| 23 | comptime const s = @typeInfo(C).Int.bits; | 23 | const s = @typeInfo(C).Int.bits; |
| 24 | comptime const Cu = std.meta.Int(.unsigned, s); | 24 | const Cu = std.meta.Int(.unsigned, s); |
| 25 | comptime const Cext = std.meta.Int(.unsigned, s + 1); | 25 | const Cext = std.meta.Int(.unsigned, s + 1); |
| 26 | return @bitCast(bool, @truncate(u1, (@as(Cext, @bitCast(Cu, acc)) -% 1) >> s)); | 26 | return @bitCast(bool, @truncate(u1, (@as(Cext, @bitCast(Cu, acc)) -% 1) >> s)); |
| 27 | }, | 27 | }, |
| 28 | .Vector => |info| { | 28 | .Vector => |info| { |
| ... | @@ -31,9 +31,9 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { | ... | @@ -31,9 +31,9 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { |
| 31 | @compileError("Elements to be compared must be integers"); | 31 | @compileError("Elements to be compared must be integers"); |
| 32 | } | 32 | } |
| 33 | const acc = @reduce(.Or, a ^ b); | 33 | const acc = @reduce(.Or, a ^ b); |
| 34 | comptime const s = @typeInfo(C).Int.bits; | 34 | const s = @typeInfo(C).Int.bits; |
| 35 | comptime const Cu = std.meta.Int(.unsigned, s); | 35 | const Cu = std.meta.Int(.unsigned, s); |
| 36 | comptime const Cext = std.meta.Int(.unsigned, s + 1); | 36 | const Cext = std.meta.Int(.unsigned, s + 1); |
| 37 | return @bitCast(bool, @truncate(u1, (@as(Cext, @bitCast(Cu, acc)) -% 1) >> s)); | 37 | return @bitCast(bool, @truncate(u1, (@as(Cext, @bitCast(Cu, acc)) -% 1) >> s)); |
| 38 | }, | 38 | }, |
| 39 | else => { | 39 | else => { |
| ... | @@ -50,7 +50,7 @@ pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: E | ... | @@ -50,7 +50,7 @@ pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: E |
| 50 | .Int => |cinfo| if (cinfo.signedness != .unsigned) @compileError("Elements to be compared must be unsigned") else cinfo.bits, | 50 | .Int => |cinfo| if (cinfo.signedness != .unsigned) @compileError("Elements to be compared must be unsigned") else cinfo.bits, |
| 51 | else => @compileError("Elements to be compared must be integers"), | 51 | else => @compileError("Elements to be compared must be integers"), |
| 52 | }; | 52 | }; |
| 53 | comptime const Cext = std.meta.Int(.unsigned, bits + 1); | 53 | const Cext = std.meta.Int(.unsigned, bits + 1); |
| 54 | var gt: T = 0; | 54 | var gt: T = 0; |
| 55 | var eq: T = 1; | 55 | var eq: T = 1; |
| 56 | if (endian == .Little) { | 56 | if (endian == .Little) { |
lib/std/cstr.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const debug = std.debug; | 8 | const debug = std.debug; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const testing = std.testing; | 10 | const testing = std.testing; |
lib/std/debug.zig+26-23| ... | @@ -21,6 +21,9 @@ const root = @import("root"); | ... | @@ -21,6 +21,9 @@ const root = @import("root"); |
| 21 | const maxInt = std.math.maxInt; | 21 | const maxInt = std.math.maxInt; |
| 22 | const File = std.fs.File; | 22 | const File = std.fs.File; |
| 23 | const windows = std.os.windows; | 23 | const windows = std.os.windows; |
| 24 | const native_arch = std.Target.current.cpu.arch; | ||
| 25 | const native_os = std.Target.current.os.tag; | ||
| 26 | const native_endian = native_arch.endian(); | ||
| 24 | 27 | ||
| 25 | pub const runtime_safety = switch (builtin.mode) { | 28 | pub const runtime_safety = switch (builtin.mode) { |
| 26 | .Debug, .ReleaseSafe => true, | 29 | .Debug, .ReleaseSafe => true, |
| ... | @@ -90,7 +93,7 @@ pub fn detectTTYConfig() TTY.Config { | ... | @@ -90,7 +93,7 @@ pub fn detectTTYConfig() TTY.Config { |
| 90 | const stderr_file = io.getStdErr(); | 93 | const stderr_file = io.getStdErr(); |
| 91 | if (stderr_file.supportsAnsiEscapeCodes()) { | 94 | if (stderr_file.supportsAnsiEscapeCodes()) { |
| 92 | return .escape_codes; | 95 | return .escape_codes; |
| 93 | } else if (builtin.os.tag == .windows and stderr_file.isTty()) { | 96 | } else if (native_os == .windows and stderr_file.isTty()) { |
| 94 | return .windows_api; | 97 | return .windows_api; |
| 95 | } else { | 98 | } else { |
| 96 | return .no_color; | 99 | return .no_color; |
| ... | @@ -148,7 +151,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { | ... | @@ -148,7 +151,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { |
| 148 | /// chopping off the irrelevant frames and shifting so that the returned addresses pointer | 151 | /// chopping off the irrelevant frames and shifting so that the returned addresses pointer |
| 149 | /// equals the passed in addresses pointer. | 152 | /// equals the passed in addresses pointer. |
| 150 | pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { | 153 | pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { |
| 151 | if (builtin.os.tag == .windows) { | 154 | if (native_os == .windows) { |
| 152 | const addrs = stack_trace.instruction_addresses; | 155 | const addrs = stack_trace.instruction_addresses; |
| 153 | const u32_addrs_len = @intCast(u32, addrs.len); | 156 | const u32_addrs_len = @intCast(u32, addrs.len); |
| 154 | const first_addr = first_address orelse { | 157 | const first_addr = first_address orelse { |
| ... | @@ -226,7 +229,7 @@ pub fn assert(ok: bool) void { | ... | @@ -226,7 +229,7 @@ pub fn assert(ok: bool) void { |
| 226 | pub fn panic(comptime format: []const u8, args: anytype) noreturn { | 229 | pub fn panic(comptime format: []const u8, args: anytype) noreturn { |
| 227 | @setCold(true); | 230 | @setCold(true); |
| 228 | // TODO: remove conditional once wasi / LLVM defines __builtin_return_address | 231 | // TODO: remove conditional once wasi / LLVM defines __builtin_return_address |
| 229 | const first_trace_addr = if (builtin.os.tag == .wasi) null else @returnAddress(); | 232 | const first_trace_addr = if (native_os == .wasi) null else @returnAddress(); |
| 230 | panicExtra(null, first_trace_addr, format, args); | 233 | panicExtra(null, first_trace_addr, format, args); |
| 231 | } | 234 | } |
| 232 | 235 | ||
| ... | @@ -337,7 +340,7 @@ pub const StackIterator = struct { | ... | @@ -337,7 +340,7 @@ pub const StackIterator = struct { |
| 337 | fp: usize, | 340 | fp: usize, |
| 338 | 341 | ||
| 339 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { | 342 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| 340 | if (builtin.arch == .sparcv9) { | 343 | if (native_arch == .sparcv9) { |
| 341 | // Flush all the register windows on stack. | 344 | // Flush all the register windows on stack. |
| 342 | asm volatile ( | 345 | asm volatile ( |
| 343 | \\ flushw | 346 | \\ flushw |
| ... | @@ -351,25 +354,25 @@ pub const StackIterator = struct { | ... | @@ -351,25 +354,25 @@ pub const StackIterator = struct { |
| 351 | } | 354 | } |
| 352 | 355 | ||
| 353 | // Offset of the saved BP wrt the frame pointer. | 356 | // Offset of the saved BP wrt the frame pointer. |
| 354 | const fp_offset = if (comptime builtin.arch.isRISCV()) | 357 | const fp_offset = if (native_arch.isRISCV()) |
| 355 | // On RISC-V the frame pointer points to the top of the saved register | 358 | // On RISC-V the frame pointer points to the top of the saved register |
| 356 | // area, on pretty much every other architecture it points to the stack | 359 | // area, on pretty much every other architecture it points to the stack |
| 357 | // slot where the previous frame pointer is saved. | 360 | // slot where the previous frame pointer is saved. |
| 358 | 2 * @sizeOf(usize) | 361 | 2 * @sizeOf(usize) |
| 359 | else if (comptime builtin.arch.isSPARC()) | 362 | else if (native_arch.isSPARC()) |
| 360 | // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. | 363 | // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. |
| 361 | 14 * @sizeOf(usize) | 364 | 14 * @sizeOf(usize) |
| 362 | else | 365 | else |
| 363 | 0; | 366 | 0; |
| 364 | 367 | ||
| 365 | const fp_bias = if (comptime builtin.arch.isSPARC()) | 368 | const fp_bias = if (native_arch.isSPARC()) |
| 366 | // On SPARC frame pointers are biased by a constant. | 369 | // On SPARC frame pointers are biased by a constant. |
| 367 | 2047 | 370 | 2047 |
| 368 | else | 371 | else |
| 369 | 0; | 372 | 0; |
| 370 | 373 | ||
| 371 | // Positive offset of the saved PC wrt the frame pointer. | 374 | // Positive offset of the saved PC wrt the frame pointer. |
| 372 | const pc_offset = if (builtin.arch == .powerpc64le) | 375 | const pc_offset = if (native_arch == .powerpc64le) |
| 373 | 2 * @sizeOf(usize) | 376 | 2 * @sizeOf(usize) |
| 374 | else | 377 | else |
| 375 | @sizeOf(usize); | 378 | @sizeOf(usize); |
| ... | @@ -388,7 +391,7 @@ pub const StackIterator = struct { | ... | @@ -388,7 +391,7 @@ pub const StackIterator = struct { |
| 388 | } | 391 | } |
| 389 | 392 | ||
| 390 | fn next_internal(self: *StackIterator) ?usize { | 393 | fn next_internal(self: *StackIterator) ?usize { |
| 391 | const fp = if (comptime builtin.arch.isSPARC()) | 394 | const fp = if (comptime native_arch.isSPARC()) |
| 392 | // On SPARC the offset is positive. (!) | 395 | // On SPARC the offset is positive. (!) |
| 393 | math.add(usize, self.fp, fp_offset) catch return null | 396 | math.add(usize, self.fp, fp_offset) catch return null |
| 394 | else | 397 | else |
| ... | @@ -424,7 +427,7 @@ pub fn writeCurrentStackTrace( | ... | @@ -424,7 +427,7 @@ pub fn writeCurrentStackTrace( |
| 424 | tty_config: TTY.Config, | 427 | tty_config: TTY.Config, |
| 425 | start_addr: ?usize, | 428 | start_addr: ?usize, |
| 426 | ) !void { | 429 | ) !void { |
| 427 | if (builtin.os.tag == .windows) { | 430 | if (native_os == .windows) { |
| 428 | return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr); | 431 | return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr); |
| 429 | } | 432 | } |
| 430 | var it = StackIterator.init(start_addr, null); | 433 | var it = StackIterator.init(start_addr, null); |
| ... | @@ -482,7 +485,7 @@ pub const TTY = struct { | ... | @@ -482,7 +485,7 @@ pub const TTY = struct { |
| 482 | .Bold => out_stream.writeAll(BOLD) catch return, | 485 | .Bold => out_stream.writeAll(BOLD) catch return, |
| 483 | .Reset => out_stream.writeAll(RESET) catch return, | 486 | .Reset => out_stream.writeAll(RESET) catch return, |
| 484 | }, | 487 | }, |
| 485 | .windows_api => if (builtin.os.tag == .windows) { | 488 | .windows_api => if (native_os == .windows) { |
| 486 | const stderr_file = io.getStdErr(); | 489 | const stderr_file = io.getStdErr(); |
| 487 | const S = struct { | 490 | const S = struct { |
| 488 | var attrs: windows.WORD = undefined; | 491 | var attrs: windows.WORD = undefined; |
| ... | @@ -684,7 +687,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { | ... | @@ -684,7 +687,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { |
| 684 | if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { | 687 | if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) { |
| 685 | return root.os.debug.openSelfDebugInfo(allocator); | 688 | return root.os.debug.openSelfDebugInfo(allocator); |
| 686 | } | 689 | } |
| 687 | switch (builtin.os.tag) { | 690 | switch (native_os) { |
| 688 | .linux, | 691 | .linux, |
| 689 | .freebsd, | 692 | .freebsd, |
| 690 | .netbsd, | 693 | .netbsd, |
| ... | @@ -897,7 +900,7 @@ pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugI | ... | @@ -897,7 +900,7 @@ pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugI |
| 897 | elf.ELFDATA2MSB => .Big, | 900 | elf.ELFDATA2MSB => .Big, |
| 898 | else => return error.InvalidElfEndian, | 901 | else => return error.InvalidElfEndian, |
| 899 | }; | 902 | }; |
| 900 | assert(endian == std.builtin.endian); // this is our own debug info | 903 | assert(endian == native_endian); // this is our own debug info |
| 901 | 904 | ||
| 902 | const shoff = hdr.e_shoff; | 905 | const shoff = hdr.e_shoff; |
| 903 | const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx); | 906 | const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx); |
| ... | @@ -1132,9 +1135,9 @@ pub const DebugInfo = struct { | ... | @@ -1132,9 +1135,9 @@ pub const DebugInfo = struct { |
| 1132 | pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { | 1135 | pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { |
| 1133 | if (comptime std.Target.current.isDarwin()) { | 1136 | if (comptime std.Target.current.isDarwin()) { |
| 1134 | return self.lookupModuleDyld(address); | 1137 | return self.lookupModuleDyld(address); |
| 1135 | } else if (builtin.os.tag == .windows) { | 1138 | } else if (native_os == .windows) { |
| 1136 | return self.lookupModuleWin32(address); | 1139 | return self.lookupModuleWin32(address); |
| 1137 | } else if (builtin.os.tag == .haiku) { | 1140 | } else if (native_os == .haiku) { |
| 1138 | return self.lookupModuleHaiku(address); | 1141 | return self.lookupModuleHaiku(address); |
| 1139 | } else { | 1142 | } else { |
| 1140 | return self.lookupModuleDl(address); | 1143 | return self.lookupModuleDl(address); |
| ... | @@ -1362,7 +1365,7 @@ const SymbolInfo = struct { | ... | @@ -1362,7 +1365,7 @@ const SymbolInfo = struct { |
| 1362 | } | 1365 | } |
| 1363 | }; | 1366 | }; |
| 1364 | 1367 | ||
| 1365 | pub const ModuleDebugInfo = switch (builtin.os.tag) { | 1368 | pub const ModuleDebugInfo = switch (native_os) { |
| 1366 | .macos, .ios, .watchos, .tvos => struct { | 1369 | .macos, .ios, .watchos, .tvos => struct { |
| 1367 | base_address: usize, | 1370 | base_address: usize, |
| 1368 | mapped_memory: []const u8, | 1371 | mapped_memory: []const u8, |
| ... | @@ -1729,7 +1732,7 @@ fn getDebugInfoAllocator() *mem.Allocator { | ... | @@ -1729,7 +1732,7 @@ fn getDebugInfoAllocator() *mem.Allocator { |
| 1729 | } | 1732 | } |
| 1730 | 1733 | ||
| 1731 | /// Whether or not the current target can print useful debug information when a segfault occurs. | 1734 | /// Whether or not the current target can print useful debug information when a segfault occurs. |
| 1732 | pub const have_segfault_handling_support = switch (builtin.os.tag) { | 1735 | pub const have_segfault_handling_support = switch (native_os) { |
| 1733 | .linux, .netbsd => true, | 1736 | .linux, .netbsd => true, |
| 1734 | .windows => true, | 1737 | .windows => true, |
| 1735 | .freebsd, .openbsd => @hasDecl(os, "ucontext_t"), | 1738 | .freebsd, .openbsd => @hasDecl(os, "ucontext_t"), |
| ... | @@ -1753,7 +1756,7 @@ pub fn attachSegfaultHandler() void { | ... | @@ -1753,7 +1756,7 @@ pub fn attachSegfaultHandler() void { |
| 1753 | if (!have_segfault_handling_support) { | 1756 | if (!have_segfault_handling_support) { |
| 1754 | @compileError("segfault handler not supported for this target"); | 1757 | @compileError("segfault handler not supported for this target"); |
| 1755 | } | 1758 | } |
| 1756 | if (builtin.os.tag == .windows) { | 1759 | if (native_os == .windows) { |
| 1757 | windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); | 1760 | windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); |
| 1758 | return; | 1761 | return; |
| 1759 | } | 1762 | } |
| ... | @@ -1769,7 +1772,7 @@ pub fn attachSegfaultHandler() void { | ... | @@ -1769,7 +1772,7 @@ pub fn attachSegfaultHandler() void { |
| 1769 | } | 1772 | } |
| 1770 | 1773 | ||
| 1771 | fn resetSegfaultHandler() void { | 1774 | fn resetSegfaultHandler() void { |
| 1772 | if (builtin.os.tag == .windows) { | 1775 | if (native_os == .windows) { |
| 1773 | if (windows_segfault_handle) |handle| { | 1776 | if (windows_segfault_handle) |handle| { |
| 1774 | assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0); | 1777 | assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0); |
| 1775 | windows_segfault_handle = null; | 1778 | windows_segfault_handle = null; |
| ... | @@ -1792,7 +1795,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v | ... | @@ -1792,7 +1795,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v |
| 1792 | // and the resulting segfault will crash the process rather than continually dump stack traces. | 1795 | // and the resulting segfault will crash the process rather than continually dump stack traces. |
| 1793 | resetSegfaultHandler(); | 1796 | resetSegfaultHandler(); |
| 1794 | 1797 | ||
| 1795 | const addr = switch (builtin.os.tag) { | 1798 | const addr = switch (native_os) { |
| 1796 | .linux => @ptrToInt(info.fields.sigfault.addr), | 1799 | .linux => @ptrToInt(info.fields.sigfault.addr), |
| 1797 | .freebsd => @ptrToInt(info.addr), | 1800 | .freebsd => @ptrToInt(info.addr), |
| 1798 | .netbsd => @ptrToInt(info.info.reason.fault.addr), | 1801 | .netbsd => @ptrToInt(info.info.reason.fault.addr), |
| ... | @@ -1811,7 +1814,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v | ... | @@ -1811,7 +1814,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v |
| 1811 | } catch os.abort(); | 1814 | } catch os.abort(); |
| 1812 | } | 1815 | } |
| 1813 | 1816 | ||
| 1814 | switch (builtin.arch) { | 1817 | switch (native_arch) { |
| 1815 | .i386 => { | 1818 | .i386 => { |
| 1816 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); | 1819 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| 1817 | const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_EIP]); | 1820 | const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_EIP]); |
| ... | @@ -1820,13 +1823,13 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v | ... | @@ -1820,13 +1823,13 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v |
| 1820 | }, | 1823 | }, |
| 1821 | .x86_64 => { | 1824 | .x86_64 => { |
| 1822 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); | 1825 | const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); |
| 1823 | const ip = switch (builtin.os.tag) { | 1826 | const ip = switch (native_os) { |
| 1824 | .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]), | 1827 | .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]), |
| 1825 | .freebsd => @intCast(usize, ctx.mcontext.rip), | 1828 | .freebsd => @intCast(usize, ctx.mcontext.rip), |
| 1826 | .openbsd => @intCast(usize, ctx.sc_rip), | 1829 | .openbsd => @intCast(usize, ctx.sc_rip), |
| 1827 | else => unreachable, | 1830 | else => unreachable, |
| 1828 | }; | 1831 | }; |
| 1829 | const bp = switch (builtin.os.tag) { | 1832 | const bp = switch (native_os) { |
| 1830 | .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG_RBP]), | 1833 | .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG_RBP]), |
| 1831 | .openbsd => @intCast(usize, ctx.sc_rbp), | 1834 | .openbsd => @intCast(usize, ctx.sc_rbp), |
| 1832 | .freebsd => @intCast(usize, ctx.mcontext.rbp), | 1835 | .freebsd => @intCast(usize, ctx.mcontext.rbp), |
lib/std/dwarf.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const debug = std.debug; | 8 | const debug = std.debug; |
| 9 | const fs = std.fs; | 9 | const fs = std.fs; |
| 10 | const io = std.io; | 10 | const io = std.io; |
lib/std/dynamic_library.zig+1-1| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | 7 | ||
| 8 | const std = @import("std.zig"); | 8 | const std = @import("std.zig"); |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
lib/std/elf.zig+9-9| ... | @@ -4,13 +4,13 @@ | ... | @@ -4,13 +4,13 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = std.builtin; | ||
| 8 | const io = std.io; | 7 | const io = std.io; |
| 9 | const os = std.os; | 8 | const os = std.os; |
| 10 | const math = std.math; | 9 | const math = std.math; |
| 11 | const mem = std.mem; | 10 | const mem = std.mem; |
| 12 | const debug = std.debug; | 11 | const debug = std.debug; |
| 13 | const File = std.fs.File; | 12 | const File = std.fs.File; |
| 13 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 14 | 14 | ||
| 15 | pub const AT_NULL = 0; | 15 | pub const AT_NULL = 0; |
| 16 | pub const AT_IGNORE = 1; | 16 | pub const AT_IGNORE = 1; |
| ... | @@ -311,7 +311,7 @@ pub const VER_FLG_BASE = 0x1; | ... | @@ -311,7 +311,7 @@ pub const VER_FLG_BASE = 0x1; |
| 311 | pub const VER_FLG_WEAK = 0x2; | 311 | pub const VER_FLG_WEAK = 0x2; |
| 312 | 312 | ||
| 313 | /// File types | 313 | /// File types |
| 314 | pub const ET = extern enum(u16) { | 314 | pub const ET = enum(u16) { |
| 315 | /// No file type | 315 | /// No file type |
| 316 | NONE = 0, | 316 | NONE = 0, |
| 317 | 317 | ||
| ... | @@ -336,7 +336,7 @@ pub const ET = extern enum(u16) { | ... | @@ -336,7 +336,7 @@ pub const ET = extern enum(u16) { |
| 336 | 336 | ||
| 337 | /// All integers are native endian. | 337 | /// All integers are native endian. |
| 338 | pub const Header = struct { | 338 | pub const Header = struct { |
| 339 | endian: builtin.Endian, | 339 | endian: std.builtin.Endian, |
| 340 | machine: EM, | 340 | machine: EM, |
| 341 | is_64: bool, | 341 | is_64: bool, |
| 342 | entry: u64, | 342 | entry: u64, |
| ... | @@ -380,7 +380,7 @@ pub const Header = struct { | ... | @@ -380,7 +380,7 @@ pub const Header = struct { |
| 380 | ELFDATA2MSB => .Big, | 380 | ELFDATA2MSB => .Big, |
| 381 | else => return error.InvalidElfEndian, | 381 | else => return error.InvalidElfEndian, |
| 382 | }; | 382 | }; |
| 383 | const need_bswap = endian != std.builtin.endian; | 383 | const need_bswap = endian != native_endian; |
| 384 | 384 | ||
| 385 | const is_64 = switch (hdr32.e_ident[EI_CLASS]) { | 385 | const is_64 = switch (hdr32.e_ident[EI_CLASS]) { |
| 386 | ELFCLASS32 => false, | 386 | ELFCLASS32 => false, |
| ... | @@ -426,7 +426,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type { | ... | @@ -426,7 +426,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type { |
| 426 | try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); | 426 | try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); |
| 427 | 427 | ||
| 428 | // ELF endianness matches native endianness. | 428 | // ELF endianness matches native endianness. |
| 429 | if (self.elf_header.endian == std.builtin.endian) return phdr; | 429 | if (self.elf_header.endian == native_endian) return phdr; |
| 430 | 430 | ||
| 431 | // Convert fields to native endianness. | 431 | // Convert fields to native endianness. |
| 432 | bswapAllFields(Elf64_Phdr, &phdr); | 432 | bswapAllFields(Elf64_Phdr, &phdr); |
| ... | @@ -439,7 +439,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type { | ... | @@ -439,7 +439,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type { |
| 439 | try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); | 439 | try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); |
| 440 | 440 | ||
| 441 | // ELF endianness does NOT match native endianness. | 441 | // ELF endianness does NOT match native endianness. |
| 442 | if (self.elf_header.endian != std.builtin.endian) { | 442 | if (self.elf_header.endian != native_endian) { |
| 443 | // Convert fields to native endianness. | 443 | // Convert fields to native endianness. |
| 444 | bswapAllFields(Elf32_Phdr, &phdr); | 444 | bswapAllFields(Elf32_Phdr, &phdr); |
| 445 | } | 445 | } |
| ... | @@ -476,7 +476,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type { | ... | @@ -476,7 +476,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type { |
| 476 | try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); | 476 | try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); |
| 477 | 477 | ||
| 478 | // ELF endianness matches native endianness. | 478 | // ELF endianness matches native endianness. |
| 479 | if (self.elf_header.endian == std.builtin.endian) return shdr; | 479 | if (self.elf_header.endian == native_endian) return shdr; |
| 480 | 480 | ||
| 481 | // Convert fields to native endianness. | 481 | // Convert fields to native endianness. |
| 482 | return Elf64_Shdr{ | 482 | return Elf64_Shdr{ |
| ... | @@ -499,7 +499,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type { | ... | @@ -499,7 +499,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type { |
| 499 | try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); | 499 | try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); |
| 500 | 500 | ||
| 501 | // ELF endianness does NOT match native endianness. | 501 | // ELF endianness does NOT match native endianness. |
| 502 | if (self.elf_header.endian != std.builtin.endian) { | 502 | if (self.elf_header.endian != native_endian) { |
| 503 | // Convert fields to native endianness. | 503 | // Convert fields to native endianness. |
| 504 | shdr = .{ | 504 | shdr = .{ |
| 505 | .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name), | 505 | .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name), |
| ... | @@ -991,7 +991,7 @@ pub const Half = switch (@sizeOf(usize)) { | ... | @@ -991,7 +991,7 @@ pub const Half = switch (@sizeOf(usize)) { |
| 991 | /// See current registered ELF machine architectures at: | 991 | /// See current registered ELF machine architectures at: |
| 992 | /// http://www.uxsglobal.com/developers/gabi/latest/ch4.eheader.html | 992 | /// http://www.uxsglobal.com/developers/gabi/latest/ch4.eheader.html |
| 993 | /// The underscore prefix is because many of these start with numbers. | 993 | /// The underscore prefix is because many of these start with numbers. |
| 994 | pub const EM = extern enum(u16) { | 994 | pub const EM = enum(u16) { |
| 995 | /// No machine | 995 | /// No machine |
| 996 | _NONE = 0, | 996 | _NONE = 0, |
| 997 | 997 |
lib/std/enums.zig+12-448| ... | @@ -18,7 +18,7 @@ const EnumField = std.builtin.TypeInfo.EnumField; | ... | @@ -18,7 +18,7 @@ const EnumField = std.builtin.TypeInfo.EnumField; |
| 18 | pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { | 18 | pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { |
| 19 | const StructField = std.builtin.TypeInfo.StructField; | 19 | const StructField = std.builtin.TypeInfo.StructField; |
| 20 | var fields: []const StructField = &[_]StructField{}; | 20 | var fields: []const StructField = &[_]StructField{}; |
| 21 | for (uniqueFields(E)) |field, i| { | 21 | for (std.meta.fields(E)) |field, i| { |
| 22 | fields = fields ++ &[_]StructField{.{ | 22 | fields = fields ++ &[_]StructField{.{ |
| 23 | .name = field.name, | 23 | .name = field.name, |
| 24 | .field_type = Data, | 24 | .field_type = Data, |
| ... | @@ -48,72 +48,12 @@ pub fn valuesFromFields(comptime E: type, comptime fields: []const EnumField) [] | ... | @@ -48,72 +48,12 @@ pub fn valuesFromFields(comptime E: type, comptime fields: []const EnumField) [] |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | test "std.enums.valuesFromFields" { | ||
| 52 | const E = extern enum { a, b, c, d = 0 }; | ||
| 53 | const fields = valuesFromFields(E, &[_]EnumField{ | ||
| 54 | .{ .name = "b", .value = undefined }, | ||
| 55 | .{ .name = "a", .value = undefined }, | ||
| 56 | .{ .name = "a", .value = undefined }, | ||
| 57 | .{ .name = "d", .value = undefined }, | ||
| 58 | }); | ||
| 59 | try testing.expectEqual(E.b, fields[0]); | ||
| 60 | try testing.expectEqual(E.a, fields[1]); | ||
| 61 | try testing.expectEqual(E.d, fields[2]); // a == d | ||
| 62 | try testing.expectEqual(E.d, fields[3]); | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Returns the set of all named values in the given enum, in | 51 | /// Returns the set of all named values in the given enum, in |
| 66 | /// declaration order. | 52 | /// declaration order. |
| 67 | pub fn values(comptime E: type) []const E { | 53 | pub fn values(comptime E: type) []const E { |
| 68 | return comptime valuesFromFields(E, @typeInfo(E).Enum.fields); | 54 | return comptime valuesFromFields(E, @typeInfo(E).Enum.fields); |
| 69 | } | 55 | } |
| 70 | 56 | ||
| 71 | test "std.enum.values" { | ||
| 72 | const E = extern enum { a, b, c, d = 0 }; | ||
| 73 | try testing.expectEqualSlices(E, &.{ .a, .b, .c, .d }, values(E)); | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Returns the set of all unique named values in the given enum, in | ||
| 77 | /// declaration order. For repeated values in extern enums, only the | ||
| 78 | /// first name for each value is included. | ||
| 79 | pub fn uniqueValues(comptime E: type) []const E { | ||
| 80 | return comptime valuesFromFields(E, uniqueFields(E)); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "std.enum.uniqueValues" { | ||
| 84 | const E = extern enum { a, b, c, d = 0, e, f = 3 }; | ||
| 85 | try testing.expectEqualSlices(E, &.{ .a, .b, .c, .f }, uniqueValues(E)); | ||
| 86 | |||
| 87 | const F = enum { a, b, c }; | ||
| 88 | try testing.expectEqualSlices(F, &.{ .a, .b, .c }, uniqueValues(F)); | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Returns the set of all unique field values in the given enum, in | ||
| 92 | /// declaration order. For repeated values in extern enums, only the | ||
| 93 | /// first name for each value is included. | ||
| 94 | pub fn uniqueFields(comptime E: type) []const EnumField { | ||
| 95 | comptime { | ||
| 96 | const info = @typeInfo(E).Enum; | ||
| 97 | const raw_fields = info.fields; | ||
| 98 | // Only extern enums can contain duplicates, | ||
| 99 | // so fast path other types. | ||
| 100 | if (info.layout != .Extern) { | ||
| 101 | return raw_fields; | ||
| 102 | } | ||
| 103 | |||
| 104 | var unique_fields: []const EnumField = &[_]EnumField{}; | ||
| 105 | outer: for (raw_fields) |candidate| { | ||
| 106 | for (unique_fields) |u| { | ||
| 107 | if (u.value == candidate.value) | ||
| 108 | continue :outer; | ||
| 109 | } | ||
| 110 | unique_fields = unique_fields ++ &[_]EnumField{candidate}; | ||
| 111 | } | ||
| 112 | |||
| 113 | return unique_fields; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Determines the length of a direct-mapped enum array, indexed by | 57 | /// Determines the length of a direct-mapped enum array, indexed by |
| 118 | /// @intCast(usize, @enumToInt(enum_value)). | 58 | /// @intCast(usize, @enumToInt(enum_value)). |
| 119 | /// If the enum is non-exhaustive, the resulting length will only be enough | 59 | /// If the enum is non-exhaustive, the resulting length will only be enough |
| ... | @@ -126,7 +66,7 @@ pub fn uniqueFields(comptime E: type) []const EnumField { | ... | @@ -126,7 +66,7 @@ pub fn uniqueFields(comptime E: type) []const EnumField { |
| 126 | fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { | 66 | fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { |
| 127 | var max_value: comptime_int = -1; | 67 | var max_value: comptime_int = -1; |
| 128 | const max_usize: comptime_int = ~@as(usize, 0); | 68 | const max_usize: comptime_int = ~@as(usize, 0); |
| 129 | const fields = uniqueFields(E); | 69 | const fields = std.meta.fields(E); |
| 130 | for (fields) |f| { | 70 | for (fields) |f| { |
| 131 | if (f.value < 0) { | 71 | if (f.value < 0) { |
| 132 | @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); | 72 | @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); |
| ... | @@ -248,8 +188,8 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E { | ... | @@ -248,8 +188,8 @@ pub fn nameCast(comptime E: type, comptime value: anytype) E { |
| 248 | } | 188 | } |
| 249 | 189 | ||
| 250 | test "std.enums.nameCast" { | 190 | test "std.enums.nameCast" { |
| 251 | const A = enum { a = 0, b = 1 }; | 191 | const A = enum(u1) { a = 0, b = 1 }; |
| 252 | const B = enum { a = 1, b = 0 }; | 192 | const B = enum(u1) { a = 1, b = 0 }; |
| 253 | try testing.expectEqual(A.a, nameCast(A, .a)); | 193 | try testing.expectEqual(A.a, nameCast(A, .a)); |
| 254 | try testing.expectEqual(A.a, nameCast(A, A.a)); | 194 | try testing.expectEqual(A.a, nameCast(A, A.a)); |
| 255 | try testing.expectEqual(A.a, nameCast(A, B.a)); | 195 | try testing.expectEqual(A.a, nameCast(A, B.a)); |
| ... | @@ -283,8 +223,8 @@ pub fn EnumSet(comptime E: type) type { | ... | @@ -283,8 +223,8 @@ pub fn EnumSet(comptime E: type) type { |
| 283 | var result = Self{}; | 223 | var result = Self{}; |
| 284 | comptime var i: usize = 0; | 224 | comptime var i: usize = 0; |
| 285 | inline while (i < Self.len) : (i += 1) { | 225 | inline while (i < Self.len) : (i += 1) { |
| 286 | comptime const key = Indexer.keyForIndex(i); | 226 | const key = comptime Indexer.keyForIndex(i); |
| 287 | comptime const tag = @tagName(key); | 227 | const tag = comptime @tagName(key); |
| 288 | if (@field(init_values, tag)) { | 228 | if (@field(init_values, tag)) { |
| 289 | result.bits.set(i); | 229 | result.bits.set(i); |
| 290 | } | 230 | } |
| ... | @@ -311,8 +251,8 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -311,8 +251,8 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 311 | var result = Self{}; | 251 | var result = Self{}; |
| 312 | comptime var i: usize = 0; | 252 | comptime var i: usize = 0; |
| 313 | inline while (i < Self.len) : (i += 1) { | 253 | inline while (i < Self.len) : (i += 1) { |
| 314 | comptime const key = Indexer.keyForIndex(i); | 254 | const key = comptime Indexer.keyForIndex(i); |
| 315 | comptime const tag = @tagName(key); | 255 | const tag = comptime @tagName(key); |
| 316 | if (@field(init_values, tag)) |*v| { | 256 | if (@field(init_values, tag)) |*v| { |
| 317 | result.bits.set(i); | 257 | result.bits.set(i); |
| 318 | result.values[i] = v.*; | 258 | result.values[i] = v.*; |
| ... | @@ -344,8 +284,8 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -344,8 +284,8 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 344 | }; | 284 | }; |
| 345 | comptime var i: usize = 0; | 285 | comptime var i: usize = 0; |
| 346 | inline while (i < Self.len) : (i += 1) { | 286 | inline while (i < Self.len) : (i += 1) { |
| 347 | comptime const key = Indexer.keyForIndex(i); | 287 | const key = comptime Indexer.keyForIndex(i); |
| 348 | comptime const tag = @tagName(key); | 288 | const tag = comptime @tagName(key); |
| 349 | result.values[i] = @field(init_values, tag); | 289 | result.values[i] = @field(init_values, tag); |
| 350 | } | 290 | } |
| 351 | return result; | 291 | return result; |
| ... | @@ -796,7 +736,7 @@ pub fn EnumIndexer(comptime E: type) type { | ... | @@ -796,7 +736,7 @@ pub fn EnumIndexer(comptime E: type) type { |
| 796 | @compileError("Cannot create an enum indexer for a non-exhaustive enum."); | 736 | @compileError("Cannot create an enum indexer for a non-exhaustive enum."); |
| 797 | } | 737 | } |
| 798 | 738 | ||
| 799 | const const_fields = uniqueFields(E); | 739 | const const_fields = std.meta.fields(E); |
| 800 | var fields = const_fields[0..const_fields.len].*; | 740 | var fields = const_fields[0..const_fields.len].*; |
| 801 | if (fields.len == 0) { | 741 | if (fields.len == 0) { |
| 802 | return struct { | 742 | return struct { |
| ... | @@ -848,7 +788,7 @@ pub fn EnumIndexer(comptime E: type) type { | ... | @@ -848,7 +788,7 @@ pub fn EnumIndexer(comptime E: type) type { |
| 848 | } | 788 | } |
| 849 | 789 | ||
| 850 | test "std.enums.EnumIndexer dense zeroed" { | 790 | test "std.enums.EnumIndexer dense zeroed" { |
| 851 | const E = enum { b = 1, a = 0, c = 2 }; | 791 | const E = enum(u2) { b = 1, a = 0, c = 2 }; |
| 852 | const Indexer = EnumIndexer(E); | 792 | const Indexer = EnumIndexer(E); |
| 853 | ensureIndexer(Indexer); | 793 | ensureIndexer(Indexer); |
| 854 | try testing.expectEqual(E, Indexer.Key); | 794 | try testing.expectEqual(E, Indexer.Key); |
| ... | @@ -910,379 +850,3 @@ test "std.enums.EnumIndexer sparse" { | ... | @@ -910,379 +850,3 @@ test "std.enums.EnumIndexer sparse" { |
| 910 | try testing.expectEqual(E.b, Indexer.keyForIndex(1)); | 850 | try testing.expectEqual(E.b, Indexer.keyForIndex(1)); |
| 911 | try testing.expectEqual(E.c, Indexer.keyForIndex(2)); | 851 | try testing.expectEqual(E.c, Indexer.keyForIndex(2)); |
| 912 | } | 852 | } |
| 913 | |||
| 914 | test "std.enums.EnumIndexer repeats" { | ||
| 915 | const E = extern enum { a = -2, c = 6, b = 4, b2 = 4 }; | ||
| 916 | const Indexer = EnumIndexer(E); | ||
| 917 | ensureIndexer(Indexer); | ||
| 918 | try testing.expectEqual(E, Indexer.Key); | ||
| 919 | try testing.expectEqual(@as(usize, 3), Indexer.count); | ||
| 920 | |||
| 921 | try testing.expectEqual(@as(usize, 0), Indexer.indexOf(.a)); | ||
| 922 | try testing.expectEqual(@as(usize, 1), Indexer.indexOf(.b)); | ||
| 923 | try testing.expectEqual(@as(usize, 2), Indexer.indexOf(.c)); | ||
| 924 | |||
| 925 | try testing.expectEqual(E.a, Indexer.keyForIndex(0)); | ||
| 926 | try testing.expectEqual(E.b, Indexer.keyForIndex(1)); | ||
| 927 | try testing.expectEqual(E.c, Indexer.keyForIndex(2)); | ||
| 928 | } | ||
| 929 | |||
| 930 | test "std.enums.EnumSet" { | ||
| 931 | const E = extern enum { a, b, c, d, e = 0 }; | ||
| 932 | const Set = EnumSet(E); | ||
| 933 | try testing.expectEqual(E, Set.Key); | ||
| 934 | try testing.expectEqual(EnumIndexer(E), Set.Indexer); | ||
| 935 | try testing.expectEqual(@as(usize, 4), Set.len); | ||
| 936 | |||
| 937 | // Empty sets | ||
| 938 | const empty = Set{}; | ||
| 939 | comptime try testing.expect(empty.count() == 0); | ||
| 940 | |||
| 941 | var empty_b = Set.init(.{}); | ||
| 942 | try testing.expect(empty_b.count() == 0); | ||
| 943 | |||
| 944 | const empty_c = comptime Set.init(.{}); | ||
| 945 | comptime try testing.expect(empty_c.count() == 0); | ||
| 946 | |||
| 947 | const full = Set.initFull(); | ||
| 948 | try testing.expect(full.count() == Set.len); | ||
| 949 | |||
| 950 | const full_b = comptime Set.initFull(); | ||
| 951 | comptime try testing.expect(full_b.count() == Set.len); | ||
| 952 | |||
| 953 | try testing.expectEqual(false, empty.contains(.a)); | ||
| 954 | try testing.expectEqual(false, empty.contains(.b)); | ||
| 955 | try testing.expectEqual(false, empty.contains(.c)); | ||
| 956 | try testing.expectEqual(false, empty.contains(.d)); | ||
| 957 | try testing.expectEqual(false, empty.contains(.e)); | ||
| 958 | { | ||
| 959 | var iter = empty_b.iterator(); | ||
| 960 | try testing.expectEqual(@as(?E, null), iter.next()); | ||
| 961 | } | ||
| 962 | |||
| 963 | var mut = Set.init(.{ | ||
| 964 | .a = true, | ||
| 965 | .c = true, | ||
| 966 | }); | ||
| 967 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 968 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 969 | try testing.expectEqual(false, mut.contains(.b)); | ||
| 970 | try testing.expectEqual(true, mut.contains(.c)); | ||
| 971 | try testing.expectEqual(false, mut.contains(.d)); | ||
| 972 | try testing.expectEqual(true, mut.contains(.e)); // aliases a | ||
| 973 | { | ||
| 974 | var it = mut.iterator(); | ||
| 975 | try testing.expectEqual(@as(?E, .a), it.next()); | ||
| 976 | try testing.expectEqual(@as(?E, .c), it.next()); | ||
| 977 | try testing.expectEqual(@as(?E, null), it.next()); | ||
| 978 | } | ||
| 979 | |||
| 980 | mut.toggleAll(); | ||
| 981 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 982 | try testing.expectEqual(false, mut.contains(.a)); | ||
| 983 | try testing.expectEqual(true, mut.contains(.b)); | ||
| 984 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 985 | try testing.expectEqual(true, mut.contains(.d)); | ||
| 986 | try testing.expectEqual(false, mut.contains(.e)); // aliases a | ||
| 987 | { | ||
| 988 | var it = mut.iterator(); | ||
| 989 | try testing.expectEqual(@as(?E, .b), it.next()); | ||
| 990 | try testing.expectEqual(@as(?E, .d), it.next()); | ||
| 991 | try testing.expectEqual(@as(?E, null), it.next()); | ||
| 992 | } | ||
| 993 | |||
| 994 | mut.toggleSet(Set.init(.{ .a = true, .b = true })); | ||
| 995 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 996 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 997 | try testing.expectEqual(false, mut.contains(.b)); | ||
| 998 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 999 | try testing.expectEqual(true, mut.contains(.d)); | ||
| 1000 | try testing.expectEqual(true, mut.contains(.e)); // aliases a | ||
| 1001 | |||
| 1002 | mut.setUnion(Set.init(.{ .a = true, .b = true })); | ||
| 1003 | try testing.expectEqual(@as(usize, 3), mut.count()); | ||
| 1004 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 1005 | try testing.expectEqual(true, mut.contains(.b)); | ||
| 1006 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 1007 | try testing.expectEqual(true, mut.contains(.d)); | ||
| 1008 | |||
| 1009 | mut.remove(.c); | ||
| 1010 | mut.remove(.b); | ||
| 1011 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 1012 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 1013 | try testing.expectEqual(false, mut.contains(.b)); | ||
| 1014 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 1015 | try testing.expectEqual(true, mut.contains(.d)); | ||
| 1016 | |||
| 1017 | mut.setIntersection(Set.init(.{ .a = true, .b = true })); | ||
| 1018 | try testing.expectEqual(@as(usize, 1), mut.count()); | ||
| 1019 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 1020 | try testing.expectEqual(false, mut.contains(.b)); | ||
| 1021 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 1022 | try testing.expectEqual(false, mut.contains(.d)); | ||
| 1023 | |||
| 1024 | mut.insert(.a); | ||
| 1025 | mut.insert(.b); | ||
| 1026 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 1027 | try testing.expectEqual(true, mut.contains(.a)); | ||
| 1028 | try testing.expectEqual(true, mut.contains(.b)); | ||
| 1029 | try testing.expectEqual(false, mut.contains(.c)); | ||
| 1030 | try testing.expectEqual(false, mut.contains(.d)); | ||
| 1031 | |||
| 1032 | mut.setPresent(.a, false); | ||
| 1033 | mut.toggle(.b); | ||
| 1034 | mut.toggle(.c); | ||
| 1035 | mut.setPresent(.d, true); | ||
| 1036 | try testing.expectEqual(@as(usize, 2), mut.count()); | ||
| 1037 | try testing.expectEqual(false, mut.contains(.a)); | ||
| 1038 | try testing.expectEqual(false, mut.contains(.b)); | ||
| 1039 | try testing.expectEqual(true, mut.contains(.c)); | ||
| 1040 | try testing.expectEqual(true, mut.contains(.d)); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | test "std.enums.EnumArray void" { | ||
| 1044 | const E = extern enum { a, b, c, d, e = 0 }; | ||
| 1045 | const ArrayVoid = EnumArray(E, void); | ||
| 1046 | try testing.expectEqual(E, ArrayVoid.Key); | ||
| 1047 | try testing.expectEqual(EnumIndexer(E), ArrayVoid.Indexer); | ||
| 1048 | try testing.expectEqual(void, ArrayVoid.Value); | ||
| 1049 | try testing.expectEqual(@as(usize, 4), ArrayVoid.len); | ||
| 1050 | |||
| 1051 | const undef = ArrayVoid.initUndefined(); | ||
| 1052 | var inst = ArrayVoid.initFill({}); | ||
| 1053 | const inst2 = ArrayVoid.init(.{ .a = {}, .b = {}, .c = {}, .d = {} }); | ||
| 1054 | const inst3 = ArrayVoid.initDefault({}, .{}); | ||
| 1055 | |||
| 1056 | _ = inst.get(.a); | ||
| 1057 | _ = inst.getPtr(.b); | ||
| 1058 | _ = inst.getPtrConst(.c); | ||
| 1059 | inst.set(.a, {}); | ||
| 1060 | |||
| 1061 | var it = inst.iterator(); | ||
| 1062 | try testing.expectEqual(E.a, it.next().?.key); | ||
| 1063 | try testing.expectEqual(E.b, it.next().?.key); | ||
| 1064 | try testing.expectEqual(E.c, it.next().?.key); | ||
| 1065 | try testing.expectEqual(E.d, it.next().?.key); | ||
| 1066 | try testing.expect(it.next() == null); | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | test "std.enums.EnumArray sized" { | ||
| 1070 | const E = extern enum { a, b, c, d, e = 0 }; | ||
| 1071 | const Array = EnumArray(E, usize); | ||
| 1072 | try testing.expectEqual(E, Array.Key); | ||
| 1073 | try testing.expectEqual(EnumIndexer(E), Array.Indexer); | ||
| 1074 | try testing.expectEqual(usize, Array.Value); | ||
| 1075 | try testing.expectEqual(@as(usize, 4), Array.len); | ||
| 1076 | |||
| 1077 | const undef = Array.initUndefined(); | ||
| 1078 | var inst = Array.initFill(5); | ||
| 1079 | const inst2 = Array.init(.{ .a = 1, .b = 2, .c = 3, .d = 4 }); | ||
| 1080 | const inst3 = Array.initDefault(6, .{ .b = 4, .c = 2 }); | ||
| 1081 | |||
| 1082 | try testing.expectEqual(@as(usize, 5), inst.get(.a)); | ||
| 1083 | try testing.expectEqual(@as(usize, 5), inst.get(.b)); | ||
| 1084 | try testing.expectEqual(@as(usize, 5), inst.get(.c)); | ||
| 1085 | try testing.expectEqual(@as(usize, 5), inst.get(.d)); | ||
| 1086 | |||
| 1087 | try testing.expectEqual(@as(usize, 1), inst2.get(.a)); | ||
| 1088 | try testing.expectEqual(@as(usize, 2), inst2.get(.b)); | ||
| 1089 | try testing.expectEqual(@as(usize, 3), inst2.get(.c)); | ||
| 1090 | try testing.expectEqual(@as(usize, 4), inst2.get(.d)); | ||
| 1091 | |||
| 1092 | try testing.expectEqual(@as(usize, 6), inst3.get(.a)); | ||
| 1093 | try testing.expectEqual(@as(usize, 4), inst3.get(.b)); | ||
| 1094 | try testing.expectEqual(@as(usize, 2), inst3.get(.c)); | ||
| 1095 | try testing.expectEqual(@as(usize, 6), inst3.get(.d)); | ||
| 1096 | |||
| 1097 | try testing.expectEqual(&inst.values[0], inst.getPtr(.a)); | ||
| 1098 | try testing.expectEqual(&inst.values[1], inst.getPtr(.b)); | ||
| 1099 | try testing.expectEqual(&inst.values[2], inst.getPtr(.c)); | ||
| 1100 | try testing.expectEqual(&inst.values[3], inst.getPtr(.d)); | ||
| 1101 | |||
| 1102 | try testing.expectEqual(@as(*const usize, &inst.values[0]), inst.getPtrConst(.a)); | ||
| 1103 | try testing.expectEqual(@as(*const usize, &inst.values[1]), inst.getPtrConst(.b)); | ||
| 1104 | try testing.expectEqual(@as(*const usize, &inst.values[2]), inst.getPtrConst(.c)); | ||
| 1105 | try testing.expectEqual(@as(*const usize, &inst.values[3]), inst.getPtrConst(.d)); | ||
| 1106 | |||
| 1107 | inst.set(.c, 8); | ||
| 1108 | try testing.expectEqual(@as(usize, 5), inst.get(.a)); | ||
| 1109 | try testing.expectEqual(@as(usize, 5), inst.get(.b)); | ||
| 1110 | try testing.expectEqual(@as(usize, 8), inst.get(.c)); | ||
| 1111 | try testing.expectEqual(@as(usize, 5), inst.get(.d)); | ||
| 1112 | |||
| 1113 | var it = inst.iterator(); | ||
| 1114 | const Entry = Array.Entry; | ||
| 1115 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1116 | .key = .a, | ||
| 1117 | .value = &inst.values[0], | ||
| 1118 | }), it.next()); | ||
| 1119 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1120 | .key = .b, | ||
| 1121 | .value = &inst.values[1], | ||
| 1122 | }), it.next()); | ||
| 1123 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1124 | .key = .c, | ||
| 1125 | .value = &inst.values[2], | ||
| 1126 | }), it.next()); | ||
| 1127 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1128 | .key = .d, | ||
| 1129 | .value = &inst.values[3], | ||
| 1130 | }), it.next()); | ||
| 1131 | try testing.expectEqual(@as(?Entry, null), it.next()); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | test "std.enums.EnumMap void" { | ||
| 1135 | const E = extern enum { a, b, c, d, e = 0 }; | ||
| 1136 | const Map = EnumMap(E, void); | ||
| 1137 | try testing.expectEqual(E, Map.Key); | ||
| 1138 | try testing.expectEqual(EnumIndexer(E), Map.Indexer); | ||
| 1139 | try testing.expectEqual(void, Map.Value); | ||
| 1140 | try testing.expectEqual(@as(usize, 4), Map.len); | ||
| 1141 | |||
| 1142 | const b = Map.initFull({}); | ||
| 1143 | try testing.expectEqual(@as(usize, 4), b.count()); | ||
| 1144 | |||
| 1145 | const c = Map.initFullWith(.{ .a = {}, .b = {}, .c = {}, .d = {} }); | ||
| 1146 | try testing.expectEqual(@as(usize, 4), c.count()); | ||
| 1147 | |||
| 1148 | const d = Map.initFullWithDefault({}, .{ .b = {} }); | ||
| 1149 | try testing.expectEqual(@as(usize, 4), d.count()); | ||
| 1150 | |||
| 1151 | var a = Map.init(.{ .b = {}, .d = {} }); | ||
| 1152 | try testing.expectEqual(@as(usize, 2), a.count()); | ||
| 1153 | try testing.expectEqual(false, a.contains(.a)); | ||
| 1154 | try testing.expectEqual(true, a.contains(.b)); | ||
| 1155 | try testing.expectEqual(false, a.contains(.c)); | ||
| 1156 | try testing.expectEqual(true, a.contains(.d)); | ||
| 1157 | try testing.expect(a.get(.a) == null); | ||
| 1158 | try testing.expect(a.get(.b) != null); | ||
| 1159 | try testing.expect(a.get(.c) == null); | ||
| 1160 | try testing.expect(a.get(.d) != null); | ||
| 1161 | try testing.expect(a.getPtr(.a) == null); | ||
| 1162 | try testing.expect(a.getPtr(.b) != null); | ||
| 1163 | try testing.expect(a.getPtr(.c) == null); | ||
| 1164 | try testing.expect(a.getPtr(.d) != null); | ||
| 1165 | try testing.expect(a.getPtrConst(.a) == null); | ||
| 1166 | try testing.expect(a.getPtrConst(.b) != null); | ||
| 1167 | try testing.expect(a.getPtrConst(.c) == null); | ||
| 1168 | try testing.expect(a.getPtrConst(.d) != null); | ||
| 1169 | _ = a.getPtrAssertContains(.b); | ||
| 1170 | _ = a.getAssertContains(.d); | ||
| 1171 | |||
| 1172 | a.put(.a, {}); | ||
| 1173 | a.put(.a, {}); | ||
| 1174 | a.putUninitialized(.c).* = {}; | ||
| 1175 | a.putUninitialized(.c).* = {}; | ||
| 1176 | |||
| 1177 | try testing.expectEqual(@as(usize, 4), a.count()); | ||
| 1178 | try testing.expect(a.get(.a) != null); | ||
| 1179 | try testing.expect(a.get(.b) != null); | ||
| 1180 | try testing.expect(a.get(.c) != null); | ||
| 1181 | try testing.expect(a.get(.d) != null); | ||
| 1182 | |||
| 1183 | a.remove(.a); | ||
| 1184 | _ = a.fetchRemove(.c); | ||
| 1185 | |||
| 1186 | var iter = a.iterator(); | ||
| 1187 | const Entry = Map.Entry; | ||
| 1188 | try testing.expectEqual(E.b, iter.next().?.key); | ||
| 1189 | try testing.expectEqual(E.d, iter.next().?.key); | ||
| 1190 | try testing.expect(iter.next() == null); | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | test "std.enums.EnumMap sized" { | ||
| 1194 | const E = extern enum { a, b, c, d, e = 0 }; | ||
| 1195 | const Map = EnumMap(E, usize); | ||
| 1196 | try testing.expectEqual(E, Map.Key); | ||
| 1197 | try testing.expectEqual(EnumIndexer(E), Map.Indexer); | ||
| 1198 | try testing.expectEqual(usize, Map.Value); | ||
| 1199 | try testing.expectEqual(@as(usize, 4), Map.len); | ||
| 1200 | |||
| 1201 | const b = Map.initFull(5); | ||
| 1202 | try testing.expectEqual(@as(usize, 4), b.count()); | ||
| 1203 | try testing.expect(b.contains(.a)); | ||
| 1204 | try testing.expect(b.contains(.b)); | ||
| 1205 | try testing.expect(b.contains(.c)); | ||
| 1206 | try testing.expect(b.contains(.d)); | ||
| 1207 | try testing.expectEqual(@as(?usize, 5), b.get(.a)); | ||
| 1208 | try testing.expectEqual(@as(?usize, 5), b.get(.b)); | ||
| 1209 | try testing.expectEqual(@as(?usize, 5), b.get(.c)); | ||
| 1210 | try testing.expectEqual(@as(?usize, 5), b.get(.d)); | ||
| 1211 | |||
| 1212 | const c = Map.initFullWith(.{ .a = 1, .b = 2, .c = 3, .d = 4 }); | ||
| 1213 | try testing.expectEqual(@as(usize, 4), c.count()); | ||
| 1214 | try testing.expect(c.contains(.a)); | ||
| 1215 | try testing.expect(c.contains(.b)); | ||
| 1216 | try testing.expect(c.contains(.c)); | ||
| 1217 | try testing.expect(c.contains(.d)); | ||
| 1218 | try testing.expectEqual(@as(?usize, 1), c.get(.a)); | ||
| 1219 | try testing.expectEqual(@as(?usize, 2), c.get(.b)); | ||
| 1220 | try testing.expectEqual(@as(?usize, 3), c.get(.c)); | ||
| 1221 | try testing.expectEqual(@as(?usize, 4), c.get(.d)); | ||
| 1222 | |||
| 1223 | const d = Map.initFullWithDefault(6, .{ .b = 2, .c = 4 }); | ||
| 1224 | try testing.expectEqual(@as(usize, 4), d.count()); | ||
| 1225 | try testing.expect(d.contains(.a)); | ||
| 1226 | try testing.expect(d.contains(.b)); | ||
| 1227 | try testing.expect(d.contains(.c)); | ||
| 1228 | try testing.expect(d.contains(.d)); | ||
| 1229 | try testing.expectEqual(@as(?usize, 6), d.get(.a)); | ||
| 1230 | try testing.expectEqual(@as(?usize, 2), d.get(.b)); | ||
| 1231 | try testing.expectEqual(@as(?usize, 4), d.get(.c)); | ||
| 1232 | try testing.expectEqual(@as(?usize, 6), d.get(.d)); | ||
| 1233 | |||
| 1234 | var a = Map.init(.{ .b = 2, .d = 4 }); | ||
| 1235 | try testing.expectEqual(@as(usize, 2), a.count()); | ||
| 1236 | try testing.expectEqual(false, a.contains(.a)); | ||
| 1237 | try testing.expectEqual(true, a.contains(.b)); | ||
| 1238 | try testing.expectEqual(false, a.contains(.c)); | ||
| 1239 | try testing.expectEqual(true, a.contains(.d)); | ||
| 1240 | |||
| 1241 | try testing.expectEqual(@as(?usize, null), a.get(.a)); | ||
| 1242 | try testing.expectEqual(@as(?usize, 2), a.get(.b)); | ||
| 1243 | try testing.expectEqual(@as(?usize, null), a.get(.c)); | ||
| 1244 | try testing.expectEqual(@as(?usize, 4), a.get(.d)); | ||
| 1245 | |||
| 1246 | try testing.expectEqual(@as(?*usize, null), a.getPtr(.a)); | ||
| 1247 | try testing.expectEqual(@as(?*usize, &a.values[1]), a.getPtr(.b)); | ||
| 1248 | try testing.expectEqual(@as(?*usize, null), a.getPtr(.c)); | ||
| 1249 | try testing.expectEqual(@as(?*usize, &a.values[3]), a.getPtr(.d)); | ||
| 1250 | |||
| 1251 | try testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.a)); | ||
| 1252 | try testing.expectEqual(@as(?*const usize, &a.values[1]), a.getPtrConst(.b)); | ||
| 1253 | try testing.expectEqual(@as(?*const usize, null), a.getPtrConst(.c)); | ||
| 1254 | try testing.expectEqual(@as(?*const usize, &a.values[3]), a.getPtrConst(.d)); | ||
| 1255 | |||
| 1256 | try testing.expectEqual(@as(*const usize, &a.values[1]), a.getPtrAssertContains(.b)); | ||
| 1257 | try testing.expectEqual(@as(*const usize, &a.values[3]), a.getPtrAssertContains(.d)); | ||
| 1258 | try testing.expectEqual(@as(usize, 2), a.getAssertContains(.b)); | ||
| 1259 | try testing.expectEqual(@as(usize, 4), a.getAssertContains(.d)); | ||
| 1260 | |||
| 1261 | a.put(.a, 3); | ||
| 1262 | a.put(.a, 5); | ||
| 1263 | a.putUninitialized(.c).* = 7; | ||
| 1264 | a.putUninitialized(.c).* = 9; | ||
| 1265 | |||
| 1266 | try testing.expectEqual(@as(usize, 4), a.count()); | ||
| 1267 | try testing.expectEqual(@as(?usize, 5), a.get(.a)); | ||
| 1268 | try testing.expectEqual(@as(?usize, 2), a.get(.b)); | ||
| 1269 | try testing.expectEqual(@as(?usize, 9), a.get(.c)); | ||
| 1270 | try testing.expectEqual(@as(?usize, 4), a.get(.d)); | ||
| 1271 | |||
| 1272 | a.remove(.a); | ||
| 1273 | try testing.expectEqual(@as(?usize, null), a.fetchRemove(.a)); | ||
| 1274 | try testing.expectEqual(@as(?usize, 9), a.fetchRemove(.c)); | ||
| 1275 | a.remove(.c); | ||
| 1276 | |||
| 1277 | var iter = a.iterator(); | ||
| 1278 | const Entry = Map.Entry; | ||
| 1279 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1280 | .key = .b, | ||
| 1281 | .value = &a.values[1], | ||
| 1282 | }), iter.next()); | ||
| 1283 | try testing.expectEqual(@as(?Entry, Entry{ | ||
| 1284 | .key = .d, | ||
| 1285 | .value = &a.values[3], | ||
| 1286 | }), iter.next()); | ||
| 1287 | try testing.expectEqual(@as(?Entry, null), iter.next()); | ||
| 1288 | } |
lib/std/event/channel.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const Loop = std.event.Loop; | 10 | const Loop = std.event.Loop; |
lib/std/event/future.zig+1-1| ... | @@ -6,7 +6,7 @@ | ... | @@ -6,7 +6,7 @@ |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const testing = std.testing; | 8 | const testing = std.testing; |
| 9 | const builtin = @import("builtin"); | 9 | const builtin = std.builtin; |
| 10 | const Lock = std.event.Lock; | 10 | const Lock = std.event.Lock; |
| 11 | 11 | ||
| 12 | /// This is a value that starts out unavailable, until resolve() is called | 12 | /// This is a value that starts out unavailable, until resolve() is called |
lib/std/event/group.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const Lock = std.event.Lock; | 8 | const Lock = std.event.Lock; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const Allocator = std.mem.Allocator; | 10 | const Allocator = std.mem.Allocator; |
lib/std/event/lock.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
lib/std/event/loop.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const root = @import("root"); | 8 | const root = @import("root"); |
| 9 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| 10 | const testing = std.testing; | 10 | const testing = std.testing; |
lib/std/event/rwlock.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
lib/std/event/wait_group.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const Loop = std.event.Loop; | 8 | const Loop = std.event.Loop; |
| 9 | 9 | ||
| 10 | /// A WaitGroup keeps track and waits for a group of async tasks to finish. | 10 | /// A WaitGroup keeps track and waits for a group of async tasks to finish. |
lib/std/fmt.zig+39-22| ... | @@ -187,7 +187,7 @@ pub fn format( | ... | @@ -187,7 +187,7 @@ pub fn format( |
| 187 | 187 | ||
| 188 | comptime var i = 0; | 188 | comptime var i = 0; |
| 189 | inline while (i < fmt.len) { | 189 | inline while (i < fmt.len) { |
| 190 | comptime const start_index = i; | 190 | const start_index = i; |
| 191 | 191 | ||
| 192 | inline while (i < fmt.len) : (i += 1) { | 192 | inline while (i < fmt.len) : (i += 1) { |
| 193 | switch (fmt[i]) { | 193 | switch (fmt[i]) { |
| ... | @@ -226,10 +226,10 @@ pub fn format( | ... | @@ -226,10 +226,10 @@ pub fn format( |
| 226 | comptime assert(fmt[i] == '{'); | 226 | comptime assert(fmt[i] == '{'); |
| 227 | i += 1; | 227 | i += 1; |
| 228 | 228 | ||
| 229 | comptime const fmt_begin = i; | 229 | const fmt_begin = i; |
| 230 | // Find the closing brace | 230 | // Find the closing brace |
| 231 | inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {} | 231 | inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {} |
| 232 | comptime const fmt_end = i; | 232 | const fmt_end = i; |
| 233 | 233 | ||
| 234 | if (i >= fmt.len) { | 234 | if (i >= fmt.len) { |
| 235 | @compileError("Missing closing }"); | 235 | @compileError("Missing closing }"); |
| ... | @@ -246,23 +246,23 @@ pub fn format( | ... | @@ -246,23 +246,23 @@ pub fn format( |
| 246 | parser.pos = 0; | 246 | parser.pos = 0; |
| 247 | 247 | ||
| 248 | // Parse the positional argument number | 248 | // Parse the positional argument number |
| 249 | comptime const opt_pos_arg = init: { | 249 | const opt_pos_arg = comptime init: { |
| 250 | if (comptime parser.maybe('[')) { | 250 | if (parser.maybe('[')) { |
| 251 | comptime const arg_name = parser.until(']'); | 251 | const arg_name = parser.until(']'); |
| 252 | 252 | ||
| 253 | if (!comptime parser.maybe(']')) { | 253 | if (!parser.maybe(']')) { |
| 254 | @compileError("Expected closing ]"); | 254 | @compileError("Expected closing ]"); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | break :init comptime meta.fieldIndex(ArgsType, arg_name) orelse | 257 | break :init meta.fieldIndex(ArgsType, arg_name) orelse |
| 258 | @compileError("No argument with name '" ++ arg_name ++ "'"); | 258 | @compileError("No argument with name '" ++ arg_name ++ "'"); |
| 259 | } else { | 259 | } else { |
| 260 | break :init comptime parser.number(); | 260 | break :init parser.number(); |
| 261 | } | 261 | } |
| 262 | }; | 262 | }; |
| 263 | 263 | ||
| 264 | // Parse the format specifier | 264 | // Parse the format specifier |
| 265 | comptime const specifier_arg = comptime parser.until(':'); | 265 | const specifier_arg = comptime parser.until(':'); |
| 266 | 266 | ||
| 267 | // Skip the colon, if present | 267 | // Skip the colon, if present |
| 268 | if (comptime parser.char()) |ch| { | 268 | if (comptime parser.char()) |ch| { |
| ... | @@ -302,13 +302,13 @@ pub fn format( | ... | @@ -302,13 +302,13 @@ pub fn format( |
| 302 | // Parse the width parameter | 302 | // Parse the width parameter |
| 303 | options.width = init: { | 303 | options.width = init: { |
| 304 | if (comptime parser.maybe('[')) { | 304 | if (comptime parser.maybe('[')) { |
| 305 | comptime const arg_name = parser.until(']'); | 305 | const arg_name = comptime parser.until(']'); |
| 306 | 306 | ||
| 307 | if (!comptime parser.maybe(']')) { | 307 | if (!comptime parser.maybe(']')) { |
| 308 | @compileError("Expected closing ]"); | 308 | @compileError("Expected closing ]"); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | comptime const index = meta.fieldIndex(ArgsType, arg_name) orelse | 311 | const index = comptime meta.fieldIndex(ArgsType, arg_name) orelse |
| 312 | @compileError("No argument with name '" ++ arg_name ++ "'"); | 312 | @compileError("No argument with name '" ++ arg_name ++ "'"); |
| 313 | const arg_index = comptime arg_state.nextArg(index); | 313 | const arg_index = comptime arg_state.nextArg(index); |
| 314 | 314 | ||
| ... | @@ -328,13 +328,13 @@ pub fn format( | ... | @@ -328,13 +328,13 @@ pub fn format( |
| 328 | // Parse the precision parameter | 328 | // Parse the precision parameter |
| 329 | options.precision = init: { | 329 | options.precision = init: { |
| 330 | if (comptime parser.maybe('[')) { | 330 | if (comptime parser.maybe('[')) { |
| 331 | comptime const arg_name = parser.until(']'); | 331 | const arg_name = comptime parser.until(']'); |
| 332 | 332 | ||
| 333 | if (!comptime parser.maybe(']')) { | 333 | if (!comptime parser.maybe(']')) { |
| 334 | @compileError("Expected closing ]"); | 334 | @compileError("Expected closing ]"); |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | comptime const arg_i = meta.fieldIndex(ArgsType, arg_name) orelse | 337 | const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse |
| 338 | @compileError("No argument with name '" ++ arg_name ++ "'"); | 338 | @compileError("No argument with name '" ++ arg_name ++ "'"); |
| 339 | const arg_to_use = comptime arg_state.nextArg(arg_i); | 339 | const arg_to_use = comptime arg_state.nextArg(arg_i); |
| 340 | 340 | ||
| ... | @@ -905,7 +905,7 @@ pub fn formatBuf( | ... | @@ -905,7 +905,7 @@ pub fn formatBuf( |
| 905 | ) !void { | 905 | ) !void { |
| 906 | if (options.width) |min_width| { | 906 | if (options.width) |min_width| { |
| 907 | // In case of error assume the buffer content is ASCII-encoded | 907 | // In case of error assume the buffer content is ASCII-encoded |
| 908 | const width = unicode.utf8CountCodepoints(buf) catch |_| buf.len; | 908 | const width = unicode.utf8CountCodepoints(buf) catch buf.len; |
| 909 | const padding = if (width < min_width) min_width - width else 0; | 909 | const padding = if (width < min_width) min_width - width else 0; |
| 910 | 910 | ||
| 911 | if (padding == 0) | 911 | if (padding == 0) |
| ... | @@ -1469,6 +1469,7 @@ pub fn Formatter(comptime format_fn: anytype) type { | ... | @@ -1469,6 +1469,7 @@ pub fn Formatter(comptime format_fn: anytype) type { |
| 1469 | /// * A prefix of "0x" implies radix=16, | 1469 | /// * A prefix of "0x" implies radix=16, |
| 1470 | /// * Otherwise radix=10 is assumed. | 1470 | /// * Otherwise radix=10 is assumed. |
| 1471 | /// | 1471 | /// |
| 1472 | /// Ignores '_' character in `buf`. | ||
| 1472 | /// See also `parseUnsigned`. | 1473 | /// See also `parseUnsigned`. |
| 1473 | pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { | 1474 | pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { |
| 1474 | if (buf.len == 0) return error.InvalidCharacter; | 1475 | if (buf.len == 0) return error.InvalidCharacter; |
| ... | @@ -1484,6 +1485,10 @@ test "parseInt" { | ... | @@ -1484,6 +1485,10 @@ test "parseInt" { |
| 1484 | try std.testing.expectError(error.Overflow, parseInt(u32, "-10", 10)); | 1485 | try std.testing.expectError(error.Overflow, parseInt(u32, "-10", 10)); |
| 1485 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, " 10", 10)); | 1486 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, " 10", 10)); |
| 1486 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "10 ", 10)); | 1487 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "10 ", 10)); |
| 1488 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "_10_", 10)); | ||
| 1489 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10_", 10)); | ||
| 1490 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x10_", 10)); | ||
| 1491 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10", 10)); | ||
| 1487 | try std.testing.expect((try parseInt(u8, "255", 10)) == 255); | 1492 | try std.testing.expect((try parseInt(u8, "255", 10)) == 255); |
| 1488 | try std.testing.expectError(error.Overflow, parseInt(u8, "256", 10)); | 1493 | try std.testing.expectError(error.Overflow, parseInt(u8, "256", 10)); |
| 1489 | 1494 | ||
| ... | @@ -1505,12 +1510,18 @@ test "parseInt" { | ... | @@ -1505,12 +1510,18 @@ test "parseInt" { |
| 1505 | 1510 | ||
| 1506 | // autodectect the radix | 1511 | // autodectect the radix |
| 1507 | try std.testing.expect((try parseInt(i32, "111", 0)) == 111); | 1512 | try std.testing.expect((try parseInt(i32, "111", 0)) == 111); |
| 1513 | try std.testing.expect((try parseInt(i32, "1_1_1", 0)) == 111); | ||
| 1514 | try std.testing.expect((try parseInt(i32, "1_1_1", 0)) == 111); | ||
| 1508 | try std.testing.expect((try parseInt(i32, "+0b111", 0)) == 7); | 1515 | try std.testing.expect((try parseInt(i32, "+0b111", 0)) == 7); |
| 1516 | try std.testing.expect((try parseInt(i32, "+0b1_11", 0)) == 7); | ||
| 1509 | try std.testing.expect((try parseInt(i32, "+0o111", 0)) == 73); | 1517 | try std.testing.expect((try parseInt(i32, "+0o111", 0)) == 73); |
| 1518 | try std.testing.expect((try parseInt(i32, "+0o11_1", 0)) == 73); | ||
| 1510 | try std.testing.expect((try parseInt(i32, "+0x111", 0)) == 273); | 1519 | try std.testing.expect((try parseInt(i32, "+0x111", 0)) == 273); |
| 1511 | try std.testing.expect((try parseInt(i32, "-0b111", 0)) == -7); | 1520 | try std.testing.expect((try parseInt(i32, "-0b111", 0)) == -7); |
| 1521 | try std.testing.expect((try parseInt(i32, "-0b11_1", 0)) == -7); | ||
| 1512 | try std.testing.expect((try parseInt(i32, "-0o111", 0)) == -73); | 1522 | try std.testing.expect((try parseInt(i32, "-0o111", 0)) == -73); |
| 1513 | try std.testing.expect((try parseInt(i32, "-0x111", 0)) == -273); | 1523 | try std.testing.expect((try parseInt(i32, "-0x111", 0)) == -273); |
| 1524 | try std.testing.expect((try parseInt(i32, "-0x1_11", 0)) == -273); | ||
| 1514 | 1525 | ||
| 1515 | // bare binary/octal/decimal prefix is invalid | 1526 | // bare binary/octal/decimal prefix is invalid |
| 1516 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); | 1527 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); |
| ... | @@ -1558,7 +1569,10 @@ fn parseWithSign( | ... | @@ -1558,7 +1569,10 @@ fn parseWithSign( |
| 1558 | 1569 | ||
| 1559 | var x: T = 0; | 1570 | var x: T = 0; |
| 1560 | 1571 | ||
| 1572 | if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; | ||
| 1573 | |||
| 1561 | for (buf_start) |c| { | 1574 | for (buf_start) |c| { |
| 1575 | if (c == '_') continue; | ||
| 1562 | const digit = try charToDigit(c, buf_radix); | 1576 | const digit = try charToDigit(c, buf_radix); |
| 1563 | 1577 | ||
| 1564 | if (x != 0) x = try math.mul(T, x, try math.cast(T, buf_radix)); | 1578 | if (x != 0) x = try math.mul(T, x, try math.cast(T, buf_radix)); |
| ... | @@ -1577,6 +1591,7 @@ fn parseWithSign( | ... | @@ -1577,6 +1591,7 @@ fn parseWithSign( |
| 1577 | /// * A prefix of "0x" implies radix=16, | 1591 | /// * A prefix of "0x" implies radix=16, |
| 1578 | /// * Otherwise radix=10 is assumed. | 1592 | /// * Otherwise radix=10 is assumed. |
| 1579 | /// | 1593 | /// |
| 1594 | /// Ignores '_' character in `buf`. | ||
| 1580 | /// See also `parseInt`. | 1595 | /// See also `parseInt`. |
| 1581 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { | 1596 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { |
| 1582 | return parseWithSign(T, buf, radix, .Pos); | 1597 | return parseWithSign(T, buf, radix, .Pos); |
| ... | @@ -1585,9 +1600,11 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError | ... | @@ -1585,9 +1600,11 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError |
| 1585 | test "parseUnsigned" { | 1600 | test "parseUnsigned" { |
| 1586 | try std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); | 1601 | try std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); |
| 1587 | try std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); | 1602 | try std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); |
| 1603 | try std.testing.expect((try parseUnsigned(u16, "65_535", 10)) == 65535); | ||
| 1588 | try std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); | 1604 | try std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); |
| 1589 | 1605 | ||
| 1590 | try std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); | 1606 | try std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); |
| 1607 | try std.testing.expect((try parseUnsigned(u64, "0f_fff_fff_fff_fff_fff", 16)) == 0xffffffffffffffff); | ||
| 1591 | try std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); | 1608 | try std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); |
| 1592 | 1609 | ||
| 1593 | try std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); | 1610 | try std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); |
| ... | @@ -1620,8 +1637,8 @@ pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; | ... | @@ -1620,8 +1637,8 @@ pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; |
| 1620 | pub const parseHexFloat = @import("fmt/parse_hex_float.zig").parseHexFloat; | 1637 | pub const parseHexFloat = @import("fmt/parse_hex_float.zig").parseHexFloat; |
| 1621 | 1638 | ||
| 1622 | test { | 1639 | test { |
| 1623 | _ = @import("fmt/parse_float.zig"); | 1640 | _ = parseFloat; |
| 1624 | _ = @import("fmt/parse_hex_float.zig"); | 1641 | _ = parseHexFloat; |
| 1625 | } | 1642 | } |
| 1626 | 1643 | ||
| 1627 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { | 1644 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { |
| ... | @@ -2004,7 +2021,7 @@ test "float.special" { | ... | @@ -2004,7 +2021,7 @@ test "float.special" { |
| 2004 | try expectFmt("f64: nan", "f64: {}", .{math.nan_f64}); | 2021 | try expectFmt("f64: nan", "f64: {}", .{math.nan_f64}); |
| 2005 | // negative nan is not defined by IEE 754, | 2022 | // negative nan is not defined by IEE 754, |
| 2006 | // and ARM thus normalizes it to positive nan | 2023 | // and ARM thus normalizes it to positive nan |
| 2007 | if (builtin.arch != builtin.Arch.arm) { | 2024 | if (builtin.target.cpu.arch != .arm) { |
| 2008 | try expectFmt("f64: -nan", "f64: {}", .{-math.nan_f64}); | 2025 | try expectFmt("f64: -nan", "f64: {}", .{-math.nan_f64}); |
| 2009 | } | 2026 | } |
| 2010 | try expectFmt("f64: inf", "f64: {}", .{math.inf_f64}); | 2027 | try expectFmt("f64: inf", "f64: {}", .{math.inf_f64}); |
| ... | @@ -2015,7 +2032,7 @@ test "float.hexadecimal.special" { | ... | @@ -2015,7 +2032,7 @@ test "float.hexadecimal.special" { |
| 2015 | try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64}); | 2032 | try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64}); |
| 2016 | // negative nan is not defined by IEE 754, | 2033 | // negative nan is not defined by IEE 754, |
| 2017 | // and ARM thus normalizes it to positive nan | 2034 | // and ARM thus normalizes it to positive nan |
| 2018 | if (builtin.arch != builtin.Arch.arm) { | 2035 | if (builtin.target.cpu.arch != .arm) { |
| 2019 | try expectFmt("f64: -nan", "f64: {x}", .{-math.nan_f64}); | 2036 | try expectFmt("f64: -nan", "f64: {x}", .{-math.nan_f64}); |
| 2020 | } | 2037 | } |
| 2021 | try expectFmt("f64: inf", "f64: {x}", .{math.inf_f64}); | 2038 | try expectFmt("f64: inf", "f64: {x}", .{math.inf_f64}); |
| ... | @@ -2364,15 +2381,15 @@ test "positional/alignment/width/precision" { | ... | @@ -2364,15 +2381,15 @@ test "positional/alignment/width/precision" { |
| 2364 | } | 2381 | } |
| 2365 | 2382 | ||
| 2366 | test "vector" { | 2383 | test "vector" { |
| 2367 | if (builtin.arch == .mipsel or builtin.arch == .mips) { | 2384 | if (builtin.target.cpu.arch == .mipsel or builtin.target.cpu.arch == .mips) { |
| 2368 | // https://github.com/ziglang/zig/issues/3317 | 2385 | // https://github.com/ziglang/zig/issues/3317 |
| 2369 | return error.SkipZigTest; | 2386 | return error.SkipZigTest; |
| 2370 | } | 2387 | } |
| 2371 | if (builtin.arch == .riscv64) { | 2388 | if (builtin.target.cpu.arch == .riscv64) { |
| 2372 | // https://github.com/ziglang/zig/issues/4486 | 2389 | // https://github.com/ziglang/zig/issues/4486 |
| 2373 | return error.SkipZigTest; | 2390 | return error.SkipZigTest; |
| 2374 | } | 2391 | } |
| 2375 | if (builtin.arch == .wasm32) { | 2392 | if (builtin.target.cpu.arch == .wasm32) { |
| 2376 | // https://github.com/ziglang/zig/issues/5339 | 2393 | // https://github.com/ziglang/zig/issues/5339 |
| 2377 | return error.SkipZigTest; | 2394 | return error.SkipZigTest; |
| 2378 | } | 2395 | } |
lib/std/fs.zig+2-2| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | const std = @import("std.zig"); | 7 | const std = @import("std.zig"); |
| 8 | const os = std.os; | 8 | const os = std.os; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| ... | @@ -572,7 +572,7 @@ pub const Dir = struct { | ... | @@ -572,7 +572,7 @@ pub const Dir = struct { |
| 572 | /// Memory such as file names referenced in this returned entry becomes invalid | 572 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 573 | /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized. | 573 | /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized. |
| 574 | pub fn next(self: *Self) Error!?Entry { | 574 | pub fn next(self: *Self) Error!?Entry { |
| 575 | start_over: while (true) { | 575 | while (true) { |
| 576 | const w = os.windows; | 576 | const w = os.windows; |
| 577 | if (self.index >= self.end_index) { | 577 | if (self.index >= self.end_index) { |
| 578 | var io: w.IO_STATUS_BLOCK = undefined; | 578 | var io: w.IO_STATUS_BLOCK = undefined; |
lib/std/fs/file.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const os = std.os; | 8 | const os = std.os; |
| 9 | const io = std.io; | 9 | const io = std.io; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
lib/std/fs/get_app_data_dir.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const unicode = std.unicode; | 8 | const unicode = std.unicode; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const fs = std.fs; | 10 | const fs = std.fs; |
lib/std/fs/path.zig+25-24| ... | @@ -15,22 +15,23 @@ const math = std.math; | ... | @@ -15,22 +15,23 @@ const math = std.math; |
| 15 | const windows = std.os.windows; | 15 | const windows = std.os.windows; |
| 16 | const fs = std.fs; | 16 | const fs = std.fs; |
| 17 | const process = std.process; | 17 | const process = std.process; |
| 18 | const native_os = builtin.target.os.tag; | ||
| 18 | 19 | ||
| 19 | pub const sep_windows = '\\'; | 20 | pub const sep_windows = '\\'; |
| 20 | pub const sep_posix = '/'; | 21 | pub const sep_posix = '/'; |
| 21 | pub const sep = if (builtin.os.tag == .windows) sep_windows else sep_posix; | 22 | pub const sep = if (native_os == .windows) sep_windows else sep_posix; |
| 22 | 23 | ||
| 23 | pub const sep_str_windows = "\\"; | 24 | pub const sep_str_windows = "\\"; |
| 24 | pub const sep_str_posix = "/"; | 25 | pub const sep_str_posix = "/"; |
| 25 | pub const sep_str = if (builtin.os.tag == .windows) sep_str_windows else sep_str_posix; | 26 | pub const sep_str = if (native_os == .windows) sep_str_windows else sep_str_posix; |
| 26 | 27 | ||
| 27 | pub const delimiter_windows = ';'; | 28 | pub const delimiter_windows = ';'; |
| 28 | pub const delimiter_posix = ':'; | 29 | pub const delimiter_posix = ':'; |
| 29 | pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix; | 30 | pub const delimiter = if (native_os == .windows) delimiter_windows else delimiter_posix; |
| 30 | 31 | ||
| 31 | /// Returns if the given byte is a valid path separator | 32 | /// Returns if the given byte is a valid path separator |
| 32 | pub fn isSep(byte: u8) bool { | 33 | pub fn isSep(byte: u8) bool { |
| 33 | if (builtin.os.tag == .windows) { | 34 | if (native_os == .windows) { |
| 34 | return byte == '/' or byte == '\\'; | 35 | return byte == '/' or byte == '\\'; |
| 35 | } else { | 36 | } else { |
| 36 | return byte == '/'; | 37 | return byte == '/'; |
| ... | @@ -168,7 +169,7 @@ test "join" { | ... | @@ -168,7 +169,7 @@ test "join" { |
| 168 | pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ"); | 169 | pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ"); |
| 169 | 170 | ||
| 170 | pub fn isAbsoluteZ(path_c: [*:0]const u8) bool { | 171 | pub fn isAbsoluteZ(path_c: [*:0]const u8) bool { |
| 171 | if (builtin.os.tag == .windows) { | 172 | if (native_os == .windows) { |
| 172 | return isAbsoluteWindowsZ(path_c); | 173 | return isAbsoluteWindowsZ(path_c); |
| 173 | } else { | 174 | } else { |
| 174 | return isAbsolutePosixZ(path_c); | 175 | return isAbsolutePosixZ(path_c); |
| ... | @@ -176,7 +177,7 @@ pub fn isAbsoluteZ(path_c: [*:0]const u8) bool { | ... | @@ -176,7 +177,7 @@ pub fn isAbsoluteZ(path_c: [*:0]const u8) bool { |
| 176 | } | 177 | } |
| 177 | 178 | ||
| 178 | pub fn isAbsolute(path: []const u8) bool { | 179 | pub fn isAbsolute(path: []const u8) bool { |
| 179 | if (builtin.os.tag == .windows) { | 180 | if (native_os == .windows) { |
| 180 | return isAbsoluteWindows(path); | 181 | return isAbsoluteWindows(path); |
| 181 | } else { | 182 | } else { |
| 182 | return isAbsolutePosix(path); | 183 | return isAbsolutePosix(path); |
| ... | @@ -365,7 +366,7 @@ test "windowsParsePath" { | ... | @@ -365,7 +366,7 @@ test "windowsParsePath" { |
| 365 | } | 366 | } |
| 366 | 367 | ||
| 367 | pub fn diskDesignator(path: []const u8) []const u8 { | 368 | pub fn diskDesignator(path: []const u8) []const u8 { |
| 368 | if (builtin.os.tag == .windows) { | 369 | if (native_os == .windows) { |
| 369 | return diskDesignatorWindows(path); | 370 | return diskDesignatorWindows(path); |
| 370 | } else { | 371 | } else { |
| 371 | return ""; | 372 | return ""; |
| ... | @@ -430,7 +431,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { | ... | @@ -430,7 +431,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool { |
| 430 | 431 | ||
| 431 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. | 432 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. |
| 432 | pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 433 | pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 433 | if (builtin.os.tag == .windows) { | 434 | if (native_os == .windows) { |
| 434 | return resolveWindows(allocator, paths); | 435 | return resolveWindows(allocator, paths); |
| 435 | } else { | 436 | } else { |
| 436 | return resolvePosix(allocator, paths); | 437 | return resolvePosix(allocator, paths); |
| ... | @@ -447,7 +448,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -447,7 +448,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 447 | /// Without performing actual syscalls, resolving `..` could be incorrect. | 448 | /// Without performing actual syscalls, resolving `..` could be incorrect. |
| 448 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 449 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 449 | if (paths.len == 0) { | 450 | if (paths.len == 0) { |
| 450 | assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd | 451 | assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd |
| 451 | return process.getCwdAlloc(allocator); | 452 | return process.getCwdAlloc(allocator); |
| 452 | } | 453 | } |
| 453 | 454 | ||
| ... | @@ -542,7 +543,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -542,7 +543,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 542 | result_disk_designator = result[0..result_index]; | 543 | result_disk_designator = result[0..result_index]; |
| 543 | }, | 544 | }, |
| 544 | WindowsPath.Kind.None => { | 545 | WindowsPath.Kind.None => { |
| 545 | assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd | 546 | assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd |
| 546 | const cwd = try process.getCwdAlloc(allocator); | 547 | const cwd = try process.getCwdAlloc(allocator); |
| 547 | defer allocator.free(cwd); | 548 | defer allocator.free(cwd); |
| 548 | const parsed_cwd = windowsParsePath(cwd); | 549 | const parsed_cwd = windowsParsePath(cwd); |
| ... | @@ -557,7 +558,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -557,7 +558,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 557 | }, | 558 | }, |
| 558 | } | 559 | } |
| 559 | } else { | 560 | } else { |
| 560 | assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd | 561 | assert(native_os == .windows); // resolveWindows called on non windows can't use getCwd |
| 561 | // TODO call get cwd for the result_disk_designator instead of the global one | 562 | // TODO call get cwd for the result_disk_designator instead of the global one |
| 562 | const cwd = try process.getCwdAlloc(allocator); | 563 | const cwd = try process.getCwdAlloc(allocator); |
| 563 | defer allocator.free(cwd); | 564 | defer allocator.free(cwd); |
| ... | @@ -628,7 +629,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -628,7 +629,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 628 | /// Without performing actual syscalls, resolving `..` could be incorrect. | 629 | /// Without performing actual syscalls, resolving `..` could be incorrect. |
| 629 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 630 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 630 | if (paths.len == 0) { | 631 | if (paths.len == 0) { |
| 631 | assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd | 632 | assert(native_os != .windows); // resolvePosix called on windows can't use getCwd |
| 632 | return process.getCwdAlloc(allocator); | 633 | return process.getCwdAlloc(allocator); |
| 633 | } | 634 | } |
| 634 | 635 | ||
| ... | @@ -650,7 +651,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -650,7 +651,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 650 | if (have_abs) { | 651 | if (have_abs) { |
| 651 | result = try allocator.alloc(u8, max_size); | 652 | result = try allocator.alloc(u8, max_size); |
| 652 | } else { | 653 | } else { |
| 653 | assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd | 654 | assert(native_os != .windows); // resolvePosix called on windows can't use getCwd |
| 654 | const cwd = try process.getCwdAlloc(allocator); | 655 | const cwd = try process.getCwdAlloc(allocator); |
| 655 | defer allocator.free(cwd); | 656 | defer allocator.free(cwd); |
| 656 | result = try allocator.alloc(u8, max_size + cwd.len + 1); | 657 | result = try allocator.alloc(u8, max_size + cwd.len + 1); |
| ... | @@ -690,11 +691,11 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ... | @@ -690,11 +691,11 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 690 | } | 691 | } |
| 691 | 692 | ||
| 692 | test "resolve" { | 693 | test "resolve" { |
| 693 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 694 | if (native_os == .wasi) return error.SkipZigTest; |
| 694 | 695 | ||
| 695 | const cwd = try process.getCwdAlloc(testing.allocator); | 696 | const cwd = try process.getCwdAlloc(testing.allocator); |
| 696 | defer testing.allocator.free(cwd); | 697 | defer testing.allocator.free(cwd); |
| 697 | if (builtin.os.tag == .windows) { | 698 | if (native_os == .windows) { |
| 698 | if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { | 699 | if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { |
| 699 | cwd[0] = asciiUpper(cwd[0]); | 700 | cwd[0] = asciiUpper(cwd[0]); |
| 700 | } | 701 | } |
| ... | @@ -706,12 +707,12 @@ test "resolve" { | ... | @@ -706,12 +707,12 @@ test "resolve" { |
| 706 | } | 707 | } |
| 707 | 708 | ||
| 708 | test "resolveWindows" { | 709 | test "resolveWindows" { |
| 709 | if (builtin.arch == .aarch64) { | 710 | if (builtin.target.cpu.arch == .aarch64) { |
| 710 | // TODO https://github.com/ziglang/zig/issues/3288 | 711 | // TODO https://github.com/ziglang/zig/issues/3288 |
| 711 | return error.SkipZigTest; | 712 | return error.SkipZigTest; |
| 712 | } | 713 | } |
| 713 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 714 | if (native_os == .wasi) return error.SkipZigTest; |
| 714 | if (builtin.os.tag == .windows) { | 715 | if (native_os == .windows) { |
| 715 | const cwd = try process.getCwdAlloc(testing.allocator); | 716 | const cwd = try process.getCwdAlloc(testing.allocator); |
| 716 | defer testing.allocator.free(cwd); | 717 | defer testing.allocator.free(cwd); |
| 717 | const parsed_cwd = windowsParsePath(cwd); | 718 | const parsed_cwd = windowsParsePath(cwd); |
| ... | @@ -755,7 +756,7 @@ test "resolveWindows" { | ... | @@ -755,7 +756,7 @@ test "resolveWindows" { |
| 755 | } | 756 | } |
| 756 | 757 | ||
| 757 | test "resolvePosix" { | 758 | test "resolvePosix" { |
| 758 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 759 | if (native_os == .wasi) return error.SkipZigTest; |
| 759 | 760 | ||
| 760 | try testResolvePosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); | 761 | try testResolvePosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); |
| 761 | try testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }, "/d/e"); | 762 | try testResolvePosix(&[_][]const u8{ "/a/b", "c", "//d", "e///" }, "/d/e"); |
| ... | @@ -788,7 +789,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void { | ... | @@ -788,7 +789,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void { |
| 788 | /// | 789 | /// |
| 789 | /// If the path is the root directory, returns null. | 790 | /// If the path is the root directory, returns null. |
| 790 | pub fn dirname(path: []const u8) ?[]const u8 { | 791 | pub fn dirname(path: []const u8) ?[]const u8 { |
| 791 | if (builtin.os.tag == .windows) { | 792 | if (native_os == .windows) { |
| 792 | return dirnameWindows(path); | 793 | return dirnameWindows(path); |
| 793 | } else { | 794 | } else { |
| 794 | return dirnamePosix(path); | 795 | return dirnamePosix(path); |
| ... | @@ -922,7 +923,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) !void { | ... | @@ -922,7 +923,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) !void { |
| 922 | } | 923 | } |
| 923 | 924 | ||
| 924 | pub fn basename(path: []const u8) []const u8 { | 925 | pub fn basename(path: []const u8) []const u8 { |
| 925 | if (builtin.os.tag == .windows) { | 926 | if (native_os == .windows) { |
| 926 | return basenameWindows(path); | 927 | return basenameWindows(path); |
| 927 | } else { | 928 | } else { |
| 928 | return basenamePosix(path); | 929 | return basenamePosix(path); |
| ... | @@ -1038,7 +1039,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) !void { | ... | @@ -1038,7 +1039,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) !void { |
| 1038 | /// string is returned. | 1039 | /// string is returned. |
| 1039 | /// On Windows this canonicalizes the drive to a capital letter and paths to `\\`. | 1040 | /// On Windows this canonicalizes the drive to a capital letter and paths to `\\`. |
| 1040 | pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 { | 1041 | pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 { |
| 1041 | if (builtin.os.tag == .windows) { | 1042 | if (native_os == .windows) { |
| 1042 | return relativeWindows(allocator, from, to); | 1043 | return relativeWindows(allocator, from, to); |
| 1043 | } else { | 1044 | } else { |
| 1044 | return relativePosix(allocator, from, to); | 1045 | return relativePosix(allocator, from, to); |
| ... | @@ -1164,11 +1165,11 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ | ... | @@ -1164,11 +1165,11 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ |
| 1164 | } | 1165 | } |
| 1165 | 1166 | ||
| 1166 | test "relative" { | 1167 | test "relative" { |
| 1167 | if (builtin.arch == .aarch64) { | 1168 | if (builtin.target.cpu.arch == .aarch64) { |
| 1168 | // TODO https://github.com/ziglang/zig/issues/3288 | 1169 | // TODO https://github.com/ziglang/zig/issues/3288 |
| 1169 | return error.SkipZigTest; | 1170 | return error.SkipZigTest; |
| 1170 | } | 1171 | } |
| 1171 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 1172 | if (native_os == .wasi) return error.SkipZigTest; |
| 1172 | 1173 | ||
| 1173 | try testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games"); | 1174 | try testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games"); |
| 1174 | try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", ".."); | 1175 | try testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", ".."); |
lib/std/fs/wasi.zig+1-1| ... | @@ -167,7 +167,7 @@ pub const PreopenList = struct { | ... | @@ -167,7 +167,7 @@ pub const PreopenList = struct { |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | test "extracting WASI preopens" { | 169 | test "extracting WASI preopens" { |
| 170 | if (@import("builtin").os.tag != .wasi) return error.SkipZigTest; | 170 | if (std.builtin.os.tag != .wasi) return error.SkipZigTest; |
| 171 | 171 | ||
| 172 | var preopens = PreopenList.init(std.testing.allocator); | 172 | var preopens = PreopenList.init(std.testing.allocator); |
| 173 | defer preopens.deinit(); | 173 | defer preopens.deinit(); |
lib/std/fs/watch.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const event = std.event; | 8 | const event = std.event; |
| 9 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| 10 | const testing = std.testing; | 10 | const testing = std.testing; |
lib/std/hash/auto_hash.zig+3-3| ... | @@ -4,10 +4,10 @@ | ... | @@ -4,10 +4,10 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | ||
| 8 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 9 | const mem = std.mem; | 8 | const mem = std.mem; |
| 10 | const meta = std.meta; | 9 | const meta = std.meta; |
| 10 | const builtin = std.builtin; | ||
| 11 | 11 | ||
| 12 | /// Describes how pointer types should be hashed. | 12 | /// Describes how pointer types should be hashed. |
| 13 | pub const HashStrategy = enum { | 13 | pub const HashStrategy = enum { |
| ... | @@ -239,7 +239,7 @@ fn testHashDeepRecursive(key: anytype) u64 { | ... | @@ -239,7 +239,7 @@ fn testHashDeepRecursive(key: anytype) u64 { |
| 239 | 239 | ||
| 240 | test "typeContainsSlice" { | 240 | test "typeContainsSlice" { |
| 241 | comptime { | 241 | comptime { |
| 242 | try testing.expect(!typeContainsSlice(meta.Tag(std.builtin.TypeInfo))); | 242 | try testing.expect(!typeContainsSlice(meta.Tag(builtin.TypeInfo))); |
| 243 | 243 | ||
| 244 | try testing.expect(typeContainsSlice([]const u8)); | 244 | try testing.expect(typeContainsSlice([]const u8)); |
| 245 | try testing.expect(!typeContainsSlice(u8)); | 245 | try testing.expect(!typeContainsSlice(u8)); |
| ... | @@ -400,7 +400,7 @@ test "testHash union" { | ... | @@ -400,7 +400,7 @@ test "testHash union" { |
| 400 | 400 | ||
| 401 | test "testHash vector" { | 401 | test "testHash vector" { |
| 402 | // Disabled because of #3317 | 402 | // Disabled because of #3317 |
| 403 | if (@import("builtin").arch == .mipsel or @import("builtin").arch == .mips) return error.SkipZigTest; | 403 | if (builtin.target.cpu.arch == .mipsel or builtin.target.cpu.arch == .mips) return error.SkipZigTest; |
| 404 | 404 | ||
| 405 | const a: meta.Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; | 405 | const a: meta.Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; |
| 406 | const b: meta.Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; | 406 | const b: meta.Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; |
lib/std/hash/benchmark.zig+1-1| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | // zig run benchmark.zig --release-fast --override-lib-dir .. | 6 | // zig run benchmark.zig --release-fast --override-lib-dir .. |
| 7 | 7 | ||
| 8 | const builtin = @import("builtin"); | 8 | const builtin = std.builtin; |
| 9 | const std = @import("std"); | 9 | const std = @import("std"); |
| 10 | const time = std.time; | 10 | const time = std.time; |
| 11 | const Timer = time.Timer; | 11 | const Timer = time.Timer; |
lib/std/hash/cityhash.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | 8 | ||
| 9 | fn offsetPtr(ptr: [*]const u8, offset: usize) callconv(.Inline) [*]const u8 { | 9 | fn offsetPtr(ptr: [*]const u8, offset: usize) callconv(.Inline) [*]const u8 { |
| 10 | // ptr + offset doesn't work at comptime so we need this instead. | 10 | // ptr + offset doesn't work at comptime so we need this instead. |
lib/std/hash/crc.zig+2-2| ... | @@ -28,7 +28,7 @@ pub const Crc32 = Crc32WithPoly(.IEEE); | ... | @@ -28,7 +28,7 @@ pub const Crc32 = Crc32WithPoly(.IEEE); |
| 28 | pub fn Crc32WithPoly(comptime poly: Polynomial) type { | 28 | pub fn Crc32WithPoly(comptime poly: Polynomial) type { |
| 29 | return struct { | 29 | return struct { |
| 30 | const Self = @This(); | 30 | const Self = @This(); |
| 31 | const lookup_tables = comptime block: { | 31 | const lookup_tables = block: { |
| 32 | @setEvalBranchQuota(20000); | 32 | @setEvalBranchQuota(20000); |
| 33 | var tables: [8][256]u32 = undefined; | 33 | var tables: [8][256]u32 = undefined; |
| 34 | 34 | ||
| ... | @@ -128,7 +128,7 @@ test "crc32 castagnoli" { | ... | @@ -128,7 +128,7 @@ test "crc32 castagnoli" { |
| 128 | pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { | 128 | pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type { |
| 129 | return struct { | 129 | return struct { |
| 130 | const Self = @This(); | 130 | const Self = @This(); |
| 131 | const lookup_table = comptime block: { | 131 | const lookup_table = block: { |
| 132 | var table: [16]u32 = undefined; | 132 | var table: [16]u32 = undefined; |
| 133 | 133 | ||
| 134 | for (table) |*e, i| { | 134 | for (table) |*e, i| { |
lib/std/hash/murmur.zig+9-8| ... | @@ -6,6 +6,7 @@ | ... | @@ -6,6 +6,7 @@ |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const testing = std.testing; | 8 | const testing = std.testing; |
| 9 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 9 | 10 | ||
| 10 | const default_seed: u32 = 0xc70f6907; | 11 | const default_seed: u32 = 0xc70f6907; |
| 11 | 12 | ||
| ... | @@ -22,7 +23,7 @@ pub const Murmur2_32 = struct { | ... | @@ -22,7 +23,7 @@ pub const Murmur2_32 = struct { |
| 22 | var h1: u32 = seed ^ len; | 23 | var h1: u32 = seed ^ len; |
| 23 | for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { | 24 | for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { |
| 24 | var k1: u32 = v; | 25 | var k1: u32 = v; |
| 25 | if (builtin.endian == .Big) | 26 | if (native_endian == .Big) |
| 26 | k1 = @byteSwap(u32, k1); | 27 | k1 = @byteSwap(u32, k1); |
| 27 | k1 *%= m; | 28 | k1 *%= m; |
| 28 | k1 ^= k1 >> 24; | 29 | k1 ^= k1 >> 24; |
| ... | @@ -107,7 +108,7 @@ pub const Murmur2_64 = struct { | ... | @@ -107,7 +108,7 @@ pub const Murmur2_64 = struct { |
| 107 | var h1: u64 = seed ^ (len *% m); | 108 | var h1: u64 = seed ^ (len *% m); |
| 108 | for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { | 109 | for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { |
| 109 | var k1: u64 = v; | 110 | var k1: u64 = v; |
| 110 | if (builtin.endian == .Big) | 111 | if (native_endian == .Big) |
| 111 | k1 = @byteSwap(u64, k1); | 112 | k1 = @byteSwap(u64, k1); |
| 112 | k1 *%= m; | 113 | k1 *%= m; |
| 113 | k1 ^= k1 >> 47; | 114 | k1 ^= k1 >> 47; |
| ... | @@ -120,7 +121,7 @@ pub const Murmur2_64 = struct { | ... | @@ -120,7 +121,7 @@ pub const Murmur2_64 = struct { |
| 120 | if (rest > 0) { | 121 | if (rest > 0) { |
| 121 | var k1: u64 = 0; | 122 | var k1: u64 = 0; |
| 122 | @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest)); | 123 | @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest)); |
| 123 | if (builtin.endian == .Big) | 124 | if (native_endian == .Big) |
| 124 | k1 = @byteSwap(u64, k1); | 125 | k1 = @byteSwap(u64, k1); |
| 125 | h1 ^= k1; | 126 | h1 ^= k1; |
| 126 | h1 *%= m; | 127 | h1 *%= m; |
| ... | @@ -187,7 +188,7 @@ pub const Murmur3_32 = struct { | ... | @@ -187,7 +188,7 @@ pub const Murmur3_32 = struct { |
| 187 | var h1: u32 = seed; | 188 | var h1: u32 = seed; |
| 188 | for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { | 189 | for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { |
| 189 | var k1: u32 = v; | 190 | var k1: u32 = v; |
| 190 | if (builtin.endian == .Big) | 191 | if (native_endian == .Big) |
| 191 | k1 = @byteSwap(u32, k1); | 192 | k1 = @byteSwap(u32, k1); |
| 192 | k1 *%= c1; | 193 | k1 *%= c1; |
| 193 | k1 = rotl32(k1, 15); | 194 | k1 = rotl32(k1, 15); |
| ... | @@ -299,7 +300,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 { | ... | @@ -299,7 +300,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 { |
| 299 | key[i] = @truncate(u8, i); | 300 | key[i] = @truncate(u8, i); |
| 300 | 301 | ||
| 301 | var h = hash_fn(key[0..i], 256 - i); | 302 | var h = hash_fn(key[0..i], 256 - i); |
| 302 | if (builtin.endian == .Big) | 303 | if (native_endian == .Big) |
| 303 | h = @byteSwap(@TypeOf(h), h); | 304 | h = @byteSwap(@TypeOf(h), h); |
| 304 | @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes); | 305 | @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes); |
| 305 | } | 306 | } |
| ... | @@ -313,7 +314,7 @@ test "murmur2_32" { | ... | @@ -313,7 +314,7 @@ test "murmur2_32" { |
| 313 | var v1: u64 = 0x1234567812345678; | 314 | var v1: u64 = 0x1234567812345678; |
| 314 | var v0le: u32 = v0; | 315 | var v0le: u32 = v0; |
| 315 | var v1le: u64 = v1; | 316 | var v1le: u64 = v1; |
| 316 | if (builtin.endian == .Big) { | 317 | if (native_endian == .Big) { |
| 317 | v0le = @byteSwap(u32, v0le); | 318 | v0le = @byteSwap(u32, v0le); |
| 318 | v1le = @byteSwap(u64, v1le); | 319 | v1le = @byteSwap(u64, v1le); |
| 319 | } | 320 | } |
| ... | @@ -327,7 +328,7 @@ test "murmur2_64" { | ... | @@ -327,7 +328,7 @@ test "murmur2_64" { |
| 327 | var v1: u64 = 0x1234567812345678; | 328 | var v1: u64 = 0x1234567812345678; |
| 328 | var v0le: u32 = v0; | 329 | var v0le: u32 = v0; |
| 329 | var v1le: u64 = v1; | 330 | var v1le: u64 = v1; |
| 330 | if (builtin.endian == .Big) { | 331 | if (native_endian == .Big) { |
| 331 | v0le = @byteSwap(u32, v0le); | 332 | v0le = @byteSwap(u32, v0le); |
| 332 | v1le = @byteSwap(u64, v1le); | 333 | v1le = @byteSwap(u64, v1le); |
| 333 | } | 334 | } |
| ... | @@ -341,7 +342,7 @@ test "murmur3_32" { | ... | @@ -341,7 +342,7 @@ test "murmur3_32" { |
| 341 | var v1: u64 = 0x1234567812345678; | 342 | var v1: u64 = 0x1234567812345678; |
| 342 | var v0le: u32 = v0; | 343 | var v0le: u32 = v0; |
| 343 | var v1le: u64 = v1; | 344 | var v1le: u64 = v1; |
| 344 | if (builtin.endian == .Big) { | 345 | if (native_endian == .Big) { |
| 345 | v0le = @byteSwap(u32, v0le); | 346 | v0le = @byteSwap(u32, v0le); |
| 346 | v1le = @byteSwap(u64, v1le); | 347 | v1le = @byteSwap(u64, v1le); |
| 347 | } | 348 | } |
lib/std/hash_map.zig-1| ... | @@ -4,7 +4,6 @@ | ... | @@ -4,7 +4,6 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | ||
| 8 | const assert = debug.assert; | 7 | const assert = debug.assert; |
| 9 | const autoHash = std.hash.autoHash; | 8 | const autoHash = std.hash.autoHash; |
| 10 | const debug = std.debug; | 9 | const debug = std.debug; |
lib/std/heap.zig+4-4| ... | @@ -10,7 +10,7 @@ const assert = debug.assert; | ... | @@ -10,7 +10,7 @@ const assert = debug.assert; |
| 10 | const testing = std.testing; | 10 | const testing = std.testing; |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const os = std.os; | 12 | const os = std.os; |
| 13 | const builtin = @import("builtin"); | 13 | const builtin = std.builtin; |
| 14 | const c = std.c; | 14 | const c = std.c; |
| 15 | const maxInt = std.math.maxInt; | 15 | const maxInt = std.math.maxInt; |
| 16 | 16 | ||
| ... | @@ -28,17 +28,17 @@ const CAllocator = struct { | ... | @@ -28,17 +28,17 @@ const CAllocator = struct { |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | usingnamespace if (comptime @hasDecl(c, "malloc_size")) | 31 | usingnamespace if (@hasDecl(c, "malloc_size")) |
| 32 | struct { | 32 | struct { |
| 33 | pub const supports_malloc_size = true; | 33 | pub const supports_malloc_size = true; |
| 34 | pub const malloc_size = c.malloc_size; | 34 | pub const malloc_size = c.malloc_size; |
| 35 | } | 35 | } |
| 36 | else if (comptime @hasDecl(c, "malloc_usable_size")) | 36 | else if (@hasDecl(c, "malloc_usable_size")) |
| 37 | struct { | 37 | struct { |
| 38 | pub const supports_malloc_size = true; | 38 | pub const supports_malloc_size = true; |
| 39 | pub const malloc_size = c.malloc_usable_size; | 39 | pub const malloc_size = c.malloc_usable_size; |
| 40 | } | 40 | } |
| 41 | else if (comptime @hasDecl(c, "_msize")) | 41 | else if (@hasDecl(c, "_msize")) |
| 42 | struct { | 42 | struct { |
| 43 | pub const supports_malloc_size = true; | 43 | pub const supports_malloc_size = true; |
| 44 | pub const malloc_size = c._msize; | 44 | pub const malloc_size = c._msize; |
lib/std/heap/general_purpose_allocator.zig+7-2| ... | @@ -317,7 +317,10 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -317,7 +317,10 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 317 | if (is_used) { | 317 | if (is_used) { |
| 318 | const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index); | 318 | const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index); |
| 319 | const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc); | 319 | const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc); |
| 320 | log.err("Memory leak detected: {s}", .{stack_trace}); | 320 | const addr = bucket.page + slot_index * size_class; |
| 321 | log.err("memory address 0x{x} leaked: {s}", .{ | ||
| 322 | @ptrToInt(addr), stack_trace, | ||
| 323 | }); | ||
| 321 | leaks = true; | 324 | leaks = true; |
| 322 | } | 325 | } |
| 323 | if (bit_index == math.maxInt(u3)) | 326 | if (bit_index == math.maxInt(u3)) |
| ... | @@ -345,7 +348,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -345,7 +348,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 345 | } | 348 | } |
| 346 | var it = self.large_allocations.iterator(); | 349 | var it = self.large_allocations.iterator(); |
| 347 | while (it.next()) |large_alloc| { | 350 | while (it.next()) |large_alloc| { |
| 348 | log.err("Memory leak detected: {s}", .{large_alloc.value.getStackTrace()}); | 351 | log.err("memory address 0x{x} leaked: {s}", .{ |
| 352 | @ptrToInt(large_alloc.value.bytes.ptr), large_alloc.value.getStackTrace(), | ||
| 353 | }); | ||
| 349 | leaks = true; | 354 | leaks = true; |
| 350 | } | 355 | } |
| 351 | return leaks; | 356 | return leaks; |
lib/std/io.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const root = @import("root"); | 8 | const root = @import("root"); |
| 9 | const c = std.c; | 9 | const c = std.c; |
| 10 | 10 |
lib/std/io/bit_reader.zig+3-3| ... | @@ -23,9 +23,9 @@ pub fn BitReader(endian: builtin.Endian, comptime ReaderType: type) type { | ... | @@ -23,9 +23,9 @@ pub fn BitReader(endian: builtin.Endian, comptime ReaderType: type) type { |
| 23 | pub const Reader = io.Reader(*Self, Error, read); | 23 | pub const Reader = io.Reader(*Self, Error, read); |
| 24 | 24 | ||
| 25 | const Self = @This(); | 25 | const Self = @This(); |
| 26 | const u8_bit_count = comptime meta.bitCount(u8); | 26 | const u8_bit_count = meta.bitCount(u8); |
| 27 | const u7_bit_count = comptime meta.bitCount(u7); | 27 | const u7_bit_count = meta.bitCount(u7); |
| 28 | const u4_bit_count = comptime meta.bitCount(u4); | 28 | const u4_bit_count = meta.bitCount(u4); |
| 29 | 29 | ||
| 30 | pub fn init(forward_reader: ReaderType) Self { | 30 | pub fn init(forward_reader: ReaderType) Self { |
| 31 | return Self{ | 31 | return Self{ |
lib/std/io/bit_writer.zig+2-2| ... | @@ -23,8 +23,8 @@ pub fn BitWriter(endian: builtin.Endian, comptime WriterType: type) type { | ... | @@ -23,8 +23,8 @@ pub fn BitWriter(endian: builtin.Endian, comptime WriterType: type) type { |
| 23 | pub const Writer = io.Writer(*Self, Error, write); | 23 | pub const Writer = io.Writer(*Self, Error, write); |
| 24 | 24 | ||
| 25 | const Self = @This(); | 25 | const Self = @This(); |
| 26 | const u8_bit_count = comptime meta.bitCount(u8); | 26 | const u8_bit_count = meta.bitCount(u8); |
| 27 | const u4_bit_count = comptime meta.bitCount(u4); | 27 | const u4_bit_count = meta.bitCount(u4); |
| 28 | 28 | ||
| 29 | pub fn init(forward_writer: WriterType) Self { | 29 | pub fn init(forward_writer: WriterType) Self { |
| 30 | return Self{ | 30 | return Self{ |
lib/std/io/test.zig+4-3| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | 7 | const builtin = @import("builtin"); |
| 8 | const io = std.io; | 8 | const io = std.io; |
| 9 | const meta = std.meta; | 9 | const meta = std.meta; |
| 10 | const trait = std.trait; | 10 | const trait = std.trait; |
| ... | @@ -15,6 +15,7 @@ const expectError = std.testing.expectError; | ... | @@ -15,6 +15,7 @@ const expectError = std.testing.expectError; |
| 15 | const mem = std.mem; | 15 | const mem = std.mem; |
| 16 | const fs = std.fs; | 16 | const fs = std.fs; |
| 17 | const File = std.fs.File; | 17 | const File = std.fs.File; |
| 18 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 18 | 19 | ||
| 19 | const tmpDir = std.testing.tmpDir; | 20 | const tmpDir = std.testing.tmpDir; |
| 20 | 21 | ||
| ... | @@ -72,7 +73,7 @@ test "BitStreams with File Stream" { | ... | @@ -72,7 +73,7 @@ test "BitStreams with File Stream" { |
| 72 | var file = try tmp.dir.createFile(tmp_file_name, .{}); | 73 | var file = try tmp.dir.createFile(tmp_file_name, .{}); |
| 73 | defer file.close(); | 74 | defer file.close(); |
| 74 | 75 | ||
| 75 | var bit_stream = io.bitWriter(builtin.endian, file.writer()); | 76 | var bit_stream = io.bitWriter(native_endian, file.writer()); |
| 76 | 77 | ||
| 77 | try bit_stream.writeBits(@as(u2, 1), 1); | 78 | try bit_stream.writeBits(@as(u2, 1), 1); |
| 78 | try bit_stream.writeBits(@as(u5, 2), 2); | 79 | try bit_stream.writeBits(@as(u5, 2), 2); |
| ... | @@ -86,7 +87,7 @@ test "BitStreams with File Stream" { | ... | @@ -86,7 +87,7 @@ test "BitStreams with File Stream" { |
| 86 | var file = try tmp.dir.openFile(tmp_file_name, .{}); | 87 | var file = try tmp.dir.openFile(tmp_file_name, .{}); |
| 87 | defer file.close(); | 88 | defer file.close(); |
| 88 | 89 | ||
| 89 | var bit_stream = io.bitReader(builtin.endian, file.reader()); | 90 | var bit_stream = io.bitReader(native_endian, file.reader()); |
| 90 | 91 | ||
| 91 | var out_bits: usize = undefined; | 92 | var out_bits: usize = undefined; |
| 92 | 93 |
lib/std/json.zig+2-2| ... | @@ -195,7 +195,7 @@ pub const StreamingParser = struct { | ... | @@ -195,7 +195,7 @@ pub const StreamingParser = struct { |
| 195 | p.number_is_integer = undefined; | 195 | p.number_is_integer = undefined; |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | pub const State = enum { | 198 | pub const State = enum(u8) { |
| 199 | // These must be first with these explicit values as we rely on them for indexing the | 199 | // These must be first with these explicit values as we rely on them for indexing the |
| 200 | // bit-stack directly and avoiding a branch. | 200 | // bit-stack directly and avoiding a branch. |
| 201 | ObjectSeparator = 0, | 201 | ObjectSeparator = 0, |
| ... | @@ -1781,7 +1781,7 @@ test "parse" { | ... | @@ -1781,7 +1781,7 @@ test "parse" { |
| 1781 | } | 1781 | } |
| 1782 | 1782 | ||
| 1783 | test "parse into enum" { | 1783 | test "parse into enum" { |
| 1784 | const T = extern enum { | 1784 | const T = enum(u32) { |
| 1785 | Foo = 42, | 1785 | Foo = 42, |
| 1786 | Bar, | 1786 | Bar, |
| 1787 | @"with\\escape", | 1787 | @"with\\escape", |
lib/std/macho.zig+3-3| ... | @@ -1365,7 +1365,7 @@ pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0; | ... | @@ -1365,7 +1365,7 @@ pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0; |
| 1365 | pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0; | 1365 | pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0; |
| 1366 | pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xc0; | 1366 | pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xc0; |
| 1367 | 1367 | ||
| 1368 | pub const reloc_type_x86_64 = packed enum(u4) { | 1368 | pub const reloc_type_x86_64 = enum(u4) { |
| 1369 | /// for absolute addresses | 1369 | /// for absolute addresses |
| 1370 | X86_64_RELOC_UNSIGNED = 0, | 1370 | X86_64_RELOC_UNSIGNED = 0, |
| 1371 | 1371 | ||
| ... | @@ -1397,9 +1397,9 @@ pub const reloc_type_x86_64 = packed enum(u4) { | ... | @@ -1397,9 +1397,9 @@ pub const reloc_type_x86_64 = packed enum(u4) { |
| 1397 | X86_64_RELOC_TLV, | 1397 | X86_64_RELOC_TLV, |
| 1398 | }; | 1398 | }; |
| 1399 | 1399 | ||
| 1400 | pub const reloc_type_arm64 = packed enum(u4) { | 1400 | pub const reloc_type_arm64 = enum(u4) { |
| 1401 | /// For pointers. | 1401 | /// For pointers. |
| 1402 | ARM64_RELOC_UNSIGNED = 0, | 1402 | ARM64_RELOC_UNSIGNED, |
| 1403 | 1403 | ||
| 1404 | /// Must be followed by a ARM64_RELOC_UNSIGNED. | 1404 | /// Must be followed by a ARM64_RELOC_UNSIGNED. |
| 1405 | ARM64_RELOC_SUBTRACTOR, | 1405 | ARM64_RELOC_SUBTRACTOR, |
lib/std/math.zig+6-6| ... | @@ -986,9 +986,9 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo( | ... | @@ -986,9 +986,9 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo( |
| 986 | comptime assert(@typeInfo(T) == .Int); | 986 | comptime assert(@typeInfo(T) == .Int); |
| 987 | comptime assert(@typeInfo(T).Int.signedness == .unsigned); | 987 | comptime assert(@typeInfo(T).Int.signedness == .unsigned); |
| 988 | assert(value != 0); | 988 | assert(value != 0); |
| 989 | comptime const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1); | 989 | const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1); |
| 990 | comptime const shiftType = std.math.Log2Int(PromotedType); | 990 | const ShiftType = std.math.Log2Int(PromotedType); |
| 991 | return @as(PromotedType, 1) << @intCast(shiftType, @typeInfo(T).Int.bits - @clz(T, value - 1)); | 991 | return @as(PromotedType, 1) << @intCast(ShiftType, @typeInfo(T).Int.bits - @clz(T, value - 1)); |
| 992 | } | 992 | } |
| 993 | 993 | ||
| 994 | /// Returns the next power of two (if the value is not already a power of two). | 994 | /// Returns the next power of two (if the value is not already a power of two). |
| ... | @@ -998,8 +998,8 @@ pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { | ... | @@ -998,8 +998,8 @@ pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { |
| 998 | comptime assert(@typeInfo(T) == .Int); | 998 | comptime assert(@typeInfo(T) == .Int); |
| 999 | const info = @typeInfo(T).Int; | 999 | const info = @typeInfo(T).Int; |
| 1000 | comptime assert(info.signedness == .unsigned); | 1000 | comptime assert(info.signedness == .unsigned); |
| 1001 | comptime const PromotedType = std.meta.Int(info.signedness, info.bits + 1); | 1001 | const PromotedType = std.meta.Int(info.signedness, info.bits + 1); |
| 1002 | comptime const overflowBit = @as(PromotedType, 1) << info.bits; | 1002 | const overflowBit = @as(PromotedType, 1) << info.bits; |
| 1003 | var x = ceilPowerOfTwoPromote(T, value); | 1003 | var x = ceilPowerOfTwoPromote(T, value); |
| 1004 | if (overflowBit & x != 0) { | 1004 | if (overflowBit & x != 0) { |
| 1005 | return error.Overflow; | 1005 | return error.Overflow; |
| ... | @@ -1327,7 +1327,7 @@ test "order.compare" { | ... | @@ -1327,7 +1327,7 @@ test "order.compare" { |
| 1327 | } | 1327 | } |
| 1328 | 1328 | ||
| 1329 | test "math.comptime" { | 1329 | test "math.comptime" { |
| 1330 | comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5)); | 1330 | const v = comptime (sin(@as(f32, 1)) + ln(@as(f32, 5))); |
| 1331 | try testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5))); | 1331 | try testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5))); |
| 1332 | } | 1332 | } |
| 1333 | 1333 |
lib/std/math/acosh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/acoshf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/acoshf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/acosh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/acosh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
lib/std/math/ceil.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
lib/std/math/complex/atan.zig-1| ... | @@ -10,7 +10,6 @@ | ... | @@ -10,7 +10,6 @@ |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/catan.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/catan.c |
| 11 | 11 | ||
| 12 | const std = @import("../../std.zig"); | 12 | const std = @import("../../std.zig"); |
| 13 | const builtin = @import("builtin"); | ||
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 15 | const math = std.math; | 14 | const math = std.math; |
| 16 | const cmath = math.complex; | 15 | const cmath = math.complex; |
lib/std/math/complex/cosh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ccoshf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ccoshf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ccosh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ccosh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../../std.zig"); | 12 | const std = @import("../../std.zig"); |
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/complex/exp.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/cexpf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/cexpf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/cexp.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/cexp.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../../std.zig"); | 12 | const std = @import("../../std.zig"); |
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/complex/sinh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/csinhf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/csinhf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/csinh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/csinh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../../std.zig"); | 12 | const std = @import("../../std.zig"); |
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/complex/tanh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanhf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanhf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/complex/ctanh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../../std.zig"); | 12 | const std = @import("../../std.zig"); |
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/cos.zig-1| ... | @@ -8,7 +8,6 @@ | ... | @@ -8,7 +8,6 @@ |
| 8 | // | 8 | // |
| 9 | // https://golang.org/src/math/sin.go | 9 | // https://golang.org/src/math/sin.go |
| 10 | 10 | ||
| 11 | const builtin = @import("builtin"); | ||
| 12 | const std = @import("../std.zig"); | 11 | const std = @import("../std.zig"); |
| 13 | const math = std.math; | 12 | const math = std.math; |
| 14 | const expect = std.testing.expect; | 13 | const expect = std.testing.expect; |
lib/std/math/cosh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/coshf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/coshf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/cosh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/cosh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expo2 = @import("expo2.zig").expo2; | 14 | const expo2 = @import("expo2.zig").expo2; |
lib/std/math/expm1.zig-1| ... | @@ -11,7 +11,6 @@ | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | ||
| 12 | // TODO: Updated recently. | 12 | // TODO: Updated recently. |
| 13 | 13 | ||
| 14 | const builtin = @import("builtin"); | ||
| 15 | const std = @import("../std.zig"); | 14 | const std = @import("../std.zig"); |
| 16 | const math = std.math; | 15 | const math = std.math; |
| 17 | const expect = std.testing.expect; | 16 | const expect = std.testing.expect; |
lib/std/math/floor.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const expect = std.testing.expect; | 12 | const expect = std.testing.expect; |
| 14 | const std = @import("../std.zig"); | 13 | const std = @import("../std.zig"); |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/log1p.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log1pf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log1pf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log1p.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/log1p.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
lib/std/math/pow.zig-1| ... | @@ -8,7 +8,6 @@ | ... | @@ -8,7 +8,6 @@ |
| 8 | // | 8 | // |
| 9 | // https://golang.org/src/math/pow.go | 9 | // https://golang.org/src/math/pow.go |
| 10 | 10 | ||
| 11 | const builtin = @import("builtin"); | ||
| 12 | const std = @import("../std.zig"); | 11 | const std = @import("../std.zig"); |
| 13 | const math = std.math; | 12 | const math = std.math; |
| 14 | const expect = std.testing.expect; | 13 | const expect = std.testing.expect; |
lib/std/math/powi.zig-1| ... | @@ -8,7 +8,6 @@ | ... | @@ -8,7 +8,6 @@ |
| 8 | // | 8 | // |
| 9 | // https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/src/libcore/num/mod.rs#L3423 | 9 | // https://github.com/rust-lang/rust/blob/360432f1e8794de58cd94f34c9c17ad65871e5b5/src/libcore/num/mod.rs#L3423 |
| 10 | 10 | ||
| 11 | const builtin = @import("builtin"); | ||
| 12 | const std = @import("../std.zig"); | 11 | const std = @import("../std.zig"); |
| 13 | const math = std.math; | 12 | const math = std.math; |
| 14 | const assert = std.debug.assert; | 13 | const assert = std.debug.assert; |
lib/std/math/round.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/roundf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/round.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/round.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const expect = std.testing.expect; | 12 | const expect = std.testing.expect; |
| 14 | const std = @import("../std.zig"); | 13 | const std = @import("../std.zig"); |
| 15 | const math = std.math; | 14 | const math = std.math; |
lib/std/math/sin.zig-1| ... | @@ -8,7 +8,6 @@ | ... | @@ -8,7 +8,6 @@ |
| 8 | // | 8 | // |
| 9 | // https://golang.org/src/math/sin.go | 9 | // https://golang.org/src/math/sin.go |
| 10 | 10 | ||
| 11 | const builtin = @import("builtin"); | ||
| 12 | const std = @import("../std.zig"); | 11 | const std = @import("../std.zig"); |
| 13 | const math = std.math; | 12 | const math = std.math; |
| 14 | const expect = std.testing.expect; | 13 | const expect = std.testing.expect; |
lib/std/math/sinh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinhf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinhf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/sinh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
lib/std/math/sqrt.zig+1-2| ... | @@ -6,8 +6,7 @@ | ... | @@ -6,8 +6,7 @@ |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const expect = std.testing.expect; | 8 | const expect = std.testing.expect; |
| 9 | const builtin = @import("builtin"); | 9 | const TypeId = std.builtin.TypeId; |
| 10 | const TypeId = builtin.TypeId; | ||
| 11 | const maxInt = std.math.maxInt; | 10 | const maxInt = std.math.maxInt; |
| 12 | 11 | ||
| 13 | /// Returns the square root of x. | 12 | /// Returns the square root of x. |
lib/std/math/tan.zig-1| ... | @@ -8,7 +8,6 @@ | ... | @@ -8,7 +8,6 @@ |
| 8 | // | 8 | // |
| 9 | // https://golang.org/src/math/tan.go | 9 | // https://golang.org/src/math/tan.go |
| 10 | 10 | ||
| 11 | const builtin = @import("builtin"); | ||
| 12 | const std = @import("../std.zig"); | 11 | const std = @import("../std.zig"); |
| 13 | const math = std.math; | 12 | const math = std.math; |
| 14 | const expect = std.testing.expect; | 13 | const expect = std.testing.expect; |
lib/std/math/tanh.zig-1| ... | @@ -9,7 +9,6 @@ | ... | @@ -9,7 +9,6 @@ |
| 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanhf.c | 9 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanhf.c |
| 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanh.c | 10 | // https://git.musl-libc.org/cgit/musl/tree/src/math/tanh.c |
| 11 | 11 | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const std = @import("../std.zig"); | 12 | const std = @import("../std.zig"); |
| 14 | const math = std.math; | 13 | const math = std.math; |
| 15 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
lib/std/mem.zig+47-46| ... | @@ -7,17 +7,18 @@ const std = @import("std.zig"); | ... | @@ -7,17 +7,18 @@ const std = @import("std.zig"); |
| 7 | const debug = std.debug; | 7 | const debug = std.debug; |
| 8 | const assert = debug.assert; | 8 | const assert = debug.assert; |
| 9 | const math = std.math; | 9 | const math = std.math; |
| 10 | const builtin = std.builtin; | ||
| 11 | const mem = @This(); | 10 | const mem = @This(); |
| 12 | const meta = std.meta; | 11 | const meta = std.meta; |
| 13 | const trait = meta.trait; | 12 | const trait = meta.trait; |
| 14 | const testing = std.testing; | 13 | const testing = std.testing; |
| 14 | const Endian = std.builtin.Endian; | ||
| 15 | const native_endian = std.Target.current.cpu.arch.endian(); | ||
| 15 | 16 | ||
| 16 | /// Compile time known minimum page size. | 17 | /// Compile time known minimum page size. |
| 17 | /// https://github.com/ziglang/zig/issues/4082 | 18 | /// https://github.com/ziglang/zig/issues/4082 |
| 18 | pub const page_size = switch (builtin.arch) { | 19 | pub const page_size = switch (std.Target.current.cpu.arch) { |
| 19 | .wasm32, .wasm64 => 64 * 1024, | 20 | .wasm32, .wasm64 => 64 * 1024, |
| 20 | .aarch64 => switch (builtin.os.tag) { | 21 | .aarch64 => switch (std.Target.current.os.tag) { |
| 21 | .macos, .ios, .watchos, .tvos => 16 * 1024, | 22 | .macos, .ios, .watchos, .tvos => 16 * 1024, |
| 22 | else => 4 * 1024, | 23 | else => 4 * 1024, |
| 23 | }, | 24 | }, |
| ... | @@ -355,7 +356,7 @@ test "mem.zeroes" { | ... | @@ -355,7 +356,7 @@ test "mem.zeroes" { |
| 355 | /// If the field is present in the provided initial values, it will have that value instead. | 356 | /// If the field is present in the provided initial values, it will have that value instead. |
| 356 | /// Structs are initialized recursively. | 357 | /// Structs are initialized recursively. |
| 357 | pub fn zeroInit(comptime T: type, init: anytype) T { | 358 | pub fn zeroInit(comptime T: type, init: anytype) T { |
| 358 | comptime const Init = @TypeOf(init); | 359 | const Init = @TypeOf(init); |
| 359 | 360 | ||
| 360 | switch (@typeInfo(T)) { | 361 | switch (@typeInfo(T)) { |
| 361 | .Struct => |struct_info| { | 362 | .Struct => |struct_info| { |
| ... | @@ -1230,7 +1231,7 @@ test "mem.containsAtLeast" { | ... | @@ -1230,7 +1231,7 @@ test "mem.containsAtLeast" { |
| 1230 | /// Reads an integer from memory with size equal to bytes.len. | 1231 | /// Reads an integer from memory with size equal to bytes.len. |
| 1231 | /// T specifies the return type, which must be large enough to store | 1232 | /// T specifies the return type, which must be large enough to store |
| 1232 | /// the result. | 1233 | /// the result. |
| 1233 | pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType { | 1234 | pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) ReturnType { |
| 1234 | var result: ReturnType = 0; | 1235 | var result: ReturnType = 0; |
| 1235 | switch (endian) { | 1236 | switch (endian) { |
| 1236 | .Big => { | 1237 | .Big => { |
| ... | @@ -1265,12 +1266,12 @@ pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).In | ... | @@ -1265,12 +1266,12 @@ pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).In |
| 1265 | return @byteSwap(T, readIntNative(T, bytes)); | 1266 | return @byteSwap(T, readIntNative(T, bytes)); |
| 1266 | } | 1267 | } |
| 1267 | 1268 | ||
| 1268 | pub const readIntLittle = switch (builtin.endian) { | 1269 | pub const readIntLittle = switch (native_endian) { |
| 1269 | .Little => readIntNative, | 1270 | .Little => readIntNative, |
| 1270 | .Big => readIntForeign, | 1271 | .Big => readIntForeign, |
| 1271 | }; | 1272 | }; |
| 1272 | 1273 | ||
| 1273 | pub const readIntBig = switch (builtin.endian) { | 1274 | pub const readIntBig = switch (native_endian) { |
| 1274 | .Little => readIntForeign, | 1275 | .Little => readIntForeign, |
| 1275 | .Big => readIntNative, | 1276 | .Big => readIntNative, |
| 1276 | }; | 1277 | }; |
| ... | @@ -1294,12 +1295,12 @@ pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { | ... | @@ -1294,12 +1295,12 @@ pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { |
| 1294 | return @byteSwap(T, readIntSliceNative(T, bytes)); | 1295 | return @byteSwap(T, readIntSliceNative(T, bytes)); |
| 1295 | } | 1296 | } |
| 1296 | 1297 | ||
| 1297 | pub const readIntSliceLittle = switch (builtin.endian) { | 1298 | pub const readIntSliceLittle = switch (native_endian) { |
| 1298 | .Little => readIntSliceNative, | 1299 | .Little => readIntSliceNative, |
| 1299 | .Big => readIntSliceForeign, | 1300 | .Big => readIntSliceForeign, |
| 1300 | }; | 1301 | }; |
| 1301 | 1302 | ||
| 1302 | pub const readIntSliceBig = switch (builtin.endian) { | 1303 | pub const readIntSliceBig = switch (native_endian) { |
| 1303 | .Little => readIntSliceForeign, | 1304 | .Little => readIntSliceForeign, |
| 1304 | .Big => readIntSliceNative, | 1305 | .Big => readIntSliceNative, |
| 1305 | }; | 1306 | }; |
| ... | @@ -1307,8 +1308,8 @@ pub const readIntSliceBig = switch (builtin.endian) { | ... | @@ -1307,8 +1308,8 @@ pub const readIntSliceBig = switch (builtin.endian) { |
| 1307 | /// Reads an integer from memory with bit count specified by T. | 1308 | /// Reads an integer from memory with bit count specified by T. |
| 1308 | /// The bit count of T must be evenly divisible by 8. | 1309 | /// The bit count of T must be evenly divisible by 8. |
| 1309 | /// This function cannot fail and cannot cause undefined behavior. | 1310 | /// This function cannot fail and cannot cause undefined behavior. |
| 1310 | pub fn readInt(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8, endian: builtin.Endian) T { | 1311 | pub fn readInt(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8, endian: Endian) T { |
| 1311 | if (endian == builtin.endian) { | 1312 | if (endian == native_endian) { |
| 1312 | return readIntNative(T, bytes); | 1313 | return readIntNative(T, bytes); |
| 1313 | } else { | 1314 | } else { |
| 1314 | return readIntForeign(T, bytes); | 1315 | return readIntForeign(T, bytes); |
| ... | @@ -1318,7 +1319,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, | ... | @@ -1318,7 +1319,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, |
| 1318 | /// Asserts that bytes.len >= @typeInfo(T).Int.bits / 8. Reads the integer starting from index 0 | 1319 | /// Asserts that bytes.len >= @typeInfo(T).Int.bits / 8. Reads the integer starting from index 0 |
| 1319 | /// and ignores extra bytes. | 1320 | /// and ignores extra bytes. |
| 1320 | /// The bit count of T must be evenly divisible by 8. | 1321 | /// The bit count of T must be evenly divisible by 8. |
| 1321 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { | 1322 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: Endian) T { |
| 1322 | const n = @divExact(@typeInfo(T).Int.bits, 8); | 1323 | const n = @divExact(@typeInfo(T).Int.bits, 8); |
| 1323 | assert(bytes.len >= n); | 1324 | assert(bytes.len >= n); |
| 1324 | return readInt(T, bytes[0..n], endian); | 1325 | return readInt(T, bytes[0..n], endian); |
| ... | @@ -1376,12 +1377,12 @@ pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, | ... | @@ -1376,12 +1377,12 @@ pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, |
| 1376 | writeIntNative(T, buf, @byteSwap(T, value)); | 1377 | writeIntNative(T, buf, @byteSwap(T, value)); |
| 1377 | } | 1378 | } |
| 1378 | 1379 | ||
| 1379 | pub const writeIntLittle = switch (builtin.endian) { | 1380 | pub const writeIntLittle = switch (native_endian) { |
| 1380 | .Little => writeIntNative, | 1381 | .Little => writeIntNative, |
| 1381 | .Big => writeIntForeign, | 1382 | .Big => writeIntForeign, |
| 1382 | }; | 1383 | }; |
| 1383 | 1384 | ||
| 1384 | pub const writeIntBig = switch (builtin.endian) { | 1385 | pub const writeIntBig = switch (native_endian) { |
| 1385 | .Little => writeIntForeign, | 1386 | .Little => writeIntForeign, |
| 1386 | .Big => writeIntNative, | 1387 | .Big => writeIntNative, |
| 1387 | }; | 1388 | }; |
| ... | @@ -1389,8 +1390,8 @@ pub const writeIntBig = switch (builtin.endian) { | ... | @@ -1389,8 +1390,8 @@ pub const writeIntBig = switch (builtin.endian) { |
| 1389 | /// Writes an integer to memory, storing it in twos-complement. | 1390 | /// Writes an integer to memory, storing it in twos-complement. |
| 1390 | /// This function always succeeds, has defined behavior for all inputs, but | 1391 | /// This function always succeeds, has defined behavior for all inputs, but |
| 1391 | /// the integer bit width must be divisible by 8. | 1392 | /// the integer bit width must be divisible by 8. |
| 1392 | pub fn writeInt(comptime T: type, buffer: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T, endian: builtin.Endian) void { | 1393 | pub fn writeInt(comptime T: type, buffer: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T, endian: Endian) void { |
| 1393 | if (endian == builtin.endian) { | 1394 | if (endian == native_endian) { |
| 1394 | return writeIntNative(T, buffer, value); | 1395 | return writeIntNative(T, buffer, value); |
| 1395 | } else { | 1396 | } else { |
| 1396 | return writeIntForeign(T, buffer, value); | 1397 | return writeIntForeign(T, buffer, value); |
| ... | @@ -1440,12 +1441,12 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { | ... | @@ -1440,12 +1441,12 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { |
| 1440 | } | 1441 | } |
| 1441 | } | 1442 | } |
| 1442 | 1443 | ||
| 1443 | pub const writeIntSliceNative = switch (builtin.endian) { | 1444 | pub const writeIntSliceNative = switch (native_endian) { |
| 1444 | .Little => writeIntSliceLittle, | 1445 | .Little => writeIntSliceLittle, |
| 1445 | .Big => writeIntSliceBig, | 1446 | .Big => writeIntSliceBig, |
| 1446 | }; | 1447 | }; |
| 1447 | 1448 | ||
| 1448 | pub const writeIntSliceForeign = switch (builtin.endian) { | 1449 | pub const writeIntSliceForeign = switch (native_endian) { |
| 1449 | .Little => writeIntSliceBig, | 1450 | .Little => writeIntSliceBig, |
| 1450 | .Big => writeIntSliceLittle, | 1451 | .Big => writeIntSliceLittle, |
| 1451 | }; | 1452 | }; |
| ... | @@ -1456,7 +1457,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) { | ... | @@ -1456,7 +1457,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) { |
| 1456 | /// Any extra bytes in buffer not part of the integer are set to zero, with | 1457 | /// Any extra bytes in buffer not part of the integer are set to zero, with |
| 1457 | /// respect to endianness. To avoid the branch to check for extra buffer bytes, | 1458 | /// respect to endianness. To avoid the branch to check for extra buffer bytes, |
| 1458 | /// use writeInt instead. | 1459 | /// use writeInt instead. |
| 1459 | pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { | 1460 | pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: Endian) void { |
| 1460 | comptime assert(@typeInfo(T).Int.bits % 8 == 0); | 1461 | comptime assert(@typeInfo(T).Int.bits % 8 == 0); |
| 1461 | return switch (endian) { | 1462 | return switch (endian) { |
| 1462 | .Little => writeIntSliceLittle(T, buffer, value), | 1463 | .Little => writeIntSliceLittle(T, buffer, value), |
| ... | @@ -1866,10 +1867,10 @@ fn testReadIntImpl() !void { | ... | @@ -1866,10 +1867,10 @@ fn testReadIntImpl() !void { |
| 1866 | 0x56, | 1867 | 0x56, |
| 1867 | 0x78, | 1868 | 0x78, |
| 1868 | }; | 1869 | }; |
| 1869 | try testing.expect(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); | 1870 | try testing.expect(readInt(u32, &bytes, Endian.Big) == 0x12345678); |
| 1870 | try testing.expect(readIntBig(u32, &bytes) == 0x12345678); | 1871 | try testing.expect(readIntBig(u32, &bytes) == 0x12345678); |
| 1871 | try testing.expect(readIntBig(i32, &bytes) == 0x12345678); | 1872 | try testing.expect(readIntBig(i32, &bytes) == 0x12345678); |
| 1872 | try testing.expect(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); | 1873 | try testing.expect(readInt(u32, &bytes, Endian.Little) == 0x78563412); |
| 1873 | try testing.expect(readIntLittle(u32, &bytes) == 0x78563412); | 1874 | try testing.expect(readIntLittle(u32, &bytes) == 0x78563412); |
| 1874 | try testing.expect(readIntLittle(i32, &bytes) == 0x78563412); | 1875 | try testing.expect(readIntLittle(i32, &bytes) == 0x78563412); |
| 1875 | } | 1876 | } |
| ... | @@ -1880,7 +1881,7 @@ fn testReadIntImpl() !void { | ... | @@ -1880,7 +1881,7 @@ fn testReadIntImpl() !void { |
| 1880 | 0x12, | 1881 | 0x12, |
| 1881 | 0x34, | 1882 | 0x34, |
| 1882 | }; | 1883 | }; |
| 1883 | const answer = readInt(u32, &buf, builtin.Endian.Big); | 1884 | const answer = readInt(u32, &buf, Endian.Big); |
| 1884 | try testing.expect(answer == 0x00001234); | 1885 | try testing.expect(answer == 0x00001234); |
| 1885 | } | 1886 | } |
| 1886 | { | 1887 | { |
| ... | @@ -1890,7 +1891,7 @@ fn testReadIntImpl() !void { | ... | @@ -1890,7 +1891,7 @@ fn testReadIntImpl() !void { |
| 1890 | 0x00, | 1891 | 0x00, |
| 1891 | 0x00, | 1892 | 0x00, |
| 1892 | }; | 1893 | }; |
| 1893 | const answer = readInt(u32, &buf, builtin.Endian.Little); | 1894 | const answer = readInt(u32, &buf, Endian.Little); |
| 1894 | try testing.expect(answer == 0x00003412); | 1895 | try testing.expect(answer == 0x00003412); |
| 1895 | } | 1896 | } |
| 1896 | { | 1897 | { |
| ... | @@ -1912,19 +1913,19 @@ test "writeIntSlice" { | ... | @@ -1912,19 +1913,19 @@ test "writeIntSlice" { |
| 1912 | fn testWriteIntImpl() !void { | 1913 | fn testWriteIntImpl() !void { |
| 1913 | var bytes: [8]u8 = undefined; | 1914 | var bytes: [8]u8 = undefined; |
| 1914 | 1915 | ||
| 1915 | writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); | 1916 | writeIntSlice(u0, bytes[0..], 0, Endian.Big); |
| 1916 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1917 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1917 | 0x00, 0x00, 0x00, 0x00, | 1918 | 0x00, 0x00, 0x00, 0x00, |
| 1918 | 0x00, 0x00, 0x00, 0x00, | 1919 | 0x00, 0x00, 0x00, 0x00, |
| 1919 | })); | 1920 | })); |
| 1920 | 1921 | ||
| 1921 | writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); | 1922 | writeIntSlice(u0, bytes[0..], 0, Endian.Little); |
| 1922 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1923 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1923 | 0x00, 0x00, 0x00, 0x00, | 1924 | 0x00, 0x00, 0x00, 0x00, |
| 1924 | 0x00, 0x00, 0x00, 0x00, | 1925 | 0x00, 0x00, 0x00, 0x00, |
| 1925 | })); | 1926 | })); |
| 1926 | 1927 | ||
| 1927 | writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); | 1928 | writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, Endian.Big); |
| 1928 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1929 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1929 | 0x12, | 1930 | 0x12, |
| 1930 | 0x34, | 1931 | 0x34, |
| ... | @@ -1936,7 +1937,7 @@ fn testWriteIntImpl() !void { | ... | @@ -1936,7 +1937,7 @@ fn testWriteIntImpl() !void { |
| 1936 | 0xBE, | 1937 | 0xBE, |
| 1937 | })); | 1938 | })); |
| 1938 | 1939 | ||
| 1939 | writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); | 1940 | writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, Endian.Little); |
| 1940 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1941 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1941 | 0x12, | 1942 | 0x12, |
| 1942 | 0x34, | 1943 | 0x34, |
| ... | @@ -1948,7 +1949,7 @@ fn testWriteIntImpl() !void { | ... | @@ -1948,7 +1949,7 @@ fn testWriteIntImpl() !void { |
| 1948 | 0xBE, | 1949 | 0xBE, |
| 1949 | })); | 1950 | })); |
| 1950 | 1951 | ||
| 1951 | writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); | 1952 | writeIntSlice(u32, bytes[0..], 0x12345678, Endian.Big); |
| 1952 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1953 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1953 | 0x00, | 1954 | 0x00, |
| 1954 | 0x00, | 1955 | 0x00, |
| ... | @@ -1960,7 +1961,7 @@ fn testWriteIntImpl() !void { | ... | @@ -1960,7 +1961,7 @@ fn testWriteIntImpl() !void { |
| 1960 | 0x78, | 1961 | 0x78, |
| 1961 | })); | 1962 | })); |
| 1962 | 1963 | ||
| 1963 | writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); | 1964 | writeIntSlice(u32, bytes[0..], 0x78563412, Endian.Little); |
| 1964 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1965 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1965 | 0x12, | 1966 | 0x12, |
| 1966 | 0x34, | 1967 | 0x34, |
| ... | @@ -1972,7 +1973,7 @@ fn testWriteIntImpl() !void { | ... | @@ -1972,7 +1973,7 @@ fn testWriteIntImpl() !void { |
| 1972 | 0x00, | 1973 | 0x00, |
| 1973 | })); | 1974 | })); |
| 1974 | 1975 | ||
| 1975 | writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); | 1976 | writeIntSlice(u16, bytes[0..], 0x1234, Endian.Big); |
| 1976 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1977 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1977 | 0x00, | 1978 | 0x00, |
| 1978 | 0x00, | 1979 | 0x00, |
| ... | @@ -1984,7 +1985,7 @@ fn testWriteIntImpl() !void { | ... | @@ -1984,7 +1985,7 @@ fn testWriteIntImpl() !void { |
| 1984 | 0x34, | 1985 | 0x34, |
| 1985 | })); | 1986 | })); |
| 1986 | 1987 | ||
| 1987 | writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); | 1988 | writeIntSlice(u16, bytes[0..], 0x1234, Endian.Little); |
| 1988 | try testing.expect(eql(u8, &bytes, &[_]u8{ | 1989 | try testing.expect(eql(u8, &bytes, &[_]u8{ |
| 1989 | 0x34, | 1990 | 0x34, |
| 1990 | 0x12, | 1991 | 0x12, |
| ... | @@ -2173,7 +2174,7 @@ test "replaceOwned" { | ... | @@ -2173,7 +2174,7 @@ test "replaceOwned" { |
| 2173 | 2174 | ||
| 2174 | /// Converts a little-endian integer to host endianness. | 2175 | /// Converts a little-endian integer to host endianness. |
| 2175 | pub fn littleToNative(comptime T: type, x: T) T { | 2176 | pub fn littleToNative(comptime T: type, x: T) T { |
| 2176 | return switch (builtin.endian) { | 2177 | return switch (native_endian) { |
| 2177 | .Little => x, | 2178 | .Little => x, |
| 2178 | .Big => @byteSwap(T, x), | 2179 | .Big => @byteSwap(T, x), |
| 2179 | }; | 2180 | }; |
| ... | @@ -2181,14 +2182,14 @@ pub fn littleToNative(comptime T: type, x: T) T { | ... | @@ -2181,14 +2182,14 @@ pub fn littleToNative(comptime T: type, x: T) T { |
| 2181 | 2182 | ||
| 2182 | /// Converts a big-endian integer to host endianness. | 2183 | /// Converts a big-endian integer to host endianness. |
| 2183 | pub fn bigToNative(comptime T: type, x: T) T { | 2184 | pub fn bigToNative(comptime T: type, x: T) T { |
| 2184 | return switch (builtin.endian) { | 2185 | return switch (native_endian) { |
| 2185 | .Little => @byteSwap(T, x), | 2186 | .Little => @byteSwap(T, x), |
| 2186 | .Big => x, | 2187 | .Big => x, |
| 2187 | }; | 2188 | }; |
| 2188 | } | 2189 | } |
| 2189 | 2190 | ||
| 2190 | /// Converts an integer from specified endianness to host endianness. | 2191 | /// Converts an integer from specified endianness to host endianness. |
| 2191 | pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { | 2192 | pub fn toNative(comptime T: type, x: T, endianness_of_x: Endian) T { |
| 2192 | return switch (endianness_of_x) { | 2193 | return switch (endianness_of_x) { |
| 2193 | .Little => littleToNative(T, x), | 2194 | .Little => littleToNative(T, x), |
| 2194 | .Big => bigToNative(T, x), | 2195 | .Big => bigToNative(T, x), |
| ... | @@ -2196,7 +2197,7 @@ pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { | ... | @@ -2196,7 +2197,7 @@ pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { |
| 2196 | } | 2197 | } |
| 2197 | 2198 | ||
| 2198 | /// Converts an integer which has host endianness to the desired endianness. | 2199 | /// Converts an integer which has host endianness to the desired endianness. |
| 2199 | pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { | 2200 | pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T { |
| 2200 | return switch (desired_endianness) { | 2201 | return switch (desired_endianness) { |
| 2201 | .Little => nativeToLittle(T, x), | 2202 | .Little => nativeToLittle(T, x), |
| 2202 | .Big => nativeToBig(T, x), | 2203 | .Big => nativeToBig(T, x), |
| ... | @@ -2205,7 +2206,7 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { | ... | @@ -2205,7 +2206,7 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { |
| 2205 | 2206 | ||
| 2206 | /// Converts an integer which has host endianness to little endian. | 2207 | /// Converts an integer which has host endianness to little endian. |
| 2207 | pub fn nativeToLittle(comptime T: type, x: T) T { | 2208 | pub fn nativeToLittle(comptime T: type, x: T) T { |
| 2208 | return switch (builtin.endian) { | 2209 | return switch (native_endian) { |
| 2209 | .Little => x, | 2210 | .Little => x, |
| 2210 | .Big => @byteSwap(T, x), | 2211 | .Big => @byteSwap(T, x), |
| 2211 | }; | 2212 | }; |
| ... | @@ -2213,13 +2214,13 @@ pub fn nativeToLittle(comptime T: type, x: T) T { | ... | @@ -2213,13 +2214,13 @@ pub fn nativeToLittle(comptime T: type, x: T) T { |
| 2213 | 2214 | ||
| 2214 | /// Converts an integer which has host endianness to big endian. | 2215 | /// Converts an integer which has host endianness to big endian. |
| 2215 | pub fn nativeToBig(comptime T: type, x: T) T { | 2216 | pub fn nativeToBig(comptime T: type, x: T) T { |
| 2216 | return switch (builtin.endian) { | 2217 | return switch (native_endian) { |
| 2217 | .Little => @byteSwap(T, x), | 2218 | .Little => @byteSwap(T, x), |
| 2218 | .Big => x, | 2219 | .Big => x, |
| 2219 | }; | 2220 | }; |
| 2220 | } | 2221 | } |
| 2221 | 2222 | ||
| 2222 | fn CopyPtrAttrs(comptime source: type, comptime size: builtin.TypeInfo.Pointer.Size, comptime child: type) type { | 2223 | fn CopyPtrAttrs(comptime source: type, comptime size: std.builtin.TypeInfo.Pointer.Size, comptime child: type) type { |
| 2223 | const info = @typeInfo(source).Pointer; | 2224 | const info = @typeInfo(source).Pointer; |
| 2224 | return @Type(.{ | 2225 | return @Type(.{ |
| 2225 | .Pointer = .{ | 2226 | .Pointer = .{ |
| ... | @@ -2251,7 +2252,7 @@ pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) { | ... | @@ -2251,7 +2252,7 @@ pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) { |
| 2251 | 2252 | ||
| 2252 | test "asBytes" { | 2253 | test "asBytes" { |
| 2253 | const deadbeef = @as(u32, 0xDEADBEEF); | 2254 | const deadbeef = @as(u32, 0xDEADBEEF); |
| 2254 | const deadbeef_bytes = switch (builtin.endian) { | 2255 | const deadbeef_bytes = switch (native_endian) { |
| 2255 | .Big => "\xDE\xAD\xBE\xEF", | 2256 | .Big => "\xDE\xAD\xBE\xEF", |
| 2256 | .Little => "\xEF\xBE\xAD\xDE", | 2257 | .Little => "\xEF\xBE\xAD\xDE", |
| 2257 | }; | 2258 | }; |
| ... | @@ -2304,13 +2305,13 @@ pub fn toBytes(value: anytype) [@sizeOf(@TypeOf(value))]u8 { | ... | @@ -2304,13 +2305,13 @@ pub fn toBytes(value: anytype) [@sizeOf(@TypeOf(value))]u8 { |
| 2304 | 2305 | ||
| 2305 | test "toBytes" { | 2306 | test "toBytes" { |
| 2306 | var my_bytes = toBytes(@as(u32, 0x12345678)); | 2307 | var my_bytes = toBytes(@as(u32, 0x12345678)); |
| 2307 | switch (builtin.endian) { | 2308 | switch (native_endian) { |
| 2308 | .Big => try testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")), | 2309 | .Big => try testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")), |
| 2309 | .Little => try testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")), | 2310 | .Little => try testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")), |
| 2310 | } | 2311 | } |
| 2311 | 2312 | ||
| 2312 | my_bytes[0] = '\x99'; | 2313 | my_bytes[0] = '\x99'; |
| 2313 | switch (builtin.endian) { | 2314 | switch (native_endian) { |
| 2314 | .Big => try testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")), | 2315 | .Big => try testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")), |
| 2315 | .Little => try testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")), | 2316 | .Little => try testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")), |
| 2316 | } | 2317 | } |
| ... | @@ -2337,14 +2338,14 @@ pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, | ... | @@ -2337,14 +2338,14 @@ pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, |
| 2337 | 2338 | ||
| 2338 | test "bytesAsValue" { | 2339 | test "bytesAsValue" { |
| 2339 | const deadbeef = @as(u32, 0xDEADBEEF); | 2340 | const deadbeef = @as(u32, 0xDEADBEEF); |
| 2340 | const deadbeef_bytes = switch (builtin.endian) { | 2341 | const deadbeef_bytes = switch (native_endian) { |
| 2341 | .Big => "\xDE\xAD\xBE\xEF", | 2342 | .Big => "\xDE\xAD\xBE\xEF", |
| 2342 | .Little => "\xEF\xBE\xAD\xDE", | 2343 | .Little => "\xEF\xBE\xAD\xDE", |
| 2343 | }; | 2344 | }; |
| 2344 | 2345 | ||
| 2345 | try testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*); | 2346 | try testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*); |
| 2346 | 2347 | ||
| 2347 | var codeface_bytes: [4]u8 = switch (builtin.endian) { | 2348 | var codeface_bytes: [4]u8 = switch (native_endian) { |
| 2348 | .Big => "\xC0\xDE\xFA\xCE", | 2349 | .Big => "\xC0\xDE\xFA\xCE", |
| 2349 | .Little => "\xCE\xFA\xDE\xC0", | 2350 | .Little => "\xCE\xFA\xDE\xC0", |
| 2350 | }.*; | 2351 | }.*; |
| ... | @@ -2392,7 +2393,7 @@ pub fn bytesToValue(comptime T: type, bytes: anytype) T { | ... | @@ -2392,7 +2393,7 @@ pub fn bytesToValue(comptime T: type, bytes: anytype) T { |
| 2392 | return bytesAsValue(T, bytes).*; | 2393 | return bytesAsValue(T, bytes).*; |
| 2393 | } | 2394 | } |
| 2394 | test "bytesToValue" { | 2395 | test "bytesToValue" { |
| 2395 | const deadbeef_bytes = switch (builtin.endian) { | 2396 | const deadbeef_bytes = switch (native_endian) { |
| 2396 | .Big => "\xDE\xAD\xBE\xEF", | 2397 | .Big => "\xDE\xAD\xBE\xEF", |
| 2397 | .Little => "\xEF\xBE\xAD\xDE", | 2398 | .Little => "\xEF\xBE\xAD\xDE", |
| 2398 | }; | 2399 | }; |
| ... | @@ -2521,7 +2522,7 @@ test "sliceAsBytes" { | ... | @@ -2521,7 +2522,7 @@ test "sliceAsBytes" { |
| 2521 | const bytes = [_]u16{ 0xDEAD, 0xBEEF }; | 2522 | const bytes = [_]u16{ 0xDEAD, 0xBEEF }; |
| 2522 | const slice = sliceAsBytes(bytes[0..]); | 2523 | const slice = sliceAsBytes(bytes[0..]); |
| 2523 | try testing.expect(slice.len == 4); | 2524 | try testing.expect(slice.len == 4); |
| 2524 | try testing.expect(eql(u8, slice, switch (builtin.endian) { | 2525 | try testing.expect(eql(u8, slice, switch (native_endian) { |
| 2525 | .Big => "\xDE\xAD\xBE\xEF", | 2526 | .Big => "\xDE\xAD\xBE\xEF", |
| 2526 | .Little => "\xAD\xDE\xEF\xBE", | 2527 | .Little => "\xAD\xDE\xEF\xBE", |
| 2527 | })); | 2528 | })); |
| ... | @@ -2543,7 +2544,7 @@ test "sliceAsBytes packed struct at runtime and comptime" { | ... | @@ -2543,7 +2544,7 @@ test "sliceAsBytes packed struct at runtime and comptime" { |
| 2543 | var foo: Foo = undefined; | 2544 | var foo: Foo = undefined; |
| 2544 | var slice = sliceAsBytes(@as(*[1]Foo, &foo)[0..1]); | 2545 | var slice = sliceAsBytes(@as(*[1]Foo, &foo)[0..1]); |
| 2545 | slice[0] = 0x13; | 2546 | slice[0] = 0x13; |
| 2546 | switch (builtin.endian) { | 2547 | switch (native_endian) { |
| 2547 | .Big => { | 2548 | .Big => { |
| 2548 | try testing.expect(foo.a == 0x1); | 2549 | try testing.expect(foo.a == 0x1); |
| 2549 | try testing.expect(foo.b == 0x3); | 2550 | try testing.expect(foo.b == 0x3); |
lib/std/meta.zig+3-11| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const debug = std.debug; | 8 | const debug = std.debug; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| ... | @@ -342,12 +342,6 @@ test "std.meta.containerLayout" { | ... | @@ -342,12 +342,6 @@ test "std.meta.containerLayout" { |
| 342 | const E1 = enum { | 342 | const E1 = enum { |
| 343 | A, | 343 | A, |
| 344 | }; | 344 | }; |
| 345 | const E2 = packed enum { | ||
| 346 | A, | ||
| 347 | }; | ||
| 348 | const E3 = extern enum { | ||
| 349 | A, | ||
| 350 | }; | ||
| 351 | const S1 = struct {}; | 345 | const S1 = struct {}; |
| 352 | const S2 = packed struct {}; | 346 | const S2 = packed struct {}; |
| 353 | const S3 = extern struct {}; | 347 | const S3 = extern struct {}; |
| ... | @@ -362,8 +356,6 @@ test "std.meta.containerLayout" { | ... | @@ -362,8 +356,6 @@ test "std.meta.containerLayout" { |
| 362 | }; | 356 | }; |
| 363 | 357 | ||
| 364 | try testing.expect(containerLayout(E1) == .Auto); | 358 | try testing.expect(containerLayout(E1) == .Auto); |
| 365 | try testing.expect(containerLayout(E2) == .Packed); | ||
| 366 | try testing.expect(containerLayout(E3) == .Extern); | ||
| 367 | try testing.expect(containerLayout(S1) == .Auto); | 359 | try testing.expect(containerLayout(S1) == .Auto); |
| 368 | try testing.expect(containerLayout(S2) == .Packed); | 360 | try testing.expect(containerLayout(S2) == .Packed); |
| 369 | try testing.expect(containerLayout(S3) == .Extern); | 361 | try testing.expect(containerLayout(S3) == .Extern); |
| ... | @@ -1024,7 +1016,7 @@ test "std.meta.cast" { | ... | @@ -1024,7 +1016,7 @@ test "std.meta.cast" { |
| 1024 | 1016 | ||
| 1025 | try testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2))); | 1017 | try testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2))); |
| 1026 | 1018 | ||
| 1027 | const C_ENUM = extern enum(c_int) { | 1019 | const C_ENUM = enum(c_int) { |
| 1028 | A = 0, | 1020 | A = 0, |
| 1029 | B, | 1021 | B, |
| 1030 | C, | 1022 | C, |
| ... | @@ -1107,7 +1099,7 @@ pub fn sizeof(target: anytype) usize { | ... | @@ -1107,7 +1099,7 @@ pub fn sizeof(target: anytype) usize { |
| 1107 | } | 1099 | } |
| 1108 | 1100 | ||
| 1109 | test "sizeof" { | 1101 | test "sizeof" { |
| 1110 | const E = extern enum(c_int) { One, _ }; | 1102 | const E = enum(c_int) { One, _ }; |
| 1111 | const S = extern struct { a: u32 }; | 1103 | const S = extern struct { a: u32 }; |
| 1112 | 1104 | ||
| 1113 | const ptr_size = @sizeOf(*c_void); | 1105 | const ptr_size = @sizeOf(*c_void); |
lib/std/meta/trait.zig+2-2| ... | @@ -483,8 +483,8 @@ pub fn hasDecls(comptime T: type, comptime names: anytype) bool { | ... | @@ -483,8 +483,8 @@ pub fn hasDecls(comptime T: type, comptime names: anytype) bool { |
| 483 | test "std.meta.trait.hasDecls" { | 483 | test "std.meta.trait.hasDecls" { |
| 484 | const TestStruct1 = struct {}; | 484 | const TestStruct1 = struct {}; |
| 485 | const TestStruct2 = struct { | 485 | const TestStruct2 = struct { |
| 486 | pub var a: u32; | 486 | pub var a: u32 = undefined; |
| 487 | pub var b: u32; | 487 | pub var b: u32 = undefined; |
| 488 | c: bool, | 488 | c: bool, |
| 489 | pub fn useless() void {} | 489 | pub fn useless() void {} |
| 490 | }; | 490 | }; |
lib/std/multi_array_list.zig+16-7| ... | @@ -147,7 +147,7 @@ pub fn MultiArrayList(comptime S: type) type { | ... | @@ -147,7 +147,7 @@ pub fn MultiArrayList(comptime S: type) type { |
| 147 | 147 | ||
| 148 | /// Extend the list by 1 element. Allocates more memory as necessary. | 148 | /// Extend the list by 1 element. Allocates more memory as necessary. |
| 149 | pub fn append(self: *Self, gpa: *Allocator, elem: S) !void { | 149 | pub fn append(self: *Self, gpa: *Allocator, elem: S) !void { |
| 150 | try self.ensureCapacity(gpa, self.len + 1); | 150 | try self.ensureUnusedCapacity(gpa, 1); |
| 151 | self.appendAssumeCapacity(elem); | 151 | self.appendAssumeCapacity(elem); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| ... | @@ -162,7 +162,7 @@ pub fn MultiArrayList(comptime S: type) type { | ... | @@ -162,7 +162,7 @@ pub fn MultiArrayList(comptime S: type) type { |
| 162 | /// Adjust the list's length to `new_len`. | 162 | /// Adjust the list's length to `new_len`. |
| 163 | /// Does not initialize added items, if any. | 163 | /// Does not initialize added items, if any. |
| 164 | pub fn resize(self: *Self, gpa: *Allocator, new_len: usize) !void { | 164 | pub fn resize(self: *Self, gpa: *Allocator, new_len: usize) !void { |
| 165 | try self.ensureCapacity(gpa, new_len); | 165 | try self.ensureTotalCapacity(gpa, new_len); |
| 166 | self.len = new_len; | 166 | self.len = new_len; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| ... | @@ -224,10 +224,13 @@ pub fn MultiArrayList(comptime S: type) type { | ... | @@ -224,10 +224,13 @@ pub fn MultiArrayList(comptime S: type) type { |
| 224 | self.len = new_len; | 224 | self.len = new_len; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | /// Deprecated: call `ensureUnusedCapacity` or `ensureTotalCapacity`. | ||
| 228 | pub const ensureCapacity = ensureTotalCapacity; | ||
| 229 | |||
| 227 | /// Modify the array so that it can hold at least `new_capacity` items. | 230 | /// Modify the array so that it can hold at least `new_capacity` items. |
| 228 | /// Implements super-linear growth to achieve amortized O(1) append operations. | 231 | /// Implements super-linear growth to achieve amortized O(1) append operations. |
| 229 | /// Invalidates pointers if additional memory is needed. | 232 | /// Invalidates pointers if additional memory is needed. |
| 230 | pub fn ensureCapacity(self: *Self, gpa: *Allocator, new_capacity: usize) !void { | 233 | pub fn ensureTotalCapacity(self: *Self, gpa: *Allocator, new_capacity: usize) !void { |
| 231 | var better_capacity = self.capacity; | 234 | var better_capacity = self.capacity; |
| 232 | if (better_capacity >= new_capacity) return; | 235 | if (better_capacity >= new_capacity) return; |
| 233 | 236 | ||
| ... | @@ -239,6 +242,12 @@ pub fn MultiArrayList(comptime S: type) type { | ... | @@ -239,6 +242,12 @@ pub fn MultiArrayList(comptime S: type) type { |
| 239 | return self.setCapacity(gpa, better_capacity); | 242 | return self.setCapacity(gpa, better_capacity); |
| 240 | } | 243 | } |
| 241 | 244 | ||
| 245 | /// Modify the array so that it can hold at least `additional_count` **more** items. | ||
| 246 | /// Invalidates pointers if additional memory is needed. | ||
| 247 | pub fn ensureUnusedCapacity(self: *Self, gpa: *Allocator, additional_count: usize) !void { | ||
| 248 | return self.ensureTotalCapacity(gpa, self.len + additional_count); | ||
| 249 | } | ||
| 250 | |||
| 242 | /// Modify the array so that it can hold exactly `new_capacity` items. | 251 | /// Modify the array so that it can hold exactly `new_capacity` items. |
| 243 | /// Invalidates pointers if additional memory is needed. | 252 | /// Invalidates pointers if additional memory is needed. |
| 244 | /// `new_capacity` must be greater or equal to `len`. | 253 | /// `new_capacity` must be greater or equal to `len`. |
| ... | @@ -305,7 +314,7 @@ test "basic usage" { | ... | @@ -305,7 +314,7 @@ test "basic usage" { |
| 305 | 314 | ||
| 306 | try testing.expectEqual(@as(usize, 0), list.items(.a).len); | 315 | try testing.expectEqual(@as(usize, 0), list.items(.a).len); |
| 307 | 316 | ||
| 308 | try list.ensureCapacity(ally, 2); | 317 | try list.ensureTotalCapacity(ally, 2); |
| 309 | 318 | ||
| 310 | list.appendAssumeCapacity(.{ | 319 | list.appendAssumeCapacity(.{ |
| 311 | .a = 1, | 320 | .a = 1, |
| ... | @@ -382,7 +391,7 @@ test "regression test for @reduce bug" { | ... | @@ -382,7 +391,7 @@ test "regression test for @reduce bug" { |
| 382 | }){}; | 391 | }){}; |
| 383 | defer list.deinit(ally); | 392 | defer list.deinit(ally); |
| 384 | 393 | ||
| 385 | try list.ensureCapacity(ally, 20); | 394 | try list.ensureTotalCapacity(ally, 20); |
| 386 | 395 | ||
| 387 | try list.append(ally, .{ .tag = .keyword_const, .start = 0 }); | 396 | try list.append(ally, .{ .tag = .keyword_const, .start = 0 }); |
| 388 | try list.append(ally, .{ .tag = .identifier, .start = 6 }); | 397 | try list.append(ally, .{ .tag = .identifier, .start = 6 }); |
| ... | @@ -462,7 +471,7 @@ test "ensure capacity on empty list" { | ... | @@ -462,7 +471,7 @@ test "ensure capacity on empty list" { |
| 462 | var list = MultiArrayList(Foo){}; | 471 | var list = MultiArrayList(Foo){}; |
| 463 | defer list.deinit(ally); | 472 | defer list.deinit(ally); |
| 464 | 473 | ||
| 465 | try list.ensureCapacity(ally, 2); | 474 | try list.ensureTotalCapacity(ally, 2); |
| 466 | list.appendAssumeCapacity(.{ .a = 1, .b = 2 }); | 475 | list.appendAssumeCapacity(.{ .a = 1, .b = 2 }); |
| 467 | list.appendAssumeCapacity(.{ .a = 3, .b = 4 }); | 476 | list.appendAssumeCapacity(.{ .a = 3, .b = 4 }); |
| 468 | 477 | ||
| ... | @@ -477,7 +486,7 @@ test "ensure capacity on empty list" { | ... | @@ -477,7 +486,7 @@ test "ensure capacity on empty list" { |
| 477 | try testing.expectEqualSlices(u8, &[_]u8{ 6, 8 }, list.items(.b)); | 486 | try testing.expectEqualSlices(u8, &[_]u8{ 6, 8 }, list.items(.b)); |
| 478 | 487 | ||
| 479 | list.len = 0; | 488 | list.len = 0; |
| 480 | try list.ensureCapacity(ally, 16); | 489 | try list.ensureTotalCapacity(ally, 16); |
| 481 | 490 | ||
| 482 | list.appendAssumeCapacity(.{ .a = 9, .b = 10 }); | 491 | list.appendAssumeCapacity(.{ .a = 9, .b = 10 }); |
| 483 | list.appendAssumeCapacity(.{ .a = 11, .b = 12 }); | 492 | list.appendAssumeCapacity(.{ .a = 11, .b = 12 }); |
lib/std/net.zig+8-7| ... | @@ -11,11 +11,12 @@ const mem = std.mem; | ... | @@ -11,11 +11,12 @@ const mem = std.mem; |
| 11 | const os = std.os; | 11 | const os = std.os; |
| 12 | const fs = std.fs; | 12 | const fs = std.fs; |
| 13 | const io = std.io; | 13 | const io = std.io; |
| 14 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 14 | 15 | ||
| 15 | // Windows 10 added support for unix sockets in build 17063, redstone 4 is the | 16 | // Windows 10 added support for unix sockets in build 17063, redstone 4 is the |
| 16 | // first release to support them. | 17 | // first release to support them. |
| 17 | pub const has_unix_sockets = @hasDecl(os, "sockaddr_un") and | 18 | pub const has_unix_sockets = @hasDecl(os, "sockaddr_un") and |
| 18 | (builtin.os.tag != .windows or | 19 | (builtin.target.os.tag != .windows or |
| 19 | std.Target.current.os.version_range.windows.isAtLeast(.win10_rs4) orelse false); | 20 | std.Target.current.os.version_range.windows.isAtLeast(.win10_rs4) orelse false); |
| 20 | 21 | ||
| 21 | pub const Address = extern union { | 22 | pub const Address = extern union { |
| ... | @@ -567,7 +568,7 @@ pub const Ip6Address = extern struct { | ... | @@ -567,7 +568,7 @@ pub const Ip6Address = extern struct { |
| 567 | return; | 568 | return; |
| 568 | } | 569 | } |
| 569 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.sa.addr); | 570 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.sa.addr); |
| 570 | const native_endian_parts = switch (builtin.endian) { | 571 | const native_endian_parts = switch (native_endian) { |
| 571 | .Big => big_endian_parts.*, | 572 | .Big => big_endian_parts.*, |
| 572 | .Little => blk: { | 573 | .Little => blk: { |
| 573 | var buf: [8]u16 = undefined; | 574 | var buf: [8]u16 = undefined; |
| ... | @@ -673,7 +674,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) | ... | @@ -673,7 +674,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 673 | pub fn tcpConnectToAddress(address: Address) !Stream { | 674 | pub fn tcpConnectToAddress(address: Address) !Stream { |
| 674 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 675 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 675 | const sock_flags = os.SOCK_STREAM | nonblock | | 676 | const sock_flags = os.SOCK_STREAM | nonblock | |
| 676 | (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC); | 677 | (if (builtin.target.os.tag == .windows) 0 else os.SOCK_CLOEXEC); |
| 677 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); | 678 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); |
| 678 | errdefer os.closeSocket(sockfd); | 679 | errdefer os.closeSocket(sockfd); |
| 679 | 680 | ||
| ... | @@ -704,14 +705,14 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -704,14 +705,14 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 704 | const arena = &result.arena.allocator; | 705 | const arena = &result.arena.allocator; |
| 705 | errdefer result.arena.deinit(); | 706 | errdefer result.arena.deinit(); |
| 706 | 707 | ||
| 707 | if (builtin.os.tag == .windows or builtin.link_libc) { | 708 | if (builtin.target.os.tag == .windows or builtin.link_libc) { |
| 708 | const name_c = try std.cstr.addNullByte(allocator, name); | 709 | const name_c = try std.cstr.addNullByte(allocator, name); |
| 709 | defer allocator.free(name_c); | 710 | defer allocator.free(name_c); |
| 710 | 711 | ||
| 711 | const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port}); | 712 | const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port}); |
| 712 | defer allocator.free(port_c); | 713 | defer allocator.free(port_c); |
| 713 | 714 | ||
| 714 | const sys = if (builtin.os.tag == .windows) os.windows.ws2_32 else os.system; | 715 | const sys = if (builtin.target.os.tag == .windows) os.windows.ws2_32 else os.system; |
| 715 | const hints = os.addrinfo{ | 716 | const hints = os.addrinfo{ |
| 716 | .flags = sys.AI_NUMERICSERV, | 717 | .flags = sys.AI_NUMERICSERV, |
| 717 | .family = os.AF_UNSPEC, | 718 | .family = os.AF_UNSPEC, |
| ... | @@ -724,7 +725,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -724,7 +725,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 724 | }; | 725 | }; |
| 725 | var res: *os.addrinfo = undefined; | 726 | var res: *os.addrinfo = undefined; |
| 726 | const rc = sys.getaddrinfo(name_c.ptr, std.meta.assumeSentinel(port_c.ptr, 0), &hints, &res); | 727 | const rc = sys.getaddrinfo(name_c.ptr, std.meta.assumeSentinel(port_c.ptr, 0), &hints, &res); |
| 727 | if (builtin.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) { | 728 | if (builtin.target.os.tag == .windows) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) { |
| 728 | @intToEnum(os.windows.ws2_32.WinsockError, 0) => {}, | 729 | @intToEnum(os.windows.ws2_32.WinsockError, 0) => {}, |
| 729 | .WSATRY_AGAIN => return error.TemporaryNameServerFailure, | 730 | .WSATRY_AGAIN => return error.TemporaryNameServerFailure, |
| 730 | .WSANO_RECOVERY => return error.NameServerFailure, | 731 | .WSANO_RECOVERY => return error.NameServerFailure, |
| ... | @@ -782,7 +783,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -782,7 +783,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 782 | 783 | ||
| 783 | return result; | 784 | return result; |
| 784 | } | 785 | } |
| 785 | if (builtin.os.tag == .linux) { | 786 | if (builtin.target.os.tag == .linux) { |
| 786 | const flags = std.c.AI_NUMERICSERV; | 787 | const flags = std.c.AI_NUMERICSERV; |
| 787 | const family = os.AF_UNSPEC; | 788 | const family = os.AF_UNSPEC; |
| 788 | var lookup_addrs = std.ArrayList(LookupAddr).init(allocator); | 789 | var lookup_addrs = std.ArrayList(LookupAddr).init(allocator); |
lib/std/os.zig+1-1| ... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | ||
| 22 | const root = @import("root"); | 22 | const root = @import("root"); |
| 23 | const std = @import("std.zig"); | 23 | const std = @import("std.zig"); |
| 24 | const builtin = @import("builtin"); | 24 | const builtin = std.builtin; |
| 25 | const assert = std.debug.assert; | 25 | const assert = std.debug.assert; |
| 26 | const math = std.math; | 26 | const math = std.math; |
| 27 | const mem = std.mem; | 27 | const mem = std.mem; |
lib/std/os/bits/darwin.zig+4-4| ... | @@ -1535,19 +1535,19 @@ pub const rusage = extern struct { | ... | @@ -1535,19 +1535,19 @@ pub const rusage = extern struct { |
| 1535 | nivcsw: isize, | 1535 | nivcsw: isize, |
| 1536 | }; | 1536 | }; |
| 1537 | 1537 | ||
| 1538 | pub const rlimit_resource = extern enum(c_int) { | 1538 | pub const rlimit_resource = enum(c_int) { |
| 1539 | CPU = 0, | 1539 | CPU = 0, |
| 1540 | FSIZE = 1, | 1540 | FSIZE = 1, |
| 1541 | DATA = 2, | 1541 | DATA = 2, |
| 1542 | STACK = 3, | 1542 | STACK = 3, |
| 1543 | CORE = 4, | 1543 | CORE = 4, |
| 1544 | AS = 5, | ||
| 1545 | RSS = 5, | 1544 | RSS = 5, |
| 1546 | MEMLOCK = 6, | 1545 | MEMLOCK = 6, |
| 1547 | NPROC = 7, | 1546 | NPROC = 7, |
| 1548 | NOFILE = 8, | 1547 | NOFILE = 8, |
| 1549 | |||
| 1550 | _, | 1548 | _, |
| 1549 | |||
| 1550 | pub const AS: rlimit_resource = .RSS; | ||
| 1551 | }; | 1551 | }; |
| 1552 | 1552 | ||
| 1553 | pub const rlim_t = u64; | 1553 | pub const rlim_t = u64; |
| ... | @@ -1683,7 +1683,7 @@ pub const TCSANOW = 0; // make change immediate | ... | @@ -1683,7 +1683,7 @@ pub const TCSANOW = 0; // make change immediate |
| 1683 | pub const TCSADRAIN = 1; // drain output, then change | 1683 | pub const TCSADRAIN = 1; // drain output, then change |
| 1684 | pub const TCSAFLUSH = 2; // drain output, flush input | 1684 | pub const TCSAFLUSH = 2; // drain output, flush input |
| 1685 | pub const TCSASOFT = 0x10; // flag - don't alter h.w. state | 1685 | pub const TCSASOFT = 0x10; // flag - don't alter h.w. state |
| 1686 | pub const TCSA = extern enum(c_uint) { | 1686 | pub const TCSA = enum(c_uint) { |
| 1687 | NOW, | 1687 | NOW, |
| 1688 | DRAIN, | 1688 | DRAIN, |
| 1689 | FLUSH, | 1689 | FLUSH, |
lib/std/os/bits/dragonfly.zig+3-3| ... | @@ -735,7 +735,7 @@ pub const Flock = extern struct { | ... | @@ -735,7 +735,7 @@ pub const Flock = extern struct { |
| 735 | l_whence: c_short, | 735 | l_whence: c_short, |
| 736 | }; | 736 | }; |
| 737 | 737 | ||
| 738 | pub const rlimit_resource = extern enum(c_int) { | 738 | pub const rlimit_resource = enum(c_int) { |
| 739 | CPU = 0, | 739 | CPU = 0, |
| 740 | FSIZE = 1, | 740 | FSIZE = 1, |
| 741 | DATA = 2, | 741 | DATA = 2, |
| ... | @@ -746,11 +746,11 @@ pub const rlimit_resource = extern enum(c_int) { | ... | @@ -746,11 +746,11 @@ pub const rlimit_resource = extern enum(c_int) { |
| 746 | NPROC = 7, | 746 | NPROC = 7, |
| 747 | NOFILE = 8, | 747 | NOFILE = 8, |
| 748 | SBSIZE = 9, | 748 | SBSIZE = 9, |
| 749 | AS = 10, | ||
| 750 | VMEM = 10, | 749 | VMEM = 10, |
| 751 | POSIXLOCKS = 11, | 750 | POSIXLOCKS = 11, |
| 752 | |||
| 753 | _, | 751 | _, |
| 752 | |||
| 753 | pub const AS: rlimit_resource = .VMEM; | ||
| 754 | }; | 754 | }; |
| 755 | 755 | ||
| 756 | pub const rlim_t = i64; | 756 | pub const rlim_t = i64; |
lib/std/os/bits/freebsd.zig+6-6| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../../std.zig"); | 6 | const std = @import("../../std.zig"); |
| 7 | const builtin = std.builtin; | 7 | const builtin = @import("builtin"); |
| 8 | const maxInt = std.math.maxInt; | 8 | const maxInt = std.math.maxInt; |
| 9 | 9 | ||
| 10 | pub const blksize_t = i32; | 10 | pub const blksize_t = i32; |
| ... | @@ -842,7 +842,7 @@ pub const sigset_t = extern struct { | ... | @@ -842,7 +842,7 @@ pub const sigset_t = extern struct { |
| 842 | 842 | ||
| 843 | pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS }; | 843 | pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS }; |
| 844 | 844 | ||
| 845 | pub usingnamespace switch (builtin.arch) { | 845 | pub usingnamespace switch (builtin.target.cpu.arch) { |
| 846 | .x86_64 => struct { | 846 | .x86_64 => struct { |
| 847 | pub const ucontext_t = extern struct { | 847 | pub const ucontext_t = extern struct { |
| 848 | sigmask: sigset_t, | 848 | sigmask: sigset_t, |
| ... | @@ -1011,7 +1011,7 @@ pub const EOWNERDEAD = 96; // Previous owner died | ... | @@ -1011,7 +1011,7 @@ pub const EOWNERDEAD = 96; // Previous owner died |
| 1011 | 1011 | ||
| 1012 | pub const ELAST = 96; // Must be equal largest errno | 1012 | pub const ELAST = 96; // Must be equal largest errno |
| 1013 | 1013 | ||
| 1014 | pub const MINSIGSTKSZ = switch (builtin.arch) { | 1014 | pub const MINSIGSTKSZ = switch (builtin.target.cpu.arch) { |
| 1015 | .i386, .x86_64 => 2048, | 1015 | .i386, .x86_64 => 2048, |
| 1016 | .arm, .aarch64 => 4096, | 1016 | .arm, .aarch64 => 4096, |
| 1017 | else => @compileError("MINSIGSTKSZ not defined for this architecture"), | 1017 | else => @compileError("MINSIGSTKSZ not defined for this architecture"), |
| ... | @@ -1467,7 +1467,7 @@ pub const IPPROTO_RESERVED_253 = 253; | ... | @@ -1467,7 +1467,7 @@ pub const IPPROTO_RESERVED_253 = 253; |
| 1467 | /// Reserved | 1467 | /// Reserved |
| 1468 | pub const IPPROTO_RESERVED_254 = 254; | 1468 | pub const IPPROTO_RESERVED_254 = 254; |
| 1469 | 1469 | ||
| 1470 | pub const rlimit_resource = extern enum(c_int) { | 1470 | pub const rlimit_resource = enum(c_int) { |
| 1471 | CPU = 0, | 1471 | CPU = 0, |
| 1472 | FSIZE = 1, | 1472 | FSIZE = 1, |
| 1473 | DATA = 2, | 1473 | DATA = 2, |
| ... | @@ -1479,13 +1479,13 @@ pub const rlimit_resource = extern enum(c_int) { | ... | @@ -1479,13 +1479,13 @@ pub const rlimit_resource = extern enum(c_int) { |
| 1479 | NOFILE = 8, | 1479 | NOFILE = 8, |
| 1480 | SBSIZE = 9, | 1480 | SBSIZE = 9, |
| 1481 | VMEM = 10, | 1481 | VMEM = 10, |
| 1482 | AS = 10, | ||
| 1483 | NPTS = 11, | 1482 | NPTS = 11, |
| 1484 | SWAP = 12, | 1483 | SWAP = 12, |
| 1485 | KQUEUES = 13, | 1484 | KQUEUES = 13, |
| 1486 | UMTXP = 14, | 1485 | UMTXP = 14, |
| 1487 | |||
| 1488 | _, | 1486 | _, |
| 1487 | |||
| 1488 | pub const AS: rlimit_resource = .VMEM; | ||
| 1489 | }; | 1489 | }; |
| 1490 | 1490 | ||
| 1491 | pub const rlim_t = i64; | 1491 | pub const rlim_t = i64; |
lib/std/os/bits/haiku.zig+4-4| ... | @@ -1314,7 +1314,7 @@ pub const IPPROTO_RESERVED_253 = 253; | ... | @@ -1314,7 +1314,7 @@ pub const IPPROTO_RESERVED_253 = 253; |
| 1314 | /// Reserved | 1314 | /// Reserved |
| 1315 | pub const IPPROTO_RESERVED_254 = 254; | 1315 | pub const IPPROTO_RESERVED_254 = 254; |
| 1316 | 1316 | ||
| 1317 | pub const rlimit_resource = extern enum(c_int) { | 1317 | pub const rlimit_resource = enum(c_int) { |
| 1318 | CPU = 0, | 1318 | CPU = 0, |
| 1319 | FSIZE = 1, | 1319 | FSIZE = 1, |
| 1320 | DATA = 2, | 1320 | DATA = 2, |
| ... | @@ -1326,13 +1326,13 @@ pub const rlimit_resource = extern enum(c_int) { | ... | @@ -1326,13 +1326,13 @@ pub const rlimit_resource = extern enum(c_int) { |
| 1326 | NOFILE = 8, | 1326 | NOFILE = 8, |
| 1327 | SBSIZE = 9, | 1327 | SBSIZE = 9, |
| 1328 | VMEM = 10, | 1328 | VMEM = 10, |
| 1329 | AS = 10, | ||
| 1330 | NPTS = 11, | 1329 | NPTS = 11, |
| 1331 | SWAP = 12, | 1330 | SWAP = 12, |
| 1332 | KQUEUES = 13, | 1331 | KQUEUES = 13, |
| 1333 | UMTXP = 14, | 1332 | UMTXP = 14, |
| 1334 | |||
| 1335 | _, | 1333 | _, |
| 1334 | |||
| 1335 | pub const AS: rlimit_resource = .VMEM; | ||
| 1336 | }; | 1336 | }; |
| 1337 | 1337 | ||
| 1338 | pub const rlim_t = i64; | 1338 | pub const rlim_t = i64; |
| ... | @@ -1355,7 +1355,7 @@ pub const SHUT_WR = 1; | ... | @@ -1355,7 +1355,7 @@ pub const SHUT_WR = 1; |
| 1355 | pub const SHUT_RDWR = 2; | 1355 | pub const SHUT_RDWR = 2; |
| 1356 | 1356 | ||
| 1357 | // TODO fill out if needed | 1357 | // TODO fill out if needed |
| 1358 | pub const directory_which = extern enum(c_int) { | 1358 | pub const directory_which = enum(c_int) { |
| 1359 | B_USER_SETTINGS_DIRECTORY = 0xbbe, | 1359 | B_USER_SETTINGS_DIRECTORY = 0xbbe, |
| 1360 | 1360 | ||
| 1361 | _, | 1361 | _, |
lib/std/os/bits/linux.zig+21-21| ... | @@ -3,18 +3,18 @@ | ... | @@ -3,18 +3,18 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | ||
| 7 | const std = @import("../../std.zig"); | 6 | const std = @import("../../std.zig"); |
| 8 | const maxInt = std.math.maxInt; | 7 | const maxInt = std.math.maxInt; |
| 8 | const arch = @import("builtin").target.cpu.arch; | ||
| 9 | usingnamespace @import("../bits.zig"); | 9 | usingnamespace @import("../bits.zig"); |
| 10 | 10 | ||
| 11 | pub usingnamespace switch (builtin.arch) { | 11 | pub usingnamespace switch (arch) { |
| 12 | .mips, .mipsel => @import("linux/errno-mips.zig"), | 12 | .mips, .mipsel => @import("linux/errno-mips.zig"), |
| 13 | .sparc, .sparcel, .sparcv9 => @import("linux/errno-sparc.zig"), | 13 | .sparc, .sparcel, .sparcv9 => @import("linux/errno-sparc.zig"), |
| 14 | else => @import("linux/errno-generic.zig"), | 14 | else => @import("linux/errno-generic.zig"), |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
| 17 | pub usingnamespace switch (builtin.arch) { | 17 | pub usingnamespace switch (arch) { |
| 18 | .i386 => @import("linux/i386.zig"), | 18 | .i386 => @import("linux/i386.zig"), |
| 19 | .x86_64 => @import("linux/x86_64.zig"), | 19 | .x86_64 => @import("linux/x86_64.zig"), |
| 20 | .aarch64 => @import("linux/arm64.zig"), | 20 | .aarch64 => @import("linux/arm64.zig"), |
| ... | @@ -31,10 +31,10 @@ pub usingnamespace @import("linux/netlink.zig"); | ... | @@ -31,10 +31,10 @@ pub usingnamespace @import("linux/netlink.zig"); |
| 31 | pub usingnamespace @import("linux/prctl.zig"); | 31 | pub usingnamespace @import("linux/prctl.zig"); |
| 32 | pub usingnamespace @import("linux/securebits.zig"); | 32 | pub usingnamespace @import("linux/securebits.zig"); |
| 33 | 33 | ||
| 34 | const is_mips = builtin.arch.isMIPS(); | 34 | const is_mips = arch.isMIPS(); |
| 35 | const is_ppc = builtin.arch.isPPC(); | 35 | const is_ppc = arch.isPPC(); |
| 36 | const is_ppc64 = builtin.arch.isPPC64(); | 36 | const is_ppc64 = arch.isPPC64(); |
| 37 | const is_sparc = builtin.arch.isSPARC(); | 37 | const is_sparc = arch.isSPARC(); |
| 38 | 38 | ||
| 39 | pub const pid_t = i32; | 39 | pub const pid_t = i32; |
| 40 | pub const fd_t = i32; | 40 | pub const fd_t = i32; |
| ... | @@ -136,7 +136,7 @@ pub const PROT_WRITE = 0x2; | ... | @@ -136,7 +136,7 @@ pub const PROT_WRITE = 0x2; |
| 136 | pub const PROT_EXEC = 0x4; | 136 | pub const PROT_EXEC = 0x4; |
| 137 | 137 | ||
| 138 | /// page may be used for atomic ops | 138 | /// page may be used for atomic ops |
| 139 | pub const PROT_SEM = switch (builtin.arch) { | 139 | pub const PROT_SEM = switch (arch) { |
| 140 | // TODO: also xtensa | 140 | // TODO: also xtensa |
| 141 | .mips, .mipsel, .mips64, .mips64el => 0x10, | 141 | .mips, .mipsel, .mips64, .mips64el => 0x10, |
| 142 | else => 0x8, | 142 | else => 0x8, |
| ... | @@ -1074,7 +1074,7 @@ pub const sigset_t = [1024 / 32]u32; | ... | @@ -1074,7 +1074,7 @@ pub const sigset_t = [1024 / 32]u32; |
| 1074 | pub const all_mask: sigset_t = [_]u32{0xffffffff} ** sigset_t.len; | 1074 | pub const all_mask: sigset_t = [_]u32{0xffffffff} ** sigset_t.len; |
| 1075 | pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; | 1075 | pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; |
| 1076 | 1076 | ||
| 1077 | pub const k_sigaction = switch (builtin.arch) { | 1077 | pub const k_sigaction = switch (arch) { |
| 1078 | .mips, .mipsel => extern struct { | 1078 | .mips, .mipsel => extern struct { |
| 1079 | flags: c_uint, | 1079 | flags: c_uint, |
| 1080 | handler: ?fn (c_int) callconv(.C) void, | 1080 | handler: ?fn (c_int) callconv(.C) void, |
| ... | @@ -1198,7 +1198,7 @@ pub const epoll_data = extern union { | ... | @@ -1198,7 +1198,7 @@ pub const epoll_data = extern union { |
| 1198 | 1198 | ||
| 1199 | // On x86_64 the structure is packed so that it matches the definition of its | 1199 | // On x86_64 the structure is packed so that it matches the definition of its |
| 1200 | // 32bit counterpart | 1200 | // 32bit counterpart |
| 1201 | pub const epoll_event = switch (builtin.arch) { | 1201 | pub const epoll_event = switch (arch) { |
| 1202 | .x86_64 => packed struct { | 1202 | .x86_64 => packed struct { |
| 1203 | events: u32, | 1203 | events: u32, |
| 1204 | data: epoll_data, | 1204 | data: epoll_data, |
| ... | @@ -1365,12 +1365,12 @@ pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t { | ... | @@ -1365,12 +1365,12 @@ pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t { |
| 1365 | //#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set) | 1365 | //#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set) |
| 1366 | //#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2) | 1366 | //#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2) |
| 1367 | 1367 | ||
| 1368 | pub const MINSIGSTKSZ = switch (builtin.arch) { | 1368 | pub const MINSIGSTKSZ = switch (arch) { |
| 1369 | .i386, .x86_64, .arm, .mipsel => 2048, | 1369 | .i386, .x86_64, .arm, .mipsel => 2048, |
| 1370 | .aarch64 => 5120, | 1370 | .aarch64 => 5120, |
| 1371 | else => @compileError("MINSIGSTKSZ not defined for this architecture"), | 1371 | else => @compileError("MINSIGSTKSZ not defined for this architecture"), |
| 1372 | }; | 1372 | }; |
| 1373 | pub const SIGSTKSZ = switch (builtin.arch) { | 1373 | pub const SIGSTKSZ = switch (arch) { |
| 1374 | .i386, .x86_64, .arm, .mipsel => 8192, | 1374 | .i386, .x86_64, .arm, .mipsel => 8192, |
| 1375 | .aarch64 => 16384, | 1375 | .aarch64 => 16384, |
| 1376 | else => @compileError("SIGSTKSZ not defined for this architecture"), | 1376 | else => @compileError("SIGSTKSZ not defined for this architecture"), |
| ... | @@ -1564,7 +1564,7 @@ pub const io_uring_sqe = extern struct { | ... | @@ -1564,7 +1564,7 @@ pub const io_uring_sqe = extern struct { |
| 1564 | __pad2: [2]u64, | 1564 | __pad2: [2]u64, |
| 1565 | }; | 1565 | }; |
| 1566 | 1566 | ||
| 1567 | pub const IOSQE_BIT = extern enum(u8) { | 1567 | pub const IOSQE_BIT = enum(u8) { |
| 1568 | FIXED_FILE, | 1568 | FIXED_FILE, |
| 1569 | IO_DRAIN, | 1569 | IO_DRAIN, |
| 1570 | IO_LINK, | 1570 | IO_LINK, |
| ... | @@ -1595,7 +1595,7 @@ pub const IOSQE_ASYNC = 1 << @enumToInt(IOSQE_BIT.ASYNC); | ... | @@ -1595,7 +1595,7 @@ pub const IOSQE_ASYNC = 1 << @enumToInt(IOSQE_BIT.ASYNC); |
| 1595 | /// select buffer from buf_group | 1595 | /// select buffer from buf_group |
| 1596 | pub const IOSQE_BUFFER_SELECT = 1 << @enumToInt(IOSQE_BIT.BUFFER_SELECT); | 1596 | pub const IOSQE_BUFFER_SELECT = 1 << @enumToInt(IOSQE_BIT.BUFFER_SELECT); |
| 1597 | 1597 | ||
| 1598 | pub const IORING_OP = extern enum(u8) { | 1598 | pub const IORING_OP = enum(u8) { |
| 1599 | NOP, | 1599 | NOP, |
| 1600 | READV, | 1600 | READV, |
| 1601 | WRITEV, | 1601 | WRITEV, |
| ... | @@ -1664,7 +1664,7 @@ pub const IORING_ENTER_GETEVENTS = 1 << 0; | ... | @@ -1664,7 +1664,7 @@ pub const IORING_ENTER_GETEVENTS = 1 << 0; |
| 1664 | pub const IORING_ENTER_SQ_WAKEUP = 1 << 1; | 1664 | pub const IORING_ENTER_SQ_WAKEUP = 1 << 1; |
| 1665 | 1665 | ||
| 1666 | // io_uring_register opcodes and arguments | 1666 | // io_uring_register opcodes and arguments |
| 1667 | pub const IORING_REGISTER = extern enum(u8) { | 1667 | pub const IORING_REGISTER = enum(u8) { |
| 1668 | REGISTER_BUFFERS, | 1668 | REGISTER_BUFFERS, |
| 1669 | UNREGISTER_BUFFERS, | 1669 | UNREGISTER_BUFFERS, |
| 1670 | REGISTER_FILES, | 1670 | REGISTER_FILES, |
| ... | @@ -1731,7 +1731,7 @@ pub const io_uring_restriction = extern struct { | ... | @@ -1731,7 +1731,7 @@ pub const io_uring_restriction = extern struct { |
| 1731 | }; | 1731 | }; |
| 1732 | 1732 | ||
| 1733 | /// io_uring_restriction->opcode values | 1733 | /// io_uring_restriction->opcode values |
| 1734 | pub const IORING_RESTRICTION = extern enum(u8) { | 1734 | pub const IORING_RESTRICTION = enum(u8) { |
| 1735 | /// Allow an io_uring_register(2) opcode | 1735 | /// Allow an io_uring_register(2) opcode |
| 1736 | REGISTER_OP = 0, | 1736 | REGISTER_OP = 0, |
| 1737 | 1737 | ||
| ... | @@ -1986,7 +1986,7 @@ pub const tcp_repair_window = extern struct { | ... | @@ -1986,7 +1986,7 @@ pub const tcp_repair_window = extern struct { |
| 1986 | rcv_wup: u32, | 1986 | rcv_wup: u32, |
| 1987 | }; | 1987 | }; |
| 1988 | 1988 | ||
| 1989 | pub const TcpRepairOption = extern enum { | 1989 | pub const TcpRepairOption = enum { |
| 1990 | TCP_NO_QUEUE, | 1990 | TCP_NO_QUEUE, |
| 1991 | TCP_RECV_QUEUE, | 1991 | TCP_RECV_QUEUE, |
| 1992 | TCP_SEND_QUEUE, | 1992 | TCP_SEND_QUEUE, |
| ... | @@ -1994,7 +1994,7 @@ pub const TcpRepairOption = extern enum { | ... | @@ -1994,7 +1994,7 @@ pub const TcpRepairOption = extern enum { |
| 1994 | }; | 1994 | }; |
| 1995 | 1995 | ||
| 1996 | /// why fastopen failed from client perspective | 1996 | /// why fastopen failed from client perspective |
| 1997 | pub const tcp_fastopen_client_fail = extern enum { | 1997 | pub const tcp_fastopen_client_fail = enum { |
| 1998 | /// catch-all | 1998 | /// catch-all |
| 1999 | TFO_STATUS_UNSPEC, | 1999 | TFO_STATUS_UNSPEC, |
| 2000 | /// if not in TFO_CLIENT_NO_COOKIE mode | 2000 | /// if not in TFO_CLIENT_NO_COOKIE mode |
| ... | @@ -2130,7 +2130,7 @@ pub const B3000000 = 0o0010015; | ... | @@ -2130,7 +2130,7 @@ pub const B3000000 = 0o0010015; |
| 2130 | pub const B3500000 = 0o0010016; | 2130 | pub const B3500000 = 0o0010016; |
| 2131 | pub const B4000000 = 0o0010017; | 2131 | pub const B4000000 = 0o0010017; |
| 2132 | 2132 | ||
| 2133 | pub usingnamespace switch (builtin.arch) { | 2133 | pub usingnamespace switch (arch) { |
| 2134 | .powerpc, .powerpc64, .powerpc64le => struct { | 2134 | .powerpc, .powerpc64, .powerpc64le => struct { |
| 2135 | pub const VINTR = 0; | 2135 | pub const VINTR = 0; |
| 2136 | pub const VQUIT = 1; | 2136 | pub const VQUIT = 1; |
| ... | @@ -2261,7 +2261,7 @@ pub const NOFLSH = 128; | ... | @@ -2261,7 +2261,7 @@ pub const NOFLSH = 128; |
| 2261 | pub const TOSTOP = 256; | 2261 | pub const TOSTOP = 256; |
| 2262 | pub const IEXTEN = 32768; | 2262 | pub const IEXTEN = 32768; |
| 2263 | 2263 | ||
| 2264 | pub const TCSA = extern enum(c_uint) { | 2264 | pub const TCSA = enum(c_uint) { |
| 2265 | NOW, | 2265 | NOW, |
| 2266 | DRAIN, | 2266 | DRAIN, |
| 2267 | FLUSH, | 2267 | FLUSH, |
| ... | @@ -2312,7 +2312,7 @@ pub const ifreq = extern struct { | ... | @@ -2312,7 +2312,7 @@ pub const ifreq = extern struct { |
| 2312 | }; | 2312 | }; |
| 2313 | 2313 | ||
| 2314 | // doc comments copied from musl | 2314 | // doc comments copied from musl |
| 2315 | pub const rlimit_resource = extern enum(c_int) { | 2315 | pub const rlimit_resource = enum(c_int) { |
| 2316 | /// Per-process CPU limit, in seconds. | 2316 | /// Per-process CPU limit, in seconds. |
| 2317 | CPU, | 2317 | CPU, |
| 2318 | 2318 |
lib/std/os/bits/linux/arm-eabi.zig+2-4| ... | @@ -15,7 +15,7 @@ const uid_t = linux.uid_t; | ... | @@ -15,7 +15,7 @@ const uid_t = linux.uid_t; |
| 15 | const gid_t = linux.gid_t; | 15 | const gid_t = linux.gid_t; |
| 16 | const pid_t = linux.pid_t; | 16 | const pid_t = linux.pid_t; |
| 17 | 17 | ||
| 18 | pub const SYS = extern enum(usize) { | 18 | pub const SYS = enum(usize) { |
| 19 | restart_syscall = 0, | 19 | restart_syscall = 0, |
| 20 | exit = 1, | 20 | exit = 1, |
| 21 | fork = 2, | 21 | fork = 2, |
| ... | @@ -242,7 +242,6 @@ pub const SYS = extern enum(usize) { | ... | @@ -242,7 +242,6 @@ pub const SYS = extern enum(usize) { |
| 242 | tgkill = 268, | 242 | tgkill = 268, |
| 243 | utimes = 269, | 243 | utimes = 269, |
| 244 | fadvise64_64 = 270, | 244 | fadvise64_64 = 270, |
| 245 | arm_fadvise64_64 = 270, | ||
| 246 | pciconfig_iobase = 271, | 245 | pciconfig_iobase = 271, |
| 247 | pciconfig_read = 272, | 246 | pciconfig_read = 272, |
| 248 | pciconfig_write = 273, | 247 | pciconfig_write = 273, |
| ... | @@ -313,8 +312,7 @@ pub const SYS = extern enum(usize) { | ... | @@ -313,8 +312,7 @@ pub const SYS = extern enum(usize) { |
| 313 | set_robust_list = 338, | 312 | set_robust_list = 338, |
| 314 | get_robust_list = 339, | 313 | get_robust_list = 339, |
| 315 | splice = 340, | 314 | splice = 340, |
| 316 | sync_file_range2 = 341, | 315 | sync_file_range = 341, |
| 317 | arm_sync_file_range = 341, | ||
| 318 | tee = 342, | 316 | tee = 342, |
| 319 | vmsplice = 343, | 317 | vmsplice = 343, |
| 320 | move_pages = 344, | 318 | move_pages = 344, |
lib/std/os/bits/linux/arm64.zig+1-2| ... | @@ -17,7 +17,7 @@ const gid_t = linux.gid_t; | ... | @@ -17,7 +17,7 @@ const gid_t = linux.gid_t; |
| 17 | const pid_t = linux.pid_t; | 17 | const pid_t = linux.pid_t; |
| 18 | const stack_t = linux.stack_t; | 18 | const stack_t = linux.stack_t; |
| 19 | const sigset_t = linux.sigset_t; | 19 | const sigset_t = linux.sigset_t; |
| 20 | pub const SYS = extern enum(usize) { | 20 | pub const SYS = enum(usize) { |
| 21 | io_setup = 0, | 21 | io_setup = 0, |
| 22 | io_destroy = 1, | 22 | io_destroy = 1, |
| 23 | io_submit = 2, | 23 | io_submit = 2, |
| ... | @@ -102,7 +102,6 @@ pub const SYS = extern enum(usize) { | ... | @@ -102,7 +102,6 @@ pub const SYS = extern enum(usize) { |
| 102 | sync = 81, | 102 | sync = 81, |
| 103 | fsync = 82, | 103 | fsync = 82, |
| 104 | fdatasync = 83, | 104 | fdatasync = 83, |
| 105 | sync_file_range2 = 84, | ||
| 106 | sync_file_range = 84, | 105 | sync_file_range = 84, |
| 107 | timerfd_create = 85, | 106 | timerfd_create = 85, |
| 108 | timerfd_settime = 86, | 107 | timerfd_settime = 86, |
lib/std/os/bits/linux/i386.zig+1-1| ... | @@ -17,7 +17,7 @@ const pid_t = linux.pid_t; | ... | @@ -17,7 +17,7 @@ const pid_t = linux.pid_t; |
| 17 | const stack_t = linux.stack_t; | 17 | const stack_t = linux.stack_t; |
| 18 | const sigset_t = linux.sigset_t; | 18 | const sigset_t = linux.sigset_t; |
| 19 | 19 | ||
| 20 | pub const SYS = extern enum(usize) { | 20 | pub const SYS = enum(usize) { |
| 21 | restart_syscall = 0, | 21 | restart_syscall = 0, |
| 22 | exit = 1, | 22 | exit = 1, |
| 23 | fork = 2, | 23 | fork = 2, |
lib/std/os/bits/linux/mips.zig+1-1| ... | @@ -12,7 +12,7 @@ const uid_t = linux.uid_t; | ... | @@ -12,7 +12,7 @@ const uid_t = linux.uid_t; |
| 12 | const gid_t = linux.gid_t; | 12 | const gid_t = linux.gid_t; |
| 13 | const pid_t = linux.pid_t; | 13 | const pid_t = linux.pid_t; |
| 14 | 14 | ||
| 15 | pub const SYS = extern enum(usize) { | 15 | pub const SYS = enum(usize) { |
| 16 | pub const Linux = 4000; | 16 | pub const Linux = 4000; |
| 17 | 17 | ||
| 18 | syscall = Linux + 0, | 18 | syscall = Linux + 0, |
lib/std/os/bits/linux/netlink.zig+5-4| ... | @@ -126,7 +126,7 @@ pub const NLM_F_CAPPED = 0x100; | ... | @@ -126,7 +126,7 @@ pub const NLM_F_CAPPED = 0x100; |
| 126 | /// extended ACK TVLs were included | 126 | /// extended ACK TVLs were included |
| 127 | pub const NLM_F_ACK_TLVS = 0x200; | 127 | pub const NLM_F_ACK_TLVS = 0x200; |
| 128 | 128 | ||
| 129 | pub const NetlinkMessageType = extern enum(u16) { | 129 | pub const NetlinkMessageType = enum(u16) { |
| 130 | /// < 0x10: reserved control messages | 130 | /// < 0x10: reserved control messages |
| 131 | pub const MIN_TYPE = 0x10; | 131 | pub const MIN_TYPE = 0x10; |
| 132 | 132 | ||
| ... | @@ -287,7 +287,7 @@ pub const rtattr = extern struct { | ... | @@ -287,7 +287,7 @@ pub const rtattr = extern struct { |
| 287 | pub const ALIGNTO = 4; | 287 | pub const ALIGNTO = 4; |
| 288 | }; | 288 | }; |
| 289 | 289 | ||
| 290 | pub const IFLA = extern enum(c_ushort) { | 290 | pub const IFLA = enum(c_ushort) { |
| 291 | UNSPEC, | 291 | UNSPEC, |
| 292 | ADDRESS, | 292 | ADDRESS, |
| 293 | BROADCAST, | 293 | BROADCAST, |
| ... | @@ -351,8 +351,7 @@ pub const IFLA = extern enum(c_ushort) { | ... | @@ -351,8 +351,7 @@ pub const IFLA = extern enum(c_ushort) { |
| 351 | EVENT, | 351 | EVENT, |
| 352 | 352 | ||
| 353 | NEW_NETNSID, | 353 | NEW_NETNSID, |
| 354 | IF_NETNSID = 46, | 354 | IF_NETNSID, |
| 355 | TARGET_NETNSID = 46, // new alias | ||
| 356 | 355 | ||
| 357 | CARRIER_UP_COUNT, | 356 | CARRIER_UP_COUNT, |
| 358 | CARRIER_DOWN_COUNT, | 357 | CARRIER_DOWN_COUNT, |
| ... | @@ -361,6 +360,8 @@ pub const IFLA = extern enum(c_ushort) { | ... | @@ -361,6 +360,8 @@ pub const IFLA = extern enum(c_ushort) { |
| 361 | MAX_MTU, | 360 | MAX_MTU, |
| 362 | 361 | ||
| 363 | _, | 362 | _, |
| 363 | |||
| 364 | pub const TARGET_NETNSID: IFLA = .IF_NETNSID; | ||
| 364 | }; | 365 | }; |
| 365 | 366 | ||
| 366 | pub const rtnl_link_ifmap = extern struct { | 367 | pub const rtnl_link_ifmap = extern struct { |
lib/std/os/bits/linux/powerpc.zig+2-2| ... | @@ -14,7 +14,7 @@ const gid_t = linux.gid_t; | ... | @@ -14,7 +14,7 @@ const gid_t = linux.gid_t; |
| 14 | const pid_t = linux.pid_t; | 14 | const pid_t = linux.pid_t; |
| 15 | const stack_t = linux.stack_t; | 15 | const stack_t = linux.stack_t; |
| 16 | const sigset_t = linux.sigset_t; | 16 | const sigset_t = linux.sigset_t; |
| 17 | pub const SYS = extern enum(usize) { | 17 | pub const SYS = enum(usize) { |
| 18 | restart_syscall = 0, | 18 | restart_syscall = 0, |
| 19 | exit = 1, | 19 | exit = 1, |
| 20 | fork = 2, | 20 | fork = 2, |
| ... | @@ -321,7 +321,7 @@ pub const SYS = extern enum(usize) { | ... | @@ -321,7 +321,7 @@ pub const SYS = extern enum(usize) { |
| 321 | signalfd = 305, | 321 | signalfd = 305, |
| 322 | timerfd_create = 306, | 322 | timerfd_create = 306, |
| 323 | eventfd = 307, | 323 | eventfd = 307, |
| 324 | sync_file_range2 = 308, | 324 | sync_file_range = 308, |
| 325 | fallocate = 309, | 325 | fallocate = 309, |
| 326 | subpage_prot = 310, | 326 | subpage_prot = 310, |
| 327 | timerfd_settime = 311, | 327 | timerfd_settime = 311, |
lib/std/os/bits/linux/powerpc64.zig+3-3| ... | @@ -14,7 +14,7 @@ const gid_t = linux.gid_t; | ... | @@ -14,7 +14,7 @@ const gid_t = linux.gid_t; |
| 14 | const pid_t = linux.pid_t; | 14 | const pid_t = linux.pid_t; |
| 15 | const stack_t = linux.stack_t; | 15 | const stack_t = linux.stack_t; |
| 16 | const sigset_t = linux.sigset_t; | 16 | const sigset_t = linux.sigset_t; |
| 17 | pub const SYS = extern enum(usize) { | 17 | pub const SYS = enum(usize) { |
| 18 | restart_syscall = 0, | 18 | restart_syscall = 0, |
| 19 | exit = 1, | 19 | exit = 1, |
| 20 | fork = 2, | 20 | fork = 2, |
| ... | @@ -295,7 +295,7 @@ pub const SYS = extern enum(usize) { | ... | @@ -295,7 +295,7 @@ pub const SYS = extern enum(usize) { |
| 295 | mknodat = 288, | 295 | mknodat = 288, |
| 296 | fchownat = 289, | 296 | fchownat = 289, |
| 297 | futimesat = 290, | 297 | futimesat = 290, |
| 298 | newfstatat = 291, | 298 | fstatat = 291, |
| 299 | unlinkat = 292, | 299 | unlinkat = 292, |
| 300 | renameat = 293, | 300 | renameat = 293, |
| 301 | linkat = 294, | 301 | linkat = 294, |
| ... | @@ -312,7 +312,7 @@ pub const SYS = extern enum(usize) { | ... | @@ -312,7 +312,7 @@ pub const SYS = extern enum(usize) { |
| 312 | signalfd = 305, | 312 | signalfd = 305, |
| 313 | timerfd_create = 306, | 313 | timerfd_create = 306, |
| 314 | eventfd = 307, | 314 | eventfd = 307, |
| 315 | sync_file_range2 = 308, | 315 | sync_file_range = 308, |
| 316 | fallocate = 309, | 316 | fallocate = 309, |
| 317 | subpage_prot = 310, | 317 | subpage_prot = 310, |
| 318 | timerfd_settime = 311, | 318 | timerfd_settime = 311, |
lib/std/os/bits/linux/prctl.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | 6 | ||
| 7 | pub const PR = extern enum(i32) { | 7 | pub const PR = enum(i32) { |
| 8 | SET_PDEATHSIG = 1, | 8 | SET_PDEATHSIG = 1, |
| 9 | GET_PDEATHSIG = 2, | 9 | GET_PDEATHSIG = 2, |
| 10 | 10 |
lib/std/os/bits/linux/riscv64.zig+1-1| ... | @@ -9,7 +9,7 @@ const uid_t = std.os.linux.uid_t; | ... | @@ -9,7 +9,7 @@ const uid_t = std.os.linux.uid_t; |
| 9 | const gid_t = std.os.linux.gid_t; | 9 | const gid_t = std.os.linux.gid_t; |
| 10 | const pid_t = std.os.linux.pid_t; | 10 | const pid_t = std.os.linux.pid_t; |
| 11 | 11 | ||
| 12 | pub const SYS = extern enum(usize) { | 12 | pub const SYS = enum(usize) { |
| 13 | pub const arch_specific_syscall = 244; | 13 | pub const arch_specific_syscall = 244; |
| 14 | 14 | ||
| 15 | io_setup = 0, | 15 | io_setup = 0, |
lib/std/os/bits/linux/sparc64.zig+1-1| ... | @@ -12,7 +12,7 @@ const socklen_t = linux.socklen_t; | ... | @@ -12,7 +12,7 @@ const socklen_t = linux.socklen_t; |
| 12 | const iovec = linux.iovec; | 12 | const iovec = linux.iovec; |
| 13 | const iovec_const = linux.iovec_const; | 13 | const iovec_const = linux.iovec_const; |
| 14 | 14 | ||
| 15 | pub const SYS = extern enum(usize) { | 15 | pub const SYS = enum(usize) { |
| 16 | restart_syscall = 0, | 16 | restart_syscall = 0, |
| 17 | exit = 1, | 17 | exit = 1, |
| 18 | fork = 2, | 18 | fork = 2, |
lib/std/os/bits/linux/x86_64.zig+1-2| ... | @@ -21,7 +21,7 @@ const iovec_const = linux.iovec_const; | ... | @@ -21,7 +21,7 @@ const iovec_const = linux.iovec_const; |
| 21 | pub const mode_t = usize; | 21 | pub const mode_t = usize; |
| 22 | pub const time_t = isize; | 22 | pub const time_t = isize; |
| 23 | 23 | ||
| 24 | pub const SYS = extern enum(usize) { | 24 | pub const SYS = enum(usize) { |
| 25 | read = 0, | 25 | read = 0, |
| 26 | write = 1, | 26 | write = 1, |
| 27 | open = 2, | 27 | open = 2, |
| ... | @@ -284,7 +284,6 @@ pub const SYS = extern enum(usize) { | ... | @@ -284,7 +284,6 @@ pub const SYS = extern enum(usize) { |
| 284 | mknodat = 259, | 284 | mknodat = 259, |
| 285 | fchownat = 260, | 285 | fchownat = 260, |
| 286 | futimesat = 261, | 286 | futimesat = 261, |
| 287 | newfstatat = 262, | ||
| 288 | fstatat = 262, | 287 | fstatat = 262, |
| 289 | unlinkat = 263, | 288 | unlinkat = 263, |
| 290 | renameat = 264, | 289 | renameat = 264, |
lib/std/os/bits/netbsd.zig+4-4| ... | @@ -60,7 +60,7 @@ pub const addrinfo = extern struct { | ... | @@ -60,7 +60,7 @@ pub const addrinfo = extern struct { |
| 60 | next: ?*addrinfo, | 60 | next: ?*addrinfo, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | pub const EAI = extern enum(c_int) { | 63 | pub const EAI = enum(c_int) { |
| 64 | /// address family for hostname not supported | 64 | /// address family for hostname not supported |
| 65 | ADDRFAMILY = 1, | 65 | ADDRFAMILY = 1, |
| 66 | 66 | ||
| ... | @@ -1187,7 +1187,7 @@ pub const IPPROTO_PFSYNC = 240; | ... | @@ -1187,7 +1187,7 @@ pub const IPPROTO_PFSYNC = 240; |
| 1187 | /// raw IP packet | 1187 | /// raw IP packet |
| 1188 | pub const IPPROTO_RAW = 255; | 1188 | pub const IPPROTO_RAW = 255; |
| 1189 | 1189 | ||
| 1190 | pub const rlimit_resource = extern enum(c_int) { | 1190 | pub const rlimit_resource = enum(c_int) { |
| 1191 | CPU = 0, | 1191 | CPU = 0, |
| 1192 | FSIZE = 1, | 1192 | FSIZE = 1, |
| 1193 | DATA = 2, | 1193 | DATA = 2, |
| ... | @@ -1198,11 +1198,11 @@ pub const rlimit_resource = extern enum(c_int) { | ... | @@ -1198,11 +1198,11 @@ pub const rlimit_resource = extern enum(c_int) { |
| 1198 | NPROC = 7, | 1198 | NPROC = 7, |
| 1199 | NOFILE = 8, | 1199 | NOFILE = 8, |
| 1200 | SBSIZE = 9, | 1200 | SBSIZE = 9, |
| 1201 | AS = 10, | ||
| 1202 | VMEM = 10, | 1201 | VMEM = 10, |
| 1203 | NTHR = 11, | 1202 | NTHR = 11, |
| 1204 | |||
| 1205 | _, | 1203 | _, |
| 1204 | |||
| 1205 | pub const AS: rlimit_resource = .VMEM; | ||
| 1206 | }; | 1206 | }; |
| 1207 | 1207 | ||
| 1208 | pub const rlim_t = u64; | 1208 | pub const rlim_t = u64; |
lib/std/os/bits/openbsd.zig+2-2| ... | @@ -76,7 +76,7 @@ pub const addrinfo = extern struct { | ... | @@ -76,7 +76,7 @@ pub const addrinfo = extern struct { |
| 76 | next: ?*addrinfo, | 76 | next: ?*addrinfo, |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | pub const EAI = extern enum(c_int) { | 79 | pub const EAI = enum(c_int) { |
| 80 | /// address family for hostname not supported | 80 | /// address family for hostname not supported |
| 81 | ADDRFAMILY = -9, | 81 | ADDRFAMILY = -9, |
| 82 | 82 | ||
| ... | @@ -1176,7 +1176,7 @@ pub const IPPROTO_PFSYNC = 240; | ... | @@ -1176,7 +1176,7 @@ pub const IPPROTO_PFSYNC = 240; |
| 1176 | /// raw IP packet | 1176 | /// raw IP packet |
| 1177 | pub const IPPROTO_RAW = 255; | 1177 | pub const IPPROTO_RAW = 255; |
| 1178 | 1178 | ||
| 1179 | pub const rlimit_resource = extern enum(c_int) { | 1179 | pub const rlimit_resource = enum(c_int) { |
| 1180 | CPU, | 1180 | CPU, |
| 1181 | FSIZE, | 1181 | FSIZE, |
| 1182 | DATA, | 1182 | DATA, |
lib/std/os/darwin.zig-1| ... | @@ -3,7 +3,6 @@ | ... | @@ -3,7 +3,6 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | ||
| 7 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 8 | pub usingnamespace std.c; | 7 | pub usingnamespace std.c; |
| 9 | pub usingnamespace @import("bits.zig"); | 8 | pub usingnamespace @import("bits.zig"); |
lib/std/os/linux.zig+24-25| ... | @@ -11,14 +11,15 @@ | ... | @@ -11,14 +11,15 @@ |
| 11 | // provide `rename` when only the `renameat` syscall exists. | 11 | // provide `rename` when only the `renameat` syscall exists. |
| 12 | // * Does not support POSIX thread cancellation. | 12 | // * Does not support POSIX thread cancellation. |
| 13 | const std = @import("../std.zig"); | 13 | const std = @import("../std.zig"); |
| 14 | const builtin = std.builtin; | ||
| 15 | const assert = std.debug.assert; | 14 | const assert = std.debug.assert; |
| 16 | const maxInt = std.math.maxInt; | 15 | const maxInt = std.math.maxInt; |
| 17 | const elf = std.elf; | 16 | const elf = std.elf; |
| 18 | const vdso = @import("linux/vdso.zig"); | 17 | const vdso = @import("linux/vdso.zig"); |
| 19 | const dl = @import("../dynamic_library.zig"); | 18 | const dl = @import("../dynamic_library.zig"); |
| 19 | const native_arch = std.Target.current.cpu.arch; | ||
| 20 | const native_endian = native_arch.endian(); | ||
| 20 | 21 | ||
| 21 | pub usingnamespace switch (builtin.arch) { | 22 | pub usingnamespace switch (native_arch) { |
| 22 | .i386 => @import("linux/i386.zig"), | 23 | .i386 => @import("linux/i386.zig"), |
| 23 | .x86_64 => @import("linux/x86_64.zig"), | 24 | .x86_64 => @import("linux/x86_64.zig"), |
| 24 | .aarch64 => @import("linux/arm64.zig"), | 25 | .aarch64 => @import("linux/arm64.zig"), |
| ... | @@ -75,7 +76,7 @@ fn splitValueBE64(val: i64) [2]u32 { | ... | @@ -75,7 +76,7 @@ fn splitValueBE64(val: i64) [2]u32 { |
| 75 | } | 76 | } |
| 76 | fn splitValue64(val: i64) [2]u32 { | 77 | fn splitValue64(val: i64) [2]u32 { |
| 77 | const u = @bitCast(u64, val); | 78 | const u = @bitCast(u64, val); |
| 78 | switch (builtin.endian) { | 79 | switch (native_endian) { |
| 79 | .Little => return [2]u32{ | 80 | .Little => return [2]u32{ |
| 80 | @truncate(u32, u), | 81 | @truncate(u32, u), |
| 81 | @truncate(u32, u >> 32), | 82 | @truncate(u32, u >> 32), |
| ... | @@ -130,7 +131,7 @@ pub fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*: | ... | @@ -130,7 +131,7 @@ pub fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*: |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | pub fn fork() usize { | 133 | pub fn fork() usize { |
| 133 | if (comptime builtin.arch.isSPARC()) { | 134 | if (comptime native_arch.isSPARC()) { |
| 134 | return syscall_fork(); | 135 | return syscall_fork(); |
| 135 | } else if (@hasField(SYS, "fork")) { | 136 | } else if (@hasField(SYS, "fork")) { |
| 136 | return syscall0(.fork); | 137 | return syscall0(.fork); |
| ... | @@ -450,7 +451,7 @@ pub fn faccessat(dirfd: i32, path: [*:0]const u8, mode: u32, flags: u32) usize { | ... | @@ -450,7 +451,7 @@ pub fn faccessat(dirfd: i32, path: [*:0]const u8, mode: u32, flags: u32) usize { |
| 450 | } | 451 | } |
| 451 | 452 | ||
| 452 | pub fn pipe(fd: *[2]i32) usize { | 453 | pub fn pipe(fd: *[2]i32) usize { |
| 453 | if (comptime (builtin.arch.isMIPS() or builtin.arch.isSPARC())) { | 454 | if (comptime (native_arch.isMIPS() or native_arch.isSPARC())) { |
| 454 | return syscall_pipe(fd); | 455 | return syscall_pipe(fd); |
| 455 | } else if (@hasField(SYS, "pipe")) { | 456 | } else if (@hasField(SYS, "pipe")) { |
| 456 | return syscall1(.pipe, @ptrToInt(fd)); | 457 | return syscall1(.pipe, @ptrToInt(fd)); |
| ... | @@ -933,7 +934,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact | ... | @@ -933,7 +934,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact |
| 933 | const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0; | 934 | const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0; |
| 934 | const oldksa_arg = if (oact != null) @ptrToInt(&oldksa) else 0; | 935 | const oldksa_arg = if (oact != null) @ptrToInt(&oldksa) else 0; |
| 935 | 936 | ||
| 936 | const result = switch (builtin.arch) { | 937 | const result = switch (native_arch) { |
| 937 | // The sparc version of rt_sigaction needs the restorer function to be passed as an argument too. | 938 | // The sparc version of rt_sigaction needs the restorer function to be passed as an argument too. |
| 938 | .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @ptrToInt(ksa.restorer), mask_size), | 939 | .sparc, .sparcv9 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @ptrToInt(ksa.restorer), mask_size), |
| 939 | else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size), | 940 | else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size), |
| ... | @@ -965,42 +966,42 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool { | ... | @@ -965,42 +966,42 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool { |
| 965 | } | 966 | } |
| 966 | 967 | ||
| 967 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 968 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 968 | if (builtin.arch == .i386) { | 969 | if (native_arch == .i386) { |
| 969 | return socketcall(SC_getsockname, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); | 970 | return socketcall(SC_getsockname, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); |
| 970 | } | 971 | } |
| 971 | return syscall3(.getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); | 972 | return syscall3(.getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); |
| 972 | } | 973 | } |
| 973 | 974 | ||
| 974 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 975 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 975 | if (builtin.arch == .i386) { | 976 | if (native_arch == .i386) { |
| 976 | return socketcall(SC_getpeername, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); | 977 | return socketcall(SC_getpeername, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) }); |
| 977 | } | 978 | } |
| 978 | return syscall3(.getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); | 979 | return syscall3(.getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len)); |
| 979 | } | 980 | } |
| 980 | 981 | ||
| 981 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { | 982 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { |
| 982 | if (builtin.arch == .i386) { | 983 | if (native_arch == .i386) { |
| 983 | return socketcall(SC_socket, &[3]usize{ domain, socket_type, protocol }); | 984 | return socketcall(SC_socket, &[3]usize{ domain, socket_type, protocol }); |
| 984 | } | 985 | } |
| 985 | return syscall3(.socket, domain, socket_type, protocol); | 986 | return syscall3(.socket, domain, socket_type, protocol); |
| 986 | } | 987 | } |
| 987 | 988 | ||
| 988 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { | 989 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { |
| 989 | if (builtin.arch == .i386) { | 990 | if (native_arch == .i386) { |
| 990 | return socketcall(SC_setsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen) }); | 991 | return socketcall(SC_setsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen) }); |
| 991 | } | 992 | } |
| 992 | return syscall5(.setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); | 993 | return syscall5(.setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); |
| 993 | } | 994 | } |
| 994 | 995 | ||
| 995 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { | 996 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { |
| 996 | if (builtin.arch == .i386) { | 997 | if (native_arch == .i386) { |
| 997 | return socketcall(SC_getsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen) }); | 998 | return socketcall(SC_getsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen) }); |
| 998 | } | 999 | } |
| 999 | return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | 1000 | return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); |
| 1000 | } | 1001 | } |
| 1001 | 1002 | ||
| 1002 | pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize { | 1003 | pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize { |
| 1003 | if (builtin.arch == .i386) { | 1004 | if (native_arch == .i386) { |
| 1004 | return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); | 1005 | return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); |
| 1005 | } | 1006 | } |
| 1006 | return syscall3(.sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); | 1007 | return syscall3(.sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); |
| ... | @@ -1047,49 +1048,49 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize | ... | @@ -1047,49 +1048,49 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize |
| 1047 | } | 1048 | } |
| 1048 | 1049 | ||
| 1049 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { | 1050 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { |
| 1050 | if (builtin.arch == .i386) { | 1051 | if (native_arch == .i386) { |
| 1051 | return socketcall(SC_connect, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len }); | 1052 | return socketcall(SC_connect, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len }); |
| 1052 | } | 1053 | } |
| 1053 | return syscall3(.connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len); | 1054 | return syscall3(.connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len); |
| 1054 | } | 1055 | } |
| 1055 | 1056 | ||
| 1056 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { | 1057 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { |
| 1057 | if (builtin.arch == .i386) { | 1058 | if (native_arch == .i386) { |
| 1058 | return socketcall(SC_recvmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); | 1059 | return socketcall(SC_recvmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); |
| 1059 | } | 1060 | } |
| 1060 | return syscall3(.recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); | 1061 | return syscall3(.recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags); |
| 1061 | } | 1062 | } |
| 1062 | 1063 | ||
| 1063 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { | 1064 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { |
| 1064 | if (builtin.arch == .i386) { | 1065 | if (native_arch == .i386) { |
| 1065 | return socketcall(SC_recvfrom, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen) }); | 1066 | return socketcall(SC_recvfrom, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen) }); |
| 1066 | } | 1067 | } |
| 1067 | return syscall6(.recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | 1068 | return syscall6(.recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); |
| 1068 | } | 1069 | } |
| 1069 | 1070 | ||
| 1070 | pub fn shutdown(fd: i32, how: i32) usize { | 1071 | pub fn shutdown(fd: i32, how: i32) usize { |
| 1071 | if (builtin.arch == .i386) { | 1072 | if (native_arch == .i386) { |
| 1072 | return socketcall(SC_shutdown, &[2]usize{ @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)) }); | 1073 | return socketcall(SC_shutdown, &[2]usize{ @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)) }); |
| 1073 | } | 1074 | } |
| 1074 | return syscall2(.shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how))); | 1075 | return syscall2(.shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how))); |
| 1075 | } | 1076 | } |
| 1076 | 1077 | ||
| 1077 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { | 1078 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { |
| 1078 | if (builtin.arch == .i386) { | 1079 | if (native_arch == .i386) { |
| 1079 | return socketcall(SC_bind, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len) }); | 1080 | return socketcall(SC_bind, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len) }); |
| 1080 | } | 1081 | } |
| 1081 | return syscall3(.bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len)); | 1082 | return syscall3(.bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len)); |
| 1082 | } | 1083 | } |
| 1083 | 1084 | ||
| 1084 | pub fn listen(fd: i32, backlog: u32) usize { | 1085 | pub fn listen(fd: i32, backlog: u32) usize { |
| 1085 | if (builtin.arch == .i386) { | 1086 | if (native_arch == .i386) { |
| 1086 | return socketcall(SC_listen, &[2]usize{ @bitCast(usize, @as(isize, fd)), backlog }); | 1087 | return socketcall(SC_listen, &[2]usize{ @bitCast(usize, @as(isize, fd)), backlog }); |
| 1087 | } | 1088 | } |
| 1088 | return syscall2(.listen, @bitCast(usize, @as(isize, fd)), backlog); | 1089 | return syscall2(.listen, @bitCast(usize, @as(isize, fd)), backlog); |
| 1089 | } | 1090 | } |
| 1090 | 1091 | ||
| 1091 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { | 1092 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { |
| 1092 | if (builtin.arch == .i386) { | 1093 | if (native_arch == .i386) { |
| 1093 | return socketcall(SC_sendto, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen) }); | 1094 | return socketcall(SC_sendto, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen) }); |
| 1094 | } | 1095 | } |
| 1095 | return syscall6(.sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); | 1096 | return syscall6(.sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); |
| ... | @@ -1116,21 +1117,21 @@ pub fn sendfile(outfd: i32, infd: i32, offset: ?*i64, count: usize) usize { | ... | @@ -1116,21 +1117,21 @@ pub fn sendfile(outfd: i32, infd: i32, offset: ?*i64, count: usize) usize { |
| 1116 | } | 1117 | } |
| 1117 | 1118 | ||
| 1118 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { | 1119 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { |
| 1119 | if (builtin.arch == .i386) { | 1120 | if (native_arch == .i386) { |
| 1120 | return socketcall(SC_socketpair, &[4]usize{ @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]) }); | 1121 | return socketcall(SC_socketpair, &[4]usize{ @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]) }); |
| 1121 | } | 1122 | } |
| 1122 | return syscall4(.socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); | 1123 | return syscall4(.socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); |
| 1123 | } | 1124 | } |
| 1124 | 1125 | ||
| 1125 | pub fn accept(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t) usize { | 1126 | pub fn accept(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t) usize { |
| 1126 | if (builtin.arch == .i386) { | 1127 | if (native_arch == .i386) { |
| 1127 | return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 }); | 1128 | return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 }); |
| 1128 | } | 1129 | } |
| 1129 | return accept4(fd, addr, len, 0); | 1130 | return accept4(fd, addr, len, 0); |
| 1130 | } | 1131 | } |
| 1131 | 1132 | ||
| 1132 | pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flags: u32) usize { | 1133 | pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flags: u32) usize { |
| 1133 | if (builtin.arch == .i386) { | 1134 | if (native_arch == .i386) { |
| 1134 | return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags }); | 1135 | return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags }); |
| 1135 | } | 1136 | } |
| 1136 | return syscall4(.accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags); | 1137 | return syscall4(.accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags); |
| ... | @@ -1163,8 +1164,6 @@ pub fn lstat(pathname: [*:0]const u8, statbuf: *kernel_stat) usize { | ... | @@ -1163,8 +1164,6 @@ pub fn lstat(pathname: [*:0]const u8, statbuf: *kernel_stat) usize { |
| 1163 | pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *kernel_stat, flags: u32) usize { | 1164 | pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *kernel_stat, flags: u32) usize { |
| 1164 | if (@hasField(SYS, "fstatat64")) { | 1165 | if (@hasField(SYS, "fstatat64")) { |
| 1165 | return syscall4(.fstatat64, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); | 1166 | return syscall4(.fstatat64, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); |
| 1166 | } else if (@hasField(SYS, "newfstatat")) { | ||
| 1167 | return syscall4(.newfstatat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); | ||
| 1168 | } else { | 1167 | } else { |
| 1169 | return syscall4(.fstatat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); | 1168 | return syscall4(.fstatat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); |
| 1170 | } | 1169 | } |
| ... | @@ -1456,7 +1455,7 @@ pub fn process_vm_writev(pid: pid_t, local: [*]const iovec, local_count: usize, | ... | @@ -1456,7 +1455,7 @@ pub fn process_vm_writev(pid: pid_t, local: [*]const iovec, local_count: usize, |
| 1456 | } | 1455 | } |
| 1457 | 1456 | ||
| 1458 | test { | 1457 | test { |
| 1459 | if (builtin.os.tag == .linux) { | 1458 | if (std.Target.current.os.tag == .linux) { |
| 1460 | _ = @import("linux/test.zig"); | 1459 | _ = @import("linux/test.zig"); |
| 1461 | } | 1460 | } |
| 1462 | } | 1461 | } |
lib/std/os/linux/bpf.zig+10-10| ... | @@ -398,10 +398,10 @@ pub const Insn = packed struct { | ... | @@ -398,10 +398,10 @@ pub const Insn = packed struct { |
| 398 | 398 | ||
| 399 | /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack | 399 | /// r0 - r9 are general purpose 64-bit registers, r10 points to the stack |
| 400 | /// frame | 400 | /// frame |
| 401 | pub const Reg = packed enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; | 401 | pub const Reg = enum(u4) { r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10 }; |
| 402 | const Source = packed enum(u1) { reg, imm }; | 402 | const Source = enum(u1) { reg, imm }; |
| 403 | 403 | ||
| 404 | const Mode = packed enum(u8) { | 404 | const Mode = enum(u8) { |
| 405 | imm = IMM, | 405 | imm = IMM, |
| 406 | abs = ABS, | 406 | abs = ABS, |
| 407 | ind = IND, | 407 | ind = IND, |
| ... | @@ -410,7 +410,7 @@ pub const Insn = packed struct { | ... | @@ -410,7 +410,7 @@ pub const Insn = packed struct { |
| 410 | msh = MSH, | 410 | msh = MSH, |
| 411 | }; | 411 | }; |
| 412 | 412 | ||
| 413 | const AluOp = packed enum(u8) { | 413 | const AluOp = enum(u8) { |
| 414 | add = ADD, | 414 | add = ADD, |
| 415 | sub = SUB, | 415 | sub = SUB, |
| 416 | mul = MUL, | 416 | mul = MUL, |
| ... | @@ -426,14 +426,14 @@ pub const Insn = packed struct { | ... | @@ -426,14 +426,14 @@ pub const Insn = packed struct { |
| 426 | arsh = ARSH, | 426 | arsh = ARSH, |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | pub const Size = packed enum(u8) { | 429 | pub const Size = enum(u8) { |
| 430 | byte = B, | 430 | byte = B, |
| 431 | half_word = H, | 431 | half_word = H, |
| 432 | word = W, | 432 | word = W, |
| 433 | double_word = DW, | 433 | double_word = DW, |
| 434 | }; | 434 | }; |
| 435 | 435 | ||
| 436 | const JmpOp = packed enum(u8) { | 436 | const JmpOp = enum(u8) { |
| 437 | ja = JA, | 437 | ja = JA, |
| 438 | jeq = JEQ, | 438 | jeq = JEQ, |
| 439 | jgt = JGT, | 439 | jgt = JGT, |
| ... | @@ -854,7 +854,7 @@ test "opcodes" { | ... | @@ -854,7 +854,7 @@ test "opcodes" { |
| 854 | try expect_opcode(0x95, Insn.exit()); | 854 | try expect_opcode(0x95, Insn.exit()); |
| 855 | } | 855 | } |
| 856 | 856 | ||
| 857 | pub const Cmd = extern enum(usize) { | 857 | pub const Cmd = enum(usize) { |
| 858 | /// Create a map and return a file descriptor that refers to the map. The | 858 | /// Create a map and return a file descriptor that refers to the map. The |
| 859 | /// close-on-exec file descriptor flag is automatically enabled for the new | 859 | /// close-on-exec file descriptor flag is automatically enabled for the new |
| 860 | /// file descriptor. | 860 | /// file descriptor. |
| ... | @@ -977,7 +977,7 @@ pub const Cmd = extern enum(usize) { | ... | @@ -977,7 +977,7 @@ pub const Cmd = extern enum(usize) { |
| 977 | _, | 977 | _, |
| 978 | }; | 978 | }; |
| 979 | 979 | ||
| 980 | pub const MapType = extern enum(u32) { | 980 | pub const MapType = enum(u32) { |
| 981 | unspec, | 981 | unspec, |
| 982 | hash, | 982 | hash, |
| 983 | array, | 983 | array, |
| ... | @@ -1044,7 +1044,7 @@ pub const MapType = extern enum(u32) { | ... | @@ -1044,7 +1044,7 @@ pub const MapType = extern enum(u32) { |
| 1044 | _, | 1044 | _, |
| 1045 | }; | 1045 | }; |
| 1046 | 1046 | ||
| 1047 | pub const ProgType = extern enum(u32) { | 1047 | pub const ProgType = enum(u32) { |
| 1048 | unspec, | 1048 | unspec, |
| 1049 | 1049 | ||
| 1050 | /// context type: __sk_buff | 1050 | /// context type: __sk_buff |
| ... | @@ -1139,7 +1139,7 @@ pub const ProgType = extern enum(u32) { | ... | @@ -1139,7 +1139,7 @@ pub const ProgType = extern enum(u32) { |
| 1139 | _, | 1139 | _, |
| 1140 | }; | 1140 | }; |
| 1141 | 1141 | ||
| 1142 | pub const AttachType = extern enum(u32) { | 1142 | pub const AttachType = enum(u32) { |
| 1143 | cgroup_inet_ingress, | 1143 | cgroup_inet_ingress, |
| 1144 | cgroup_inet_egress, | 1144 | cgroup_inet_egress, |
| 1145 | cgroup_inet_sock_create, | 1145 | cgroup_inet_sock_create, |
lib/std/os/linux/start_pie.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const elf = std.elf; | 2 | const elf = std.elf; |
| 3 | const builtin = @import("builtin"); | 3 | const builtin = std.builtin; |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | 5 | ||
| 6 | const R_AMD64_RELATIVE = 8; | 6 | const R_AMD64_RELATIVE = 8; |
lib/std/os/linux/test.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("../../std.zig"); | 6 | const std = @import("../../std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const linux = std.os.linux; | 8 | const linux = std.os.linux; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const elf = std.elf; | 10 | const elf = std.elf; |
lib/std/os/linux/tls.zig+8-8| ... | @@ -4,12 +4,12 @@ | ... | @@ -4,12 +4,12 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | ||
| 8 | const os = std.os; | 7 | const os = std.os; |
| 9 | const mem = std.mem; | 8 | const mem = std.mem; |
| 10 | const elf = std.elf; | 9 | const elf = std.elf; |
| 11 | const math = std.math; | 10 | const math = std.math; |
| 12 | const assert = std.debug.assert; | 11 | const assert = std.debug.assert; |
| 12 | const native_arch = std.Target.current.cpu.arch; | ||
| 13 | 13 | ||
| 14 | // This file implements the two TLS variants [1] used by ELF-based systems. | 14 | // This file implements the two TLS variants [1] used by ELF-based systems. |
| 15 | // | 15 | // |
| ... | @@ -52,14 +52,14 @@ const TLSVariant = enum { | ... | @@ -52,14 +52,14 @@ const TLSVariant = enum { |
| 52 | VariantII, | 52 | VariantII, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | const tls_variant = switch (builtin.arch) { | 55 | const tls_variant = switch (native_arch) { |
| 56 | .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, | 56 | .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, |
| 57 | .x86_64, .i386, .sparcv9 => TLSVariant.VariantII, | 57 | .x86_64, .i386, .sparcv9 => TLSVariant.VariantII, |
| 58 | else => @compileError("undefined tls_variant for this architecture"), | 58 | else => @compileError("undefined tls_variant for this architecture"), |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | // Controls how many bytes are reserved for the Thread Control Block | 61 | // Controls how many bytes are reserved for the Thread Control Block |
| 62 | const tls_tcb_size = switch (builtin.arch) { | 62 | const tls_tcb_size = switch (native_arch) { |
| 63 | // ARM EABI mandates enough space for two pointers: the first one points to | 63 | // ARM EABI mandates enough space for two pointers: the first one points to |
| 64 | // the DTV while the second one is unspecified but reserved | 64 | // the DTV while the second one is unspecified but reserved |
| 65 | .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), | 65 | .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), |
| ... | @@ -68,7 +68,7 @@ const tls_tcb_size = switch (builtin.arch) { | ... | @@ -68,7 +68,7 @@ const tls_tcb_size = switch (builtin.arch) { |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | // Controls if the TP points to the end of the TCB instead of its beginning | 70 | // Controls if the TP points to the end of the TCB instead of its beginning |
| 71 | const tls_tp_points_past_tcb = switch (builtin.arch) { | 71 | const tls_tp_points_past_tcb = switch (native_arch) { |
| 72 | .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => true, | 72 | .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => true, |
| 73 | else => false, | 73 | else => false, |
| 74 | }; | 74 | }; |
| ... | @@ -76,12 +76,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) { | ... | @@ -76,12 +76,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) { |
| 76 | // Some architectures add some offset to the tp and dtv addresses in order to | 76 | // Some architectures add some offset to the tp and dtv addresses in order to |
| 77 | // make the generated code more efficient | 77 | // make the generated code more efficient |
| 78 | 78 | ||
| 79 | const tls_tp_offset = switch (builtin.arch) { | 79 | const tls_tp_offset = switch (native_arch) { |
| 80 | .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x7000, | 80 | .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x7000, |
| 81 | else => 0, | 81 | else => 0, |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | const tls_dtv_offset = switch (builtin.arch) { | 84 | const tls_dtv_offset = switch (native_arch) { |
| 85 | .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x8000, | 85 | .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x8000, |
| 86 | .riscv32, .riscv64 => 0x800, | 86 | .riscv32, .riscv64 => 0x800, |
| 87 | else => 0, | 87 | else => 0, |
| ... | @@ -114,7 +114,7 @@ const TLSImage = struct { | ... | @@ -114,7 +114,7 @@ const TLSImage = struct { |
| 114 | pub var tls_image: TLSImage = undefined; | 114 | pub var tls_image: TLSImage = undefined; |
| 115 | 115 | ||
| 116 | pub fn setThreadPointer(addr: usize) void { | 116 | pub fn setThreadPointer(addr: usize) void { |
| 117 | switch (builtin.arch) { | 117 | switch (native_arch) { |
| 118 | .i386 => { | 118 | .i386 => { |
| 119 | var user_desc = std.os.linux.user_desc{ | 119 | var user_desc = std.os.linux.user_desc{ |
| 120 | .entry_number = tls_image.gdt_entry_number, | 120 | .entry_number = tls_image.gdt_entry_number, |
| ... | @@ -228,7 +228,7 @@ fn initTLS() void { | ... | @@ -228,7 +228,7 @@ fn initTLS() void { |
| 228 | // ARMv6 targets (and earlier) have no support for TLS in hardware | 228 | // ARMv6 targets (and earlier) have no support for TLS in hardware |
| 229 | // FIXME: Elide the check for targets >= ARMv7 when the target feature API | 229 | // FIXME: Elide the check for targets >= ARMv7 when the target feature API |
| 230 | // becomes less verbose (and more usable). | 230 | // becomes less verbose (and more usable). |
| 231 | if (comptime builtin.arch.isARM()) { | 231 | if (comptime native_arch.isARM()) { |
| 232 | if (at_hwcap & std.os.linux.HWCAP_TLS == 0) { | 232 | if (at_hwcap & std.os.linux.HWCAP_TLS == 0) { |
| 233 | // FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls | 233 | // FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls |
| 234 | // For the time being use a simple abort instead of a @panic call to | 234 | // For the time being use a simple abort instead of a @panic call to |
lib/std/os/test.zig+35-34| ... | @@ -19,14 +19,15 @@ const Thread = std.Thread; | ... | @@ -19,14 +19,15 @@ const Thread = std.Thread; |
| 19 | const a = std.testing.allocator; | 19 | const a = std.testing.allocator; |
| 20 | 20 | ||
| 21 | const builtin = @import("builtin"); | 21 | const builtin = @import("builtin"); |
| 22 | const AtomicRmwOp = builtin.AtomicRmwOp; | 22 | const AtomicRmwOp = std.builtin.AtomicRmwOp; |
| 23 | const AtomicOrder = builtin.AtomicOrder; | 23 | const AtomicOrder = std.builtin.AtomicOrder; |
| 24 | const native_os = builtin.target.os.tag; | ||
| 24 | const tmpDir = std.testing.tmpDir; | 25 | const tmpDir = std.testing.tmpDir; |
| 25 | const Dir = std.fs.Dir; | 26 | const Dir = std.fs.Dir; |
| 26 | const ArenaAllocator = std.heap.ArenaAllocator; | 27 | const ArenaAllocator = std.heap.ArenaAllocator; |
| 27 | 28 | ||
| 28 | test "chdir smoke test" { | 29 | test "chdir smoke test" { |
| 29 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 30 | if (native_os == .wasi) return error.SkipZigTest; |
| 30 | 31 | ||
| 31 | // Get current working directory path | 32 | // Get current working directory path |
| 32 | var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; | 33 | var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; |
| ... | @@ -52,7 +53,7 @@ test "chdir smoke test" { | ... | @@ -52,7 +53,7 @@ test "chdir smoke test" { |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | test "open smoke test" { | 55 | test "open smoke test" { |
| 55 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 56 | if (native_os == .wasi) return error.SkipZigTest; |
| 56 | 57 | ||
| 57 | // TODO verify file attributes using `fstat` | 58 | // TODO verify file attributes using `fstat` |
| 58 | 59 | ||
| ... | @@ -70,7 +71,7 @@ test "open smoke test" { | ... | @@ -70,7 +71,7 @@ test "open smoke test" { |
| 70 | 71 | ||
| 71 | var file_path: []u8 = undefined; | 72 | var file_path: []u8 = undefined; |
| 72 | var fd: os.fd_t = undefined; | 73 | var fd: os.fd_t = undefined; |
| 73 | const mode: os.mode_t = if (builtin.os.tag == .windows) 0 else 0o666; | 74 | const mode: os.mode_t = if (native_os == .windows) 0 else 0o666; |
| 74 | 75 | ||
| 75 | // Create some file using `open`. | 76 | // Create some file using `open`. |
| 76 | file_path = try fs.path.join(&arena.allocator, &[_][]const u8{ base_path, "some_file" }); | 77 | file_path = try fs.path.join(&arena.allocator, &[_][]const u8{ base_path, "some_file" }); |
| ... | @@ -105,7 +106,7 @@ test "open smoke test" { | ... | @@ -105,7 +106,7 @@ test "open smoke test" { |
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | test "openat smoke test" { | 108 | test "openat smoke test" { |
| 108 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 109 | if (native_os == .wasi) return error.SkipZigTest; |
| 109 | 110 | ||
| 110 | // TODO verify file attributes using `fstatat` | 111 | // TODO verify file attributes using `fstatat` |
| 111 | 112 | ||
| ... | @@ -113,7 +114,7 @@ test "openat smoke test" { | ... | @@ -113,7 +114,7 @@ test "openat smoke test" { |
| 113 | defer tmp.cleanup(); | 114 | defer tmp.cleanup(); |
| 114 | 115 | ||
| 115 | var fd: os.fd_t = undefined; | 116 | var fd: os.fd_t = undefined; |
| 116 | const mode: os.mode_t = if (builtin.os.tag == .windows) 0 else 0o666; | 117 | const mode: os.mode_t = if (native_os == .windows) 0 else 0o666; |
| 117 | 118 | ||
| 118 | // Create some file using `openat`. | 119 | // Create some file using `openat`. |
| 119 | fd = try os.openat(tmp.dir.fd, "some_file", os.O_RDWR | os.O_CREAT | os.O_EXCL, mode); | 120 | fd = try os.openat(tmp.dir.fd, "some_file", os.O_RDWR | os.O_CREAT | os.O_EXCL, mode); |
| ... | @@ -141,7 +142,7 @@ test "openat smoke test" { | ... | @@ -141,7 +142,7 @@ test "openat smoke test" { |
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | test "symlink with relative paths" { | 144 | test "symlink with relative paths" { |
| 144 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 145 | if (native_os == .wasi) return error.SkipZigTest; |
| 145 | 146 | ||
| 146 | const cwd = fs.cwd(); | 147 | const cwd = fs.cwd(); |
| 147 | cwd.deleteFile("file.txt") catch {}; | 148 | cwd.deleteFile("file.txt") catch {}; |
| ... | @@ -150,7 +151,7 @@ test "symlink with relative paths" { | ... | @@ -150,7 +151,7 @@ test "symlink with relative paths" { |
| 150 | // First, try relative paths in cwd | 151 | // First, try relative paths in cwd |
| 151 | try cwd.writeFile("file.txt", "nonsense"); | 152 | try cwd.writeFile("file.txt", "nonsense"); |
| 152 | 153 | ||
| 153 | if (builtin.os.tag == .windows) { | 154 | if (native_os == .windows) { |
| 154 | os.windows.CreateSymbolicLink( | 155 | os.windows.CreateSymbolicLink( |
| 155 | cwd.fd, | 156 | cwd.fd, |
| 156 | &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' }, | 157 | &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' }, |
| ... | @@ -178,7 +179,7 @@ test "symlink with relative paths" { | ... | @@ -178,7 +179,7 @@ test "symlink with relative paths" { |
| 178 | } | 179 | } |
| 179 | 180 | ||
| 180 | test "readlink on Windows" { | 181 | test "readlink on Windows" { |
| 181 | if (builtin.os.tag != .windows) return error.SkipZigTest; | 182 | if (native_os != .windows) return error.SkipZigTest; |
| 182 | 183 | ||
| 183 | try testReadlink("C:\\ProgramData", "C:\\Users\\All Users"); | 184 | try testReadlink("C:\\ProgramData", "C:\\Users\\All Users"); |
| 184 | try testReadlink("C:\\Users\\Default", "C:\\Users\\Default User"); | 185 | try testReadlink("C:\\Users\\Default", "C:\\Users\\Default User"); |
| ... | @@ -192,7 +193,7 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { | ... | @@ -192,7 +193,7 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { |
| 192 | } | 193 | } |
| 193 | 194 | ||
| 194 | test "link with relative paths" { | 195 | test "link with relative paths" { |
| 195 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 196 | if (native_os != .linux) return error.SkipZigTest; |
| 196 | var cwd = fs.cwd(); | 197 | var cwd = fs.cwd(); |
| 197 | 198 | ||
| 198 | cwd.deleteFile("example.txt") catch {}; | 199 | cwd.deleteFile("example.txt") catch {}; |
| ... | @@ -226,7 +227,7 @@ test "link with relative paths" { | ... | @@ -226,7 +227,7 @@ test "link with relative paths" { |
| 226 | } | 227 | } |
| 227 | 228 | ||
| 228 | test "linkat with different directories" { | 229 | test "linkat with different directories" { |
| 229 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 230 | if (native_os != .linux) return error.SkipZigTest; |
| 230 | var cwd = fs.cwd(); | 231 | var cwd = fs.cwd(); |
| 231 | var tmp = tmpDir(.{}); | 232 | var tmp = tmpDir(.{}); |
| 232 | 233 | ||
| ... | @@ -262,7 +263,7 @@ test "linkat with different directories" { | ... | @@ -262,7 +263,7 @@ test "linkat with different directories" { |
| 262 | 263 | ||
| 263 | test "fstatat" { | 264 | test "fstatat" { |
| 264 | // enable when `fstat` and `fstatat` are implemented on Windows | 265 | // enable when `fstat` and `fstatat` are implemented on Windows |
| 265 | if (builtin.os.tag == .windows) return error.SkipZigTest; | 266 | if (native_os == .windows) return error.SkipZigTest; |
| 266 | 267 | ||
| 267 | var tmp = tmpDir(.{}); | 268 | var tmp = tmpDir(.{}); |
| 268 | defer tmp.cleanup(); | 269 | defer tmp.cleanup(); |
| ... | @@ -277,7 +278,7 @@ test "fstatat" { | ... | @@ -277,7 +278,7 @@ test "fstatat" { |
| 277 | defer file.close(); | 278 | defer file.close(); |
| 278 | 279 | ||
| 279 | // now repeat but using `fstatat` instead | 280 | // now repeat but using `fstatat` instead |
| 280 | const flags = if (builtin.os.tag == .wasi) 0x0 else os.AT_SYMLINK_NOFOLLOW; | 281 | const flags = if (native_os == .wasi) 0x0 else os.AT_SYMLINK_NOFOLLOW; |
| 281 | const statat = try os.fstatat(tmp.dir.fd, "file.txt", flags); | 282 | const statat = try os.fstatat(tmp.dir.fd, "file.txt", flags); |
| 282 | try expectEqual(stat, statat); | 283 | try expectEqual(stat, statat); |
| 283 | } | 284 | } |
| ... | @@ -290,7 +291,7 @@ test "readlinkat" { | ... | @@ -290,7 +291,7 @@ test "readlinkat" { |
| 290 | try tmp.dir.writeFile("file.txt", "nonsense"); | 291 | try tmp.dir.writeFile("file.txt", "nonsense"); |
| 291 | 292 | ||
| 292 | // create a symbolic link | 293 | // create a symbolic link |
| 293 | if (builtin.os.tag == .windows) { | 294 | if (native_os == .windows) { |
| 294 | os.windows.CreateSymbolicLink( | 295 | os.windows.CreateSymbolicLink( |
| 295 | tmp.dir.fd, | 296 | tmp.dir.fd, |
| 296 | &[_]u16{ 'l', 'i', 'n', 'k' }, | 297 | &[_]u16{ 'l', 'i', 'n', 'k' }, |
| ... | @@ -324,7 +325,7 @@ test "std.Thread.getCurrentId" { | ... | @@ -324,7 +325,7 @@ test "std.Thread.getCurrentId" { |
| 324 | thread.wait(); | 325 | thread.wait(); |
| 325 | if (Thread.use_pthreads) { | 326 | if (Thread.use_pthreads) { |
| 326 | try expect(thread_current_id == thread_id); | 327 | try expect(thread_current_id == thread_id); |
| 327 | } else if (builtin.os.tag == .windows) { | 328 | } else if (native_os == .windows) { |
| 328 | try expect(Thread.getCurrentId() != thread_current_id); | 329 | try expect(Thread.getCurrentId() != thread_current_id); |
| 329 | } else { | 330 | } else { |
| 330 | // If the thread completes very quickly, then thread_id can be 0. See the | 331 | // If the thread completes very quickly, then thread_id can be 0. See the |
| ... | @@ -361,7 +362,7 @@ fn start2(ctx: *i32) u8 { | ... | @@ -361,7 +362,7 @@ fn start2(ctx: *i32) u8 { |
| 361 | } | 362 | } |
| 362 | 363 | ||
| 363 | test "cpu count" { | 364 | test "cpu count" { |
| 364 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 365 | if (native_os == .wasi) return error.SkipZigTest; |
| 365 | 366 | ||
| 366 | const cpu_count = try Thread.cpuCount(); | 367 | const cpu_count = try Thread.cpuCount(); |
| 367 | try expect(cpu_count >= 1); | 368 | try expect(cpu_count >= 1); |
| ... | @@ -394,7 +395,7 @@ test "getrandom" { | ... | @@ -394,7 +395,7 @@ test "getrandom" { |
| 394 | } | 395 | } |
| 395 | 396 | ||
| 396 | test "getcwd" { | 397 | test "getcwd" { |
| 397 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | 398 | if (native_os == .wasi) return error.SkipZigTest; |
| 398 | 399 | ||
| 399 | // at least call it so it gets compiled | 400 | // at least call it so it gets compiled |
| 400 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 401 | var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| ... | @@ -402,7 +403,7 @@ test "getcwd" { | ... | @@ -402,7 +403,7 @@ test "getcwd" { |
| 402 | } | 403 | } |
| 403 | 404 | ||
| 404 | test "sigaltstack" { | 405 | test "sigaltstack" { |
| 405 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) return error.SkipZigTest; | 406 | if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; |
| 406 | 407 | ||
| 407 | var st: os.stack_t = undefined; | 408 | var st: os.stack_t = undefined; |
| 408 | try os.sigaltstack(null, &st); | 409 | try os.sigaltstack(null, &st); |
| ... | @@ -455,7 +456,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { | ... | @@ -455,7 +456,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { |
| 455 | } | 456 | } |
| 456 | 457 | ||
| 457 | test "dl_iterate_phdr" { | 458 | test "dl_iterate_phdr" { |
| 458 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) | 459 | if (native_os == .windows or native_os == .wasi or native_os == .macos) |
| 459 | return error.SkipZigTest; | 460 | return error.SkipZigTest; |
| 460 | 461 | ||
| 461 | var counter: usize = 0; | 462 | var counter: usize = 0; |
| ... | @@ -464,7 +465,7 @@ test "dl_iterate_phdr" { | ... | @@ -464,7 +465,7 @@ test "dl_iterate_phdr" { |
| 464 | } | 465 | } |
| 465 | 466 | ||
| 466 | test "gethostname" { | 467 | test "gethostname" { |
| 467 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | 468 | if (native_os == .windows or native_os == .wasi) |
| 468 | return error.SkipZigTest; | 469 | return error.SkipZigTest; |
| 469 | 470 | ||
| 470 | var buf: [os.HOST_NAME_MAX]u8 = undefined; | 471 | var buf: [os.HOST_NAME_MAX]u8 = undefined; |
| ... | @@ -473,7 +474,7 @@ test "gethostname" { | ... | @@ -473,7 +474,7 @@ test "gethostname" { |
| 473 | } | 474 | } |
| 474 | 475 | ||
| 475 | test "pipe" { | 476 | test "pipe" { |
| 476 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | 477 | if (native_os == .windows or native_os == .wasi) |
| 477 | return error.SkipZigTest; | 478 | return error.SkipZigTest; |
| 478 | 479 | ||
| 479 | var fds = try os.pipe(); | 480 | var fds = try os.pipe(); |
| ... | @@ -492,7 +493,7 @@ test "argsAlloc" { | ... | @@ -492,7 +493,7 @@ test "argsAlloc" { |
| 492 | 493 | ||
| 493 | test "memfd_create" { | 494 | test "memfd_create" { |
| 494 | // memfd_create is linux specific. | 495 | // memfd_create is linux specific. |
| 495 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 496 | if (native_os != .linux) return error.SkipZigTest; |
| 496 | const fd = std.os.memfd_create("test", 0) catch |err| switch (err) { | 497 | const fd = std.os.memfd_create("test", 0) catch |err| switch (err) { |
| 497 | // Related: https://github.com/ziglang/zig/issues/4019 | 498 | // Related: https://github.com/ziglang/zig/issues/4019 |
| 498 | error.SystemOutdated => return error.SkipZigTest, | 499 | error.SystemOutdated => return error.SkipZigTest, |
| ... | @@ -509,7 +510,7 @@ test "memfd_create" { | ... | @@ -509,7 +510,7 @@ test "memfd_create" { |
| 509 | } | 510 | } |
| 510 | 511 | ||
| 511 | test "mmap" { | 512 | test "mmap" { |
| 512 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | 513 | if (native_os == .windows or native_os == .wasi) |
| 513 | return error.SkipZigTest; | 514 | return error.SkipZigTest; |
| 514 | 515 | ||
| 515 | var tmp = tmpDir(.{}); | 516 | var tmp = tmpDir(.{}); |
| ... | @@ -606,7 +607,7 @@ test "mmap" { | ... | @@ -606,7 +607,7 @@ test "mmap" { |
| 606 | } | 607 | } |
| 607 | 608 | ||
| 608 | test "getenv" { | 609 | test "getenv" { |
| 609 | if (builtin.os.tag == .windows) { | 610 | if (native_os == .windows) { |
| 610 | try expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null); | 611 | try expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null); |
| 611 | } else { | 612 | } else { |
| 612 | try expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); | 613 | try expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); |
| ... | @@ -614,7 +615,7 @@ test "getenv" { | ... | @@ -614,7 +615,7 @@ test "getenv" { |
| 614 | } | 615 | } |
| 615 | 616 | ||
| 616 | test "fcntl" { | 617 | test "fcntl" { |
| 617 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | 618 | if (native_os == .windows or native_os == .wasi) |
| 618 | return error.SkipZigTest; | 619 | return error.SkipZigTest; |
| 619 | 620 | ||
| 620 | var tmp = tmpDir(.{}); | 621 | var tmp = tmpDir(.{}); |
| ... | @@ -646,13 +647,13 @@ test "fcntl" { | ... | @@ -646,13 +647,13 @@ test "fcntl" { |
| 646 | } | 647 | } |
| 647 | 648 | ||
| 648 | test "signalfd" { | 649 | test "signalfd" { |
| 649 | if (builtin.os.tag != .linux) | 650 | if (native_os != .linux) |
| 650 | return error.SkipZigTest; | 651 | return error.SkipZigTest; |
| 651 | _ = std.os.signalfd; | 652 | _ = std.os.signalfd; |
| 652 | } | 653 | } |
| 653 | 654 | ||
| 654 | test "sync" { | 655 | test "sync" { |
| 655 | if (builtin.os.tag != .linux) | 656 | if (native_os != .linux) |
| 656 | return error.SkipZigTest; | 657 | return error.SkipZigTest; |
| 657 | 658 | ||
| 658 | var tmp = tmpDir(.{}); | 659 | var tmp = tmpDir(.{}); |
| ... | @@ -670,7 +671,7 @@ test "sync" { | ... | @@ -670,7 +671,7 @@ test "sync" { |
| 670 | } | 671 | } |
| 671 | 672 | ||
| 672 | test "fsync" { | 673 | test "fsync" { |
| 673 | if (builtin.os.tag != .linux and builtin.os.tag != .windows) | 674 | if (native_os != .linux and native_os != .windows) |
| 674 | return error.SkipZigTest; | 675 | return error.SkipZigTest; |
| 675 | 676 | ||
| 676 | var tmp = tmpDir(.{}); | 677 | var tmp = tmpDir(.{}); |
| ... | @@ -700,13 +701,13 @@ test "getrlimit and setrlimit" { | ... | @@ -700,13 +701,13 @@ test "getrlimit and setrlimit" { |
| 700 | } | 701 | } |
| 701 | 702 | ||
| 702 | test "shutdown socket" { | 703 | test "shutdown socket" { |
| 703 | if (builtin.os.tag == .wasi) | 704 | if (native_os == .wasi) |
| 704 | return error.SkipZigTest; | 705 | return error.SkipZigTest; |
| 705 | if (builtin.os.tag == .windows) { | 706 | if (native_os == .windows) { |
| 706 | _ = try std.os.windows.WSAStartup(2, 2); | 707 | _ = try std.os.windows.WSAStartup(2, 2); |
| 707 | } | 708 | } |
| 708 | defer { | 709 | defer { |
| 709 | if (builtin.os.tag == .windows) { | 710 | if (native_os == .windows) { |
| 710 | std.os.windows.WSACleanup() catch unreachable; | 711 | std.os.windows.WSACleanup() catch unreachable; |
| 711 | } | 712 | } |
| 712 | } | 713 | } |
| ... | @@ -721,11 +722,11 @@ test "shutdown socket" { | ... | @@ -721,11 +722,11 @@ test "shutdown socket" { |
| 721 | var signal_test_failed = true; | 722 | var signal_test_failed = true; |
| 722 | 723 | ||
| 723 | test "sigaction" { | 724 | test "sigaction" { |
| 724 | if (builtin.os.tag == .wasi or builtin.os.tag == .windows) | 725 | if (native_os == .wasi or native_os == .windows) |
| 725 | return error.SkipZigTest; | 726 | return error.SkipZigTest; |
| 726 | 727 | ||
| 727 | // https://github.com/ziglang/zig/issues/7427 | 728 | // https://github.com/ziglang/zig/issues/7427 |
| 728 | if (builtin.os.tag == .linux and builtin.arch == .i386) | 729 | if (native_os == .linux and builtin.target.cpu.arch == .i386) |
| 729 | return error.SkipZigTest; | 730 | return error.SkipZigTest; |
| 730 | 731 | ||
| 731 | const S = struct { | 732 | const S = struct { |
lib/std/os/uefi/protocols/device_path_protocol.zig+7-7| ... | @@ -90,7 +90,7 @@ pub const DevicePath = union(DevicePathType) { | ... | @@ -90,7 +90,7 @@ pub const DevicePath = union(DevicePathType) { |
| 90 | End: EndDevicePath, | 90 | End: EndDevicePath, |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | pub const DevicePathType = extern enum(u8) { | 93 | pub const DevicePathType = enum(u8) { |
| 94 | Hardware = 0x01, | 94 | Hardware = 0x01, |
| 95 | Acpi = 0x02, | 95 | Acpi = 0x02, |
| 96 | Messaging = 0x03, | 96 | Messaging = 0x03, |
| ... | @@ -108,7 +108,7 @@ pub const HardwareDevicePath = union(Subtype) { | ... | @@ -108,7 +108,7 @@ pub const HardwareDevicePath = union(Subtype) { |
| 108 | Controller: *const ControllerDevicePath, | 108 | Controller: *const ControllerDevicePath, |
| 109 | Bmc: *const BmcDevicePath, | 109 | Bmc: *const BmcDevicePath, |
| 110 | 110 | ||
| 111 | pub const Subtype = extern enum(u8) { | 111 | pub const Subtype = enum(u8) { |
| 112 | Pci = 1, | 112 | Pci = 1, |
| 113 | PcCard = 2, | 113 | PcCard = 2, |
| 114 | MemoryMapped = 3, | 114 | MemoryMapped = 3, |
| ... | @@ -167,7 +167,7 @@ pub const AcpiDevicePath = union(Subtype) { | ... | @@ -167,7 +167,7 @@ pub const AcpiDevicePath = union(Subtype) { |
| 167 | Adr: void, // TODO | 167 | Adr: void, // TODO |
| 168 | Nvdimm: void, // TODO | 168 | Nvdimm: void, // TODO |
| 169 | 169 | ||
| 170 | pub const Subtype = extern enum(u8) { | 170 | pub const Subtype = enum(u8) { |
| 171 | Acpi = 1, | 171 | Acpi = 1, |
| 172 | ExpandedAcpi = 2, | 172 | ExpandedAcpi = 2, |
| 173 | Adr = 3, | 173 | Adr = 3, |
| ... | @@ -196,7 +196,7 @@ pub const MessagingDevicePath = union(Subtype) { | ... | @@ -196,7 +196,7 @@ pub const MessagingDevicePath = union(Subtype) { |
| 196 | Uart: void, // TODO | 196 | Uart: void, // TODO |
| 197 | Vendor: void, // TODO | 197 | Vendor: void, // TODO |
| 198 | 198 | ||
| 199 | pub const Subtype = extern enum(u8) { | 199 | pub const Subtype = enum(u8) { |
| 200 | Atapi = 1, | 200 | Atapi = 1, |
| 201 | Scsi = 2, | 201 | Scsi = 2, |
| 202 | FibreChannel = 3, | 202 | FibreChannel = 3, |
| ... | @@ -230,7 +230,7 @@ pub const MediaDevicePath = union(Subtype) { | ... | @@ -230,7 +230,7 @@ pub const MediaDevicePath = union(Subtype) { |
| 230 | RelativeOffsetRange: *const RelativeOffsetRangeDevicePath, | 230 | RelativeOffsetRange: *const RelativeOffsetRangeDevicePath, |
| 231 | RamDisk: *const RamDiskDevicePath, | 231 | RamDisk: *const RamDiskDevicePath, |
| 232 | 232 | ||
| 233 | pub const Subtype = extern enum(u8) { | 233 | pub const Subtype = enum(u8) { |
| 234 | HardDrive = 1, | 234 | HardDrive = 1, |
| 235 | Cdrom = 2, | 235 | Cdrom = 2, |
| 236 | Vendor = 3, | 236 | Vendor = 3, |
| ... | @@ -316,7 +316,7 @@ pub const MediaDevicePath = union(Subtype) { | ... | @@ -316,7 +316,7 @@ pub const MediaDevicePath = union(Subtype) { |
| 316 | pub const BiosBootSpecificationDevicePath = union(Subtype) { | 316 | pub const BiosBootSpecificationDevicePath = union(Subtype) { |
| 317 | BBS101: *const BBS101DevicePath, | 317 | BBS101: *const BBS101DevicePath, |
| 318 | 318 | ||
| 319 | pub const Subtype = extern enum(u8) { | 319 | pub const Subtype = enum(u8) { |
| 320 | BBS101 = 1, | 320 | BBS101 = 1, |
| 321 | _, | 321 | _, |
| 322 | }; | 322 | }; |
| ... | @@ -338,7 +338,7 @@ pub const EndDevicePath = union(Subtype) { | ... | @@ -338,7 +338,7 @@ pub const EndDevicePath = union(Subtype) { |
| 338 | EndEntire: *const EndEntireDevicePath, | 338 | EndEntire: *const EndEntireDevicePath, |
| 339 | EndThisInstance: *const EndThisInstanceDevicePath, | 339 | EndThisInstance: *const EndThisInstanceDevicePath, |
| 340 | 340 | ||
| 341 | pub const Subtype = extern enum(u8) { | 341 | pub const Subtype = enum(u8) { |
| 342 | EndEntire = 0xff, | 342 | EndEntire = 0xff, |
| 343 | EndThisInstance = 0x01, | 343 | EndThisInstance = 0x01, |
| 344 | _, | 344 | _, |
lib/std/os/uefi/protocols/graphics_output_protocol.zig+2-2| ... | @@ -57,7 +57,7 @@ pub const GraphicsOutputModeInformation = extern struct { | ... | @@ -57,7 +57,7 @@ pub const GraphicsOutputModeInformation = extern struct { |
| 57 | pixels_per_scan_line: u32 = undefined, | 57 | pixels_per_scan_line: u32 = undefined, |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | pub const GraphicsPixelFormat = extern enum(u32) { | 60 | pub const GraphicsPixelFormat = enum(u32) { |
| 61 | PixelRedGreenBlueReserved8BitPerColor, | 61 | PixelRedGreenBlueReserved8BitPerColor, |
| 62 | PixelBlueGreenRedReserved8BitPerColor, | 62 | PixelBlueGreenRedReserved8BitPerColor, |
| 63 | PixelBitMask, | 63 | PixelBitMask, |
| ... | @@ -79,7 +79,7 @@ pub const GraphicsOutputBltPixel = extern struct { | ... | @@ -79,7 +79,7 @@ pub const GraphicsOutputBltPixel = extern struct { |
| 79 | reserved: u8 = undefined, | 79 | reserved: u8 = undefined, |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | pub const GraphicsOutputBltOperation = extern enum(u32) { | 82 | pub const GraphicsOutputBltOperation = enum(u32) { |
| 83 | BltVideoFill, | 83 | BltVideoFill, |
| 84 | BltVideoToBltBuffer, | 84 | BltVideoToBltBuffer, |
| 85 | BltBufferToVideo, | 85 | BltBufferToVideo, |
lib/std/os/uefi/protocols/hii_popup_protocol.zig+3-3| ... | @@ -28,20 +28,20 @@ pub const HIIPopupProtocol = extern struct { | ... | @@ -28,20 +28,20 @@ pub const HIIPopupProtocol = extern struct { |
| 28 | }; | 28 | }; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | pub const HIIPopupStyle = extern enum(u32) { | 31 | pub const HIIPopupStyle = enum(u32) { |
| 32 | Info, | 32 | Info, |
| 33 | Warning, | 33 | Warning, |
| 34 | Error, | 34 | Error, |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | pub const HIIPopupType = extern enum(u32) { | 37 | pub const HIIPopupType = enum(u32) { |
| 38 | Ok, | 38 | Ok, |
| 39 | Cancel, | 39 | Cancel, |
| 40 | YesNo, | 40 | YesNo, |
| 41 | YesNoCancel, | 41 | YesNoCancel, |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | pub const HIIPopupSelection = extern enum(u32) { | 44 | pub const HIIPopupSelection = enum(u32) { |
| 45 | Ok, | 45 | Ok, |
| 46 | Cancel, | 46 | Cancel, |
| 47 | Yes, | 47 | Yes, |
lib/std/os/uefi/protocols/ip6_config_protocol.zig+1-1| ... | @@ -40,7 +40,7 @@ pub const Ip6ConfigProtocol = extern struct { | ... | @@ -40,7 +40,7 @@ pub const Ip6ConfigProtocol = extern struct { |
| 40 | }; | 40 | }; |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | pub const Ip6ConfigDataType = extern enum(u32) { | 43 | pub const Ip6ConfigDataType = enum(u32) { |
| 44 | InterfaceInfo, | 44 | InterfaceInfo, |
| 45 | AltInterfaceId, | 45 | AltInterfaceId, |
| 46 | Policy, | 46 | Policy, |
lib/std/os/uefi/protocols/ip6_protocol.zig+1-1| ... | @@ -123,7 +123,7 @@ pub const Ip6RouteTable = extern struct { | ... | @@ -123,7 +123,7 @@ pub const Ip6RouteTable = extern struct { |
| 123 | prefix_length: u8, | 123 | prefix_length: u8, |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | pub const Ip6NeighborState = extern enum(u32) { | 126 | pub const Ip6NeighborState = enum(u32) { |
| 127 | Incomplete, | 127 | Incomplete, |
| 128 | Reachable, | 128 | Reachable, |
| 129 | Stale, | 129 | Stale, |
lib/std/os/uefi/protocols/simple_network_protocol.zig+1-1| ... | @@ -134,7 +134,7 @@ pub const SimpleNetworkReceiveFilter = packed struct { | ... | @@ -134,7 +134,7 @@ pub const SimpleNetworkReceiveFilter = packed struct { |
| 134 | _pad: u27 = undefined, | 134 | _pad: u27 = undefined, |
| 135 | }; | 135 | }; |
| 136 | 136 | ||
| 137 | pub const SimpleNetworkState = extern enum(u32) { | 137 | pub const SimpleNetworkState = enum(u32) { |
| 138 | Stopped, | 138 | Stopped, |
| 139 | Started, | 139 | Started, |
| 140 | Initialized, | 140 | Initialized, |
lib/std/os/uefi/status.zig+1-1| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const high_bit = 1 << @typeInfo(usize).Int.bits - 1; | 6 | const high_bit = 1 << @typeInfo(usize).Int.bits - 1; |
| 7 | 7 | ||
| 8 | pub const Status = extern enum(usize) { | 8 | pub const Status = enum(usize) { |
| 9 | /// The operation completed successfully. | 9 | /// The operation completed successfully. |
| 10 | Success = 0, | 10 | Success = 0, |
| 11 | 11 |
lib/std/os/uefi/tables/boot_services.zig+4-4| ... | @@ -156,13 +156,13 @@ pub const BootServices = extern struct { | ... | @@ -156,13 +156,13 @@ pub const BootServices = extern struct { |
| 156 | pub const tpl_high_level: usize = 31; | 156 | pub const tpl_high_level: usize = 31; |
| 157 | }; | 157 | }; |
| 158 | 158 | ||
| 159 | pub const TimerDelay = extern enum(u32) { | 159 | pub const TimerDelay = enum(u32) { |
| 160 | TimerCancel, | 160 | TimerCancel, |
| 161 | TimerPeriodic, | 161 | TimerPeriodic, |
| 162 | TimerRelative, | 162 | TimerRelative, |
| 163 | }; | 163 | }; |
| 164 | 164 | ||
| 165 | pub const MemoryType = extern enum(u32) { | 165 | pub const MemoryType = enum(u32) { |
| 166 | ReservedMemoryType, | 166 | ReservedMemoryType, |
| 167 | LoaderCode, | 167 | LoaderCode, |
| 168 | LoaderData, | 168 | LoaderData, |
| ... | @@ -206,7 +206,7 @@ pub const MemoryDescriptor = extern struct { | ... | @@ -206,7 +206,7 @@ pub const MemoryDescriptor = extern struct { |
| 206 | }, | 206 | }, |
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | pub const LocateSearchType = extern enum(u32) { | 209 | pub const LocateSearchType = enum(u32) { |
| 210 | AllHandles, | 210 | AllHandles, |
| 211 | ByRegisterNotify, | 211 | ByRegisterNotify, |
| 212 | ByProtocol, | 212 | ByProtocol, |
| ... | @@ -229,7 +229,7 @@ pub const ProtocolInformationEntry = extern struct { | ... | @@ -229,7 +229,7 @@ pub const ProtocolInformationEntry = extern struct { |
| 229 | open_count: u32, | 229 | open_count: u32, |
| 230 | }; | 230 | }; |
| 231 | 231 | ||
| 232 | pub const AllocateType = extern enum(u32) { | 232 | pub const AllocateType = enum(u32) { |
| 233 | AllocateAnyPages, | 233 | AllocateAnyPages, |
| 234 | AllocateMaxAddress, | 234 | AllocateMaxAddress, |
| 235 | AllocateAddress, | 235 | AllocateAddress, |
lib/std/os/uefi/tables/runtime_services.zig+1-1| ... | @@ -51,7 +51,7 @@ pub const RuntimeServices = extern struct { | ... | @@ -51,7 +51,7 @@ pub const RuntimeServices = extern struct { |
| 51 | pub const signature: u64 = 0x56524553544e5552; | 51 | pub const signature: u64 = 0x56524553544e5552; |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | pub const ResetType = extern enum(u32) { | 54 | pub const ResetType = enum(u32) { |
| 55 | ResetCold, | 55 | ResetCold, |
| 56 | ResetWarm, | 56 | ResetWarm, |
| 57 | ResetShutdown, | 57 | ResetShutdown, |
lib/std/os/windows.zig+3-3| ... | @@ -1022,7 +1022,7 @@ pub fn QueryObjectName( | ... | @@ -1022,7 +1022,7 @@ pub fn QueryObjectName( |
| 1022 | } | 1022 | } |
| 1023 | } | 1023 | } |
| 1024 | test "QueryObjectName" { | 1024 | test "QueryObjectName" { |
| 1025 | if (comptime builtin.os.tag != .windows) | 1025 | if (comptime builtin.target.os.tag != .windows) |
| 1026 | return; | 1026 | return; |
| 1027 | 1027 | ||
| 1028 | //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths. | 1028 | //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths. |
| ... | @@ -1177,7 +1177,7 @@ pub fn GetFinalPathNameByHandle( | ... | @@ -1177,7 +1177,7 @@ pub fn GetFinalPathNameByHandle( |
| 1177 | } | 1177 | } |
| 1178 | 1178 | ||
| 1179 | test "GetFinalPathNameByHandle" { | 1179 | test "GetFinalPathNameByHandle" { |
| 1180 | if (comptime builtin.os.tag != .windows) | 1180 | if (comptime builtin.target.os.tag != .windows) |
| 1181 | return; | 1181 | return; |
| 1182 | 1182 | ||
| 1183 | //any file will do | 1183 | //any file will do |
| ... | @@ -1617,7 +1617,7 @@ pub fn SetFileTime( | ... | @@ -1617,7 +1617,7 @@ pub fn SetFileTime( |
| 1617 | } | 1617 | } |
| 1618 | 1618 | ||
| 1619 | pub fn teb() *TEB { | 1619 | pub fn teb() *TEB { |
| 1620 | return switch (builtin.arch) { | 1620 | return switch (builtin.target.cpu.arch) { |
| 1621 | .i386 => asm volatile ( | 1621 | .i386 => asm volatile ( |
| 1622 | \\ movl %%fs:0x18, %[ptr] | 1622 | \\ movl %%fs:0x18, %[ptr] |
| 1623 | : [ptr] "=r" (-> *TEB) | 1623 | : [ptr] "=r" (-> *TEB) |
lib/std/os/windows/bits.zig+6-6| ... | @@ -5,10 +5,10 @@ | ... | @@ -5,10 +5,10 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | // Platform-dependent types and values that are used along with OS-specific APIs. | 6 | // Platform-dependent types and values that are used along with OS-specific APIs. |
| 7 | 7 | ||
| 8 | const builtin = @import("builtin"); | ||
| 9 | const std = @import("../../std.zig"); | 8 | const std = @import("../../std.zig"); |
| 10 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| 11 | const maxInt = std.math.maxInt; | 10 | const maxInt = std.math.maxInt; |
| 11 | const arch = std.Target.current.cpu.arch; | ||
| 12 | 12 | ||
| 13 | pub usingnamespace @import("win32error.zig"); | 13 | pub usingnamespace @import("win32error.zig"); |
| 14 | pub usingnamespace @import("ntstatus.zig"); | 14 | pub usingnamespace @import("ntstatus.zig"); |
| ... | @@ -24,7 +24,7 @@ pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; | ... | @@ -24,7 +24,7 @@ pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; |
| 24 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. | 24 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. |
| 25 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; | 25 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; |
| 26 | 26 | ||
| 27 | pub const WINAPI: builtin.CallingConvention = if (builtin.arch == .i386) | 27 | pub const WINAPI: std.builtin.CallingConvention = if (arch == .i386) |
| 28 | .Stdcall | 28 | .Stdcall |
| 29 | else | 29 | else |
| 30 | .C; | 30 | .C; |
| ... | @@ -281,7 +281,7 @@ pub const IO_STATUS_BLOCK = extern struct { | ... | @@ -281,7 +281,7 @@ pub const IO_STATUS_BLOCK = extern struct { |
| 281 | Information: ULONG_PTR, | 281 | Information: ULONG_PTR, |
| 282 | }; | 282 | }; |
| 283 | 283 | ||
| 284 | pub const FILE_INFORMATION_CLASS = extern enum { | 284 | pub const FILE_INFORMATION_CLASS = enum(c_int) { |
| 285 | FileDirectoryInformation = 1, | 285 | FileDirectoryInformation = 1, |
| 286 | FileFullDirectoryInformation, | 286 | FileFullDirectoryInformation, |
| 287 | FileBothDirectoryInformation, | 287 | FileBothDirectoryInformation, |
| ... | @@ -901,7 +901,7 @@ pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; | ... | @@ -901,7 +901,7 @@ pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; |
| 901 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; | 901 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; |
| 902 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; | 902 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; |
| 903 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; | 903 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; |
| 904 | pub const COINIT = extern enum { | 904 | pub const COINIT = enum(c_int) { |
| 905 | COINIT_APARTMENTTHREADED = 2, | 905 | COINIT_APARTMENTTHREADED = 2, |
| 906 | COINIT_MULTITHREADED = 0, | 906 | COINIT_MULTITHREADED = 0, |
| 907 | COINIT_DISABLE_OLE1DDE = 4, | 907 | COINIT_DISABLE_OLE1DDE = 4, |
| ... | @@ -937,7 +937,7 @@ pub const EXCEPTION_RECORD = extern struct { | ... | @@ -937,7 +937,7 @@ pub const EXCEPTION_RECORD = extern struct { |
| 937 | ExceptionInformation: [15]usize, | 937 | ExceptionInformation: [15]usize, |
| 938 | }; | 938 | }; |
| 939 | 939 | ||
| 940 | pub usingnamespace switch (builtin.arch) { | 940 | pub usingnamespace switch (arch) { |
| 941 | .i386 => struct { | 941 | .i386 => struct { |
| 942 | pub const FLOATING_SAVE_AREA = extern struct { | 942 | pub const FLOATING_SAVE_AREA = extern struct { |
| 943 | ControlWord: DWORD, | 943 | ControlWord: DWORD, |
| ... | @@ -1619,7 +1619,7 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct { | ... | @@ -1619,7 +1619,7 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct { |
| 1619 | }; | 1619 | }; |
| 1620 | pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008; | 1620 | pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008; |
| 1621 | 1621 | ||
| 1622 | pub const OBJECT_INFORMATION_CLASS = extern enum { | 1622 | pub const OBJECT_INFORMATION_CLASS = enum(c_int) { |
| 1623 | ObjectBasicInformation = 0, | 1623 | ObjectBasicInformation = 0, |
| 1624 | ObjectNameInformation = 1, | 1624 | ObjectNameInformation = 1, |
| 1625 | ObjectTypeInformation = 2, | 1625 | ObjectTypeInformation = 2, |
lib/std/os/windows/ntstatus.zig+11-1803| ... | @@ -3,5603 +3,3811 @@ | ... | @@ -3,5603 +3,3811 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | // NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55? | ||
| 7 | pub const NTSTATUS = extern enum(u32) { | ||
| 8 | /// The operation completed successfully. | ||
| 9 | SUCCESS = 0x00000000, | ||
| 10 | 6 | ||
| 11 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. | 7 | /// NTSTATUS codes from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55? |
| 12 | WAIT_0 = 0x00000000, | 8 | pub const NTSTATUS = enum(u32) { |
| 9 | /// The caller specified WaitAny for WaitType and one of the dispatcher | ||
| 10 | /// objects in the Object array has been set to the signaled state. | ||
| 11 | pub const WAIT_0: NTSTATUS = .SUCCESS; | ||
| 12 | /// The caller attempted to wait for a mutex that has been abandoned. | ||
| 13 | pub const ABANDONED_WAIT_0: NTSTATUS = .ABANDONED; | ||
| 14 | /// The maximum number of boot-time filters has been reached. | ||
| 15 | pub const FWP_TOO_MANY_BOOTTIME_FILTERS: NTSTATUS = .FWP_TOO_MANY_CALLOUTS; | ||
| 13 | 16 | ||
| 17 | /// The operation completed successfully. | ||
| 18 | SUCCESS = 0x00000000, | ||
| 14 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. | 19 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. |
| 15 | WAIT_1 = 0x00000001, | 20 | WAIT_1 = 0x00000001, |
| 16 | |||
| 17 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. | 21 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. |
| 18 | WAIT_2 = 0x00000002, | 22 | WAIT_2 = 0x00000002, |
| 19 | |||
| 20 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. | 23 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. |
| 21 | WAIT_3 = 0x00000003, | 24 | WAIT_3 = 0x00000003, |
| 22 | |||
| 23 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. | 25 | /// The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. |
| 24 | WAIT_63 = 0x0000003F, | 26 | WAIT_63 = 0x0000003F, |
| 25 | |||
| 26 | /// The caller attempted to wait for a mutex that has been abandoned. | 27 | /// The caller attempted to wait for a mutex that has been abandoned. |
| 27 | ABANDONED = 0x00000080, | 28 | ABANDONED = 0x00000080, |
| 28 | |||
| 29 | /// The caller attempted to wait for a mutex that has been abandoned. | ||
| 30 | ABANDONED_WAIT_0 = 0x00000080, | ||
| 31 | |||
| 32 | /// The caller attempted to wait for a mutex that has been abandoned. | 29 | /// The caller attempted to wait for a mutex that has been abandoned. |
| 33 | ABANDONED_WAIT_63 = 0x000000BF, | 30 | ABANDONED_WAIT_63 = 0x000000BF, |
| 34 | |||
| 35 | /// A user-mode APC was delivered before the given Interval expired. | 31 | /// A user-mode APC was delivered before the given Interval expired. |
| 36 | USER_APC = 0x000000C0, | 32 | USER_APC = 0x000000C0, |
| 37 | |||
| 38 | /// The delay completed because the thread was alerted. | 33 | /// The delay completed because the thread was alerted. |
| 39 | ALERTED = 0x00000101, | 34 | ALERTED = 0x00000101, |
| 40 | |||
| 41 | /// The given Timeout interval expired. | 35 | /// The given Timeout interval expired. |
| 42 | TIMEOUT = 0x00000102, | 36 | TIMEOUT = 0x00000102, |
| 43 | |||
| 44 | /// The operation that was requested is pending completion. | 37 | /// The operation that was requested is pending completion. |
| 45 | PENDING = 0x00000103, | 38 | PENDING = 0x00000103, |
| 46 | |||
| 47 | /// A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link. | 39 | /// A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link. |
| 48 | REPARSE = 0x00000104, | 40 | REPARSE = 0x00000104, |
| 49 | |||
| 50 | /// Returned by enumeration APIs to indicate more information is available to successive calls. | 41 | /// Returned by enumeration APIs to indicate more information is available to successive calls. |
| 51 | MORE_ENTRIES = 0x00000105, | 42 | MORE_ENTRIES = 0x00000105, |
| 52 | |||
| 53 | /// Indicates not all privileges or groups that are referenced are assigned to the caller. | 43 | /// Indicates not all privileges or groups that are referenced are assigned to the caller. |
| 54 | /// This allows, for example, all privileges to be disabled without having to know exactly which privileges are assigned. | 44 | /// This allows, for example, all privileges to be disabled without having to know exactly which privileges are assigned. |
| 55 | NOT_ALL_ASSIGNED = 0x00000106, | 45 | NOT_ALL_ASSIGNED = 0x00000106, |
| 56 | |||
| 57 | /// Some of the information to be translated has not been translated. | 46 | /// Some of the information to be translated has not been translated. |
| 58 | SOME_NOT_MAPPED = 0x00000107, | 47 | SOME_NOT_MAPPED = 0x00000107, |
| 59 | |||
| 60 | /// An open/create operation completed while an opportunistic lock (oplock) break is underway. | 48 | /// An open/create operation completed while an opportunistic lock (oplock) break is underway. |
| 61 | OPLOCK_BREAK_IN_PROGRESS = 0x00000108, | 49 | OPLOCK_BREAK_IN_PROGRESS = 0x00000108, |
| 62 | |||
| 63 | /// A new volume has been mounted by a file system. | 50 | /// A new volume has been mounted by a file system. |
| 64 | VOLUME_MOUNTED = 0x00000109, | 51 | VOLUME_MOUNTED = 0x00000109, |
| 65 | |||
| 66 | /// This success level status indicates that the transaction state already exists for the registry subtree but that a transaction commit was previously aborted. The commit has now been completed. | 52 | /// This success level status indicates that the transaction state already exists for the registry subtree but that a transaction commit was previously aborted. The commit has now been completed. |
| 67 | RXACT_COMMITTED = 0x0000010A, | 53 | RXACT_COMMITTED = 0x0000010A, |
| 68 | |||
| 69 | /// Indicates that a notify change request has been completed due to closing the handle that made the notify change request. | 54 | /// Indicates that a notify change request has been completed due to closing the handle that made the notify change request. |
| 70 | NOTIFY_CLEANUP = 0x0000010B, | 55 | NOTIFY_CLEANUP = 0x0000010B, |
| 71 | |||
| 72 | /// Indicates that a notify change request is being completed and that the information is not being returned in the caller's buffer. | 56 | /// Indicates that a notify change request is being completed and that the information is not being returned in the caller's buffer. |
| 73 | /// The caller now needs to enumerate the files to find the changes. | 57 | /// The caller now needs to enumerate the files to find the changes. |
| 74 | NOTIFY_ENUM_DIR = 0x0000010C, | 58 | NOTIFY_ENUM_DIR = 0x0000010C, |
| 75 | |||
| 76 | /// {No Quotas} No system quota limits are specifically set for this account. | 59 | /// {No Quotas} No system quota limits are specifically set for this account. |
| 77 | NO_QUOTAS_FOR_ACCOUNT = 0x0000010D, | 60 | NO_QUOTAS_FOR_ACCOUNT = 0x0000010D, |
| 78 | |||
| 79 | /// {Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. | 61 | /// {Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. |
| 80 | /// The computer WAS able to connect on a secondary transport. | 62 | /// The computer WAS able to connect on a secondary transport. |
| 81 | PRIMARY_TRANSPORT_CONNECT_FAILED = 0x0000010E, | 63 | PRIMARY_TRANSPORT_CONNECT_FAILED = 0x0000010E, |
| 82 | |||
| 83 | /// The page fault was a transition fault. | 64 | /// The page fault was a transition fault. |
| 84 | PAGE_FAULT_TRANSITION = 0x00000110, | 65 | PAGE_FAULT_TRANSITION = 0x00000110, |
| 85 | |||
| 86 | /// The page fault was a demand zero fault. | 66 | /// The page fault was a demand zero fault. |
| 87 | PAGE_FAULT_DEMAND_ZERO = 0x00000111, | 67 | PAGE_FAULT_DEMAND_ZERO = 0x00000111, |
| 88 | |||
| 89 | /// The page fault was a demand zero fault. | 68 | /// The page fault was a demand zero fault. |
| 90 | PAGE_FAULT_COPY_ON_WRITE = 0x00000112, | 69 | PAGE_FAULT_COPY_ON_WRITE = 0x00000112, |
| 91 | |||
| 92 | /// The page fault was a demand zero fault. | 70 | /// The page fault was a demand zero fault. |
| 93 | PAGE_FAULT_GUARD_PAGE = 0x00000113, | 71 | PAGE_FAULT_GUARD_PAGE = 0x00000113, |
| 94 | |||
| 95 | /// The page fault was satisfied by reading from a secondary storage device. | 72 | /// The page fault was satisfied by reading from a secondary storage device. |
| 96 | PAGE_FAULT_PAGING_FILE = 0x00000114, | 73 | PAGE_FAULT_PAGING_FILE = 0x00000114, |
| 97 | |||
| 98 | /// The cached page was locked during operation. | 74 | /// The cached page was locked during operation. |
| 99 | CACHE_PAGE_LOCKED = 0x00000115, | 75 | CACHE_PAGE_LOCKED = 0x00000115, |
| 100 | |||
| 101 | /// The crash dump exists in a paging file. | 76 | /// The crash dump exists in a paging file. |
| 102 | CRASH_DUMP = 0x00000116, | 77 | CRASH_DUMP = 0x00000116, |
| 103 | |||
| 104 | /// The specified buffer contains all zeros. | 78 | /// The specified buffer contains all zeros. |
| 105 | BUFFER_ALL_ZEROS = 0x00000117, | 79 | BUFFER_ALL_ZEROS = 0x00000117, |
| 106 | |||
| 107 | /// A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link. | 80 | /// A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link. |
| 108 | REPARSE_OBJECT = 0x00000118, | 81 | REPARSE_OBJECT = 0x00000118, |
| 109 | |||
| 110 | /// The device has succeeded a query-stop and its resource requirements have changed. | 82 | /// The device has succeeded a query-stop and its resource requirements have changed. |
| 111 | RESOURCE_REQUIREMENTS_CHANGED = 0x00000119, | 83 | RESOURCE_REQUIREMENTS_CHANGED = 0x00000119, |
| 112 | |||
| 113 | /// The translator has translated these resources into the global space and no additional translations should be performed. | 84 | /// The translator has translated these resources into the global space and no additional translations should be performed. |
| 114 | TRANSLATION_COMPLETE = 0x00000120, | 85 | TRANSLATION_COMPLETE = 0x00000120, |
| 115 | |||
| 116 | /// The directory service evaluated group memberships locally, because it was unable to contact a global catalog server. | 86 | /// The directory service evaluated group memberships locally, because it was unable to contact a global catalog server. |
| 117 | DS_MEMBERSHIP_EVALUATED_LOCALLY = 0x00000121, | 87 | DS_MEMBERSHIP_EVALUATED_LOCALLY = 0x00000121, |
| 118 | |||
| 119 | /// A process being terminated has no threads to terminate. | 88 | /// A process being terminated has no threads to terminate. |
| 120 | NOTHING_TO_TERMINATE = 0x00000122, | 89 | NOTHING_TO_TERMINATE = 0x00000122, |
| 121 | |||
| 122 | /// The specified process is not part of a job. | 90 | /// The specified process is not part of a job. |
| 123 | PROCESS_NOT_IN_JOB = 0x00000123, | 91 | PROCESS_NOT_IN_JOB = 0x00000123, |
| 124 | |||
| 125 | /// The specified process is part of a job. | 92 | /// The specified process is part of a job. |
| 126 | PROCESS_IN_JOB = 0x00000124, | 93 | PROCESS_IN_JOB = 0x00000124, |
| 127 | |||
| 128 | /// {Volume Shadow Copy Service} The system is now ready for hibernation. | 94 | /// {Volume Shadow Copy Service} The system is now ready for hibernation. |
| 129 | VOLSNAP_HIBERNATE_READY = 0x00000125, | 95 | VOLSNAP_HIBERNATE_READY = 0x00000125, |
| 130 | |||
| 131 | /// A file system or file system filter driver has successfully completed an FsFilter operation. | 96 | /// A file system or file system filter driver has successfully completed an FsFilter operation. |
| 132 | FSFILTER_OP_COMPLETED_SUCCESSFULLY = 0x00000126, | 97 | FSFILTER_OP_COMPLETED_SUCCESSFULLY = 0x00000126, |
| 133 | |||
| 134 | /// The specified interrupt vector was already connected. | 98 | /// The specified interrupt vector was already connected. |
| 135 | INTERRUPT_VECTOR_ALREADY_CONNECTED = 0x00000127, | 99 | INTERRUPT_VECTOR_ALREADY_CONNECTED = 0x00000127, |
| 136 | |||
| 137 | /// The specified interrupt vector is still connected. | 100 | /// The specified interrupt vector is still connected. |
| 138 | INTERRUPT_STILL_CONNECTED = 0x00000128, | 101 | INTERRUPT_STILL_CONNECTED = 0x00000128, |
| 139 | |||
| 140 | /// The current process is a cloned process. | 102 | /// The current process is a cloned process. |
| 141 | PROCESS_CLONED = 0x00000129, | 103 | PROCESS_CLONED = 0x00000129, |
| 142 | |||
| 143 | /// The file was locked and all users of the file can only read. | 104 | /// The file was locked and all users of the file can only read. |
| 144 | FILE_LOCKED_WITH_ONLY_READERS = 0x0000012A, | 105 | FILE_LOCKED_WITH_ONLY_READERS = 0x0000012A, |
| 145 | |||
| 146 | /// The file was locked and at least one user of the file can write. | 106 | /// The file was locked and at least one user of the file can write. |
| 147 | FILE_LOCKED_WITH_WRITERS = 0x0000012B, | 107 | FILE_LOCKED_WITH_WRITERS = 0x0000012B, |
| 148 | |||
| 149 | /// The specified ResourceManager made no changes or updates to the resource under this transaction. | 108 | /// The specified ResourceManager made no changes or updates to the resource under this transaction. |
| 150 | RESOURCEMANAGER_READ_ONLY = 0x00000202, | 109 | RESOURCEMANAGER_READ_ONLY = 0x00000202, |
| 151 | |||
| 152 | /// An operation is blocked and waiting for an oplock. | 110 | /// An operation is blocked and waiting for an oplock. |
| 153 | WAIT_FOR_OPLOCK = 0x00000367, | 111 | WAIT_FOR_OPLOCK = 0x00000367, |
| 154 | |||
| 155 | /// Debugger handled the exception. | 112 | /// Debugger handled the exception. |
| 156 | DBG_EXCEPTION_HANDLED = 0x00010001, | 113 | DBG_EXCEPTION_HANDLED = 0x00010001, |
| 157 | |||
| 158 | /// The debugger continued. | 114 | /// The debugger continued. |
| 159 | DBG_CONTINUE = 0x00010002, | 115 | DBG_CONTINUE = 0x00010002, |
| 160 | |||
| 161 | /// The IO was completed by a filter. | 116 | /// The IO was completed by a filter. |
| 162 | FLT_IO_COMPLETE = 0x001C0001, | 117 | FLT_IO_COMPLETE = 0x001C0001, |
| 163 | |||
| 164 | /// The file is temporarily unavailable. | 118 | /// The file is temporarily unavailable. |
| 165 | FILE_NOT_AVAILABLE = 0xC0000467, | 119 | FILE_NOT_AVAILABLE = 0xC0000467, |
| 166 | |||
| 167 | /// The share is temporarily unavailable. | 120 | /// The share is temporarily unavailable. |
| 168 | SHARE_UNAVAILABLE = 0xC0000480, | 121 | SHARE_UNAVAILABLE = 0xC0000480, |
| 169 | |||
| 170 | /// A threadpool worker thread entered a callback at thread affinity %p and exited at affinity %p. | 122 | /// A threadpool worker thread entered a callback at thread affinity %p and exited at affinity %p. |
| 171 | /// This is unexpected, indicating that the callback missed restoring the priority. | 123 | /// This is unexpected, indicating that the callback missed restoring the priority. |
| 172 | CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721, | 124 | CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721, |
| 173 | |||
| 174 | /// {Object Exists} An attempt was made to create an object but the object name already exists. | 125 | /// {Object Exists} An attempt was made to create an object but the object name already exists. |
| 175 | OBJECT_NAME_EXISTS = 0x40000000, | 126 | OBJECT_NAME_EXISTS = 0x40000000, |
| 176 | |||
| 177 | /// {Thread Suspended} A thread termination occurred while the thread was suspended. The thread resumed, and termination proceeded. | 127 | /// {Thread Suspended} A thread termination occurred while the thread was suspended. The thread resumed, and termination proceeded. |
| 178 | THREAD_WAS_SUSPENDED = 0x40000001, | 128 | THREAD_WAS_SUSPENDED = 0x40000001, |
| 179 | |||
| 180 | /// {Working Set Range Error} An attempt was made to set the working set minimum or maximum to values that are outside the allowable range. | 129 | /// {Working Set Range Error} An attempt was made to set the working set minimum or maximum to values that are outside the allowable range. |
| 181 | WORKING_SET_LIMIT_RANGE = 0x40000002, | 130 | WORKING_SET_LIMIT_RANGE = 0x40000002, |
| 182 | |||
| 183 | /// {Image Relocated} An image file could not be mapped at the address that is specified in the image file. Local fixes must be performed on this image. | 131 | /// {Image Relocated} An image file could not be mapped at the address that is specified in the image file. Local fixes must be performed on this image. |
| 184 | IMAGE_NOT_AT_BASE = 0x40000003, | 132 | IMAGE_NOT_AT_BASE = 0x40000003, |
| 185 | |||
| 186 | /// This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created. | 133 | /// This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created. |
| 187 | RXACT_STATE_CREATED = 0x40000004, | 134 | RXACT_STATE_CREATED = 0x40000004, |
| 188 | |||
| 189 | /// {Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. | 135 | /// {Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. |
| 190 | /// An exception is raised so that a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments. | 136 | /// An exception is raised so that a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments. |
| 191 | SEGMENT_NOTIFICATION = 0x40000005, | 137 | SEGMENT_NOTIFICATION = 0x40000005, |
| 192 | |||
| 193 | /// {Local Session Key} A user session key was requested for a local remote procedure call (RPC) connection. | 138 | /// {Local Session Key} A user session key was requested for a local remote procedure call (RPC) connection. |
| 194 | /// The session key that is returned is a constant value and not unique to this connection. | 139 | /// The session key that is returned is a constant value and not unique to this connection. |
| 195 | LOCAL_USER_SESSION_KEY = 0x40000006, | 140 | LOCAL_USER_SESSION_KEY = 0x40000006, |
| 196 | |||
| 197 | /// {Invalid Current Directory} The process cannot switch to the startup current directory %hs. | 141 | /// {Invalid Current Directory} The process cannot switch to the startup current directory %hs. |
| 198 | /// Select OK to set the current directory to %hs, or select CANCEL to exit. | 142 | /// Select OK to set the current directory to %hs, or select CANCEL to exit. |
| 199 | BAD_CURRENT_DIRECTORY = 0x40000007, | 143 | BAD_CURRENT_DIRECTORY = 0x40000007, |
| 200 | |||
| 201 | /// {Serial IOCTL Complete} A serial I/O operation was completed by another write to a serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.) | 144 | /// {Serial IOCTL Complete} A serial I/O operation was completed by another write to a serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.) |
| 202 | SERIAL_MORE_WRITES = 0x40000008, | 145 | SERIAL_MORE_WRITES = 0x40000008, |
| 203 | |||
| 204 | /// {Registry Recovery} One of the files that contains the system registry data had to be recovered by using a log or alternate copy. The recovery was successful. | 146 | /// {Registry Recovery} One of the files that contains the system registry data had to be recovered by using a log or alternate copy. The recovery was successful. |
| 205 | REGISTRY_RECOVERED = 0x40000009, | 147 | REGISTRY_RECOVERED = 0x40000009, |
| 206 | |||
| 207 | /// {Redundant Read} To satisfy a read request, the Windows NT operating system fault-tolerant file system successfully read the requested data from a redundant copy. | 148 | /// {Redundant Read} To satisfy a read request, the Windows NT operating system fault-tolerant file system successfully read the requested data from a redundant copy. |
| 208 | /// This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device. | 149 | /// This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device. |
| 209 | FT_READ_RECOVERY_FROM_BACKUP = 0x4000000A, | 150 | FT_READ_RECOVERY_FROM_BACKUP = 0x4000000A, |
| 210 | |||
| 211 | /// {Redundant Write} To satisfy a write request, the Windows NT fault-tolerant file system successfully wrote a redundant copy of the information. | 151 | /// {Redundant Write} To satisfy a write request, the Windows NT fault-tolerant file system successfully wrote a redundant copy of the information. |
| 212 | /// This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device. | 152 | /// This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device. |
| 213 | FT_WRITE_RECOVERY = 0x4000000B, | 153 | FT_WRITE_RECOVERY = 0x4000000B, |
| 214 | |||
| 215 | /// {Serial IOCTL Timeout} A serial I/O operation completed because the time-out period expired. | 154 | /// {Serial IOCTL Timeout} A serial I/O operation completed because the time-out period expired. |
| 216 | /// (The IOCTL_SERIAL_XOFF_COUNTER had not reached zero.) | 155 | /// (The IOCTL_SERIAL_XOFF_COUNTER had not reached zero.) |
| 217 | SERIAL_COUNTER_TIMEOUT = 0x4000000C, | 156 | SERIAL_COUNTER_TIMEOUT = 0x4000000C, |
| 218 | |||
| 219 | /// {Password Too Complex} The Windows password is too complex to be converted to a LAN Manager password. | 157 | /// {Password Too Complex} The Windows password is too complex to be converted to a LAN Manager password. |
| 220 | /// The LAN Manager password that returned is a NULL string. | 158 | /// The LAN Manager password that returned is a NULL string. |
| 221 | NULL_LM_PASSWORD = 0x4000000D, | 159 | NULL_LM_PASSWORD = 0x4000000D, |
| 222 | |||
| 223 | /// {Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. | 160 | /// {Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. |
| 224 | /// Select OK to continue, or CANCEL to fail the DLL load. | 161 | /// Select OK to continue, or CANCEL to fail the DLL load. |
| 225 | IMAGE_MACHINE_TYPE_MISMATCH = 0x4000000E, | 162 | IMAGE_MACHINE_TYPE_MISMATCH = 0x4000000E, |
| 226 | |||
| 227 | /// {Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later. | 163 | /// {Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later. |
| 228 | RECEIVE_PARTIAL = 0x4000000F, | 164 | RECEIVE_PARTIAL = 0x4000000F, |
| 229 | |||
| 230 | /// {Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system. | 165 | /// {Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system. |
| 231 | RECEIVE_EXPEDITED = 0x40000010, | 166 | RECEIVE_EXPEDITED = 0x40000010, |
| 232 | |||
| 233 | /// {Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later. | 167 | /// {Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later. |
| 234 | RECEIVE_PARTIAL_EXPEDITED = 0x40000011, | 168 | RECEIVE_PARTIAL_EXPEDITED = 0x40000011, |
| 235 | |||
| 236 | /// {TDI Event Done} The TDI indication has completed successfully. | 169 | /// {TDI Event Done} The TDI indication has completed successfully. |
| 237 | EVENT_DONE = 0x40000012, | 170 | EVENT_DONE = 0x40000012, |
| 238 | |||
| 239 | /// {TDI Event Pending} The TDI indication has entered the pending state. | 171 | /// {TDI Event Pending} The TDI indication has entered the pending state. |
| 240 | EVENT_PENDING = 0x40000013, | 172 | EVENT_PENDING = 0x40000013, |
| 241 | |||
| 242 | /// Checking file system on %wZ. | 173 | /// Checking file system on %wZ. |
| 243 | CHECKING_FILE_SYSTEM = 0x40000014, | 174 | CHECKING_FILE_SYSTEM = 0x40000014, |
| 244 | |||
| 245 | /// {Fatal Application Exit} %hs | 175 | /// {Fatal Application Exit} %hs |
| 246 | FATAL_APP_EXIT = 0x40000015, | 176 | FATAL_APP_EXIT = 0x40000015, |
| 247 | |||
| 248 | /// The specified registry key is referenced by a predefined handle. | 177 | /// The specified registry key is referenced by a predefined handle. |
| 249 | PREDEFINED_HANDLE = 0x40000016, | 178 | PREDEFINED_HANDLE = 0x40000016, |
| 250 | |||
| 251 | /// {Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process. | 179 | /// {Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process. |
| 252 | WAS_UNLOCKED = 0x40000017, | 180 | WAS_UNLOCKED = 0x40000017, |
| 253 | |||
| 254 | /// %hs | 181 | /// %hs |
| 255 | SERVICE_NOTIFICATION = 0x40000018, | 182 | SERVICE_NOTIFICATION = 0x40000018, |
| 256 | |||
| 257 | /// {Page Locked} One of the pages to lock was already locked. | 183 | /// {Page Locked} One of the pages to lock was already locked. |
| 258 | WAS_LOCKED = 0x40000019, | 184 | WAS_LOCKED = 0x40000019, |
| 259 | |||
| 260 | /// Application popup: %1 : %2 | 185 | /// Application popup: %1 : %2 |
| 261 | LOG_HARD_ERROR = 0x4000001A, | 186 | LOG_HARD_ERROR = 0x4000001A, |
| 262 | |||
| 263 | /// A Win32 process already exists. | 187 | /// A Win32 process already exists. |
| 264 | ALREADY_WIN32 = 0x4000001B, | 188 | ALREADY_WIN32 = 0x4000001B, |
| 265 | |||
| 266 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 189 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 267 | WX86_UNSIMULATE = 0x4000001C, | 190 | WX86_UNSIMULATE = 0x4000001C, |
| 268 | |||
| 269 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 191 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 270 | WX86_CONTINUE = 0x4000001D, | 192 | WX86_CONTINUE = 0x4000001D, |
| 271 | |||
| 272 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 193 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 273 | WX86_SINGLE_STEP = 0x4000001E, | 194 | WX86_SINGLE_STEP = 0x4000001E, |
| 274 | |||
| 275 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 195 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 276 | WX86_BREAKPOINT = 0x4000001F, | 196 | WX86_BREAKPOINT = 0x4000001F, |
| 277 | |||
| 278 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 197 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 279 | WX86_EXCEPTION_CONTINUE = 0x40000020, | 198 | WX86_EXCEPTION_CONTINUE = 0x40000020, |
| 280 | |||
| 281 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 199 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 282 | WX86_EXCEPTION_LASTCHANCE = 0x40000021, | 200 | WX86_EXCEPTION_LASTCHANCE = 0x40000021, |
| 283 | |||
| 284 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 201 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 285 | WX86_EXCEPTION_CHAIN = 0x40000022, | 202 | WX86_EXCEPTION_CHAIN = 0x40000022, |
| 286 | |||
| 287 | /// {Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. | 203 | /// {Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. |
| 288 | IMAGE_MACHINE_TYPE_MISMATCH_EXE = 0x40000023, | 204 | IMAGE_MACHINE_TYPE_MISMATCH_EXE = 0x40000023, |
| 289 | |||
| 290 | /// A yield execution was performed and no thread was available to run. | 205 | /// A yield execution was performed and no thread was available to run. |
| 291 | NO_YIELD_PERFORMED = 0x40000024, | 206 | NO_YIELD_PERFORMED = 0x40000024, |
| 292 | |||
| 293 | /// The resume flag to a timer API was ignored. | 207 | /// The resume flag to a timer API was ignored. |
| 294 | TIMER_RESUME_IGNORED = 0x40000025, | 208 | TIMER_RESUME_IGNORED = 0x40000025, |
| 295 | |||
| 296 | /// The arbiter has deferred arbitration of these resources to its parent. | 209 | /// The arbiter has deferred arbitration of these resources to its parent. |
| 297 | ARBITRATION_UNHANDLED = 0x40000026, | 210 | ARBITRATION_UNHANDLED = 0x40000026, |
| 298 | |||
| 299 | /// The device has detected a CardBus card in its slot. | 211 | /// The device has detected a CardBus card in its slot. |
| 300 | CARDBUS_NOT_SUPPORTED = 0x40000027, | 212 | CARDBUS_NOT_SUPPORTED = 0x40000027, |
| 301 | |||
| 302 | /// An exception status code that is used by the Win32 x86 emulation subsystem. | 213 | /// An exception status code that is used by the Win32 x86 emulation subsystem. |
| 303 | WX86_CREATEWX86TIB = 0x40000028, | 214 | WX86_CREATEWX86TIB = 0x40000028, |
| 304 | |||
| 305 | /// The CPUs in this multiprocessor system are not all the same revision level. | 215 | /// The CPUs in this multiprocessor system are not all the same revision level. |
| 306 | /// To use all processors, the operating system restricts itself to the features of the least capable processor in the system. | 216 | /// To use all processors, the operating system restricts itself to the features of the least capable processor in the system. |
| 307 | /// If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported. | 217 | /// If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported. |
| 308 | MP_PROCESSOR_MISMATCH = 0x40000029, | 218 | MP_PROCESSOR_MISMATCH = 0x40000029, |
| 309 | |||
| 310 | /// The system was put into hibernation. | 219 | /// The system was put into hibernation. |
| 311 | HIBERNATED = 0x4000002A, | 220 | HIBERNATED = 0x4000002A, |
| 312 | |||
| 313 | /// The system was resumed from hibernation. | 221 | /// The system was resumed from hibernation. |
| 314 | RESUME_HIBERNATION = 0x4000002B, | 222 | RESUME_HIBERNATION = 0x4000002B, |
| 315 | |||
| 316 | /// Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3]. | 223 | /// Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3]. |
| 317 | FIRMWARE_UPDATED = 0x4000002C, | 224 | FIRMWARE_UPDATED = 0x4000002C, |
| 318 | |||
| 319 | /// A device driver is leaking locked I/O pages and is causing system degradation. | 225 | /// A device driver is leaking locked I/O pages and is causing system degradation. |
| 320 | /// The system has automatically enabled the tracking code to try and catch the culprit. | 226 | /// The system has automatically enabled the tracking code to try and catch the culprit. |
| 321 | DRIVERS_LEAKING_LOCKED_PAGES = 0x4000002D, | 227 | DRIVERS_LEAKING_LOCKED_PAGES = 0x4000002D, |
| 322 | |||
| 323 | /// The ALPC message being canceled has already been retrieved from the queue on the other side. | 228 | /// The ALPC message being canceled has already been retrieved from the queue on the other side. |
| 324 | MESSAGE_RETRIEVED = 0x4000002E, | 229 | MESSAGE_RETRIEVED = 0x4000002E, |
| 325 | |||
| 326 | /// The system power state is transitioning from %2 to %3. | 230 | /// The system power state is transitioning from %2 to %3. |
| 327 | SYSTEM_POWERSTATE_TRANSITION = 0x4000002F, | 231 | SYSTEM_POWERSTATE_TRANSITION = 0x4000002F, |
| 328 | |||
| 329 | /// The receive operation was successful. | 232 | /// The receive operation was successful. |
| 330 | /// Check the ALPC completion list for the received message. | 233 | /// Check the ALPC completion list for the received message. |
| 331 | ALPC_CHECK_COMPLETION_LIST = 0x40000030, | 234 | ALPC_CHECK_COMPLETION_LIST = 0x40000030, |
| 332 | |||
| 333 | /// The system power state is transitioning from %2 to %3 but could enter %4. | 235 | /// The system power state is transitioning from %2 to %3 but could enter %4. |
| 334 | SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 0x40000031, | 236 | SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 0x40000031, |
| 335 | |||
| 336 | /// Access to %1 is monitored by policy rule %2. | 237 | /// Access to %1 is monitored by policy rule %2. |
| 337 | ACCESS_AUDIT_BY_POLICY = 0x40000032, | 238 | ACCESS_AUDIT_BY_POLICY = 0x40000032, |
| 338 | |||
| 339 | /// A valid hibernation file has been invalidated and should be abandoned. | 239 | /// A valid hibernation file has been invalidated and should be abandoned. |
| 340 | ABANDON_HIBERFILE = 0x40000033, | 240 | ABANDON_HIBERFILE = 0x40000033, |
| 341 | |||
| 342 | /// Business rule scripts are disabled for the calling application. | 241 | /// Business rule scripts are disabled for the calling application. |
| 343 | BIZRULES_NOT_ENABLED = 0x40000034, | 242 | BIZRULES_NOT_ENABLED = 0x40000034, |
| 344 | |||
| 345 | /// The system has awoken. | 243 | /// The system has awoken. |
| 346 | WAKE_SYSTEM = 0x40000294, | 244 | WAKE_SYSTEM = 0x40000294, |
| 347 | |||
| 348 | /// The directory service is shutting down. | 245 | /// The directory service is shutting down. |
| 349 | DS_SHUTTING_DOWN = 0x40000370, | 246 | DS_SHUTTING_DOWN = 0x40000370, |
| 350 | |||
| 351 | /// Debugger will reply later. | 247 | /// Debugger will reply later. |
| 352 | DBG_REPLY_LATER = 0x40010001, | 248 | DBG_REPLY_LATER = 0x40010001, |
| 353 | |||
| 354 | /// Debugger cannot provide a handle. | 249 | /// Debugger cannot provide a handle. |
| 355 | DBG_UNABLE_TO_PROVIDE_HANDLE = 0x40010002, | 250 | DBG_UNABLE_TO_PROVIDE_HANDLE = 0x40010002, |
| 356 | |||
| 357 | /// Debugger terminated the thread. | 251 | /// Debugger terminated the thread. |
| 358 | DBG_TERMINATE_THREAD = 0x40010003, | 252 | DBG_TERMINATE_THREAD = 0x40010003, |
| 359 | |||
| 360 | /// Debugger terminated the process. | 253 | /// Debugger terminated the process. |
| 361 | DBG_TERMINATE_PROCESS = 0x40010004, | 254 | DBG_TERMINATE_PROCESS = 0x40010004, |
| 362 | |||
| 363 | /// Debugger obtained control of C. | 255 | /// Debugger obtained control of C. |
| 364 | DBG_CONTROL_C = 0x40010005, | 256 | DBG_CONTROL_C = 0x40010005, |
| 365 | |||
| 366 | /// Debugger printed an exception on control C. | 257 | /// Debugger printed an exception on control C. |
| 367 | DBG_PRINTEXCEPTION_C = 0x40010006, | 258 | DBG_PRINTEXCEPTION_C = 0x40010006, |
| 368 | |||
| 369 | /// Debugger received a RIP exception. | 259 | /// Debugger received a RIP exception. |
| 370 | DBG_RIPEXCEPTION = 0x40010007, | 260 | DBG_RIPEXCEPTION = 0x40010007, |
| 371 | |||
| 372 | /// Debugger received a control break. | 261 | /// Debugger received a control break. |
| 373 | DBG_CONTROL_BREAK = 0x40010008, | 262 | DBG_CONTROL_BREAK = 0x40010008, |
| 374 | |||
| 375 | /// Debugger command communication exception. | 263 | /// Debugger command communication exception. |
| 376 | DBG_COMMAND_EXCEPTION = 0x40010009, | 264 | DBG_COMMAND_EXCEPTION = 0x40010009, |
| 377 | |||
| 378 | /// A UUID that is valid only on this computer has been allocated. | 265 | /// A UUID that is valid only on this computer has been allocated. |
| 379 | RPC_NT_UUID_LOCAL_ONLY = 0x40020056, | 266 | RPC_NT_UUID_LOCAL_ONLY = 0x40020056, |
| 380 | |||
| 381 | /// Some data remains to be sent in the request buffer. | 267 | /// Some data remains to be sent in the request buffer. |
| 382 | RPC_NT_SEND_INCOMPLETE = 0x400200AF, | 268 | RPC_NT_SEND_INCOMPLETE = 0x400200AF, |
| 383 | |||
| 384 | /// The Client Drive Mapping Service has connected on Terminal Connection. | 269 | /// The Client Drive Mapping Service has connected on Terminal Connection. |
| 385 | CTX_CDM_CONNECT = 0x400A0004, | 270 | CTX_CDM_CONNECT = 0x400A0004, |
| 386 | |||
| 387 | /// The Client Drive Mapping Service has disconnected on Terminal Connection. | 271 | /// The Client Drive Mapping Service has disconnected on Terminal Connection. |
| 388 | CTX_CDM_DISCONNECT = 0x400A0005, | 272 | CTX_CDM_DISCONNECT = 0x400A0005, |
| 389 | |||
| 390 | /// A kernel mode component is releasing a reference on an activation context. | 273 | /// A kernel mode component is releasing a reference on an activation context. |
| 391 | SXS_RELEASE_ACTIVATION_CONTEXT = 0x4015000D, | 274 | SXS_RELEASE_ACTIVATION_CONTEXT = 0x4015000D, |
| 392 | |||
| 393 | /// The transactional resource manager is already consistent. Recovery is not needed. | 275 | /// The transactional resource manager is already consistent. Recovery is not needed. |
| 394 | RECOVERY_NOT_NEEDED = 0x40190034, | 276 | RECOVERY_NOT_NEEDED = 0x40190034, |
| 395 | |||
| 396 | /// The transactional resource manager has already been started. | 277 | /// The transactional resource manager has already been started. |
| 397 | RM_ALREADY_STARTED = 0x40190035, | 278 | RM_ALREADY_STARTED = 0x40190035, |
| 398 | |||
| 399 | /// The log service encountered a log stream with no restart area. | 279 | /// The log service encountered a log stream with no restart area. |
| 400 | LOG_NO_RESTART = 0x401A000C, | 280 | LOG_NO_RESTART = 0x401A000C, |
| 401 | |||
| 402 | /// {Display Driver Recovered From Failure} The %hs display driver has detected a failure and recovered from it. Some graphical operations might have failed. | 281 | /// {Display Driver Recovered From Failure} The %hs display driver has detected a failure and recovered from it. Some graphical operations might have failed. |
| 403 | /// The next time you restart the machine, a dialog box appears, giving you an opportunity to upload data about this failure to Microsoft. | 282 | /// The next time you restart the machine, a dialog box appears, giving you an opportunity to upload data about this failure to Microsoft. |
| 404 | VIDEO_DRIVER_DEBUG_REPORT_REQUEST = 0x401B00EC, | 283 | VIDEO_DRIVER_DEBUG_REPORT_REQUEST = 0x401B00EC, |
| 405 | |||
| 406 | /// The specified buffer is not big enough to contain the entire requested dataset. | 284 | /// The specified buffer is not big enough to contain the entire requested dataset. |
| 407 | /// Partial data is populated up to the size of the buffer. | 285 | /// Partial data is populated up to the size of the buffer. |
| 408 | /// The caller needs to provide a buffer of the size as specified in the partially populated buffer's content (interface specific). | 286 | /// The caller needs to provide a buffer of the size as specified in the partially populated buffer's content (interface specific). |
| 409 | GRAPHICS_PARTIAL_DATA_POPULATED = 0x401E000A, | 287 | GRAPHICS_PARTIAL_DATA_POPULATED = 0x401E000A, |
| 410 | |||
| 411 | /// The kernel driver detected a version mismatch between it and the user mode driver. | 288 | /// The kernel driver detected a version mismatch between it and the user mode driver. |
| 412 | GRAPHICS_DRIVER_MISMATCH = 0x401E0117, | 289 | GRAPHICS_DRIVER_MISMATCH = 0x401E0117, |
| 413 | |||
| 414 | /// No mode is pinned on the specified VidPN source/target. | 290 | /// No mode is pinned on the specified VidPN source/target. |
| 415 | GRAPHICS_MODE_NOT_PINNED = 0x401E0307, | 291 | GRAPHICS_MODE_NOT_PINNED = 0x401E0307, |
| 416 | |||
| 417 | /// The specified mode set does not specify a preference for one of its modes. | 292 | /// The specified mode set does not specify a preference for one of its modes. |
| 418 | GRAPHICS_NO_PREFERRED_MODE = 0x401E031E, | 293 | GRAPHICS_NO_PREFERRED_MODE = 0x401E031E, |
| 419 | |||
| 420 | /// The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) is empty. | 294 | /// The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) is empty. |
| 421 | GRAPHICS_DATASET_IS_EMPTY = 0x401E034B, | 295 | GRAPHICS_DATASET_IS_EMPTY = 0x401E034B, |
| 422 | |||
| 423 | /// The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) does not contain any more elements. | 296 | /// The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) does not contain any more elements. |
| 424 | GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET = 0x401E034C, | 297 | GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET = 0x401E034C, |
| 425 | |||
| 426 | /// The specified content transformation is not pinned on the specified VidPN present path. | 298 | /// The specified content transformation is not pinned on the specified VidPN present path. |
| 427 | GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED = 0x401E0351, | 299 | GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED = 0x401E0351, |
| 428 | |||
| 429 | /// The child device presence was not reliably detected. | 300 | /// The child device presence was not reliably detected. |
| 430 | GRAPHICS_UNKNOWN_CHILD_STATUS = 0x401E042F, | 301 | GRAPHICS_UNKNOWN_CHILD_STATUS = 0x401E042F, |
| 431 | |||
| 432 | /// Starting the lead adapter in a linked configuration has been temporarily deferred. | 302 | /// Starting the lead adapter in a linked configuration has been temporarily deferred. |
| 433 | GRAPHICS_LEADLINK_START_DEFERRED = 0x401E0437, | 303 | GRAPHICS_LEADLINK_START_DEFERRED = 0x401E0437, |
| 434 | |||
| 435 | /// The display adapter is being polled for children too frequently at the same polling level. | 304 | /// The display adapter is being polled for children too frequently at the same polling level. |
| 436 | GRAPHICS_POLLING_TOO_FREQUENTLY = 0x401E0439, | 305 | GRAPHICS_POLLING_TOO_FREQUENTLY = 0x401E0439, |
| 437 | |||
| 438 | /// Starting the adapter has been temporarily deferred. | 306 | /// Starting the adapter has been temporarily deferred. |
| 439 | GRAPHICS_START_DEFERRED = 0x401E043A, | 307 | GRAPHICS_START_DEFERRED = 0x401E043A, |
| 440 | |||
| 441 | /// The request will be completed later by an NDIS status indication. | 308 | /// The request will be completed later by an NDIS status indication. |
| 442 | NDIS_INDICATION_REQUIRED = 0x40230001, | 309 | NDIS_INDICATION_REQUIRED = 0x40230001, |
| 443 | |||
| 444 | /// {EXCEPTION} Guard Page Exception A page of memory that marks the end of a data structure, such as a stack or an array, has been accessed. | 310 | /// {EXCEPTION} Guard Page Exception A page of memory that marks the end of a data structure, such as a stack or an array, has been accessed. |
| 445 | GUARD_PAGE_VIOLATION = 0x80000001, | 311 | GUARD_PAGE_VIOLATION = 0x80000001, |
| 446 | |||
| 447 | /// {EXCEPTION} Alignment Fault A data type misalignment was detected in a load or store instruction. | 312 | /// {EXCEPTION} Alignment Fault A data type misalignment was detected in a load or store instruction. |
| 448 | DATATYPE_MISALIGNMENT = 0x80000002, | 313 | DATATYPE_MISALIGNMENT = 0x80000002, |
| 449 | |||
| 450 | /// {EXCEPTION} Breakpoint A breakpoint has been reached. | 314 | /// {EXCEPTION} Breakpoint A breakpoint has been reached. |
| 451 | BREAKPOINT = 0x80000003, | 315 | BREAKPOINT = 0x80000003, |
| 452 | |||
| 453 | /// {EXCEPTION} Single Step A single step or trace operation has just been completed. | 316 | /// {EXCEPTION} Single Step A single step or trace operation has just been completed. |
| 454 | SINGLE_STEP = 0x80000004, | 317 | SINGLE_STEP = 0x80000004, |
| 455 | |||
| 456 | /// {Buffer Overflow} The data was too large to fit into the specified buffer. | 318 | /// {Buffer Overflow} The data was too large to fit into the specified buffer. |
| 457 | BUFFER_OVERFLOW = 0x80000005, | 319 | BUFFER_OVERFLOW = 0x80000005, |
| 458 | |||
| 459 | /// {No More Files} No more files were found which match the file specification. | 320 | /// {No More Files} No more files were found which match the file specification. |
| 460 | NO_MORE_FILES = 0x80000006, | 321 | NO_MORE_FILES = 0x80000006, |
| 461 | |||
| 462 | /// {Kernel Debugger Awakened} The system debugger was awakened by an interrupt. | 322 | /// {Kernel Debugger Awakened} The system debugger was awakened by an interrupt. |
| 463 | WAKE_SYSTEM_DEBUGGER = 0x80000007, | 323 | WAKE_SYSTEM_DEBUGGER = 0x80000007, |
| 464 | |||
| 465 | /// {Handles Closed} Handles to objects have been automatically closed because of the requested operation. | 324 | /// {Handles Closed} Handles to objects have been automatically closed because of the requested operation. |
| 466 | HANDLES_CLOSED = 0x8000000A, | 325 | HANDLES_CLOSED = 0x8000000A, |
| 467 | |||
| 468 | /// {Non-Inheritable ACL} An access control list (ACL) contains no components that can be inherited. | 326 | /// {Non-Inheritable ACL} An access control list (ACL) contains no components that can be inherited. |
| 469 | NO_INHERITANCE = 0x8000000B, | 327 | NO_INHERITANCE = 0x8000000B, |
| 470 | |||
| 471 | /// {GUID Substitution} During the translation of a globally unique identifier (GUID) to a Windows security ID (SID), no administratively defined GUID prefix was found. | 328 | /// {GUID Substitution} During the translation of a globally unique identifier (GUID) to a Windows security ID (SID), no administratively defined GUID prefix was found. |
| 472 | /// A substitute prefix was used, which will not compromise system security. | 329 | /// A substitute prefix was used, which will not compromise system security. |
| 473 | /// However, this might provide a more restrictive access than intended. | 330 | /// However, this might provide a more restrictive access than intended. |
| 474 | GUID_SUBSTITUTION_MADE = 0x8000000C, | 331 | GUID_SUBSTITUTION_MADE = 0x8000000C, |
| 475 | |||
| 476 | /// Because of protection conflicts, not all the requested bytes could be copied. | 332 | /// Because of protection conflicts, not all the requested bytes could be copied. |
| 477 | PARTIAL_COPY = 0x8000000D, | 333 | PARTIAL_COPY = 0x8000000D, |
| 478 | |||
| 479 | /// {Out of Paper} The printer is out of paper. | 334 | /// {Out of Paper} The printer is out of paper. |
| 480 | DEVICE_PAPER_EMPTY = 0x8000000E, | 335 | DEVICE_PAPER_EMPTY = 0x8000000E, |
| 481 | |||
| 482 | /// {Device Power Is Off} The printer power has been turned off. | 336 | /// {Device Power Is Off} The printer power has been turned off. |
| 483 | DEVICE_POWERED_OFF = 0x8000000F, | 337 | DEVICE_POWERED_OFF = 0x8000000F, |
| 484 | |||
| 485 | /// {Device Offline} The printer has been taken offline. | 338 | /// {Device Offline} The printer has been taken offline. |
| 486 | DEVICE_OFF_LINE = 0x80000010, | 339 | DEVICE_OFF_LINE = 0x80000010, |
| 487 | |||
| 488 | /// {Device Busy} The device is currently busy. | 340 | /// {Device Busy} The device is currently busy. |
| 489 | DEVICE_BUSY = 0x80000011, | 341 | DEVICE_BUSY = 0x80000011, |
| 490 | |||
| 491 | /// {No More EAs} No more extended attributes (EAs) were found for the file. | 342 | /// {No More EAs} No more extended attributes (EAs) were found for the file. |
| 492 | NO_MORE_EAS = 0x80000012, | 343 | NO_MORE_EAS = 0x80000012, |
| 493 | |||
| 494 | /// {Illegal EA} The specified extended attribute (EA) name contains at least one illegal character. | 344 | /// {Illegal EA} The specified extended attribute (EA) name contains at least one illegal character. |
| 495 | INVALID_EA_NAME = 0x80000013, | 345 | INVALID_EA_NAME = 0x80000013, |
| 496 | |||
| 497 | /// {Inconsistent EA List} The extended attribute (EA) list is inconsistent. | 346 | /// {Inconsistent EA List} The extended attribute (EA) list is inconsistent. |
| 498 | EA_LIST_INCONSISTENT = 0x80000014, | 347 | EA_LIST_INCONSISTENT = 0x80000014, |
| 499 | |||
| 500 | /// {Invalid EA Flag} An invalid extended attribute (EA) flag was set. | 348 | /// {Invalid EA Flag} An invalid extended attribute (EA) flag was set. |
| 501 | INVALID_EA_FLAG = 0x80000015, | 349 | INVALID_EA_FLAG = 0x80000015, |
| 502 | |||
| 503 | /// {Verifying Disk} The media has changed and a verify operation is in progress; therefore, no reads or writes can be performed to the device, except those that are used in the verify operation. | 350 | /// {Verifying Disk} The media has changed and a verify operation is in progress; therefore, no reads or writes can be performed to the device, except those that are used in the verify operation. |
| 504 | VERIFY_REQUIRED = 0x80000016, | 351 | VERIFY_REQUIRED = 0x80000016, |
| 505 | |||
| 506 | /// {Too Much Information} The specified access control list (ACL) contained more information than was expected. | 352 | /// {Too Much Information} The specified access control list (ACL) contained more information than was expected. |
| 507 | EXTRANEOUS_INFORMATION = 0x80000017, | 353 | EXTRANEOUS_INFORMATION = 0x80000017, |
| 508 | |||
| 509 | /// This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. | 354 | /// This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. |
| 510 | /// The commit has NOT been completed but has not been rolled back either; therefore, it can still be committed, if needed. | 355 | /// The commit has NOT been completed but has not been rolled back either; therefore, it can still be committed, if needed. |
| 511 | RXACT_COMMIT_NECESSARY = 0x80000018, | 356 | RXACT_COMMIT_NECESSARY = 0x80000018, |
| 512 | |||
| 513 | /// {No More Entries} No more entries are available from an enumeration operation. | 357 | /// {No More Entries} No more entries are available from an enumeration operation. |
| 514 | NO_MORE_ENTRIES = 0x8000001A, | 358 | NO_MORE_ENTRIES = 0x8000001A, |
| 515 | |||
| 516 | /// {Filemark Found} A filemark was detected. | 359 | /// {Filemark Found} A filemark was detected. |
| 517 | FILEMARK_DETECTED = 0x8000001B, | 360 | FILEMARK_DETECTED = 0x8000001B, |
| 518 | |||
| 519 | /// {Media Changed} The media has changed. | 361 | /// {Media Changed} The media has changed. |
| 520 | MEDIA_CHANGED = 0x8000001C, | 362 | MEDIA_CHANGED = 0x8000001C, |
| 521 | |||
| 522 | /// {I/O Bus Reset} An I/O bus reset was detected. | 363 | /// {I/O Bus Reset} An I/O bus reset was detected. |
| 523 | BUS_RESET = 0x8000001D, | 364 | BUS_RESET = 0x8000001D, |
| 524 | |||
| 525 | /// {End of Media} The end of the media was encountered. | 365 | /// {End of Media} The end of the media was encountered. |
| 526 | END_OF_MEDIA = 0x8000001E, | 366 | END_OF_MEDIA = 0x8000001E, |
| 527 | |||
| 528 | /// The beginning of a tape or partition has been detected. | 367 | /// The beginning of a tape or partition has been detected. |
| 529 | BEGINNING_OF_MEDIA = 0x8000001F, | 368 | BEGINNING_OF_MEDIA = 0x8000001F, |
| 530 | |||
| 531 | /// {Media Changed} The media might have changed. | 369 | /// {Media Changed} The media might have changed. |
| 532 | MEDIA_CHECK = 0x80000020, | 370 | MEDIA_CHECK = 0x80000020, |
| 533 | |||
| 534 | /// A tape access reached a set mark. | 371 | /// A tape access reached a set mark. |
| 535 | SETMARK_DETECTED = 0x80000021, | 372 | SETMARK_DETECTED = 0x80000021, |
| 536 | |||
| 537 | /// During a tape access, the end of the data written is reached. | 373 | /// During a tape access, the end of the data written is reached. |
| 538 | NO_DATA_DETECTED = 0x80000022, | 374 | NO_DATA_DETECTED = 0x80000022, |
| 539 | |||
| 540 | /// The redirector is in use and cannot be unloaded. | 375 | /// The redirector is in use and cannot be unloaded. |
| 541 | REDIRECTOR_HAS_OPEN_HANDLES = 0x80000023, | 376 | REDIRECTOR_HAS_OPEN_HANDLES = 0x80000023, |
| 542 | |||
| 543 | /// The server is in use and cannot be unloaded. | 377 | /// The server is in use and cannot be unloaded. |
| 544 | SERVER_HAS_OPEN_HANDLES = 0x80000024, | 378 | SERVER_HAS_OPEN_HANDLES = 0x80000024, |
| 545 | |||
| 546 | /// The specified connection has already been disconnected. | 379 | /// The specified connection has already been disconnected. |
| 547 | ALREADY_DISCONNECTED = 0x80000025, | 380 | ALREADY_DISCONNECTED = 0x80000025, |
| 548 | |||
| 549 | /// A long jump has been executed. | 381 | /// A long jump has been executed. |
| 550 | LONGJUMP = 0x80000026, | 382 | LONGJUMP = 0x80000026, |
| 551 | |||
| 552 | /// A cleaner cartridge is present in the tape library. | 383 | /// A cleaner cartridge is present in the tape library. |
| 553 | CLEANER_CARTRIDGE_INSTALLED = 0x80000027, | 384 | CLEANER_CARTRIDGE_INSTALLED = 0x80000027, |
| 554 | |||
| 555 | /// The Plug and Play query operation was not successful. | 385 | /// The Plug and Play query operation was not successful. |
| 556 | PLUGPLAY_QUERY_VETOED = 0x80000028, | 386 | PLUGPLAY_QUERY_VETOED = 0x80000028, |
| 557 | |||
| 558 | /// A frame consolidation has been executed. | 387 | /// A frame consolidation has been executed. |
| 559 | UNWIND_CONSOLIDATE = 0x80000029, | 388 | UNWIND_CONSOLIDATE = 0x80000029, |
| 560 | |||
| 561 | /// {Registry Hive Recovered} The registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost. | 389 | /// {Registry Hive Recovered} The registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost. |
| 562 | REGISTRY_HIVE_RECOVERED = 0x8000002A, | 390 | REGISTRY_HIVE_RECOVERED = 0x8000002A, |
| 563 | |||
| 564 | /// The application is attempting to run executable code from the module %hs. This might be insecure. | 391 | /// The application is attempting to run executable code from the module %hs. This might be insecure. |
| 565 | /// An alternative, %hs, is available. Should the application use the secure module %hs? | 392 | /// An alternative, %hs, is available. Should the application use the secure module %hs? |
| 566 | DLL_MIGHT_BE_INSECURE = 0x8000002B, | 393 | DLL_MIGHT_BE_INSECURE = 0x8000002B, |
| 567 | |||
| 568 | /// The application is loading executable code from the module %hs. | 394 | /// The application is loading executable code from the module %hs. |
| 569 | /// This is secure but might be incompatible with previous releases of the operating system. | 395 | /// This is secure but might be incompatible with previous releases of the operating system. |
| 570 | /// An alternative, %hs, is available. Should the application use the secure module %hs? | 396 | /// An alternative, %hs, is available. Should the application use the secure module %hs? |
| 571 | DLL_MIGHT_BE_INCOMPATIBLE = 0x8000002C, | 397 | DLL_MIGHT_BE_INCOMPATIBLE = 0x8000002C, |
| 572 | |||
| 573 | /// The create operation stopped after reaching a symbolic link. | 398 | /// The create operation stopped after reaching a symbolic link. |
| 574 | STOPPED_ON_SYMLINK = 0x8000002D, | 399 | STOPPED_ON_SYMLINK = 0x8000002D, |
| 575 | |||
| 576 | /// The device has indicated that cleaning is necessary. | 400 | /// The device has indicated that cleaning is necessary. |
| 577 | DEVICE_REQUIRES_CLEANING = 0x80000288, | 401 | DEVICE_REQUIRES_CLEANING = 0x80000288, |
| 578 | |||
| 579 | /// The device has indicated that its door is open. Further operations require it closed and secured. | 402 | /// The device has indicated that its door is open. Further operations require it closed and secured. |
| 580 | DEVICE_DOOR_OPEN = 0x80000289, | 403 | DEVICE_DOOR_OPEN = 0x80000289, |
| 581 | |||
| 582 | /// Windows discovered a corruption in the file %hs. This file has now been repaired. | 404 | /// Windows discovered a corruption in the file %hs. This file has now been repaired. |
| 583 | /// Check if any data in the file was lost because of the corruption. | 405 | /// Check if any data in the file was lost because of the corruption. |
| 584 | DATA_LOST_REPAIR = 0x80000803, | 406 | DATA_LOST_REPAIR = 0x80000803, |
| 585 | |||
| 586 | /// Debugger did not handle the exception. | 407 | /// Debugger did not handle the exception. |
| 587 | DBG_EXCEPTION_NOT_HANDLED = 0x80010001, | 408 | DBG_EXCEPTION_NOT_HANDLED = 0x80010001, |
| 588 | |||
| 589 | /// The cluster node is already up. | 409 | /// The cluster node is already up. |
| 590 | CLUSTER_NODE_ALREADY_UP = 0x80130001, | 410 | CLUSTER_NODE_ALREADY_UP = 0x80130001, |
| 591 | |||
| 592 | /// The cluster node is already down. | 411 | /// The cluster node is already down. |
| 593 | CLUSTER_NODE_ALREADY_DOWN = 0x80130002, | 412 | CLUSTER_NODE_ALREADY_DOWN = 0x80130002, |
| 594 | |||
| 595 | /// The cluster network is already online. | 413 | /// The cluster network is already online. |
| 596 | CLUSTER_NETWORK_ALREADY_ONLINE = 0x80130003, | 414 | CLUSTER_NETWORK_ALREADY_ONLINE = 0x80130003, |
| 597 | |||
| 598 | /// The cluster network is already offline. | 415 | /// The cluster network is already offline. |
| 599 | CLUSTER_NETWORK_ALREADY_OFFLINE = 0x80130004, | 416 | CLUSTER_NETWORK_ALREADY_OFFLINE = 0x80130004, |
| 600 | |||
| 601 | /// The cluster node is already a member of the cluster. | 417 | /// The cluster node is already a member of the cluster. |
| 602 | CLUSTER_NODE_ALREADY_MEMBER = 0x80130005, | 418 | CLUSTER_NODE_ALREADY_MEMBER = 0x80130005, |
| 603 | |||
| 604 | /// The log could not be set to the requested size. | 419 | /// The log could not be set to the requested size. |
| 605 | COULD_NOT_RESIZE_LOG = 0x80190009, | 420 | COULD_NOT_RESIZE_LOG = 0x80190009, |
| 606 | |||
| 607 | /// There is no transaction metadata on the file. | 421 | /// There is no transaction metadata on the file. |
| 608 | NO_TXF_METADATA = 0x80190029, | 422 | NO_TXF_METADATA = 0x80190029, |
| 609 | |||
| 610 | /// The file cannot be recovered because there is a handle still open on it. | 423 | /// The file cannot be recovered because there is a handle still open on it. |
| 611 | CANT_RECOVER_WITH_HANDLE_OPEN = 0x80190031, | 424 | CANT_RECOVER_WITH_HANDLE_OPEN = 0x80190031, |
| 612 | |||
| 613 | /// Transaction metadata is already present on this file and cannot be superseded. | 425 | /// Transaction metadata is already present on this file and cannot be superseded. |
| 614 | TXF_METADATA_ALREADY_PRESENT = 0x80190041, | 426 | TXF_METADATA_ALREADY_PRESENT = 0x80190041, |
| 615 | |||
| 616 | /// A transaction scope could not be entered because the scope handler has not been initialized. | 427 | /// A transaction scope could not be entered because the scope handler has not been initialized. |
| 617 | TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 0x80190042, | 428 | TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 0x80190042, |
| 618 | |||
| 619 | /// {Display Driver Stopped Responding and recovered} The %hs display driver has stopped working normally. The recovery had been performed. | 429 | /// {Display Driver Stopped Responding and recovered} The %hs display driver has stopped working normally. The recovery had been performed. |
| 620 | VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED = 0x801B00EB, | 430 | VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED = 0x801B00EB, |
| 621 | |||
| 622 | /// {Buffer too small} The buffer is too small to contain the entry. No information has been written to the buffer. | 431 | /// {Buffer too small} The buffer is too small to contain the entry. No information has been written to the buffer. |
| 623 | FLT_BUFFER_TOO_SMALL = 0x801C0001, | 432 | FLT_BUFFER_TOO_SMALL = 0x801C0001, |
| 624 | |||
| 625 | /// Volume metadata read or write is incomplete. | 433 | /// Volume metadata read or write is incomplete. |
| 626 | FVE_PARTIAL_METADATA = 0x80210001, | 434 | FVE_PARTIAL_METADATA = 0x80210001, |
| 627 | |||
| 628 | /// BitLocker encryption keys were ignored because the volume was in a transient state. | 435 | /// BitLocker encryption keys were ignored because the volume was in a transient state. |
| 629 | FVE_TRANSIENT_STATE = 0x80210002, | 436 | FVE_TRANSIENT_STATE = 0x80210002, |
| 630 | |||
| 631 | /// {Operation Failed} The requested operation was unsuccessful. | 437 | /// {Operation Failed} The requested operation was unsuccessful. |
| 632 | UNSUCCESSFUL = 0xC0000001, | 438 | UNSUCCESSFUL = 0xC0000001, |
| 633 | |||
| 634 | /// {Not Implemented} The requested operation is not implemented. | 439 | /// {Not Implemented} The requested operation is not implemented. |
| 635 | NOT_IMPLEMENTED = 0xC0000002, | 440 | NOT_IMPLEMENTED = 0xC0000002, |
| 636 | |||
| 637 | /// {Invalid Parameter} The specified information class is not a valid information class for the specified object. | 441 | /// {Invalid Parameter} The specified information class is not a valid information class for the specified object. |
| 638 | INVALID_INFO_CLASS = 0xC0000003, | 442 | INVALID_INFO_CLASS = 0xC0000003, |
| 639 | |||
| 640 | /// The specified information record length does not match the length that is required for the specified information class. | 443 | /// The specified information record length does not match the length that is required for the specified information class. |
| 641 | INFO_LENGTH_MISMATCH = 0xC0000004, | 444 | INFO_LENGTH_MISMATCH = 0xC0000004, |
| 642 | |||
| 643 | /// The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. | 445 | /// The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. |
| 644 | ACCESS_VIOLATION = 0xC0000005, | 446 | ACCESS_VIOLATION = 0xC0000005, |
| 645 | |||
| 646 | /// The instruction at 0x%08lx referenced memory at 0x%08lx. | 447 | /// The instruction at 0x%08lx referenced memory at 0x%08lx. |
| 647 | /// The required data was not placed into memory because of an I/O error status of 0x%08lx. | 448 | /// The required data was not placed into memory because of an I/O error status of 0x%08lx. |
| 648 | IN_PAGE_ERROR = 0xC0000006, | 449 | IN_PAGE_ERROR = 0xC0000006, |
| 649 | |||
| 650 | /// The page file quota for the process has been exhausted. | 450 | /// The page file quota for the process has been exhausted. |
| 651 | PAGEFILE_QUOTA = 0xC0000007, | 451 | PAGEFILE_QUOTA = 0xC0000007, |
| 652 | |||
| 653 | /// An invalid HANDLE was specified. | 452 | /// An invalid HANDLE was specified. |
| 654 | INVALID_HANDLE = 0xC0000008, | 453 | INVALID_HANDLE = 0xC0000008, |
| 655 | |||
| 656 | /// An invalid initial stack was specified in a call to NtCreateThread. | 454 | /// An invalid initial stack was specified in a call to NtCreateThread. |
| 657 | BAD_INITIAL_STACK = 0xC0000009, | 455 | BAD_INITIAL_STACK = 0xC0000009, |
| 658 | |||
| 659 | /// An invalid initial start address was specified in a call to NtCreateThread. | 456 | /// An invalid initial start address was specified in a call to NtCreateThread. |
| 660 | BAD_INITIAL_PC = 0xC000000A, | 457 | BAD_INITIAL_PC = 0xC000000A, |
| 661 | |||
| 662 | /// An invalid client ID was specified. | 458 | /// An invalid client ID was specified. |
| 663 | INVALID_CID = 0xC000000B, | 459 | INVALID_CID = 0xC000000B, |
| 664 | |||
| 665 | /// An attempt was made to cancel or set a timer that has an associated APC and the specified thread is not the thread that originally set the timer with an associated APC routine. | 460 | /// An attempt was made to cancel or set a timer that has an associated APC and the specified thread is not the thread that originally set the timer with an associated APC routine. |
| 666 | TIMER_NOT_CANCELED = 0xC000000C, | 461 | TIMER_NOT_CANCELED = 0xC000000C, |
| 667 | |||
| 668 | /// An invalid parameter was passed to a service or function. | 462 | /// An invalid parameter was passed to a service or function. |
| 669 | INVALID_PARAMETER = 0xC000000D, | 463 | INVALID_PARAMETER = 0xC000000D, |
| 670 | |||
| 671 | /// A device that does not exist was specified. | 464 | /// A device that does not exist was specified. |
| 672 | NO_SUCH_DEVICE = 0xC000000E, | 465 | NO_SUCH_DEVICE = 0xC000000E, |
| 673 | |||
| 674 | /// {File Not Found} The file %hs does not exist. | 466 | /// {File Not Found} The file %hs does not exist. |
| 675 | NO_SUCH_FILE = 0xC000000F, | 467 | NO_SUCH_FILE = 0xC000000F, |
| 676 | |||
| 677 | /// The specified request is not a valid operation for the target device. | 468 | /// The specified request is not a valid operation for the target device. |
| 678 | INVALID_DEVICE_REQUEST = 0xC0000010, | 469 | INVALID_DEVICE_REQUEST = 0xC0000010, |
| 679 | |||
| 680 | /// The end-of-file marker has been reached. | 470 | /// The end-of-file marker has been reached. |
| 681 | /// There is no valid data in the file beyond this marker. | 471 | /// There is no valid data in the file beyond this marker. |
| 682 | END_OF_FILE = 0xC0000011, | 472 | END_OF_FILE = 0xC0000011, |
| 683 | |||
| 684 | /// {Wrong Volume} The wrong volume is in the drive. Insert volume %hs into drive %hs. | 473 | /// {Wrong Volume} The wrong volume is in the drive. Insert volume %hs into drive %hs. |
| 685 | WRONG_VOLUME = 0xC0000012, | 474 | WRONG_VOLUME = 0xC0000012, |
| 686 | |||
| 687 | /// {No Disk} There is no disk in the drive. Insert a disk into drive %hs. | 475 | /// {No Disk} There is no disk in the drive. Insert a disk into drive %hs. |
| 688 | NO_MEDIA_IN_DEVICE = 0xC0000013, | 476 | NO_MEDIA_IN_DEVICE = 0xC0000013, |
| 689 | |||
| 690 | /// {Unknown Disk Format} The disk in drive %hs is not formatted properly. | 477 | /// {Unknown Disk Format} The disk in drive %hs is not formatted properly. |
| 691 | /// Check the disk, and reformat it, if needed. | 478 | /// Check the disk, and reformat it, if needed. |
| 692 | UNRECOGNIZED_MEDIA = 0xC0000014, | 479 | UNRECOGNIZED_MEDIA = 0xC0000014, |
| 693 | |||
| 694 | /// {Sector Not Found} The specified sector does not exist. | 480 | /// {Sector Not Found} The specified sector does not exist. |
| 695 | NONEXISTENT_SECTOR = 0xC0000015, | 481 | NONEXISTENT_SECTOR = 0xC0000015, |
| 696 | |||
| 697 | /// {Still Busy} The specified I/O request packet (IRP) cannot be disposed of because the I/O operation is not complete. | 482 | /// {Still Busy} The specified I/O request packet (IRP) cannot be disposed of because the I/O operation is not complete. |
| 698 | MORE_PROCESSING_REQUIRED = 0xC0000016, | 483 | MORE_PROCESSING_REQUIRED = 0xC0000016, |
| 699 | |||
| 700 | /// {Not Enough Quota} Not enough virtual memory or paging file quota is available to complete the specified operation. | 484 | /// {Not Enough Quota} Not enough virtual memory or paging file quota is available to complete the specified operation. |
| 701 | NO_MEMORY = 0xC0000017, | 485 | NO_MEMORY = 0xC0000017, |
| 702 | |||
| 703 | /// {Conflicting Address Range} The specified address range conflicts with the address space. | 486 | /// {Conflicting Address Range} The specified address range conflicts with the address space. |
| 704 | CONFLICTING_ADDRESSES = 0xC0000018, | 487 | CONFLICTING_ADDRESSES = 0xC0000018, |
| 705 | |||
| 706 | /// The address range to unmap is not a mapped view. | 488 | /// The address range to unmap is not a mapped view. |
| 707 | NOT_MAPPED_VIEW = 0xC0000019, | 489 | NOT_MAPPED_VIEW = 0xC0000019, |
| 708 | |||
| 709 | /// The virtual memory cannot be freed. | 490 | /// The virtual memory cannot be freed. |
| 710 | UNABLE_TO_FREE_VM = 0xC000001A, | 491 | UNABLE_TO_FREE_VM = 0xC000001A, |
| 711 | |||
| 712 | /// The specified section cannot be deleted. | 492 | /// The specified section cannot be deleted. |
| 713 | UNABLE_TO_DELETE_SECTION = 0xC000001B, | 493 | UNABLE_TO_DELETE_SECTION = 0xC000001B, |
| 714 | |||
| 715 | /// An invalid system service was specified in a system service call. | 494 | /// An invalid system service was specified in a system service call. |
| 716 | INVALID_SYSTEM_SERVICE = 0xC000001C, | 495 | INVALID_SYSTEM_SERVICE = 0xC000001C, |
| 717 | |||
| 718 | /// {EXCEPTION} Illegal Instruction An attempt was made to execute an illegal instruction. | 496 | /// {EXCEPTION} Illegal Instruction An attempt was made to execute an illegal instruction. |
| 719 | ILLEGAL_INSTRUCTION = 0xC000001D, | 497 | ILLEGAL_INSTRUCTION = 0xC000001D, |
| 720 | |||
| 721 | /// {Invalid Lock Sequence} An attempt was made to execute an invalid lock sequence. | 498 | /// {Invalid Lock Sequence} An attempt was made to execute an invalid lock sequence. |
| 722 | INVALID_LOCK_SEQUENCE = 0xC000001E, | 499 | INVALID_LOCK_SEQUENCE = 0xC000001E, |
| 723 | |||
| 724 | /// {Invalid Mapping} An attempt was made to create a view for a section that is bigger than the section. | 500 | /// {Invalid Mapping} An attempt was made to create a view for a section that is bigger than the section. |
| 725 | INVALID_VIEW_SIZE = 0xC000001F, | 501 | INVALID_VIEW_SIZE = 0xC000001F, |
| 726 | |||
| 727 | /// {Bad File} The attributes of the specified mapping file for a section of memory cannot be read. | 502 | /// {Bad File} The attributes of the specified mapping file for a section of memory cannot be read. |
| 728 | INVALID_FILE_FOR_SECTION = 0xC0000020, | 503 | INVALID_FILE_FOR_SECTION = 0xC0000020, |
| 729 | |||
| 730 | /// {Already Committed} The specified address range is already committed. | 504 | /// {Already Committed} The specified address range is already committed. |
| 731 | ALREADY_COMMITTED = 0xC0000021, | 505 | ALREADY_COMMITTED = 0xC0000021, |
| 732 | |||
| 733 | /// {Access Denied} A process has requested access to an object but has not been granted those access rights. | 506 | /// {Access Denied} A process has requested access to an object but has not been granted those access rights. |
| 734 | ACCESS_DENIED = 0xC0000022, | 507 | ACCESS_DENIED = 0xC0000022, |
| 735 | |||
| 736 | /// {Buffer Too Small} The buffer is too small to contain the entry. No information has been written to the buffer. | 508 | /// {Buffer Too Small} The buffer is too small to contain the entry. No information has been written to the buffer. |
| 737 | BUFFER_TOO_SMALL = 0xC0000023, | 509 | BUFFER_TOO_SMALL = 0xC0000023, |
| 738 | |||
| 739 | /// {Wrong Type} There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request. | 510 | /// {Wrong Type} There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request. |
| 740 | OBJECT_TYPE_MISMATCH = 0xC0000024, | 511 | OBJECT_TYPE_MISMATCH = 0xC0000024, |
| 741 | |||
| 742 | /// {EXCEPTION} Cannot Continue Windows cannot continue from this exception. | 512 | /// {EXCEPTION} Cannot Continue Windows cannot continue from this exception. |
| 743 | NONCONTINUABLE_EXCEPTION = 0xC0000025, | 513 | NONCONTINUABLE_EXCEPTION = 0xC0000025, |
| 744 | |||
| 745 | /// An invalid exception disposition was returned by an exception handler. | 514 | /// An invalid exception disposition was returned by an exception handler. |
| 746 | INVALID_DISPOSITION = 0xC0000026, | 515 | INVALID_DISPOSITION = 0xC0000026, |
| 747 | |||
| 748 | /// Unwind exception code. | 516 | /// Unwind exception code. |
| 749 | UNWIND = 0xC0000027, | 517 | UNWIND = 0xC0000027, |
| 750 | |||
| 751 | /// An invalid or unaligned stack was encountered during an unwind operation. | 518 | /// An invalid or unaligned stack was encountered during an unwind operation. |
| 752 | BAD_STACK = 0xC0000028, | 519 | BAD_STACK = 0xC0000028, |
| 753 | |||
| 754 | /// An invalid unwind target was encountered during an unwind operation. | 520 | /// An invalid unwind target was encountered during an unwind operation. |
| 755 | INVALID_UNWIND_TARGET = 0xC0000029, | 521 | INVALID_UNWIND_TARGET = 0xC0000029, |
| 756 | |||
| 757 | /// An attempt was made to unlock a page of memory that was not locked. | 522 | /// An attempt was made to unlock a page of memory that was not locked. |
| 758 | NOT_LOCKED = 0xC000002A, | 523 | NOT_LOCKED = 0xC000002A, |
| 759 | |||
| 760 | /// A device parity error on an I/O operation. | 524 | /// A device parity error on an I/O operation. |
| 761 | PARITY_ERROR = 0xC000002B, | 525 | PARITY_ERROR = 0xC000002B, |
| 762 | |||
| 763 | /// An attempt was made to decommit uncommitted virtual memory. | 526 | /// An attempt was made to decommit uncommitted virtual memory. |
| 764 | UNABLE_TO_DECOMMIT_VM = 0xC000002C, | 527 | UNABLE_TO_DECOMMIT_VM = 0xC000002C, |
| 765 | |||
| 766 | /// An attempt was made to change the attributes on memory that has not been committed. | 528 | /// An attempt was made to change the attributes on memory that has not been committed. |
| 767 | NOT_COMMITTED = 0xC000002D, | 529 | NOT_COMMITTED = 0xC000002D, |
| 768 | |||
| 769 | /// Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort. | 530 | /// Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort. |
| 770 | INVALID_PORT_ATTRIBUTES = 0xC000002E, | 531 | INVALID_PORT_ATTRIBUTES = 0xC000002E, |
| 771 | |||
| 772 | /// The length of the message that was passed to NtRequestPort or NtRequestWaitReplyPort is longer than the maximum message that is allowed by the port. | 532 | /// The length of the message that was passed to NtRequestPort or NtRequestWaitReplyPort is longer than the maximum message that is allowed by the port. |
| 773 | PORT_MESSAGE_TOO_LONG = 0xC000002F, | 533 | PORT_MESSAGE_TOO_LONG = 0xC000002F, |
| 774 | |||
| 775 | /// An invalid combination of parameters was specified. | 534 | /// An invalid combination of parameters was specified. |
| 776 | INVALID_PARAMETER_MIX = 0xC0000030, | 535 | INVALID_PARAMETER_MIX = 0xC0000030, |
| 777 | |||
| 778 | /// An attempt was made to lower a quota limit below the current usage. | 536 | /// An attempt was made to lower a quota limit below the current usage. |
| 779 | INVALID_QUOTA_LOWER = 0xC0000031, | 537 | INVALID_QUOTA_LOWER = 0xC0000031, |
| 780 | |||
| 781 | /// {Corrupt Disk} The file system structure on the disk is corrupt and unusable. Run the Chkdsk utility on the volume %hs. | 538 | /// {Corrupt Disk} The file system structure on the disk is corrupt and unusable. Run the Chkdsk utility on the volume %hs. |
| 782 | DISK_CORRUPT_ERROR = 0xC0000032, | 539 | DISK_CORRUPT_ERROR = 0xC0000032, |
| 783 | |||
| 784 | /// The object name is invalid. | 540 | /// The object name is invalid. |
| 785 | OBJECT_NAME_INVALID = 0xC0000033, | 541 | OBJECT_NAME_INVALID = 0xC0000033, |
| 786 | |||
| 787 | /// The object name is not found. | 542 | /// The object name is not found. |
| 788 | OBJECT_NAME_NOT_FOUND = 0xC0000034, | 543 | OBJECT_NAME_NOT_FOUND = 0xC0000034, |
| 789 | |||
| 790 | /// The object name already exists. | 544 | /// The object name already exists. |
| 791 | OBJECT_NAME_COLLISION = 0xC0000035, | 545 | OBJECT_NAME_COLLISION = 0xC0000035, |
| 792 | |||
| 793 | /// An attempt was made to send a message to a disconnected communication port. | 546 | /// An attempt was made to send a message to a disconnected communication port. |
| 794 | PORT_DISCONNECTED = 0xC0000037, | 547 | PORT_DISCONNECTED = 0xC0000037, |
| 795 | |||
| 796 | /// An attempt was made to attach to a device that was already attached to another device. | 548 | /// An attempt was made to attach to a device that was already attached to another device. |
| 797 | DEVICE_ALREADY_ATTACHED = 0xC0000038, | 549 | DEVICE_ALREADY_ATTACHED = 0xC0000038, |
| 798 | |||
| 799 | /// The object path component was not a directory object. | 550 | /// The object path component was not a directory object. |
| 800 | OBJECT_PATH_INVALID = 0xC0000039, | 551 | OBJECT_PATH_INVALID = 0xC0000039, |
| 801 | |||
| 802 | /// {Path Not Found} The path %hs does not exist. | 552 | /// {Path Not Found} The path %hs does not exist. |
| 803 | OBJECT_PATH_NOT_FOUND = 0xC000003A, | 553 | OBJECT_PATH_NOT_FOUND = 0xC000003A, |
| 804 | |||
| 805 | /// The object path component was not a directory object. | 554 | /// The object path component was not a directory object. |
| 806 | OBJECT_PATH_SYNTAX_BAD = 0xC000003B, | 555 | OBJECT_PATH_SYNTAX_BAD = 0xC000003B, |
| 807 | |||
| 808 | /// {Data Overrun} A data overrun error occurred. | 556 | /// {Data Overrun} A data overrun error occurred. |
| 809 | DATA_OVERRUN = 0xC000003C, | 557 | DATA_OVERRUN = 0xC000003C, |
| 810 | |||
| 811 | /// {Data Late} A data late error occurred. | 558 | /// {Data Late} A data late error occurred. |
| 812 | DATA_LATE_ERROR = 0xC000003D, | 559 | DATA_LATE_ERROR = 0xC000003D, |
| 813 | |||
| 814 | /// {Data Error} An error occurred in reading or writing data. | 560 | /// {Data Error} An error occurred in reading or writing data. |
| 815 | DATA_ERROR = 0xC000003E, | 561 | DATA_ERROR = 0xC000003E, |
| 816 | |||
| 817 | /// {Bad CRC} A cyclic redundancy check (CRC) checksum error occurred. | 562 | /// {Bad CRC} A cyclic redundancy check (CRC) checksum error occurred. |
| 818 | CRC_ERROR = 0xC000003F, | 563 | CRC_ERROR = 0xC000003F, |
| 819 | |||
| 820 | /// {Section Too Large} The specified section is too big to map the file. | 564 | /// {Section Too Large} The specified section is too big to map the file. |
| 821 | SECTION_TOO_BIG = 0xC0000040, | 565 | SECTION_TOO_BIG = 0xC0000040, |
| 822 | |||
| 823 | /// The NtConnectPort request is refused. | 566 | /// The NtConnectPort request is refused. |
| 824 | PORT_CONNECTION_REFUSED = 0xC0000041, | 567 | PORT_CONNECTION_REFUSED = 0xC0000041, |
| 825 | |||
| 826 | /// The type of port handle is invalid for the operation that is requested. | 568 | /// The type of port handle is invalid for the operation that is requested. |
| 827 | INVALID_PORT_HANDLE = 0xC0000042, | 569 | INVALID_PORT_HANDLE = 0xC0000042, |
| 828 | |||
| 829 | /// A file cannot be opened because the share access flags are incompatible. | 570 | /// A file cannot be opened because the share access flags are incompatible. |
| 830 | SHARING_VIOLATION = 0xC0000043, | 571 | SHARING_VIOLATION = 0xC0000043, |
| 831 | |||
| 832 | /// Insufficient quota exists to complete the operation. | 572 | /// Insufficient quota exists to complete the operation. |
| 833 | QUOTA_EXCEEDED = 0xC0000044, | 573 | QUOTA_EXCEEDED = 0xC0000044, |
| 834 | |||
| 835 | /// The specified page protection was not valid. | 574 | /// The specified page protection was not valid. |
| 836 | INVALID_PAGE_PROTECTION = 0xC0000045, | 575 | INVALID_PAGE_PROTECTION = 0xC0000045, |
| 837 | |||
| 838 | /// An attempt to release a mutant object was made by a thread that was not the owner of the mutant object. | 576 | /// An attempt to release a mutant object was made by a thread that was not the owner of the mutant object. |
| 839 | MUTANT_NOT_OWNED = 0xC0000046, | 577 | MUTANT_NOT_OWNED = 0xC0000046, |
| 840 | |||
| 841 | /// An attempt was made to release a semaphore such that its maximum count would have been exceeded. | 578 | /// An attempt was made to release a semaphore such that its maximum count would have been exceeded. |
| 842 | SEMAPHORE_LIMIT_EXCEEDED = 0xC0000047, | 579 | SEMAPHORE_LIMIT_EXCEEDED = 0xC0000047, |
| 843 | |||
| 844 | /// An attempt was made to set the DebugPort or ExceptionPort of a process, but a port already exists in the process, or an attempt was made to set the CompletionPort of a file but a port was already set in the file, or an attempt was made to set the associated completion port of an ALPC port but it is already set. | 580 | /// An attempt was made to set the DebugPort or ExceptionPort of a process, but a port already exists in the process, or an attempt was made to set the CompletionPort of a file but a port was already set in the file, or an attempt was made to set the associated completion port of an ALPC port but it is already set. |
| 845 | PORT_ALREADY_SET = 0xC0000048, | 581 | PORT_ALREADY_SET = 0xC0000048, |
| 846 | |||
| 847 | /// An attempt was made to query image information on a section that does not map an image. | 582 | /// An attempt was made to query image information on a section that does not map an image. |
| 848 | SECTION_NOT_IMAGE = 0xC0000049, | 583 | SECTION_NOT_IMAGE = 0xC0000049, |
| 849 | |||
| 850 | /// An attempt was made to suspend a thread whose suspend count was at its maximum. | 584 | /// An attempt was made to suspend a thread whose suspend count was at its maximum. |
| 851 | SUSPEND_COUNT_EXCEEDED = 0xC000004A, | 585 | SUSPEND_COUNT_EXCEEDED = 0xC000004A, |
| 852 | |||
| 853 | /// An attempt was made to suspend a thread that has begun termination. | 586 | /// An attempt was made to suspend a thread that has begun termination. |
| 854 | THREAD_IS_TERMINATING = 0xC000004B, | 587 | THREAD_IS_TERMINATING = 0xC000004B, |
| 855 | |||
| 856 | /// An attempt was made to set the working set limit to an invalid value (for example, the minimum greater than maximum). | 588 | /// An attempt was made to set the working set limit to an invalid value (for example, the minimum greater than maximum). |
| 857 | BAD_WORKING_SET_LIMIT = 0xC000004C, | 589 | BAD_WORKING_SET_LIMIT = 0xC000004C, |
| 858 | |||
| 859 | /// A section was created to map a file that is not compatible with an already existing section that maps the same file. | 590 | /// A section was created to map a file that is not compatible with an already existing section that maps the same file. |
| 860 | INCOMPATIBLE_FILE_MAP = 0xC000004D, | 591 | INCOMPATIBLE_FILE_MAP = 0xC000004D, |
| 861 | |||
| 862 | /// A view to a section specifies a protection that is incompatible with the protection of the initial view. | 592 | /// A view to a section specifies a protection that is incompatible with the protection of the initial view. |
| 863 | SECTION_PROTECTION = 0xC000004E, | 593 | SECTION_PROTECTION = 0xC000004E, |
| 864 | |||
| 865 | /// An operation involving EAs failed because the file system does not support EAs. | 594 | /// An operation involving EAs failed because the file system does not support EAs. |
| 866 | EAS_NOT_SUPPORTED = 0xC000004F, | 595 | EAS_NOT_SUPPORTED = 0xC000004F, |
| 867 | |||
| 868 | /// An EA operation failed because the EA set is too large. | 596 | /// An EA operation failed because the EA set is too large. |
| 869 | EA_TOO_LARGE = 0xC0000050, | 597 | EA_TOO_LARGE = 0xC0000050, |
| 870 | |||
| 871 | /// An EA operation failed because the name or EA index is invalid. | 598 | /// An EA operation failed because the name or EA index is invalid. |
| 872 | NONEXISTENT_EA_ENTRY = 0xC0000051, | 599 | NONEXISTENT_EA_ENTRY = 0xC0000051, |
| 873 | |||
| 874 | /// The file for which EAs were requested has no EAs. | 600 | /// The file for which EAs were requested has no EAs. |
| 875 | NO_EAS_ON_FILE = 0xC0000052, | 601 | NO_EAS_ON_FILE = 0xC0000052, |
| 876 | |||
| 877 | /// The EA is corrupt and cannot be read. | 602 | /// The EA is corrupt and cannot be read. |
| 878 | EA_CORRUPT_ERROR = 0xC0000053, | 603 | EA_CORRUPT_ERROR = 0xC0000053, |
| 879 | |||
| 880 | /// A requested read/write cannot be granted due to a conflicting file lock. | 604 | /// A requested read/write cannot be granted due to a conflicting file lock. |
| 881 | FILE_LOCK_CONFLICT = 0xC0000054, | 605 | FILE_LOCK_CONFLICT = 0xC0000054, |
| 882 | |||
| 883 | /// A requested file lock cannot be granted due to other existing locks. | 606 | /// A requested file lock cannot be granted due to other existing locks. |
| 884 | LOCK_NOT_GRANTED = 0xC0000055, | 607 | LOCK_NOT_GRANTED = 0xC0000055, |
| 885 | |||
| 886 | /// A non-close operation has been requested of a file object that has a delete pending. | 608 | /// A non-close operation has been requested of a file object that has a delete pending. |
| 887 | DELETE_PENDING = 0xC0000056, | 609 | DELETE_PENDING = 0xC0000056, |
| 888 | |||
| 889 | /// An attempt was made to set the control attribute on a file. | 610 | /// An attempt was made to set the control attribute on a file. |
| 890 | /// This attribute is not supported in the destination file system. | 611 | /// This attribute is not supported in the destination file system. |
| 891 | CTL_FILE_NOT_SUPPORTED = 0xC0000057, | 612 | CTL_FILE_NOT_SUPPORTED = 0xC0000057, |
| 892 | |||
| 893 | /// Indicates a revision number that was encountered or specified is not one that is known by the service. | 613 | /// Indicates a revision number that was encountered or specified is not one that is known by the service. |
| 894 | /// It might be a more recent revision than the service is aware of. | 614 | /// It might be a more recent revision than the service is aware of. |
| 895 | UNKNOWN_REVISION = 0xC0000058, | 615 | UNKNOWN_REVISION = 0xC0000058, |
| 896 | |||
| 897 | /// Indicates that two revision levels are incompatible. | 616 | /// Indicates that two revision levels are incompatible. |
| 898 | REVISION_MISMATCH = 0xC0000059, | 617 | REVISION_MISMATCH = 0xC0000059, |
| 899 | |||
| 900 | /// Indicates a particular security ID cannot be assigned as the owner of an object. | 618 | /// Indicates a particular security ID cannot be assigned as the owner of an object. |
| 901 | INVALID_OWNER = 0xC000005A, | 619 | INVALID_OWNER = 0xC000005A, |
| 902 | |||
| 903 | /// Indicates a particular security ID cannot be assigned as the primary group of an object. | 620 | /// Indicates a particular security ID cannot be assigned as the primary group of an object. |
| 904 | INVALID_PRIMARY_GROUP = 0xC000005B, | 621 | INVALID_PRIMARY_GROUP = 0xC000005B, |
| 905 | |||
| 906 | /// An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client. | 622 | /// An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client. |
| 907 | NO_IMPERSONATION_TOKEN = 0xC000005C, | 623 | NO_IMPERSONATION_TOKEN = 0xC000005C, |
| 908 | |||
| 909 | /// A mandatory group cannot be disabled. | 624 | /// A mandatory group cannot be disabled. |
| 910 | CANT_DISABLE_MANDATORY = 0xC000005D, | 625 | CANT_DISABLE_MANDATORY = 0xC000005D, |
| 911 | |||
| 912 | /// No logon servers are currently available to service the logon request. | 626 | /// No logon servers are currently available to service the logon request. |
| 913 | NO_LOGON_SERVERS = 0xC000005E, | 627 | NO_LOGON_SERVERS = 0xC000005E, |
| 914 | |||
| 915 | /// A specified logon session does not exist. It might already have been terminated. | 628 | /// A specified logon session does not exist. It might already have been terminated. |
| 916 | NO_SUCH_LOGON_SESSION = 0xC000005F, | 629 | NO_SUCH_LOGON_SESSION = 0xC000005F, |
| 917 | |||
| 918 | /// A specified privilege does not exist. | 630 | /// A specified privilege does not exist. |
| 919 | NO_SUCH_PRIVILEGE = 0xC0000060, | 631 | NO_SUCH_PRIVILEGE = 0xC0000060, |
| 920 | |||
| 921 | /// A required privilege is not held by the client. | 632 | /// A required privilege is not held by the client. |
| 922 | PRIVILEGE_NOT_HELD = 0xC0000061, | 633 | PRIVILEGE_NOT_HELD = 0xC0000061, |
| 923 | |||
| 924 | /// The name provided is not a properly formed account name. | 634 | /// The name provided is not a properly formed account name. |
| 925 | INVALID_ACCOUNT_NAME = 0xC0000062, | 635 | INVALID_ACCOUNT_NAME = 0xC0000062, |
| 926 | |||
| 927 | /// The specified account already exists. | 636 | /// The specified account already exists. |
| 928 | USER_EXISTS = 0xC0000063, | 637 | USER_EXISTS = 0xC0000063, |
| 929 | |||
| 930 | /// The specified account does not exist. | 638 | /// The specified account does not exist. |
| 931 | NO_SUCH_USER = 0xC0000064, | 639 | NO_SUCH_USER = 0xC0000064, |
| 932 | |||
| 933 | /// The specified group already exists. | 640 | /// The specified group already exists. |
| 934 | GROUP_EXISTS = 0xC0000065, | 641 | GROUP_EXISTS = 0xC0000065, |
| 935 | |||
| 936 | /// The specified group does not exist. | 642 | /// The specified group does not exist. |
| 937 | NO_SUCH_GROUP = 0xC0000066, | 643 | NO_SUCH_GROUP = 0xC0000066, |
| 938 | |||
| 939 | /// The specified user account is already in the specified group account. | 644 | /// The specified user account is already in the specified group account. |
| 940 | /// Also used to indicate a group cannot be deleted because it contains a member. | 645 | /// Also used to indicate a group cannot be deleted because it contains a member. |
| 941 | MEMBER_IN_GROUP = 0xC0000067, | 646 | MEMBER_IN_GROUP = 0xC0000067, |
| 942 | |||
| 943 | /// The specified user account is not a member of the specified group account. | 647 | /// The specified user account is not a member of the specified group account. |
| 944 | MEMBER_NOT_IN_GROUP = 0xC0000068, | 648 | MEMBER_NOT_IN_GROUP = 0xC0000068, |
| 945 | |||
| 946 | /// Indicates the requested operation would disable or delete the last remaining administration account. | 649 | /// Indicates the requested operation would disable or delete the last remaining administration account. |
| 947 | /// This is not allowed to prevent creating a situation in which the system cannot be administrated. | 650 | /// This is not allowed to prevent creating a situation in which the system cannot be administrated. |
| 948 | LAST_ADMIN = 0xC0000069, | 651 | LAST_ADMIN = 0xC0000069, |
| 949 | |||
| 950 | /// When trying to update a password, this return status indicates that the value provided as the current password is not correct. | 652 | /// When trying to update a password, this return status indicates that the value provided as the current password is not correct. |
| 951 | WRONG_PASSWORD = 0xC000006A, | 653 | WRONG_PASSWORD = 0xC000006A, |
| 952 | |||
| 953 | /// When trying to update a password, this return status indicates that the value provided for the new password contains values that are not allowed in passwords. | 654 | /// When trying to update a password, this return status indicates that the value provided for the new password contains values that are not allowed in passwords. |
| 954 | ILL_FORMED_PASSWORD = 0xC000006B, | 655 | ILL_FORMED_PASSWORD = 0xC000006B, |
| 955 | |||
| 956 | /// When trying to update a password, this status indicates that some password update rule has been violated. | 656 | /// When trying to update a password, this status indicates that some password update rule has been violated. |
| 957 | /// For example, the password might not meet length criteria. | 657 | /// For example, the password might not meet length criteria. |
| 958 | PASSWORD_RESTRICTION = 0xC000006C, | 658 | PASSWORD_RESTRICTION = 0xC000006C, |
| 959 | |||
| 960 | /// The attempted logon is invalid. | 659 | /// The attempted logon is invalid. |
| 961 | /// This is either due to a bad username or authentication information. | 660 | /// This is either due to a bad username or authentication information. |
| 962 | LOGON_FAILURE = 0xC000006D, | 661 | LOGON_FAILURE = 0xC000006D, |
| 963 | |||
| 964 | /// Indicates a referenced user name and authentication information are valid, but some user account restriction has prevented successful authentication (such as time-of-day restrictions). | 662 | /// Indicates a referenced user name and authentication information are valid, but some user account restriction has prevented successful authentication (such as time-of-day restrictions). |
| 965 | ACCOUNT_RESTRICTION = 0xC000006E, | 663 | ACCOUNT_RESTRICTION = 0xC000006E, |
| 966 | |||
| 967 | /// The user account has time restrictions and cannot be logged onto at this time. | 664 | /// The user account has time restrictions and cannot be logged onto at this time. |
| 968 | INVALID_LOGON_HOURS = 0xC000006F, | 665 | INVALID_LOGON_HOURS = 0xC000006F, |
| 969 | |||
| 970 | /// The user account is restricted so that it cannot be used to log on from the source workstation. | 666 | /// The user account is restricted so that it cannot be used to log on from the source workstation. |
| 971 | INVALID_WORKSTATION = 0xC0000070, | 667 | INVALID_WORKSTATION = 0xC0000070, |
| 972 | |||
| 973 | /// The user account password has expired. | 668 | /// The user account password has expired. |
| 974 | PASSWORD_EXPIRED = 0xC0000071, | 669 | PASSWORD_EXPIRED = 0xC0000071, |
| 975 | |||
| 976 | /// The referenced account is currently disabled and cannot be logged on to. | 670 | /// The referenced account is currently disabled and cannot be logged on to. |
| 977 | ACCOUNT_DISABLED = 0xC0000072, | 671 | ACCOUNT_DISABLED = 0xC0000072, |
| 978 | |||
| 979 | /// None of the information to be translated has been translated. | 672 | /// None of the information to be translated has been translated. |
| 980 | NONE_MAPPED = 0xC0000073, | 673 | NONE_MAPPED = 0xC0000073, |
| 981 | |||
| 982 | /// The number of LUIDs requested cannot be allocated with a single allocation. | 674 | /// The number of LUIDs requested cannot be allocated with a single allocation. |
| 983 | TOO_MANY_LUIDS_REQUESTED = 0xC0000074, | 675 | TOO_MANY_LUIDS_REQUESTED = 0xC0000074, |
| 984 | |||
| 985 | /// Indicates there are no more LUIDs to allocate. | 676 | /// Indicates there are no more LUIDs to allocate. |
| 986 | LUIDS_EXHAUSTED = 0xC0000075, | 677 | LUIDS_EXHAUSTED = 0xC0000075, |
| 987 | |||
| 988 | /// Indicates the sub-authority value is invalid for the particular use. | 678 | /// Indicates the sub-authority value is invalid for the particular use. |
| 989 | INVALID_SUB_AUTHORITY = 0xC0000076, | 679 | INVALID_SUB_AUTHORITY = 0xC0000076, |
| 990 | |||
| 991 | /// Indicates the ACL structure is not valid. | 680 | /// Indicates the ACL structure is not valid. |
| 992 | INVALID_ACL = 0xC0000077, | 681 | INVALID_ACL = 0xC0000077, |
| 993 | |||
| 994 | /// Indicates the SID structure is not valid. | 682 | /// Indicates the SID structure is not valid. |
| 995 | INVALID_SID = 0xC0000078, | 683 | INVALID_SID = 0xC0000078, |
| 996 | |||
| 997 | /// Indicates the SECURITY_DESCRIPTOR structure is not valid. | 684 | /// Indicates the SECURITY_DESCRIPTOR structure is not valid. |
| 998 | INVALID_SECURITY_DESCR = 0xC0000079, | 685 | INVALID_SECURITY_DESCR = 0xC0000079, |
| 999 | |||
| 1000 | /// Indicates the specified procedure address cannot be found in the DLL. | 686 | /// Indicates the specified procedure address cannot be found in the DLL. |
| 1001 | PROCEDURE_NOT_FOUND = 0xC000007A, | 687 | PROCEDURE_NOT_FOUND = 0xC000007A, |
| 1002 | |||
| 1003 | /// {Bad Image} %hs is either not designed to run on Windows or it contains an error. | 688 | /// {Bad Image} %hs is either not designed to run on Windows or it contains an error. |
| 1004 | /// Try installing the program again using the original installation media or contact your system administrator or the software vendor for support. | 689 | /// Try installing the program again using the original installation media or contact your system administrator or the software vendor for support. |
| 1005 | INVALID_IMAGE_FORMAT = 0xC000007B, | 690 | INVALID_IMAGE_FORMAT = 0xC000007B, |
| 1006 | |||
| 1007 | /// An attempt was made to reference a token that does not exist. | 691 | /// An attempt was made to reference a token that does not exist. |
| 1008 | /// This is typically done by referencing the token that is associated with a thread when the thread is not impersonating a client. | 692 | /// This is typically done by referencing the token that is associated with a thread when the thread is not impersonating a client. |
| 1009 | NO_TOKEN = 0xC000007C, | 693 | NO_TOKEN = 0xC000007C, |
| 1010 | |||
| 1011 | /// Indicates that an attempt to build either an inherited ACL or ACE was not successful. This can be caused by a number of things. | 694 | /// Indicates that an attempt to build either an inherited ACL or ACE was not successful. This can be caused by a number of things. |
| 1012 | /// One of the more probable causes is the replacement of a CreatorId with a SID that did not fit into the ACE or ACL. | 695 | /// One of the more probable causes is the replacement of a CreatorId with a SID that did not fit into the ACE or ACL. |
| 1013 | BAD_INHERITANCE_ACL = 0xC000007D, | 696 | BAD_INHERITANCE_ACL = 0xC000007D, |
| 1014 | |||
| 1015 | /// The range specified in NtUnlockFile was not locked. | 697 | /// The range specified in NtUnlockFile was not locked. |
| 1016 | RANGE_NOT_LOCKED = 0xC000007E, | 698 | RANGE_NOT_LOCKED = 0xC000007E, |
| 1017 | |||
| 1018 | /// An operation failed because the disk was full. | 699 | /// An operation failed because the disk was full. |
| 1019 | DISK_FULL = 0xC000007F, | 700 | DISK_FULL = 0xC000007F, |
| 1020 | |||
| 1021 | /// The GUID allocation server is disabled at the moment. | 701 | /// The GUID allocation server is disabled at the moment. |
| 1022 | SERVER_DISABLED = 0xC0000080, | 702 | SERVER_DISABLED = 0xC0000080, |
| 1023 | |||
| 1024 | /// The GUID allocation server is enabled at the moment. | 703 | /// The GUID allocation server is enabled at the moment. |
| 1025 | SERVER_NOT_DISABLED = 0xC0000081, | 704 | SERVER_NOT_DISABLED = 0xC0000081, |
| 1026 | |||
| 1027 | /// Too many GUIDs were requested from the allocation server at once. | 705 | /// Too many GUIDs were requested from the allocation server at once. |
| 1028 | TOO_MANY_GUIDS_REQUESTED = 0xC0000082, | 706 | TOO_MANY_GUIDS_REQUESTED = 0xC0000082, |
| 1029 | |||
| 1030 | /// The GUIDs could not be allocated because the Authority Agent was exhausted. | 707 | /// The GUIDs could not be allocated because the Authority Agent was exhausted. |
| 1031 | GUIDS_EXHAUSTED = 0xC0000083, | 708 | GUIDS_EXHAUSTED = 0xC0000083, |
| 1032 | |||
| 1033 | /// The value provided was an invalid value for an identifier authority. | 709 | /// The value provided was an invalid value for an identifier authority. |
| 1034 | INVALID_ID_AUTHORITY = 0xC0000084, | 710 | INVALID_ID_AUTHORITY = 0xC0000084, |
| 1035 | |||
| 1036 | /// No more authority agent values are available for the particular identifier authority value. | 711 | /// No more authority agent values are available for the particular identifier authority value. |
| 1037 | AGENTS_EXHAUSTED = 0xC0000085, | 712 | AGENTS_EXHAUSTED = 0xC0000085, |
| 1038 | |||
| 1039 | /// An invalid volume label has been specified. | 713 | /// An invalid volume label has been specified. |
| 1040 | INVALID_VOLUME_LABEL = 0xC0000086, | 714 | INVALID_VOLUME_LABEL = 0xC0000086, |
| 1041 | |||
| 1042 | /// A mapped section could not be extended. | 715 | /// A mapped section could not be extended. |
| 1043 | SECTION_NOT_EXTENDED = 0xC0000087, | 716 | SECTION_NOT_EXTENDED = 0xC0000087, |
| 1044 | |||
| 1045 | /// Specified section to flush does not map a data file. | 717 | /// Specified section to flush does not map a data file. |
| 1046 | NOT_MAPPED_DATA = 0xC0000088, | 718 | NOT_MAPPED_DATA = 0xC0000088, |
| 1047 | |||
| 1048 | /// Indicates the specified image file did not contain a resource section. | 719 | /// Indicates the specified image file did not contain a resource section. |
| 1049 | RESOURCE_DATA_NOT_FOUND = 0xC0000089, | 720 | RESOURCE_DATA_NOT_FOUND = 0xC0000089, |
| 1050 | |||
| 1051 | /// Indicates the specified resource type cannot be found in the image file. | 721 | /// Indicates the specified resource type cannot be found in the image file. |
| 1052 | RESOURCE_TYPE_NOT_FOUND = 0xC000008A, | 722 | RESOURCE_TYPE_NOT_FOUND = 0xC000008A, |
| 1053 | |||
| 1054 | /// Indicates the specified resource name cannot be found in the image file. | 723 | /// Indicates the specified resource name cannot be found in the image file. |
| 1055 | RESOURCE_NAME_NOT_FOUND = 0xC000008B, | 724 | RESOURCE_NAME_NOT_FOUND = 0xC000008B, |
| 1056 | |||
| 1057 | /// {EXCEPTION} Array bounds exceeded. | 725 | /// {EXCEPTION} Array bounds exceeded. |
| 1058 | ARRAY_BOUNDS_EXCEEDED = 0xC000008C, | 726 | ARRAY_BOUNDS_EXCEEDED = 0xC000008C, |
| 1059 | |||
| 1060 | /// {EXCEPTION} Floating-point denormal operand. | 727 | /// {EXCEPTION} Floating-point denormal operand. |
| 1061 | FLOAT_DENORMAL_OPERAND = 0xC000008D, | 728 | FLOAT_DENORMAL_OPERAND = 0xC000008D, |
| 1062 | |||
| 1063 | /// {EXCEPTION} Floating-point division by zero. | 729 | /// {EXCEPTION} Floating-point division by zero. |
| 1064 | FLOAT_DIVIDE_BY_ZERO = 0xC000008E, | 730 | FLOAT_DIVIDE_BY_ZERO = 0xC000008E, |
| 1065 | |||
| 1066 | /// {EXCEPTION} Floating-point inexact result. | 731 | /// {EXCEPTION} Floating-point inexact result. |
| 1067 | FLOAT_INEXACT_RESULT = 0xC000008F, | 732 | FLOAT_INEXACT_RESULT = 0xC000008F, |
| 1068 | |||
| 1069 | /// {EXCEPTION} Floating-point invalid operation. | 733 | /// {EXCEPTION} Floating-point invalid operation. |
| 1070 | FLOAT_INVALID_OPERATION = 0xC0000090, | 734 | FLOAT_INVALID_OPERATION = 0xC0000090, |
| 1071 | |||
| 1072 | /// {EXCEPTION} Floating-point overflow. | 735 | /// {EXCEPTION} Floating-point overflow. |
| 1073 | FLOAT_OVERFLOW = 0xC0000091, | 736 | FLOAT_OVERFLOW = 0xC0000091, |
| 1074 | |||
| 1075 | /// {EXCEPTION} Floating-point stack check. | 737 | /// {EXCEPTION} Floating-point stack check. |
| 1076 | FLOAT_STACK_CHECK = 0xC0000092, | 738 | FLOAT_STACK_CHECK = 0xC0000092, |
| 1077 | |||
| 1078 | /// {EXCEPTION} Floating-point underflow. | 739 | /// {EXCEPTION} Floating-point underflow. |
| 1079 | FLOAT_UNDERFLOW = 0xC0000093, | 740 | FLOAT_UNDERFLOW = 0xC0000093, |
| 1080 | |||
| 1081 | /// {EXCEPTION} Integer division by zero. | 741 | /// {EXCEPTION} Integer division by zero. |
| 1082 | INTEGER_DIVIDE_BY_ZERO = 0xC0000094, | 742 | INTEGER_DIVIDE_BY_ZERO = 0xC0000094, |
| 1083 | |||
| 1084 | /// {EXCEPTION} Integer overflow. | 743 | /// {EXCEPTION} Integer overflow. |
| 1085 | INTEGER_OVERFLOW = 0xC0000095, | 744 | INTEGER_OVERFLOW = 0xC0000095, |
| 1086 | |||
| 1087 | /// {EXCEPTION} Privileged instruction. | 745 | /// {EXCEPTION} Privileged instruction. |
| 1088 | PRIVILEGED_INSTRUCTION = 0xC0000096, | 746 | PRIVILEGED_INSTRUCTION = 0xC0000096, |
| 1089 | |||
| 1090 | /// An attempt was made to install more paging files than the system supports. | 747 | /// An attempt was made to install more paging files than the system supports. |
| 1091 | TOO_MANY_PAGING_FILES = 0xC0000097, | 748 | TOO_MANY_PAGING_FILES = 0xC0000097, |
| 1092 | |||
| 1093 | /// The volume for a file has been externally altered such that the opened file is no longer valid. | 749 | /// The volume for a file has been externally altered such that the opened file is no longer valid. |
| 1094 | FILE_INVALID = 0xC0000098, | 750 | FILE_INVALID = 0xC0000098, |
| 1095 | |||
| 1096 | /// When a block of memory is allotted for future updates, such as the memory allocated to hold discretionary access control and primary group information, successive updates might exceed the amount of memory originally allotted. | 751 | /// When a block of memory is allotted for future updates, such as the memory allocated to hold discretionary access control and primary group information, successive updates might exceed the amount of memory originally allotted. |
| 1097 | /// Because a quota might already have been charged to several processes that have handles to the object, it is not reasonable to alter the size of the allocated memory. | 752 | /// Because a quota might already have been charged to several processes that have handles to the object, it is not reasonable to alter the size of the allocated memory. |
| 1098 | /// Instead, a request that requires more memory than has been allotted must fail and the STATUS_ALLOTTED_SPACE_EXCEEDED error returned. | 753 | /// Instead, a request that requires more memory than has been allotted must fail and the STATUS_ALLOTTED_SPACE_EXCEEDED error returned. |
| 1099 | ALLOTTED_SPACE_EXCEEDED = 0xC0000099, | 754 | ALLOTTED_SPACE_EXCEEDED = 0xC0000099, |
| 1100 | |||
| 1101 | /// Insufficient system resources exist to complete the API. | 755 | /// Insufficient system resources exist to complete the API. |
| 1102 | INSUFFICIENT_RESOURCES = 0xC000009A, | 756 | INSUFFICIENT_RESOURCES = 0xC000009A, |
| 1103 | |||
| 1104 | /// An attempt has been made to open a DFS exit path control file. | 757 | /// An attempt has been made to open a DFS exit path control file. |
| 1105 | DFS_EXIT_PATH_FOUND = 0xC000009B, | 758 | DFS_EXIT_PATH_FOUND = 0xC000009B, |
| 1106 | |||
| 1107 | /// There are bad blocks (sectors) on the hard disk. | 759 | /// There are bad blocks (sectors) on the hard disk. |
| 1108 | DEVICE_DATA_ERROR = 0xC000009C, | 760 | DEVICE_DATA_ERROR = 0xC000009C, |
| 1109 | |||
| 1110 | /// There is bad cabling, non-termination, or the controller is not able to obtain access to the hard disk. | 761 | /// There is bad cabling, non-termination, or the controller is not able to obtain access to the hard disk. |
| 1111 | DEVICE_NOT_CONNECTED = 0xC000009D, | 762 | DEVICE_NOT_CONNECTED = 0xC000009D, |
| 1112 | |||
| 1113 | /// Virtual memory cannot be freed because the base address is not the base of the region and a region size of zero was specified. | 763 | /// Virtual memory cannot be freed because the base address is not the base of the region and a region size of zero was specified. |
| 1114 | FREE_VM_NOT_AT_BASE = 0xC000009F, | 764 | FREE_VM_NOT_AT_BASE = 0xC000009F, |
| 1115 | |||
| 1116 | /// An attempt was made to free virtual memory that is not allocated. | 765 | /// An attempt was made to free virtual memory that is not allocated. |
| 1117 | MEMORY_NOT_ALLOCATED = 0xC00000A0, | 766 | MEMORY_NOT_ALLOCATED = 0xC00000A0, |
| 1118 | |||
| 1119 | /// The working set is not big enough to allow the requested pages to be locked. | 767 | /// The working set is not big enough to allow the requested pages to be locked. |
| 1120 | WORKING_SET_QUOTA = 0xC00000A1, | 768 | WORKING_SET_QUOTA = 0xC00000A1, |
| 1121 | |||
| 1122 | /// {Write Protect Error} The disk cannot be written to because it is write-protected. | 769 | /// {Write Protect Error} The disk cannot be written to because it is write-protected. |
| 1123 | /// Remove the write protection from the volume %hs in drive %hs. | 770 | /// Remove the write protection from the volume %hs in drive %hs. |
| 1124 | MEDIA_WRITE_PROTECTED = 0xC00000A2, | 771 | MEDIA_WRITE_PROTECTED = 0xC00000A2, |
| 1125 | |||
| 1126 | /// {Drive Not Ready} The drive is not ready for use; its door might be open. | 772 | /// {Drive Not Ready} The drive is not ready for use; its door might be open. |
| 1127 | /// Check drive %hs and make sure that a disk is inserted and that the drive door is closed. | 773 | /// Check drive %hs and make sure that a disk is inserted and that the drive door is closed. |
| 1128 | DEVICE_NOT_READY = 0xC00000A3, | 774 | DEVICE_NOT_READY = 0xC00000A3, |
| 1129 | |||
| 1130 | /// The specified attributes are invalid or are incompatible with the attributes for the group as a whole. | 775 | /// The specified attributes are invalid or are incompatible with the attributes for the group as a whole. |
| 1131 | INVALID_GROUP_ATTRIBUTES = 0xC00000A4, | 776 | INVALID_GROUP_ATTRIBUTES = 0xC00000A4, |
| 1132 | |||
| 1133 | /// A specified impersonation level is invalid. | 777 | /// A specified impersonation level is invalid. |
| 1134 | /// Also used to indicate that a required impersonation level was not provided. | 778 | /// Also used to indicate that a required impersonation level was not provided. |
| 1135 | BAD_IMPERSONATION_LEVEL = 0xC00000A5, | 779 | BAD_IMPERSONATION_LEVEL = 0xC00000A5, |
| 1136 | |||
| 1137 | /// An attempt was made to open an anonymous-level token. Anonymous tokens cannot be opened. | 780 | /// An attempt was made to open an anonymous-level token. Anonymous tokens cannot be opened. |
| 1138 | CANT_OPEN_ANONYMOUS = 0xC00000A6, | 781 | CANT_OPEN_ANONYMOUS = 0xC00000A6, |
| 1139 | |||
| 1140 | /// The validation information class requested was invalid. | 782 | /// The validation information class requested was invalid. |
| 1141 | BAD_VALIDATION_CLASS = 0xC00000A7, | 783 | BAD_VALIDATION_CLASS = 0xC00000A7, |
| 1142 | |||
| 1143 | /// The type of a token object is inappropriate for its attempted use. | 784 | /// The type of a token object is inappropriate for its attempted use. |
| 1144 | BAD_TOKEN_TYPE = 0xC00000A8, | 785 | BAD_TOKEN_TYPE = 0xC00000A8, |
| 1145 | |||
| 1146 | /// The type of a token object is inappropriate for its attempted use. | 786 | /// The type of a token object is inappropriate for its attempted use. |
| 1147 | BAD_MASTER_BOOT_RECORD = 0xC00000A9, | 787 | BAD_MASTER_BOOT_RECORD = 0xC00000A9, |
| 1148 | |||
| 1149 | /// An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references. | 788 | /// An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references. |
| 1150 | INSTRUCTION_MISALIGNMENT = 0xC00000AA, | 789 | INSTRUCTION_MISALIGNMENT = 0xC00000AA, |
| 1151 | |||
| 1152 | /// The maximum named pipe instance count has been reached. | 790 | /// The maximum named pipe instance count has been reached. |
| 1153 | INSTANCE_NOT_AVAILABLE = 0xC00000AB, | 791 | INSTANCE_NOT_AVAILABLE = 0xC00000AB, |
| 1154 | |||
| 1155 | /// An instance of a named pipe cannot be found in the listening state. | 792 | /// An instance of a named pipe cannot be found in the listening state. |
| 1156 | PIPE_NOT_AVAILABLE = 0xC00000AC, | 793 | PIPE_NOT_AVAILABLE = 0xC00000AC, |
| 1157 | |||
| 1158 | /// The named pipe is not in the connected or closing state. | 794 | /// The named pipe is not in the connected or closing state. |
| 1159 | INVALID_PIPE_STATE = 0xC00000AD, | 795 | INVALID_PIPE_STATE = 0xC00000AD, |
| 1160 | |||
| 1161 | /// The specified pipe is set to complete operations and there are current I/O operations queued so that it cannot be changed to queue operations. | 796 | /// The specified pipe is set to complete operations and there are current I/O operations queued so that it cannot be changed to queue operations. |
| 1162 | PIPE_BUSY = 0xC00000AE, | 797 | PIPE_BUSY = 0xC00000AE, |
| 1163 | |||
| 1164 | /// The specified handle is not open to the server end of the named pipe. | 798 | /// The specified handle is not open to the server end of the named pipe. |
| 1165 | ILLEGAL_FUNCTION = 0xC00000AF, | 799 | ILLEGAL_FUNCTION = 0xC00000AF, |
| 1166 | |||
| 1167 | /// The specified named pipe is in the disconnected state. | 800 | /// The specified named pipe is in the disconnected state. |
| 1168 | PIPE_DISCONNECTED = 0xC00000B0, | 801 | PIPE_DISCONNECTED = 0xC00000B0, |
| 1169 | |||
| 1170 | /// The specified named pipe is in the closing state. | 802 | /// The specified named pipe is in the closing state. |
| 1171 | PIPE_CLOSING = 0xC00000B1, | 803 | PIPE_CLOSING = 0xC00000B1, |
| 1172 | |||
| 1173 | /// The specified named pipe is in the connected state. | 804 | /// The specified named pipe is in the connected state. |
| 1174 | PIPE_CONNECTED = 0xC00000B2, | 805 | PIPE_CONNECTED = 0xC00000B2, |
| 1175 | |||
| 1176 | /// The specified named pipe is in the listening state. | 806 | /// The specified named pipe is in the listening state. |
| 1177 | PIPE_LISTENING = 0xC00000B3, | 807 | PIPE_LISTENING = 0xC00000B3, |
| 1178 | |||
| 1179 | /// The specified named pipe is not in message mode. | 808 | /// The specified named pipe is not in message mode. |
| 1180 | INVALID_READ_MODE = 0xC00000B4, | 809 | INVALID_READ_MODE = 0xC00000B4, |
| 1181 | |||
| 1182 | /// {Device Timeout} The specified I/O operation on %hs was not completed before the time-out period expired. | 810 | /// {Device Timeout} The specified I/O operation on %hs was not completed before the time-out period expired. |
| 1183 | IO_TIMEOUT = 0xC00000B5, | 811 | IO_TIMEOUT = 0xC00000B5, |
| 1184 | |||
| 1185 | /// The specified file has been closed by another process. | 812 | /// The specified file has been closed by another process. |
| 1186 | FILE_FORCED_CLOSED = 0xC00000B6, | 813 | FILE_FORCED_CLOSED = 0xC00000B6, |
| 1187 | |||
| 1188 | /// Profiling is not started. | 814 | /// Profiling is not started. |
| 1189 | PROFILING_NOT_STARTED = 0xC00000B7, | 815 | PROFILING_NOT_STARTED = 0xC00000B7, |
| 1190 | |||
| 1191 | /// Profiling is not stopped. | 816 | /// Profiling is not stopped. |
| 1192 | PROFILING_NOT_STOPPED = 0xC00000B8, | 817 | PROFILING_NOT_STOPPED = 0xC00000B8, |
| 1193 | |||
| 1194 | /// The passed ACL did not contain the minimum required information. | 818 | /// The passed ACL did not contain the minimum required information. |
| 1195 | COULD_NOT_INTERPRET = 0xC00000B9, | 819 | COULD_NOT_INTERPRET = 0xC00000B9, |
| 1196 | |||
| 1197 | /// The file that was specified as a target is a directory, and the caller specified that it could be anything but a directory. | 820 | /// The file that was specified as a target is a directory, and the caller specified that it could be anything but a directory. |
| 1198 | FILE_IS_A_DIRECTORY = 0xC00000BA, | 821 | FILE_IS_A_DIRECTORY = 0xC00000BA, |
| 1199 | |||
| 1200 | /// The request is not supported. | 822 | /// The request is not supported. |
| 1201 | NOT_SUPPORTED = 0xC00000BB, | 823 | NOT_SUPPORTED = 0xC00000BB, |
| 1202 | |||
| 1203 | /// This remote computer is not listening. | 824 | /// This remote computer is not listening. |
| 1204 | REMOTE_NOT_LISTENING = 0xC00000BC, | 825 | REMOTE_NOT_LISTENING = 0xC00000BC, |
| 1205 | |||
| 1206 | /// A duplicate name exists on the network. | 826 | /// A duplicate name exists on the network. |
| 1207 | DUPLICATE_NAME = 0xC00000BD, | 827 | DUPLICATE_NAME = 0xC00000BD, |
| 1208 | |||
| 1209 | /// The network path cannot be located. | 828 | /// The network path cannot be located. |
| 1210 | BAD_NETWORK_PATH = 0xC00000BE, | 829 | BAD_NETWORK_PATH = 0xC00000BE, |
| 1211 | |||
| 1212 | /// The network is busy. | 830 | /// The network is busy. |
| 1213 | NETWORK_BUSY = 0xC00000BF, | 831 | NETWORK_BUSY = 0xC00000BF, |
| 1214 | |||
| 1215 | /// This device does not exist. | 832 | /// This device does not exist. |
| 1216 | DEVICE_DOES_NOT_EXIST = 0xC00000C0, | 833 | DEVICE_DOES_NOT_EXIST = 0xC00000C0, |
| 1217 | |||
| 1218 | /// The network BIOS command limit has been reached. | 834 | /// The network BIOS command limit has been reached. |
| 1219 | TOO_MANY_COMMANDS = 0xC00000C1, | 835 | TOO_MANY_COMMANDS = 0xC00000C1, |
| 1220 | |||
| 1221 | /// An I/O adapter hardware error has occurred. | 836 | /// An I/O adapter hardware error has occurred. |
| 1222 | ADAPTER_HARDWARE_ERROR = 0xC00000C2, | 837 | ADAPTER_HARDWARE_ERROR = 0xC00000C2, |
| 1223 | |||
| 1224 | /// The network responded incorrectly. | 838 | /// The network responded incorrectly. |
| 1225 | INVALID_NETWORK_RESPONSE = 0xC00000C3, | 839 | INVALID_NETWORK_RESPONSE = 0xC00000C3, |
| 1226 | |||
| 1227 | /// An unexpected network error occurred. | 840 | /// An unexpected network error occurred. |
| 1228 | UNEXPECTED_NETWORK_ERROR = 0xC00000C4, | 841 | UNEXPECTED_NETWORK_ERROR = 0xC00000C4, |
| 1229 | |||
| 1230 | /// The remote adapter is not compatible. | 842 | /// The remote adapter is not compatible. |
| 1231 | BAD_REMOTE_ADAPTER = 0xC00000C5, | 843 | BAD_REMOTE_ADAPTER = 0xC00000C5, |
| 1232 | |||
| 1233 | /// The print queue is full. | 844 | /// The print queue is full. |
| 1234 | PRINT_QUEUE_FULL = 0xC00000C6, | 845 | PRINT_QUEUE_FULL = 0xC00000C6, |
| 1235 | |||
| 1236 | /// Space to store the file that is waiting to be printed is not available on the server. | 846 | /// Space to store the file that is waiting to be printed is not available on the server. |
| 1237 | NO_SPOOL_SPACE = 0xC00000C7, | 847 | NO_SPOOL_SPACE = 0xC00000C7, |
| 1238 | |||
| 1239 | /// The requested print file has been canceled. | 848 | /// The requested print file has been canceled. |
| 1240 | PRINT_CANCELLED = 0xC00000C8, | 849 | PRINT_CANCELLED = 0xC00000C8, |
| 1241 | |||
| 1242 | /// The network name was deleted. | 850 | /// The network name was deleted. |
| 1243 | NETWORK_NAME_DELETED = 0xC00000C9, | 851 | NETWORK_NAME_DELETED = 0xC00000C9, |
| 1244 | |||
| 1245 | /// Network access is denied. | 852 | /// Network access is denied. |
| 1246 | NETWORK_ACCESS_DENIED = 0xC00000CA, | 853 | NETWORK_ACCESS_DENIED = 0xC00000CA, |
| 1247 | |||
| 1248 | /// {Incorrect Network Resource Type} The specified device type (LPT, for example) conflicts with the actual device type on the remote resource. | 854 | /// {Incorrect Network Resource Type} The specified device type (LPT, for example) conflicts with the actual device type on the remote resource. |
| 1249 | BAD_DEVICE_TYPE = 0xC00000CB, | 855 | BAD_DEVICE_TYPE = 0xC00000CB, |
| 1250 | |||
| 1251 | /// {Network Name Not Found} The specified share name cannot be found on the remote server. | 856 | /// {Network Name Not Found} The specified share name cannot be found on the remote server. |
| 1252 | BAD_NETWORK_NAME = 0xC00000CC, | 857 | BAD_NETWORK_NAME = 0xC00000CC, |
| 1253 | |||
| 1254 | /// The name limit for the network adapter card of the local computer was exceeded. | 858 | /// The name limit for the network adapter card of the local computer was exceeded. |
| 1255 | TOO_MANY_NAMES = 0xC00000CD, | 859 | TOO_MANY_NAMES = 0xC00000CD, |
| 1256 | |||
| 1257 | /// The network BIOS session limit was exceeded. | 860 | /// The network BIOS session limit was exceeded. |
| 1258 | TOO_MANY_SESSIONS = 0xC00000CE, | 861 | TOO_MANY_SESSIONS = 0xC00000CE, |
| 1259 | |||
| 1260 | /// File sharing has been temporarily paused. | 862 | /// File sharing has been temporarily paused. |
| 1261 | SHARING_PAUSED = 0xC00000CF, | 863 | SHARING_PAUSED = 0xC00000CF, |
| 1262 | |||
| 1263 | /// No more connections can be made to this remote computer at this time because the computer has already accepted the maximum number of connections. | 864 | /// No more connections can be made to this remote computer at this time because the computer has already accepted the maximum number of connections. |
| 1264 | REQUEST_NOT_ACCEPTED = 0xC00000D0, | 865 | REQUEST_NOT_ACCEPTED = 0xC00000D0, |
| 1265 | |||
| 1266 | /// Print or disk redirection is temporarily paused. | 866 | /// Print or disk redirection is temporarily paused. |
| 1267 | REDIRECTOR_PAUSED = 0xC00000D1, | 867 | REDIRECTOR_PAUSED = 0xC00000D1, |
| 1268 | |||
| 1269 | /// A network data fault occurred. | 868 | /// A network data fault occurred. |
| 1270 | NET_WRITE_FAULT = 0xC00000D2, | 869 | NET_WRITE_FAULT = 0xC00000D2, |
| 1271 | |||
| 1272 | /// The number of active profiling objects is at the maximum and no more can be started. | 870 | /// The number of active profiling objects is at the maximum and no more can be started. |
| 1273 | PROFILING_AT_LIMIT = 0xC00000D3, | 871 | PROFILING_AT_LIMIT = 0xC00000D3, |
| 1274 | |||
| 1275 | /// {Incorrect Volume} The destination file of a rename request is located on a different device than the source of the rename request. | 872 | /// {Incorrect Volume} The destination file of a rename request is located on a different device than the source of the rename request. |
| 1276 | NOT_SAME_DEVICE = 0xC00000D4, | 873 | NOT_SAME_DEVICE = 0xC00000D4, |
| 1277 | |||
| 1278 | /// The specified file has been renamed and thus cannot be modified. | 874 | /// The specified file has been renamed and thus cannot be modified. |
| 1279 | FILE_RENAMED = 0xC00000D5, | 875 | FILE_RENAMED = 0xC00000D5, |
| 1280 | |||
| 1281 | /// {Network Request Timeout} The session with a remote server has been disconnected because the time-out interval for a request has expired. | 876 | /// {Network Request Timeout} The session with a remote server has been disconnected because the time-out interval for a request has expired. |
| 1282 | VIRTUAL_CIRCUIT_CLOSED = 0xC00000D6, | 877 | VIRTUAL_CIRCUIT_CLOSED = 0xC00000D6, |
| 1283 | |||
| 1284 | /// Indicates an attempt was made to operate on the security of an object that does not have security associated with it. | 878 | /// Indicates an attempt was made to operate on the security of an object that does not have security associated with it. |
| 1285 | NO_SECURITY_ON_OBJECT = 0xC00000D7, | 879 | NO_SECURITY_ON_OBJECT = 0xC00000D7, |
| 1286 | |||
| 1287 | /// Used to indicate that an operation cannot continue without blocking for I/O. | 880 | /// Used to indicate that an operation cannot continue without blocking for I/O. |
| 1288 | CANT_WAIT = 0xC00000D8, | 881 | CANT_WAIT = 0xC00000D8, |
| 1289 | |||
| 1290 | /// Used to indicate that a read operation was done on an empty pipe. | 882 | /// Used to indicate that a read operation was done on an empty pipe. |
| 1291 | PIPE_EMPTY = 0xC00000D9, | 883 | PIPE_EMPTY = 0xC00000D9, |
| 1292 | |||
| 1293 | /// Configuration information could not be read from the domain controller, either because the machine is unavailable or access has been denied. | 884 | /// Configuration information could not be read from the domain controller, either because the machine is unavailable or access has been denied. |
| 1294 | CANT_ACCESS_DOMAIN_INFO = 0xC00000DA, | 885 | CANT_ACCESS_DOMAIN_INFO = 0xC00000DA, |
| 1295 | |||
| 1296 | /// Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process. | 886 | /// Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process. |
| 1297 | CANT_TERMINATE_SELF = 0xC00000DB, | 887 | CANT_TERMINATE_SELF = 0xC00000DB, |
| 1298 | |||
| 1299 | /// Indicates the Sam Server was in the wrong state to perform the desired operation. | 888 | /// Indicates the Sam Server was in the wrong state to perform the desired operation. |
| 1300 | INVALID_SERVER_STATE = 0xC00000DC, | 889 | INVALID_SERVER_STATE = 0xC00000DC, |
| 1301 | |||
| 1302 | /// Indicates the domain was in the wrong state to perform the desired operation. | 890 | /// Indicates the domain was in the wrong state to perform the desired operation. |
| 1303 | INVALID_DOMAIN_STATE = 0xC00000DD, | 891 | INVALID_DOMAIN_STATE = 0xC00000DD, |
| 1304 | |||
| 1305 | /// This operation is only allowed for the primary domain controller of the domain. | 892 | /// This operation is only allowed for the primary domain controller of the domain. |
| 1306 | INVALID_DOMAIN_ROLE = 0xC00000DE, | 893 | INVALID_DOMAIN_ROLE = 0xC00000DE, |
| 1307 | |||
| 1308 | /// The specified domain did not exist. | 894 | /// The specified domain did not exist. |
| 1309 | NO_SUCH_DOMAIN = 0xC00000DF, | 895 | NO_SUCH_DOMAIN = 0xC00000DF, |
| 1310 | |||
| 1311 | /// The specified domain already exists. | 896 | /// The specified domain already exists. |
| 1312 | DOMAIN_EXISTS = 0xC00000E0, | 897 | DOMAIN_EXISTS = 0xC00000E0, |
| 1313 | |||
| 1314 | /// An attempt was made to exceed the limit on the number of domains per server for this release. | 898 | /// An attempt was made to exceed the limit on the number of domains per server for this release. |
| 1315 | DOMAIN_LIMIT_EXCEEDED = 0xC00000E1, | 899 | DOMAIN_LIMIT_EXCEEDED = 0xC00000E1, |
| 1316 | |||
| 1317 | /// An error status returned when the opportunistic lock (oplock) request is denied. | 900 | /// An error status returned when the opportunistic lock (oplock) request is denied. |
| 1318 | OPLOCK_NOT_GRANTED = 0xC00000E2, | 901 | OPLOCK_NOT_GRANTED = 0xC00000E2, |
| 1319 | |||
| 1320 | /// An error status returned when an invalid opportunistic lock (oplock) acknowledgment is received by a file system. | 902 | /// An error status returned when an invalid opportunistic lock (oplock) acknowledgment is received by a file system. |
| 1321 | INVALID_OPLOCK_PROTOCOL = 0xC00000E3, | 903 | INVALID_OPLOCK_PROTOCOL = 0xC00000E3, |
| 1322 | |||
| 1323 | /// This error indicates that the requested operation cannot be completed due to a catastrophic media failure or an on-disk data structure corruption. | 904 | /// This error indicates that the requested operation cannot be completed due to a catastrophic media failure or an on-disk data structure corruption. |
| 1324 | INTERNAL_DB_CORRUPTION = 0xC00000E4, | 905 | INTERNAL_DB_CORRUPTION = 0xC00000E4, |
| 1325 | |||
| 1326 | /// An internal error occurred. | 906 | /// An internal error occurred. |
| 1327 | INTERNAL_ERROR = 0xC00000E5, | 907 | INTERNAL_ERROR = 0xC00000E5, |
| 1328 | |||
| 1329 | /// Indicates generic access types were contained in an access mask which should already be mapped to non-generic access types. | 908 | /// Indicates generic access types were contained in an access mask which should already be mapped to non-generic access types. |
| 1330 | GENERIC_NOT_MAPPED = 0xC00000E6, | 909 | GENERIC_NOT_MAPPED = 0xC00000E6, |
| 1331 | |||
| 1332 | /// Indicates a security descriptor is not in the necessary format (absolute or self-relative). | 910 | /// Indicates a security descriptor is not in the necessary format (absolute or self-relative). |
| 1333 | BAD_DESCRIPTOR_FORMAT = 0xC00000E7, | 911 | BAD_DESCRIPTOR_FORMAT = 0xC00000E7, |
| 1334 | |||
| 1335 | /// An access to a user buffer failed at an expected point in time. | 912 | /// An access to a user buffer failed at an expected point in time. |
| 1336 | /// This code is defined because the caller does not want to accept STATUS_ACCESS_VIOLATION in its filter. | 913 | /// This code is defined because the caller does not want to accept STATUS_ACCESS_VIOLATION in its filter. |
| 1337 | INVALID_USER_BUFFER = 0xC00000E8, | 914 | INVALID_USER_BUFFER = 0xC00000E8, |
| 1338 | |||
| 1339 | /// If an I/O error that is not defined in the standard FsRtl filter is returned, it is converted to the following error, which is guaranteed to be in the filter. | 915 | /// If an I/O error that is not defined in the standard FsRtl filter is returned, it is converted to the following error, which is guaranteed to be in the filter. |
| 1340 | /// In this case, information is lost; however, the filter correctly handles the exception. | 916 | /// In this case, information is lost; however, the filter correctly handles the exception. |
| 1341 | UNEXPECTED_IO_ERROR = 0xC00000E9, | 917 | UNEXPECTED_IO_ERROR = 0xC00000E9, |
| 1342 | |||
| 1343 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. | 918 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. |
| 1344 | /// In this case, information is lost; however, the filter correctly handles the exception. | 919 | /// In this case, information is lost; however, the filter correctly handles the exception. |
| 1345 | UNEXPECTED_MM_CREATE_ERR = 0xC00000EA, | 920 | UNEXPECTED_MM_CREATE_ERR = 0xC00000EA, |
| 1346 | |||
| 1347 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. | 921 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. |
| 1348 | /// In this case, information is lost; however, the filter correctly handles the exception. | 922 | /// In this case, information is lost; however, the filter correctly handles the exception. |
| 1349 | UNEXPECTED_MM_MAP_ERROR = 0xC00000EB, | 923 | UNEXPECTED_MM_MAP_ERROR = 0xC00000EB, |
| 1350 | |||
| 1351 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. | 924 | /// If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. |
| 1352 | /// In this case, information is lost; however, the filter correctly handles the exception. | 925 | /// In this case, information is lost; however, the filter correctly handles the exception. |
| 1353 | UNEXPECTED_MM_EXTEND_ERR = 0xC00000EC, | 926 | UNEXPECTED_MM_EXTEND_ERR = 0xC00000EC, |
| 1354 | |||
| 1355 | /// The requested action is restricted for use by logon processes only. | 927 | /// The requested action is restricted for use by logon processes only. |
| 1356 | /// The calling process has not registered as a logon process. | 928 | /// The calling process has not registered as a logon process. |
| 1357 | NOT_LOGON_PROCESS = 0xC00000ED, | 929 | NOT_LOGON_PROCESS = 0xC00000ED, |
| 1358 | |||
| 1359 | /// An attempt has been made to start a new session manager or LSA logon session by using an ID that is already in use. | 930 | /// An attempt has been made to start a new session manager or LSA logon session by using an ID that is already in use. |
| 1360 | LOGON_SESSION_EXISTS = 0xC00000EE, | 931 | LOGON_SESSION_EXISTS = 0xC00000EE, |
| 1361 | |||
| 1362 | /// An invalid parameter was passed to a service or function as the first argument. | 932 | /// An invalid parameter was passed to a service or function as the first argument. |
| 1363 | INVALID_PARAMETER_1 = 0xC00000EF, | 933 | INVALID_PARAMETER_1 = 0xC00000EF, |
| 1364 | |||
| 1365 | /// An invalid parameter was passed to a service or function as the second argument. | 934 | /// An invalid parameter was passed to a service or function as the second argument. |
| 1366 | INVALID_PARAMETER_2 = 0xC00000F0, | 935 | INVALID_PARAMETER_2 = 0xC00000F0, |
| 1367 | |||
| 1368 | /// An invalid parameter was passed to a service or function as the third argument. | 936 | /// An invalid parameter was passed to a service or function as the third argument. |
| 1369 | INVALID_PARAMETER_3 = 0xC00000F1, | 937 | INVALID_PARAMETER_3 = 0xC00000F1, |
| 1370 | |||
| 1371 | /// An invalid parameter was passed to a service or function as the fourth argument. | 938 | /// An invalid parameter was passed to a service or function as the fourth argument. |
| 1372 | INVALID_PARAMETER_4 = 0xC00000F2, | 939 | INVALID_PARAMETER_4 = 0xC00000F2, |
| 1373 | |||
| 1374 | /// An invalid parameter was passed to a service or function as the fifth argument. | 940 | /// An invalid parameter was passed to a service or function as the fifth argument. |
| 1375 | INVALID_PARAMETER_5 = 0xC00000F3, | 941 | INVALID_PARAMETER_5 = 0xC00000F3, |
| 1376 | |||
| 1377 | /// An invalid parameter was passed to a service or function as the sixth argument. | 942 | /// An invalid parameter was passed to a service or function as the sixth argument. |
| 1378 | INVALID_PARAMETER_6 = 0xC00000F4, | 943 | INVALID_PARAMETER_6 = 0xC00000F4, |
| 1379 | |||
| 1380 | /// An invalid parameter was passed to a service or function as the seventh argument. | 944 | /// An invalid parameter was passed to a service or function as the seventh argument. |
| 1381 | INVALID_PARAMETER_7 = 0xC00000F5, | 945 | INVALID_PARAMETER_7 = 0xC00000F5, |
| 1382 | |||
| 1383 | /// An invalid parameter was passed to a service or function as the eighth argument. | 946 | /// An invalid parameter was passed to a service or function as the eighth argument. |
| 1384 | INVALID_PARAMETER_8 = 0xC00000F6, | 947 | INVALID_PARAMETER_8 = 0xC00000F6, |
| 1385 | |||
| 1386 | /// An invalid parameter was passed to a service or function as the ninth argument. | 948 | /// An invalid parameter was passed to a service or function as the ninth argument. |
| 1387 | INVALID_PARAMETER_9 = 0xC00000F7, | 949 | INVALID_PARAMETER_9 = 0xC00000F7, |
| 1388 | |||
| 1389 | /// An invalid parameter was passed to a service or function as the tenth argument. | 950 | /// An invalid parameter was passed to a service or function as the tenth argument. |
| 1390 | INVALID_PARAMETER_10 = 0xC00000F8, | 951 | INVALID_PARAMETER_10 = 0xC00000F8, |
| 1391 | |||
| 1392 | /// An invalid parameter was passed to a service or function as the eleventh argument. | 952 | /// An invalid parameter was passed to a service or function as the eleventh argument. |
| 1393 | INVALID_PARAMETER_11 = 0xC00000F9, | 953 | INVALID_PARAMETER_11 = 0xC00000F9, |
| 1394 | |||
| 1395 | /// An invalid parameter was passed to a service or function as the twelfth argument. | 954 | /// An invalid parameter was passed to a service or function as the twelfth argument. |
| 1396 | INVALID_PARAMETER_12 = 0xC00000FA, | 955 | INVALID_PARAMETER_12 = 0xC00000FA, |
| 1397 | |||
| 1398 | /// An attempt was made to access a network file, but the network software was not yet started. | 956 | /// An attempt was made to access a network file, but the network software was not yet started. |
| 1399 | REDIRECTOR_NOT_STARTED = 0xC00000FB, | 957 | REDIRECTOR_NOT_STARTED = 0xC00000FB, |
| 1400 | |||
| 1401 | /// An attempt was made to start the redirector, but the redirector has already been started. | 958 | /// An attempt was made to start the redirector, but the redirector has already been started. |
| 1402 | REDIRECTOR_STARTED = 0xC00000FC, | 959 | REDIRECTOR_STARTED = 0xC00000FC, |
| 1403 | |||
| 1404 | /// A new guard page for the stack cannot be created. | 960 | /// A new guard page for the stack cannot be created. |
| 1405 | STACK_OVERFLOW = 0xC00000FD, | 961 | STACK_OVERFLOW = 0xC00000FD, |
| 1406 | |||
| 1407 | /// A specified authentication package is unknown. | 962 | /// A specified authentication package is unknown. |
| 1408 | NO_SUCH_PACKAGE = 0xC00000FE, | 963 | NO_SUCH_PACKAGE = 0xC00000FE, |
| 1409 | |||
| 1410 | /// A malformed function table was encountered during an unwind operation. | 964 | /// A malformed function table was encountered during an unwind operation. |
| 1411 | BAD_FUNCTION_TABLE = 0xC00000FF, | 965 | BAD_FUNCTION_TABLE = 0xC00000FF, |
| 1412 | |||
| 1413 | /// Indicates the specified environment variable name was not found in the specified environment block. | 966 | /// Indicates the specified environment variable name was not found in the specified environment block. |
| 1414 | VARIABLE_NOT_FOUND = 0xC0000100, | 967 | VARIABLE_NOT_FOUND = 0xC0000100, |
| 1415 | |||
| 1416 | /// Indicates that the directory trying to be deleted is not empty. | 968 | /// Indicates that the directory trying to be deleted is not empty. |
| 1417 | DIRECTORY_NOT_EMPTY = 0xC0000101, | 969 | DIRECTORY_NOT_EMPTY = 0xC0000101, |
| 1418 | |||
| 1419 | /// {Corrupt File} The file or directory %hs is corrupt and unreadable. Run the Chkdsk utility. | 970 | /// {Corrupt File} The file or directory %hs is corrupt and unreadable. Run the Chkdsk utility. |
| 1420 | FILE_CORRUPT_ERROR = 0xC0000102, | 971 | FILE_CORRUPT_ERROR = 0xC0000102, |
| 1421 | |||
| 1422 | /// A requested opened file is not a directory. | 972 | /// A requested opened file is not a directory. |
| 1423 | NOT_A_DIRECTORY = 0xC0000103, | 973 | NOT_A_DIRECTORY = 0xC0000103, |
| 1424 | |||
| 1425 | /// The logon session is not in a state that is consistent with the requested operation. | 974 | /// The logon session is not in a state that is consistent with the requested operation. |
| 1426 | BAD_LOGON_SESSION_STATE = 0xC0000104, | 975 | BAD_LOGON_SESSION_STATE = 0xC0000104, |
| 1427 | |||
| 1428 | /// An internal LSA error has occurred. | 976 | /// An internal LSA error has occurred. |
| 1429 | /// An authentication package has requested the creation of a logon session but the ID of an already existing logon session has been specified. | 977 | /// An authentication package has requested the creation of a logon session but the ID of an already existing logon session has been specified. |
| 1430 | LOGON_SESSION_COLLISION = 0xC0000105, | 978 | LOGON_SESSION_COLLISION = 0xC0000105, |
| 1431 | |||
| 1432 | /// A specified name string is too long for its intended use. | 979 | /// A specified name string is too long for its intended use. |
| 1433 | NAME_TOO_LONG = 0xC0000106, | 980 | NAME_TOO_LONG = 0xC0000106, |
| 1434 | |||
| 1435 | /// The user attempted to force close the files on a redirected drive, but there were opened files on the drive, and the user did not specify a sufficient level of force. | 981 | /// The user attempted to force close the files on a redirected drive, but there were opened files on the drive, and the user did not specify a sufficient level of force. |
| 1436 | FILES_OPEN = 0xC0000107, | 982 | FILES_OPEN = 0xC0000107, |
| 1437 | |||
| 1438 | /// The user attempted to force close the files on a redirected drive, but there were opened directories on the drive, and the user did not specify a sufficient level of force. | 983 | /// The user attempted to force close the files on a redirected drive, but there were opened directories on the drive, and the user did not specify a sufficient level of force. |
| 1439 | CONNECTION_IN_USE = 0xC0000108, | 984 | CONNECTION_IN_USE = 0xC0000108, |
| 1440 | |||
| 1441 | /// RtlFindMessage could not locate the requested message ID in the message table resource. | 985 | /// RtlFindMessage could not locate the requested message ID in the message table resource. |
| 1442 | MESSAGE_NOT_FOUND = 0xC0000109, | 986 | MESSAGE_NOT_FOUND = 0xC0000109, |
| 1443 | |||
| 1444 | /// An attempt was made to duplicate an object handle into or out of an exiting process. | 987 | /// An attempt was made to duplicate an object handle into or out of an exiting process. |
| 1445 | PROCESS_IS_TERMINATING = 0xC000010A, | 988 | PROCESS_IS_TERMINATING = 0xC000010A, |
| 1446 | |||
| 1447 | /// Indicates an invalid value has been provided for the LogonType requested. | 989 | /// Indicates an invalid value has been provided for the LogonType requested. |
| 1448 | INVALID_LOGON_TYPE = 0xC000010B, | 990 | INVALID_LOGON_TYPE = 0xC000010B, |
| 1449 | |||
| 1450 | /// Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. | 991 | /// Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. |
| 1451 | /// This causes the protection attempt to fail, which might cause a file creation attempt to fail. | 992 | /// This causes the protection attempt to fail, which might cause a file creation attempt to fail. |
| 1452 | NO_GUID_TRANSLATION = 0xC000010C, | 993 | NO_GUID_TRANSLATION = 0xC000010C, |
| 1453 | |||
| 1454 | /// Indicates that an attempt has been made to impersonate via a named pipe that has not yet been read from. | 994 | /// Indicates that an attempt has been made to impersonate via a named pipe that has not yet been read from. |
| 1455 | CANNOT_IMPERSONATE = 0xC000010D, | 995 | CANNOT_IMPERSONATE = 0xC000010D, |
| 1456 | |||
| 1457 | /// Indicates that the specified image is already loaded. | 996 | /// Indicates that the specified image is already loaded. |
| 1458 | IMAGE_ALREADY_LOADED = 0xC000010E, | 997 | IMAGE_ALREADY_LOADED = 0xC000010E, |
| 1459 | |||
| 1460 | /// Indicates that an attempt was made to change the size of the LDT for a process that has no LDT. | 998 | /// Indicates that an attempt was made to change the size of the LDT for a process that has no LDT. |
| 1461 | NO_LDT = 0xC0000117, | 999 | NO_LDT = 0xC0000117, |
| 1462 | |||
| 1463 | /// Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors. | 1000 | /// Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors. |
| 1464 | INVALID_LDT_SIZE = 0xC0000118, | 1001 | INVALID_LDT_SIZE = 0xC0000118, |
| 1465 | |||
| 1466 | /// Indicates that the starting value for the LDT information was not an integral multiple of the selector size. | 1002 | /// Indicates that the starting value for the LDT information was not an integral multiple of the selector size. |
| 1467 | INVALID_LDT_OFFSET = 0xC0000119, | 1003 | INVALID_LDT_OFFSET = 0xC0000119, |
| 1468 | |||
| 1469 | /// Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors. | 1004 | /// Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors. |
| 1470 | INVALID_LDT_DESCRIPTOR = 0xC000011A, | 1005 | INVALID_LDT_DESCRIPTOR = 0xC000011A, |
| 1471 | |||
| 1472 | /// The specified image file did not have the correct format. It appears to be NE format. | 1006 | /// The specified image file did not have the correct format. It appears to be NE format. |
| 1473 | INVALID_IMAGE_NE_FORMAT = 0xC000011B, | 1007 | INVALID_IMAGE_NE_FORMAT = 0xC000011B, |
| 1474 | |||
| 1475 | /// Indicates that the transaction state of a registry subtree is incompatible with the requested operation. | 1008 | /// Indicates that the transaction state of a registry subtree is incompatible with the requested operation. |
| 1476 | /// For example, a request has been made to start a new transaction with one already in progress, or a request has been made to apply a transaction when one is not currently in progress. | 1009 | /// For example, a request has been made to start a new transaction with one already in progress, or a request has been made to apply a transaction when one is not currently in progress. |
| 1477 | RXACT_INVALID_STATE = 0xC000011C, | 1010 | RXACT_INVALID_STATE = 0xC000011C, |
| 1478 | |||
| 1479 | /// Indicates an error has occurred during a registry transaction commit. | 1011 | /// Indicates an error has occurred during a registry transaction commit. |
| 1480 | /// The database has been left in an unknown, but probably inconsistent, state. | 1012 | /// The database has been left in an unknown, but probably inconsistent, state. |
| 1481 | /// The state of the registry transaction is left as COMMITTING. | 1013 | /// The state of the registry transaction is left as COMMITTING. |
| 1482 | RXACT_COMMIT_FAILURE = 0xC000011D, | 1014 | RXACT_COMMIT_FAILURE = 0xC000011D, |
| 1483 | |||
| 1484 | /// An attempt was made to map a file of size zero with the maximum size specified as zero. | 1015 | /// An attempt was made to map a file of size zero with the maximum size specified as zero. |
| 1485 | MAPPED_FILE_SIZE_ZERO = 0xC000011E, | 1016 | MAPPED_FILE_SIZE_ZERO = 0xC000011E, |
| 1486 | |||
| 1487 | /// Too many files are opened on a remote server. | 1017 | /// Too many files are opened on a remote server. |
| 1488 | /// This error should only be returned by the Windows redirector on a remote drive. | 1018 | /// This error should only be returned by the Windows redirector on a remote drive. |
| 1489 | TOO_MANY_OPENED_FILES = 0xC000011F, | 1019 | TOO_MANY_OPENED_FILES = 0xC000011F, |
| 1490 | |||
| 1491 | /// The I/O request was canceled. | 1020 | /// The I/O request was canceled. |
| 1492 | CANCELLED = 0xC0000120, | 1021 | CANCELLED = 0xC0000120, |
| 1493 | |||
| 1494 | /// An attempt has been made to remove a file or directory that cannot be deleted. | 1022 | /// An attempt has been made to remove a file or directory that cannot be deleted. |
| 1495 | CANNOT_DELETE = 0xC0000121, | 1023 | CANNOT_DELETE = 0xC0000121, |
| 1496 | |||
| 1497 | /// Indicates a name that was specified as a remote computer name is syntactically invalid. | 1024 | /// Indicates a name that was specified as a remote computer name is syntactically invalid. |
| 1498 | INVALID_COMPUTER_NAME = 0xC0000122, | 1025 | INVALID_COMPUTER_NAME = 0xC0000122, |
| 1499 | |||
| 1500 | /// An I/O request other than close was performed on a file after it was deleted, which can only happen to a request that did not complete before the last handle was closed via NtClose. | 1026 | /// An I/O request other than close was performed on a file after it was deleted, which can only happen to a request that did not complete before the last handle was closed via NtClose. |
| 1501 | FILE_DELETED = 0xC0000123, | 1027 | FILE_DELETED = 0xC0000123, |
| 1502 | |||
| 1503 | /// Indicates an operation that is incompatible with built-in accounts has been attempted on a built-in (special) SAM account. For example, built-in accounts cannot be deleted. | 1028 | /// Indicates an operation that is incompatible with built-in accounts has been attempted on a built-in (special) SAM account. For example, built-in accounts cannot be deleted. |
| 1504 | SPECIAL_ACCOUNT = 0xC0000124, | 1029 | SPECIAL_ACCOUNT = 0xC0000124, |
| 1505 | |||
| 1506 | /// The operation requested cannot be performed on the specified group because it is a built-in special group. | 1030 | /// The operation requested cannot be performed on the specified group because it is a built-in special group. |
| 1507 | SPECIAL_GROUP = 0xC0000125, | 1031 | SPECIAL_GROUP = 0xC0000125, |
| 1508 | |||
| 1509 | /// The operation requested cannot be performed on the specified user because it is a built-in special user. | 1032 | /// The operation requested cannot be performed on the specified user because it is a built-in special user. |
| 1510 | SPECIAL_USER = 0xC0000126, | 1033 | SPECIAL_USER = 0xC0000126, |
| 1511 | |||
| 1512 | /// Indicates a member cannot be removed from a group because the group is currently the member's primary group. | 1034 | /// Indicates a member cannot be removed from a group because the group is currently the member's primary group. |
| 1513 | MEMBERS_PRIMARY_GROUP = 0xC0000127, | 1035 | MEMBERS_PRIMARY_GROUP = 0xC0000127, |
| 1514 | |||
| 1515 | /// An I/O request other than close and several other special case operations was attempted using a file object that had already been closed. | 1036 | /// An I/O request other than close and several other special case operations was attempted using a file object that had already been closed. |
| 1516 | FILE_CLOSED = 0xC0000128, | 1037 | FILE_CLOSED = 0xC0000128, |
| 1517 | |||
| 1518 | /// Indicates a process has too many threads to perform the requested action. | 1038 | /// Indicates a process has too many threads to perform the requested action. |
| 1519 | /// For example, assignment of a primary token can be performed only when a process has zero or one threads. | 1039 | /// For example, assignment of a primary token can be performed only when a process has zero or one threads. |
| 1520 | TOO_MANY_THREADS = 0xC0000129, | 1040 | TOO_MANY_THREADS = 0xC0000129, |
| 1521 | |||
| 1522 | /// An attempt was made to operate on a thread within a specific process, but the specified thread is not in the specified process. | 1041 | /// An attempt was made to operate on a thread within a specific process, but the specified thread is not in the specified process. |
| 1523 | THREAD_NOT_IN_PROCESS = 0xC000012A, | 1042 | THREAD_NOT_IN_PROCESS = 0xC000012A, |
| 1524 | |||
| 1525 | /// An attempt was made to establish a token for use as a primary token but the token is already in use. | 1043 | /// An attempt was made to establish a token for use as a primary token but the token is already in use. |
| 1526 | /// A token can only be the primary token of one process at a time. | 1044 | /// A token can only be the primary token of one process at a time. |
| 1527 | TOKEN_ALREADY_IN_USE = 0xC000012B, | 1045 | TOKEN_ALREADY_IN_USE = 0xC000012B, |
| 1528 | |||
| 1529 | /// The page file quota was exceeded. | 1046 | /// The page file quota was exceeded. |
| 1530 | PAGEFILE_QUOTA_EXCEEDED = 0xC000012C, | 1047 | PAGEFILE_QUOTA_EXCEEDED = 0xC000012C, |
| 1531 | |||
| 1532 | /// {Out of Virtual Memory} Your system is low on virtual memory. | 1048 | /// {Out of Virtual Memory} Your system is low on virtual memory. |
| 1533 | /// To ensure that Windows runs correctly, increase the size of your virtual memory paging file. For more information, see Help. | 1049 | /// To ensure that Windows runs correctly, increase the size of your virtual memory paging file. For more information, see Help. |
| 1534 | COMMITMENT_LIMIT = 0xC000012D, | 1050 | COMMITMENT_LIMIT = 0xC000012D, |
| 1535 | |||
| 1536 | /// The specified image file did not have the correct format: it appears to be LE format. | 1051 | /// The specified image file did not have the correct format: it appears to be LE format. |
| 1537 | INVALID_IMAGE_LE_FORMAT = 0xC000012E, | 1052 | INVALID_IMAGE_LE_FORMAT = 0xC000012E, |
| 1538 | |||
| 1539 | /// The specified image file did not have the correct format: it did not have an initial MZ. | 1053 | /// The specified image file did not have the correct format: it did not have an initial MZ. |
| 1540 | INVALID_IMAGE_NOT_MZ = 0xC000012F, | 1054 | INVALID_IMAGE_NOT_MZ = 0xC000012F, |
| 1541 | |||
| 1542 | /// The specified image file did not have the correct format: it did not have a proper e_lfarlc in the MZ header. | 1055 | /// The specified image file did not have the correct format: it did not have a proper e_lfarlc in the MZ header. |
| 1543 | INVALID_IMAGE_PROTECT = 0xC0000130, | 1056 | INVALID_IMAGE_PROTECT = 0xC0000130, |
| 1544 | |||
| 1545 | /// The specified image file did not have the correct format: it appears to be a 16-bit Windows image. | 1057 | /// The specified image file did not have the correct format: it appears to be a 16-bit Windows image. |
| 1546 | INVALID_IMAGE_WIN_16 = 0xC0000131, | 1058 | INVALID_IMAGE_WIN_16 = 0xC0000131, |
| 1547 | |||
| 1548 | /// The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role. | 1059 | /// The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role. |
| 1549 | LOGON_SERVER_CONFLICT = 0xC0000132, | 1060 | LOGON_SERVER_CONFLICT = 0xC0000132, |
| 1550 | |||
| 1551 | /// The time at the primary domain controller is different from the time at the backup domain controller or member server by too large an amount. | 1061 | /// The time at the primary domain controller is different from the time at the backup domain controller or member server by too large an amount. |
| 1552 | TIME_DIFFERENCE_AT_DC = 0xC0000133, | 1062 | TIME_DIFFERENCE_AT_DC = 0xC0000133, |
| 1553 | |||
| 1554 | /// On applicable Windows Server releases, the SAM database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required. | 1063 | /// On applicable Windows Server releases, the SAM database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required. |
| 1555 | SYNCHRONIZATION_REQUIRED = 0xC0000134, | 1064 | SYNCHRONIZATION_REQUIRED = 0xC0000134, |
| 1556 | |||
| 1557 | /// {Unable To Locate Component} This application has failed to start because %hs was not found. | 1065 | /// {Unable To Locate Component} This application has failed to start because %hs was not found. |
| 1558 | /// Reinstalling the application might fix this problem. | 1066 | /// Reinstalling the application might fix this problem. |
| 1559 | DLL_NOT_FOUND = 0xC0000135, | 1067 | DLL_NOT_FOUND = 0xC0000135, |
| 1560 | |||
| 1561 | /// The NtCreateFile API failed. This error should never be returned to an application; it is a place holder for the Windows LAN Manager Redirector to use in its internal error-mapping routines. | 1068 | /// The NtCreateFile API failed. This error should never be returned to an application; it is a place holder for the Windows LAN Manager Redirector to use in its internal error-mapping routines. |
| 1562 | OPEN_FAILED = 0xC0000136, | 1069 | OPEN_FAILED = 0xC0000136, |
| 1563 | |||
| 1564 | /// {Privilege Failed} The I/O permissions for the process could not be changed. | 1070 | /// {Privilege Failed} The I/O permissions for the process could not be changed. |
| 1565 | IO_PRIVILEGE_FAILED = 0xC0000137, | 1071 | IO_PRIVILEGE_FAILED = 0xC0000137, |
| 1566 | |||
| 1567 | /// {Ordinal Not Found} The ordinal %ld could not be located in the dynamic link library %hs. | 1072 | /// {Ordinal Not Found} The ordinal %ld could not be located in the dynamic link library %hs. |
| 1568 | ORDINAL_NOT_FOUND = 0xC0000138, | 1073 | ORDINAL_NOT_FOUND = 0xC0000138, |
| 1569 | |||
| 1570 | /// {Entry Point Not Found} The procedure entry point %hs could not be located in the dynamic link library %hs. | 1074 | /// {Entry Point Not Found} The procedure entry point %hs could not be located in the dynamic link library %hs. |
| 1571 | ENTRYPOINT_NOT_FOUND = 0xC0000139, | 1075 | ENTRYPOINT_NOT_FOUND = 0xC0000139, |
| 1572 | |||
| 1573 | /// {Application Exit by CTRL+C} The application terminated as a result of a CTRL+C. | 1076 | /// {Application Exit by CTRL+C} The application terminated as a result of a CTRL+C. |
| 1574 | CONTROL_C_EXIT = 0xC000013A, | 1077 | CONTROL_C_EXIT = 0xC000013A, |
| 1575 | |||
| 1576 | /// {Virtual Circuit Closed} The network transport on your computer has closed a network connection. | 1078 | /// {Virtual Circuit Closed} The network transport on your computer has closed a network connection. |
| 1577 | /// There might or might not be I/O requests outstanding. | 1079 | /// There might or might not be I/O requests outstanding. |
| 1578 | LOCAL_DISCONNECT = 0xC000013B, | 1080 | LOCAL_DISCONNECT = 0xC000013B, |
| 1579 | |||
| 1580 | /// {Virtual Circuit Closed} The network transport on a remote computer has closed a network connection. | 1081 | /// {Virtual Circuit Closed} The network transport on a remote computer has closed a network connection. |
| 1581 | /// There might or might not be I/O requests outstanding. | 1082 | /// There might or might not be I/O requests outstanding. |
| 1582 | REMOTE_DISCONNECT = 0xC000013C, | 1083 | REMOTE_DISCONNECT = 0xC000013C, |
| 1583 | |||
| 1584 | /// {Insufficient Resources on Remote Computer} The remote computer has insufficient resources to complete the network request. | 1084 | /// {Insufficient Resources on Remote Computer} The remote computer has insufficient resources to complete the network request. |
| 1585 | /// For example, the remote computer might not have enough available memory to carry out the request at this time. | 1085 | /// For example, the remote computer might not have enough available memory to carry out the request at this time. |
| 1586 | REMOTE_RESOURCES = 0xC000013D, | 1086 | REMOTE_RESOURCES = 0xC000013D, |
| 1587 | |||
| 1588 | /// {Virtual Circuit Closed} An existing connection (virtual circuit) has been broken at the remote computer. | 1087 | /// {Virtual Circuit Closed} An existing connection (virtual circuit) has been broken at the remote computer. |
| 1589 | /// There is probably something wrong with the network software protocol or the network hardware on the remote computer. | 1088 | /// There is probably something wrong with the network software protocol or the network hardware on the remote computer. |
| 1590 | LINK_FAILED = 0xC000013E, | 1089 | LINK_FAILED = 0xC000013E, |
| 1591 | |||
| 1592 | /// {Virtual Circuit Closed} The network transport on your computer has closed a network connection because it had to wait too long for a response from the remote computer. | 1090 | /// {Virtual Circuit Closed} The network transport on your computer has closed a network connection because it had to wait too long for a response from the remote computer. |
| 1593 | LINK_TIMEOUT = 0xC000013F, | 1091 | LINK_TIMEOUT = 0xC000013F, |
| 1594 | |||
| 1595 | /// The connection handle that was given to the transport was invalid. | 1092 | /// The connection handle that was given to the transport was invalid. |
| 1596 | INVALID_CONNECTION = 0xC0000140, | 1093 | INVALID_CONNECTION = 0xC0000140, |
| 1597 | |||
| 1598 | /// The address handle that was given to the transport was invalid. | 1094 | /// The address handle that was given to the transport was invalid. |
| 1599 | INVALID_ADDRESS = 0xC0000141, | 1095 | INVALID_ADDRESS = 0xC0000141, |
| 1600 | |||
| 1601 | /// {DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally. | 1096 | /// {DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally. |
| 1602 | DLL_INIT_FAILED = 0xC0000142, | 1097 | DLL_INIT_FAILED = 0xC0000142, |
| 1603 | |||
| 1604 | /// {Missing System File} The required system file %hs is bad or missing. | 1098 | /// {Missing System File} The required system file %hs is bad or missing. |
| 1605 | MISSING_SYSTEMFILE = 0xC0000143, | 1099 | MISSING_SYSTEMFILE = 0xC0000143, |
| 1606 | |||
| 1607 | /// {Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx. | 1100 | /// {Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx. |
| 1608 | UNHANDLED_EXCEPTION = 0xC0000144, | 1101 | UNHANDLED_EXCEPTION = 0xC0000144, |
| 1609 | |||
| 1610 | /// {Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application. | 1102 | /// {Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application. |
| 1611 | APP_INIT_FAILURE = 0xC0000145, | 1103 | APP_INIT_FAILURE = 0xC0000145, |
| 1612 | |||
| 1613 | /// {Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld. | 1104 | /// {Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld. |
| 1614 | PAGEFILE_CREATE_FAILED = 0xC0000146, | 1105 | PAGEFILE_CREATE_FAILED = 0xC0000146, |
| 1615 | |||
| 1616 | /// {No Paging File Specified} No paging file was specified in the system configuration. | 1106 | /// {No Paging File Specified} No paging file was specified in the system configuration. |
| 1617 | NO_PAGEFILE = 0xC0000147, | 1107 | NO_PAGEFILE = 0xC0000147, |
| 1618 | |||
| 1619 | /// {Incorrect System Call Level} An invalid level was passed into the specified system call. | 1108 | /// {Incorrect System Call Level} An invalid level was passed into the specified system call. |
| 1620 | INVALID_LEVEL = 0xC0000148, | 1109 | INVALID_LEVEL = 0xC0000148, |
| 1621 | |||
| 1622 | /// {Incorrect Password to LAN Manager Server} You specified an incorrect password to a LAN Manager 2.x or MS-NET server. | 1110 | /// {Incorrect Password to LAN Manager Server} You specified an incorrect password to a LAN Manager 2.x or MS-NET server. |
| 1623 | WRONG_PASSWORD_CORE = 0xC0000149, | 1111 | WRONG_PASSWORD_CORE = 0xC0000149, |
| 1624 | |||
| 1625 | /// {EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present. | 1112 | /// {EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present. |
| 1626 | ILLEGAL_FLOAT_CONTEXT = 0xC000014A, | 1113 | ILLEGAL_FLOAT_CONTEXT = 0xC000014A, |
| 1627 | |||
| 1628 | /// The pipe operation has failed because the other end of the pipe has been closed. | 1114 | /// The pipe operation has failed because the other end of the pipe has been closed. |
| 1629 | PIPE_BROKEN = 0xC000014B, | 1115 | PIPE_BROKEN = 0xC000014B, |
| 1630 | |||
| 1631 | /// {The Registry Is Corrupt} The structure of one of the files that contains registry data is corrupt; the image of the file in memory is corrupt; or the file could not be recovered because the alternate copy or log was absent or corrupt. | 1116 | /// {The Registry Is Corrupt} The structure of one of the files that contains registry data is corrupt; the image of the file in memory is corrupt; or the file could not be recovered because the alternate copy or log was absent or corrupt. |
| 1632 | REGISTRY_CORRUPT = 0xC000014C, | 1117 | REGISTRY_CORRUPT = 0xC000014C, |
| 1633 | |||
| 1634 | /// An I/O operation initiated by the Registry failed and cannot be recovered. | 1118 | /// An I/O operation initiated by the Registry failed and cannot be recovered. |
| 1635 | /// The registry could not read in, write out, or flush one of the files that contain the system's image of the registry. | 1119 | /// The registry could not read in, write out, or flush one of the files that contain the system's image of the registry. |
| 1636 | REGISTRY_IO_FAILED = 0xC000014D, | 1120 | REGISTRY_IO_FAILED = 0xC000014D, |
| 1637 | |||
| 1638 | /// An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread. | 1121 | /// An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread. |
| 1639 | NO_EVENT_PAIR = 0xC000014E, | 1122 | NO_EVENT_PAIR = 0xC000014E, |
| 1640 | |||
| 1641 | /// The volume does not contain a recognized file system. | 1123 | /// The volume does not contain a recognized file system. |
| 1642 | /// Be sure that all required file system drivers are loaded and that the volume is not corrupt. | 1124 | /// Be sure that all required file system drivers are loaded and that the volume is not corrupt. |
| 1643 | UNRECOGNIZED_VOLUME = 0xC000014F, | 1125 | UNRECOGNIZED_VOLUME = 0xC000014F, |
| 1644 | |||
| 1645 | /// No serial device was successfully initialized. The serial driver will unload. | 1126 | /// No serial device was successfully initialized. The serial driver will unload. |
| 1646 | SERIAL_NO_DEVICE_INITED = 0xC0000150, | 1127 | SERIAL_NO_DEVICE_INITED = 0xC0000150, |
| 1647 | |||
| 1648 | /// The specified local group does not exist. | 1128 | /// The specified local group does not exist. |
| 1649 | NO_SUCH_ALIAS = 0xC0000151, | 1129 | NO_SUCH_ALIAS = 0xC0000151, |
| 1650 | |||
| 1651 | /// The specified account name is not a member of the group. | 1130 | /// The specified account name is not a member of the group. |
| 1652 | MEMBER_NOT_IN_ALIAS = 0xC0000152, | 1131 | MEMBER_NOT_IN_ALIAS = 0xC0000152, |
| 1653 | |||
| 1654 | /// The specified account name is already a member of the group. | 1132 | /// The specified account name is already a member of the group. |
| 1655 | MEMBER_IN_ALIAS = 0xC0000153, | 1133 | MEMBER_IN_ALIAS = 0xC0000153, |
| 1656 | |||
| 1657 | /// The specified local group already exists. | 1134 | /// The specified local group already exists. |
| 1658 | ALIAS_EXISTS = 0xC0000154, | 1135 | ALIAS_EXISTS = 0xC0000154, |
| 1659 | |||
| 1660 | /// A requested type of logon (for example, interactive, network, and service) is not granted by the local security policy of the target system. | 1136 | /// A requested type of logon (for example, interactive, network, and service) is not granted by the local security policy of the target system. |
| 1661 | /// Ask the system administrator to grant the necessary form of logon. | 1137 | /// Ask the system administrator to grant the necessary form of logon. |
| 1662 | LOGON_NOT_GRANTED = 0xC0000155, | 1138 | LOGON_NOT_GRANTED = 0xC0000155, |
| 1663 | |||
| 1664 | /// The maximum number of secrets that can be stored in a single system was exceeded. | 1139 | /// The maximum number of secrets that can be stored in a single system was exceeded. |
| 1665 | /// The length and number of secrets is limited to satisfy U.S. State Department export restrictions. | 1140 | /// The length and number of secrets is limited to satisfy U.S. State Department export restrictions. |
| 1666 | TOO_MANY_SECRETS = 0xC0000156, | 1141 | TOO_MANY_SECRETS = 0xC0000156, |
| 1667 | |||
| 1668 | /// The length of a secret exceeds the maximum allowable length. | 1142 | /// The length of a secret exceeds the maximum allowable length. |
| 1669 | /// The length and number of secrets is limited to satisfy U.S. State Department export restrictions. | 1143 | /// The length and number of secrets is limited to satisfy U.S. State Department export restrictions. |
| 1670 | SECRET_TOO_LONG = 0xC0000157, | 1144 | SECRET_TOO_LONG = 0xC0000157, |
| 1671 | |||
| 1672 | /// The local security authority (LSA) database contains an internal inconsistency. | 1145 | /// The local security authority (LSA) database contains an internal inconsistency. |
| 1673 | INTERNAL_DB_ERROR = 0xC0000158, | 1146 | INTERNAL_DB_ERROR = 0xC0000158, |
| 1674 | |||
| 1675 | /// The requested operation cannot be performed in full-screen mode. | 1147 | /// The requested operation cannot be performed in full-screen mode. |
| 1676 | FULLSCREEN_MODE = 0xC0000159, | 1148 | FULLSCREEN_MODE = 0xC0000159, |
| 1677 | |||
| 1678 | /// During a logon attempt, the user's security context accumulated too many security IDs. This is a very unusual situation. | 1149 | /// During a logon attempt, the user's security context accumulated too many security IDs. This is a very unusual situation. |
| 1679 | /// Remove the user from some global or local groups to reduce the number of security IDs to incorporate into the security context. | 1150 | /// Remove the user from some global or local groups to reduce the number of security IDs to incorporate into the security context. |
| 1680 | TOO_MANY_CONTEXT_IDS = 0xC000015A, | 1151 | TOO_MANY_CONTEXT_IDS = 0xC000015A, |
| 1681 | |||
| 1682 | /// A user has requested a type of logon (for example, interactive or network) that has not been granted. | 1152 | /// A user has requested a type of logon (for example, interactive or network) that has not been granted. |
| 1683 | /// An administrator has control over who can logon interactively and through the network. | 1153 | /// An administrator has control over who can logon interactively and through the network. |
| 1684 | LOGON_TYPE_NOT_GRANTED = 0xC000015B, | 1154 | LOGON_TYPE_NOT_GRANTED = 0xC000015B, |
| 1685 | |||
| 1686 | /// The system has attempted to load or restore a file into the registry, and the specified file is not in the format of a registry file. | 1155 | /// The system has attempted to load or restore a file into the registry, and the specified file is not in the format of a registry file. |
| 1687 | NOT_REGISTRY_FILE = 0xC000015C, | 1156 | NOT_REGISTRY_FILE = 0xC000015C, |
| 1688 | |||
| 1689 | /// An attempt was made to change a user password in the security account manager without providing the necessary Windows cross-encrypted password. | 1157 | /// An attempt was made to change a user password in the security account manager without providing the necessary Windows cross-encrypted password. |
| 1690 | NT_CROSS_ENCRYPTION_REQUIRED = 0xC000015D, | 1158 | NT_CROSS_ENCRYPTION_REQUIRED = 0xC000015D, |
| 1691 | |||
| 1692 | /// A domain server has an incorrect configuration. | 1159 | /// A domain server has an incorrect configuration. |
| 1693 | DOMAIN_CTRLR_CONFIG_ERROR = 0xC000015E, | 1160 | DOMAIN_CTRLR_CONFIG_ERROR = 0xC000015E, |
| 1694 | |||
| 1695 | /// An attempt was made to explicitly access the secondary copy of information via a device control to the fault tolerance driver and the secondary copy is not present in the system. | 1161 | /// An attempt was made to explicitly access the secondary copy of information via a device control to the fault tolerance driver and the secondary copy is not present in the system. |
| 1696 | FT_MISSING_MEMBER = 0xC000015F, | 1162 | FT_MISSING_MEMBER = 0xC000015F, |
| 1697 | |||
| 1698 | /// A configuration registry node that represents a driver service entry was ill-formed and did not contain the required value entries. | 1163 | /// A configuration registry node that represents a driver service entry was ill-formed and did not contain the required value entries. |
| 1699 | ILL_FORMED_SERVICE_ENTRY = 0xC0000160, | 1164 | ILL_FORMED_SERVICE_ENTRY = 0xC0000160, |
| 1700 | |||
| 1701 | /// An illegal character was encountered. | 1165 | /// An illegal character was encountered. |
| 1702 | /// For a multibyte character set, this includes a lead byte without a succeeding trail byte. | 1166 | /// For a multibyte character set, this includes a lead byte without a succeeding trail byte. |
| 1703 | /// For the Unicode character set this includes the characters 0xFFFF and 0xFFFE. | 1167 | /// For the Unicode character set this includes the characters 0xFFFF and 0xFFFE. |
| 1704 | ILLEGAL_CHARACTER = 0xC0000161, | 1168 | ILLEGAL_CHARACTER = 0xC0000161, |
| 1705 | |||
| 1706 | /// No mapping for the Unicode character exists in the target multibyte code page. | 1169 | /// No mapping for the Unicode character exists in the target multibyte code page. |
| 1707 | UNMAPPABLE_CHARACTER = 0xC0000162, | 1170 | UNMAPPABLE_CHARACTER = 0xC0000162, |
| 1708 | |||
| 1709 | /// The Unicode character is not defined in the Unicode character set that is installed on the system. | 1171 | /// The Unicode character is not defined in the Unicode character set that is installed on the system. |
| 1710 | UNDEFINED_CHARACTER = 0xC0000163, | 1172 | UNDEFINED_CHARACTER = 0xC0000163, |
| 1711 | |||
| 1712 | /// The paging file cannot be created on a floppy disk. | 1173 | /// The paging file cannot be created on a floppy disk. |
| 1713 | FLOPPY_VOLUME = 0xC0000164, | 1174 | FLOPPY_VOLUME = 0xC0000164, |
| 1714 | |||
| 1715 | /// {Floppy Disk Error} While accessing a floppy disk, an ID address mark was not found. | 1175 | /// {Floppy Disk Error} While accessing a floppy disk, an ID address mark was not found. |
| 1716 | FLOPPY_ID_MARK_NOT_FOUND = 0xC0000165, | 1176 | FLOPPY_ID_MARK_NOT_FOUND = 0xC0000165, |
| 1717 | |||
| 1718 | /// {Floppy Disk Error} While accessing a floppy disk, the track address from the sector ID field was found to be different from the track address that is maintained by the controller. | 1177 | /// {Floppy Disk Error} While accessing a floppy disk, the track address from the sector ID field was found to be different from the track address that is maintained by the controller. |
| 1719 | FLOPPY_WRONG_CYLINDER = 0xC0000166, | 1178 | FLOPPY_WRONG_CYLINDER = 0xC0000166, |
| 1720 | |||
| 1721 | /// {Floppy Disk Error} The floppy disk controller reported an error that is not recognized by the floppy disk driver. | 1179 | /// {Floppy Disk Error} The floppy disk controller reported an error that is not recognized by the floppy disk driver. |
| 1722 | FLOPPY_UNKNOWN_ERROR = 0xC0000167, | 1180 | FLOPPY_UNKNOWN_ERROR = 0xC0000167, |
| 1723 | |||
| 1724 | /// {Floppy Disk Error} While accessing a floppy-disk, the controller returned inconsistent results via its registers. | 1181 | /// {Floppy Disk Error} While accessing a floppy-disk, the controller returned inconsistent results via its registers. |
| 1725 | FLOPPY_BAD_REGISTERS = 0xC0000168, | 1182 | FLOPPY_BAD_REGISTERS = 0xC0000168, |
| 1726 | |||
| 1727 | /// {Hard Disk Error} While accessing the hard disk, a recalibrate operation failed, even after retries. | 1183 | /// {Hard Disk Error} While accessing the hard disk, a recalibrate operation failed, even after retries. |
| 1728 | DISK_RECALIBRATE_FAILED = 0xC0000169, | 1184 | DISK_RECALIBRATE_FAILED = 0xC0000169, |
| 1729 | |||
| 1730 | /// {Hard Disk Error} While accessing the hard disk, a disk operation failed even after retries. | 1185 | /// {Hard Disk Error} While accessing the hard disk, a disk operation failed even after retries. |
| 1731 | DISK_OPERATION_FAILED = 0xC000016A, | 1186 | DISK_OPERATION_FAILED = 0xC000016A, |
| 1732 | |||
| 1733 | /// {Hard Disk Error} While accessing the hard disk, a disk controller reset was needed, but even that failed. | 1187 | /// {Hard Disk Error} While accessing the hard disk, a disk controller reset was needed, but even that failed. |
| 1734 | DISK_RESET_FAILED = 0xC000016B, | 1188 | DISK_RESET_FAILED = 0xC000016B, |
| 1735 | |||
| 1736 | /// An attempt was made to open a device that was sharing an interrupt request (IRQ) with other devices. | 1189 | /// An attempt was made to open a device that was sharing an interrupt request (IRQ) with other devices. |
| 1737 | /// At least one other device that uses that IRQ was already opened. | 1190 | /// At least one other device that uses that IRQ was already opened. |
| 1738 | /// Two concurrent opens of devices that share an IRQ and only work via interrupts is not supported for the particular bus type that the devices use. | 1191 | /// Two concurrent opens of devices that share an IRQ and only work via interrupts is not supported for the particular bus type that the devices use. |
| 1739 | SHARED_IRQ_BUSY = 0xC000016C, | 1192 | SHARED_IRQ_BUSY = 0xC000016C, |
| 1740 | |||
| 1741 | /// {FT Orphaning} A disk that is part of a fault-tolerant volume can no longer be accessed. | 1193 | /// {FT Orphaning} A disk that is part of a fault-tolerant volume can no longer be accessed. |
| 1742 | FT_ORPHANING = 0xC000016D, | 1194 | FT_ORPHANING = 0xC000016D, |
| 1743 | |||
| 1744 | /// The basic input/output system (BIOS) failed to connect a system interrupt to the device or bus for which the device is connected. | 1195 | /// The basic input/output system (BIOS) failed to connect a system interrupt to the device or bus for which the device is connected. |
| 1745 | BIOS_FAILED_TO_CONNECT_INTERRUPT = 0xC000016E, | 1196 | BIOS_FAILED_TO_CONNECT_INTERRUPT = 0xC000016E, |
| 1746 | |||
| 1747 | /// The tape could not be partitioned. | 1197 | /// The tape could not be partitioned. |
| 1748 | PARTITION_FAILURE = 0xC0000172, | 1198 | PARTITION_FAILURE = 0xC0000172, |
| 1749 | |||
| 1750 | /// When accessing a new tape of a multi-volume partition, the current blocksize is incorrect. | 1199 | /// When accessing a new tape of a multi-volume partition, the current blocksize is incorrect. |
| 1751 | INVALID_BLOCK_LENGTH = 0xC0000173, | 1200 | INVALID_BLOCK_LENGTH = 0xC0000173, |
| 1752 | |||
| 1753 | /// The tape partition information could not be found when loading a tape. | 1201 | /// The tape partition information could not be found when loading a tape. |
| 1754 | DEVICE_NOT_PARTITIONED = 0xC0000174, | 1202 | DEVICE_NOT_PARTITIONED = 0xC0000174, |
| 1755 | |||
| 1756 | /// An attempt to lock the eject media mechanism failed. | 1203 | /// An attempt to lock the eject media mechanism failed. |
| 1757 | UNABLE_TO_LOCK_MEDIA = 0xC0000175, | 1204 | UNABLE_TO_LOCK_MEDIA = 0xC0000175, |
| 1758 | |||
| 1759 | /// An attempt to unload media failed. | 1205 | /// An attempt to unload media failed. |
| 1760 | UNABLE_TO_UNLOAD_MEDIA = 0xC0000176, | 1206 | UNABLE_TO_UNLOAD_MEDIA = 0xC0000176, |
| 1761 | |||
| 1762 | /// The physical end of tape was detected. | 1207 | /// The physical end of tape was detected. |
| 1763 | EOM_OVERFLOW = 0xC0000177, | 1208 | EOM_OVERFLOW = 0xC0000177, |
| 1764 | |||
| 1765 | /// {No Media} There is no media in the drive. Insert media into drive %hs. | 1209 | /// {No Media} There is no media in the drive. Insert media into drive %hs. |
| 1766 | NO_MEDIA = 0xC0000178, | 1210 | NO_MEDIA = 0xC0000178, |
| 1767 | |||
| 1768 | /// A member could not be added to or removed from the local group because the member does not exist. | 1211 | /// A member could not be added to or removed from the local group because the member does not exist. |
| 1769 | NO_SUCH_MEMBER = 0xC000017A, | 1212 | NO_SUCH_MEMBER = 0xC000017A, |
| 1770 | |||
| 1771 | /// A new member could not be added to a local group because the member has the wrong account type. | 1213 | /// A new member could not be added to a local group because the member has the wrong account type. |
| 1772 | INVALID_MEMBER = 0xC000017B, | 1214 | INVALID_MEMBER = 0xC000017B, |
| 1773 | |||
| 1774 | /// An illegal operation was attempted on a registry key that has been marked for deletion. | 1215 | /// An illegal operation was attempted on a registry key that has been marked for deletion. |
| 1775 | KEY_DELETED = 0xC000017C, | 1216 | KEY_DELETED = 0xC000017C, |
| 1776 | |||
| 1777 | /// The system could not allocate the required space in a registry log. | 1217 | /// The system could not allocate the required space in a registry log. |
| 1778 | NO_LOG_SPACE = 0xC000017D, | 1218 | NO_LOG_SPACE = 0xC000017D, |
| 1779 | |||
| 1780 | /// Too many SIDs have been specified. | 1219 | /// Too many SIDs have been specified. |
| 1781 | TOO_MANY_SIDS = 0xC000017E, | 1220 | TOO_MANY_SIDS = 0xC000017E, |
| 1782 | |||
| 1783 | /// An attempt was made to change a user password in the security account manager without providing the necessary LM cross-encrypted password. | 1221 | /// An attempt was made to change a user password in the security account manager without providing the necessary LM cross-encrypted password. |
| 1784 | LM_CROSS_ENCRYPTION_REQUIRED = 0xC000017F, | 1222 | LM_CROSS_ENCRYPTION_REQUIRED = 0xC000017F, |
| 1785 | |||
| 1786 | /// An attempt was made to create a symbolic link in a registry key that already has subkeys or values. | 1223 | /// An attempt was made to create a symbolic link in a registry key that already has subkeys or values. |
| 1787 | KEY_HAS_CHILDREN = 0xC0000180, | 1224 | KEY_HAS_CHILDREN = 0xC0000180, |
| 1788 | |||
| 1789 | /// An attempt was made to create a stable subkey under a volatile parent key. | 1225 | /// An attempt was made to create a stable subkey under a volatile parent key. |
| 1790 | CHILD_MUST_BE_VOLATILE = 0xC0000181, | 1226 | CHILD_MUST_BE_VOLATILE = 0xC0000181, |
| 1791 | |||
| 1792 | /// The I/O device is configured incorrectly or the configuration parameters to the driver are incorrect. | 1227 | /// The I/O device is configured incorrectly or the configuration parameters to the driver are incorrect. |
| 1793 | DEVICE_CONFIGURATION_ERROR = 0xC0000182, | 1228 | DEVICE_CONFIGURATION_ERROR = 0xC0000182, |
| 1794 | |||
| 1795 | /// An error was detected between two drivers or within an I/O driver. | 1229 | /// An error was detected between two drivers or within an I/O driver. |
| 1796 | DRIVER_INTERNAL_ERROR = 0xC0000183, | 1230 | DRIVER_INTERNAL_ERROR = 0xC0000183, |
| 1797 | |||
| 1798 | /// The device is not in a valid state to perform this request. | 1231 | /// The device is not in a valid state to perform this request. |
| 1799 | INVALID_DEVICE_STATE = 0xC0000184, | 1232 | INVALID_DEVICE_STATE = 0xC0000184, |
| 1800 | |||
| 1801 | /// The I/O device reported an I/O error. | 1233 | /// The I/O device reported an I/O error. |
| 1802 | IO_DEVICE_ERROR = 0xC0000185, | 1234 | IO_DEVICE_ERROR = 0xC0000185, |
| 1803 | |||
| 1804 | /// A protocol error was detected between the driver and the device. | 1235 | /// A protocol error was detected between the driver and the device. |
| 1805 | DEVICE_PROTOCOL_ERROR = 0xC0000186, | 1236 | DEVICE_PROTOCOL_ERROR = 0xC0000186, |
| 1806 | |||
| 1807 | /// This operation is only allowed for the primary domain controller of the domain. | 1237 | /// This operation is only allowed for the primary domain controller of the domain. |
| 1808 | BACKUP_CONTROLLER = 0xC0000187, | 1238 | BACKUP_CONTROLLER = 0xC0000187, |
| 1809 | |||
| 1810 | /// The log file space is insufficient to support this operation. | 1239 | /// The log file space is insufficient to support this operation. |
| 1811 | LOG_FILE_FULL = 0xC0000188, | 1240 | LOG_FILE_FULL = 0xC0000188, |
| 1812 | |||
| 1813 | /// A write operation was attempted to a volume after it was dismounted. | 1241 | /// A write operation was attempted to a volume after it was dismounted. |
| 1814 | TOO_LATE = 0xC0000189, | 1242 | TOO_LATE = 0xC0000189, |
| 1815 | |||
| 1816 | /// The workstation does not have a trust secret for the primary domain in the local LSA database. | 1243 | /// The workstation does not have a trust secret for the primary domain in the local LSA database. |
| 1817 | NO_TRUST_LSA_SECRET = 0xC000018A, | 1244 | NO_TRUST_LSA_SECRET = 0xC000018A, |
| 1818 | |||
| 1819 | /// On applicable Windows Server releases, the SAM database does not have a computer account for this workstation trust relationship. | 1245 | /// On applicable Windows Server releases, the SAM database does not have a computer account for this workstation trust relationship. |
| 1820 | NO_TRUST_SAM_ACCOUNT = 0xC000018B, | 1246 | NO_TRUST_SAM_ACCOUNT = 0xC000018B, |
| 1821 | |||
| 1822 | /// The logon request failed because the trust relationship between the primary domain and the trusted domain failed. | 1247 | /// The logon request failed because the trust relationship between the primary domain and the trusted domain failed. |
| 1823 | TRUSTED_DOMAIN_FAILURE = 0xC000018C, | 1248 | TRUSTED_DOMAIN_FAILURE = 0xC000018C, |
| 1824 | |||
| 1825 | /// The logon request failed because the trust relationship between this workstation and the primary domain failed. | 1249 | /// The logon request failed because the trust relationship between this workstation and the primary domain failed. |
| 1826 | TRUSTED_RELATIONSHIP_FAILURE = 0xC000018D, | 1250 | TRUSTED_RELATIONSHIP_FAILURE = 0xC000018D, |
| 1827 | |||
| 1828 | /// The Eventlog log file is corrupt. | 1251 | /// The Eventlog log file is corrupt. |
| 1829 | EVENTLOG_FILE_CORRUPT = 0xC000018E, | 1252 | EVENTLOG_FILE_CORRUPT = 0xC000018E, |
| 1830 | |||
| 1831 | /// No Eventlog log file could be opened. The Eventlog service did not start. | 1253 | /// No Eventlog log file could be opened. The Eventlog service did not start. |
| 1832 | EVENTLOG_CANT_START = 0xC000018F, | 1254 | EVENTLOG_CANT_START = 0xC000018F, |
| 1833 | |||
| 1834 | /// The network logon failed. This might be because the validation authority cannot be reached. | 1255 | /// The network logon failed. This might be because the validation authority cannot be reached. |
| 1835 | TRUST_FAILURE = 0xC0000190, | 1256 | TRUST_FAILURE = 0xC0000190, |
| 1836 | |||
| 1837 | /// An attempt was made to acquire a mutant such that its maximum count would have been exceeded. | 1257 | /// An attempt was made to acquire a mutant such that its maximum count would have been exceeded. |
| 1838 | MUTANT_LIMIT_EXCEEDED = 0xC0000191, | 1258 | MUTANT_LIMIT_EXCEEDED = 0xC0000191, |
| 1839 | |||
| 1840 | /// An attempt was made to logon, but the NetLogon service was not started. | 1259 | /// An attempt was made to logon, but the NetLogon service was not started. |
| 1841 | NETLOGON_NOT_STARTED = 0xC0000192, | 1260 | NETLOGON_NOT_STARTED = 0xC0000192, |
| 1842 | |||
| 1843 | /// The user account has expired. | 1261 | /// The user account has expired. |
| 1844 | ACCOUNT_EXPIRED = 0xC0000193, | 1262 | ACCOUNT_EXPIRED = 0xC0000193, |
| 1845 | |||
| 1846 | /// {EXCEPTION} Possible deadlock condition. | 1263 | /// {EXCEPTION} Possible deadlock condition. |
| 1847 | POSSIBLE_DEADLOCK = 0xC0000194, | 1264 | POSSIBLE_DEADLOCK = 0xC0000194, |
| 1848 | |||
| 1849 | /// Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. | 1265 | /// Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. |
| 1850 | /// Disconnect all previous connections to the server or shared resource and try again. | 1266 | /// Disconnect all previous connections to the server or shared resource and try again. |
| 1851 | NETWORK_CREDENTIAL_CONFLICT = 0xC0000195, | 1267 | NETWORK_CREDENTIAL_CONFLICT = 0xC0000195, |
| 1852 | |||
| 1853 | /// An attempt was made to establish a session to a network server, but there are already too many sessions established to that server. | 1268 | /// An attempt was made to establish a session to a network server, but there are already too many sessions established to that server. |
| 1854 | REMOTE_SESSION_LIMIT = 0xC0000196, | 1269 | REMOTE_SESSION_LIMIT = 0xC0000196, |
| 1855 | |||
| 1856 | /// The log file has changed between reads. | 1270 | /// The log file has changed between reads. |
| 1857 | EVENTLOG_FILE_CHANGED = 0xC0000197, | 1271 | EVENTLOG_FILE_CHANGED = 0xC0000197, |
| 1858 | |||
| 1859 | /// The account used is an interdomain trust account. | 1272 | /// The account used is an interdomain trust account. |
| 1860 | /// Use your global user account or local user account to access this server. | 1273 | /// Use your global user account or local user account to access this server. |
| 1861 | NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xC0000198, | 1274 | NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xC0000198, |
| 1862 | |||
| 1863 | /// The account used is a computer account. | 1275 | /// The account used is a computer account. |
| 1864 | /// Use your global user account or local user account to access this server. | 1276 | /// Use your global user account or local user account to access this server. |
| 1865 | NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xC0000199, | 1277 | NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xC0000199, |
| 1866 | |||
| 1867 | /// The account used is a server trust account. | 1278 | /// The account used is a server trust account. |
| 1868 | /// Use your global user account or local user account to access this server. | 1279 | /// Use your global user account or local user account to access this server. |
| 1869 | NOLOGON_SERVER_TRUST_ACCOUNT = 0xC000019A, | 1280 | NOLOGON_SERVER_TRUST_ACCOUNT = 0xC000019A, |
| 1870 | |||
| 1871 | /// The name or SID of the specified domain is inconsistent with the trust information for that domain. | 1281 | /// The name or SID of the specified domain is inconsistent with the trust information for that domain. |
| 1872 | DOMAIN_TRUST_INCONSISTENT = 0xC000019B, | 1282 | DOMAIN_TRUST_INCONSISTENT = 0xC000019B, |
| 1873 | |||
| 1874 | /// A volume has been accessed for which a file system driver is required that has not yet been loaded. | 1283 | /// A volume has been accessed for which a file system driver is required that has not yet been loaded. |
| 1875 | FS_DRIVER_REQUIRED = 0xC000019C, | 1284 | FS_DRIVER_REQUIRED = 0xC000019C, |
| 1876 | |||
| 1877 | /// Indicates that the specified image is already loaded as a DLL. | 1285 | /// Indicates that the specified image is already loaded as a DLL. |
| 1878 | IMAGE_ALREADY_LOADED_AS_DLL = 0xC000019D, | 1286 | IMAGE_ALREADY_LOADED_AS_DLL = 0xC000019D, |
| 1879 | |||
| 1880 | /// Short name settings cannot be changed on this volume due to the global registry setting. | 1287 | /// Short name settings cannot be changed on this volume due to the global registry setting. |
| 1881 | INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0xC000019E, | 1288 | INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0xC000019E, |
| 1882 | |||
| 1883 | /// Short names are not enabled on this volume. | 1289 | /// Short names are not enabled on this volume. |
| 1884 | SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0xC000019F, | 1290 | SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0xC000019F, |
| 1885 | |||
| 1886 | /// The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume. | 1291 | /// The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume. |
| 1887 | SECURITY_STREAM_IS_INCONSISTENT = 0xC00001A0, | 1292 | SECURITY_STREAM_IS_INCONSISTENT = 0xC00001A0, |
| 1888 | |||
| 1889 | /// A requested file lock operation cannot be processed due to an invalid byte range. | 1293 | /// A requested file lock operation cannot be processed due to an invalid byte range. |
| 1890 | INVALID_LOCK_RANGE = 0xC00001A1, | 1294 | INVALID_LOCK_RANGE = 0xC00001A1, |
| 1891 | |||
| 1892 | /// The specified access control entry (ACE) contains an invalid condition. | 1295 | /// The specified access control entry (ACE) contains an invalid condition. |
| 1893 | INVALID_ACE_CONDITION = 0xC00001A2, | 1296 | INVALID_ACE_CONDITION = 0xC00001A2, |
| 1894 | |||
| 1895 | /// The subsystem needed to support the image type is not present. | 1297 | /// The subsystem needed to support the image type is not present. |
| 1896 | IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3, | 1298 | IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3, |
| 1897 | |||
| 1898 | /// The specified file already has a notification GUID associated with it. | 1299 | /// The specified file already has a notification GUID associated with it. |
| 1899 | NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4, | 1300 | NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4, |
| 1900 | |||
| 1901 | /// A remote open failed because the network open restrictions were not satisfied. | 1301 | /// A remote open failed because the network open restrictions were not satisfied. |
| 1902 | NETWORK_OPEN_RESTRICTION = 0xC0000201, | 1302 | NETWORK_OPEN_RESTRICTION = 0xC0000201, |
| 1903 | |||
| 1904 | /// There is no user session key for the specified logon session. | 1303 | /// There is no user session key for the specified logon session. |
| 1905 | NO_USER_SESSION_KEY = 0xC0000202, | 1304 | NO_USER_SESSION_KEY = 0xC0000202, |
| 1906 | |||
| 1907 | /// The remote user session has been deleted. | 1305 | /// The remote user session has been deleted. |
| 1908 | USER_SESSION_DELETED = 0xC0000203, | 1306 | USER_SESSION_DELETED = 0xC0000203, |
| 1909 | |||
| 1910 | /// Indicates the specified resource language ID cannot be found in the image file. | 1307 | /// Indicates the specified resource language ID cannot be found in the image file. |
| 1911 | RESOURCE_LANG_NOT_FOUND = 0xC0000204, | 1308 | RESOURCE_LANG_NOT_FOUND = 0xC0000204, |
| 1912 | |||
| 1913 | /// Insufficient server resources exist to complete the request. | 1309 | /// Insufficient server resources exist to complete the request. |
| 1914 | INSUFF_SERVER_RESOURCES = 0xC0000205, | 1310 | INSUFF_SERVER_RESOURCES = 0xC0000205, |
| 1915 | |||
| 1916 | /// The size of the buffer is invalid for the specified operation. | 1311 | /// The size of the buffer is invalid for the specified operation. |
| 1917 | INVALID_BUFFER_SIZE = 0xC0000206, | 1312 | INVALID_BUFFER_SIZE = 0xC0000206, |
| 1918 | |||
| 1919 | /// The transport rejected the specified network address as invalid. | 1313 | /// The transport rejected the specified network address as invalid. |
| 1920 | INVALID_ADDRESS_COMPONENT = 0xC0000207, | 1314 | INVALID_ADDRESS_COMPONENT = 0xC0000207, |
| 1921 | |||
| 1922 | /// The transport rejected the specified network address due to invalid use of a wildcard. | 1315 | /// The transport rejected the specified network address due to invalid use of a wildcard. |
| 1923 | INVALID_ADDRESS_WILDCARD = 0xC0000208, | 1316 | INVALID_ADDRESS_WILDCARD = 0xC0000208, |
| 1924 | |||
| 1925 | /// The transport address could not be opened because all the available addresses are in use. | 1317 | /// The transport address could not be opened because all the available addresses are in use. |
| 1926 | TOO_MANY_ADDRESSES = 0xC0000209, | 1318 | TOO_MANY_ADDRESSES = 0xC0000209, |
| 1927 | |||
| 1928 | /// The transport address could not be opened because it already exists. | 1319 | /// The transport address could not be opened because it already exists. |
| 1929 | ADDRESS_ALREADY_EXISTS = 0xC000020A, | 1320 | ADDRESS_ALREADY_EXISTS = 0xC000020A, |
| 1930 | |||
| 1931 | /// The transport address is now closed. | 1321 | /// The transport address is now closed. |
| 1932 | ADDRESS_CLOSED = 0xC000020B, | 1322 | ADDRESS_CLOSED = 0xC000020B, |
| 1933 | |||
| 1934 | /// The transport connection is now disconnected. | 1323 | /// The transport connection is now disconnected. |
| 1935 | CONNECTION_DISCONNECTED = 0xC000020C, | 1324 | CONNECTION_DISCONNECTED = 0xC000020C, |
| 1936 | |||
| 1937 | /// The transport connection has been reset. | 1325 | /// The transport connection has been reset. |
| 1938 | CONNECTION_RESET = 0xC000020D, | 1326 | CONNECTION_RESET = 0xC000020D, |
| 1939 | |||
| 1940 | /// The transport cannot dynamically acquire any more nodes. | 1327 | /// The transport cannot dynamically acquire any more nodes. |
| 1941 | TOO_MANY_NODES = 0xC000020E, | 1328 | TOO_MANY_NODES = 0xC000020E, |
| 1942 | |||
| 1943 | /// The transport aborted a pending transaction. | 1329 | /// The transport aborted a pending transaction. |
| 1944 | TRANSACTION_ABORTED = 0xC000020F, | 1330 | TRANSACTION_ABORTED = 0xC000020F, |
| 1945 | |||
| 1946 | /// The transport timed out a request that is waiting for a response. | 1331 | /// The transport timed out a request that is waiting for a response. |
| 1947 | TRANSACTION_TIMED_OUT = 0xC0000210, | 1332 | TRANSACTION_TIMED_OUT = 0xC0000210, |
| 1948 | |||
| 1949 | /// The transport did not receive a release for a pending response. | 1333 | /// The transport did not receive a release for a pending response. |
| 1950 | TRANSACTION_NO_RELEASE = 0xC0000211, | 1334 | TRANSACTION_NO_RELEASE = 0xC0000211, |
| 1951 | |||
| 1952 | /// The transport did not find a transaction that matches the specific token. | 1335 | /// The transport did not find a transaction that matches the specific token. |
| 1953 | TRANSACTION_NO_MATCH = 0xC0000212, | 1336 | TRANSACTION_NO_MATCH = 0xC0000212, |
| 1954 | |||
| 1955 | /// The transport had previously responded to a transaction request. | 1337 | /// The transport had previously responded to a transaction request. |
| 1956 | TRANSACTION_RESPONDED = 0xC0000213, | 1338 | TRANSACTION_RESPONDED = 0xC0000213, |
| 1957 | |||
| 1958 | /// The transport does not recognize the specified transaction request ID. | 1339 | /// The transport does not recognize the specified transaction request ID. |
| 1959 | TRANSACTION_INVALID_ID = 0xC0000214, | 1340 | TRANSACTION_INVALID_ID = 0xC0000214, |
| 1960 | |||
| 1961 | /// The transport does not recognize the specified transaction request type. | 1341 | /// The transport does not recognize the specified transaction request type. |
| 1962 | TRANSACTION_INVALID_TYPE = 0xC0000215, | 1342 | TRANSACTION_INVALID_TYPE = 0xC0000215, |
| 1963 | |||
| 1964 | /// The transport can only process the specified request on the server side of a session. | 1343 | /// The transport can only process the specified request on the server side of a session. |
| 1965 | NOT_SERVER_SESSION = 0xC0000216, | 1344 | NOT_SERVER_SESSION = 0xC0000216, |
| 1966 | |||
| 1967 | /// The transport can only process the specified request on the client side of a session. | 1345 | /// The transport can only process the specified request on the client side of a session. |
| 1968 | NOT_CLIENT_SESSION = 0xC0000217, | 1346 | NOT_CLIENT_SESSION = 0xC0000217, |
| 1969 | |||
| 1970 | /// {Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable. | 1347 | /// {Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable. |
| 1971 | CANNOT_LOAD_REGISTRY_FILE = 0xC0000218, | 1348 | CANNOT_LOAD_REGISTRY_FILE = 0xC0000218, |
| 1972 | |||
| 1973 | /// {Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. | 1349 | /// {Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. |
| 1974 | /// Choosing OK will terminate the process, and choosing Cancel will ignore the error. | 1350 | /// Choosing OK will terminate the process, and choosing Cancel will ignore the error. |
| 1975 | DEBUG_ATTACH_FAILED = 0xC0000219, | 1351 | DEBUG_ATTACH_FAILED = 0xC0000219, |
| 1976 | |||
| 1977 | /// {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down. | 1352 | /// {Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down. |
| 1978 | SYSTEM_PROCESS_TERMINATED = 0xC000021A, | 1353 | SYSTEM_PROCESS_TERMINATED = 0xC000021A, |
| 1979 | |||
| 1980 | /// {Data Not Accepted} The TDI client could not handle the data received during an indication. | 1354 | /// {Data Not Accepted} The TDI client could not handle the data received during an indication. |
| 1981 | DATA_NOT_ACCEPTED = 0xC000021B, | 1355 | DATA_NOT_ACCEPTED = 0xC000021B, |
| 1982 | |||
| 1983 | /// {Unable to Retrieve Browser Server List} The list of servers for this workgroup is not currently available. | 1356 | /// {Unable to Retrieve Browser Server List} The list of servers for this workgroup is not currently available. |
| 1984 | NO_BROWSER_SERVERS_FOUND = 0xC000021C, | 1357 | NO_BROWSER_SERVERS_FOUND = 0xC000021C, |
| 1985 | |||
| 1986 | /// NTVDM encountered a hard error. | 1358 | /// NTVDM encountered a hard error. |
| 1987 | VDM_HARD_ERROR = 0xC000021D, | 1359 | VDM_HARD_ERROR = 0xC000021D, |
| 1988 | |||
| 1989 | /// {Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time. | 1360 | /// {Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time. |
| 1990 | DRIVER_CANCEL_TIMEOUT = 0xC000021E, | 1361 | DRIVER_CANCEL_TIMEOUT = 0xC000021E, |
| 1991 | |||
| 1992 | /// {Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message. | 1362 | /// {Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message. |
| 1993 | REPLY_MESSAGE_MISMATCH = 0xC000021F, | 1363 | REPLY_MESSAGE_MISMATCH = 0xC000021F, |
| 1994 | |||
| 1995 | /// {Mapped View Alignment Incorrect} An attempt was made to map a view of a file, but either the specified base address or the offset into the file were not aligned on the proper allocation granularity. | 1364 | /// {Mapped View Alignment Incorrect} An attempt was made to map a view of a file, but either the specified base address or the offset into the file were not aligned on the proper allocation granularity. |
| 1996 | MAPPED_ALIGNMENT = 0xC0000220, | 1365 | MAPPED_ALIGNMENT = 0xC0000220, |
| 1997 | |||
| 1998 | /// {Bad Image Checksum} The image %hs is possibly corrupt. | 1366 | /// {Bad Image Checksum} The image %hs is possibly corrupt. |
| 1999 | /// The header checksum does not match the computed checksum. | 1367 | /// The header checksum does not match the computed checksum. |
| 2000 | IMAGE_CHECKSUM_MISMATCH = 0xC0000221, | 1368 | IMAGE_CHECKSUM_MISMATCH = 0xC0000221, |
| 2001 | |||
| 2002 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. | 1369 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. |
| 2003 | /// This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere. | 1370 | /// This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere. |
| 2004 | LOST_WRITEBEHIND_DATA = 0xC0000222, | 1371 | LOST_WRITEBEHIND_DATA = 0xC0000222, |
| 2005 | |||
| 2006 | /// The parameters passed to the server in the client/server shared memory window were invalid. | 1372 | /// The parameters passed to the server in the client/server shared memory window were invalid. |
| 2007 | /// Too much data might have been put in the shared memory window. | 1373 | /// Too much data might have been put in the shared memory window. |
| 2008 | CLIENT_SERVER_PARAMETERS_INVALID = 0xC0000223, | 1374 | CLIENT_SERVER_PARAMETERS_INVALID = 0xC0000223, |
| 2009 | |||
| 2010 | /// The user password must be changed before logging on the first time. | 1375 | /// The user password must be changed before logging on the first time. |
| 2011 | PASSWORD_MUST_CHANGE = 0xC0000224, | 1376 | PASSWORD_MUST_CHANGE = 0xC0000224, |
| 2012 | |||
| 2013 | /// The object was not found. | 1377 | /// The object was not found. |
| 2014 | NOT_FOUND = 0xC0000225, | 1378 | NOT_FOUND = 0xC0000225, |
| 2015 | |||
| 2016 | /// The stream is not a tiny stream. | 1379 | /// The stream is not a tiny stream. |
| 2017 | NOT_TINY_STREAM = 0xC0000226, | 1380 | NOT_TINY_STREAM = 0xC0000226, |
| 2018 | |||
| 2019 | /// A transaction recovery failed. | 1381 | /// A transaction recovery failed. |
| 2020 | RECOVERY_FAILURE = 0xC0000227, | 1382 | RECOVERY_FAILURE = 0xC0000227, |
| 2021 | |||
| 2022 | /// The request must be handled by the stack overflow code. | 1383 | /// The request must be handled by the stack overflow code. |
| 2023 | STACK_OVERFLOW_READ = 0xC0000228, | 1384 | STACK_OVERFLOW_READ = 0xC0000228, |
| 2024 | |||
| 2025 | /// A consistency check failed. | 1385 | /// A consistency check failed. |
| 2026 | FAIL_CHECK = 0xC0000229, | 1386 | FAIL_CHECK = 0xC0000229, |
| 2027 | |||
| 2028 | /// The attempt to insert the ID in the index failed because the ID is already in the index. | 1387 | /// The attempt to insert the ID in the index failed because the ID is already in the index. |
| 2029 | DUPLICATE_OBJECTID = 0xC000022A, | 1388 | DUPLICATE_OBJECTID = 0xC000022A, |
| 2030 | |||
| 2031 | /// The attempt to set the object ID failed because the object already has an ID. | 1389 | /// The attempt to set the object ID failed because the object already has an ID. |
| 2032 | OBJECTID_EXISTS = 0xC000022B, | 1390 | OBJECTID_EXISTS = 0xC000022B, |
| 2033 | |||
| 2034 | /// Internal OFS status codes indicating how an allocation operation is handled. | 1391 | /// Internal OFS status codes indicating how an allocation operation is handled. |
| 2035 | /// Either it is retried after the containing oNode is moved or the extent stream is converted to a large stream. | 1392 | /// Either it is retried after the containing oNode is moved or the extent stream is converted to a large stream. |
| 2036 | CONVERT_TO_LARGE = 0xC000022C, | 1393 | CONVERT_TO_LARGE = 0xC000022C, |
| 2037 | |||
| 2038 | /// The request needs to be retried. | 1394 | /// The request needs to be retried. |
| 2039 | RETRY = 0xC000022D, | 1395 | RETRY = 0xC000022D, |
| 2040 | |||
| 2041 | /// The attempt to find the object found an object on the volume that matches by ID; however, it is out of the scope of the handle that is used for the operation. | 1396 | /// The attempt to find the object found an object on the volume that matches by ID; however, it is out of the scope of the handle that is used for the operation. |
| 2042 | FOUND_OUT_OF_SCOPE = 0xC000022E, | 1397 | FOUND_OUT_OF_SCOPE = 0xC000022E, |
| 2043 | |||
| 2044 | /// The bucket array must be grown. Retry the transaction after doing so. | 1398 | /// The bucket array must be grown. Retry the transaction after doing so. |
| 2045 | ALLOCATE_BUCKET = 0xC000022F, | 1399 | ALLOCATE_BUCKET = 0xC000022F, |
| 2046 | |||
| 2047 | /// The specified property set does not exist on the object. | 1400 | /// The specified property set does not exist on the object. |
| 2048 | PROPSET_NOT_FOUND = 0xC0000230, | 1401 | PROPSET_NOT_FOUND = 0xC0000230, |
| 2049 | |||
| 2050 | /// The user/kernel marshaling buffer has overflowed. | 1402 | /// The user/kernel marshaling buffer has overflowed. |
| 2051 | MARSHALL_OVERFLOW = 0xC0000231, | 1403 | MARSHALL_OVERFLOW = 0xC0000231, |
| 2052 | |||
| 2053 | /// The supplied variant structure contains invalid data. | 1404 | /// The supplied variant structure contains invalid data. |
| 2054 | INVALID_VARIANT = 0xC0000232, | 1405 | INVALID_VARIANT = 0xC0000232, |
| 2055 | |||
| 2056 | /// A domain controller for this domain was not found. | 1406 | /// A domain controller for this domain was not found. |
| 2057 | DOMAIN_CONTROLLER_NOT_FOUND = 0xC0000233, | 1407 | DOMAIN_CONTROLLER_NOT_FOUND = 0xC0000233, |
| 2058 | |||
| 2059 | /// The user account has been automatically locked because too many invalid logon attempts or password change attempts have been requested. | 1408 | /// The user account has been automatically locked because too many invalid logon attempts or password change attempts have been requested. |
| 2060 | ACCOUNT_LOCKED_OUT = 0xC0000234, | 1409 | ACCOUNT_LOCKED_OUT = 0xC0000234, |
| 2061 | |||
| 2062 | /// NtClose was called on a handle that was protected from close via NtSetInformationObject. | 1410 | /// NtClose was called on a handle that was protected from close via NtSetInformationObject. |
| 2063 | HANDLE_NOT_CLOSABLE = 0xC0000235, | 1411 | HANDLE_NOT_CLOSABLE = 0xC0000235, |
| 2064 | |||
| 2065 | /// The transport-connection attempt was refused by the remote system. | 1412 | /// The transport-connection attempt was refused by the remote system. |
| 2066 | CONNECTION_REFUSED = 0xC0000236, | 1413 | CONNECTION_REFUSED = 0xC0000236, |
| 2067 | |||
| 2068 | /// The transport connection was gracefully closed. | 1414 | /// The transport connection was gracefully closed. |
| 2069 | GRACEFUL_DISCONNECT = 0xC0000237, | 1415 | GRACEFUL_DISCONNECT = 0xC0000237, |
| 2070 | |||
| 2071 | /// The transport endpoint already has an address associated with it. | 1416 | /// The transport endpoint already has an address associated with it. |
| 2072 | ADDRESS_ALREADY_ASSOCIATED = 0xC0000238, | 1417 | ADDRESS_ALREADY_ASSOCIATED = 0xC0000238, |
| 2073 | |||
| 2074 | /// An address has not yet been associated with the transport endpoint. | 1418 | /// An address has not yet been associated with the transport endpoint. |
| 2075 | ADDRESS_NOT_ASSOCIATED = 0xC0000239, | 1419 | ADDRESS_NOT_ASSOCIATED = 0xC0000239, |
| 2076 | |||
| 2077 | /// An operation was attempted on a nonexistent transport connection. | 1420 | /// An operation was attempted on a nonexistent transport connection. |
| 2078 | CONNECTION_INVALID = 0xC000023A, | 1421 | CONNECTION_INVALID = 0xC000023A, |
| 2079 | |||
| 2080 | /// An invalid operation was attempted on an active transport connection. | 1422 | /// An invalid operation was attempted on an active transport connection. |
| 2081 | CONNECTION_ACTIVE = 0xC000023B, | 1423 | CONNECTION_ACTIVE = 0xC000023B, |
| 2082 | |||
| 2083 | /// The remote network is not reachable by the transport. | 1424 | /// The remote network is not reachable by the transport. |
| 2084 | NETWORK_UNREACHABLE = 0xC000023C, | 1425 | NETWORK_UNREACHABLE = 0xC000023C, |
| 2085 | |||
| 2086 | /// The remote system is not reachable by the transport. | 1426 | /// The remote system is not reachable by the transport. |
| 2087 | HOST_UNREACHABLE = 0xC000023D, | 1427 | HOST_UNREACHABLE = 0xC000023D, |
| 2088 | |||
| 2089 | /// The remote system does not support the transport protocol. | 1428 | /// The remote system does not support the transport protocol. |
| 2090 | PROTOCOL_UNREACHABLE = 0xC000023E, | 1429 | PROTOCOL_UNREACHABLE = 0xC000023E, |
| 2091 | |||
| 2092 | /// No service is operating at the destination port of the transport on the remote system. | 1430 | /// No service is operating at the destination port of the transport on the remote system. |
| 2093 | PORT_UNREACHABLE = 0xC000023F, | 1431 | PORT_UNREACHABLE = 0xC000023F, |
| 2094 | |||
| 2095 | /// The request was aborted. | 1432 | /// The request was aborted. |
| 2096 | REQUEST_ABORTED = 0xC0000240, | 1433 | REQUEST_ABORTED = 0xC0000240, |
| 2097 | |||
| 2098 | /// The transport connection was aborted by the local system. | 1434 | /// The transport connection was aborted by the local system. |
| 2099 | CONNECTION_ABORTED = 0xC0000241, | 1435 | CONNECTION_ABORTED = 0xC0000241, |
| 2100 | |||
| 2101 | /// The specified buffer contains ill-formed data. | 1436 | /// The specified buffer contains ill-formed data. |
| 2102 | BAD_COMPRESSION_BUFFER = 0xC0000242, | 1437 | BAD_COMPRESSION_BUFFER = 0xC0000242, |
| 2103 | |||
| 2104 | /// The requested operation cannot be performed on a file with a user mapped section open. | 1438 | /// The requested operation cannot be performed on a file with a user mapped section open. |
| 2105 | USER_MAPPED_FILE = 0xC0000243, | 1439 | USER_MAPPED_FILE = 0xC0000243, |
| 2106 | |||
| 2107 | /// {Audit Failed} An attempt to generate a security audit failed. | 1440 | /// {Audit Failed} An attempt to generate a security audit failed. |
| 2108 | AUDIT_FAILED = 0xC0000244, | 1441 | AUDIT_FAILED = 0xC0000244, |
| 2109 | |||
| 2110 | /// The timer resolution was not previously set by the current process. | 1442 | /// The timer resolution was not previously set by the current process. |
| 2111 | TIMER_RESOLUTION_NOT_SET = 0xC0000245, | 1443 | TIMER_RESOLUTION_NOT_SET = 0xC0000245, |
| 2112 | |||
| 2113 | /// A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached. | 1444 | /// A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached. |
| 2114 | CONNECTION_COUNT_LIMIT = 0xC0000246, | 1445 | CONNECTION_COUNT_LIMIT = 0xC0000246, |
| 2115 | |||
| 2116 | /// Attempting to log on during an unauthorized time of day for this account. | 1446 | /// Attempting to log on during an unauthorized time of day for this account. |
| 2117 | LOGIN_TIME_RESTRICTION = 0xC0000247, | 1447 | LOGIN_TIME_RESTRICTION = 0xC0000247, |
| 2118 | |||
| 2119 | /// The account is not authorized to log on from this station. | 1448 | /// The account is not authorized to log on from this station. |
| 2120 | LOGIN_WKSTA_RESTRICTION = 0xC0000248, | 1449 | LOGIN_WKSTA_RESTRICTION = 0xC0000248, |
| 2121 | |||
| 2122 | /// {UP/MP Image Mismatch} The image %hs has been modified for use on a uniprocessor system, but you are running it on a multiprocessor machine. Reinstall the image file. | 1450 | /// {UP/MP Image Mismatch} The image %hs has been modified for use on a uniprocessor system, but you are running it on a multiprocessor machine. Reinstall the image file. |
| 2123 | IMAGE_MP_UP_MISMATCH = 0xC0000249, | 1451 | IMAGE_MP_UP_MISMATCH = 0xC0000249, |
| 2124 | |||
| 2125 | /// There is insufficient account information to log you on. | 1452 | /// There is insufficient account information to log you on. |
| 2126 | INSUFFICIENT_LOGON_INFO = 0xC0000250, | 1453 | INSUFFICIENT_LOGON_INFO = 0xC0000250, |
| 2127 | |||
| 2128 | /// {Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. | 1454 | /// {Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. |
| 2129 | /// The stack pointer has been left in an inconsistent state. | 1455 | /// The stack pointer has been left in an inconsistent state. |
| 2130 | /// The entry point should be declared as WINAPI or STDCALL. | 1456 | /// The entry point should be declared as WINAPI or STDCALL. |
| 2131 | /// Select YES to fail the DLL load. Select NO to continue execution. | 1457 | /// Select YES to fail the DLL load. Select NO to continue execution. |
| 2132 | /// Selecting NO might cause the application to operate incorrectly. | 1458 | /// Selecting NO might cause the application to operate incorrectly. |
| 2133 | BAD_DLL_ENTRYPOINT = 0xC0000251, | 1459 | BAD_DLL_ENTRYPOINT = 0xC0000251, |
| 2134 | |||
| 2135 | /// {Invalid Service Callback Entrypoint} The %hs service is not written correctly. | 1460 | /// {Invalid Service Callback Entrypoint} The %hs service is not written correctly. |
| 2136 | /// The stack pointer has been left in an inconsistent state. | 1461 | /// The stack pointer has been left in an inconsistent state. |
| 2137 | /// The callback entry point should be declared as WINAPI or STDCALL. | 1462 | /// The callback entry point should be declared as WINAPI or STDCALL. |
| 2138 | /// Selecting OK will cause the service to continue operation. | 1463 | /// Selecting OK will cause the service to continue operation. |
| 2139 | /// However, the service process might operate incorrectly. | 1464 | /// However, the service process might operate incorrectly. |
| 2140 | BAD_SERVICE_ENTRYPOINT = 0xC0000252, | 1465 | BAD_SERVICE_ENTRYPOINT = 0xC0000252, |
| 2141 | |||
| 2142 | /// The server received the messages but did not send a reply. | 1466 | /// The server received the messages but did not send a reply. |
| 2143 | LPC_REPLY_LOST = 0xC0000253, | 1467 | LPC_REPLY_LOST = 0xC0000253, |
| 2144 | |||
| 2145 | /// There is an IP address conflict with another system on the network. | 1468 | /// There is an IP address conflict with another system on the network. |
| 2146 | IP_ADDRESS_CONFLICT1 = 0xC0000254, | 1469 | IP_ADDRESS_CONFLICT1 = 0xC0000254, |
| 2147 | |||
| 2148 | /// There is an IP address conflict with another system on the network. | 1470 | /// There is an IP address conflict with another system on the network. |
| 2149 | IP_ADDRESS_CONFLICT2 = 0xC0000255, | 1471 | IP_ADDRESS_CONFLICT2 = 0xC0000255, |
| 2150 | |||
| 2151 | /// {Low On Registry Space} The system has reached the maximum size that is allowed for the system part of the registry. Additional storage requests will be ignored. | 1472 | /// {Low On Registry Space} The system has reached the maximum size that is allowed for the system part of the registry. Additional storage requests will be ignored. |
| 2152 | REGISTRY_QUOTA_LIMIT = 0xC0000256, | 1473 | REGISTRY_QUOTA_LIMIT = 0xC0000256, |
| 2153 | |||
| 2154 | /// The contacted server does not support the indicated part of the DFS namespace. | 1474 | /// The contacted server does not support the indicated part of the DFS namespace. |
| 2155 | PATH_NOT_COVERED = 0xC0000257, | 1475 | PATH_NOT_COVERED = 0xC0000257, |
| 2156 | |||
| 2157 | /// A callback return system service cannot be executed when no callback is active. | 1476 | /// A callback return system service cannot be executed when no callback is active. |
| 2158 | NO_CALLBACK_ACTIVE = 0xC0000258, | 1477 | NO_CALLBACK_ACTIVE = 0xC0000258, |
| 2159 | |||
| 2160 | /// The service being accessed is licensed for a particular number of connections. | 1478 | /// The service being accessed is licensed for a particular number of connections. |
| 2161 | /// No more connections can be made to the service at this time because the service has already accepted the maximum number of connections. | 1479 | /// No more connections can be made to the service at this time because the service has already accepted the maximum number of connections. |
| 2162 | LICENSE_QUOTA_EXCEEDED = 0xC0000259, | 1480 | LICENSE_QUOTA_EXCEEDED = 0xC0000259, |
| 2163 | |||
| 2164 | /// The password provided is too short to meet the policy of your user account. Choose a longer password. | 1481 | /// The password provided is too short to meet the policy of your user account. Choose a longer password. |
| 2165 | PWD_TOO_SHORT = 0xC000025A, | 1482 | PWD_TOO_SHORT = 0xC000025A, |
| 2166 | |||
| 2167 | /// The policy of your user account does not allow you to change passwords too frequently. | 1483 | /// The policy of your user account does not allow you to change passwords too frequently. |
| 2168 | /// This is done to prevent users from changing back to a familiar, but potentially discovered, password. | 1484 | /// This is done to prevent users from changing back to a familiar, but potentially discovered, password. |
| 2169 | /// If you feel your password has been compromised, contact your administrator immediately to have a new one assigned. | 1485 | /// If you feel your password has been compromised, contact your administrator immediately to have a new one assigned. |
| 2170 | PWD_TOO_RECENT = 0xC000025B, | 1486 | PWD_TOO_RECENT = 0xC000025B, |
| 2171 | |||
| 2172 | /// You have attempted to change your password to one that you have used in the past. | 1487 | /// You have attempted to change your password to one that you have used in the past. |
| 2173 | /// The policy of your user account does not allow this. | 1488 | /// The policy of your user account does not allow this. |
| 2174 | /// Select a password that you have not previously used. | 1489 | /// Select a password that you have not previously used. |
| 2175 | PWD_HISTORY_CONFLICT = 0xC000025C, | 1490 | PWD_HISTORY_CONFLICT = 0xC000025C, |
| 2176 | |||
| 2177 | /// You have attempted to load a legacy device driver while its device instance had been disabled. | 1491 | /// You have attempted to load a legacy device driver while its device instance had been disabled. |
| 2178 | PLUGPLAY_NO_DEVICE = 0xC000025E, | 1492 | PLUGPLAY_NO_DEVICE = 0xC000025E, |
| 2179 | |||
| 2180 | /// The specified compression format is unsupported. | 1493 | /// The specified compression format is unsupported. |
| 2181 | UNSUPPORTED_COMPRESSION = 0xC000025F, | 1494 | UNSUPPORTED_COMPRESSION = 0xC000025F, |
| 2182 | |||
| 2183 | /// The specified hardware profile configuration is invalid. | 1495 | /// The specified hardware profile configuration is invalid. |
| 2184 | INVALID_HW_PROFILE = 0xC0000260, | 1496 | INVALID_HW_PROFILE = 0xC0000260, |
| 2185 | |||
| 2186 | /// The specified Plug and Play registry device path is invalid. | 1497 | /// The specified Plug and Play registry device path is invalid. |
| 2187 | INVALID_PLUGPLAY_DEVICE_PATH = 0xC0000261, | 1498 | INVALID_PLUGPLAY_DEVICE_PATH = 0xC0000261, |
| 2188 | |||
| 2189 | /// {Driver Entry Point Not Found} The %hs device driver could not locate the ordinal %ld in driver %hs. | 1499 | /// {Driver Entry Point Not Found} The %hs device driver could not locate the ordinal %ld in driver %hs. |
| 2190 | DRIVER_ORDINAL_NOT_FOUND = 0xC0000262, | 1500 | DRIVER_ORDINAL_NOT_FOUND = 0xC0000262, |
| 2191 | |||
| 2192 | /// {Driver Entry Point Not Found} The %hs device driver could not locate the entry point %hs in driver %hs. | 1501 | /// {Driver Entry Point Not Found} The %hs device driver could not locate the entry point %hs in driver %hs. |
| 2193 | DRIVER_ENTRYPOINT_NOT_FOUND = 0xC0000263, | 1502 | DRIVER_ENTRYPOINT_NOT_FOUND = 0xC0000263, |
| 2194 | |||
| 2195 | /// {Application Error} The application attempted to release a resource it did not own. Click OK to terminate the application. | 1503 | /// {Application Error} The application attempted to release a resource it did not own. Click OK to terminate the application. |
| 2196 | RESOURCE_NOT_OWNED = 0xC0000264, | 1504 | RESOURCE_NOT_OWNED = 0xC0000264, |
| 2197 | |||
| 2198 | /// An attempt was made to create more links on a file than the file system supports. | 1505 | /// An attempt was made to create more links on a file than the file system supports. |
| 2199 | TOO_MANY_LINKS = 0xC0000265, | 1506 | TOO_MANY_LINKS = 0xC0000265, |
| 2200 | |||
| 2201 | /// The specified quota list is internally inconsistent with its descriptor. | 1507 | /// The specified quota list is internally inconsistent with its descriptor. |
| 2202 | QUOTA_LIST_INCONSISTENT = 0xC0000266, | 1508 | QUOTA_LIST_INCONSISTENT = 0xC0000266, |
| 2203 | |||
| 2204 | /// The specified file has been relocated to offline storage. | 1509 | /// The specified file has been relocated to offline storage. |
| 2205 | FILE_IS_OFFLINE = 0xC0000267, | 1510 | FILE_IS_OFFLINE = 0xC0000267, |
| 2206 | |||
| 2207 | /// {Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. | 1511 | /// {Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. |
| 2208 | /// To restore access to this installation of Windows, upgrade this installation by using a licensed distribution of this product. | 1512 | /// To restore access to this installation of Windows, upgrade this installation by using a licensed distribution of this product. |
| 2209 | EVALUATION_EXPIRATION = 0xC0000268, | 1513 | EVALUATION_EXPIRATION = 0xC0000268, |
| 2210 | |||
| 2211 | /// {Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. | 1514 | /// {Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. |
| 2212 | /// The relocation occurred because the DLL %hs occupied an address range that is reserved for Windows system DLLs. | 1515 | /// The relocation occurred because the DLL %hs occupied an address range that is reserved for Windows system DLLs. |
| 2213 | /// The vendor supplying the DLL should be contacted for a new DLL. | 1516 | /// The vendor supplying the DLL should be contacted for a new DLL. |
| 2214 | ILLEGAL_DLL_RELOCATION = 0xC0000269, | 1517 | ILLEGAL_DLL_RELOCATION = 0xC0000269, |
| 2215 | |||
| 2216 | /// {License Violation} The system has detected tampering with your registered product type. | 1518 | /// {License Violation} The system has detected tampering with your registered product type. |
| 2217 | /// This is a violation of your software license. Tampering with the product type is not permitted. | 1519 | /// This is a violation of your software license. Tampering with the product type is not permitted. |
| 2218 | LICENSE_VIOLATION = 0xC000026A, | 1520 | LICENSE_VIOLATION = 0xC000026A, |
| 2219 | |||
| 2220 | /// {DLL Initialization Failed} The application failed to initialize because the window station is shutting down. | 1521 | /// {DLL Initialization Failed} The application failed to initialize because the window station is shutting down. |
| 2221 | DLL_INIT_FAILED_LOGOFF = 0xC000026B, | 1522 | DLL_INIT_FAILED_LOGOFF = 0xC000026B, |
| 2222 | |||
| 2223 | /// {Unable to Load Device Driver} %hs device driver could not be loaded. Error Status was 0x%x. | 1523 | /// {Unable to Load Device Driver} %hs device driver could not be loaded. Error Status was 0x%x. |
| 2224 | DRIVER_UNABLE_TO_LOAD = 0xC000026C, | 1524 | DRIVER_UNABLE_TO_LOAD = 0xC000026C, |
| 2225 | |||
| 2226 | /// DFS is unavailable on the contacted server. | 1525 | /// DFS is unavailable on the contacted server. |
| 2227 | DFS_UNAVAILABLE = 0xC000026D, | 1526 | DFS_UNAVAILABLE = 0xC000026D, |
| 2228 | |||
| 2229 | /// An operation was attempted to a volume after it was dismounted. | 1527 | /// An operation was attempted to a volume after it was dismounted. |
| 2230 | VOLUME_DISMOUNTED = 0xC000026E, | 1528 | VOLUME_DISMOUNTED = 0xC000026E, |
| 2231 | |||
| 2232 | /// An internal error occurred in the Win32 x86 emulation subsystem. | 1529 | /// An internal error occurred in the Win32 x86 emulation subsystem. |
| 2233 | WX86_INTERNAL_ERROR = 0xC000026F, | 1530 | WX86_INTERNAL_ERROR = 0xC000026F, |
| 2234 | |||
| 2235 | /// Win32 x86 emulation subsystem floating-point stack check. | 1531 | /// Win32 x86 emulation subsystem floating-point stack check. |
| 2236 | WX86_FLOAT_STACK_CHECK = 0xC0000270, | 1532 | WX86_FLOAT_STACK_CHECK = 0xC0000270, |
| 2237 | |||
| 2238 | /// The validation process needs to continue on to the next step. | 1533 | /// The validation process needs to continue on to the next step. |
| 2239 | VALIDATE_CONTINUE = 0xC0000271, | 1534 | VALIDATE_CONTINUE = 0xC0000271, |
| 2240 | |||
| 2241 | /// There was no match for the specified key in the index. | 1535 | /// There was no match for the specified key in the index. |
| 2242 | NO_MATCH = 0xC0000272, | 1536 | NO_MATCH = 0xC0000272, |
| 2243 | |||
| 2244 | /// There are no more matches for the current index enumeration. | 1537 | /// There are no more matches for the current index enumeration. |
| 2245 | NO_MORE_MATCHES = 0xC0000273, | 1538 | NO_MORE_MATCHES = 0xC0000273, |
| 2246 | |||
| 2247 | /// The NTFS file or directory is not a reparse point. | 1539 | /// The NTFS file or directory is not a reparse point. |
| 2248 | NOT_A_REPARSE_POINT = 0xC0000275, | 1540 | NOT_A_REPARSE_POINT = 0xC0000275, |
| 2249 | |||
| 2250 | /// The Windows I/O reparse tag passed for the NTFS reparse point is invalid. | 1541 | /// The Windows I/O reparse tag passed for the NTFS reparse point is invalid. |
| 2251 | IO_REPARSE_TAG_INVALID = 0xC0000276, | 1542 | IO_REPARSE_TAG_INVALID = 0xC0000276, |
| 2252 | |||
| 2253 | /// The Windows I/O reparse tag does not match the one that is in the NTFS reparse point. | 1543 | /// The Windows I/O reparse tag does not match the one that is in the NTFS reparse point. |
| 2254 | IO_REPARSE_TAG_MISMATCH = 0xC0000277, | 1544 | IO_REPARSE_TAG_MISMATCH = 0xC0000277, |
| 2255 | |||
| 2256 | /// The user data passed for the NTFS reparse point is invalid. | 1545 | /// The user data passed for the NTFS reparse point is invalid. |
| 2257 | IO_REPARSE_DATA_INVALID = 0xC0000278, | 1546 | IO_REPARSE_DATA_INVALID = 0xC0000278, |
| 2258 | |||
| 2259 | /// The layered file system driver for this I/O tag did not handle it when needed. | 1547 | /// The layered file system driver for this I/O tag did not handle it when needed. |
| 2260 | IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279, | 1548 | IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279, |
| 2261 | |||
| 2262 | /// The NTFS symbolic link could not be resolved even though the initial file name is valid. | 1549 | /// The NTFS symbolic link could not be resolved even though the initial file name is valid. |
| 2263 | REPARSE_POINT_NOT_RESOLVED = 0xC0000280, | 1550 | REPARSE_POINT_NOT_RESOLVED = 0xC0000280, |
| 2264 | |||
| 2265 | /// The NTFS directory is a reparse point. | 1551 | /// The NTFS directory is a reparse point. |
| 2266 | DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281, | 1552 | DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281, |
| 2267 | |||
| 2268 | /// The range could not be added to the range list because of a conflict. | 1553 | /// The range could not be added to the range list because of a conflict. |
| 2269 | RANGE_LIST_CONFLICT = 0xC0000282, | 1554 | RANGE_LIST_CONFLICT = 0xC0000282, |
| 2270 | |||
| 2271 | /// The specified medium changer source element contains no media. | 1555 | /// The specified medium changer source element contains no media. |
| 2272 | SOURCE_ELEMENT_EMPTY = 0xC0000283, | 1556 | SOURCE_ELEMENT_EMPTY = 0xC0000283, |
| 2273 | |||
| 2274 | /// The specified medium changer destination element already contains media. | 1557 | /// The specified medium changer destination element already contains media. |
| 2275 | DESTINATION_ELEMENT_FULL = 0xC0000284, | 1558 | DESTINATION_ELEMENT_FULL = 0xC0000284, |
| 2276 | |||
| 2277 | /// The specified medium changer element does not exist. | 1559 | /// The specified medium changer element does not exist. |
| 2278 | ILLEGAL_ELEMENT_ADDRESS = 0xC0000285, | 1560 | ILLEGAL_ELEMENT_ADDRESS = 0xC0000285, |
| 2279 | |||
| 2280 | /// The specified element is contained in a magazine that is no longer present. | 1561 | /// The specified element is contained in a magazine that is no longer present. |
| 2281 | MAGAZINE_NOT_PRESENT = 0xC0000286, | 1562 | MAGAZINE_NOT_PRESENT = 0xC0000286, |
| 2282 | |||
| 2283 | /// The device requires re-initialization due to hardware errors. | 1563 | /// The device requires re-initialization due to hardware errors. |
| 2284 | REINITIALIZATION_NEEDED = 0xC0000287, | 1564 | REINITIALIZATION_NEEDED = 0xC0000287, |
| 2285 | |||
| 2286 | /// The file encryption attempt failed. | 1565 | /// The file encryption attempt failed. |
| 2287 | ENCRYPTION_FAILED = 0xC000028A, | 1566 | ENCRYPTION_FAILED = 0xC000028A, |
| 2288 | |||
| 2289 | /// The file decryption attempt failed. | 1567 | /// The file decryption attempt failed. |
| 2290 | DECRYPTION_FAILED = 0xC000028B, | 1568 | DECRYPTION_FAILED = 0xC000028B, |
| 2291 | |||
| 2292 | /// The specified range could not be found in the range list. | 1569 | /// The specified range could not be found in the range list. |
| 2293 | RANGE_NOT_FOUND = 0xC000028C, | 1570 | RANGE_NOT_FOUND = 0xC000028C, |
| 2294 | |||
| 2295 | /// There is no encryption recovery policy configured for this system. | 1571 | /// There is no encryption recovery policy configured for this system. |
| 2296 | NO_RECOVERY_POLICY = 0xC000028D, | 1572 | NO_RECOVERY_POLICY = 0xC000028D, |
| 2297 | |||
| 2298 | /// The required encryption driver is not loaded for this system. | 1573 | /// The required encryption driver is not loaded for this system. |
| 2299 | NO_EFS = 0xC000028E, | 1574 | NO_EFS = 0xC000028E, |
| 2300 | |||
| 2301 | /// The file was encrypted with a different encryption driver than is currently loaded. | 1575 | /// The file was encrypted with a different encryption driver than is currently loaded. |
| 2302 | WRONG_EFS = 0xC000028F, | 1576 | WRONG_EFS = 0xC000028F, |
| 2303 | |||
| 2304 | /// There are no EFS keys defined for the user. | 1577 | /// There are no EFS keys defined for the user. |
| 2305 | NO_USER_KEYS = 0xC0000290, | 1578 | NO_USER_KEYS = 0xC0000290, |
| 2306 | |||
| 2307 | /// The specified file is not encrypted. | 1579 | /// The specified file is not encrypted. |
| 2308 | FILE_NOT_ENCRYPTED = 0xC0000291, | 1580 | FILE_NOT_ENCRYPTED = 0xC0000291, |
| 2309 | |||
| 2310 | /// The specified file is not in the defined EFS export format. | 1581 | /// The specified file is not in the defined EFS export format. |
| 2311 | NOT_EXPORT_FORMAT = 0xC0000292, | 1582 | NOT_EXPORT_FORMAT = 0xC0000292, |
| 2312 | |||
| 2313 | /// The specified file is encrypted and the user does not have the ability to decrypt it. | 1583 | /// The specified file is encrypted and the user does not have the ability to decrypt it. |
| 2314 | FILE_ENCRYPTED = 0xC0000293, | 1584 | FILE_ENCRYPTED = 0xC0000293, |
| 2315 | |||
| 2316 | /// The GUID passed was not recognized as valid by a WMI data provider. | 1585 | /// The GUID passed was not recognized as valid by a WMI data provider. |
| 2317 | WMI_GUID_NOT_FOUND = 0xC0000295, | 1586 | WMI_GUID_NOT_FOUND = 0xC0000295, |
| 2318 | |||
| 2319 | /// The instance name passed was not recognized as valid by a WMI data provider. | 1587 | /// The instance name passed was not recognized as valid by a WMI data provider. |
| 2320 | WMI_INSTANCE_NOT_FOUND = 0xC0000296, | 1588 | WMI_INSTANCE_NOT_FOUND = 0xC0000296, |
| 2321 | |||
| 2322 | /// The data item ID passed was not recognized as valid by a WMI data provider. | 1589 | /// The data item ID passed was not recognized as valid by a WMI data provider. |
| 2323 | WMI_ITEMID_NOT_FOUND = 0xC0000297, | 1590 | WMI_ITEMID_NOT_FOUND = 0xC0000297, |
| 2324 | |||
| 2325 | /// The WMI request could not be completed and should be retried. | 1591 | /// The WMI request could not be completed and should be retried. |
| 2326 | WMI_TRY_AGAIN = 0xC0000298, | 1592 | WMI_TRY_AGAIN = 0xC0000298, |
| 2327 | |||
| 2328 | /// The policy object is shared and can only be modified at the root. | 1593 | /// The policy object is shared and can only be modified at the root. |
| 2329 | SHARED_POLICY = 0xC0000299, | 1594 | SHARED_POLICY = 0xC0000299, |
| 2330 | |||
| 2331 | /// The policy object does not exist when it should. | 1595 | /// The policy object does not exist when it should. |
| 2332 | POLICY_OBJECT_NOT_FOUND = 0xC000029A, | 1596 | POLICY_OBJECT_NOT_FOUND = 0xC000029A, |
| 2333 | |||
| 2334 | /// The requested policy information only lives in the Ds. | 1597 | /// The requested policy information only lives in the Ds. |
| 2335 | POLICY_ONLY_IN_DS = 0xC000029B, | 1598 | POLICY_ONLY_IN_DS = 0xC000029B, |
| 2336 | |||
| 2337 | /// The volume must be upgraded to enable this feature. | 1599 | /// The volume must be upgraded to enable this feature. |
| 2338 | VOLUME_NOT_UPGRADED = 0xC000029C, | 1600 | VOLUME_NOT_UPGRADED = 0xC000029C, |
| 2339 | |||
| 2340 | /// The remote storage service is not operational at this time. | 1601 | /// The remote storage service is not operational at this time. |
| 2341 | REMOTE_STORAGE_NOT_ACTIVE = 0xC000029D, | 1602 | REMOTE_STORAGE_NOT_ACTIVE = 0xC000029D, |
| 2342 | |||
| 2343 | /// The remote storage service encountered a media error. | 1603 | /// The remote storage service encountered a media error. |
| 2344 | REMOTE_STORAGE_MEDIA_ERROR = 0xC000029E, | 1604 | REMOTE_STORAGE_MEDIA_ERROR = 0xC000029E, |
| 2345 | |||
| 2346 | /// The tracking (workstation) service is not running. | 1605 | /// The tracking (workstation) service is not running. |
| 2347 | NO_TRACKING_SERVICE = 0xC000029F, | 1606 | NO_TRACKING_SERVICE = 0xC000029F, |
| 2348 | |||
| 2349 | /// The server process is running under a SID that is different from the SID that is required by client. | 1607 | /// The server process is running under a SID that is different from the SID that is required by client. |
| 2350 | SERVER_SID_MISMATCH = 0xC00002A0, | 1608 | SERVER_SID_MISMATCH = 0xC00002A0, |
| 2351 | |||
| 2352 | /// The specified directory service attribute or value does not exist. | 1609 | /// The specified directory service attribute or value does not exist. |
| 2353 | DS_NO_ATTRIBUTE_OR_VALUE = 0xC00002A1, | 1610 | DS_NO_ATTRIBUTE_OR_VALUE = 0xC00002A1, |
| 2354 | |||
| 2355 | /// The attribute syntax specified to the directory service is invalid. | 1611 | /// The attribute syntax specified to the directory service is invalid. |
| 2356 | DS_INVALID_ATTRIBUTE_SYNTAX = 0xC00002A2, | 1612 | DS_INVALID_ATTRIBUTE_SYNTAX = 0xC00002A2, |
| 2357 | |||
| 2358 | /// The attribute type specified to the directory service is not defined. | 1613 | /// The attribute type specified to the directory service is not defined. |
| 2359 | DS_ATTRIBUTE_TYPE_UNDEFINED = 0xC00002A3, | 1614 | DS_ATTRIBUTE_TYPE_UNDEFINED = 0xC00002A3, |
| 2360 | |||
| 2361 | /// The specified directory service attribute or value already exists. | 1615 | /// The specified directory service attribute or value already exists. |
| 2362 | DS_ATTRIBUTE_OR_VALUE_EXISTS = 0xC00002A4, | 1616 | DS_ATTRIBUTE_OR_VALUE_EXISTS = 0xC00002A4, |
| 2363 | |||
| 2364 | /// The directory service is busy. | 1617 | /// The directory service is busy. |
| 2365 | DS_BUSY = 0xC00002A5, | 1618 | DS_BUSY = 0xC00002A5, |
| 2366 | |||
| 2367 | /// The directory service is unavailable. | 1619 | /// The directory service is unavailable. |
| 2368 | DS_UNAVAILABLE = 0xC00002A6, | 1620 | DS_UNAVAILABLE = 0xC00002A6, |
| 2369 | |||
| 2370 | /// The directory service was unable to allocate a relative identifier. | 1621 | /// The directory service was unable to allocate a relative identifier. |
| 2371 | DS_NO_RIDS_ALLOCATED = 0xC00002A7, | 1622 | DS_NO_RIDS_ALLOCATED = 0xC00002A7, |
| 2372 | |||
| 2373 | /// The directory service has exhausted the pool of relative identifiers. | 1623 | /// The directory service has exhausted the pool of relative identifiers. |
| 2374 | DS_NO_MORE_RIDS = 0xC00002A8, | 1624 | DS_NO_MORE_RIDS = 0xC00002A8, |
| 2375 | |||
| 2376 | /// The requested operation could not be performed because the directory service is not the master for that type of operation. | 1625 | /// The requested operation could not be performed because the directory service is not the master for that type of operation. |
| 2377 | DS_INCORRECT_ROLE_OWNER = 0xC00002A9, | 1626 | DS_INCORRECT_ROLE_OWNER = 0xC00002A9, |
| 2378 | |||
| 2379 | /// The directory service was unable to initialize the subsystem that allocates relative identifiers. | 1627 | /// The directory service was unable to initialize the subsystem that allocates relative identifiers. |
| 2380 | DS_RIDMGR_INIT_ERROR = 0xC00002AA, | 1628 | DS_RIDMGR_INIT_ERROR = 0xC00002AA, |
| 2381 | |||
| 2382 | /// The requested operation did not satisfy one or more constraints that are associated with the class of the object. | 1629 | /// The requested operation did not satisfy one or more constraints that are associated with the class of the object. |
| 2383 | DS_OBJ_CLASS_VIOLATION = 0xC00002AB, | 1630 | DS_OBJ_CLASS_VIOLATION = 0xC00002AB, |
| 2384 | |||
| 2385 | /// The directory service can perform the requested operation only on a leaf object. | 1631 | /// The directory service can perform the requested operation only on a leaf object. |
| 2386 | DS_CANT_ON_NON_LEAF = 0xC00002AC, | 1632 | DS_CANT_ON_NON_LEAF = 0xC00002AC, |
| 2387 | |||
| 2388 | /// The directory service cannot perform the requested operation on the Relatively Defined Name (RDN) attribute of an object. | 1633 | /// The directory service cannot perform the requested operation on the Relatively Defined Name (RDN) attribute of an object. |
| 2389 | DS_CANT_ON_RDN = 0xC00002AD, | 1634 | DS_CANT_ON_RDN = 0xC00002AD, |
| 2390 | |||
| 2391 | /// The directory service detected an attempt to modify the object class of an object. | 1635 | /// The directory service detected an attempt to modify the object class of an object. |
| 2392 | DS_CANT_MOD_OBJ_CLASS = 0xC00002AE, | 1636 | DS_CANT_MOD_OBJ_CLASS = 0xC00002AE, |
| 2393 | |||
| 2394 | /// An error occurred while performing a cross domain move operation. | 1637 | /// An error occurred while performing a cross domain move operation. |
| 2395 | DS_CROSS_DOM_MOVE_FAILED = 0xC00002AF, | 1638 | DS_CROSS_DOM_MOVE_FAILED = 0xC00002AF, |
| 2396 | |||
| 2397 | /// Unable to contact the global catalog server. | 1639 | /// Unable to contact the global catalog server. |
| 2398 | DS_GC_NOT_AVAILABLE = 0xC00002B0, | 1640 | DS_GC_NOT_AVAILABLE = 0xC00002B0, |
| 2399 | |||
| 2400 | /// The requested operation requires a directory service, and none was available. | 1641 | /// The requested operation requires a directory service, and none was available. |
| 2401 | DIRECTORY_SERVICE_REQUIRED = 0xC00002B1, | 1642 | DIRECTORY_SERVICE_REQUIRED = 0xC00002B1, |
| 2402 | |||
| 2403 | /// The reparse attribute cannot be set because it is incompatible with an existing attribute. | 1643 | /// The reparse attribute cannot be set because it is incompatible with an existing attribute. |
| 2404 | REPARSE_ATTRIBUTE_CONFLICT = 0xC00002B2, | 1644 | REPARSE_ATTRIBUTE_CONFLICT = 0xC00002B2, |
| 2405 | |||
| 2406 | /// A group marked "use for deny only" cannot be enabled. | 1645 | /// A group marked "use for deny only" cannot be enabled. |
| 2407 | CANT_ENABLE_DENY_ONLY = 0xC00002B3, | 1646 | CANT_ENABLE_DENY_ONLY = 0xC00002B3, |
| 2408 | |||
| 2409 | /// {EXCEPTION} Multiple floating-point faults. | 1647 | /// {EXCEPTION} Multiple floating-point faults. |
| 2410 | FLOAT_MULTIPLE_FAULTS = 0xC00002B4, | 1648 | FLOAT_MULTIPLE_FAULTS = 0xC00002B4, |
| 2411 | |||
| 2412 | /// {EXCEPTION} Multiple floating-point traps. | 1649 | /// {EXCEPTION} Multiple floating-point traps. |
| 2413 | FLOAT_MULTIPLE_TRAPS = 0xC00002B5, | 1650 | FLOAT_MULTIPLE_TRAPS = 0xC00002B5, |
| 2414 | |||
| 2415 | /// The device has been removed. | 1651 | /// The device has been removed. |
| 2416 | DEVICE_REMOVED = 0xC00002B6, | 1652 | DEVICE_REMOVED = 0xC00002B6, |
| 2417 | |||
| 2418 | /// The volume change journal is being deleted. | 1653 | /// The volume change journal is being deleted. |
| 2419 | JOURNAL_DELETE_IN_PROGRESS = 0xC00002B7, | 1654 | JOURNAL_DELETE_IN_PROGRESS = 0xC00002B7, |
| 2420 | |||
| 2421 | /// The volume change journal is not active. | 1655 | /// The volume change journal is not active. |
| 2422 | JOURNAL_NOT_ACTIVE = 0xC00002B8, | 1656 | JOURNAL_NOT_ACTIVE = 0xC00002B8, |
| 2423 | |||
| 2424 | /// The requested interface is not supported. | 1657 | /// The requested interface is not supported. |
| 2425 | NOINTERFACE = 0xC00002B9, | 1658 | NOINTERFACE = 0xC00002B9, |
| 2426 | |||
| 2427 | /// A directory service resource limit has been exceeded. | 1659 | /// A directory service resource limit has been exceeded. |
| 2428 | DS_ADMIN_LIMIT_EXCEEDED = 0xC00002C1, | 1660 | DS_ADMIN_LIMIT_EXCEEDED = 0xC00002C1, |
| 2429 | |||
| 2430 | /// {System Standby Failed} The driver %hs does not support standby mode. | 1661 | /// {System Standby Failed} The driver %hs does not support standby mode. |
| 2431 | /// Updating this driver allows the system to go to standby mode. | 1662 | /// Updating this driver allows the system to go to standby mode. |
| 2432 | DRIVER_FAILED_SLEEP = 0xC00002C2, | 1663 | DRIVER_FAILED_SLEEP = 0xC00002C2, |
| 2433 | |||
| 2434 | /// Mutual Authentication failed. The server password is out of date at the domain controller. | 1664 | /// Mutual Authentication failed. The server password is out of date at the domain controller. |
| 2435 | MUTUAL_AUTHENTICATION_FAILED = 0xC00002C3, | 1665 | MUTUAL_AUTHENTICATION_FAILED = 0xC00002C3, |
| 2436 | |||
| 2437 | /// The system file %1 has become corrupt and has been replaced. | 1666 | /// The system file %1 has become corrupt and has been replaced. |
| 2438 | CORRUPT_SYSTEM_FILE = 0xC00002C4, | 1667 | CORRUPT_SYSTEM_FILE = 0xC00002C4, |
| 2439 | |||
| 2440 | /// {EXCEPTION} Alignment Error A data type misalignment error was detected in a load or store instruction. | 1668 | /// {EXCEPTION} Alignment Error A data type misalignment error was detected in a load or store instruction. |
| 2441 | DATATYPE_MISALIGNMENT_ERROR = 0xC00002C5, | 1669 | DATATYPE_MISALIGNMENT_ERROR = 0xC00002C5, |
| 2442 | |||
| 2443 | /// The WMI data item or data block is read-only. | 1670 | /// The WMI data item or data block is read-only. |
| 2444 | WMI_READ_ONLY = 0xC00002C6, | 1671 | WMI_READ_ONLY = 0xC00002C6, |
| 2445 | |||
| 2446 | /// The WMI data item or data block could not be changed. | 1672 | /// The WMI data item or data block could not be changed. |
| 2447 | WMI_SET_FAILURE = 0xC00002C7, | 1673 | WMI_SET_FAILURE = 0xC00002C7, |
| 2448 | |||
| 2449 | /// {Virtual Memory Minimum Too Low} Your system is low on virtual memory. | 1674 | /// {Virtual Memory Minimum Too Low} Your system is low on virtual memory. |
| 2450 | /// Windows is increasing the size of your virtual memory paging file. | 1675 | /// Windows is increasing the size of your virtual memory paging file. |
| 2451 | /// During this process, memory requests for some applications might be denied. For more information, see Help. | 1676 | /// During this process, memory requests for some applications might be denied. For more information, see Help. |
| 2452 | COMMITMENT_MINIMUM = 0xC00002C8, | 1677 | COMMITMENT_MINIMUM = 0xC00002C8, |
| 2453 | |||
| 2454 | /// {EXCEPTION} Register NaT consumption faults. | 1678 | /// {EXCEPTION} Register NaT consumption faults. |
| 2455 | /// A NaT value is consumed on a non-speculative instruction. | 1679 | /// A NaT value is consumed on a non-speculative instruction. |
| 2456 | REG_NAT_CONSUMPTION = 0xC00002C9, | 1680 | REG_NAT_CONSUMPTION = 0xC00002C9, |
| 2457 | |||
| 2458 | /// The transport element of the medium changer contains media, which is causing the operation to fail. | 1681 | /// The transport element of the medium changer contains media, which is causing the operation to fail. |
| 2459 | TRANSPORT_FULL = 0xC00002CA, | 1682 | TRANSPORT_FULL = 0xC00002CA, |
| 2460 | |||
| 2461 | /// Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. | 1683 | /// Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. |
| 2462 | /// Click OK to shut down this system and restart in Directory Services Restore Mode. | 1684 | /// Click OK to shut down this system and restart in Directory Services Restore Mode. |
| 2463 | /// Check the event log for more detailed information. | 1685 | /// Check the event log for more detailed information. |
| 2464 | DS_SAM_INIT_FAILURE = 0xC00002CB, | 1686 | DS_SAM_INIT_FAILURE = 0xC00002CB, |
| 2465 | |||
| 2466 | /// This operation is supported only when you are connected to the server. | 1687 | /// This operation is supported only when you are connected to the server. |
| 2467 | ONLY_IF_CONNECTED = 0xC00002CC, | 1688 | ONLY_IF_CONNECTED = 0xC00002CC, |
| 2468 | |||
| 2469 | /// Only an administrator can modify the membership list of an administrative group. | 1689 | /// Only an administrator can modify the membership list of an administrative group. |
| 2470 | DS_SENSITIVE_GROUP_VIOLATION = 0xC00002CD, | 1690 | DS_SENSITIVE_GROUP_VIOLATION = 0xC00002CD, |
| 2471 | |||
| 2472 | /// A device was removed so enumeration must be restarted. | 1691 | /// A device was removed so enumeration must be restarted. |
| 2473 | PNP_RESTART_ENUMERATION = 0xC00002CE, | 1692 | PNP_RESTART_ENUMERATION = 0xC00002CE, |
| 2474 | |||
| 2475 | /// The journal entry has been deleted from the journal. | 1693 | /// The journal entry has been deleted from the journal. |
| 2476 | JOURNAL_ENTRY_DELETED = 0xC00002CF, | 1694 | JOURNAL_ENTRY_DELETED = 0xC00002CF, |
| 2477 | |||
| 2478 | /// Cannot change the primary group ID of a domain controller account. | 1695 | /// Cannot change the primary group ID of a domain controller account. |
| 2479 | DS_CANT_MOD_PRIMARYGROUPID = 0xC00002D0, | 1696 | DS_CANT_MOD_PRIMARYGROUPID = 0xC00002D0, |
| 2480 | |||
| 2481 | /// {Fatal System Error} The system image %s is not properly signed. | 1697 | /// {Fatal System Error} The system image %s is not properly signed. |
| 2482 | /// The file has been replaced with the signed file. The system has been shut down. | 1698 | /// The file has been replaced with the signed file. The system has been shut down. |
| 2483 | SYSTEM_IMAGE_BAD_SIGNATURE = 0xC00002D1, | 1699 | SYSTEM_IMAGE_BAD_SIGNATURE = 0xC00002D1, |
| 2484 | |||
| 2485 | /// The device will not start without a reboot. | 1700 | /// The device will not start without a reboot. |
| 2486 | PNP_REBOOT_REQUIRED = 0xC00002D2, | 1701 | PNP_REBOOT_REQUIRED = 0xC00002D2, |
| 2487 | |||
| 2488 | /// The power state of the current device cannot support this request. | 1702 | /// The power state of the current device cannot support this request. |
| 2489 | POWER_STATE_INVALID = 0xC00002D3, | 1703 | POWER_STATE_INVALID = 0xC00002D3, |
| 2490 | |||
| 2491 | /// The specified group type is invalid. | 1704 | /// The specified group type is invalid. |
| 2492 | DS_INVALID_GROUP_TYPE = 0xC00002D4, | 1705 | DS_INVALID_GROUP_TYPE = 0xC00002D4, |
| 2493 | |||
| 2494 | /// In a mixed domain, no nesting of a global group if the group is security enabled. | 1706 | /// In a mixed domain, no nesting of a global group if the group is security enabled. |
| 2495 | DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 0xC00002D5, | 1707 | DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 0xC00002D5, |
| 2496 | |||
| 2497 | /// In a mixed domain, cannot nest local groups with other local groups, if the group is security enabled. | 1708 | /// In a mixed domain, cannot nest local groups with other local groups, if the group is security enabled. |
| 2498 | DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 0xC00002D6, | 1709 | DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 0xC00002D6, |
| 2499 | |||
| 2500 | /// A global group cannot have a local group as a member. | 1710 | /// A global group cannot have a local group as a member. |
| 2501 | DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D7, | 1711 | DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D7, |
| 2502 | |||
| 2503 | /// A global group cannot have a universal group as a member. | 1712 | /// A global group cannot have a universal group as a member. |
| 2504 | DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 0xC00002D8, | 1713 | DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 0xC00002D8, |
| 2505 | |||
| 2506 | /// A universal group cannot have a local group as a member. | 1714 | /// A universal group cannot have a local group as a member. |
| 2507 | DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D9, | 1715 | DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D9, |
| 2508 | |||
| 2509 | /// A global group cannot have a cross-domain member. | 1716 | /// A global group cannot have a cross-domain member. |
| 2510 | DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 0xC00002DA, | 1717 | DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 0xC00002DA, |
| 2511 | |||
| 2512 | /// A local group cannot have another cross-domain local group as a member. | 1718 | /// A local group cannot have another cross-domain local group as a member. |
| 2513 | DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 0xC00002DB, | 1719 | DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 0xC00002DB, |
| 2514 | |||
| 2515 | /// Cannot change to a security-disabled group because primary members are in this group. | 1720 | /// Cannot change to a security-disabled group because primary members are in this group. |
| 2516 | DS_HAVE_PRIMARY_MEMBERS = 0xC00002DC, | 1721 | DS_HAVE_PRIMARY_MEMBERS = 0xC00002DC, |
| 2517 | |||
| 2518 | /// The WMI operation is not supported by the data block or method. | 1722 | /// The WMI operation is not supported by the data block or method. |
| 2519 | WMI_NOT_SUPPORTED = 0xC00002DD, | 1723 | WMI_NOT_SUPPORTED = 0xC00002DD, |
| 2520 | |||
| 2521 | /// There is not enough power to complete the requested operation. | 1724 | /// There is not enough power to complete the requested operation. |
| 2522 | INSUFFICIENT_POWER = 0xC00002DE, | 1725 | INSUFFICIENT_POWER = 0xC00002DE, |
| 2523 | |||
| 2524 | /// The Security Accounts Manager needs to get the boot password. | 1726 | /// The Security Accounts Manager needs to get the boot password. |
| 2525 | SAM_NEED_BOOTKEY_PASSWORD = 0xC00002DF, | 1727 | SAM_NEED_BOOTKEY_PASSWORD = 0xC00002DF, |
| 2526 | |||
| 2527 | /// The Security Accounts Manager needs to get the boot key from the floppy disk. | 1728 | /// The Security Accounts Manager needs to get the boot key from the floppy disk. |
| 2528 | SAM_NEED_BOOTKEY_FLOPPY = 0xC00002E0, | 1729 | SAM_NEED_BOOTKEY_FLOPPY = 0xC00002E0, |
| 2529 | |||
| 2530 | /// The directory service cannot start. | 1730 | /// The directory service cannot start. |
| 2531 | DS_CANT_START = 0xC00002E1, | 1731 | DS_CANT_START = 0xC00002E1, |
| 2532 | |||
| 2533 | /// The directory service could not start because of the following error: %hs Error Status: 0x%x. | 1732 | /// The directory service could not start because of the following error: %hs Error Status: 0x%x. |
| 2534 | /// Click OK to shut down this system and restart in Directory Services Restore Mode. | 1733 | /// Click OK to shut down this system and restart in Directory Services Restore Mode. |
| 2535 | /// Check the event log for more detailed information. | 1734 | /// Check the event log for more detailed information. |
| 2536 | DS_INIT_FAILURE = 0xC00002E2, | 1735 | DS_INIT_FAILURE = 0xC00002E2, |
| 2537 | |||
| 2538 | /// The Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. | 1736 | /// The Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. |
| 2539 | /// Click OK to shut down this system and restart in Safe Mode. | 1737 | /// Click OK to shut down this system and restart in Safe Mode. |
| 2540 | /// Check the event log for more detailed information. | 1738 | /// Check the event log for more detailed information. |
| 2541 | SAM_INIT_FAILURE = 0xC00002E3, | 1739 | SAM_INIT_FAILURE = 0xC00002E3, |
| 2542 | |||
| 2543 | /// The requested operation can be performed only on a global catalog server. | 1740 | /// The requested operation can be performed only on a global catalog server. |
| 2544 | DS_GC_REQUIRED = 0xC00002E4, | 1741 | DS_GC_REQUIRED = 0xC00002E4, |
| 2545 | |||
| 2546 | /// A local group can only be a member of other local groups in the same domain. | 1742 | /// A local group can only be a member of other local groups in the same domain. |
| 2547 | DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 0xC00002E5, | 1743 | DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 0xC00002E5, |
| 2548 | |||
| 2549 | /// Foreign security principals cannot be members of universal groups. | 1744 | /// Foreign security principals cannot be members of universal groups. |
| 2550 | DS_NO_FPO_IN_UNIVERSAL_GROUPS = 0xC00002E6, | 1745 | DS_NO_FPO_IN_UNIVERSAL_GROUPS = 0xC00002E6, |
| 2551 | |||
| 2552 | /// Your computer could not be joined to the domain. | 1746 | /// Your computer could not be joined to the domain. |
| 2553 | /// You have exceeded the maximum number of computer accounts you are allowed to create in this domain. | 1747 | /// You have exceeded the maximum number of computer accounts you are allowed to create in this domain. |
| 2554 | /// Contact your system administrator to have this limit reset or increased. | 1748 | /// Contact your system administrator to have this limit reset or increased. |
| 2555 | DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 0xC00002E7, | 1749 | DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 0xC00002E7, |
| 2556 | |||
| 2557 | /// This operation cannot be performed on the current domain. | 1750 | /// This operation cannot be performed on the current domain. |
| 2558 | CURRENT_DOMAIN_NOT_ALLOWED = 0xC00002E9, | 1751 | CURRENT_DOMAIN_NOT_ALLOWED = 0xC00002E9, |
| 2559 | |||
| 2560 | /// The directory or file cannot be created. | 1752 | /// The directory or file cannot be created. |
| 2561 | CANNOT_MAKE = 0xC00002EA, | 1753 | CANNOT_MAKE = 0xC00002EA, |
| 2562 | |||
| 2563 | /// The system is in the process of shutting down. | 1754 | /// The system is in the process of shutting down. |
| 2564 | SYSTEM_SHUTDOWN = 0xC00002EB, | 1755 | SYSTEM_SHUTDOWN = 0xC00002EB, |
| 2565 | |||
| 2566 | /// Directory Services could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. | 1756 | /// Directory Services could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. |
| 2567 | /// You can use the recovery console to diagnose the system further. | 1757 | /// You can use the recovery console to diagnose the system further. |
| 2568 | DS_INIT_FAILURE_CONSOLE = 0xC00002EC, | 1758 | DS_INIT_FAILURE_CONSOLE = 0xC00002EC, |
| 2569 | |||
| 2570 | /// Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. | 1759 | /// Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. |
| 2571 | /// You can use the recovery console to diagnose the system further. | 1760 | /// You can use the recovery console to diagnose the system further. |
| 2572 | DS_SAM_INIT_FAILURE_CONSOLE = 0xC00002ED, | 1761 | DS_SAM_INIT_FAILURE_CONSOLE = 0xC00002ED, |
| 2573 | |||
| 2574 | /// A security context was deleted before the context was completed. This is considered a logon failure. | 1762 | /// A security context was deleted before the context was completed. This is considered a logon failure. |
| 2575 | UNFINISHED_CONTEXT_DELETED = 0xC00002EE, | 1763 | UNFINISHED_CONTEXT_DELETED = 0xC00002EE, |
| 2576 | |||
| 2577 | /// The client is trying to negotiate a context and the server requires user-to-user but did not send a TGT reply. | 1764 | /// The client is trying to negotiate a context and the server requires user-to-user but did not send a TGT reply. |
| 2578 | NO_TGT_REPLY = 0xC00002EF, | 1765 | NO_TGT_REPLY = 0xC00002EF, |
| 2579 | |||
| 2580 | /// An object ID was not found in the file. | 1766 | /// An object ID was not found in the file. |
| 2581 | OBJECTID_NOT_FOUND = 0xC00002F0, | 1767 | OBJECTID_NOT_FOUND = 0xC00002F0, |
| 2582 | |||
| 2583 | /// Unable to accomplish the requested task because the local machine does not have any IP addresses. | 1768 | /// Unable to accomplish the requested task because the local machine does not have any IP addresses. |
| 2584 | NO_IP_ADDRESSES = 0xC00002F1, | 1769 | NO_IP_ADDRESSES = 0xC00002F1, |
| 2585 | |||
| 2586 | /// The supplied credential handle does not match the credential that is associated with the security context. | 1770 | /// The supplied credential handle does not match the credential that is associated with the security context. |
| 2587 | WRONG_CREDENTIAL_HANDLE = 0xC00002F2, | 1771 | WRONG_CREDENTIAL_HANDLE = 0xC00002F2, |
| 2588 | |||
| 2589 | /// The crypto system or checksum function is invalid because a required function is unavailable. | 1772 | /// The crypto system or checksum function is invalid because a required function is unavailable. |
| 2590 | CRYPTO_SYSTEM_INVALID = 0xC00002F3, | 1773 | CRYPTO_SYSTEM_INVALID = 0xC00002F3, |
| 2591 | |||
| 2592 | /// The number of maximum ticket referrals has been exceeded. | 1774 | /// The number of maximum ticket referrals has been exceeded. |
| 2593 | MAX_REFERRALS_EXCEEDED = 0xC00002F4, | 1775 | MAX_REFERRALS_EXCEEDED = 0xC00002F4, |
| 2594 | |||
| 2595 | /// The local machine must be a Kerberos KDC (domain controller) and it is not. | 1776 | /// The local machine must be a Kerberos KDC (domain controller) and it is not. |
| 2596 | MUST_BE_KDC = 0xC00002F5, | 1777 | MUST_BE_KDC = 0xC00002F5, |
| 2597 | |||
| 2598 | /// The other end of the security negotiation requires strong crypto but it is not supported on the local machine. | 1778 | /// The other end of the security negotiation requires strong crypto but it is not supported on the local machine. |
| 2599 | STRONG_CRYPTO_NOT_SUPPORTED = 0xC00002F6, | 1779 | STRONG_CRYPTO_NOT_SUPPORTED = 0xC00002F6, |
| 2600 | |||
| 2601 | /// The KDC reply contained more than one principal name. | 1780 | /// The KDC reply contained more than one principal name. |
| 2602 | TOO_MANY_PRINCIPALS = 0xC00002F7, | 1781 | TOO_MANY_PRINCIPALS = 0xC00002F7, |
| 2603 | |||
| 2604 | /// Expected to find PA data for a hint of what etype to use, but it was not found. | 1782 | /// Expected to find PA data for a hint of what etype to use, but it was not found. |
| 2605 | NO_PA_DATA = 0xC00002F8, | 1783 | NO_PA_DATA = 0xC00002F8, |
| 2606 | |||
| 2607 | /// The client certificate does not contain a valid UPN, or does not match the client name in the logon request. Contact your administrator. | 1784 | /// The client certificate does not contain a valid UPN, or does not match the client name in the logon request. Contact your administrator. |
| 2608 | PKINIT_NAME_MISMATCH = 0xC00002F9, | 1785 | PKINIT_NAME_MISMATCH = 0xC00002F9, |
| 2609 | |||
| 2610 | /// Smart card logon is required and was not used. | 1786 | /// Smart card logon is required and was not used. |
| 2611 | SMARTCARD_LOGON_REQUIRED = 0xC00002FA, | 1787 | SMARTCARD_LOGON_REQUIRED = 0xC00002FA, |
| 2612 | |||
| 2613 | /// An invalid request was sent to the KDC. | 1788 | /// An invalid request was sent to the KDC. |
| 2614 | KDC_INVALID_REQUEST = 0xC00002FB, | 1789 | KDC_INVALID_REQUEST = 0xC00002FB, |
| 2615 | |||
| 2616 | /// The KDC was unable to generate a referral for the service requested. | 1790 | /// The KDC was unable to generate a referral for the service requested. |
| 2617 | KDC_UNABLE_TO_REFER = 0xC00002FC, | 1791 | KDC_UNABLE_TO_REFER = 0xC00002FC, |
| 2618 | |||
| 2619 | /// The encryption type requested is not supported by the KDC. | 1792 | /// The encryption type requested is not supported by the KDC. |
| 2620 | KDC_UNKNOWN_ETYPE = 0xC00002FD, | 1793 | KDC_UNKNOWN_ETYPE = 0xC00002FD, |
| 2621 | |||
| 2622 | /// A system shutdown is in progress. | 1794 | /// A system shutdown is in progress. |
| 2623 | SHUTDOWN_IN_PROGRESS = 0xC00002FE, | 1795 | SHUTDOWN_IN_PROGRESS = 0xC00002FE, |
| 2624 | |||
| 2625 | /// The server machine is shutting down. | 1796 | /// The server machine is shutting down. |
| 2626 | SERVER_SHUTDOWN_IN_PROGRESS = 0xC00002FF, | 1797 | SERVER_SHUTDOWN_IN_PROGRESS = 0xC00002FF, |
| 2627 | |||
| 2628 | /// This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server. | 1798 | /// This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server. |
| 2629 | NOT_SUPPORTED_ON_SBS = 0xC0000300, | 1799 | NOT_SUPPORTED_ON_SBS = 0xC0000300, |
| 2630 | |||
| 2631 | /// The WMI GUID is no longer available. | 1800 | /// The WMI GUID is no longer available. |
| 2632 | WMI_GUID_DISCONNECTED = 0xC0000301, | 1801 | WMI_GUID_DISCONNECTED = 0xC0000301, |
| 2633 | |||
| 2634 | /// Collection or events for the WMI GUID is already disabled. | 1802 | /// Collection or events for the WMI GUID is already disabled. |
| 2635 | WMI_ALREADY_DISABLED = 0xC0000302, | 1803 | WMI_ALREADY_DISABLED = 0xC0000302, |
| 2636 | |||
| 2637 | /// Collection or events for the WMI GUID is already enabled. | 1804 | /// Collection or events for the WMI GUID is already enabled. |
| 2638 | WMI_ALREADY_ENABLED = 0xC0000303, | 1805 | WMI_ALREADY_ENABLED = 0xC0000303, |
| 2639 | |||
| 2640 | /// The master file table on the volume is too fragmented to complete this operation. | 1806 | /// The master file table on the volume is too fragmented to complete this operation. |
| 2641 | MFT_TOO_FRAGMENTED = 0xC0000304, | 1807 | MFT_TOO_FRAGMENTED = 0xC0000304, |
| 2642 | |||
| 2643 | /// Copy protection failure. | 1808 | /// Copy protection failure. |
| 2644 | COPY_PROTECTION_FAILURE = 0xC0000305, | 1809 | COPY_PROTECTION_FAILURE = 0xC0000305, |
| 2645 | |||
| 2646 | /// Copy protection error—DVD CSS Authentication failed. | 1810 | /// Copy protection error—DVD CSS Authentication failed. |
| 2647 | CSS_AUTHENTICATION_FAILURE = 0xC0000306, | 1811 | CSS_AUTHENTICATION_FAILURE = 0xC0000306, |
| 2648 | |||
| 2649 | /// Copy protection error—The specified sector does not contain a valid key. | 1812 | /// Copy protection error—The specified sector does not contain a valid key. |
| 2650 | CSS_KEY_NOT_PRESENT = 0xC0000307, | 1813 | CSS_KEY_NOT_PRESENT = 0xC0000307, |
| 2651 | |||
| 2652 | /// Copy protection error—DVD session key not established. | 1814 | /// Copy protection error—DVD session key not established. |
| 2653 | CSS_KEY_NOT_ESTABLISHED = 0xC0000308, | 1815 | CSS_KEY_NOT_ESTABLISHED = 0xC0000308, |
| 2654 | |||
| 2655 | /// Copy protection error—The read failed because the sector is encrypted. | 1816 | /// Copy protection error—The read failed because the sector is encrypted. |
| 2656 | CSS_SCRAMBLED_SECTOR = 0xC0000309, | 1817 | CSS_SCRAMBLED_SECTOR = 0xC0000309, |
| 2657 | |||
| 2658 | /// Copy protection error—The region of the specified DVD does not correspond to the region setting of the drive. | 1818 | /// Copy protection error—The region of the specified DVD does not correspond to the region setting of the drive. |
| 2659 | CSS_REGION_MISMATCH = 0xC000030A, | 1819 | CSS_REGION_MISMATCH = 0xC000030A, |
| 2660 | |||
| 2661 | /// Copy protection error—The region setting of the drive might be permanent. | 1820 | /// Copy protection error—The region setting of the drive might be permanent. |
| 2662 | CSS_RESETS_EXHAUSTED = 0xC000030B, | 1821 | CSS_RESETS_EXHAUSTED = 0xC000030B, |
| 2663 | |||
| 2664 | /// The Kerberos protocol encountered an error while validating the KDC certificate during smart card logon. | 1822 | /// The Kerberos protocol encountered an error while validating the KDC certificate during smart card logon. |
| 2665 | /// There is more information in the system event log. | 1823 | /// There is more information in the system event log. |
| 2666 | PKINIT_FAILURE = 0xC0000320, | 1824 | PKINIT_FAILURE = 0xC0000320, |
| 2667 | |||
| 2668 | /// The Kerberos protocol encountered an error while attempting to use the smart card subsystem. | 1825 | /// The Kerberos protocol encountered an error while attempting to use the smart card subsystem. |
| 2669 | SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321, | 1826 | SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321, |
| 2670 | |||
| 2671 | /// The target server does not have acceptable Kerberos credentials. | 1827 | /// The target server does not have acceptable Kerberos credentials. |
| 2672 | NO_KERB_KEY = 0xC0000322, | 1828 | NO_KERB_KEY = 0xC0000322, |
| 2673 | |||
| 2674 | /// The transport determined that the remote system is down. | 1829 | /// The transport determined that the remote system is down. |
| 2675 | HOST_DOWN = 0xC0000350, | 1830 | HOST_DOWN = 0xC0000350, |
| 2676 | |||
| 2677 | /// An unsupported pre-authentication mechanism was presented to the Kerberos package. | 1831 | /// An unsupported pre-authentication mechanism was presented to the Kerberos package. |
| 2678 | UNSUPPORTED_PREAUTH = 0xC0000351, | 1832 | UNSUPPORTED_PREAUTH = 0xC0000351, |
| 2679 | |||
| 2680 | /// The encryption algorithm that is used on the source file needs a bigger key buffer than the one that is used on the destination file. | 1833 | /// The encryption algorithm that is used on the source file needs a bigger key buffer than the one that is used on the destination file. |
| 2681 | EFS_ALG_BLOB_TOO_BIG = 0xC0000352, | 1834 | EFS_ALG_BLOB_TOO_BIG = 0xC0000352, |
| 2682 | |||
| 2683 | /// An attempt to remove a processes DebugPort was made, but a port was not already associated with the process. | 1835 | /// An attempt to remove a processes DebugPort was made, but a port was not already associated with the process. |
| 2684 | PORT_NOT_SET = 0xC0000353, | 1836 | PORT_NOT_SET = 0xC0000353, |
| 2685 | |||
| 2686 | /// An attempt to do an operation on a debug port failed because the port is in the process of being deleted. | 1837 | /// An attempt to do an operation on a debug port failed because the port is in the process of being deleted. |
| 2687 | DEBUGGER_INACTIVE = 0xC0000354, | 1838 | DEBUGGER_INACTIVE = 0xC0000354, |
| 2688 | |||
| 2689 | /// This version of Windows is not compatible with the behavior version of the directory forest, domain, or domain controller. | 1839 | /// This version of Windows is not compatible with the behavior version of the directory forest, domain, or domain controller. |
| 2690 | DS_VERSION_CHECK_FAILURE = 0xC0000355, | 1840 | DS_VERSION_CHECK_FAILURE = 0xC0000355, |
| 2691 | |||
| 2692 | /// The specified event is currently not being audited. | 1841 | /// The specified event is currently not being audited. |
| 2693 | AUDITING_DISABLED = 0xC0000356, | 1842 | AUDITING_DISABLED = 0xC0000356, |
| 2694 | |||
| 2695 | /// The machine account was created prior to Windows NT 4.0 operating system. The account needs to be recreated. | 1843 | /// The machine account was created prior to Windows NT 4.0 operating system. The account needs to be recreated. |
| 2696 | PRENT4_MACHINE_ACCOUNT = 0xC0000357, | 1844 | PRENT4_MACHINE_ACCOUNT = 0xC0000357, |
| 2697 | |||
| 2698 | /// An account group cannot have a universal group as a member. | 1845 | /// An account group cannot have a universal group as a member. |
| 2699 | DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 0xC0000358, | 1846 | DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 0xC0000358, |
| 2700 | |||
| 2701 | /// The specified image file did not have the correct format; it appears to be a 32-bit Windows image. | 1847 | /// The specified image file did not have the correct format; it appears to be a 32-bit Windows image. |
| 2702 | INVALID_IMAGE_WIN_32 = 0xC0000359, | 1848 | INVALID_IMAGE_WIN_32 = 0xC0000359, |
| 2703 | |||
| 2704 | /// The specified image file did not have the correct format; it appears to be a 64-bit Windows image. | 1849 | /// The specified image file did not have the correct format; it appears to be a 64-bit Windows image. |
| 2705 | INVALID_IMAGE_WIN_64 = 0xC000035A, | 1850 | INVALID_IMAGE_WIN_64 = 0xC000035A, |
| 2706 | |||
| 2707 | /// The client's supplied SSPI channel bindings were incorrect. | 1851 | /// The client's supplied SSPI channel bindings were incorrect. |
| 2708 | BAD_BINDINGS = 0xC000035B, | 1852 | BAD_BINDINGS = 0xC000035B, |
| 2709 | |||
| 2710 | /// The client session has expired; so the client must re-authenticate to continue accessing the remote resources. | 1853 | /// The client session has expired; so the client must re-authenticate to continue accessing the remote resources. |
| 2711 | NETWORK_SESSION_EXPIRED = 0xC000035C, | 1854 | NETWORK_SESSION_EXPIRED = 0xC000035C, |
| 2712 | |||
| 2713 | /// The AppHelp dialog box canceled; thus preventing the application from starting. | 1855 | /// The AppHelp dialog box canceled; thus preventing the application from starting. |
| 2714 | APPHELP_BLOCK = 0xC000035D, | 1856 | APPHELP_BLOCK = 0xC000035D, |
| 2715 | |||
| 2716 | /// The SID filtering operation removed all SIDs. | 1857 | /// The SID filtering operation removed all SIDs. |
| 2717 | ALL_SIDS_FILTERED = 0xC000035E, | 1858 | ALL_SIDS_FILTERED = 0xC000035E, |
| 2718 | |||
| 2719 | /// The driver was not loaded because the system is starting in safe mode. | 1859 | /// The driver was not loaded because the system is starting in safe mode. |
| 2720 | NOT_SAFE_MODE_DRIVER = 0xC000035F, | 1860 | NOT_SAFE_MODE_DRIVER = 0xC000035F, |
| 2721 | |||
| 2722 | /// Access to %1 has been restricted by your Administrator by the default software restriction policy level. | 1861 | /// Access to %1 has been restricted by your Administrator by the default software restriction policy level. |
| 2723 | ACCESS_DISABLED_BY_POLICY_DEFAULT = 0xC0000361, | 1862 | ACCESS_DISABLED_BY_POLICY_DEFAULT = 0xC0000361, |
| 2724 | |||
| 2725 | /// Access to %1 has been restricted by your Administrator by location with policy rule %2 placed on path %3. | 1863 | /// Access to %1 has been restricted by your Administrator by location with policy rule %2 placed on path %3. |
| 2726 | ACCESS_DISABLED_BY_POLICY_PATH = 0xC0000362, | 1864 | ACCESS_DISABLED_BY_POLICY_PATH = 0xC0000362, |
| 2727 | |||
| 2728 | /// Access to %1 has been restricted by your Administrator by software publisher policy. | 1865 | /// Access to %1 has been restricted by your Administrator by software publisher policy. |
| 2729 | ACCESS_DISABLED_BY_POLICY_PUBLISHER = 0xC0000363, | 1866 | ACCESS_DISABLED_BY_POLICY_PUBLISHER = 0xC0000363, |
| 2730 | |||
| 2731 | /// Access to %1 has been restricted by your Administrator by policy rule %2. | 1867 | /// Access to %1 has been restricted by your Administrator by policy rule %2. |
| 2732 | ACCESS_DISABLED_BY_POLICY_OTHER = 0xC0000364, | 1868 | ACCESS_DISABLED_BY_POLICY_OTHER = 0xC0000364, |
| 2733 | |||
| 2734 | /// The driver was not loaded because it failed its initialization call. | 1869 | /// The driver was not loaded because it failed its initialization call. |
| 2735 | FAILED_DRIVER_ENTRY = 0xC0000365, | 1870 | FAILED_DRIVER_ENTRY = 0xC0000365, |
| 2736 | |||
| 2737 | /// The device encountered an error while applying power or reading the device configuration. | 1871 | /// The device encountered an error while applying power or reading the device configuration. |
| 2738 | /// This might be caused by a failure of your hardware or by a poor connection. | 1872 | /// This might be caused by a failure of your hardware or by a poor connection. |
| 2739 | DEVICE_ENUMERATION_ERROR = 0xC0000366, | 1873 | DEVICE_ENUMERATION_ERROR = 0xC0000366, |
| 2740 | |||
| 2741 | /// The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached. | 1874 | /// The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached. |
| 2742 | MOUNT_POINT_NOT_RESOLVED = 0xC0000368, | 1875 | MOUNT_POINT_NOT_RESOLVED = 0xC0000368, |
| 2743 | |||
| 2744 | /// The device object parameter is either not a valid device object or is not attached to the volume that is specified by the file name. | 1876 | /// The device object parameter is either not a valid device object or is not attached to the volume that is specified by the file name. |
| 2745 | INVALID_DEVICE_OBJECT_PARAMETER = 0xC0000369, | 1877 | INVALID_DEVICE_OBJECT_PARAMETER = 0xC0000369, |
| 2746 | |||
| 2747 | /// A machine check error has occurred. | 1878 | /// A machine check error has occurred. |
| 2748 | /// Check the system event log for additional information. | 1879 | /// Check the system event log for additional information. |
| 2749 | MCA_OCCURED = 0xC000036A, | 1880 | MCA_OCCURED = 0xC000036A, |
| 2750 | |||
| 2751 | /// Driver %2 has been blocked from loading. | 1881 | /// Driver %2 has been blocked from loading. |
| 2752 | DRIVER_BLOCKED_CRITICAL = 0xC000036B, | 1882 | DRIVER_BLOCKED_CRITICAL = 0xC000036B, |
| 2753 | |||
| 2754 | /// Driver %2 has been blocked from loading. | 1883 | /// Driver %2 has been blocked from loading. |
| 2755 | DRIVER_BLOCKED = 0xC000036C, | 1884 | DRIVER_BLOCKED = 0xC000036C, |
| 2756 | |||
| 2757 | /// There was error [%2] processing the driver database. | 1885 | /// There was error [%2] processing the driver database. |
| 2758 | DRIVER_DATABASE_ERROR = 0xC000036D, | 1886 | DRIVER_DATABASE_ERROR = 0xC000036D, |
| 2759 | |||
| 2760 | /// System hive size has exceeded its limit. | 1887 | /// System hive size has exceeded its limit. |
| 2761 | SYSTEM_HIVE_TOO_LARGE = 0xC000036E, | 1888 | SYSTEM_HIVE_TOO_LARGE = 0xC000036E, |
| 2762 | |||
| 2763 | /// A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image. | 1889 | /// A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image. |
| 2764 | INVALID_IMPORT_OF_NON_DLL = 0xC000036F, | 1890 | INVALID_IMPORT_OF_NON_DLL = 0xC000036F, |
| 2765 | |||
| 2766 | /// The local account store does not contain secret material for the specified account. | 1891 | /// The local account store does not contain secret material for the specified account. |
| 2767 | NO_SECRETS = 0xC0000371, | 1892 | NO_SECRETS = 0xC0000371, |
| 2768 | |||
| 2769 | /// Access to %1 has been restricted by your Administrator by policy rule %2. | 1893 | /// Access to %1 has been restricted by your Administrator by policy rule %2. |
| 2770 | ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 0xC0000372, | 1894 | ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 0xC0000372, |
| 2771 | |||
| 2772 | /// The system was not able to allocate enough memory to perform a stack switch. | 1895 | /// The system was not able to allocate enough memory to perform a stack switch. |
| 2773 | FAILED_STACK_SWITCH = 0xC0000373, | 1896 | FAILED_STACK_SWITCH = 0xC0000373, |
| 2774 | |||
| 2775 | /// A heap has been corrupted. | 1897 | /// A heap has been corrupted. |
| 2776 | HEAP_CORRUPTION = 0xC0000374, | 1898 | HEAP_CORRUPTION = 0xC0000374, |
| 2777 | |||
| 2778 | /// An incorrect PIN was presented to the smart card. | 1899 | /// An incorrect PIN was presented to the smart card. |
| 2779 | SMARTCARD_WRONG_PIN = 0xC0000380, | 1900 | SMARTCARD_WRONG_PIN = 0xC0000380, |
| 2780 | |||
| 2781 | /// The smart card is blocked. | 1901 | /// The smart card is blocked. |
| 2782 | SMARTCARD_CARD_BLOCKED = 0xC0000381, | 1902 | SMARTCARD_CARD_BLOCKED = 0xC0000381, |
| 2783 | |||
| 2784 | /// No PIN was presented to the smart card. | 1903 | /// No PIN was presented to the smart card. |
| 2785 | SMARTCARD_CARD_NOT_AUTHENTICATED = 0xC0000382, | 1904 | SMARTCARD_CARD_NOT_AUTHENTICATED = 0xC0000382, |
| 2786 | |||
| 2787 | /// No smart card is available. | 1905 | /// No smart card is available. |
| 2788 | SMARTCARD_NO_CARD = 0xC0000383, | 1906 | SMARTCARD_NO_CARD = 0xC0000383, |
| 2789 | |||
| 2790 | /// The requested key container does not exist on the smart card. | 1907 | /// The requested key container does not exist on the smart card. |
| 2791 | SMARTCARD_NO_KEY_CONTAINER = 0xC0000384, | 1908 | SMARTCARD_NO_KEY_CONTAINER = 0xC0000384, |
| 2792 | |||
| 2793 | /// The requested certificate does not exist on the smart card. | 1909 | /// The requested certificate does not exist on the smart card. |
| 2794 | SMARTCARD_NO_CERTIFICATE = 0xC0000385, | 1910 | SMARTCARD_NO_CERTIFICATE = 0xC0000385, |
| 2795 | |||
| 2796 | /// The requested keyset does not exist. | 1911 | /// The requested keyset does not exist. |
| 2797 | SMARTCARD_NO_KEYSET = 0xC0000386, | 1912 | SMARTCARD_NO_KEYSET = 0xC0000386, |
| 2798 | |||
| 2799 | /// A communication error with the smart card has been detected. | 1913 | /// A communication error with the smart card has been detected. |
| 2800 | SMARTCARD_IO_ERROR = 0xC0000387, | 1914 | SMARTCARD_IO_ERROR = 0xC0000387, |
| 2801 | |||
| 2802 | /// The system detected a possible attempt to compromise security. | 1915 | /// The system detected a possible attempt to compromise security. |
| 2803 | /// Ensure that you can contact the server that authenticated you. | 1916 | /// Ensure that you can contact the server that authenticated you. |
| 2804 | DOWNGRADE_DETECTED = 0xC0000388, | 1917 | DOWNGRADE_DETECTED = 0xC0000388, |
| 2805 | |||
| 2806 | /// The smart card certificate used for authentication has been revoked. Contact your system administrator. | 1918 | /// The smart card certificate used for authentication has been revoked. Contact your system administrator. |
| 2807 | /// There might be additional information in the event log. | 1919 | /// There might be additional information in the event log. |
| 2808 | SMARTCARD_CERT_REVOKED = 0xC0000389, | 1920 | SMARTCARD_CERT_REVOKED = 0xC0000389, |
| 2809 | |||
| 2810 | /// An untrusted certificate authority was detected while processing the smart card certificate that is used for authentication. Contact your system administrator. | 1921 | /// An untrusted certificate authority was detected while processing the smart card certificate that is used for authentication. Contact your system administrator. |
| 2811 | ISSUING_CA_UNTRUSTED = 0xC000038A, | 1922 | ISSUING_CA_UNTRUSTED = 0xC000038A, |
| 2812 | |||
| 2813 | /// The revocation status of the smart card certificate that is used for authentication could not be determined. Contact your system administrator. | 1923 | /// The revocation status of the smart card certificate that is used for authentication could not be determined. Contact your system administrator. |
| 2814 | REVOCATION_OFFLINE_C = 0xC000038B, | 1924 | REVOCATION_OFFLINE_C = 0xC000038B, |
| 2815 | |||
| 2816 | /// The smart card certificate used for authentication was not trusted. Contact your system administrator. | 1925 | /// The smart card certificate used for authentication was not trusted. Contact your system administrator. |
| 2817 | PKINIT_CLIENT_FAILURE = 0xC000038C, | 1926 | PKINIT_CLIENT_FAILURE = 0xC000038C, |
| 2818 | |||
| 2819 | /// The smart card certificate used for authentication has expired. Contact your system administrator. | 1927 | /// The smart card certificate used for authentication has expired. Contact your system administrator. |
| 2820 | SMARTCARD_CERT_EXPIRED = 0xC000038D, | 1928 | SMARTCARD_CERT_EXPIRED = 0xC000038D, |
| 2821 | |||
| 2822 | /// The driver could not be loaded because a previous version of the driver is still in memory. | 1929 | /// The driver could not be loaded because a previous version of the driver is still in memory. |
| 2823 | DRIVER_FAILED_PRIOR_UNLOAD = 0xC000038E, | 1930 | DRIVER_FAILED_PRIOR_UNLOAD = 0xC000038E, |
| 2824 | |||
| 2825 | /// The smart card provider could not perform the action because the context was acquired as silent. | 1931 | /// The smart card provider could not perform the action because the context was acquired as silent. |
| 2826 | SMARTCARD_SILENT_CONTEXT = 0xC000038F, | 1932 | SMARTCARD_SILENT_CONTEXT = 0xC000038F, |
| 2827 | |||
| 2828 | /// The delegated trust creation quota of the current user has been exceeded. | 1933 | /// The delegated trust creation quota of the current user has been exceeded. |
| 2829 | PER_USER_TRUST_QUOTA_EXCEEDED = 0xC0000401, | 1934 | PER_USER_TRUST_QUOTA_EXCEEDED = 0xC0000401, |
| 2830 | |||
| 2831 | /// The total delegated trust creation quota has been exceeded. | 1935 | /// The total delegated trust creation quota has been exceeded. |
| 2832 | ALL_USER_TRUST_QUOTA_EXCEEDED = 0xC0000402, | 1936 | ALL_USER_TRUST_QUOTA_EXCEEDED = 0xC0000402, |
| 2833 | |||
| 2834 | /// The delegated trust deletion quota of the current user has been exceeded. | 1937 | /// The delegated trust deletion quota of the current user has been exceeded. |
| 2835 | USER_DELETE_TRUST_QUOTA_EXCEEDED = 0xC0000403, | 1938 | USER_DELETE_TRUST_QUOTA_EXCEEDED = 0xC0000403, |
| 2836 | |||
| 2837 | /// The requested name already exists as a unique identifier. | 1939 | /// The requested name already exists as a unique identifier. |
| 2838 | DS_NAME_NOT_UNIQUE = 0xC0000404, | 1940 | DS_NAME_NOT_UNIQUE = 0xC0000404, |
| 2839 | |||
| 2840 | /// The requested object has a non-unique identifier and cannot be retrieved. | 1941 | /// The requested object has a non-unique identifier and cannot be retrieved. |
| 2841 | DS_DUPLICATE_ID_FOUND = 0xC0000405, | 1942 | DS_DUPLICATE_ID_FOUND = 0xC0000405, |
| 2842 | |||
| 2843 | /// The group cannot be converted due to attribute restrictions on the requested group type. | 1943 | /// The group cannot be converted due to attribute restrictions on the requested group type. |
| 2844 | DS_GROUP_CONVERSION_ERROR = 0xC0000406, | 1944 | DS_GROUP_CONVERSION_ERROR = 0xC0000406, |
| 2845 | |||
| 2846 | /// {Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation. | 1945 | /// {Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation. |
| 2847 | VOLSNAP_PREPARE_HIBERNATE = 0xC0000407, | 1946 | VOLSNAP_PREPARE_HIBERNATE = 0xC0000407, |
| 2848 | |||
| 2849 | /// Kerberos sub-protocol User2User is required. | 1947 | /// Kerberos sub-protocol User2User is required. |
| 2850 | USER2USER_REQUIRED = 0xC0000408, | 1948 | USER2USER_REQUIRED = 0xC0000408, |
| 2851 | |||
| 2852 | /// The system detected an overrun of a stack-based buffer in this application. | 1949 | /// The system detected an overrun of a stack-based buffer in this application. |
| 2853 | /// This overrun could potentially allow a malicious user to gain control of this application. | 1950 | /// This overrun could potentially allow a malicious user to gain control of this application. |
| 2854 | STACK_BUFFER_OVERRUN = 0xC0000409, | 1951 | STACK_BUFFER_OVERRUN = 0xC0000409, |
| 2855 | |||
| 2856 | /// The Kerberos subsystem encountered an error. | 1952 | /// The Kerberos subsystem encountered an error. |
| 2857 | /// A service for user protocol request was made against a domain controller which does not support service for user. | 1953 | /// A service for user protocol request was made against a domain controller which does not support service for user. |
| 2858 | NO_S4U_PROT_SUPPORT = 0xC000040A, | 1954 | NO_S4U_PROT_SUPPORT = 0xC000040A, |
| 2859 | |||
| 2860 | /// An attempt was made by this server to make a Kerberos constrained delegation request for a target that is outside the server realm. | 1955 | /// An attempt was made by this server to make a Kerberos constrained delegation request for a target that is outside the server realm. |
| 2861 | /// This action is not supported and the resulting error indicates a misconfiguration on the allowed-to-delegate-to list for this server. Contact your administrator. | 1956 | /// This action is not supported and the resulting error indicates a misconfiguration on the allowed-to-delegate-to list for this server. Contact your administrator. |
| 2862 | CROSSREALM_DELEGATION_FAILURE = 0xC000040B, | 1957 | CROSSREALM_DELEGATION_FAILURE = 0xC000040B, |
| 2863 | |||
| 2864 | /// The revocation status of the domain controller certificate used for smart card authentication could not be determined. | 1958 | /// The revocation status of the domain controller certificate used for smart card authentication could not be determined. |
| 2865 | /// There is additional information in the system event log. Contact your system administrator. | 1959 | /// There is additional information in the system event log. Contact your system administrator. |
| 2866 | REVOCATION_OFFLINE_KDC = 0xC000040C, | 1960 | REVOCATION_OFFLINE_KDC = 0xC000040C, |
| 2867 | |||
| 2868 | /// An untrusted certificate authority was detected while processing the domain controller certificate used for authentication. | 1961 | /// An untrusted certificate authority was detected while processing the domain controller certificate used for authentication. |
| 2869 | /// There is additional information in the system event log. Contact your system administrator. | 1962 | /// There is additional information in the system event log. Contact your system administrator. |
| 2870 | ISSUING_CA_UNTRUSTED_KDC = 0xC000040D, | 1963 | ISSUING_CA_UNTRUSTED_KDC = 0xC000040D, |
| 2871 | |||
| 2872 | /// The domain controller certificate used for smart card logon has expired. | 1964 | /// The domain controller certificate used for smart card logon has expired. |
| 2873 | /// Contact your system administrator with the contents of your system event log. | 1965 | /// Contact your system administrator with the contents of your system event log. |
| 2874 | KDC_CERT_EXPIRED = 0xC000040E, | 1966 | KDC_CERT_EXPIRED = 0xC000040E, |
| 2875 | |||
| 2876 | /// The domain controller certificate used for smart card logon has been revoked. | 1967 | /// The domain controller certificate used for smart card logon has been revoked. |
| 2877 | /// Contact your system administrator with the contents of your system event log. | 1968 | /// Contact your system administrator with the contents of your system event log. |
| 2878 | KDC_CERT_REVOKED = 0xC000040F, | 1969 | KDC_CERT_REVOKED = 0xC000040F, |
| 2879 | |||
| 2880 | /// Data present in one of the parameters is more than the function can operate on. | 1970 | /// Data present in one of the parameters is more than the function can operate on. |
| 2881 | PARAMETER_QUOTA_EXCEEDED = 0xC0000410, | 1971 | PARAMETER_QUOTA_EXCEEDED = 0xC0000410, |
| 2882 | |||
| 2883 | /// The system has failed to hibernate (The error code is %hs). | 1972 | /// The system has failed to hibernate (The error code is %hs). |
| 2884 | /// Hibernation will be disabled until the system is restarted. | 1973 | /// Hibernation will be disabled until the system is restarted. |
| 2885 | HIBERNATION_FAILURE = 0xC0000411, | 1974 | HIBERNATION_FAILURE = 0xC0000411, |
| 2886 | |||
| 2887 | /// An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed. | 1975 | /// An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed. |
| 2888 | DELAY_LOAD_FAILED = 0xC0000412, | 1976 | DELAY_LOAD_FAILED = 0xC0000412, |
| 2889 | |||
| 2890 | /// Logon Failure: The machine you are logging onto is protected by an authentication firewall. | 1977 | /// Logon Failure: The machine you are logging onto is protected by an authentication firewall. |
| 2891 | /// The specified account is not allowed to authenticate to the machine. | 1978 | /// The specified account is not allowed to authenticate to the machine. |
| 2892 | AUTHENTICATION_FIREWALL_FAILED = 0xC0000413, | 1979 | AUTHENTICATION_FIREWALL_FAILED = 0xC0000413, |
| 2893 | |||
| 2894 | /// %hs is a 16-bit application. You do not have permissions to execute 16-bit applications. | 1980 | /// %hs is a 16-bit application. You do not have permissions to execute 16-bit applications. |
| 2895 | /// Check your permissions with your system administrator. | 1981 | /// Check your permissions with your system administrator. |
| 2896 | VDM_DISALLOWED = 0xC0000414, | 1982 | VDM_DISALLOWED = 0xC0000414, |
| 2897 | |||
| 2898 | /// {Display Driver Stopped Responding} The %hs display driver has stopped working normally. | 1983 | /// {Display Driver Stopped Responding} The %hs display driver has stopped working normally. |
| 2899 | /// Save your work and reboot the system to restore full display functionality. | 1984 | /// Save your work and reboot the system to restore full display functionality. |
| 2900 | /// The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft. | 1985 | /// The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft. |
| 2901 | HUNG_DISPLAY_DRIVER_THREAD = 0xC0000415, | 1986 | HUNG_DISPLAY_DRIVER_THREAD = 0xC0000415, |
| 2902 | |||
| 2903 | /// The Desktop heap encountered an error while allocating session memory. | 1987 | /// The Desktop heap encountered an error while allocating session memory. |
| 2904 | /// There is more information in the system event log. | 1988 | /// There is more information in the system event log. |
| 2905 | INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 0xC0000416, | 1989 | INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 0xC0000416, |
| 2906 | |||
| 2907 | /// An invalid parameter was passed to a C runtime function. | 1990 | /// An invalid parameter was passed to a C runtime function. |
| 2908 | INVALID_CRUNTIME_PARAMETER = 0xC0000417, | 1991 | INVALID_CRUNTIME_PARAMETER = 0xC0000417, |
| 2909 | |||
| 2910 | /// The authentication failed because NTLM was blocked. | 1992 | /// The authentication failed because NTLM was blocked. |
| 2911 | NTLM_BLOCKED = 0xC0000418, | 1993 | NTLM_BLOCKED = 0xC0000418, |
| 2912 | |||
| 2913 | /// The source object's SID already exists in destination forest. | 1994 | /// The source object's SID already exists in destination forest. |
| 2914 | DS_SRC_SID_EXISTS_IN_FOREST = 0xC0000419, | 1995 | DS_SRC_SID_EXISTS_IN_FOREST = 0xC0000419, |
| 2915 | |||
| 2916 | /// The domain name of the trusted domain already exists in the forest. | 1996 | /// The domain name of the trusted domain already exists in the forest. |
| 2917 | DS_DOMAIN_NAME_EXISTS_IN_FOREST = 0xC000041A, | 1997 | DS_DOMAIN_NAME_EXISTS_IN_FOREST = 0xC000041A, |
| 2918 | |||
| 2919 | /// The flat name of the trusted domain already exists in the forest. | 1998 | /// The flat name of the trusted domain already exists in the forest. |
| 2920 | DS_FLAT_NAME_EXISTS_IN_FOREST = 0xC000041B, | 1999 | DS_FLAT_NAME_EXISTS_IN_FOREST = 0xC000041B, |
| 2921 | |||
| 2922 | /// The User Principal Name (UPN) is invalid. | 2000 | /// The User Principal Name (UPN) is invalid. |
| 2923 | INVALID_USER_PRINCIPAL_NAME = 0xC000041C, | 2001 | INVALID_USER_PRINCIPAL_NAME = 0xC000041C, |
| 2924 | |||
| 2925 | /// There has been an assertion failure. | 2002 | /// There has been an assertion failure. |
| 2926 | ASSERTION_FAILURE = 0xC0000420, | 2003 | ASSERTION_FAILURE = 0xC0000420, |
| 2927 | |||
| 2928 | /// Application verifier has found an error in the current process. | 2004 | /// Application verifier has found an error in the current process. |
| 2929 | VERIFIER_STOP = 0xC0000421, | 2005 | VERIFIER_STOP = 0xC0000421, |
| 2930 | |||
| 2931 | /// A user mode unwind is in progress. | 2006 | /// A user mode unwind is in progress. |
| 2932 | CALLBACK_POP_STACK = 0xC0000423, | 2007 | CALLBACK_POP_STACK = 0xC0000423, |
| 2933 | |||
| 2934 | /// %2 has been blocked from loading due to incompatibility with this system. | 2008 | /// %2 has been blocked from loading due to incompatibility with this system. |
| 2935 | /// Contact your software vendor for a compatible version of the driver. | 2009 | /// Contact your software vendor for a compatible version of the driver. |
| 2936 | INCOMPATIBLE_DRIVER_BLOCKED = 0xC0000424, | 2010 | INCOMPATIBLE_DRIVER_BLOCKED = 0xC0000424, |
| 2937 | |||
| 2938 | /// Illegal operation attempted on a registry key which has already been unloaded. | 2011 | /// Illegal operation attempted on a registry key which has already been unloaded. |
| 2939 | HIVE_UNLOADED = 0xC0000425, | 2012 | HIVE_UNLOADED = 0xC0000425, |
| 2940 | |||
| 2941 | /// Compression is disabled for this volume. | 2013 | /// Compression is disabled for this volume. |
| 2942 | COMPRESSION_DISABLED = 0xC0000426, | 2014 | COMPRESSION_DISABLED = 0xC0000426, |
| 2943 | |||
| 2944 | /// The requested operation could not be completed due to a file system limitation. | 2015 | /// The requested operation could not be completed due to a file system limitation. |
| 2945 | FILE_SYSTEM_LIMITATION = 0xC0000427, | 2016 | FILE_SYSTEM_LIMITATION = 0xC0000427, |
| 2946 | |||
| 2947 | /// The hash for image %hs cannot be found in the system catalogs. | 2017 | /// The hash for image %hs cannot be found in the system catalogs. |
| 2948 | /// The image is likely corrupt or the victim of tampering. | 2018 | /// The image is likely corrupt or the victim of tampering. |
| 2949 | INVALID_IMAGE_HASH = 0xC0000428, | 2019 | INVALID_IMAGE_HASH = 0xC0000428, |
| 2950 | |||
| 2951 | /// The implementation is not capable of performing the request. | 2020 | /// The implementation is not capable of performing the request. |
| 2952 | NOT_CAPABLE = 0xC0000429, | 2021 | NOT_CAPABLE = 0xC0000429, |
| 2953 | |||
| 2954 | /// The requested operation is out of order with respect to other operations. | 2022 | /// The requested operation is out of order with respect to other operations. |
| 2955 | REQUEST_OUT_OF_SEQUENCE = 0xC000042A, | 2023 | REQUEST_OUT_OF_SEQUENCE = 0xC000042A, |
| 2956 | |||
| 2957 | /// An operation attempted to exceed an implementation-defined limit. | 2024 | /// An operation attempted to exceed an implementation-defined limit. |
| 2958 | IMPLEMENTATION_LIMIT = 0xC000042B, | 2025 | IMPLEMENTATION_LIMIT = 0xC000042B, |
| 2959 | |||
| 2960 | /// The requested operation requires elevation. | 2026 | /// The requested operation requires elevation. |
| 2961 | ELEVATION_REQUIRED = 0xC000042C, | 2027 | ELEVATION_REQUIRED = 0xC000042C, |
| 2962 | |||
| 2963 | /// The required security context does not exist. | 2028 | /// The required security context does not exist. |
| 2964 | NO_SECURITY_CONTEXT = 0xC000042D, | 2029 | NO_SECURITY_CONTEXT = 0xC000042D, |
| 2965 | |||
| 2966 | /// The PKU2U protocol encountered an error while attempting to utilize the associated certificates. | 2030 | /// The PKU2U protocol encountered an error while attempting to utilize the associated certificates. |
| 2967 | PKU2U_CERT_FAILURE = 0xC000042E, | 2031 | PKU2U_CERT_FAILURE = 0xC000042E, |
| 2968 | |||
| 2969 | /// The operation was attempted beyond the valid data length of the file. | 2032 | /// The operation was attempted beyond the valid data length of the file. |
| 2970 | BEYOND_VDL = 0xC0000432, | 2033 | BEYOND_VDL = 0xC0000432, |
| 2971 | |||
| 2972 | /// The attempted write operation encountered a write already in progress for some portion of the range. | 2034 | /// The attempted write operation encountered a write already in progress for some portion of the range. |
| 2973 | ENCOUNTERED_WRITE_IN_PROGRESS = 0xC0000433, | 2035 | ENCOUNTERED_WRITE_IN_PROGRESS = 0xC0000433, |
| 2974 | |||
| 2975 | /// The page fault mappings changed in the middle of processing a fault so the operation must be retried. | 2036 | /// The page fault mappings changed in the middle of processing a fault so the operation must be retried. |
| 2976 | PTE_CHANGED = 0xC0000434, | 2037 | PTE_CHANGED = 0xC0000434, |
| 2977 | |||
| 2978 | /// The attempt to purge this file from memory failed to purge some or all the data from memory. | 2038 | /// The attempt to purge this file from memory failed to purge some or all the data from memory. |
| 2979 | PURGE_FAILED = 0xC0000435, | 2039 | PURGE_FAILED = 0xC0000435, |
| 2980 | |||
| 2981 | /// The requested credential requires confirmation. | 2040 | /// The requested credential requires confirmation. |
| 2982 | CRED_REQUIRES_CONFIRMATION = 0xC0000440, | 2041 | CRED_REQUIRES_CONFIRMATION = 0xC0000440, |
| 2983 | |||
| 2984 | /// The remote server sent an invalid response for a file being opened with Client Side Encryption. | 2042 | /// The remote server sent an invalid response for a file being opened with Client Side Encryption. |
| 2985 | CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 0xC0000441, | 2043 | CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 0xC0000441, |
| 2986 | |||
| 2987 | /// Client Side Encryption is not supported by the remote server even though it claims to support it. | 2044 | /// Client Side Encryption is not supported by the remote server even though it claims to support it. |
| 2988 | CS_ENCRYPTION_UNSUPPORTED_SERVER = 0xC0000442, | 2045 | CS_ENCRYPTION_UNSUPPORTED_SERVER = 0xC0000442, |
| 2989 | |||
| 2990 | /// File is encrypted and should be opened in Client Side Encryption mode. | 2046 | /// File is encrypted and should be opened in Client Side Encryption mode. |
| 2991 | CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 0xC0000443, | 2047 | CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 0xC0000443, |
| 2992 | |||
| 2993 | /// A new encrypted file is being created and a $EFS needs to be provided. | 2048 | /// A new encrypted file is being created and a $EFS needs to be provided. |
| 2994 | CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 0xC0000444, | 2049 | CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 0xC0000444, |
| 2995 | |||
| 2996 | /// The SMB client requested a CSE FSCTL on a non-CSE file. | 2050 | /// The SMB client requested a CSE FSCTL on a non-CSE file. |
| 2997 | CS_ENCRYPTION_FILE_NOT_CSE = 0xC0000445, | 2051 | CS_ENCRYPTION_FILE_NOT_CSE = 0xC0000445, |
| 2998 | |||
| 2999 | /// Indicates a particular Security ID cannot be assigned as the label of an object. | 2052 | /// Indicates a particular Security ID cannot be assigned as the label of an object. |
| 3000 | INVALID_LABEL = 0xC0000446, | 2053 | INVALID_LABEL = 0xC0000446, |
| 3001 | |||
| 3002 | /// The process hosting the driver for this device has terminated. | 2054 | /// The process hosting the driver for this device has terminated. |
| 3003 | DRIVER_PROCESS_TERMINATED = 0xC0000450, | 2055 | DRIVER_PROCESS_TERMINATED = 0xC0000450, |
| 3004 | |||
| 3005 | /// The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria. | 2056 | /// The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria. |
| 3006 | AMBIGUOUS_SYSTEM_DEVICE = 0xC0000451, | 2057 | AMBIGUOUS_SYSTEM_DEVICE = 0xC0000451, |
| 3007 | |||
| 3008 | /// The requested system device cannot be found. | 2058 | /// The requested system device cannot be found. |
| 3009 | SYSTEM_DEVICE_NOT_FOUND = 0xC0000452, | 2059 | SYSTEM_DEVICE_NOT_FOUND = 0xC0000452, |
| 3010 | |||
| 3011 | /// This boot application must be restarted. | 2060 | /// This boot application must be restarted. |
| 3012 | RESTART_BOOT_APPLICATION = 0xC0000453, | 2061 | RESTART_BOOT_APPLICATION = 0xC0000453, |
| 3013 | |||
| 3014 | /// Insufficient NVRAM resources exist to complete the API. A reboot might be required. | 2062 | /// Insufficient NVRAM resources exist to complete the API. A reboot might be required. |
| 3015 | INSUFFICIENT_NVRAM_RESOURCES = 0xC0000454, | 2063 | INSUFFICIENT_NVRAM_RESOURCES = 0xC0000454, |
| 3016 | |||
| 3017 | /// No ranges for the specified operation were able to be processed. | 2064 | /// No ranges for the specified operation were able to be processed. |
| 3018 | NO_RANGES_PROCESSED = 0xC0000460, | 2065 | NO_RANGES_PROCESSED = 0xC0000460, |
| 3019 | |||
| 3020 | /// The storage device does not support Offload Write. | 2066 | /// The storage device does not support Offload Write. |
| 3021 | DEVICE_FEATURE_NOT_SUPPORTED = 0xC0000463, | 2067 | DEVICE_FEATURE_NOT_SUPPORTED = 0xC0000463, |
| 3022 | |||
| 3023 | /// Data cannot be moved because the source device cannot communicate with the destination device. | 2068 | /// Data cannot be moved because the source device cannot communicate with the destination device. |
| 3024 | DEVICE_UNREACHABLE = 0xC0000464, | 2069 | DEVICE_UNREACHABLE = 0xC0000464, |
| 3025 | |||
| 3026 | /// The token representing the data is invalid or expired. | 2070 | /// The token representing the data is invalid or expired. |
| 3027 | INVALID_TOKEN = 0xC0000465, | 2071 | INVALID_TOKEN = 0xC0000465, |
| 3028 | |||
| 3029 | /// The file server is temporarily unavailable. | 2072 | /// The file server is temporarily unavailable. |
| 3030 | SERVER_UNAVAILABLE = 0xC0000466, | 2073 | SERVER_UNAVAILABLE = 0xC0000466, |
| 3031 | |||
| 3032 | /// The specified task name is invalid. | 2074 | /// The specified task name is invalid. |
| 3033 | INVALID_TASK_NAME = 0xC0000500, | 2075 | INVALID_TASK_NAME = 0xC0000500, |
| 3034 | |||
| 3035 | /// The specified task index is invalid. | 2076 | /// The specified task index is invalid. |
| 3036 | INVALID_TASK_INDEX = 0xC0000501, | 2077 | INVALID_TASK_INDEX = 0xC0000501, |
| 3037 | |||
| 3038 | /// The specified thread is already joining a task. | 2078 | /// The specified thread is already joining a task. |
| 3039 | THREAD_ALREADY_IN_TASK = 0xC0000502, | 2079 | THREAD_ALREADY_IN_TASK = 0xC0000502, |
| 3040 | |||
| 3041 | /// A callback has requested to bypass native code. | 2080 | /// A callback has requested to bypass native code. |
| 3042 | CALLBACK_BYPASS = 0xC0000503, | 2081 | CALLBACK_BYPASS = 0xC0000503, |
| 3043 | |||
| 3044 | /// A fail fast exception occurred. | 2082 | /// A fail fast exception occurred. |
| 3045 | /// Exception handlers will not be invoked and the process will be terminated immediately. | 2083 | /// Exception handlers will not be invoked and the process will be terminated immediately. |
| 3046 | FAIL_FAST_EXCEPTION = 0xC0000602, | 2084 | FAIL_FAST_EXCEPTION = 0xC0000602, |
| 3047 | |||
| 3048 | /// Windows cannot verify the digital signature for this file. | 2085 | /// Windows cannot verify the digital signature for this file. |
| 3049 | /// The signing certificate for this file has been revoked. | 2086 | /// The signing certificate for this file has been revoked. |
| 3050 | IMAGE_CERT_REVOKED = 0xC0000603, | 2087 | IMAGE_CERT_REVOKED = 0xC0000603, |
| 3051 | |||
| 3052 | /// The ALPC port is closed. | 2088 | /// The ALPC port is closed. |
| 3053 | PORT_CLOSED = 0xC0000700, | 2089 | PORT_CLOSED = 0xC0000700, |
| 3054 | |||
| 3055 | /// The ALPC message requested is no longer available. | 2090 | /// The ALPC message requested is no longer available. |
| 3056 | MESSAGE_LOST = 0xC0000701, | 2091 | MESSAGE_LOST = 0xC0000701, |
| 3057 | |||
| 3058 | /// The ALPC message supplied is invalid. | 2092 | /// The ALPC message supplied is invalid. |
| 3059 | INVALID_MESSAGE = 0xC0000702, | 2093 | INVALID_MESSAGE = 0xC0000702, |
| 3060 | |||
| 3061 | /// The ALPC message has been canceled. | 2094 | /// The ALPC message has been canceled. |
| 3062 | REQUEST_CANCELED = 0xC0000703, | 2095 | REQUEST_CANCELED = 0xC0000703, |
| 3063 | |||
| 3064 | /// Invalid recursive dispatch attempt. | 2096 | /// Invalid recursive dispatch attempt. |
| 3065 | RECURSIVE_DISPATCH = 0xC0000704, | 2097 | RECURSIVE_DISPATCH = 0xC0000704, |
| 3066 | |||
| 3067 | /// No receive buffer has been supplied in a synchronous request. | 2098 | /// No receive buffer has been supplied in a synchronous request. |
| 3068 | LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705, | 2099 | LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705, |
| 3069 | |||
| 3070 | /// The connection port is used in an invalid context. | 2100 | /// The connection port is used in an invalid context. |
| 3071 | LPC_INVALID_CONNECTION_USAGE = 0xC0000706, | 2101 | LPC_INVALID_CONNECTION_USAGE = 0xC0000706, |
| 3072 | |||
| 3073 | /// The ALPC port does not accept new request messages. | 2102 | /// The ALPC port does not accept new request messages. |
| 3074 | LPC_REQUESTS_NOT_ALLOWED = 0xC0000707, | 2103 | LPC_REQUESTS_NOT_ALLOWED = 0xC0000707, |
| 3075 | |||
| 3076 | /// The resource requested is already in use. | 2104 | /// The resource requested is already in use. |
| 3077 | RESOURCE_IN_USE = 0xC0000708, | 2105 | RESOURCE_IN_USE = 0xC0000708, |
| 3078 | |||
| 3079 | /// The hardware has reported an uncorrectable memory error. | 2106 | /// The hardware has reported an uncorrectable memory error. |
| 3080 | HARDWARE_MEMORY_ERROR = 0xC0000709, | 2107 | HARDWARE_MEMORY_ERROR = 0xC0000709, |
| 3081 | |||
| 3082 | /// Status 0x%08x was returned, waiting on handle 0x%x for wait 0x%p, in waiter 0x%p. | 2108 | /// Status 0x%08x was returned, waiting on handle 0x%x for wait 0x%p, in waiter 0x%p. |
| 3083 | THREADPOOL_HANDLE_EXCEPTION = 0xC000070A, | 2109 | THREADPOOL_HANDLE_EXCEPTION = 0xC000070A, |
| 3084 | |||
| 3085 | /// After a callback to 0x%p(0x%p), a completion call to Set event(0x%p) failed with status 0x%08x. | 2110 | /// After a callback to 0x%p(0x%p), a completion call to Set event(0x%p) failed with status 0x%08x. |
| 3086 | THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED = 0xC000070B, | 2111 | THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED = 0xC000070B, |
| 3087 | |||
| 3088 | /// After a callback to 0x%p(0x%p), a completion call to ReleaseSemaphore(0x%p, %d) failed with status 0x%08x. | 2112 | /// After a callback to 0x%p(0x%p), a completion call to ReleaseSemaphore(0x%p, %d) failed with status 0x%08x. |
| 3089 | THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED = 0xC000070C, | 2113 | THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED = 0xC000070C, |
| 3090 | |||
| 3091 | /// After a callback to 0x%p(0x%p), a completion call to ReleaseMutex(%p) failed with status 0x%08x. | 2114 | /// After a callback to 0x%p(0x%p), a completion call to ReleaseMutex(%p) failed with status 0x%08x. |
| 3092 | THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED = 0xC000070D, | 2115 | THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED = 0xC000070D, |
| 3093 | |||
| 3094 | /// After a callback to 0x%p(0x%p), a completion call to FreeLibrary(%p) failed with status 0x%08x. | 2116 | /// After a callback to 0x%p(0x%p), a completion call to FreeLibrary(%p) failed with status 0x%08x. |
| 3095 | THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED = 0xC000070E, | 2117 | THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED = 0xC000070E, |
| 3096 | |||
| 3097 | /// The thread pool 0x%p was released while a thread was posting a callback to 0x%p(0x%p) to it. | 2118 | /// The thread pool 0x%p was released while a thread was posting a callback to 0x%p(0x%p) to it. |
| 3098 | THREADPOOL_RELEASED_DURING_OPERATION = 0xC000070F, | 2119 | THREADPOOL_RELEASED_DURING_OPERATION = 0xC000070F, |
| 3099 | |||
| 3100 | /// A thread pool worker thread is impersonating a client, after a callback to 0x%p(0x%p). | 2120 | /// A thread pool worker thread is impersonating a client, after a callback to 0x%p(0x%p). |
| 3101 | /// This is unexpected, indicating that the callback is missing a call to revert the impersonation. | 2121 | /// This is unexpected, indicating that the callback is missing a call to revert the impersonation. |
| 3102 | CALLBACK_RETURNED_WHILE_IMPERSONATING = 0xC0000710, | 2122 | CALLBACK_RETURNED_WHILE_IMPERSONATING = 0xC0000710, |
| 3103 | |||
| 3104 | /// A thread pool worker thread is impersonating a client, after executing an APC. | 2123 | /// A thread pool worker thread is impersonating a client, after executing an APC. |
| 3105 | /// This is unexpected, indicating that the APC is missing a call to revert the impersonation. | 2124 | /// This is unexpected, indicating that the APC is missing a call to revert the impersonation. |
| 3106 | APC_RETURNED_WHILE_IMPERSONATING = 0xC0000711, | 2125 | APC_RETURNED_WHILE_IMPERSONATING = 0xC0000711, |
| 3107 | |||
| 3108 | /// Either the target process, or the target thread's containing process, is a protected process. | 2126 | /// Either the target process, or the target thread's containing process, is a protected process. |
| 3109 | PROCESS_IS_PROTECTED = 0xC0000712, | 2127 | PROCESS_IS_PROTECTED = 0xC0000712, |
| 3110 | |||
| 3111 | /// A thread is getting dispatched with MCA EXCEPTION because of MCA. | 2128 | /// A thread is getting dispatched with MCA EXCEPTION because of MCA. |
| 3112 | MCA_EXCEPTION = 0xC0000713, | 2129 | MCA_EXCEPTION = 0xC0000713, |
| 3113 | |||
| 3114 | /// The client certificate account mapping is not unique. | 2130 | /// The client certificate account mapping is not unique. |
| 3115 | CERTIFICATE_MAPPING_NOT_UNIQUE = 0xC0000714, | 2131 | CERTIFICATE_MAPPING_NOT_UNIQUE = 0xC0000714, |
| 3116 | |||
| 3117 | /// The symbolic link cannot be followed because its type is disabled. | 2132 | /// The symbolic link cannot be followed because its type is disabled. |
| 3118 | SYMLINK_CLASS_DISABLED = 0xC0000715, | 2133 | SYMLINK_CLASS_DISABLED = 0xC0000715, |
| 3119 | |||
| 3120 | /// Indicates that the specified string is not valid for IDN normalization. | 2134 | /// Indicates that the specified string is not valid for IDN normalization. |
| 3121 | INVALID_IDN_NORMALIZATION = 0xC0000716, | 2135 | INVALID_IDN_NORMALIZATION = 0xC0000716, |
| 3122 | |||
| 3123 | /// No mapping for the Unicode character exists in the target multi-byte code page. | 2136 | /// No mapping for the Unicode character exists in the target multi-byte code page. |
| 3124 | NO_UNICODE_TRANSLATION = 0xC0000717, | 2137 | NO_UNICODE_TRANSLATION = 0xC0000717, |
| 3125 | |||
| 3126 | /// The provided callback is already registered. | 2138 | /// The provided callback is already registered. |
| 3127 | ALREADY_REGISTERED = 0xC0000718, | 2139 | ALREADY_REGISTERED = 0xC0000718, |
| 3128 | |||
| 3129 | /// The provided context did not match the target. | 2140 | /// The provided context did not match the target. |
| 3130 | CONTEXT_MISMATCH = 0xC0000719, | 2141 | CONTEXT_MISMATCH = 0xC0000719, |
| 3131 | |||
| 3132 | /// The specified port already has a completion list. | 2142 | /// The specified port already has a completion list. |
| 3133 | PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A, | 2143 | PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A, |
| 3134 | |||
| 3135 | /// A threadpool worker thread entered a callback at thread base priority 0x%x and exited at priority 0x%x. | 2144 | /// A threadpool worker thread entered a callback at thread base priority 0x%x and exited at priority 0x%x. |
| 3136 | /// This is unexpected, indicating that the callback missed restoring the priority. | 2145 | /// This is unexpected, indicating that the callback missed restoring the priority. |
| 3137 | CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B, | 2146 | CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B, |
| 3138 | |||
| 3139 | /// An invalid thread, handle %p, is specified for this operation. | 2147 | /// An invalid thread, handle %p, is specified for this operation. |
| 3140 | /// Possibly, a threadpool worker thread was specified. | 2148 | /// Possibly, a threadpool worker thread was specified. |
| 3141 | INVALID_THREAD = 0xC000071C, | 2149 | INVALID_THREAD = 0xC000071C, |
| 3142 | |||
| 3143 | /// A threadpool worker thread entered a callback, which left transaction state. | 2150 | /// A threadpool worker thread entered a callback, which left transaction state. |
| 3144 | /// This is unexpected, indicating that the callback missed clearing the transaction. | 2151 | /// This is unexpected, indicating that the callback missed clearing the transaction. |
| 3145 | CALLBACK_RETURNED_TRANSACTION = 0xC000071D, | 2152 | CALLBACK_RETURNED_TRANSACTION = 0xC000071D, |
| 3146 | |||
| 3147 | /// A threadpool worker thread entered a callback, which left the loader lock held. | 2153 | /// A threadpool worker thread entered a callback, which left the loader lock held. |
| 3148 | /// This is unexpected, indicating that the callback missed releasing the lock. | 2154 | /// This is unexpected, indicating that the callback missed releasing the lock. |
| 3149 | CALLBACK_RETURNED_LDR_LOCK = 0xC000071E, | 2155 | CALLBACK_RETURNED_LDR_LOCK = 0xC000071E, |
| 3150 | |||
| 3151 | /// A threadpool worker thread entered a callback, which left with preferred languages set. | 2156 | /// A threadpool worker thread entered a callback, which left with preferred languages set. |
| 3152 | /// This is unexpected, indicating that the callback missed clearing them. | 2157 | /// This is unexpected, indicating that the callback missed clearing them. |
| 3153 | CALLBACK_RETURNED_LANG = 0xC000071F, | 2158 | CALLBACK_RETURNED_LANG = 0xC000071F, |
| 3154 | |||
| 3155 | /// A threadpool worker thread entered a callback, which left with background priorities set. | 2159 | /// A threadpool worker thread entered a callback, which left with background priorities set. |
| 3156 | /// This is unexpected, indicating that the callback missed restoring the original priorities. | 2160 | /// This is unexpected, indicating that the callback missed restoring the original priorities. |
| 3157 | CALLBACK_RETURNED_PRI_BACK = 0xC0000720, | 2161 | CALLBACK_RETURNED_PRI_BACK = 0xC0000720, |
| 3158 | |||
| 3159 | /// The attempted operation required self healing to be enabled. | 2162 | /// The attempted operation required self healing to be enabled. |
| 3160 | DISK_REPAIR_DISABLED = 0xC0000800, | 2163 | DISK_REPAIR_DISABLED = 0xC0000800, |
| 3161 | |||
| 3162 | /// The directory service cannot perform the requested operation because a domain rename operation is in progress. | 2164 | /// The directory service cannot perform the requested operation because a domain rename operation is in progress. |
| 3163 | DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801, | 2165 | DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801, |
| 3164 | |||
| 3165 | /// An operation failed because the storage quota was exceeded. | 2166 | /// An operation failed because the storage quota was exceeded. |
| 3166 | DISK_QUOTA_EXCEEDED = 0xC0000802, | 2167 | DISK_QUOTA_EXCEEDED = 0xC0000802, |
| 3167 | |||
| 3168 | /// An operation failed because the content was blocked. | 2168 | /// An operation failed because the content was blocked. |
| 3169 | CONTENT_BLOCKED = 0xC0000804, | 2169 | CONTENT_BLOCKED = 0xC0000804, |
| 3170 | |||
| 3171 | /// The operation could not be completed due to bad clusters on disk. | 2170 | /// The operation could not be completed due to bad clusters on disk. |
| 3172 | BAD_CLUSTERS = 0xC0000805, | 2171 | BAD_CLUSTERS = 0xC0000805, |
| 3173 | |||
| 3174 | /// The operation could not be completed because the volume is dirty. Please run the Chkdsk utility and try again. | 2172 | /// The operation could not be completed because the volume is dirty. Please run the Chkdsk utility and try again. |
| 3175 | VOLUME_DIRTY = 0xC0000806, | 2173 | VOLUME_DIRTY = 0xC0000806, |
| 3176 | |||
| 3177 | /// This file is checked out or locked for editing by another user. | 2174 | /// This file is checked out or locked for editing by another user. |
| 3178 | FILE_CHECKED_OUT = 0xC0000901, | 2175 | FILE_CHECKED_OUT = 0xC0000901, |
| 3179 | |||
| 3180 | /// The file must be checked out before saving changes. | 2176 | /// The file must be checked out before saving changes. |
| 3181 | CHECKOUT_REQUIRED = 0xC0000902, | 2177 | CHECKOUT_REQUIRED = 0xC0000902, |
| 3182 | |||
| 3183 | /// The file type being saved or retrieved has been blocked. | 2178 | /// The file type being saved or retrieved has been blocked. |
| 3184 | BAD_FILE_TYPE = 0xC0000903, | 2179 | BAD_FILE_TYPE = 0xC0000903, |
| 3185 | |||
| 3186 | /// The file size exceeds the limit allowed and cannot be saved. | 2180 | /// The file size exceeds the limit allowed and cannot be saved. |
| 3187 | FILE_TOO_LARGE = 0xC0000904, | 2181 | FILE_TOO_LARGE = 0xC0000904, |
| 3188 | |||
| 3189 | /// Access Denied. Before opening files in this location, you must first browse to the e.g. | 2182 | /// Access Denied. Before opening files in this location, you must first browse to the e.g. |
| 3190 | /// site and select the option to log on automatically. | 2183 | /// site and select the option to log on automatically. |
| 3191 | FORMS_AUTH_REQUIRED = 0xC0000905, | 2184 | FORMS_AUTH_REQUIRED = 0xC0000905, |
| 3192 | |||
| 3193 | /// The operation did not complete successfully because the file contains a virus. | 2185 | /// The operation did not complete successfully because the file contains a virus. |
| 3194 | VIRUS_INFECTED = 0xC0000906, | 2186 | VIRUS_INFECTED = 0xC0000906, |
| 3195 | |||
| 3196 | /// This file contains a virus and cannot be opened. | 2187 | /// This file contains a virus and cannot be opened. |
| 3197 | /// Due to the nature of this virus, the file has been removed from this location. | 2188 | /// Due to the nature of this virus, the file has been removed from this location. |
| 3198 | VIRUS_DELETED = 0xC0000907, | 2189 | VIRUS_DELETED = 0xC0000907, |
| 3199 | |||
| 3200 | /// The resources required for this device conflict with the MCFG table. | 2190 | /// The resources required for this device conflict with the MCFG table. |
| 3201 | BAD_MCFG_TABLE = 0xC0000908, | 2191 | BAD_MCFG_TABLE = 0xC0000908, |
| 3202 | |||
| 3203 | /// The operation did not complete successfully because it would cause an oplock to be broken. | 2192 | /// The operation did not complete successfully because it would cause an oplock to be broken. |
| 3204 | /// The caller has requested that existing oplocks not be broken. | 2193 | /// The caller has requested that existing oplocks not be broken. |
| 3205 | CANNOT_BREAK_OPLOCK = 0xC0000909, | 2194 | CANNOT_BREAK_OPLOCK = 0xC0000909, |
| 3206 | |||
| 3207 | /// WOW Assertion Error. | 2195 | /// WOW Assertion Error. |
| 3208 | WOW_ASSERTION = 0xC0009898, | 2196 | WOW_ASSERTION = 0xC0009898, |
| 3209 | |||
| 3210 | /// The cryptographic signature is invalid. | 2197 | /// The cryptographic signature is invalid. |
| 3211 | INVALID_SIGNATURE = 0xC000A000, | 2198 | INVALID_SIGNATURE = 0xC000A000, |
| 3212 | |||
| 3213 | /// The cryptographic provider does not support HMAC. | 2199 | /// The cryptographic provider does not support HMAC. |
| 3214 | HMAC_NOT_SUPPORTED = 0xC000A001, | 2200 | HMAC_NOT_SUPPORTED = 0xC000A001, |
| 3215 | |||
| 3216 | /// The IPsec queue overflowed. | 2201 | /// The IPsec queue overflowed. |
| 3217 | IPSEC_QUEUE_OVERFLOW = 0xC000A010, | 2202 | IPSEC_QUEUE_OVERFLOW = 0xC000A010, |
| 3218 | |||
| 3219 | /// The neighbor discovery queue overflowed. | 2203 | /// The neighbor discovery queue overflowed. |
| 3220 | ND_QUEUE_OVERFLOW = 0xC000A011, | 2204 | ND_QUEUE_OVERFLOW = 0xC000A011, |
| 3221 | |||
| 3222 | /// An Internet Control Message Protocol (ICMP) hop limit exceeded error was received. | 2205 | /// An Internet Control Message Protocol (ICMP) hop limit exceeded error was received. |
| 3223 | HOPLIMIT_EXCEEDED = 0xC000A012, | 2206 | HOPLIMIT_EXCEEDED = 0xC000A012, |
| 3224 | |||
| 3225 | /// The protocol is not installed on the local machine. | 2207 | /// The protocol is not installed on the local machine. |
| 3226 | PROTOCOL_NOT_SUPPORTED = 0xC000A013, | 2208 | PROTOCOL_NOT_SUPPORTED = 0xC000A013, |
| 3227 | |||
| 3228 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. | 2209 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. |
| 3229 | /// This error might be caused by network connectivity issues. Try to save this file elsewhere. | 2210 | /// This error might be caused by network connectivity issues. Try to save this file elsewhere. |
| 3230 | LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080, | 2211 | LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080, |
| 3231 | |||
| 3232 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. | 2212 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. |
| 3233 | /// This error was returned by the server on which the file exists. Try to save this file elsewhere. | 2213 | /// This error was returned by the server on which the file exists. Try to save this file elsewhere. |
| 3234 | LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081, | 2214 | LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081, |
| 3235 | |||
| 3236 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. | 2215 | /// {Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. |
| 3237 | /// This error might be caused if the device has been removed or the media is write-protected. | 2216 | /// This error might be caused if the device has been removed or the media is write-protected. |
| 3238 | LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082, | 2217 | LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082, |
| 3239 | |||
| 3240 | /// Windows was unable to parse the requested XML data. | 2218 | /// Windows was unable to parse the requested XML data. |
| 3241 | XML_PARSE_ERROR = 0xC000A083, | 2219 | XML_PARSE_ERROR = 0xC000A083, |
| 3242 | |||
| 3243 | /// An error was encountered while processing an XML digital signature. | 2220 | /// An error was encountered while processing an XML digital signature. |
| 3244 | XMLDSIG_ERROR = 0xC000A084, | 2221 | XMLDSIG_ERROR = 0xC000A084, |
| 3245 | |||
| 3246 | /// This indicates that the caller made the connection request in the wrong routing compartment. | 2222 | /// This indicates that the caller made the connection request in the wrong routing compartment. |
| 3247 | WRONG_COMPARTMENT = 0xC000A085, | 2223 | WRONG_COMPARTMENT = 0xC000A085, |
| 3248 | |||
| 3249 | /// This indicates that there was an AuthIP failure when attempting to connect to the remote host. | 2224 | /// This indicates that there was an AuthIP failure when attempting to connect to the remote host. |
| 3250 | AUTHIP_FAILURE = 0xC000A086, | 2225 | AUTHIP_FAILURE = 0xC000A086, |
| 3251 | |||
| 3252 | /// OID mapped groups cannot have members. | 2226 | /// OID mapped groups cannot have members. |
| 3253 | DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 0xC000A087, | 2227 | DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 0xC000A087, |
| 3254 | |||
| 3255 | /// The specified OID cannot be found. | 2228 | /// The specified OID cannot be found. |
| 3256 | DS_OID_NOT_FOUND = 0xC000A088, | 2229 | DS_OID_NOT_FOUND = 0xC000A088, |
| 3257 | |||
| 3258 | /// Hash generation for the specified version and hash type is not enabled on server. | 2230 | /// Hash generation for the specified version and hash type is not enabled on server. |
| 3259 | HASH_NOT_SUPPORTED = 0xC000A100, | 2231 | HASH_NOT_SUPPORTED = 0xC000A100, |
| 3260 | |||
| 3261 | /// The hash requests is not present or not up to date with the current file contents. | 2232 | /// The hash requests is not present or not up to date with the current file contents. |
| 3262 | HASH_NOT_PRESENT = 0xC000A101, | 2233 | HASH_NOT_PRESENT = 0xC000A101, |
| 3263 | |||
| 3264 | /// A file system filter on the server has not opted in for Offload Read support. | 2234 | /// A file system filter on the server has not opted in for Offload Read support. |
| 3265 | OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1, | 2235 | OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1, |
| 3266 | |||
| 3267 | /// A file system filter on the server has not opted in for Offload Write support. | 2236 | /// A file system filter on the server has not opted in for Offload Write support. |
| 3268 | OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2, | 2237 | OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2, |
| 3269 | |||
| 3270 | /// Offload read operations cannot be performed on: | 2238 | /// Offload read operations cannot be performed on: |
| 3271 | /// - Compressed files | 2239 | /// - Compressed files |
| 3272 | /// - Sparse files | 2240 | /// - Sparse files |
| 3273 | /// - Encrypted files | 2241 | /// - Encrypted files |
| 3274 | /// - File system metadata files | 2242 | /// - File system metadata files |
| 3275 | OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3, | 2243 | OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3, |
| 3276 | |||
| 3277 | /// Offload write operations cannot be performed on: | 2244 | /// Offload write operations cannot be performed on: |
| 3278 | /// - Compressed files | 2245 | /// - Compressed files |
| 3279 | /// - Sparse files | 2246 | /// - Sparse files |
| 3280 | /// - Encrypted files | 2247 | /// - Encrypted files |
| 3281 | /// - File system metadata files | 2248 | /// - File system metadata files |
| 3282 | OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4, | 2249 | OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4, |
| 3283 | |||
| 3284 | /// The debugger did not perform a state change. | 2250 | /// The debugger did not perform a state change. |
| 3285 | DBG_NO_STATE_CHANGE = 0xC0010001, | 2251 | DBG_NO_STATE_CHANGE = 0xC0010001, |
| 3286 | |||
| 3287 | /// The debugger found that the application is not idle. | 2252 | /// The debugger found that the application is not idle. |
| 3288 | DBG_APP_NOT_IDLE = 0xC0010002, | 2253 | DBG_APP_NOT_IDLE = 0xC0010002, |
| 3289 | |||
| 3290 | /// The string binding is invalid. | 2254 | /// The string binding is invalid. |
| 3291 | RPC_NT_INVALID_STRING_BINDING = 0xC0020001, | 2255 | RPC_NT_INVALID_STRING_BINDING = 0xC0020001, |
| 3292 | |||
| 3293 | /// The binding handle is not the correct type. | 2256 | /// The binding handle is not the correct type. |
| 3294 | RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002, | 2257 | RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002, |
| 3295 | |||
| 3296 | /// The binding handle is invalid. | 2258 | /// The binding handle is invalid. |
| 3297 | RPC_NT_INVALID_BINDING = 0xC0020003, | 2259 | RPC_NT_INVALID_BINDING = 0xC0020003, |
| 3298 | |||
| 3299 | /// The RPC protocol sequence is not supported. | 2260 | /// The RPC protocol sequence is not supported. |
| 3300 | RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004, | 2261 | RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004, |
| 3301 | |||
| 3302 | /// The RPC protocol sequence is invalid. | 2262 | /// The RPC protocol sequence is invalid. |
| 3303 | RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005, | 2263 | RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005, |
| 3304 | |||
| 3305 | /// The string UUID is invalid. | 2264 | /// The string UUID is invalid. |
| 3306 | RPC_NT_INVALID_STRING_UUID = 0xC0020006, | 2265 | RPC_NT_INVALID_STRING_UUID = 0xC0020006, |
| 3307 | |||
| 3308 | /// The endpoint format is invalid. | 2266 | /// The endpoint format is invalid. |
| 3309 | RPC_NT_INVALID_ENDPOINT_FORMAT = 0xC0020007, | 2267 | RPC_NT_INVALID_ENDPOINT_FORMAT = 0xC0020007, |
| 3310 | |||
| 3311 | /// The network address is invalid. | 2268 | /// The network address is invalid. |
| 3312 | RPC_NT_INVALID_NET_ADDR = 0xC0020008, | 2269 | RPC_NT_INVALID_NET_ADDR = 0xC0020008, |
| 3313 | |||
| 3314 | /// No endpoint was found. | 2270 | /// No endpoint was found. |
| 3315 | RPC_NT_NO_ENDPOINT_FOUND = 0xC0020009, | 2271 | RPC_NT_NO_ENDPOINT_FOUND = 0xC0020009, |
| 3316 | |||
| 3317 | /// The time-out value is invalid. | 2272 | /// The time-out value is invalid. |
| 3318 | RPC_NT_INVALID_TIMEOUT = 0xC002000A, | 2273 | RPC_NT_INVALID_TIMEOUT = 0xC002000A, |
| 3319 | |||
| 3320 | /// The object UUID was not found. | 2274 | /// The object UUID was not found. |
| 3321 | RPC_NT_OBJECT_NOT_FOUND = 0xC002000B, | 2275 | RPC_NT_OBJECT_NOT_FOUND = 0xC002000B, |
| 3322 | |||
| 3323 | /// The object UUID has already been registered. | 2276 | /// The object UUID has already been registered. |
| 3324 | RPC_NT_ALREADY_REGISTERED = 0xC002000C, | 2277 | RPC_NT_ALREADY_REGISTERED = 0xC002000C, |
| 3325 | |||
| 3326 | /// The type UUID has already been registered. | 2278 | /// The type UUID has already been registered. |
| 3327 | RPC_NT_TYPE_ALREADY_REGISTERED = 0xC002000D, | 2279 | RPC_NT_TYPE_ALREADY_REGISTERED = 0xC002000D, |
| 3328 | |||
| 3329 | /// The RPC server is already listening. | 2280 | /// The RPC server is already listening. |
| 3330 | RPC_NT_ALREADY_LISTENING = 0xC002000E, | 2281 | RPC_NT_ALREADY_LISTENING = 0xC002000E, |
| 3331 | |||
| 3332 | /// No protocol sequences have been registered. | 2282 | /// No protocol sequences have been registered. |
| 3333 | RPC_NT_NO_PROTSEQS_REGISTERED = 0xC002000F, | 2283 | RPC_NT_NO_PROTSEQS_REGISTERED = 0xC002000F, |
| 3334 | |||
| 3335 | /// The RPC server is not listening. | 2284 | /// The RPC server is not listening. |
| 3336 | RPC_NT_NOT_LISTENING = 0xC0020010, | 2285 | RPC_NT_NOT_LISTENING = 0xC0020010, |
| 3337 | |||
| 3338 | /// The manager type is unknown. | 2286 | /// The manager type is unknown. |
| 3339 | RPC_NT_UNKNOWN_MGR_TYPE = 0xC0020011, | 2287 | RPC_NT_UNKNOWN_MGR_TYPE = 0xC0020011, |
| 3340 | |||
| 3341 | /// The interface is unknown. | 2288 | /// The interface is unknown. |
| 3342 | RPC_NT_UNKNOWN_IF = 0xC0020012, | 2289 | RPC_NT_UNKNOWN_IF = 0xC0020012, |
| 3343 | |||
| 3344 | /// There are no bindings. | 2290 | /// There are no bindings. |
| 3345 | RPC_NT_NO_BINDINGS = 0xC0020013, | 2291 | RPC_NT_NO_BINDINGS = 0xC0020013, |
| 3346 | |||
| 3347 | /// There are no protocol sequences. | 2292 | /// There are no protocol sequences. |
| 3348 | RPC_NT_NO_PROTSEQS = 0xC0020014, | 2293 | RPC_NT_NO_PROTSEQS = 0xC0020014, |
| 3349 | |||
| 3350 | /// The endpoint cannot be created. | 2294 | /// The endpoint cannot be created. |
| 3351 | RPC_NT_CANT_CREATE_ENDPOINT = 0xC0020015, | 2295 | RPC_NT_CANT_CREATE_ENDPOINT = 0xC0020015, |
| 3352 | |||
| 3353 | /// Insufficient resources are available to complete this operation. | 2296 | /// Insufficient resources are available to complete this operation. |
| 3354 | RPC_NT_OUT_OF_RESOURCES = 0xC0020016, | 2297 | RPC_NT_OUT_OF_RESOURCES = 0xC0020016, |
| 3355 | |||
| 3356 | /// The RPC server is unavailable. | 2298 | /// The RPC server is unavailable. |
| 3357 | RPC_NT_SERVER_UNAVAILABLE = 0xC0020017, | 2299 | RPC_NT_SERVER_UNAVAILABLE = 0xC0020017, |
| 3358 | |||
| 3359 | /// The RPC server is too busy to complete this operation. | 2300 | /// The RPC server is too busy to complete this operation. |
| 3360 | RPC_NT_SERVER_TOO_BUSY = 0xC0020018, | 2301 | RPC_NT_SERVER_TOO_BUSY = 0xC0020018, |
| 3361 | |||
| 3362 | /// The network options are invalid. | 2302 | /// The network options are invalid. |
| 3363 | RPC_NT_INVALID_NETWORK_OPTIONS = 0xC0020019, | 2303 | RPC_NT_INVALID_NETWORK_OPTIONS = 0xC0020019, |
| 3364 | |||
| 3365 | /// No RPCs are active on this thread. | 2304 | /// No RPCs are active on this thread. |
| 3366 | RPC_NT_NO_CALL_ACTIVE = 0xC002001A, | 2305 | RPC_NT_NO_CALL_ACTIVE = 0xC002001A, |
| 3367 | |||
| 3368 | /// The RPC failed. | 2306 | /// The RPC failed. |
| 3369 | RPC_NT_CALL_FAILED = 0xC002001B, | 2307 | RPC_NT_CALL_FAILED = 0xC002001B, |
| 3370 | |||
| 3371 | /// The RPC failed and did not execute. | 2308 | /// The RPC failed and did not execute. |
| 3372 | RPC_NT_CALL_FAILED_DNE = 0xC002001C, | 2309 | RPC_NT_CALL_FAILED_DNE = 0xC002001C, |
| 3373 | |||
| 3374 | /// An RPC protocol error occurred. | 2310 | /// An RPC protocol error occurred. |
| 3375 | RPC_NT_PROTOCOL_ERROR = 0xC002001D, | 2311 | RPC_NT_PROTOCOL_ERROR = 0xC002001D, |
| 3376 | |||
| 3377 | /// The RPC server does not support the transfer syntax. | 2312 | /// The RPC server does not support the transfer syntax. |
| 3378 | RPC_NT_UNSUPPORTED_TRANS_SYN = 0xC002001F, | 2313 | RPC_NT_UNSUPPORTED_TRANS_SYN = 0xC002001F, |
| 3379 | |||
| 3380 | /// The type UUID is not supported. | 2314 | /// The type UUID is not supported. |
| 3381 | RPC_NT_UNSUPPORTED_TYPE = 0xC0020021, | 2315 | RPC_NT_UNSUPPORTED_TYPE = 0xC0020021, |
| 3382 | |||
| 3383 | /// The tag is invalid. | 2316 | /// The tag is invalid. |
| 3384 | RPC_NT_INVALID_TAG = 0xC0020022, | 2317 | RPC_NT_INVALID_TAG = 0xC0020022, |
| 3385 | |||
| 3386 | /// The array bounds are invalid. | 2318 | /// The array bounds are invalid. |
| 3387 | RPC_NT_INVALID_BOUND = 0xC0020023, | 2319 | RPC_NT_INVALID_BOUND = 0xC0020023, |
| 3388 | |||
| 3389 | /// The binding does not contain an entry name. | 2320 | /// The binding does not contain an entry name. |
| 3390 | RPC_NT_NO_ENTRY_NAME = 0xC0020024, | 2321 | RPC_NT_NO_ENTRY_NAME = 0xC0020024, |
| 3391 | |||
| 3392 | /// The name syntax is invalid. | 2322 | /// The name syntax is invalid. |
| 3393 | RPC_NT_INVALID_NAME_SYNTAX = 0xC0020025, | 2323 | RPC_NT_INVALID_NAME_SYNTAX = 0xC0020025, |
| 3394 | |||
| 3395 | /// The name syntax is not supported. | 2324 | /// The name syntax is not supported. |
| 3396 | RPC_NT_UNSUPPORTED_NAME_SYNTAX = 0xC0020026, | 2325 | RPC_NT_UNSUPPORTED_NAME_SYNTAX = 0xC0020026, |
| 3397 | |||
| 3398 | /// No network address is available to construct a UUID. | 2326 | /// No network address is available to construct a UUID. |
| 3399 | RPC_NT_UUID_NO_ADDRESS = 0xC0020028, | 2327 | RPC_NT_UUID_NO_ADDRESS = 0xC0020028, |
| 3400 | |||
| 3401 | /// The endpoint is a duplicate. | 2328 | /// The endpoint is a duplicate. |
| 3402 | RPC_NT_DUPLICATE_ENDPOINT = 0xC0020029, | 2329 | RPC_NT_DUPLICATE_ENDPOINT = 0xC0020029, |
| 3403 | |||
| 3404 | /// The authentication type is unknown. | 2330 | /// The authentication type is unknown. |
| 3405 | RPC_NT_UNKNOWN_AUTHN_TYPE = 0xC002002A, | 2331 | RPC_NT_UNKNOWN_AUTHN_TYPE = 0xC002002A, |
| 3406 | |||
| 3407 | /// The maximum number of calls is too small. | 2332 | /// The maximum number of calls is too small. |
| 3408 | RPC_NT_MAX_CALLS_TOO_SMALL = 0xC002002B, | 2333 | RPC_NT_MAX_CALLS_TOO_SMALL = 0xC002002B, |
| 3409 | |||
| 3410 | /// The string is too long. | 2334 | /// The string is too long. |
| 3411 | RPC_NT_STRING_TOO_LONG = 0xC002002C, | 2335 | RPC_NT_STRING_TOO_LONG = 0xC002002C, |
| 3412 | |||
| 3413 | /// The RPC protocol sequence was not found. | 2336 | /// The RPC protocol sequence was not found. |
| 3414 | RPC_NT_PROTSEQ_NOT_FOUND = 0xC002002D, | 2337 | RPC_NT_PROTSEQ_NOT_FOUND = 0xC002002D, |
| 3415 | |||
| 3416 | /// The procedure number is out of range. | 2338 | /// The procedure number is out of range. |
| 3417 | RPC_NT_PROCNUM_OUT_OF_RANGE = 0xC002002E, | 2339 | RPC_NT_PROCNUM_OUT_OF_RANGE = 0xC002002E, |
| 3418 | |||
| 3419 | /// The binding does not contain any authentication information. | 2340 | /// The binding does not contain any authentication information. |
| 3420 | RPC_NT_BINDING_HAS_NO_AUTH = 0xC002002F, | 2341 | RPC_NT_BINDING_HAS_NO_AUTH = 0xC002002F, |
| 3421 | |||
| 3422 | /// The authentication service is unknown. | 2342 | /// The authentication service is unknown. |
| 3423 | RPC_NT_UNKNOWN_AUTHN_SERVICE = 0xC0020030, | 2343 | RPC_NT_UNKNOWN_AUTHN_SERVICE = 0xC0020030, |
| 3424 | |||
| 3425 | /// The authentication level is unknown. | 2344 | /// The authentication level is unknown. |
| 3426 | RPC_NT_UNKNOWN_AUTHN_LEVEL = 0xC0020031, | 2345 | RPC_NT_UNKNOWN_AUTHN_LEVEL = 0xC0020031, |
| 3427 | |||
| 3428 | /// The security context is invalid. | 2346 | /// The security context is invalid. |
| 3429 | RPC_NT_INVALID_AUTH_IDENTITY = 0xC0020032, | 2347 | RPC_NT_INVALID_AUTH_IDENTITY = 0xC0020032, |
| 3430 | |||
| 3431 | /// The authorization service is unknown. | 2348 | /// The authorization service is unknown. |
| 3432 | RPC_NT_UNKNOWN_AUTHZ_SERVICE = 0xC0020033, | 2349 | RPC_NT_UNKNOWN_AUTHZ_SERVICE = 0xC0020033, |
| 3433 | |||
| 3434 | /// The entry is invalid. | 2350 | /// The entry is invalid. |
| 3435 | EPT_NT_INVALID_ENTRY = 0xC0020034, | 2351 | EPT_NT_INVALID_ENTRY = 0xC0020034, |
| 3436 | |||
| 3437 | /// The operation cannot be performed. | 2352 | /// The operation cannot be performed. |
| 3438 | EPT_NT_CANT_PERFORM_OP = 0xC0020035, | 2353 | EPT_NT_CANT_PERFORM_OP = 0xC0020035, |
| 3439 | |||
| 3440 | /// No more endpoints are available from the endpoint mapper. | 2354 | /// No more endpoints are available from the endpoint mapper. |
| 3441 | EPT_NT_NOT_REGISTERED = 0xC0020036, | 2355 | EPT_NT_NOT_REGISTERED = 0xC0020036, |
| 3442 | |||
| 3443 | /// No interfaces have been exported. | 2356 | /// No interfaces have been exported. |
| 3444 | RPC_NT_NOTHING_TO_EXPORT = 0xC0020037, | 2357 | RPC_NT_NOTHING_TO_EXPORT = 0xC0020037, |
| 3445 | |||
| 3446 | /// The entry name is incomplete. | 2358 | /// The entry name is incomplete. |
| 3447 | RPC_NT_INCOMPLETE_NAME = 0xC0020038, | 2359 | RPC_NT_INCOMPLETE_NAME = 0xC0020038, |
| 3448 | |||
| 3449 | /// The version option is invalid. | 2360 | /// The version option is invalid. |
| 3450 | RPC_NT_INVALID_VERS_OPTION = 0xC0020039, | 2361 | RPC_NT_INVALID_VERS_OPTION = 0xC0020039, |
| 3451 | |||
| 3452 | /// There are no more members. | 2362 | /// There are no more members. |
| 3453 | RPC_NT_NO_MORE_MEMBERS = 0xC002003A, | 2363 | RPC_NT_NO_MORE_MEMBERS = 0xC002003A, |
| 3454 | |||
| 3455 | /// There is nothing to unexport. | 2364 | /// There is nothing to unexport. |
| 3456 | RPC_NT_NOT_ALL_OBJS_UNEXPORTED = 0xC002003B, | 2365 | RPC_NT_NOT_ALL_OBJS_UNEXPORTED = 0xC002003B, |
| 3457 | |||
| 3458 | /// The interface was not found. | 2366 | /// The interface was not found. |
| 3459 | RPC_NT_INTERFACE_NOT_FOUND = 0xC002003C, | 2367 | RPC_NT_INTERFACE_NOT_FOUND = 0xC002003C, |
| 3460 | |||
| 3461 | /// The entry already exists. | 2368 | /// The entry already exists. |
| 3462 | RPC_NT_ENTRY_ALREADY_EXISTS = 0xC002003D, | 2369 | RPC_NT_ENTRY_ALREADY_EXISTS = 0xC002003D, |
| 3463 | |||
| 3464 | /// The entry was not found. | 2370 | /// The entry was not found. |
| 3465 | RPC_NT_ENTRY_NOT_FOUND = 0xC002003E, | 2371 | RPC_NT_ENTRY_NOT_FOUND = 0xC002003E, |
| 3466 | |||
| 3467 | /// The name service is unavailable. | 2372 | /// The name service is unavailable. |
| 3468 | RPC_NT_NAME_SERVICE_UNAVAILABLE = 0xC002003F, | 2373 | RPC_NT_NAME_SERVICE_UNAVAILABLE = 0xC002003F, |
| 3469 | |||
| 3470 | /// The network address family is invalid. | 2374 | /// The network address family is invalid. |
| 3471 | RPC_NT_INVALID_NAF_ID = 0xC0020040, | 2375 | RPC_NT_INVALID_NAF_ID = 0xC0020040, |
| 3472 | |||
| 3473 | /// The requested operation is not supported. | 2376 | /// The requested operation is not supported. |
| 3474 | RPC_NT_CANNOT_SUPPORT = 0xC0020041, | 2377 | RPC_NT_CANNOT_SUPPORT = 0xC0020041, |
| 3475 | |||
| 3476 | /// No security context is available to allow impersonation. | 2378 | /// No security context is available to allow impersonation. |
| 3477 | RPC_NT_NO_CONTEXT_AVAILABLE = 0xC0020042, | 2379 | RPC_NT_NO_CONTEXT_AVAILABLE = 0xC0020042, |
| 3478 | |||
| 3479 | /// An internal error occurred in the RPC. | 2380 | /// An internal error occurred in the RPC. |
| 3480 | RPC_NT_INTERNAL_ERROR = 0xC0020043, | 2381 | RPC_NT_INTERNAL_ERROR = 0xC0020043, |
| 3481 | |||
| 3482 | /// The RPC server attempted to divide an integer by zero. | 2382 | /// The RPC server attempted to divide an integer by zero. |
| 3483 | RPC_NT_ZERO_DIVIDE = 0xC0020044, | 2383 | RPC_NT_ZERO_DIVIDE = 0xC0020044, |
| 3484 | |||
| 3485 | /// An addressing error occurred in the RPC server. | 2384 | /// An addressing error occurred in the RPC server. |
| 3486 | RPC_NT_ADDRESS_ERROR = 0xC0020045, | 2385 | RPC_NT_ADDRESS_ERROR = 0xC0020045, |
| 3487 | |||
| 3488 | /// A floating point operation at the RPC server caused a divide by zero. | 2386 | /// A floating point operation at the RPC server caused a divide by zero. |
| 3489 | RPC_NT_FP_DIV_ZERO = 0xC0020046, | 2387 | RPC_NT_FP_DIV_ZERO = 0xC0020046, |
| 3490 | |||
| 3491 | /// A floating point underflow occurred at the RPC server. | 2388 | /// A floating point underflow occurred at the RPC server. |
| 3492 | RPC_NT_FP_UNDERFLOW = 0xC0020047, | 2389 | RPC_NT_FP_UNDERFLOW = 0xC0020047, |
| 3493 | |||
| 3494 | /// A floating point overflow occurred at the RPC server. | 2390 | /// A floating point overflow occurred at the RPC server. |
| 3495 | RPC_NT_FP_OVERFLOW = 0xC0020048, | 2391 | RPC_NT_FP_OVERFLOW = 0xC0020048, |
| 3496 | |||
| 3497 | /// An RPC is already in progress for this thread. | 2392 | /// An RPC is already in progress for this thread. |
| 3498 | RPC_NT_CALL_IN_PROGRESS = 0xC0020049, | 2393 | RPC_NT_CALL_IN_PROGRESS = 0xC0020049, |
| 3499 | |||
| 3500 | /// There are no more bindings. | 2394 | /// There are no more bindings. |
| 3501 | RPC_NT_NO_MORE_BINDINGS = 0xC002004A, | 2395 | RPC_NT_NO_MORE_BINDINGS = 0xC002004A, |
| 3502 | |||
| 3503 | /// The group member was not found. | 2396 | /// The group member was not found. |
| 3504 | RPC_NT_GROUP_MEMBER_NOT_FOUND = 0xC002004B, | 2397 | RPC_NT_GROUP_MEMBER_NOT_FOUND = 0xC002004B, |
| 3505 | |||
| 3506 | /// The endpoint mapper database entry could not be created. | 2398 | /// The endpoint mapper database entry could not be created. |
| 3507 | EPT_NT_CANT_CREATE = 0xC002004C, | 2399 | EPT_NT_CANT_CREATE = 0xC002004C, |
| 3508 | |||
| 3509 | /// The object UUID is the nil UUID. | 2400 | /// The object UUID is the nil UUID. |
| 3510 | RPC_NT_INVALID_OBJECT = 0xC002004D, | 2401 | RPC_NT_INVALID_OBJECT = 0xC002004D, |
| 3511 | |||
| 3512 | /// No interfaces have been registered. | 2402 | /// No interfaces have been registered. |
| 3513 | RPC_NT_NO_INTERFACES = 0xC002004F, | 2403 | RPC_NT_NO_INTERFACES = 0xC002004F, |
| 3514 | |||
| 3515 | /// The RPC was canceled. | 2404 | /// The RPC was canceled. |
| 3516 | RPC_NT_CALL_CANCELLED = 0xC0020050, | 2405 | RPC_NT_CALL_CANCELLED = 0xC0020050, |
| 3517 | |||
| 3518 | /// The binding handle does not contain all the required information. | 2406 | /// The binding handle does not contain all the required information. |
| 3519 | RPC_NT_BINDING_INCOMPLETE = 0xC0020051, | 2407 | RPC_NT_BINDING_INCOMPLETE = 0xC0020051, |
| 3520 | |||
| 3521 | /// A communications failure occurred during an RPC. | 2408 | /// A communications failure occurred during an RPC. |
| 3522 | RPC_NT_COMM_FAILURE = 0xC0020052, | 2409 | RPC_NT_COMM_FAILURE = 0xC0020052, |
| 3523 | |||
| 3524 | /// The requested authentication level is not supported. | 2410 | /// The requested authentication level is not supported. |
| 3525 | RPC_NT_UNSUPPORTED_AUTHN_LEVEL = 0xC0020053, | 2411 | RPC_NT_UNSUPPORTED_AUTHN_LEVEL = 0xC0020053, |
| 3526 | |||
| 3527 | /// No principal name was registered. | 2412 | /// No principal name was registered. |
| 3528 | RPC_NT_NO_PRINC_NAME = 0xC0020054, | 2413 | RPC_NT_NO_PRINC_NAME = 0xC0020054, |
| 3529 | |||
| 3530 | /// The error specified is not a valid Windows RPC error code. | 2414 | /// The error specified is not a valid Windows RPC error code. |
| 3531 | RPC_NT_NOT_RPC_ERROR = 0xC0020055, | 2415 | RPC_NT_NOT_RPC_ERROR = 0xC0020055, |
| 3532 | |||
| 3533 | /// A security package-specific error occurred. | 2416 | /// A security package-specific error occurred. |
| 3534 | RPC_NT_SEC_PKG_ERROR = 0xC0020057, | 2417 | RPC_NT_SEC_PKG_ERROR = 0xC0020057, |
| 3535 | |||
| 3536 | /// The thread was not canceled. | 2418 | /// The thread was not canceled. |
| 3537 | RPC_NT_NOT_CANCELLED = 0xC0020058, | 2419 | RPC_NT_NOT_CANCELLED = 0xC0020058, |
| 3538 | |||
| 3539 | /// Invalid asynchronous RPC handle. | 2420 | /// Invalid asynchronous RPC handle. |
| 3540 | RPC_NT_INVALID_ASYNC_HANDLE = 0xC0020062, | 2421 | RPC_NT_INVALID_ASYNC_HANDLE = 0xC0020062, |
| 3541 | |||
| 3542 | /// Invalid asynchronous RPC call handle for this operation. | 2422 | /// Invalid asynchronous RPC call handle for this operation. |
| 3543 | RPC_NT_INVALID_ASYNC_CALL = 0xC0020063, | 2423 | RPC_NT_INVALID_ASYNC_CALL = 0xC0020063, |
| 3544 | |||
| 3545 | /// Access to the HTTP proxy is denied. | 2424 | /// Access to the HTTP proxy is denied. |
| 3546 | RPC_NT_PROXY_ACCESS_DENIED = 0xC0020064, | 2425 | RPC_NT_PROXY_ACCESS_DENIED = 0xC0020064, |
| 3547 | |||
| 3548 | /// The list of RPC servers available for auto-handle binding has been exhausted. | 2426 | /// The list of RPC servers available for auto-handle binding has been exhausted. |
| 3549 | RPC_NT_NO_MORE_ENTRIES = 0xC0030001, | 2427 | RPC_NT_NO_MORE_ENTRIES = 0xC0030001, |
| 3550 | |||
| 3551 | /// The file designated by DCERPCCHARTRANS cannot be opened. | 2428 | /// The file designated by DCERPCCHARTRANS cannot be opened. |
| 3552 | RPC_NT_SS_CHAR_TRANS_OPEN_FAIL = 0xC0030002, | 2429 | RPC_NT_SS_CHAR_TRANS_OPEN_FAIL = 0xC0030002, |
| 3553 | |||
| 3554 | /// The file containing the character translation table has fewer than 512 bytes. | 2430 | /// The file containing the character translation table has fewer than 512 bytes. |
| 3555 | RPC_NT_SS_CHAR_TRANS_SHORT_FILE = 0xC0030003, | 2431 | RPC_NT_SS_CHAR_TRANS_SHORT_FILE = 0xC0030003, |
| 3556 | |||
| 3557 | /// A null context handle is passed as an [in] parameter. | 2432 | /// A null context handle is passed as an [in] parameter. |
| 3558 | RPC_NT_SS_IN_NULL_CONTEXT = 0xC0030004, | 2433 | RPC_NT_SS_IN_NULL_CONTEXT = 0xC0030004, |
| 3559 | |||
| 3560 | /// The context handle does not match any known context handles. | 2434 | /// The context handle does not match any known context handles. |
| 3561 | RPC_NT_SS_CONTEXT_MISMATCH = 0xC0030005, | 2435 | RPC_NT_SS_CONTEXT_MISMATCH = 0xC0030005, |
| 3562 | |||
| 3563 | /// The context handle changed during a call. | 2436 | /// The context handle changed during a call. |
| 3564 | RPC_NT_SS_CONTEXT_DAMAGED = 0xC0030006, | 2437 | RPC_NT_SS_CONTEXT_DAMAGED = 0xC0030006, |
| 3565 | |||
| 3566 | /// The binding handles passed to an RPC do not match. | 2438 | /// The binding handles passed to an RPC do not match. |
| 3567 | RPC_NT_SS_HANDLES_MISMATCH = 0xC0030007, | 2439 | RPC_NT_SS_HANDLES_MISMATCH = 0xC0030007, |
| 3568 | |||
| 3569 | /// The stub is unable to get the call handle. | 2440 | /// The stub is unable to get the call handle. |
| 3570 | RPC_NT_SS_CANNOT_GET_CALL_HANDLE = 0xC0030008, | 2441 | RPC_NT_SS_CANNOT_GET_CALL_HANDLE = 0xC0030008, |
| 3571 | |||
| 3572 | /// A null reference pointer was passed to the stub. | 2442 | /// A null reference pointer was passed to the stub. |
| 3573 | RPC_NT_NULL_REF_POINTER = 0xC0030009, | 2443 | RPC_NT_NULL_REF_POINTER = 0xC0030009, |
| 3574 | |||
| 3575 | /// The enumeration value is out of range. | 2444 | /// The enumeration value is out of range. |
| 3576 | RPC_NT_ENUM_VALUE_OUT_OF_RANGE = 0xC003000A, | 2445 | RPC_NT_ENUM_VALUE_OUT_OF_RANGE = 0xC003000A, |
| 3577 | |||
| 3578 | /// The byte count is too small. | 2446 | /// The byte count is too small. |
| 3579 | RPC_NT_BYTE_COUNT_TOO_SMALL = 0xC003000B, | 2447 | RPC_NT_BYTE_COUNT_TOO_SMALL = 0xC003000B, |
| 3580 | |||
| 3581 | /// The stub received bad data. | 2448 | /// The stub received bad data. |
| 3582 | RPC_NT_BAD_STUB_DATA = 0xC003000C, | 2449 | RPC_NT_BAD_STUB_DATA = 0xC003000C, |
| 3583 | |||
| 3584 | /// Invalid operation on the encoding/decoding handle. | 2450 | /// Invalid operation on the encoding/decoding handle. |
| 3585 | RPC_NT_INVALID_ES_ACTION = 0xC0030059, | 2451 | RPC_NT_INVALID_ES_ACTION = 0xC0030059, |
| 3586 | |||
| 3587 | /// Incompatible version of the serializing package. | 2452 | /// Incompatible version of the serializing package. |
| 3588 | RPC_NT_WRONG_ES_VERSION = 0xC003005A, | 2453 | RPC_NT_WRONG_ES_VERSION = 0xC003005A, |
| 3589 | |||
| 3590 | /// Incompatible version of the RPC stub. | 2454 | /// Incompatible version of the RPC stub. |
| 3591 | RPC_NT_WRONG_STUB_VERSION = 0xC003005B, | 2455 | RPC_NT_WRONG_STUB_VERSION = 0xC003005B, |
| 3592 | |||
| 3593 | /// The RPC pipe object is invalid or corrupt. | 2456 | /// The RPC pipe object is invalid or corrupt. |
| 3594 | RPC_NT_INVALID_PIPE_OBJECT = 0xC003005C, | 2457 | RPC_NT_INVALID_PIPE_OBJECT = 0xC003005C, |
| 3595 | |||
| 3596 | /// An invalid operation was attempted on an RPC pipe object. | 2458 | /// An invalid operation was attempted on an RPC pipe object. |
| 3597 | RPC_NT_INVALID_PIPE_OPERATION = 0xC003005D, | 2459 | RPC_NT_INVALID_PIPE_OPERATION = 0xC003005D, |
| 3598 | |||
| 3599 | /// Unsupported RPC pipe version. | 2460 | /// Unsupported RPC pipe version. |
| 3600 | RPC_NT_WRONG_PIPE_VERSION = 0xC003005E, | 2461 | RPC_NT_WRONG_PIPE_VERSION = 0xC003005E, |
| 3601 | |||
| 3602 | /// The RPC pipe object has already been closed. | 2462 | /// The RPC pipe object has already been closed. |
| 3603 | RPC_NT_PIPE_CLOSED = 0xC003005F, | 2463 | RPC_NT_PIPE_CLOSED = 0xC003005F, |
| 3604 | |||
| 3605 | /// The RPC call completed before all pipes were processed. | 2464 | /// The RPC call completed before all pipes were processed. |
| 3606 | RPC_NT_PIPE_DISCIPLINE_ERROR = 0xC0030060, | 2465 | RPC_NT_PIPE_DISCIPLINE_ERROR = 0xC0030060, |
| 3607 | |||
| 3608 | /// No more data is available from the RPC pipe. | 2466 | /// No more data is available from the RPC pipe. |
| 3609 | RPC_NT_PIPE_EMPTY = 0xC0030061, | 2467 | RPC_NT_PIPE_EMPTY = 0xC0030061, |
| 3610 | |||
| 3611 | /// A device is missing in the system BIOS MPS table. This device will not be used. | 2468 | /// A device is missing in the system BIOS MPS table. This device will not be used. |
| 3612 | /// Contact your system vendor for a system BIOS update. | 2469 | /// Contact your system vendor for a system BIOS update. |
| 3613 | PNP_BAD_MPS_TABLE = 0xC0040035, | 2470 | PNP_BAD_MPS_TABLE = 0xC0040035, |
| 3614 | |||
| 3615 | /// A translator failed to translate resources. | 2471 | /// A translator failed to translate resources. |
| 3616 | PNP_TRANSLATION_FAILED = 0xC0040036, | 2472 | PNP_TRANSLATION_FAILED = 0xC0040036, |
| 3617 | |||
| 3618 | /// An IRQ translator failed to translate resources. | 2473 | /// An IRQ translator failed to translate resources. |
| 3619 | PNP_IRQ_TRANSLATION_FAILED = 0xC0040037, | 2474 | PNP_IRQ_TRANSLATION_FAILED = 0xC0040037, |
| 3620 | |||
| 3621 | /// Driver %2 returned an invalid ID for a child device (%3). | 2475 | /// Driver %2 returned an invalid ID for a child device (%3). |
| 3622 | PNP_INVALID_ID = 0xC0040038, | 2476 | PNP_INVALID_ID = 0xC0040038, |
| 3623 | |||
| 3624 | /// Reissue the given operation as a cached I/O operation | 2477 | /// Reissue the given operation as a cached I/O operation |
| 3625 | IO_REISSUE_AS_CACHED = 0xC0040039, | 2478 | IO_REISSUE_AS_CACHED = 0xC0040039, |
| 3626 | |||
| 3627 | /// Session name %1 is invalid. | 2479 | /// Session name %1 is invalid. |
| 3628 | CTX_WINSTATION_NAME_INVALID = 0xC00A0001, | 2480 | CTX_WINSTATION_NAME_INVALID = 0xC00A0001, |
| 3629 | |||
| 3630 | /// The protocol driver %1 is invalid. | 2481 | /// The protocol driver %1 is invalid. |
| 3631 | CTX_INVALID_PD = 0xC00A0002, | 2482 | CTX_INVALID_PD = 0xC00A0002, |
| 3632 | |||
| 3633 | /// The protocol driver %1 was not found in the system path. | 2483 | /// The protocol driver %1 was not found in the system path. |
| 3634 | CTX_PD_NOT_FOUND = 0xC00A0003, | 2484 | CTX_PD_NOT_FOUND = 0xC00A0003, |
| 3635 | |||
| 3636 | /// A close operation is pending on the terminal connection. | 2485 | /// A close operation is pending on the terminal connection. |
| 3637 | CTX_CLOSE_PENDING = 0xC00A0006, | 2486 | CTX_CLOSE_PENDING = 0xC00A0006, |
| 3638 | |||
| 3639 | /// No free output buffers are available. | 2487 | /// No free output buffers are available. |
| 3640 | CTX_NO_OUTBUF = 0xC00A0007, | 2488 | CTX_NO_OUTBUF = 0xC00A0007, |
| 3641 | |||
| 3642 | /// The MODEM.INF file was not found. | 2489 | /// The MODEM.INF file was not found. |
| 3643 | CTX_MODEM_INF_NOT_FOUND = 0xC00A0008, | 2490 | CTX_MODEM_INF_NOT_FOUND = 0xC00A0008, |
| 3644 | |||
| 3645 | /// The modem (%1) was not found in the MODEM.INF file. | 2491 | /// The modem (%1) was not found in the MODEM.INF file. |
| 3646 | CTX_INVALID_MODEMNAME = 0xC00A0009, | 2492 | CTX_INVALID_MODEMNAME = 0xC00A0009, |
| 3647 | |||
| 3648 | /// The modem did not accept the command sent to it. | 2493 | /// The modem did not accept the command sent to it. |
| 3649 | /// Verify that the configured modem name matches the attached modem. | 2494 | /// Verify that the configured modem name matches the attached modem. |
| 3650 | CTX_RESPONSE_ERROR = 0xC00A000A, | 2495 | CTX_RESPONSE_ERROR = 0xC00A000A, |
| 3651 | |||
| 3652 | /// The modem did not respond to the command sent to it. | 2496 | /// The modem did not respond to the command sent to it. |
| 3653 | /// Verify that the modem cable is properly attached and the modem is turned on. | 2497 | /// Verify that the modem cable is properly attached and the modem is turned on. |
| 3654 | CTX_MODEM_RESPONSE_TIMEOUT = 0xC00A000B, | 2498 | CTX_MODEM_RESPONSE_TIMEOUT = 0xC00A000B, |
| 3655 | |||
| 3656 | /// Carrier detection has failed or the carrier has been dropped due to disconnection. | 2499 | /// Carrier detection has failed or the carrier has been dropped due to disconnection. |
| 3657 | CTX_MODEM_RESPONSE_NO_CARRIER = 0xC00A000C, | 2500 | CTX_MODEM_RESPONSE_NO_CARRIER = 0xC00A000C, |
| 3658 | |||
| 3659 | /// A dial tone was not detected within the required time. | 2501 | /// A dial tone was not detected within the required time. |
| 3660 | /// Verify that the phone cable is properly attached and functional. | 2502 | /// Verify that the phone cable is properly attached and functional. |
| 3661 | CTX_MODEM_RESPONSE_NO_DIALTONE = 0xC00A000D, | 2503 | CTX_MODEM_RESPONSE_NO_DIALTONE = 0xC00A000D, |
| 3662 | |||
| 3663 | /// A busy signal was detected at a remote site on callback. | 2504 | /// A busy signal was detected at a remote site on callback. |
| 3664 | CTX_MODEM_RESPONSE_BUSY = 0xC00A000E, | 2505 | CTX_MODEM_RESPONSE_BUSY = 0xC00A000E, |
| 3665 | |||
| 3666 | /// A voice was detected at a remote site on callback. | 2506 | /// A voice was detected at a remote site on callback. |
| 3667 | CTX_MODEM_RESPONSE_VOICE = 0xC00A000F, | 2507 | CTX_MODEM_RESPONSE_VOICE = 0xC00A000F, |
| 3668 | |||
| 3669 | /// Transport driver error. | 2508 | /// Transport driver error. |
| 3670 | CTX_TD_ERROR = 0xC00A0010, | 2509 | CTX_TD_ERROR = 0xC00A0010, |
| 3671 | |||
| 3672 | /// The client you are using is not licensed to use this system. Your logon request is denied. | 2510 | /// The client you are using is not licensed to use this system. Your logon request is denied. |
| 3673 | CTX_LICENSE_CLIENT_INVALID = 0xC00A0012, | 2511 | CTX_LICENSE_CLIENT_INVALID = 0xC00A0012, |
| 3674 | |||
| 3675 | /// The system has reached its licensed logon limit. Try again later. | 2512 | /// The system has reached its licensed logon limit. Try again later. |
| 3676 | CTX_LICENSE_NOT_AVAILABLE = 0xC00A0013, | 2513 | CTX_LICENSE_NOT_AVAILABLE = 0xC00A0013, |
| 3677 | |||
| 3678 | /// The system license has expired. Your logon request is denied. | 2514 | /// The system license has expired. Your logon request is denied. |
| 3679 | CTX_LICENSE_EXPIRED = 0xC00A0014, | 2515 | CTX_LICENSE_EXPIRED = 0xC00A0014, |
| 3680 | |||
| 3681 | /// The specified session cannot be found. | 2516 | /// The specified session cannot be found. |
| 3682 | CTX_WINSTATION_NOT_FOUND = 0xC00A0015, | 2517 | CTX_WINSTATION_NOT_FOUND = 0xC00A0015, |
| 3683 | |||
| 3684 | /// The specified session name is already in use. | 2518 | /// The specified session name is already in use. |
| 3685 | CTX_WINSTATION_NAME_COLLISION = 0xC00A0016, | 2519 | CTX_WINSTATION_NAME_COLLISION = 0xC00A0016, |
| 3686 | |||
| 3687 | /// The requested operation cannot be completed because the terminal connection is currently processing a connect, disconnect, reset, or delete operation. | 2520 | /// The requested operation cannot be completed because the terminal connection is currently processing a connect, disconnect, reset, or delete operation. |
| 3688 | CTX_WINSTATION_BUSY = 0xC00A0017, | 2521 | CTX_WINSTATION_BUSY = 0xC00A0017, |
| 3689 | |||
| 3690 | /// An attempt has been made to connect to a session whose video mode is not supported by the current client. | 2522 | /// An attempt has been made to connect to a session whose video mode is not supported by the current client. |
| 3691 | CTX_BAD_VIDEO_MODE = 0xC00A0018, | 2523 | CTX_BAD_VIDEO_MODE = 0xC00A0018, |
| 3692 | |||
| 3693 | /// The application attempted to enable DOS graphics mode. DOS graphics mode is not supported. | 2524 | /// The application attempted to enable DOS graphics mode. DOS graphics mode is not supported. |
| 3694 | CTX_GRAPHICS_INVALID = 0xC00A0022, | 2525 | CTX_GRAPHICS_INVALID = 0xC00A0022, |
| 3695 | |||
| 3696 | /// The requested operation can be performed only on the system console. | 2526 | /// The requested operation can be performed only on the system console. |
| 3697 | /// This is most often the result of a driver or system DLL requiring direct console access. | 2527 | /// This is most often the result of a driver or system DLL requiring direct console access. |
| 3698 | CTX_NOT_CONSOLE = 0xC00A0024, | 2528 | CTX_NOT_CONSOLE = 0xC00A0024, |
| 3699 | |||
| 3700 | /// The client failed to respond to the server connect message. | 2529 | /// The client failed to respond to the server connect message. |
| 3701 | CTX_CLIENT_QUERY_TIMEOUT = 0xC00A0026, | 2530 | CTX_CLIENT_QUERY_TIMEOUT = 0xC00A0026, |
| 3702 | |||
| 3703 | /// Disconnecting the console session is not supported. | 2531 | /// Disconnecting the console session is not supported. |
| 3704 | CTX_CONSOLE_DISCONNECT = 0xC00A0027, | 2532 | CTX_CONSOLE_DISCONNECT = 0xC00A0027, |
| 3705 | |||
| 3706 | /// Reconnecting a disconnected session to the console is not supported. | 2533 | /// Reconnecting a disconnected session to the console is not supported. |
| 3707 | CTX_CONSOLE_CONNECT = 0xC00A0028, | 2534 | CTX_CONSOLE_CONNECT = 0xC00A0028, |
| 3708 | |||
| 3709 | /// The request to control another session remotely was denied. | 2535 | /// The request to control another session remotely was denied. |
| 3710 | CTX_SHADOW_DENIED = 0xC00A002A, | 2536 | CTX_SHADOW_DENIED = 0xC00A002A, |
| 3711 | |||
| 3712 | /// A process has requested access to a session, but has not been granted those access rights. | 2537 | /// A process has requested access to a session, but has not been granted those access rights. |
| 3713 | CTX_WINSTATION_ACCESS_DENIED = 0xC00A002B, | 2538 | CTX_WINSTATION_ACCESS_DENIED = 0xC00A002B, |
| 3714 | |||
| 3715 | /// The terminal connection driver %1 is invalid. | 2539 | /// The terminal connection driver %1 is invalid. |
| 3716 | CTX_INVALID_WD = 0xC00A002E, | 2540 | CTX_INVALID_WD = 0xC00A002E, |
| 3717 | |||
| 3718 | /// The terminal connection driver %1 was not found in the system path. | 2541 | /// The terminal connection driver %1 was not found in the system path. |
| 3719 | CTX_WD_NOT_FOUND = 0xC00A002F, | 2542 | CTX_WD_NOT_FOUND = 0xC00A002F, |
| 3720 | |||
| 3721 | /// The requested session cannot be controlled remotely. | 2543 | /// The requested session cannot be controlled remotely. |
| 3722 | /// You cannot control your own session, a session that is trying to control your session, a session that has no user logged on, or other sessions from the console. | 2544 | /// You cannot control your own session, a session that is trying to control your session, a session that has no user logged on, or other sessions from the console. |
| 3723 | CTX_SHADOW_INVALID = 0xC00A0030, | 2545 | CTX_SHADOW_INVALID = 0xC00A0030, |
| 3724 | |||
| 3725 | /// The requested session is not configured to allow remote control. | 2546 | /// The requested session is not configured to allow remote control. |
| 3726 | CTX_SHADOW_DISABLED = 0xC00A0031, | 2547 | CTX_SHADOW_DISABLED = 0xC00A0031, |
| 3727 | |||
| 3728 | /// The RDP protocol component %2 detected an error in the protocol stream and has disconnected the client. | 2548 | /// The RDP protocol component %2 detected an error in the protocol stream and has disconnected the client. |
| 3729 | RDP_PROTOCOL_ERROR = 0xC00A0032, | 2549 | RDP_PROTOCOL_ERROR = 0xC00A0032, |
| 3730 | |||
| 3731 | /// Your request to connect to this terminal server has been rejected. | 2550 | /// Your request to connect to this terminal server has been rejected. |
| 3732 | /// Your terminal server client license number has not been entered for this copy of the terminal client. | 2551 | /// Your terminal server client license number has not been entered for this copy of the terminal client. |
| 3733 | /// Contact your system administrator for help in entering a valid, unique license number for this terminal server client. Click OK to continue. | 2552 | /// Contact your system administrator for help in entering a valid, unique license number for this terminal server client. Click OK to continue. |
| 3734 | CTX_CLIENT_LICENSE_NOT_SET = 0xC00A0033, | 2553 | CTX_CLIENT_LICENSE_NOT_SET = 0xC00A0033, |
| 3735 | |||
| 3736 | /// Your request to connect to this terminal server has been rejected. | 2554 | /// Your request to connect to this terminal server has been rejected. |
| 3737 | /// Your terminal server client license number is currently being used by another user. | 2555 | /// Your terminal server client license number is currently being used by another user. |
| 3738 | /// Contact your system administrator to obtain a new copy of the terminal server client with a valid, unique license number. Click OK to continue. | 2556 | /// Contact your system administrator to obtain a new copy of the terminal server client with a valid, unique license number. Click OK to continue. |
| 3739 | CTX_CLIENT_LICENSE_IN_USE = 0xC00A0034, | 2557 | CTX_CLIENT_LICENSE_IN_USE = 0xC00A0034, |
| 3740 | |||
| 3741 | /// The remote control of the console was terminated because the display mode was changed. | 2558 | /// The remote control of the console was terminated because the display mode was changed. |
| 3742 | /// Changing the display mode in a remote control session is not supported. | 2559 | /// Changing the display mode in a remote control session is not supported. |
| 3743 | CTX_SHADOW_ENDED_BY_MODE_CHANGE = 0xC00A0035, | 2560 | CTX_SHADOW_ENDED_BY_MODE_CHANGE = 0xC00A0035, |
| 3744 | |||
| 3745 | /// Remote control could not be terminated because the specified session is not currently being remotely controlled. | 2561 | /// Remote control could not be terminated because the specified session is not currently being remotely controlled. |
| 3746 | CTX_SHADOW_NOT_RUNNING = 0xC00A0036, | 2562 | CTX_SHADOW_NOT_RUNNING = 0xC00A0036, |
| 3747 | |||
| 3748 | /// Your interactive logon privilege has been disabled. Contact your system administrator. | 2563 | /// Your interactive logon privilege has been disabled. Contact your system administrator. |
| 3749 | CTX_LOGON_DISABLED = 0xC00A0037, | 2564 | CTX_LOGON_DISABLED = 0xC00A0037, |
| 3750 | |||
| 3751 | /// The terminal server security layer detected an error in the protocol stream and has disconnected the client. | 2565 | /// The terminal server security layer detected an error in the protocol stream and has disconnected the client. |
| 3752 | CTX_SECURITY_LAYER_ERROR = 0xC00A0038, | 2566 | CTX_SECURITY_LAYER_ERROR = 0xC00A0038, |
| 3753 | |||
| 3754 | /// The target session is incompatible with the current session. | 2567 | /// The target session is incompatible with the current session. |
| 3755 | TS_INCOMPATIBLE_SESSIONS = 0xC00A0039, | 2568 | TS_INCOMPATIBLE_SESSIONS = 0xC00A0039, |
| 3756 | |||
| 3757 | /// The resource loader failed to find an MUI file. | 2569 | /// The resource loader failed to find an MUI file. |
| 3758 | MUI_FILE_NOT_FOUND = 0xC00B0001, | 2570 | MUI_FILE_NOT_FOUND = 0xC00B0001, |
| 3759 | |||
| 3760 | /// The resource loader failed to load an MUI file because the file failed to pass validation. | 2571 | /// The resource loader failed to load an MUI file because the file failed to pass validation. |
| 3761 | MUI_INVALID_FILE = 0xC00B0002, | 2572 | MUI_INVALID_FILE = 0xC00B0002, |
| 3762 | |||
| 3763 | /// The RC manifest is corrupted with garbage data, is an unsupported version, or is missing a required item. | 2573 | /// The RC manifest is corrupted with garbage data, is an unsupported version, or is missing a required item. |
| 3764 | MUI_INVALID_RC_CONFIG = 0xC00B0003, | 2574 | MUI_INVALID_RC_CONFIG = 0xC00B0003, |
| 3765 | |||
| 3766 | /// The RC manifest has an invalid culture name. | 2575 | /// The RC manifest has an invalid culture name. |
| 3767 | MUI_INVALID_LOCALE_NAME = 0xC00B0004, | 2576 | MUI_INVALID_LOCALE_NAME = 0xC00B0004, |
| 3768 | |||
| 3769 | /// The RC manifest has and invalid ultimate fallback name. | 2577 | /// The RC manifest has and invalid ultimate fallback name. |
| 3770 | MUI_INVALID_ULTIMATEFALLBACK_NAME = 0xC00B0005, | 2578 | MUI_INVALID_ULTIMATEFALLBACK_NAME = 0xC00B0005, |
| 3771 | |||
| 3772 | /// The resource loader cache does not have a loaded MUI entry. | 2579 | /// The resource loader cache does not have a loaded MUI entry. |
| 3773 | MUI_FILE_NOT_LOADED = 0xC00B0006, | 2580 | MUI_FILE_NOT_LOADED = 0xC00B0006, |
| 3774 | |||
| 3775 | /// The user stopped resource enumeration. | 2581 | /// The user stopped resource enumeration. |
| 3776 | RESOURCE_ENUM_USER_STOP = 0xC00B0007, | 2582 | RESOURCE_ENUM_USER_STOP = 0xC00B0007, |
| 3777 | |||
| 3778 | /// The cluster node is not valid. | 2583 | /// The cluster node is not valid. |
| 3779 | CLUSTER_INVALID_NODE = 0xC0130001, | 2584 | CLUSTER_INVALID_NODE = 0xC0130001, |
| 3780 | |||
| 3781 | /// The cluster node already exists. | 2585 | /// The cluster node already exists. |
| 3782 | CLUSTER_NODE_EXISTS = 0xC0130002, | 2586 | CLUSTER_NODE_EXISTS = 0xC0130002, |
| 3783 | |||
| 3784 | /// A node is in the process of joining the cluster. | 2587 | /// A node is in the process of joining the cluster. |
| 3785 | CLUSTER_JOIN_IN_PROGRESS = 0xC0130003, | 2588 | CLUSTER_JOIN_IN_PROGRESS = 0xC0130003, |
| 3786 | |||
| 3787 | /// The cluster node was not found. | 2589 | /// The cluster node was not found. |
| 3788 | CLUSTER_NODE_NOT_FOUND = 0xC0130004, | 2590 | CLUSTER_NODE_NOT_FOUND = 0xC0130004, |
| 3789 | |||
| 3790 | /// The cluster local node information was not found. | 2591 | /// The cluster local node information was not found. |
| 3791 | CLUSTER_LOCAL_NODE_NOT_FOUND = 0xC0130005, | 2592 | CLUSTER_LOCAL_NODE_NOT_FOUND = 0xC0130005, |
| 3792 | |||
| 3793 | /// The cluster network already exists. | 2593 | /// The cluster network already exists. |
| 3794 | CLUSTER_NETWORK_EXISTS = 0xC0130006, | 2594 | CLUSTER_NETWORK_EXISTS = 0xC0130006, |
| 3795 | |||
| 3796 | /// The cluster network was not found. | 2595 | /// The cluster network was not found. |
| 3797 | CLUSTER_NETWORK_NOT_FOUND = 0xC0130007, | 2596 | CLUSTER_NETWORK_NOT_FOUND = 0xC0130007, |
| 3798 | |||
| 3799 | /// The cluster network interface already exists. | 2597 | /// The cluster network interface already exists. |
| 3800 | CLUSTER_NETINTERFACE_EXISTS = 0xC0130008, | 2598 | CLUSTER_NETINTERFACE_EXISTS = 0xC0130008, |
| 3801 | |||
| 3802 | /// The cluster network interface was not found. | 2599 | /// The cluster network interface was not found. |
| 3803 | CLUSTER_NETINTERFACE_NOT_FOUND = 0xC0130009, | 2600 | CLUSTER_NETINTERFACE_NOT_FOUND = 0xC0130009, |
| 3804 | |||
| 3805 | /// The cluster request is not valid for this object. | 2601 | /// The cluster request is not valid for this object. |
| 3806 | CLUSTER_INVALID_REQUEST = 0xC013000A, | 2602 | CLUSTER_INVALID_REQUEST = 0xC013000A, |
| 3807 | |||
| 3808 | /// The cluster network provider is not valid. | 2603 | /// The cluster network provider is not valid. |
| 3809 | CLUSTER_INVALID_NETWORK_PROVIDER = 0xC013000B, | 2604 | CLUSTER_INVALID_NETWORK_PROVIDER = 0xC013000B, |
| 3810 | |||
| 3811 | /// The cluster node is down. | 2605 | /// The cluster node is down. |
| 3812 | CLUSTER_NODE_DOWN = 0xC013000C, | 2606 | CLUSTER_NODE_DOWN = 0xC013000C, |
| 3813 | |||
| 3814 | /// The cluster node is not reachable. | 2607 | /// The cluster node is not reachable. |
| 3815 | CLUSTER_NODE_UNREACHABLE = 0xC013000D, | 2608 | CLUSTER_NODE_UNREACHABLE = 0xC013000D, |
| 3816 | |||
| 3817 | /// The cluster node is not a member of the cluster. | 2609 | /// The cluster node is not a member of the cluster. |
| 3818 | CLUSTER_NODE_NOT_MEMBER = 0xC013000E, | 2610 | CLUSTER_NODE_NOT_MEMBER = 0xC013000E, |
| 3819 | |||
| 3820 | /// A cluster join operation is not in progress. | 2611 | /// A cluster join operation is not in progress. |
| 3821 | CLUSTER_JOIN_NOT_IN_PROGRESS = 0xC013000F, | 2612 | CLUSTER_JOIN_NOT_IN_PROGRESS = 0xC013000F, |
| 3822 | |||
| 3823 | /// The cluster network is not valid. | 2613 | /// The cluster network is not valid. |
| 3824 | CLUSTER_INVALID_NETWORK = 0xC0130010, | 2614 | CLUSTER_INVALID_NETWORK = 0xC0130010, |
| 3825 | |||
| 3826 | /// No network adapters are available. | 2615 | /// No network adapters are available. |
| 3827 | CLUSTER_NO_NET_ADAPTERS = 0xC0130011, | 2616 | CLUSTER_NO_NET_ADAPTERS = 0xC0130011, |
| 3828 | |||
| 3829 | /// The cluster node is up. | 2617 | /// The cluster node is up. |
| 3830 | CLUSTER_NODE_UP = 0xC0130012, | 2618 | CLUSTER_NODE_UP = 0xC0130012, |
| 3831 | |||
| 3832 | /// The cluster node is paused. | 2619 | /// The cluster node is paused. |
| 3833 | CLUSTER_NODE_PAUSED = 0xC0130013, | 2620 | CLUSTER_NODE_PAUSED = 0xC0130013, |
| 3834 | |||
| 3835 | /// The cluster node is not paused. | 2621 | /// The cluster node is not paused. |
| 3836 | CLUSTER_NODE_NOT_PAUSED = 0xC0130014, | 2622 | CLUSTER_NODE_NOT_PAUSED = 0xC0130014, |
| 3837 | |||
| 3838 | /// No cluster security context is available. | 2623 | /// No cluster security context is available. |
| 3839 | CLUSTER_NO_SECURITY_CONTEXT = 0xC0130015, | 2624 | CLUSTER_NO_SECURITY_CONTEXT = 0xC0130015, |
| 3840 | |||
| 3841 | /// The cluster network is not configured for internal cluster communication. | 2625 | /// The cluster network is not configured for internal cluster communication. |
| 3842 | CLUSTER_NETWORK_NOT_INTERNAL = 0xC0130016, | 2626 | CLUSTER_NETWORK_NOT_INTERNAL = 0xC0130016, |
| 3843 | |||
| 3844 | /// The cluster node has been poisoned. | 2627 | /// The cluster node has been poisoned. |
| 3845 | CLUSTER_POISONED = 0xC0130017, | 2628 | CLUSTER_POISONED = 0xC0130017, |
| 3846 | |||
| 3847 | /// An attempt was made to run an invalid AML opcode. | 2629 | /// An attempt was made to run an invalid AML opcode. |
| 3848 | ACPI_INVALID_OPCODE = 0xC0140001, | 2630 | ACPI_INVALID_OPCODE = 0xC0140001, |
| 3849 | |||
| 3850 | /// The AML interpreter stack has overflowed. | 2631 | /// The AML interpreter stack has overflowed. |
| 3851 | ACPI_STACK_OVERFLOW = 0xC0140002, | 2632 | ACPI_STACK_OVERFLOW = 0xC0140002, |
| 3852 | |||
| 3853 | /// An inconsistent state has occurred. | 2633 | /// An inconsistent state has occurred. |
| 3854 | ACPI_ASSERT_FAILED = 0xC0140003, | 2634 | ACPI_ASSERT_FAILED = 0xC0140003, |
| 3855 | |||
| 3856 | /// An attempt was made to access an array outside its bounds. | 2635 | /// An attempt was made to access an array outside its bounds. |
| 3857 | ACPI_INVALID_INDEX = 0xC0140004, | 2636 | ACPI_INVALID_INDEX = 0xC0140004, |
| 3858 | |||
| 3859 | /// A required argument was not specified. | 2637 | /// A required argument was not specified. |
| 3860 | ACPI_INVALID_ARGUMENT = 0xC0140005, | 2638 | ACPI_INVALID_ARGUMENT = 0xC0140005, |
| 3861 | |||
| 3862 | /// A fatal error has occurred. | 2639 | /// A fatal error has occurred. |
| 3863 | ACPI_FATAL = 0xC0140006, | 2640 | ACPI_FATAL = 0xC0140006, |
| 3864 | |||
| 3865 | /// An invalid SuperName was specified. | 2641 | /// An invalid SuperName was specified. |
| 3866 | ACPI_INVALID_SUPERNAME = 0xC0140007, | 2642 | ACPI_INVALID_SUPERNAME = 0xC0140007, |
| 3867 | |||
| 3868 | /// An argument with an incorrect type was specified. | 2643 | /// An argument with an incorrect type was specified. |
| 3869 | ACPI_INVALID_ARGTYPE = 0xC0140008, | 2644 | ACPI_INVALID_ARGTYPE = 0xC0140008, |
| 3870 | |||
| 3871 | /// An object with an incorrect type was specified. | 2645 | /// An object with an incorrect type was specified. |
| 3872 | ACPI_INVALID_OBJTYPE = 0xC0140009, | 2646 | ACPI_INVALID_OBJTYPE = 0xC0140009, |
| 3873 | |||
| 3874 | /// A target with an incorrect type was specified. | 2647 | /// A target with an incorrect type was specified. |
| 3875 | ACPI_INVALID_TARGETTYPE = 0xC014000A, | 2648 | ACPI_INVALID_TARGETTYPE = 0xC014000A, |
| 3876 | |||
| 3877 | /// An incorrect number of arguments was specified. | 2649 | /// An incorrect number of arguments was specified. |
| 3878 | ACPI_INCORRECT_ARGUMENT_COUNT = 0xC014000B, | 2650 | ACPI_INCORRECT_ARGUMENT_COUNT = 0xC014000B, |
| 3879 | |||
| 3880 | /// An address failed to translate. | 2651 | /// An address failed to translate. |
| 3881 | ACPI_ADDRESS_NOT_MAPPED = 0xC014000C, | 2652 | ACPI_ADDRESS_NOT_MAPPED = 0xC014000C, |
| 3882 | |||
| 3883 | /// An incorrect event type was specified. | 2653 | /// An incorrect event type was specified. |
| 3884 | ACPI_INVALID_EVENTTYPE = 0xC014000D, | 2654 | ACPI_INVALID_EVENTTYPE = 0xC014000D, |
| 3885 | |||
| 3886 | /// A handler for the target already exists. | 2655 | /// A handler for the target already exists. |
| 3887 | ACPI_HANDLER_COLLISION = 0xC014000E, | 2656 | ACPI_HANDLER_COLLISION = 0xC014000E, |
| 3888 | |||
| 3889 | /// Invalid data for the target was specified. | 2657 | /// Invalid data for the target was specified. |
| 3890 | ACPI_INVALID_DATA = 0xC014000F, | 2658 | ACPI_INVALID_DATA = 0xC014000F, |
| 3891 | |||
| 3892 | /// An invalid region for the target was specified. | 2659 | /// An invalid region for the target was specified. |
| 3893 | ACPI_INVALID_REGION = 0xC0140010, | 2660 | ACPI_INVALID_REGION = 0xC0140010, |
| 3894 | |||
| 3895 | /// An attempt was made to access a field outside the defined range. | 2661 | /// An attempt was made to access a field outside the defined range. |
| 3896 | ACPI_INVALID_ACCESS_SIZE = 0xC0140011, | 2662 | ACPI_INVALID_ACCESS_SIZE = 0xC0140011, |
| 3897 | |||
| 3898 | /// The global system lock could not be acquired. | 2663 | /// The global system lock could not be acquired. |
| 3899 | ACPI_ACQUIRE_GLOBAL_LOCK = 0xC0140012, | 2664 | ACPI_ACQUIRE_GLOBAL_LOCK = 0xC0140012, |
| 3900 | |||
| 3901 | /// An attempt was made to reinitialize the ACPI subsystem. | 2665 | /// An attempt was made to reinitialize the ACPI subsystem. |
| 3902 | ACPI_ALREADY_INITIALIZED = 0xC0140013, | 2666 | ACPI_ALREADY_INITIALIZED = 0xC0140013, |
| 3903 | |||
| 3904 | /// The ACPI subsystem has not been initialized. | 2667 | /// The ACPI subsystem has not been initialized. |
| 3905 | ACPI_NOT_INITIALIZED = 0xC0140014, | 2668 | ACPI_NOT_INITIALIZED = 0xC0140014, |
| 3906 | |||
| 3907 | /// An incorrect mutex was specified. | 2669 | /// An incorrect mutex was specified. |
| 3908 | ACPI_INVALID_MUTEX_LEVEL = 0xC0140015, | 2670 | ACPI_INVALID_MUTEX_LEVEL = 0xC0140015, |
| 3909 | |||
| 3910 | /// The mutex is not currently owned. | 2671 | /// The mutex is not currently owned. |
| 3911 | ACPI_MUTEX_NOT_OWNED = 0xC0140016, | 2672 | ACPI_MUTEX_NOT_OWNED = 0xC0140016, |
| 3912 | |||
| 3913 | /// An attempt was made to access the mutex by a process that was not the owner. | 2673 | /// An attempt was made to access the mutex by a process that was not the owner. |
| 3914 | ACPI_MUTEX_NOT_OWNER = 0xC0140017, | 2674 | ACPI_MUTEX_NOT_OWNER = 0xC0140017, |
| 3915 | |||
| 3916 | /// An error occurred during an access to region space. | 2675 | /// An error occurred during an access to region space. |
| 3917 | ACPI_RS_ACCESS = 0xC0140018, | 2676 | ACPI_RS_ACCESS = 0xC0140018, |
| 3918 | |||
| 3919 | /// An attempt was made to use an incorrect table. | 2677 | /// An attempt was made to use an incorrect table. |
| 3920 | ACPI_INVALID_TABLE = 0xC0140019, | 2678 | ACPI_INVALID_TABLE = 0xC0140019, |
| 3921 | |||
| 3922 | /// The registration of an ACPI event failed. | 2679 | /// The registration of an ACPI event failed. |
| 3923 | ACPI_REG_HANDLER_FAILED = 0xC0140020, | 2680 | ACPI_REG_HANDLER_FAILED = 0xC0140020, |
| 3924 | |||
| 3925 | /// An ACPI power object failed to transition state. | 2681 | /// An ACPI power object failed to transition state. |
| 3926 | ACPI_POWER_REQUEST_FAILED = 0xC0140021, | 2682 | ACPI_POWER_REQUEST_FAILED = 0xC0140021, |
| 3927 | |||
| 3928 | /// The requested section is not present in the activation context. | 2683 | /// The requested section is not present in the activation context. |
| 3929 | SXS_SECTION_NOT_FOUND = 0xC0150001, | 2684 | SXS_SECTION_NOT_FOUND = 0xC0150001, |
| 3930 | |||
| 3931 | /// Windows was unble to process the application binding information. | 2685 | /// Windows was unble to process the application binding information. |
| 3932 | /// Refer to the system event log for further information. | 2686 | /// Refer to the system event log for further information. |
| 3933 | SXS_CANT_GEN_ACTCTX = 0xC0150002, | 2687 | SXS_CANT_GEN_ACTCTX = 0xC0150002, |
| 3934 | |||
| 3935 | /// The application binding data format is invalid. | 2688 | /// The application binding data format is invalid. |
| 3936 | SXS_INVALID_ACTCTXDATA_FORMAT = 0xC0150003, | 2689 | SXS_INVALID_ACTCTXDATA_FORMAT = 0xC0150003, |
| 3937 | |||
| 3938 | /// The referenced assembly is not installed on the system. | 2690 | /// The referenced assembly is not installed on the system. |
| 3939 | SXS_ASSEMBLY_NOT_FOUND = 0xC0150004, | 2691 | SXS_ASSEMBLY_NOT_FOUND = 0xC0150004, |
| 3940 | |||
| 3941 | /// The manifest file does not begin with the required tag and format information. | 2692 | /// The manifest file does not begin with the required tag and format information. |
| 3942 | SXS_MANIFEST_FORMAT_ERROR = 0xC0150005, | 2693 | SXS_MANIFEST_FORMAT_ERROR = 0xC0150005, |
| 3943 | |||
| 3944 | /// The manifest file contains one or more syntax errors. | 2694 | /// The manifest file contains one or more syntax errors. |
| 3945 | SXS_MANIFEST_PARSE_ERROR = 0xC0150006, | 2695 | SXS_MANIFEST_PARSE_ERROR = 0xC0150006, |
| 3946 | |||
| 3947 | /// The application attempted to activate a disabled activation context. | 2696 | /// The application attempted to activate a disabled activation context. |
| 3948 | SXS_ACTIVATION_CONTEXT_DISABLED = 0xC0150007, | 2697 | SXS_ACTIVATION_CONTEXT_DISABLED = 0xC0150007, |
| 3949 | |||
| 3950 | /// The requested lookup key was not found in any active activation context. | 2698 | /// The requested lookup key was not found in any active activation context. |
| 3951 | SXS_KEY_NOT_FOUND = 0xC0150008, | 2699 | SXS_KEY_NOT_FOUND = 0xC0150008, |
| 3952 | |||
| 3953 | /// A component version required by the application conflicts with another component version that is already active. | 2700 | /// A component version required by the application conflicts with another component version that is already active. |
| 3954 | SXS_VERSION_CONFLICT = 0xC0150009, | 2701 | SXS_VERSION_CONFLICT = 0xC0150009, |
| 3955 | |||
| 3956 | /// The type requested activation context section does not match the query API used. | 2702 | /// The type requested activation context section does not match the query API used. |
| 3957 | SXS_WRONG_SECTION_TYPE = 0xC015000A, | 2703 | SXS_WRONG_SECTION_TYPE = 0xC015000A, |
| 3958 | |||
| 3959 | /// Lack of system resources has required isolated activation to be disabled for the current thread of execution. | 2704 | /// Lack of system resources has required isolated activation to be disabled for the current thread of execution. |
| 3960 | SXS_THREAD_QUERIES_DISABLED = 0xC015000B, | 2705 | SXS_THREAD_QUERIES_DISABLED = 0xC015000B, |
| 3961 | |||
| 3962 | /// The referenced assembly could not be found. | 2706 | /// The referenced assembly could not be found. |
| 3963 | SXS_ASSEMBLY_MISSING = 0xC015000C, | 2707 | SXS_ASSEMBLY_MISSING = 0xC015000C, |
| 3964 | |||
| 3965 | /// An attempt to set the process default activation context failed because the process default activation context was already set. | 2708 | /// An attempt to set the process default activation context failed because the process default activation context was already set. |
| 3966 | SXS_PROCESS_DEFAULT_ALREADY_SET = 0xC015000E, | 2709 | SXS_PROCESS_DEFAULT_ALREADY_SET = 0xC015000E, |
| 3967 | |||
| 3968 | /// The activation context being deactivated is not the most recently activated one. | 2710 | /// The activation context being deactivated is not the most recently activated one. |
| 3969 | SXS_EARLY_DEACTIVATION = 0xC015000F, | 2711 | SXS_EARLY_DEACTIVATION = 0xC015000F, |
| 3970 | |||
| 3971 | /// The activation context being deactivated is not active for the current thread of execution. | 2712 | /// The activation context being deactivated is not active for the current thread of execution. |
| 3972 | SXS_INVALID_DEACTIVATION = 0xC0150010, | 2713 | SXS_INVALID_DEACTIVATION = 0xC0150010, |
| 3973 | |||
| 3974 | /// The activation context being deactivated has already been deactivated. | 2714 | /// The activation context being deactivated has already been deactivated. |
| 3975 | SXS_MULTIPLE_DEACTIVATION = 0xC0150011, | 2715 | SXS_MULTIPLE_DEACTIVATION = 0xC0150011, |
| 3976 | |||
| 3977 | /// The activation context of the system default assembly could not be generated. | 2716 | /// The activation context of the system default assembly could not be generated. |
| 3978 | SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 0xC0150012, | 2717 | SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 0xC0150012, |
| 3979 | |||
| 3980 | /// A component used by the isolation facility has requested that the process be terminated. | 2718 | /// A component used by the isolation facility has requested that the process be terminated. |
| 3981 | SXS_PROCESS_TERMINATION_REQUESTED = 0xC0150013, | 2719 | SXS_PROCESS_TERMINATION_REQUESTED = 0xC0150013, |
| 3982 | |||
| 3983 | /// The activation context activation stack for the running thread of execution is corrupt. | 2720 | /// The activation context activation stack for the running thread of execution is corrupt. |
| 3984 | SXS_CORRUPT_ACTIVATION_STACK = 0xC0150014, | 2721 | SXS_CORRUPT_ACTIVATION_STACK = 0xC0150014, |
| 3985 | |||
| 3986 | /// The application isolation metadata for this process or thread has become corrupt. | 2722 | /// The application isolation metadata for this process or thread has become corrupt. |
| 3987 | SXS_CORRUPTION = 0xC0150015, | 2723 | SXS_CORRUPTION = 0xC0150015, |
| 3988 | |||
| 3989 | /// The value of an attribute in an identity is not within the legal range. | 2724 | /// The value of an attribute in an identity is not within the legal range. |
| 3990 | SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 0xC0150016, | 2725 | SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 0xC0150016, |
| 3991 | |||
| 3992 | /// The name of an attribute in an identity is not within the legal range. | 2726 | /// The name of an attribute in an identity is not within the legal range. |
| 3993 | SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 0xC0150017, | 2727 | SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 0xC0150017, |
| 3994 | |||
| 3995 | /// An identity contains two definitions for the same attribute. | 2728 | /// An identity contains two definitions for the same attribute. |
| 3996 | SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 0xC0150018, | 2729 | SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 0xC0150018, |
| 3997 | |||
| 3998 | /// The identity string is malformed. | 2730 | /// The identity string is malformed. |
| 3999 | /// This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value. | 2731 | /// This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value. |
| 4000 | SXS_IDENTITY_PARSE_ERROR = 0xC0150019, | 2732 | SXS_IDENTITY_PARSE_ERROR = 0xC0150019, |
| 4001 | |||
| 4002 | /// The component store has become corrupted. | 2733 | /// The component store has become corrupted. |
| 4003 | SXS_COMPONENT_STORE_CORRUPT = 0xC015001A, | 2734 | SXS_COMPONENT_STORE_CORRUPT = 0xC015001A, |
| 4004 | |||
| 4005 | /// A component's file does not match the verification information present in the component manifest. | 2735 | /// A component's file does not match the verification information present in the component manifest. |
| 4006 | SXS_FILE_HASH_MISMATCH = 0xC015001B, | 2736 | SXS_FILE_HASH_MISMATCH = 0xC015001B, |
| 4007 | |||
| 4008 | /// The identities of the manifests are identical, but their contents are different. | 2737 | /// The identities of the manifests are identical, but their contents are different. |
| 4009 | SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 0xC015001C, | 2738 | SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 0xC015001C, |
| 4010 | |||
| 4011 | /// The component identities are different. | 2739 | /// The component identities are different. |
| 4012 | SXS_IDENTITIES_DIFFERENT = 0xC015001D, | 2740 | SXS_IDENTITIES_DIFFERENT = 0xC015001D, |
| 4013 | |||
| 4014 | /// The assembly is not a deployment. | 2741 | /// The assembly is not a deployment. |
| 4015 | SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 0xC015001E, | 2742 | SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 0xC015001E, |
| 4016 | |||
| 4017 | /// The file is not a part of the assembly. | 2743 | /// The file is not a part of the assembly. |
| 4018 | SXS_FILE_NOT_PART_OF_ASSEMBLY = 0xC015001F, | 2744 | SXS_FILE_NOT_PART_OF_ASSEMBLY = 0xC015001F, |
| 4019 | |||
| 4020 | /// An advanced installer failed during setup or servicing. | 2745 | /// An advanced installer failed during setup or servicing. |
| 4021 | ADVANCED_INSTALLER_FAILED = 0xC0150020, | 2746 | ADVANCED_INSTALLER_FAILED = 0xC0150020, |
| 4022 | |||
| 4023 | /// The character encoding in the XML declaration did not match the encoding used in the document. | 2747 | /// The character encoding in the XML declaration did not match the encoding used in the document. |
| 4024 | XML_ENCODING_MISMATCH = 0xC0150021, | 2748 | XML_ENCODING_MISMATCH = 0xC0150021, |
| 4025 | |||
| 4026 | /// The size of the manifest exceeds the maximum allowed. | 2749 | /// The size of the manifest exceeds the maximum allowed. |
| 4027 | SXS_MANIFEST_TOO_BIG = 0xC0150022, | 2750 | SXS_MANIFEST_TOO_BIG = 0xC0150022, |
| 4028 | |||
| 4029 | /// The setting is not registered. | 2751 | /// The setting is not registered. |
| 4030 | SXS_SETTING_NOT_REGISTERED = 0xC0150023, | 2752 | SXS_SETTING_NOT_REGISTERED = 0xC0150023, |
| 4031 | |||
| 4032 | /// One or more required transaction members are not present. | 2753 | /// One or more required transaction members are not present. |
| 4033 | SXS_TRANSACTION_CLOSURE_INCOMPLETE = 0xC0150024, | 2754 | SXS_TRANSACTION_CLOSURE_INCOMPLETE = 0xC0150024, |
| 4034 | |||
| 4035 | /// The SMI primitive installer failed during setup or servicing. | 2755 | /// The SMI primitive installer failed during setup or servicing. |
| 4036 | SMI_PRIMITIVE_INSTALLER_FAILED = 0xC0150025, | 2756 | SMI_PRIMITIVE_INSTALLER_FAILED = 0xC0150025, |
| 4037 | |||
| 4038 | /// A generic command executable returned a result that indicates failure. | 2757 | /// A generic command executable returned a result that indicates failure. |
| 4039 | GENERIC_COMMAND_FAILED = 0xC0150026, | 2758 | GENERIC_COMMAND_FAILED = 0xC0150026, |
| 4040 | |||
| 4041 | /// A component is missing file verification information in its manifest. | 2759 | /// A component is missing file verification information in its manifest. |
| 4042 | SXS_FILE_HASH_MISSING = 0xC0150027, | 2760 | SXS_FILE_HASH_MISSING = 0xC0150027, |
| 4043 | |||
| 4044 | /// The function attempted to use a name that is reserved for use by another transaction. | 2761 | /// The function attempted to use a name that is reserved for use by another transaction. |
| 4045 | TRANSACTIONAL_CONFLICT = 0xC0190001, | 2762 | TRANSACTIONAL_CONFLICT = 0xC0190001, |
| 4046 | |||
| 4047 | /// The transaction handle associated with this operation is invalid. | 2763 | /// The transaction handle associated with this operation is invalid. |
| 4048 | INVALID_TRANSACTION = 0xC0190002, | 2764 | INVALID_TRANSACTION = 0xC0190002, |
| 4049 | |||
| 4050 | /// The requested operation was made in the context of a transaction that is no longer active. | 2765 | /// The requested operation was made in the context of a transaction that is no longer active. |
| 4051 | TRANSACTION_NOT_ACTIVE = 0xC0190003, | 2766 | TRANSACTION_NOT_ACTIVE = 0xC0190003, |
| 4052 | |||
| 4053 | /// The transaction manager was unable to be successfully initialized. Transacted operations are not supported. | 2767 | /// The transaction manager was unable to be successfully initialized. Transacted operations are not supported. |
| 4054 | TM_INITIALIZATION_FAILED = 0xC0190004, | 2768 | TM_INITIALIZATION_FAILED = 0xC0190004, |
| 4055 | |||
| 4056 | /// Transaction support within the specified file system resource manager was not started or was shut down due to an error. | 2769 | /// Transaction support within the specified file system resource manager was not started or was shut down due to an error. |
| 4057 | RM_NOT_ACTIVE = 0xC0190005, | 2770 | RM_NOT_ACTIVE = 0xC0190005, |
| 4058 | |||
| 4059 | /// The metadata of the resource manager has been corrupted. The resource manager will not function. | 2771 | /// The metadata of the resource manager has been corrupted. The resource manager will not function. |
| 4060 | RM_METADATA_CORRUPT = 0xC0190006, | 2772 | RM_METADATA_CORRUPT = 0xC0190006, |
| 4061 | |||
| 4062 | /// The resource manager attempted to prepare a transaction that it has not successfully joined. | 2773 | /// The resource manager attempted to prepare a transaction that it has not successfully joined. |
| 4063 | TRANSACTION_NOT_JOINED = 0xC0190007, | 2774 | TRANSACTION_NOT_JOINED = 0xC0190007, |
| 4064 | |||
| 4065 | /// The specified directory does not contain a file system resource manager. | 2775 | /// The specified directory does not contain a file system resource manager. |
| 4066 | DIRECTORY_NOT_RM = 0xC0190008, | 2776 | DIRECTORY_NOT_RM = 0xC0190008, |
| 4067 | |||
| 4068 | /// The remote server or share does not support transacted file operations. | 2777 | /// The remote server or share does not support transacted file operations. |
| 4069 | TRANSACTIONS_UNSUPPORTED_REMOTE = 0xC019000A, | 2778 | TRANSACTIONS_UNSUPPORTED_REMOTE = 0xC019000A, |
| 4070 | |||
| 4071 | /// The requested log size for the file system resource manager is invalid. | 2779 | /// The requested log size for the file system resource manager is invalid. |
| 4072 | LOG_RESIZE_INVALID_SIZE = 0xC019000B, | 2780 | LOG_RESIZE_INVALID_SIZE = 0xC019000B, |
| 4073 | |||
| 4074 | /// The remote server sent mismatching version number or Fid for a file opened with transactions. | 2781 | /// The remote server sent mismatching version number or Fid for a file opened with transactions. |
| 4075 | REMOTE_FILE_VERSION_MISMATCH = 0xC019000C, | 2782 | REMOTE_FILE_VERSION_MISMATCH = 0xC019000C, |
| 4076 | |||
| 4077 | /// The resource manager tried to register a protocol that already exists. | 2783 | /// The resource manager tried to register a protocol that already exists. |
| 4078 | CRM_PROTOCOL_ALREADY_EXISTS = 0xC019000F, | 2784 | CRM_PROTOCOL_ALREADY_EXISTS = 0xC019000F, |
| 4079 | |||
| 4080 | /// The attempt to propagate the transaction failed. | 2785 | /// The attempt to propagate the transaction failed. |
| 4081 | TRANSACTION_PROPAGATION_FAILED = 0xC0190010, | 2786 | TRANSACTION_PROPAGATION_FAILED = 0xC0190010, |
| 4082 | |||
| 4083 | /// The requested propagation protocol was not registered as a CRM. | 2787 | /// The requested propagation protocol was not registered as a CRM. |
| 4084 | CRM_PROTOCOL_NOT_FOUND = 0xC0190011, | 2788 | CRM_PROTOCOL_NOT_FOUND = 0xC0190011, |
| 4085 | |||
| 4086 | /// The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed. | 2789 | /// The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed. |
| 4087 | TRANSACTION_SUPERIOR_EXISTS = 0xC0190012, | 2790 | TRANSACTION_SUPERIOR_EXISTS = 0xC0190012, |
| 4088 | |||
| 4089 | /// The requested operation is not valid on the transaction object in its current state. | 2791 | /// The requested operation is not valid on the transaction object in its current state. |
| 4090 | TRANSACTION_REQUEST_NOT_VALID = 0xC0190013, | 2792 | TRANSACTION_REQUEST_NOT_VALID = 0xC0190013, |
| 4091 | |||
| 4092 | /// The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller. | 2793 | /// The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller. |
| 4093 | TRANSACTION_NOT_REQUESTED = 0xC0190014, | 2794 | TRANSACTION_NOT_REQUESTED = 0xC0190014, |
| 4094 | |||
| 4095 | /// It is too late to perform the requested operation, because the transaction has already been aborted. | 2795 | /// It is too late to perform the requested operation, because the transaction has already been aborted. |
| 4096 | TRANSACTION_ALREADY_ABORTED = 0xC0190015, | 2796 | TRANSACTION_ALREADY_ABORTED = 0xC0190015, |
| 4097 | |||
| 4098 | /// It is too late to perform the requested operation, because the transaction has already been committed. | 2797 | /// It is too late to perform the requested operation, because the transaction has already been committed. |
| 4099 | TRANSACTION_ALREADY_COMMITTED = 0xC0190016, | 2798 | TRANSACTION_ALREADY_COMMITTED = 0xC0190016, |
| 4100 | |||
| 4101 | /// The buffer passed in to NtPushTransaction or NtPullTransaction is not in a valid format. | 2799 | /// The buffer passed in to NtPushTransaction or NtPullTransaction is not in a valid format. |
| 4102 | TRANSACTION_INVALID_MARSHALL_BUFFER = 0xC0190017, | 2800 | TRANSACTION_INVALID_MARSHALL_BUFFER = 0xC0190017, |
| 4103 | |||
| 4104 | /// The current transaction context associated with the thread is not a valid handle to a transaction object. | 2801 | /// The current transaction context associated with the thread is not a valid handle to a transaction object. |
| 4105 | CURRENT_TRANSACTION_NOT_VALID = 0xC0190018, | 2802 | CURRENT_TRANSACTION_NOT_VALID = 0xC0190018, |
| 4106 | |||
| 4107 | /// An attempt to create space in the transactional resource manager's log failed. | 2803 | /// An attempt to create space in the transactional resource manager's log failed. |
| 4108 | /// The failure status has been recorded in the event log. | 2804 | /// The failure status has been recorded in the event log. |
| 4109 | LOG_GROWTH_FAILED = 0xC0190019, | 2805 | LOG_GROWTH_FAILED = 0xC0190019, |
| 4110 | |||
| 4111 | /// The object (file, stream, or link) that corresponds to the handle has been deleted by a transaction savepoint rollback. | 2806 | /// The object (file, stream, or link) that corresponds to the handle has been deleted by a transaction savepoint rollback. |
| 4112 | OBJECT_NO_LONGER_EXISTS = 0xC0190021, | 2807 | OBJECT_NO_LONGER_EXISTS = 0xC0190021, |
| 4113 | |||
| 4114 | /// The specified file miniversion was not found for this transacted file open. | 2808 | /// The specified file miniversion was not found for this transacted file open. |
| 4115 | STREAM_MINIVERSION_NOT_FOUND = 0xC0190022, | 2809 | STREAM_MINIVERSION_NOT_FOUND = 0xC0190022, |
| 4116 | |||
| 4117 | /// The specified file miniversion was found but has been invalidated. | 2810 | /// The specified file miniversion was found but has been invalidated. |
| 4118 | /// The most likely cause is a transaction savepoint rollback. | 2811 | /// The most likely cause is a transaction savepoint rollback. |
| 4119 | STREAM_MINIVERSION_NOT_VALID = 0xC0190023, | 2812 | STREAM_MINIVERSION_NOT_VALID = 0xC0190023, |
| 4120 | |||
| 4121 | /// A miniversion can be opened only in the context of the transaction that created it. | 2813 | /// A miniversion can be opened only in the context of the transaction that created it. |
| 4122 | MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xC0190024, | 2814 | MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xC0190024, |
| 4123 | |||
| 4124 | /// It is not possible to open a miniversion with modify access. | 2815 | /// It is not possible to open a miniversion with modify access. |
| 4125 | CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xC0190025, | 2816 | CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xC0190025, |
| 4126 | |||
| 4127 | /// It is not possible to create any more miniversions for this stream. | 2817 | /// It is not possible to create any more miniversions for this stream. |
| 4128 | CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xC0190026, | 2818 | CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xC0190026, |
| 4129 | |||
| 4130 | /// The handle has been invalidated by a transaction. | 2819 | /// The handle has been invalidated by a transaction. |
| 4131 | /// The most likely cause is the presence of memory mapping on a file or an open handle when the transaction ended or rolled back to savepoint. | 2820 | /// The most likely cause is the presence of memory mapping on a file or an open handle when the transaction ended or rolled back to savepoint. |
| 4132 | HANDLE_NO_LONGER_VALID = 0xC0190028, | 2821 | HANDLE_NO_LONGER_VALID = 0xC0190028, |
| 4133 | |||
| 4134 | /// The log data is corrupt. | 2822 | /// The log data is corrupt. |
| 4135 | LOG_CORRUPTION_DETECTED = 0xC0190030, | 2823 | LOG_CORRUPTION_DETECTED = 0xC0190030, |
| 4136 | |||
| 4137 | /// The transaction outcome is unavailable because the resource manager responsible for it is disconnected. | 2824 | /// The transaction outcome is unavailable because the resource manager responsible for it is disconnected. |
| 4138 | RM_DISCONNECTED = 0xC0190032, | 2825 | RM_DISCONNECTED = 0xC0190032, |
| 4139 | |||
| 4140 | /// The request was rejected because the enlistment in question is not a superior enlistment. | 2826 | /// The request was rejected because the enlistment in question is not a superior enlistment. |
| 4141 | ENLISTMENT_NOT_SUPERIOR = 0xC0190033, | 2827 | ENLISTMENT_NOT_SUPERIOR = 0xC0190033, |
| 4142 | |||
| 4143 | /// The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction. | 2828 | /// The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction. |
| 4144 | FILE_IDENTITY_NOT_PERSISTENT = 0xC0190036, | 2829 | FILE_IDENTITY_NOT_PERSISTENT = 0xC0190036, |
| 4145 | |||
| 4146 | /// The operation cannot be performed because another transaction is depending on this property not changing. | 2830 | /// The operation cannot be performed because another transaction is depending on this property not changing. |
| 4147 | CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xC0190037, | 2831 | CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xC0190037, |
| 4148 | |||
| 4149 | /// The operation would involve a single file with two transactional resource managers and is, therefore, not allowed. | 2832 | /// The operation would involve a single file with two transactional resource managers and is, therefore, not allowed. |
| 4150 | CANT_CROSS_RM_BOUNDARY = 0xC0190038, | 2833 | CANT_CROSS_RM_BOUNDARY = 0xC0190038, |
| 4151 | |||
| 4152 | /// The $Txf directory must be empty for this operation to succeed. | 2834 | /// The $Txf directory must be empty for this operation to succeed. |
| 4153 | TXF_DIR_NOT_EMPTY = 0xC0190039, | 2835 | TXF_DIR_NOT_EMPTY = 0xC0190039, |
| 4154 | |||
| 4155 | /// The operation would leave a transactional resource manager in an inconsistent state and is therefore not allowed. | 2836 | /// The operation would leave a transactional resource manager in an inconsistent state and is therefore not allowed. |
| 4156 | INDOUBT_TRANSACTIONS_EXIST = 0xC019003A, | 2837 | INDOUBT_TRANSACTIONS_EXIST = 0xC019003A, |
| 4157 | |||
| 4158 | /// The operation could not be completed because the transaction manager does not have a log. | 2838 | /// The operation could not be completed because the transaction manager does not have a log. |
| 4159 | TM_VOLATILE = 0xC019003B, | 2839 | TM_VOLATILE = 0xC019003B, |
| 4160 | |||
| 4161 | /// A rollback could not be scheduled because a previously scheduled rollback has already executed or been queued for execution. | 2840 | /// A rollback could not be scheduled because a previously scheduled rollback has already executed or been queued for execution. |
| 4162 | ROLLBACK_TIMER_EXPIRED = 0xC019003C, | 2841 | ROLLBACK_TIMER_EXPIRED = 0xC019003C, |
| 4163 | |||
| 4164 | /// The transactional metadata attribute on the file or directory %hs is corrupt and unreadable. | 2842 | /// The transactional metadata attribute on the file or directory %hs is corrupt and unreadable. |
| 4165 | TXF_ATTRIBUTE_CORRUPT = 0xC019003D, | 2843 | TXF_ATTRIBUTE_CORRUPT = 0xC019003D, |
| 4166 | |||
| 4167 | /// The encryption operation could not be completed because a transaction is active. | 2844 | /// The encryption operation could not be completed because a transaction is active. |
| 4168 | EFS_NOT_ALLOWED_IN_TRANSACTION = 0xC019003E, | 2845 | EFS_NOT_ALLOWED_IN_TRANSACTION = 0xC019003E, |
| 4169 | |||
| 4170 | /// This object is not allowed to be opened in a transaction. | 2846 | /// This object is not allowed to be opened in a transaction. |
| 4171 | TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xC019003F, | 2847 | TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xC019003F, |
| 4172 | |||
| 4173 | /// Memory mapping (creating a mapped section) a remote file under a transaction is not supported. | 2848 | /// Memory mapping (creating a mapped section) a remote file under a transaction is not supported. |
| 4174 | TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xC0190040, | 2849 | TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xC0190040, |
| 4175 | |||
| 4176 | /// Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it. | 2850 | /// Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it. |
| 4177 | TRANSACTION_REQUIRED_PROMOTION = 0xC0190043, | 2851 | TRANSACTION_REQUIRED_PROMOTION = 0xC0190043, |
| 4178 | |||
| 4179 | /// This file is open for modification in an unresolved transaction and can be opened for execute only by a transacted reader. | 2852 | /// This file is open for modification in an unresolved transaction and can be opened for execute only by a transacted reader. |
| 4180 | CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xC0190044, | 2853 | CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xC0190044, |
| 4181 | |||
| 4182 | /// The request to thaw frozen transactions was ignored because transactions were not previously frozen. | 2854 | /// The request to thaw frozen transactions was ignored because transactions were not previously frozen. |
| 4183 | TRANSACTIONS_NOT_FROZEN = 0xC0190045, | 2855 | TRANSACTIONS_NOT_FROZEN = 0xC0190045, |
| 4184 | |||
| 4185 | /// Transactions cannot be frozen because a freeze is already in progress. | 2856 | /// Transactions cannot be frozen because a freeze is already in progress. |
| 4186 | TRANSACTION_FREEZE_IN_PROGRESS = 0xC0190046, | 2857 | TRANSACTION_FREEZE_IN_PROGRESS = 0xC0190046, |
| 4187 | |||
| 4188 | /// The target volume is not a snapshot volume. | 2858 | /// The target volume is not a snapshot volume. |
| 4189 | /// This operation is valid only on a volume mounted as a snapshot. | 2859 | /// This operation is valid only on a volume mounted as a snapshot. |
| 4190 | NOT_SNAPSHOT_VOLUME = 0xC0190047, | 2860 | NOT_SNAPSHOT_VOLUME = 0xC0190047, |
| 4191 | |||
| 4192 | /// The savepoint operation failed because files are open on the transaction, which is not permitted. | 2861 | /// The savepoint operation failed because files are open on the transaction, which is not permitted. |
| 4193 | NO_SAVEPOINT_WITH_OPEN_FILES = 0xC0190048, | 2862 | NO_SAVEPOINT_WITH_OPEN_FILES = 0xC0190048, |
| 4194 | |||
| 4195 | /// The sparse operation could not be completed because a transaction is active on the file. | 2863 | /// The sparse operation could not be completed because a transaction is active on the file. |
| 4196 | SPARSE_NOT_ALLOWED_IN_TRANSACTION = 0xC0190049, | 2864 | SPARSE_NOT_ALLOWED_IN_TRANSACTION = 0xC0190049, |
| 4197 | |||
| 4198 | /// The call to create a transaction manager object failed because the Tm Identity that is stored in the log file does not match the Tm Identity that was passed in as an argument. | 2865 | /// The call to create a transaction manager object failed because the Tm Identity that is stored in the log file does not match the Tm Identity that was passed in as an argument. |
| 4199 | TM_IDENTITY_MISMATCH = 0xC019004A, | 2866 | TM_IDENTITY_MISMATCH = 0xC019004A, |
| 4200 | |||
| 4201 | /// I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data. | 2867 | /// I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data. |
| 4202 | FLOATED_SECTION = 0xC019004B, | 2868 | FLOATED_SECTION = 0xC019004B, |
| 4203 | |||
| 4204 | /// The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources. | 2869 | /// The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources. |
| 4205 | CANNOT_ACCEPT_TRANSACTED_WORK = 0xC019004C, | 2870 | CANNOT_ACCEPT_TRANSACTED_WORK = 0xC019004C, |
| 4206 | |||
| 4207 | /// The transactional resource manager had too many transactions outstanding that could not be aborted. | 2871 | /// The transactional resource manager had too many transactions outstanding that could not be aborted. |
| 4208 | /// The transactional resource manager has been shut down. | 2872 | /// The transactional resource manager has been shut down. |
| 4209 | CANNOT_ABORT_TRANSACTIONS = 0xC019004D, | 2873 | CANNOT_ABORT_TRANSACTIONS = 0xC019004D, |
| 4210 | |||
| 4211 | /// The specified transaction was unable to be opened because it was not found. | 2874 | /// The specified transaction was unable to be opened because it was not found. |
| 4212 | TRANSACTION_NOT_FOUND = 0xC019004E, | 2875 | TRANSACTION_NOT_FOUND = 0xC019004E, |
| 4213 | |||
| 4214 | /// The specified resource manager was unable to be opened because it was not found. | 2876 | /// The specified resource manager was unable to be opened because it was not found. |
| 4215 | RESOURCEMANAGER_NOT_FOUND = 0xC019004F, | 2877 | RESOURCEMANAGER_NOT_FOUND = 0xC019004F, |
| 4216 | |||
| 4217 | /// The specified enlistment was unable to be opened because it was not found. | 2878 | /// The specified enlistment was unable to be opened because it was not found. |
| 4218 | ENLISTMENT_NOT_FOUND = 0xC0190050, | 2879 | ENLISTMENT_NOT_FOUND = 0xC0190050, |
| 4219 | |||
| 4220 | /// The specified transaction manager was unable to be opened because it was not found. | 2880 | /// The specified transaction manager was unable to be opened because it was not found. |
| 4221 | TRANSACTIONMANAGER_NOT_FOUND = 0xC0190051, | 2881 | TRANSACTIONMANAGER_NOT_FOUND = 0xC0190051, |
| 4222 | |||
| 4223 | /// The specified resource manager was unable to create an enlistment because its associated transaction manager is not online. | 2882 | /// The specified resource manager was unable to create an enlistment because its associated transaction manager is not online. |
| 4224 | TRANSACTIONMANAGER_NOT_ONLINE = 0xC0190052, | 2883 | TRANSACTIONMANAGER_NOT_ONLINE = 0xC0190052, |
| 4225 | |||
| 4226 | /// The specified transaction manager was unable to create the objects contained in its log file in the Ob namespace. | 2884 | /// The specified transaction manager was unable to create the objects contained in its log file in the Ob namespace. |
| 4227 | /// Therefore, the transaction manager was unable to recover. | 2885 | /// Therefore, the transaction manager was unable to recover. |
| 4228 | TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 0xC0190053, | 2886 | TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 0xC0190053, |
| 4229 | |||
| 4230 | /// The call to create a superior enlistment on this transaction object could not be completed because the transaction object specified for the enlistment is a subordinate branch of the transaction. | 2887 | /// The call to create a superior enlistment on this transaction object could not be completed because the transaction object specified for the enlistment is a subordinate branch of the transaction. |
| 4231 | /// Only the root of the transaction can be enlisted as a superior. | 2888 | /// Only the root of the transaction can be enlisted as a superior. |
| 4232 | TRANSACTION_NOT_ROOT = 0xC0190054, | 2889 | TRANSACTION_NOT_ROOT = 0xC0190054, |
| 4233 | |||
| 4234 | /// Because the associated transaction manager or resource manager has been closed, the handle is no longer valid. | 2890 | /// Because the associated transaction manager or resource manager has been closed, the handle is no longer valid. |
| 4235 | TRANSACTION_OBJECT_EXPIRED = 0xC0190055, | 2891 | TRANSACTION_OBJECT_EXPIRED = 0xC0190055, |
| 4236 | |||
| 4237 | /// The compression operation could not be completed because a transaction is active on the file. | 2892 | /// The compression operation could not be completed because a transaction is active on the file. |
| 4238 | COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 0xC0190056, | 2893 | COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 0xC0190056, |
| 4239 | |||
| 4240 | /// The specified operation could not be performed on this superior enlistment because the enlistment was not created with the corresponding completion response in the NotificationMask. | 2894 | /// The specified operation could not be performed on this superior enlistment because the enlistment was not created with the corresponding completion response in the NotificationMask. |
| 4241 | TRANSACTION_RESPONSE_NOT_ENLISTED = 0xC0190057, | 2895 | TRANSACTION_RESPONSE_NOT_ENLISTED = 0xC0190057, |
| 4242 | |||
| 4243 | /// The specified operation could not be performed because the record to be logged was too long. | 2896 | /// The specified operation could not be performed because the record to be logged was too long. |
| 4244 | /// This can occur because either there are too many enlistments on this transaction or the combined RecoveryInformation being logged on behalf of those enlistments is too long. | 2897 | /// This can occur because either there are too many enlistments on this transaction or the combined RecoveryInformation being logged on behalf of those enlistments is too long. |
| 4245 | TRANSACTION_RECORD_TOO_LONG = 0xC0190058, | 2898 | TRANSACTION_RECORD_TOO_LONG = 0xC0190058, |
| 4246 | |||
| 4247 | /// The link-tracking operation could not be completed because a transaction is active. | 2899 | /// The link-tracking operation could not be completed because a transaction is active. |
| 4248 | NO_LINK_TRACKING_IN_TRANSACTION = 0xC0190059, | 2900 | NO_LINK_TRACKING_IN_TRANSACTION = 0xC0190059, |
| 4249 | |||
| 4250 | /// This operation cannot be performed in a transaction. | 2901 | /// This operation cannot be performed in a transaction. |
| 4251 | OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 0xC019005A, | 2902 | OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 0xC019005A, |
| 4252 | |||
| 4253 | /// The kernel transaction manager had to abort or forget the transaction because it blocked forward progress. | 2903 | /// The kernel transaction manager had to abort or forget the transaction because it blocked forward progress. |
| 4254 | TRANSACTION_INTEGRITY_VIOLATED = 0xC019005B, | 2904 | TRANSACTION_INTEGRITY_VIOLATED = 0xC019005B, |
| 4255 | |||
| 4256 | /// The handle is no longer properly associated with its transaction. | 2905 | /// The handle is no longer properly associated with its transaction. |
| 4257 | /// It might have been opened in a transactional resource manager that was subsequently forced to restart. Please close the handle and open a new one. | 2906 | /// It might have been opened in a transactional resource manager that was subsequently forced to restart. Please close the handle and open a new one. |
| 4258 | EXPIRED_HANDLE = 0xC0190060, | 2907 | EXPIRED_HANDLE = 0xC0190060, |
| 4259 | |||
| 4260 | /// The specified operation could not be performed because the resource manager is not enlisted in the transaction. | 2908 | /// The specified operation could not be performed because the resource manager is not enlisted in the transaction. |
| 4261 | TRANSACTION_NOT_ENLISTED = 0xC0190061, | 2909 | TRANSACTION_NOT_ENLISTED = 0xC0190061, |
| 4262 | |||
| 4263 | /// The log service found an invalid log sector. | 2910 | /// The log service found an invalid log sector. |
| 4264 | LOG_SECTOR_INVALID = 0xC01A0001, | 2911 | LOG_SECTOR_INVALID = 0xC01A0001, |
| 4265 | |||
| 4266 | /// The log service encountered a log sector with invalid block parity. | 2912 | /// The log service encountered a log sector with invalid block parity. |
| 4267 | LOG_SECTOR_PARITY_INVALID = 0xC01A0002, | 2913 | LOG_SECTOR_PARITY_INVALID = 0xC01A0002, |
| 4268 | |||
| 4269 | /// The log service encountered a remapped log sector. | 2914 | /// The log service encountered a remapped log sector. |
| 4270 | LOG_SECTOR_REMAPPED = 0xC01A0003, | 2915 | LOG_SECTOR_REMAPPED = 0xC01A0003, |
| 4271 | |||
| 4272 | /// The log service encountered a partial or incomplete log block. | 2916 | /// The log service encountered a partial or incomplete log block. |
| 4273 | LOG_BLOCK_INCOMPLETE = 0xC01A0004, | 2917 | LOG_BLOCK_INCOMPLETE = 0xC01A0004, |
| 4274 | |||
| 4275 | /// The log service encountered an attempt to access data outside the active log range. | 2918 | /// The log service encountered an attempt to access data outside the active log range. |
| 4276 | LOG_INVALID_RANGE = 0xC01A0005, | 2919 | LOG_INVALID_RANGE = 0xC01A0005, |
| 4277 | |||
| 4278 | /// The log service user-log marshaling buffers are exhausted. | 2920 | /// The log service user-log marshaling buffers are exhausted. |
| 4279 | LOG_BLOCKS_EXHAUSTED = 0xC01A0006, | 2921 | LOG_BLOCKS_EXHAUSTED = 0xC01A0006, |
| 4280 | |||
| 4281 | /// The log service encountered an attempt to read from a marshaling area with an invalid read context. | 2922 | /// The log service encountered an attempt to read from a marshaling area with an invalid read context. |
| 4282 | LOG_READ_CONTEXT_INVALID = 0xC01A0007, | 2923 | LOG_READ_CONTEXT_INVALID = 0xC01A0007, |
| 4283 | |||
| 4284 | /// The log service encountered an invalid log restart area. | 2924 | /// The log service encountered an invalid log restart area. |
| 4285 | LOG_RESTART_INVALID = 0xC01A0008, | 2925 | LOG_RESTART_INVALID = 0xC01A0008, |
| 4286 | |||
| 4287 | /// The log service encountered an invalid log block version. | 2926 | /// The log service encountered an invalid log block version. |
| 4288 | LOG_BLOCK_VERSION = 0xC01A0009, | 2927 | LOG_BLOCK_VERSION = 0xC01A0009, |
| 4289 | |||
| 4290 | /// The log service encountered an invalid log block. | 2928 | /// The log service encountered an invalid log block. |
| 4291 | LOG_BLOCK_INVALID = 0xC01A000A, | 2929 | LOG_BLOCK_INVALID = 0xC01A000A, |
| 4292 | |||
| 4293 | /// The log service encountered an attempt to read the log with an invalid read mode. | 2930 | /// The log service encountered an attempt to read the log with an invalid read mode. |
| 4294 | LOG_READ_MODE_INVALID = 0xC01A000B, | 2931 | LOG_READ_MODE_INVALID = 0xC01A000B, |
| 4295 | |||
| 4296 | /// The log service encountered a corrupted metadata file. | 2932 | /// The log service encountered a corrupted metadata file. |
| 4297 | LOG_METADATA_CORRUPT = 0xC01A000D, | 2933 | LOG_METADATA_CORRUPT = 0xC01A000D, |
| 4298 | |||
| 4299 | /// The log service encountered a metadata file that could not be created by the log file system. | 2934 | /// The log service encountered a metadata file that could not be created by the log file system. |
| 4300 | LOG_METADATA_INVALID = 0xC01A000E, | 2935 | LOG_METADATA_INVALID = 0xC01A000E, |
| 4301 | |||
| 4302 | /// The log service encountered a metadata file with inconsistent data. | 2936 | /// The log service encountered a metadata file with inconsistent data. |
| 4303 | LOG_METADATA_INCONSISTENT = 0xC01A000F, | 2937 | LOG_METADATA_INCONSISTENT = 0xC01A000F, |
| 4304 | |||
| 4305 | /// The log service encountered an attempt to erroneously allocate or dispose reservation space. | 2938 | /// The log service encountered an attempt to erroneously allocate or dispose reservation space. |
| 4306 | LOG_RESERVATION_INVALID = 0xC01A0010, | 2939 | LOG_RESERVATION_INVALID = 0xC01A0010, |
| 4307 | |||
| 4308 | /// The log service cannot delete the log file or the file system container. | 2940 | /// The log service cannot delete the log file or the file system container. |
| 4309 | LOG_CANT_DELETE = 0xC01A0011, | 2941 | LOG_CANT_DELETE = 0xC01A0011, |
| 4310 | |||
| 4311 | /// The log service has reached the maximum allowable containers allocated to a log file. | 2942 | /// The log service has reached the maximum allowable containers allocated to a log file. |
| 4312 | LOG_CONTAINER_LIMIT_EXCEEDED = 0xC01A0012, | 2943 | LOG_CONTAINER_LIMIT_EXCEEDED = 0xC01A0012, |
| 4313 | |||
| 4314 | /// The log service has attempted to read or write backward past the start of the log. | 2944 | /// The log service has attempted to read or write backward past the start of the log. |
| 4315 | LOG_START_OF_LOG = 0xC01A0013, | 2945 | LOG_START_OF_LOG = 0xC01A0013, |
| 4316 | |||
| 4317 | /// The log policy could not be installed because a policy of the same type is already present. | 2946 | /// The log policy could not be installed because a policy of the same type is already present. |
| 4318 | LOG_POLICY_ALREADY_INSTALLED = 0xC01A0014, | 2947 | LOG_POLICY_ALREADY_INSTALLED = 0xC01A0014, |
| 4319 | |||
| 4320 | /// The log policy in question was not installed at the time of the request. | 2948 | /// The log policy in question was not installed at the time of the request. |
| 4321 | LOG_POLICY_NOT_INSTALLED = 0xC01A0015, | 2949 | LOG_POLICY_NOT_INSTALLED = 0xC01A0015, |
| 4322 | |||
| 4323 | /// The installed set of policies on the log is invalid. | 2950 | /// The installed set of policies on the log is invalid. |
| 4324 | LOG_POLICY_INVALID = 0xC01A0016, | 2951 | LOG_POLICY_INVALID = 0xC01A0016, |
| 4325 | |||
| 4326 | /// A policy on the log in question prevented the operation from completing. | 2952 | /// A policy on the log in question prevented the operation from completing. |
| 4327 | LOG_POLICY_CONFLICT = 0xC01A0017, | 2953 | LOG_POLICY_CONFLICT = 0xC01A0017, |
| 4328 | |||
| 4329 | /// The log space cannot be reclaimed because the log is pinned by the archive tail. | 2954 | /// The log space cannot be reclaimed because the log is pinned by the archive tail. |
| 4330 | LOG_PINNED_ARCHIVE_TAIL = 0xC01A0018, | 2955 | LOG_PINNED_ARCHIVE_TAIL = 0xC01A0018, |
| 4331 | |||
| 4332 | /// The log record is not a record in the log file. | 2956 | /// The log record is not a record in the log file. |
| 4333 | LOG_RECORD_NONEXISTENT = 0xC01A0019, | 2957 | LOG_RECORD_NONEXISTENT = 0xC01A0019, |
| 4334 | |||
| 4335 | /// The number of reserved log records or the adjustment of the number of reserved log records is invalid. | 2958 | /// The number of reserved log records or the adjustment of the number of reserved log records is invalid. |
| 4336 | LOG_RECORDS_RESERVED_INVALID = 0xC01A001A, | 2959 | LOG_RECORDS_RESERVED_INVALID = 0xC01A001A, |
| 4337 | |||
| 4338 | /// The reserved log space or the adjustment of the log space is invalid. | 2960 | /// The reserved log space or the adjustment of the log space is invalid. |
| 4339 | LOG_SPACE_RESERVED_INVALID = 0xC01A001B, | 2961 | LOG_SPACE_RESERVED_INVALID = 0xC01A001B, |
| 4340 | |||
| 4341 | /// A new or existing archive tail or the base of the active log is invalid. | 2962 | /// A new or existing archive tail or the base of the active log is invalid. |
| 4342 | LOG_TAIL_INVALID = 0xC01A001C, | 2963 | LOG_TAIL_INVALID = 0xC01A001C, |
| 4343 | |||
| 4344 | /// The log space is exhausted. | 2964 | /// The log space is exhausted. |
| 4345 | LOG_FULL = 0xC01A001D, | 2965 | LOG_FULL = 0xC01A001D, |
| 4346 | |||
| 4347 | /// The log is multiplexed; no direct writes to the physical log are allowed. | 2966 | /// The log is multiplexed; no direct writes to the physical log are allowed. |
| 4348 | LOG_MULTIPLEXED = 0xC01A001E, | 2967 | LOG_MULTIPLEXED = 0xC01A001E, |
| 4349 | |||
| 4350 | /// The operation failed because the log is dedicated. | 2968 | /// The operation failed because the log is dedicated. |
| 4351 | LOG_DEDICATED = 0xC01A001F, | 2969 | LOG_DEDICATED = 0xC01A001F, |
| 4352 | |||
| 4353 | /// The operation requires an archive context. | 2970 | /// The operation requires an archive context. |
| 4354 | LOG_ARCHIVE_NOT_IN_PROGRESS = 0xC01A0020, | 2971 | LOG_ARCHIVE_NOT_IN_PROGRESS = 0xC01A0020, |
| 4355 | |||
| 4356 | /// Log archival is in progress. | 2972 | /// Log archival is in progress. |
| 4357 | LOG_ARCHIVE_IN_PROGRESS = 0xC01A0021, | 2973 | LOG_ARCHIVE_IN_PROGRESS = 0xC01A0021, |
| 4358 | |||
| 4359 | /// The operation requires a nonephemeral log, but the log is ephemeral. | 2974 | /// The operation requires a nonephemeral log, but the log is ephemeral. |
| 4360 | LOG_EPHEMERAL = 0xC01A0022, | 2975 | LOG_EPHEMERAL = 0xC01A0022, |
| 4361 | |||
| 4362 | /// The log must have at least two containers before it can be read from or written to. | 2976 | /// The log must have at least two containers before it can be read from or written to. |
| 4363 | LOG_NOT_ENOUGH_CONTAINERS = 0xC01A0023, | 2977 | LOG_NOT_ENOUGH_CONTAINERS = 0xC01A0023, |
| 4364 | |||
| 4365 | /// A log client has already registered on the stream. | 2978 | /// A log client has already registered on the stream. |
| 4366 | LOG_CLIENT_ALREADY_REGISTERED = 0xC01A0024, | 2979 | LOG_CLIENT_ALREADY_REGISTERED = 0xC01A0024, |
| 4367 | |||
| 4368 | /// A log client has not been registered on the stream. | 2980 | /// A log client has not been registered on the stream. |
| 4369 | LOG_CLIENT_NOT_REGISTERED = 0xC01A0025, | 2981 | LOG_CLIENT_NOT_REGISTERED = 0xC01A0025, |
| 4370 | |||
| 4371 | /// A request has already been made to handle the log full condition. | 2982 | /// A request has already been made to handle the log full condition. |
| 4372 | LOG_FULL_HANDLER_IN_PROGRESS = 0xC01A0026, | 2983 | LOG_FULL_HANDLER_IN_PROGRESS = 0xC01A0026, |
| 4373 | |||
| 4374 | /// The log service encountered an error when attempting to read from a log container. | 2984 | /// The log service encountered an error when attempting to read from a log container. |
| 4375 | LOG_CONTAINER_READ_FAILED = 0xC01A0027, | 2985 | LOG_CONTAINER_READ_FAILED = 0xC01A0027, |
| 4376 | |||
| 4377 | /// The log service encountered an error when attempting to write to a log container. | 2986 | /// The log service encountered an error when attempting to write to a log container. |
| 4378 | LOG_CONTAINER_WRITE_FAILED = 0xC01A0028, | 2987 | LOG_CONTAINER_WRITE_FAILED = 0xC01A0028, |
| 4379 | |||
| 4380 | /// The log service encountered an error when attempting to open a log container. | 2988 | /// The log service encountered an error when attempting to open a log container. |
| 4381 | LOG_CONTAINER_OPEN_FAILED = 0xC01A0029, | 2989 | LOG_CONTAINER_OPEN_FAILED = 0xC01A0029, |
| 4382 | |||
| 4383 | /// The log service encountered an invalid container state when attempting a requested action. | 2990 | /// The log service encountered an invalid container state when attempting a requested action. |
| 4384 | LOG_CONTAINER_STATE_INVALID = 0xC01A002A, | 2991 | LOG_CONTAINER_STATE_INVALID = 0xC01A002A, |
| 4385 | |||
| 4386 | /// The log service is not in the correct state to perform a requested action. | 2992 | /// The log service is not in the correct state to perform a requested action. |
| 4387 | LOG_STATE_INVALID = 0xC01A002B, | 2993 | LOG_STATE_INVALID = 0xC01A002B, |
| 4388 | |||
| 4389 | /// The log space cannot be reclaimed because the log is pinned. | 2994 | /// The log space cannot be reclaimed because the log is pinned. |
| 4390 | LOG_PINNED = 0xC01A002C, | 2995 | LOG_PINNED = 0xC01A002C, |
| 4391 | |||
| 4392 | /// The log metadata flush failed. | 2996 | /// The log metadata flush failed. |
| 4393 | LOG_METADATA_FLUSH_FAILED = 0xC01A002D, | 2997 | LOG_METADATA_FLUSH_FAILED = 0xC01A002D, |
| 4394 | |||
| 4395 | /// Security on the log and its containers is inconsistent. | 2998 | /// Security on the log and its containers is inconsistent. |
| 4396 | LOG_INCONSISTENT_SECURITY = 0xC01A002E, | 2999 | LOG_INCONSISTENT_SECURITY = 0xC01A002E, |
| 4397 | |||
| 4398 | /// Records were appended to the log or reservation changes were made, but the log could not be flushed. | 3000 | /// Records were appended to the log or reservation changes were made, but the log could not be flushed. |
| 4399 | LOG_APPENDED_FLUSH_FAILED = 0xC01A002F, | 3001 | LOG_APPENDED_FLUSH_FAILED = 0xC01A002F, |
| 4400 | |||
| 4401 | /// The log is pinned due to reservation consuming most of the log space. | 3002 | /// The log is pinned due to reservation consuming most of the log space. |
| 4402 | /// Free some reserved records to make space available. | 3003 | /// Free some reserved records to make space available. |
| 4403 | LOG_PINNED_RESERVATION = 0xC01A0030, | 3004 | LOG_PINNED_RESERVATION = 0xC01A0030, |
| 4404 | |||
| 4405 | /// {Display Driver Stopped Responding} The %hs display driver has stopped working normally. | 3005 | /// {Display Driver Stopped Responding} The %hs display driver has stopped working normally. |
| 4406 | /// Save your work and reboot the system to restore full display functionality. | 3006 | /// Save your work and reboot the system to restore full display functionality. |
| 4407 | /// The next time you reboot the computer, a dialog box will allow you to upload data about this failure to Microsoft. | 3007 | /// The next time you reboot the computer, a dialog box will allow you to upload data about this failure to Microsoft. |
| 4408 | VIDEO_HUNG_DISPLAY_DRIVER_THREAD = 0xC01B00EA, | 3008 | VIDEO_HUNG_DISPLAY_DRIVER_THREAD = 0xC01B00EA, |
| 4409 | |||
| 4410 | /// A handler was not defined by the filter for this operation. | 3009 | /// A handler was not defined by the filter for this operation. |
| 4411 | FLT_NO_HANDLER_DEFINED = 0xC01C0001, | 3010 | FLT_NO_HANDLER_DEFINED = 0xC01C0001, |
| 4412 | |||
| 4413 | /// A context is already defined for this object. | 3011 | /// A context is already defined for this object. |
| 4414 | FLT_CONTEXT_ALREADY_DEFINED = 0xC01C0002, | 3012 | FLT_CONTEXT_ALREADY_DEFINED = 0xC01C0002, |
| 4415 | |||
| 4416 | /// Asynchronous requests are not valid for this operation. | 3013 | /// Asynchronous requests are not valid for this operation. |
| 4417 | FLT_INVALID_ASYNCHRONOUS_REQUEST = 0xC01C0003, | 3014 | FLT_INVALID_ASYNCHRONOUS_REQUEST = 0xC01C0003, |
| 4418 | |||
| 4419 | /// This is an internal error code used by the filter manager to determine if a fast I/O operation should be forced down the input/output request packet (IRP) path. Minifilters should never return this value. | 3015 | /// This is an internal error code used by the filter manager to determine if a fast I/O operation should be forced down the input/output request packet (IRP) path. Minifilters should never return this value. |
| 4420 | FLT_DISALLOW_FAST_IO = 0xC01C0004, | 3016 | FLT_DISALLOW_FAST_IO = 0xC01C0004, |
| 4421 | |||
| 4422 | /// An invalid name request was made. | 3017 | /// An invalid name request was made. |
| 4423 | /// The name requested cannot be retrieved at this time. | 3018 | /// The name requested cannot be retrieved at this time. |
| 4424 | FLT_INVALID_NAME_REQUEST = 0xC01C0005, | 3019 | FLT_INVALID_NAME_REQUEST = 0xC01C0005, |
| 4425 | |||
| 4426 | /// Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock. | 3020 | /// Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock. |
| 4427 | FLT_NOT_SAFE_TO_POST_OPERATION = 0xC01C0006, | 3021 | FLT_NOT_SAFE_TO_POST_OPERATION = 0xC01C0006, |
| 4428 | |||
| 4429 | /// The Filter Manager was not initialized when a filter tried to register. | 3022 | /// The Filter Manager was not initialized when a filter tried to register. |
| 4430 | /// Make sure that the Filter Manager is loaded as a driver. | 3023 | /// Make sure that the Filter Manager is loaded as a driver. |
| 4431 | FLT_NOT_INITIALIZED = 0xC01C0007, | 3024 | FLT_NOT_INITIALIZED = 0xC01C0007, |
| 4432 | |||
| 4433 | /// The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called). | 3025 | /// The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called). |
| 4434 | FLT_FILTER_NOT_READY = 0xC01C0008, | 3026 | FLT_FILTER_NOT_READY = 0xC01C0008, |
| 4435 | |||
| 4436 | /// The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers. | 3027 | /// The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers. |
| 4437 | FLT_POST_OPERATION_CLEANUP = 0xC01C0009, | 3028 | FLT_POST_OPERATION_CLEANUP = 0xC01C0009, |
| 4438 | |||
| 4439 | /// The Filter Manager had an internal error from which it cannot recover; therefore, the operation has failed. | 3029 | /// The Filter Manager had an internal error from which it cannot recover; therefore, the operation has failed. |
| 4440 | /// This is usually the result of a filter returning an invalid value from a pre-operation callback. | 3030 | /// This is usually the result of a filter returning an invalid value from a pre-operation callback. |
| 4441 | FLT_INTERNAL_ERROR = 0xC01C000A, | 3031 | FLT_INTERNAL_ERROR = 0xC01C000A, |
| 4442 | |||
| 4443 | /// The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time. | 3032 | /// The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time. |
| 4444 | FLT_DELETING_OBJECT = 0xC01C000B, | 3033 | FLT_DELETING_OBJECT = 0xC01C000B, |
| 4445 | |||
| 4446 | /// A nonpaged pool must be used for this type of context. | 3034 | /// A nonpaged pool must be used for this type of context. |
| 4447 | FLT_MUST_BE_NONPAGED_POOL = 0xC01C000C, | 3035 | FLT_MUST_BE_NONPAGED_POOL = 0xC01C000C, |
| 4448 | |||
| 4449 | /// A duplicate handler definition has been provided for an operation. | 3036 | /// A duplicate handler definition has been provided for an operation. |
| 4450 | FLT_DUPLICATE_ENTRY = 0xC01C000D, | 3037 | FLT_DUPLICATE_ENTRY = 0xC01C000D, |
| 4451 | |||
| 4452 | /// The callback data queue has been disabled. | 3038 | /// The callback data queue has been disabled. |
| 4453 | FLT_CBDQ_DISABLED = 0xC01C000E, | 3039 | FLT_CBDQ_DISABLED = 0xC01C000E, |
| 4454 | |||
| 4455 | /// Do not attach the filter to the volume at this time. | 3040 | /// Do not attach the filter to the volume at this time. |
| 4456 | FLT_DO_NOT_ATTACH = 0xC01C000F, | 3041 | FLT_DO_NOT_ATTACH = 0xC01C000F, |
| 4457 | |||
| 4458 | /// Do not detach the filter from the volume at this time. | 3042 | /// Do not detach the filter from the volume at this time. |
| 4459 | FLT_DO_NOT_DETACH = 0xC01C0010, | 3043 | FLT_DO_NOT_DETACH = 0xC01C0010, |
| 4460 | |||
| 4461 | /// An instance already exists at this altitude on the volume specified. | 3044 | /// An instance already exists at this altitude on the volume specified. |
| 4462 | FLT_INSTANCE_ALTITUDE_COLLISION = 0xC01C0011, | 3045 | FLT_INSTANCE_ALTITUDE_COLLISION = 0xC01C0011, |
| 4463 | |||
| 4464 | /// An instance already exists with this name on the volume specified. | 3046 | /// An instance already exists with this name on the volume specified. |
| 4465 | FLT_INSTANCE_NAME_COLLISION = 0xC01C0012, | 3047 | FLT_INSTANCE_NAME_COLLISION = 0xC01C0012, |
| 4466 | |||
| 4467 | /// The system could not find the filter specified. | 3048 | /// The system could not find the filter specified. |
| 4468 | FLT_FILTER_NOT_FOUND = 0xC01C0013, | 3049 | FLT_FILTER_NOT_FOUND = 0xC01C0013, |
| 4469 | |||
| 4470 | /// The system could not find the volume specified. | 3050 | /// The system could not find the volume specified. |
| 4471 | FLT_VOLUME_NOT_FOUND = 0xC01C0014, | 3051 | FLT_VOLUME_NOT_FOUND = 0xC01C0014, |
| 4472 | |||
| 4473 | /// The system could not find the instance specified. | 3052 | /// The system could not find the instance specified. |
| 4474 | FLT_INSTANCE_NOT_FOUND = 0xC01C0015, | 3053 | FLT_INSTANCE_NOT_FOUND = 0xC01C0015, |
| 4475 | |||
| 4476 | /// No registered context allocation definition was found for the given request. | 3054 | /// No registered context allocation definition was found for the given request. |
| 4477 | FLT_CONTEXT_ALLOCATION_NOT_FOUND = 0xC01C0016, | 3055 | FLT_CONTEXT_ALLOCATION_NOT_FOUND = 0xC01C0016, |
| 4478 | |||
| 4479 | /// An invalid parameter was specified during context registration. | 3056 | /// An invalid parameter was specified during context registration. |
| 4480 | FLT_INVALID_CONTEXT_REGISTRATION = 0xC01C0017, | 3057 | FLT_INVALID_CONTEXT_REGISTRATION = 0xC01C0017, |
| 4481 | |||
| 4482 | /// The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system. | 3058 | /// The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system. |
| 4483 | FLT_NAME_CACHE_MISS = 0xC01C0018, | 3059 | FLT_NAME_CACHE_MISS = 0xC01C0018, |
| 4484 | |||
| 4485 | /// The requested device object does not exist for the given volume. | 3060 | /// The requested device object does not exist for the given volume. |
| 4486 | FLT_NO_DEVICE_OBJECT = 0xC01C0019, | 3061 | FLT_NO_DEVICE_OBJECT = 0xC01C0019, |
| 4487 | |||
| 4488 | /// The specified volume is already mounted. | 3062 | /// The specified volume is already mounted. |
| 4489 | FLT_VOLUME_ALREADY_MOUNTED = 0xC01C001A, | 3063 | FLT_VOLUME_ALREADY_MOUNTED = 0xC01C001A, |
| 4490 | |||
| 4491 | /// The specified transaction context is already enlisted in a transaction. | 3064 | /// The specified transaction context is already enlisted in a transaction. |
| 4492 | FLT_ALREADY_ENLISTED = 0xC01C001B, | 3065 | FLT_ALREADY_ENLISTED = 0xC01C001B, |
| 4493 | |||
| 4494 | /// The specified context is already attached to another object. | 3066 | /// The specified context is already attached to another object. |
| 4495 | FLT_CONTEXT_ALREADY_LINKED = 0xC01C001C, | 3067 | FLT_CONTEXT_ALREADY_LINKED = 0xC01C001C, |
| 4496 | |||
| 4497 | /// No waiter is present for the filter's reply to this message. | 3068 | /// No waiter is present for the filter's reply to this message. |
| 4498 | FLT_NO_WAITER_FOR_REPLY = 0xC01C0020, | 3069 | FLT_NO_WAITER_FOR_REPLY = 0xC01C0020, |
| 4499 | |||
| 4500 | /// A monitor descriptor could not be obtained. | 3070 | /// A monitor descriptor could not be obtained. |
| 4501 | MONITOR_NO_DESCRIPTOR = 0xC01D0001, | 3071 | MONITOR_NO_DESCRIPTOR = 0xC01D0001, |
| 4502 | |||
| 4503 | /// This release does not support the format of the obtained monitor descriptor. | 3072 | /// This release does not support the format of the obtained monitor descriptor. |
| 4504 | MONITOR_UNKNOWN_DESCRIPTOR_FORMAT = 0xC01D0002, | 3073 | MONITOR_UNKNOWN_DESCRIPTOR_FORMAT = 0xC01D0002, |
| 4505 | |||
| 4506 | /// The checksum of the obtained monitor descriptor is invalid. | 3074 | /// The checksum of the obtained monitor descriptor is invalid. |
| 4507 | MONITOR_INVALID_DESCRIPTOR_CHECKSUM = 0xC01D0003, | 3075 | MONITOR_INVALID_DESCRIPTOR_CHECKSUM = 0xC01D0003, |
| 4508 | |||
| 4509 | /// The monitor descriptor contains an invalid standard timing block. | 3076 | /// The monitor descriptor contains an invalid standard timing block. |
| 4510 | MONITOR_INVALID_STANDARD_TIMING_BLOCK = 0xC01D0004, | 3077 | MONITOR_INVALID_STANDARD_TIMING_BLOCK = 0xC01D0004, |
| 4511 | |||
| 4512 | /// WMI data-block registration failed for one of the MSMonitorClass WMI subclasses. | 3078 | /// WMI data-block registration failed for one of the MSMonitorClass WMI subclasses. |
| 4513 | MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED = 0xC01D0005, | 3079 | MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED = 0xC01D0005, |
| 4514 | |||
| 4515 | /// The provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number. | 3080 | /// The provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number. |
| 4516 | MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK = 0xC01D0006, | 3081 | MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK = 0xC01D0006, |
| 4517 | |||
| 4518 | /// The provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name. | 3082 | /// The provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name. |
| 4519 | MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK = 0xC01D0007, | 3083 | MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK = 0xC01D0007, |
| 4520 | |||
| 4521 | /// There is no monitor descriptor data at the specified (offset or size) region. | 3084 | /// There is no monitor descriptor data at the specified (offset or size) region. |
| 4522 | MONITOR_NO_MORE_DESCRIPTOR_DATA = 0xC01D0008, | 3085 | MONITOR_NO_MORE_DESCRIPTOR_DATA = 0xC01D0008, |
| 4523 | |||
| 4524 | /// The monitor descriptor contains an invalid detailed timing block. | 3086 | /// The monitor descriptor contains an invalid detailed timing block. |
| 4525 | MONITOR_INVALID_DETAILED_TIMING_BLOCK = 0xC01D0009, | 3087 | MONITOR_INVALID_DETAILED_TIMING_BLOCK = 0xC01D0009, |
| 4526 | |||
| 4527 | /// Monitor descriptor contains invalid manufacture date. | 3088 | /// Monitor descriptor contains invalid manufacture date. |
| 4528 | MONITOR_INVALID_MANUFACTURE_DATE = 0xC01D000A, | 3089 | MONITOR_INVALID_MANUFACTURE_DATE = 0xC01D000A, |
| 4529 | |||
| 4530 | /// Exclusive mode ownership is needed to create an unmanaged primary allocation. | 3090 | /// Exclusive mode ownership is needed to create an unmanaged primary allocation. |
| 4531 | GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER = 0xC01E0000, | 3091 | GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER = 0xC01E0000, |
| 4532 | |||
| 4533 | /// The driver needs more DMA buffer space to complete the requested operation. | 3092 | /// The driver needs more DMA buffer space to complete the requested operation. |
| 4534 | GRAPHICS_INSUFFICIENT_DMA_BUFFER = 0xC01E0001, | 3093 | GRAPHICS_INSUFFICIENT_DMA_BUFFER = 0xC01E0001, |
| 4535 | |||
| 4536 | /// The specified display adapter handle is invalid. | 3094 | /// The specified display adapter handle is invalid. |
| 4537 | GRAPHICS_INVALID_DISPLAY_ADAPTER = 0xC01E0002, | 3095 | GRAPHICS_INVALID_DISPLAY_ADAPTER = 0xC01E0002, |
| 4538 | |||
| 4539 | /// The specified display adapter and all of its state have been reset. | 3096 | /// The specified display adapter and all of its state have been reset. |
| 4540 | GRAPHICS_ADAPTER_WAS_RESET = 0xC01E0003, | 3097 | GRAPHICS_ADAPTER_WAS_RESET = 0xC01E0003, |
| 4541 | |||
| 4542 | /// The driver stack does not match the expected driver model. | 3098 | /// The driver stack does not match the expected driver model. |
| 4543 | GRAPHICS_INVALID_DRIVER_MODEL = 0xC01E0004, | 3099 | GRAPHICS_INVALID_DRIVER_MODEL = 0xC01E0004, |
| 4544 | |||
| 4545 | /// Present happened but ended up into the changed desktop mode. | 3100 | /// Present happened but ended up into the changed desktop mode. |
| 4546 | GRAPHICS_PRESENT_MODE_CHANGED = 0xC01E0005, | 3101 | GRAPHICS_PRESENT_MODE_CHANGED = 0xC01E0005, |
| 4547 | |||
| 4548 | /// Nothing to present due to desktop occlusion. | 3102 | /// Nothing to present due to desktop occlusion. |
| 4549 | GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006, | 3103 | GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006, |
| 4550 | |||
| 4551 | /// Not able to present due to denial of desktop access. | 3104 | /// Not able to present due to denial of desktop access. |
| 4552 | GRAPHICS_PRESENT_DENIED = 0xC01E0007, | 3105 | GRAPHICS_PRESENT_DENIED = 0xC01E0007, |
| 4553 | |||
| 4554 | /// Not able to present with color conversion. | 3106 | /// Not able to present with color conversion. |
| 4555 | GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008, | 3107 | GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008, |
| 4556 | |||
| 4557 | /// Present redirection is disabled (desktop windowing management subsystem is off). | 3108 | /// Present redirection is disabled (desktop windowing management subsystem is off). |
| 4558 | GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B, | 3109 | GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B, |
| 4559 | |||
| 4560 | /// Previous exclusive VidPn source owner has released its ownership | 3110 | /// Previous exclusive VidPn source owner has released its ownership |
| 4561 | GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C, | 3111 | GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C, |
| 4562 | |||
| 4563 | /// Not enough video memory is available to complete the operation. | 3112 | /// Not enough video memory is available to complete the operation. |
| 4564 | GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100, | 3113 | GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100, |
| 4565 | |||
| 4566 | /// Could not probe and lock the underlying memory of an allocation. | 3114 | /// Could not probe and lock the underlying memory of an allocation. |
| 4567 | GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101, | 3115 | GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101, |
| 4568 | |||
| 4569 | /// The allocation is currently busy. | 3116 | /// The allocation is currently busy. |
| 4570 | GRAPHICS_ALLOCATION_BUSY = 0xC01E0102, | 3117 | GRAPHICS_ALLOCATION_BUSY = 0xC01E0102, |
| 4571 | |||
| 4572 | /// An object being referenced has already reached the maximum reference count and cannot be referenced further. | 3118 | /// An object being referenced has already reached the maximum reference count and cannot be referenced further. |
| 4573 | GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103, | 3119 | GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103, |
| 4574 | |||
| 4575 | /// A problem could not be solved due to an existing condition. Try again later. | 3120 | /// A problem could not be solved due to an existing condition. Try again later. |
| 4576 | GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104, | 3121 | GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104, |
| 4577 | |||
| 4578 | /// A problem could not be solved due to an existing condition. Try again now. | 3122 | /// A problem could not be solved due to an existing condition. Try again now. |
| 4579 | GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105, | 3123 | GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105, |
| 4580 | |||
| 4581 | /// The allocation is invalid. | 3124 | /// The allocation is invalid. |
| 4582 | GRAPHICS_ALLOCATION_INVALID = 0xC01E0106, | 3125 | GRAPHICS_ALLOCATION_INVALID = 0xC01E0106, |
| 4583 | |||
| 4584 | /// No more unswizzling apertures are currently available. | 3126 | /// No more unswizzling apertures are currently available. |
| 4585 | GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107, | 3127 | GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107, |
| 4586 | |||
| 4587 | /// The current allocation cannot be unswizzled by an aperture. | 3128 | /// The current allocation cannot be unswizzled by an aperture. |
| 4588 | GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED = 0xC01E0108, | 3129 | GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED = 0xC01E0108, |
| 4589 | |||
| 4590 | /// The request failed because a pinned allocation cannot be evicted. | 3130 | /// The request failed because a pinned allocation cannot be evicted. |
| 4591 | GRAPHICS_CANT_EVICT_PINNED_ALLOCATION = 0xC01E0109, | 3131 | GRAPHICS_CANT_EVICT_PINNED_ALLOCATION = 0xC01E0109, |
| 4592 | |||
| 4593 | /// The allocation cannot be used from its current segment location for the specified operation. | 3132 | /// The allocation cannot be used from its current segment location for the specified operation. |
| 4594 | GRAPHICS_INVALID_ALLOCATION_USAGE = 0xC01E0110, | 3133 | GRAPHICS_INVALID_ALLOCATION_USAGE = 0xC01E0110, |
| 4595 | |||
| 4596 | /// A locked allocation cannot be used in the current command buffer. | 3134 | /// A locked allocation cannot be used in the current command buffer. |
| 4597 | GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION = 0xC01E0111, | 3135 | GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION = 0xC01E0111, |
| 4598 | |||
| 4599 | /// The allocation being referenced has been closed permanently. | 3136 | /// The allocation being referenced has been closed permanently. |
| 4600 | GRAPHICS_ALLOCATION_CLOSED = 0xC01E0112, | 3137 | GRAPHICS_ALLOCATION_CLOSED = 0xC01E0112, |
| 4601 | |||
| 4602 | /// An invalid allocation instance is being referenced. | 3138 | /// An invalid allocation instance is being referenced. |
| 4603 | GRAPHICS_INVALID_ALLOCATION_INSTANCE = 0xC01E0113, | 3139 | GRAPHICS_INVALID_ALLOCATION_INSTANCE = 0xC01E0113, |
| 4604 | |||
| 4605 | /// An invalid allocation handle is being referenced. | 3140 | /// An invalid allocation handle is being referenced. |
| 4606 | GRAPHICS_INVALID_ALLOCATION_HANDLE = 0xC01E0114, | 3141 | GRAPHICS_INVALID_ALLOCATION_HANDLE = 0xC01E0114, |
| 4607 | |||
| 4608 | /// The allocation being referenced does not belong to the current device. | 3142 | /// The allocation being referenced does not belong to the current device. |
| 4609 | GRAPHICS_WRONG_ALLOCATION_DEVICE = 0xC01E0115, | 3143 | GRAPHICS_WRONG_ALLOCATION_DEVICE = 0xC01E0115, |
| 4610 | |||
| 4611 | /// The specified allocation lost its content. | 3144 | /// The specified allocation lost its content. |
| 4612 | GRAPHICS_ALLOCATION_CONTENT_LOST = 0xC01E0116, | 3145 | GRAPHICS_ALLOCATION_CONTENT_LOST = 0xC01E0116, |
| 4613 | |||
| 4614 | /// A GPU exception was detected on the given device. The device cannot be scheduled. | 3146 | /// A GPU exception was detected on the given device. The device cannot be scheduled. |
| 4615 | GRAPHICS_GPU_EXCEPTION_ON_DEVICE = 0xC01E0200, | 3147 | GRAPHICS_GPU_EXCEPTION_ON_DEVICE = 0xC01E0200, |
| 4616 | |||
| 4617 | /// The specified VidPN topology is invalid. | 3148 | /// The specified VidPN topology is invalid. |
| 4618 | GRAPHICS_INVALID_VIDPN_TOPOLOGY = 0xC01E0300, | 3149 | GRAPHICS_INVALID_VIDPN_TOPOLOGY = 0xC01E0300, |
| 4619 | |||
| 4620 | /// The specified VidPN topology is valid but is not supported by this model of the display adapter. | 3150 | /// The specified VidPN topology is valid but is not supported by this model of the display adapter. |
| 4621 | GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED = 0xC01E0301, | 3151 | GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED = 0xC01E0301, |
| 4622 | |||
| 4623 | /// The specified VidPN topology is valid but is not currently supported by the display adapter due to allocation of its resources. | 3152 | /// The specified VidPN topology is valid but is not currently supported by the display adapter due to allocation of its resources. |
| 4624 | GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED = 0xC01E0302, | 3153 | GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED = 0xC01E0302, |
| 4625 | |||
| 4626 | /// The specified VidPN handle is invalid. | 3154 | /// The specified VidPN handle is invalid. |
| 4627 | GRAPHICS_INVALID_VIDPN = 0xC01E0303, | 3155 | GRAPHICS_INVALID_VIDPN = 0xC01E0303, |
| 4628 | |||
| 4629 | /// The specified video present source is invalid. | 3156 | /// The specified video present source is invalid. |
| 4630 | GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE = 0xC01E0304, | 3157 | GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE = 0xC01E0304, |
| 4631 | |||
| 4632 | /// The specified video present target is invalid. | 3158 | /// The specified video present target is invalid. |
| 4633 | GRAPHICS_INVALID_VIDEO_PRESENT_TARGET = 0xC01E0305, | 3159 | GRAPHICS_INVALID_VIDEO_PRESENT_TARGET = 0xC01E0305, |
| 4634 | |||
| 4635 | /// The specified VidPN modality is not supported (for example, at least two of the pinned modes are not co-functional). | 3160 | /// The specified VidPN modality is not supported (for example, at least two of the pinned modes are not co-functional). |
| 4636 | GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED = 0xC01E0306, | 3161 | GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED = 0xC01E0306, |
| 4637 | |||
| 4638 | /// The specified VidPN source mode set is invalid. | 3162 | /// The specified VidPN source mode set is invalid. |
| 4639 | GRAPHICS_INVALID_VIDPN_SOURCEMODESET = 0xC01E0308, | 3163 | GRAPHICS_INVALID_VIDPN_SOURCEMODESET = 0xC01E0308, |
| 4640 | |||
| 4641 | /// The specified VidPN target mode set is invalid. | 3164 | /// The specified VidPN target mode set is invalid. |
| 4642 | GRAPHICS_INVALID_VIDPN_TARGETMODESET = 0xC01E0309, | 3165 | GRAPHICS_INVALID_VIDPN_TARGETMODESET = 0xC01E0309, |
| 4643 | |||
| 4644 | /// The specified video signal frequency is invalid. | 3166 | /// The specified video signal frequency is invalid. |
| 4645 | GRAPHICS_INVALID_FREQUENCY = 0xC01E030A, | 3167 | GRAPHICS_INVALID_FREQUENCY = 0xC01E030A, |
| 4646 | |||
| 4647 | /// The specified video signal active region is invalid. | 3168 | /// The specified video signal active region is invalid. |
| 4648 | GRAPHICS_INVALID_ACTIVE_REGION = 0xC01E030B, | 3169 | GRAPHICS_INVALID_ACTIVE_REGION = 0xC01E030B, |
| 4649 | |||
| 4650 | /// The specified video signal total region is invalid. | 3170 | /// The specified video signal total region is invalid. |
| 4651 | GRAPHICS_INVALID_TOTAL_REGION = 0xC01E030C, | 3171 | GRAPHICS_INVALID_TOTAL_REGION = 0xC01E030C, |
| 4652 | |||
| 4653 | /// The specified video present source mode is invalid. | 3172 | /// The specified video present source mode is invalid. |
| 4654 | GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE = 0xC01E0310, | 3173 | GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE = 0xC01E0310, |
| 4655 | |||
| 4656 | /// The specified video present target mode is invalid. | 3174 | /// The specified video present target mode is invalid. |
| 4657 | GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE = 0xC01E0311, | 3175 | GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE = 0xC01E0311, |
| 4658 | |||
| 4659 | /// The pinned mode must remain in the set on the VidPN's co-functional modality enumeration. | 3176 | /// The pinned mode must remain in the set on the VidPN's co-functional modality enumeration. |
| 4660 | GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET = 0xC01E0312, | 3177 | GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET = 0xC01E0312, |
| 4661 | |||
| 4662 | /// The specified video present path is already in the VidPN's topology. | 3178 | /// The specified video present path is already in the VidPN's topology. |
| 4663 | GRAPHICS_PATH_ALREADY_IN_TOPOLOGY = 0xC01E0313, | 3179 | GRAPHICS_PATH_ALREADY_IN_TOPOLOGY = 0xC01E0313, |
| 4664 | |||
| 4665 | /// The specified mode is already in the mode set. | 3180 | /// The specified mode is already in the mode set. |
| 4666 | GRAPHICS_MODE_ALREADY_IN_MODESET = 0xC01E0314, | 3181 | GRAPHICS_MODE_ALREADY_IN_MODESET = 0xC01E0314, |
| 4667 | |||
| 4668 | /// The specified video present source set is invalid. | 3182 | /// The specified video present source set is invalid. |
| 4669 | GRAPHICS_INVALID_VIDEOPRESENTSOURCESET = 0xC01E0315, | 3183 | GRAPHICS_INVALID_VIDEOPRESENTSOURCESET = 0xC01E0315, |
| 4670 | |||
| 4671 | /// The specified video present target set is invalid. | 3184 | /// The specified video present target set is invalid. |
| 4672 | GRAPHICS_INVALID_VIDEOPRESENTTARGETSET = 0xC01E0316, | 3185 | GRAPHICS_INVALID_VIDEOPRESENTTARGETSET = 0xC01E0316, |
| 4673 | |||
| 4674 | /// The specified video present source is already in the video present source set. | 3186 | /// The specified video present source is already in the video present source set. |
| 4675 | GRAPHICS_SOURCE_ALREADY_IN_SET = 0xC01E0317, | 3187 | GRAPHICS_SOURCE_ALREADY_IN_SET = 0xC01E0317, |
| 4676 | |||
| 4677 | /// The specified video present target is already in the video present target set. | 3188 | /// The specified video present target is already in the video present target set. |
| 4678 | GRAPHICS_TARGET_ALREADY_IN_SET = 0xC01E0318, | 3189 | GRAPHICS_TARGET_ALREADY_IN_SET = 0xC01E0318, |
| 4679 | |||
| 4680 | /// The specified VidPN present path is invalid. | 3190 | /// The specified VidPN present path is invalid. |
| 4681 | GRAPHICS_INVALID_VIDPN_PRESENT_PATH = 0xC01E0319, | 3191 | GRAPHICS_INVALID_VIDPN_PRESENT_PATH = 0xC01E0319, |
| 4682 | |||
| 4683 | /// The miniport has no recommendation for augmenting the specified VidPN's topology. | 3192 | /// The miniport has no recommendation for augmenting the specified VidPN's topology. |
| 4684 | GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY = 0xC01E031A, | 3193 | GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY = 0xC01E031A, |
| 4685 | |||
| 4686 | /// The specified monitor frequency range set is invalid. | 3194 | /// The specified monitor frequency range set is invalid. |
| 4687 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET = 0xC01E031B, | 3195 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET = 0xC01E031B, |
| 4688 | |||
| 4689 | /// The specified monitor frequency range is invalid. | 3196 | /// The specified monitor frequency range is invalid. |
| 4690 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE = 0xC01E031C, | 3197 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE = 0xC01E031C, |
| 4691 | |||
| 4692 | /// The specified frequency range is not in the specified monitor frequency range set. | 3198 | /// The specified frequency range is not in the specified monitor frequency range set. |
| 4693 | GRAPHICS_FREQUENCYRANGE_NOT_IN_SET = 0xC01E031D, | 3199 | GRAPHICS_FREQUENCYRANGE_NOT_IN_SET = 0xC01E031D, |
| 4694 | |||
| 4695 | /// The specified frequency range is already in the specified monitor frequency range set. | 3200 | /// The specified frequency range is already in the specified monitor frequency range set. |
| 4696 | GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET = 0xC01E031F, | 3201 | GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET = 0xC01E031F, |
| 4697 | |||
| 4698 | /// The specified mode set is stale. Reacquire the new mode set. | 3202 | /// The specified mode set is stale. Reacquire the new mode set. |
| 4699 | GRAPHICS_STALE_MODESET = 0xC01E0320, | 3203 | GRAPHICS_STALE_MODESET = 0xC01E0320, |
| 4700 | |||
| 4701 | /// The specified monitor source mode set is invalid. | 3204 | /// The specified monitor source mode set is invalid. |
| 4702 | GRAPHICS_INVALID_MONITOR_SOURCEMODESET = 0xC01E0321, | 3205 | GRAPHICS_INVALID_MONITOR_SOURCEMODESET = 0xC01E0321, |
| 4703 | |||
| 4704 | /// The specified monitor source mode is invalid. | 3206 | /// The specified monitor source mode is invalid. |
| 4705 | GRAPHICS_INVALID_MONITOR_SOURCE_MODE = 0xC01E0322, | 3207 | GRAPHICS_INVALID_MONITOR_SOURCE_MODE = 0xC01E0322, |
| 4706 | |||
| 4707 | /// The miniport does not have a recommendation regarding the request to provide a functional VidPN given the current display adapter configuration. | 3208 | /// The miniport does not have a recommendation regarding the request to provide a functional VidPN given the current display adapter configuration. |
| 4708 | GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN = 0xC01E0323, | 3209 | GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN = 0xC01E0323, |
| 4709 | |||
| 4710 | /// The ID of the specified mode is being used by another mode in the set. | 3210 | /// The ID of the specified mode is being used by another mode in the set. |
| 4711 | GRAPHICS_MODE_ID_MUST_BE_UNIQUE = 0xC01E0324, | 3211 | GRAPHICS_MODE_ID_MUST_BE_UNIQUE = 0xC01E0324, |
| 4712 | |||
| 4713 | /// The system failed to determine a mode that is supported by both the display adapter and the monitor connected to it. | 3212 | /// The system failed to determine a mode that is supported by both the display adapter and the monitor connected to it. |
| 4714 | GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION = 0xC01E0325, | 3213 | GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION = 0xC01E0325, |
| 4715 | |||
| 4716 | /// The number of video present targets must be greater than or equal to the number of video present sources. | 3214 | /// The number of video present targets must be greater than or equal to the number of video present sources. |
| 4717 | GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES = 0xC01E0326, | 3215 | GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES = 0xC01E0326, |
| 4718 | |||
| 4719 | /// The specified present path is not in the VidPN's topology. | 3216 | /// The specified present path is not in the VidPN's topology. |
| 4720 | GRAPHICS_PATH_NOT_IN_TOPOLOGY = 0xC01E0327, | 3217 | GRAPHICS_PATH_NOT_IN_TOPOLOGY = 0xC01E0327, |
| 4721 | |||
| 4722 | /// The display adapter must have at least one video present source. | 3218 | /// The display adapter must have at least one video present source. |
| 4723 | GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE = 0xC01E0328, | 3219 | GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE = 0xC01E0328, |
| 4724 | |||
| 4725 | /// The display adapter must have at least one video present target. | 3220 | /// The display adapter must have at least one video present target. |
| 4726 | GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET = 0xC01E0329, | 3221 | GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET = 0xC01E0329, |
| 4727 | |||
| 4728 | /// The specified monitor descriptor set is invalid. | 3222 | /// The specified monitor descriptor set is invalid. |
| 4729 | GRAPHICS_INVALID_MONITORDESCRIPTORSET = 0xC01E032A, | 3223 | GRAPHICS_INVALID_MONITORDESCRIPTORSET = 0xC01E032A, |
| 4730 | |||
| 4731 | /// The specified monitor descriptor is invalid. | 3224 | /// The specified monitor descriptor is invalid. |
| 4732 | GRAPHICS_INVALID_MONITORDESCRIPTOR = 0xC01E032B, | 3225 | GRAPHICS_INVALID_MONITORDESCRIPTOR = 0xC01E032B, |
| 4733 | |||
| 4734 | /// The specified descriptor is not in the specified monitor descriptor set. | 3226 | /// The specified descriptor is not in the specified monitor descriptor set. |
| 4735 | GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET = 0xC01E032C, | 3227 | GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET = 0xC01E032C, |
| 4736 | |||
| 4737 | /// The specified descriptor is already in the specified monitor descriptor set. | 3228 | /// The specified descriptor is already in the specified monitor descriptor set. |
| 4738 | GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET = 0xC01E032D, | 3229 | GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET = 0xC01E032D, |
| 4739 | |||
| 4740 | /// The ID of the specified monitor descriptor is being used by another descriptor in the set. | 3230 | /// The ID of the specified monitor descriptor is being used by another descriptor in the set. |
| 4741 | GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE = 0xC01E032E, | 3231 | GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE = 0xC01E032E, |
| 4742 | |||
| 4743 | /// The specified video present target subset type is invalid. | 3232 | /// The specified video present target subset type is invalid. |
| 4744 | GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE = 0xC01E032F, | 3233 | GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE = 0xC01E032F, |
| 4745 | |||
| 4746 | /// Two or more of the specified resources are not related to each other, as defined by the interface semantics. | 3234 | /// Two or more of the specified resources are not related to each other, as defined by the interface semantics. |
| 4747 | GRAPHICS_RESOURCES_NOT_RELATED = 0xC01E0330, | 3235 | GRAPHICS_RESOURCES_NOT_RELATED = 0xC01E0330, |
| 4748 | |||
| 4749 | /// The ID of the specified video present source is being used by another source in the set. | 3236 | /// The ID of the specified video present source is being used by another source in the set. |
| 4750 | GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE = 0xC01E0331, | 3237 | GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE = 0xC01E0331, |
| 4751 | |||
| 4752 | /// The ID of the specified video present target is being used by another target in the set. | 3238 | /// The ID of the specified video present target is being used by another target in the set. |
| 4753 | GRAPHICS_TARGET_ID_MUST_BE_UNIQUE = 0xC01E0332, | 3239 | GRAPHICS_TARGET_ID_MUST_BE_UNIQUE = 0xC01E0332, |
| 4754 | |||
| 4755 | /// The specified VidPN source cannot be used because there is no available VidPN target to connect it to. | 3240 | /// The specified VidPN source cannot be used because there is no available VidPN target to connect it to. |
| 4756 | GRAPHICS_NO_AVAILABLE_VIDPN_TARGET = 0xC01E0333, | 3241 | GRAPHICS_NO_AVAILABLE_VIDPN_TARGET = 0xC01E0333, |
| 4757 | |||
| 4758 | /// The newly arrived monitor could not be associated with a display adapter. | 3242 | /// The newly arrived monitor could not be associated with a display adapter. |
| 4759 | GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER = 0xC01E0334, | 3243 | GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER = 0xC01E0334, |
| 4760 | |||
| 4761 | /// The particular display adapter does not have an associated VidPN manager. | 3244 | /// The particular display adapter does not have an associated VidPN manager. |
| 4762 | GRAPHICS_NO_VIDPNMGR = 0xC01E0335, | 3245 | GRAPHICS_NO_VIDPNMGR = 0xC01E0335, |
| 4763 | |||
| 4764 | /// The VidPN manager of the particular display adapter does not have an active VidPN. | 3246 | /// The VidPN manager of the particular display adapter does not have an active VidPN. |
| 4765 | GRAPHICS_NO_ACTIVE_VIDPN = 0xC01E0336, | 3247 | GRAPHICS_NO_ACTIVE_VIDPN = 0xC01E0336, |
| 4766 | |||
| 4767 | /// The specified VidPN topology is stale; obtain the new topology. | 3248 | /// The specified VidPN topology is stale; obtain the new topology. |
| 4768 | GRAPHICS_STALE_VIDPN_TOPOLOGY = 0xC01E0337, | 3249 | GRAPHICS_STALE_VIDPN_TOPOLOGY = 0xC01E0337, |
| 4769 | |||
| 4770 | /// No monitor is connected on the specified video present target. | 3250 | /// No monitor is connected on the specified video present target. |
| 4771 | GRAPHICS_MONITOR_NOT_CONNECTED = 0xC01E0338, | 3251 | GRAPHICS_MONITOR_NOT_CONNECTED = 0xC01E0338, |
| 4772 | |||
| 4773 | /// The specified source is not part of the specified VidPN's topology. | 3252 | /// The specified source is not part of the specified VidPN's topology. |
| 4774 | GRAPHICS_SOURCE_NOT_IN_TOPOLOGY = 0xC01E0339, | 3253 | GRAPHICS_SOURCE_NOT_IN_TOPOLOGY = 0xC01E0339, |
| 4775 | |||
| 4776 | /// The specified primary surface size is invalid. | 3254 | /// The specified primary surface size is invalid. |
| 4777 | GRAPHICS_INVALID_PRIMARYSURFACE_SIZE = 0xC01E033A, | 3255 | GRAPHICS_INVALID_PRIMARYSURFACE_SIZE = 0xC01E033A, |
| 4778 | |||
| 4779 | /// The specified visible region size is invalid. | 3256 | /// The specified visible region size is invalid. |
| 4780 | GRAPHICS_INVALID_VISIBLEREGION_SIZE = 0xC01E033B, | 3257 | GRAPHICS_INVALID_VISIBLEREGION_SIZE = 0xC01E033B, |
| 4781 | |||
| 4782 | /// The specified stride is invalid. | 3258 | /// The specified stride is invalid. |
| 4783 | GRAPHICS_INVALID_STRIDE = 0xC01E033C, | 3259 | GRAPHICS_INVALID_STRIDE = 0xC01E033C, |
| 4784 | |||
| 4785 | /// The specified pixel format is invalid. | 3260 | /// The specified pixel format is invalid. |
| 4786 | GRAPHICS_INVALID_PIXELFORMAT = 0xC01E033D, | 3261 | GRAPHICS_INVALID_PIXELFORMAT = 0xC01E033D, |
| 4787 | |||
| 4788 | /// The specified color basis is invalid. | 3262 | /// The specified color basis is invalid. |
| 4789 | GRAPHICS_INVALID_COLORBASIS = 0xC01E033E, | 3263 | GRAPHICS_INVALID_COLORBASIS = 0xC01E033E, |
| 4790 | |||
| 4791 | /// The specified pixel value access mode is invalid. | 3264 | /// The specified pixel value access mode is invalid. |
| 4792 | GRAPHICS_INVALID_PIXELVALUEACCESSMODE = 0xC01E033F, | 3265 | GRAPHICS_INVALID_PIXELVALUEACCESSMODE = 0xC01E033F, |
| 4793 | |||
| 4794 | /// The specified target is not part of the specified VidPN's topology. | 3266 | /// The specified target is not part of the specified VidPN's topology. |
| 4795 | GRAPHICS_TARGET_NOT_IN_TOPOLOGY = 0xC01E0340, | 3267 | GRAPHICS_TARGET_NOT_IN_TOPOLOGY = 0xC01E0340, |
| 4796 | |||
| 4797 | /// Failed to acquire the display mode management interface. | 3268 | /// Failed to acquire the display mode management interface. |
| 4798 | GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT = 0xC01E0341, | 3269 | GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT = 0xC01E0341, |
| 4799 | |||
| 4800 | /// The specified VidPN source is already owned by a DMM client and cannot be used until that client releases it. | 3270 | /// The specified VidPN source is already owned by a DMM client and cannot be used until that client releases it. |
| 4801 | GRAPHICS_VIDPN_SOURCE_IN_USE = 0xC01E0342, | 3271 | GRAPHICS_VIDPN_SOURCE_IN_USE = 0xC01E0342, |
| 4802 | |||
| 4803 | /// The specified VidPN is active and cannot be accessed. | 3272 | /// The specified VidPN is active and cannot be accessed. |
| 4804 | GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN = 0xC01E0343, | 3273 | GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN = 0xC01E0343, |
| 4805 | |||
| 4806 | /// The specified VidPN's present path importance ordinal is invalid. | 3274 | /// The specified VidPN's present path importance ordinal is invalid. |
| 4807 | GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL = 0xC01E0344, | 3275 | GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL = 0xC01E0344, |
| 4808 | |||
| 4809 | /// The specified VidPN's present path content geometry transformation is invalid. | 3276 | /// The specified VidPN's present path content geometry transformation is invalid. |
| 4810 | GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION = 0xC01E0345, | 3277 | GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION = 0xC01E0345, |
| 4811 | |||
| 4812 | /// The specified content geometry transformation is not supported on the respective VidPN present path. | 3278 | /// The specified content geometry transformation is not supported on the respective VidPN present path. |
| 4813 | GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED = 0xC01E0346, | 3279 | GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED = 0xC01E0346, |
| 4814 | |||
| 4815 | /// The specified gamma ramp is invalid. | 3280 | /// The specified gamma ramp is invalid. |
| 4816 | GRAPHICS_INVALID_GAMMA_RAMP = 0xC01E0347, | 3281 | GRAPHICS_INVALID_GAMMA_RAMP = 0xC01E0347, |
| 4817 | |||
| 4818 | /// The specified gamma ramp is not supported on the respective VidPN present path. | 3282 | /// The specified gamma ramp is not supported on the respective VidPN present path. |
| 4819 | GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED = 0xC01E0348, | 3283 | GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED = 0xC01E0348, |
| 4820 | |||
| 4821 | /// Multisampling is not supported on the respective VidPN present path. | 3284 | /// Multisampling is not supported on the respective VidPN present path. |
| 4822 | GRAPHICS_MULTISAMPLING_NOT_SUPPORTED = 0xC01E0349, | 3285 | GRAPHICS_MULTISAMPLING_NOT_SUPPORTED = 0xC01E0349, |
| 4823 | |||
| 4824 | /// The specified mode is not in the specified mode set. | 3286 | /// The specified mode is not in the specified mode set. |
| 4825 | GRAPHICS_MODE_NOT_IN_MODESET = 0xC01E034A, | 3287 | GRAPHICS_MODE_NOT_IN_MODESET = 0xC01E034A, |
| 4826 | |||
| 4827 | /// The specified VidPN topology recommendation reason is invalid. | 3288 | /// The specified VidPN topology recommendation reason is invalid. |
| 4828 | GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON = 0xC01E034D, | 3289 | GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON = 0xC01E034D, |
| 4829 | |||
| 4830 | /// The specified VidPN present path content type is invalid. | 3290 | /// The specified VidPN present path content type is invalid. |
| 4831 | GRAPHICS_INVALID_PATH_CONTENT_TYPE = 0xC01E034E, | 3291 | GRAPHICS_INVALID_PATH_CONTENT_TYPE = 0xC01E034E, |
| 4832 | |||
| 4833 | /// The specified VidPN present path copy protection type is invalid. | 3292 | /// The specified VidPN present path copy protection type is invalid. |
| 4834 | GRAPHICS_INVALID_COPYPROTECTION_TYPE = 0xC01E034F, | 3293 | GRAPHICS_INVALID_COPYPROTECTION_TYPE = 0xC01E034F, |
| 4835 | |||
| 4836 | /// Only one unassigned mode set can exist at any one time for a particular VidPN source or target. | 3294 | /// Only one unassigned mode set can exist at any one time for a particular VidPN source or target. |
| 4837 | GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS = 0xC01E0350, | 3295 | GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS = 0xC01E0350, |
| 4838 | |||
| 4839 | /// The specified scan line ordering type is invalid. | 3296 | /// The specified scan line ordering type is invalid. |
| 4840 | GRAPHICS_INVALID_SCANLINE_ORDERING = 0xC01E0352, | 3297 | GRAPHICS_INVALID_SCANLINE_ORDERING = 0xC01E0352, |
| 4841 | |||
| 4842 | /// The topology changes are not allowed for the specified VidPN. | 3298 | /// The topology changes are not allowed for the specified VidPN. |
| 4843 | GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED = 0xC01E0353, | 3299 | GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED = 0xC01E0353, |
| 4844 | |||
| 4845 | /// All available importance ordinals are being used in the specified topology. | 3300 | /// All available importance ordinals are being used in the specified topology. |
| 4846 | GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS = 0xC01E0354, | 3301 | GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS = 0xC01E0354, |
| 4847 | |||
| 4848 | /// The specified primary surface has a different private-format attribute than the current primary surface. | 3302 | /// The specified primary surface has a different private-format attribute than the current primary surface. |
| 4849 | GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT = 0xC01E0355, | 3303 | GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT = 0xC01E0355, |
| 4850 | |||
| 4851 | /// The specified mode-pruning algorithm is invalid. | 3304 | /// The specified mode-pruning algorithm is invalid. |
| 4852 | GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM = 0xC01E0356, | 3305 | GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM = 0xC01E0356, |
| 4853 | |||
| 4854 | /// The specified monitor-capability origin is invalid. | 3306 | /// The specified monitor-capability origin is invalid. |
| 4855 | GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN = 0xC01E0357, | 3307 | GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN = 0xC01E0357, |
| 4856 | |||
| 4857 | /// The specified monitor-frequency range constraint is invalid. | 3308 | /// The specified monitor-frequency range constraint is invalid. |
| 4858 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT = 0xC01E0358, | 3309 | GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT = 0xC01E0358, |
| 4859 | |||
| 4860 | /// The maximum supported number of present paths has been reached. | 3310 | /// The maximum supported number of present paths has been reached. |
| 4861 | GRAPHICS_MAX_NUM_PATHS_REACHED = 0xC01E0359, | 3311 | GRAPHICS_MAX_NUM_PATHS_REACHED = 0xC01E0359, |
| 4862 | |||
| 4863 | /// The miniport requested that augmentation be canceled for the specified source of the specified VidPN's topology. | 3312 | /// The miniport requested that augmentation be canceled for the specified source of the specified VidPN's topology. |
| 4864 | GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION = 0xC01E035A, | 3313 | GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION = 0xC01E035A, |
| 4865 | |||
| 4866 | /// The specified client type was not recognized. | 3314 | /// The specified client type was not recognized. |
| 4867 | GRAPHICS_INVALID_CLIENT_TYPE = 0xC01E035B, | 3315 | GRAPHICS_INVALID_CLIENT_TYPE = 0xC01E035B, |
| 4868 | |||
| 4869 | /// The client VidPN is not set on this adapter (for example, no user mode-initiated mode changes have taken place on this adapter). | 3316 | /// The client VidPN is not set on this adapter (for example, no user mode-initiated mode changes have taken place on this adapter). |
| 4870 | GRAPHICS_CLIENTVIDPN_NOT_SET = 0xC01E035C, | 3317 | GRAPHICS_CLIENTVIDPN_NOT_SET = 0xC01E035C, |
| 4871 | |||
| 4872 | /// The specified display adapter child device already has an external device connected to it. | 3318 | /// The specified display adapter child device already has an external device connected to it. |
| 4873 | GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED = 0xC01E0400, | 3319 | GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED = 0xC01E0400, |
| 4874 | |||
| 4875 | /// The display adapter child device does not support reporting a descriptor. | 3320 | /// The display adapter child device does not support reporting a descriptor. |
| 4876 | GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED = 0xC01E0401, | 3321 | GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED = 0xC01E0401, |
| 4877 | |||
| 4878 | /// The display adapter is not linked to any other adapters. | 3322 | /// The display adapter is not linked to any other adapters. |
| 4879 | GRAPHICS_NOT_A_LINKED_ADAPTER = 0xC01E0430, | 3323 | GRAPHICS_NOT_A_LINKED_ADAPTER = 0xC01E0430, |
| 4880 | |||
| 4881 | /// The lead adapter in a linked configuration was not enumerated yet. | 3324 | /// The lead adapter in a linked configuration was not enumerated yet. |
| 4882 | GRAPHICS_LEADLINK_NOT_ENUMERATED = 0xC01E0431, | 3325 | GRAPHICS_LEADLINK_NOT_ENUMERATED = 0xC01E0431, |
| 4883 | |||
| 4884 | /// Some chain adapters in a linked configuration have not yet been enumerated. | 3326 | /// Some chain adapters in a linked configuration have not yet been enumerated. |
| 4885 | GRAPHICS_CHAINLINKS_NOT_ENUMERATED = 0xC01E0432, | 3327 | GRAPHICS_CHAINLINKS_NOT_ENUMERATED = 0xC01E0432, |
| 4886 | |||
| 4887 | /// The chain of linked adapters is not ready to start because of an unknown failure. | 3328 | /// The chain of linked adapters is not ready to start because of an unknown failure. |
| 4888 | GRAPHICS_ADAPTER_CHAIN_NOT_READY = 0xC01E0433, | 3329 | GRAPHICS_ADAPTER_CHAIN_NOT_READY = 0xC01E0433, |
| 4889 | |||
| 4890 | /// An attempt was made to start a lead link display adapter when the chain links had not yet started. | 3330 | /// An attempt was made to start a lead link display adapter when the chain links had not yet started. |
| 4891 | GRAPHICS_CHAINLINKS_NOT_STARTED = 0xC01E0434, | 3331 | GRAPHICS_CHAINLINKS_NOT_STARTED = 0xC01E0434, |
| 4892 | |||
| 4893 | /// An attempt was made to turn on a lead link display adapter when the chain links were turned off. | 3332 | /// An attempt was made to turn on a lead link display adapter when the chain links were turned off. |
| 4894 | GRAPHICS_CHAINLINKS_NOT_POWERED_ON = 0xC01E0435, | 3333 | GRAPHICS_CHAINLINKS_NOT_POWERED_ON = 0xC01E0435, |
| 4895 | |||
| 4896 | /// The adapter link was found in an inconsistent state. | 3334 | /// The adapter link was found in an inconsistent state. |
| 4897 | /// Not all adapters are in an expected PNP/power state. | 3335 | /// Not all adapters are in an expected PNP/power state. |
| 4898 | GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE = 0xC01E0436, | 3336 | GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE = 0xC01E0436, |
| 4899 | |||
| 4900 | /// The driver trying to start is not the same as the driver for the posted display adapter. | 3337 | /// The driver trying to start is not the same as the driver for the posted display adapter. |
| 4901 | GRAPHICS_NOT_POST_DEVICE_DRIVER = 0xC01E0438, | 3338 | GRAPHICS_NOT_POST_DEVICE_DRIVER = 0xC01E0438, |
| 4902 | |||
| 4903 | /// An operation is being attempted that requires the display adapter to be in a quiescent state. | 3339 | /// An operation is being attempted that requires the display adapter to be in a quiescent state. |
| 4904 | GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED = 0xC01E043B, | 3340 | GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED = 0xC01E043B, |
| 4905 | |||
| 4906 | /// The driver does not support OPM. | 3341 | /// The driver does not support OPM. |
| 4907 | GRAPHICS_OPM_NOT_SUPPORTED = 0xC01E0500, | 3342 | GRAPHICS_OPM_NOT_SUPPORTED = 0xC01E0500, |
| 4908 | |||
| 4909 | /// The driver does not support COPP. | 3343 | /// The driver does not support COPP. |
| 4910 | GRAPHICS_COPP_NOT_SUPPORTED = 0xC01E0501, | 3344 | GRAPHICS_COPP_NOT_SUPPORTED = 0xC01E0501, |
| 4911 | |||
| 4912 | /// The driver does not support UAB. | 3345 | /// The driver does not support UAB. |
| 4913 | GRAPHICS_UAB_NOT_SUPPORTED = 0xC01E0502, | 3346 | GRAPHICS_UAB_NOT_SUPPORTED = 0xC01E0502, |
| 4914 | |||
| 4915 | /// The specified encrypted parameters are invalid. | 3347 | /// The specified encrypted parameters are invalid. |
| 4916 | GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS = 0xC01E0503, | 3348 | GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS = 0xC01E0503, |
| 4917 | |||
| 4918 | /// An array passed to a function cannot hold all of the data that the function wants to put in it. | 3349 | /// An array passed to a function cannot hold all of the data that the function wants to put in it. |
| 4919 | GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL = 0xC01E0504, | 3350 | GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL = 0xC01E0504, |
| 4920 | |||
| 4921 | /// The GDI display device passed to this function does not have any active protected outputs. | 3351 | /// The GDI display device passed to this function does not have any active protected outputs. |
| 4922 | GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST = 0xC01E0505, | 3352 | GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST = 0xC01E0505, |
| 4923 | |||
| 4924 | /// The PVP cannot find an actual GDI display device that corresponds to the passed-in GDI display device name. | 3353 | /// The PVP cannot find an actual GDI display device that corresponds to the passed-in GDI display device name. |
| 4925 | GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E0506, | 3354 | GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E0506, |
| 4926 | |||
| 4927 | /// This function failed because the GDI display device passed to it was not attached to the Windows desktop. | 3355 | /// This function failed because the GDI display device passed to it was not attached to the Windows desktop. |
| 4928 | GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E0507, | 3356 | GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E0507, |
| 4929 | |||
| 4930 | /// The PVP does not support mirroring display devices because they do not have any protected outputs. | 3357 | /// The PVP does not support mirroring display devices because they do not have any protected outputs. |
| 4931 | GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E0508, | 3358 | GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E0508, |
| 4932 | |||
| 4933 | /// The function failed because an invalid pointer parameter was passed to it. | 3359 | /// The function failed because an invalid pointer parameter was passed to it. |
| 4934 | /// A pointer parameter is invalid if it is null, is not correctly aligned, or it points to an invalid address or a kernel mode address. | 3360 | /// A pointer parameter is invalid if it is null, is not correctly aligned, or it points to an invalid address or a kernel mode address. |
| 4935 | GRAPHICS_OPM_INVALID_POINTER = 0xC01E050A, | 3361 | GRAPHICS_OPM_INVALID_POINTER = 0xC01E050A, |
| 4936 | |||
| 4937 | /// An internal error caused an operation to fail. | 3362 | /// An internal error caused an operation to fail. |
| 4938 | GRAPHICS_OPM_INTERNAL_ERROR = 0xC01E050B, | 3363 | GRAPHICS_OPM_INTERNAL_ERROR = 0xC01E050B, |
| 4939 | |||
| 4940 | /// The function failed because the caller passed in an invalid OPM user-mode handle. | 3364 | /// The function failed because the caller passed in an invalid OPM user-mode handle. |
| 4941 | GRAPHICS_OPM_INVALID_HANDLE = 0xC01E050C, | 3365 | GRAPHICS_OPM_INVALID_HANDLE = 0xC01E050C, |
| 4942 | |||
| 4943 | /// This function failed because the GDI device passed to it did not have any monitors associated with it. | 3366 | /// This function failed because the GDI device passed to it did not have any monitors associated with it. |
| 4944 | GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E050D, | 3367 | GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E050D, |
| 4945 | |||
| 4946 | /// A certificate could not be returned because the certificate buffer passed to the function was too small. | 3368 | /// A certificate could not be returned because the certificate buffer passed to the function was too small. |
| 4947 | GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH = 0xC01E050E, | 3369 | GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH = 0xC01E050E, |
| 4948 | |||
| 4949 | /// DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present yarget is in spanning mode. | 3370 | /// DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present yarget is in spanning mode. |
| 4950 | GRAPHICS_OPM_SPANNING_MODE_ENABLED = 0xC01E050F, | 3371 | GRAPHICS_OPM_SPANNING_MODE_ENABLED = 0xC01E050F, |
| 4951 | |||
| 4952 | /// DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present target is in theater mode. | 3372 | /// DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present target is in theater mode. |
| 4953 | GRAPHICS_OPM_THEATER_MODE_ENABLED = 0xC01E0510, | 3373 | GRAPHICS_OPM_THEATER_MODE_ENABLED = 0xC01E0510, |
| 4954 | |||
| 4955 | /// The function call failed because the display adapter's hardware functionality scan (HFS) failed to validate the graphics hardware. | 3374 | /// The function call failed because the display adapter's hardware functionality scan (HFS) failed to validate the graphics hardware. |
| 4956 | GRAPHICS_PVP_HFS_FAILED = 0xC01E0511, | 3375 | GRAPHICS_PVP_HFS_FAILED = 0xC01E0511, |
| 4957 | |||
| 4958 | /// The HDCP SRM passed to this function did not comply with section 5 of the HDCP 1.1 specification. | 3376 | /// The HDCP SRM passed to this function did not comply with section 5 of the HDCP 1.1 specification. |
| 4959 | GRAPHICS_OPM_INVALID_SRM = 0xC01E0512, | 3377 | GRAPHICS_OPM_INVALID_SRM = 0xC01E0512, |
| 4960 | |||
| 4961 | /// The protected output cannot enable the HDCP system because it does not support it. | 3378 | /// The protected output cannot enable the HDCP system because it does not support it. |
| 4962 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP = 0xC01E0513, | 3379 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP = 0xC01E0513, |
| 4963 | |||
| 4964 | /// The protected output cannot enable analog copy protection because it does not support it. | 3380 | /// The protected output cannot enable analog copy protection because it does not support it. |
| 4965 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP = 0xC01E0514, | 3381 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP = 0xC01E0514, |
| 4966 | |||
| 4967 | /// The protected output cannot enable the CGMS-A protection technology because it does not support it. | 3382 | /// The protected output cannot enable the CGMS-A protection technology because it does not support it. |
| 4968 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA = 0xC01E0515, | 3383 | GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA = 0xC01E0515, |
| 4969 | |||
| 4970 | /// DxgkDdiOPMGetInformation() cannot return the version of the SRM being used because the application never successfully passed an SRM to the protected output. | 3384 | /// DxgkDdiOPMGetInformation() cannot return the version of the SRM being used because the application never successfully passed an SRM to the protected output. |
| 4971 | GRAPHICS_OPM_HDCP_SRM_NEVER_SET = 0xC01E0516, | 3385 | GRAPHICS_OPM_HDCP_SRM_NEVER_SET = 0xC01E0516, |
| 4972 | |||
| 4973 | /// DxgkDdiOPMConfigureProtectedOutput() cannot enable the specified output protection technology because the output's screen resolution is too high. | 3386 | /// DxgkDdiOPMConfigureProtectedOutput() cannot enable the specified output protection technology because the output's screen resolution is too high. |
| 4974 | GRAPHICS_OPM_RESOLUTION_TOO_HIGH = 0xC01E0517, | 3387 | GRAPHICS_OPM_RESOLUTION_TOO_HIGH = 0xC01E0517, |
| 4975 | |||
| 4976 | /// DxgkDdiOPMConfigureProtectedOutput() cannot enable HDCP because other physical outputs are using the display adapter's HDCP hardware. | 3388 | /// DxgkDdiOPMConfigureProtectedOutput() cannot enable HDCP because other physical outputs are using the display adapter's HDCP hardware. |
| 4977 | GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE = 0xC01E0518, | 3389 | GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE = 0xC01E0518, |
| 4978 | |||
| 4979 | /// The operating system asynchronously destroyed this OPM-protected output because the operating system state changed. | 3390 | /// The operating system asynchronously destroyed this OPM-protected output because the operating system state changed. |
| 4980 | /// This error typically occurs because the monitor PDO associated with this protected output was removed or stopped, the protected output's session became a nonconsole session, or the protected output's desktop became inactive. | 3391 | /// This error typically occurs because the monitor PDO associated with this protected output was removed or stopped, the protected output's session became a nonconsole session, or the protected output's desktop became inactive. |
| 4981 | GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS = 0xC01E051A, | 3392 | GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS = 0xC01E051A, |
| 4982 | |||
| 4983 | /// OPM functions cannot be called when a session is changing its type. | 3393 | /// OPM functions cannot be called when a session is changing its type. |
| 4984 | /// Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA). | 3394 | /// Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA). |
| 4985 | GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E051B, | 3395 | GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E051B, |
| 4986 | |||
| 4987 | /// The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. | 3396 | /// The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. |
| 4988 | /// This error is returned only if a protected output has OPM semantics. | 3397 | /// This error is returned only if a protected output has OPM semantics. |
| 4989 | /// DxgkDdiOPMGetCOPPCompatibleInformation always returns this error if a protected output has OPM semantics. | 3398 | /// DxgkDdiOPMGetCOPPCompatibleInformation always returns this error if a protected output has OPM semantics. |
| 4990 | /// DxgkDdiOPMGetInformation returns this error code if the caller requested COPP-specific information. | 3399 | /// DxgkDdiOPMGetInformation returns this error code if the caller requested COPP-specific information. |
| 4991 | /// DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use a COPP-specific command. | 3400 | /// DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use a COPP-specific command. |
| 4992 | GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS = 0xC01E051C, | 3401 | GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS = 0xC01E051C, |
| 4993 | |||
| 4994 | /// The DxgkDdiOPMGetInformation and DxgkDdiOPMGetCOPPCompatibleInformation functions return this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid. | 3402 | /// The DxgkDdiOPMGetInformation and DxgkDdiOPMGetCOPPCompatibleInformation functions return this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid. |
| 4995 | GRAPHICS_OPM_INVALID_INFORMATION_REQUEST = 0xC01E051D, | 3403 | GRAPHICS_OPM_INVALID_INFORMATION_REQUEST = 0xC01E051D, |
| 4996 | |||
| 4997 | /// The function failed because an unexpected error occurred inside a display driver. | 3404 | /// The function failed because an unexpected error occurred inside a display driver. |
| 4998 | GRAPHICS_OPM_DRIVER_INTERNAL_ERROR = 0xC01E051E, | 3405 | GRAPHICS_OPM_DRIVER_INTERNAL_ERROR = 0xC01E051E, |
| 4999 | |||
| 5000 | /// The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. | 3406 | /// The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. |
| 5001 | /// This error is returned only if a protected output has COPP semantics. | 3407 | /// This error is returned only if a protected output has COPP semantics. |
| 5002 | /// DxgkDdiOPMGetCOPPCompatibleInformation returns this error code if the caller requested OPM-specific information. | 3408 | /// DxgkDdiOPMGetCOPPCompatibleInformation returns this error code if the caller requested OPM-specific information. |
| 5003 | /// DxgkDdiOPMGetInformation always returns this error if a protected output has COPP semantics. | 3409 | /// DxgkDdiOPMGetInformation always returns this error if a protected output has COPP semantics. |
| 5004 | /// DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use an OPM-specific command. | 3410 | /// DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use an OPM-specific command. |
| 5005 | GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS = 0xC01E051F, | 3411 | GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS = 0xC01E051F, |
| 5006 | |||
| 5007 | /// The DxgkDdiOPMGetCOPPCompatibleInformation and DxgkDdiOPMConfigureProtectedOutput functions return this error if the display driver does not support the DXGKMDT_OPM_GET_ACP_AND_CGMSA_SIGNALING and DXGKMDT_OPM_SET_ACP_AND_CGMSA_SIGNALING GUIDs. | 3412 | /// The DxgkDdiOPMGetCOPPCompatibleInformation and DxgkDdiOPMConfigureProtectedOutput functions return this error if the display driver does not support the DXGKMDT_OPM_GET_ACP_AND_CGMSA_SIGNALING and DXGKMDT_OPM_SET_ACP_AND_CGMSA_SIGNALING GUIDs. |
| 5008 | GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED = 0xC01E0520, | 3413 | GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED = 0xC01E0520, |
| 5009 | |||
| 5010 | /// The DxgkDdiOPMConfigureProtectedOutput function returns this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid. | 3414 | /// The DxgkDdiOPMConfigureProtectedOutput function returns this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid. |
| 5011 | GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST = 0xC01E0521, | 3415 | GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST = 0xC01E0521, |
| 5012 | |||
| 5013 | /// The monitor connected to the specified video output does not have an I2C bus. | 3416 | /// The monitor connected to the specified video output does not have an I2C bus. |
| 5014 | GRAPHICS_I2C_NOT_SUPPORTED = 0xC01E0580, | 3417 | GRAPHICS_I2C_NOT_SUPPORTED = 0xC01E0580, |
| 5015 | |||
| 5016 | /// No device on the I2C bus has the specified address. | 3418 | /// No device on the I2C bus has the specified address. |
| 5017 | GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST = 0xC01E0581, | 3419 | GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST = 0xC01E0581, |
| 5018 | |||
| 5019 | /// An error occurred while transmitting data to the device on the I2C bus. | 3420 | /// An error occurred while transmitting data to the device on the I2C bus. |
| 5020 | GRAPHICS_I2C_ERROR_TRANSMITTING_DATA = 0xC01E0582, | 3421 | GRAPHICS_I2C_ERROR_TRANSMITTING_DATA = 0xC01E0582, |
| 5021 | |||
| 5022 | /// An error occurred while receiving data from the device on the I2C bus. | 3422 | /// An error occurred while receiving data from the device on the I2C bus. |
| 5023 | GRAPHICS_I2C_ERROR_RECEIVING_DATA = 0xC01E0583, | 3423 | GRAPHICS_I2C_ERROR_RECEIVING_DATA = 0xC01E0583, |
| 5024 | |||
| 5025 | /// The monitor does not support the specified VCP code. | 3424 | /// The monitor does not support the specified VCP code. |
| 5026 | GRAPHICS_DDCCI_VCP_NOT_SUPPORTED = 0xC01E0584, | 3425 | GRAPHICS_DDCCI_VCP_NOT_SUPPORTED = 0xC01E0584, |
| 5027 | |||
| 5028 | /// The data received from the monitor is invalid. | 3426 | /// The data received from the monitor is invalid. |
| 5029 | GRAPHICS_DDCCI_INVALID_DATA = 0xC01E0585, | 3427 | GRAPHICS_DDCCI_INVALID_DATA = 0xC01E0585, |
| 5030 | |||
| 5031 | /// A function call failed because a monitor returned an invalid timing status byte when the operating system used the DDC/CI get timing report and timing message command to get a timing report from a monitor. | 3428 | /// A function call failed because a monitor returned an invalid timing status byte when the operating system used the DDC/CI get timing report and timing message command to get a timing report from a monitor. |
| 5032 | GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE = 0xC01E0586, | 3429 | GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE = 0xC01E0586, |
| 5033 | |||
| 5034 | /// A monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification. | 3430 | /// A monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification. |
| 5035 | GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING = 0xC01E0587, | 3431 | GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING = 0xC01E0587, |
| 5036 | |||
| 5037 | /// An internal error caused an operation to fail. | 3432 | /// An internal error caused an operation to fail. |
| 5038 | GRAPHICS_MCA_INTERNAL_ERROR = 0xC01E0588, | 3433 | GRAPHICS_MCA_INTERNAL_ERROR = 0xC01E0588, |
| 5039 | |||
| 5040 | /// An operation failed because a DDC/CI message had an invalid value in its command field. | 3434 | /// An operation failed because a DDC/CI message had an invalid value in its command field. |
| 5041 | GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND = 0xC01E0589, | 3435 | GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND = 0xC01E0589, |
| 5042 | |||
| 5043 | /// This error occurred because a DDC/CI message had an invalid value in its length field. | 3436 | /// This error occurred because a DDC/CI message had an invalid value in its length field. |
| 5044 | GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH = 0xC01E058A, | 3437 | GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH = 0xC01E058A, |
| 5045 | |||
| 5046 | /// This error occurred because the value in a DDC/CI message's checksum field did not match the message's computed checksum value. | 3438 | /// This error occurred because the value in a DDC/CI message's checksum field did not match the message's computed checksum value. |
| 5047 | /// This error implies that the data was corrupted while it was being transmitted from a monitor to a computer. | 3439 | /// This error implies that the data was corrupted while it was being transmitted from a monitor to a computer. |
| 5048 | GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM = 0xC01E058B, | 3440 | GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM = 0xC01E058B, |
| 5049 | |||
| 5050 | /// This function failed because an invalid monitor handle was passed to it. | 3441 | /// This function failed because an invalid monitor handle was passed to it. |
| 5051 | GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE = 0xC01E058C, | 3442 | GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE = 0xC01E058C, |
| 5052 | |||
| 5053 | /// The operating system asynchronously destroyed the monitor that corresponds to this handle because the operating system's state changed. | 3443 | /// The operating system asynchronously destroyed the monitor that corresponds to this handle because the operating system's state changed. |
| 5054 | /// This error typically occurs because the monitor PDO associated with this handle was removed or stopped, or a display mode change occurred. | 3444 | /// This error typically occurs because the monitor PDO associated with this handle was removed or stopped, or a display mode change occurred. |
| 5055 | /// A display mode change occurs when Windows sends a WM_DISPLAYCHANGE message to applications. | 3445 | /// A display mode change occurs when Windows sends a WM_DISPLAYCHANGE message to applications. |
| 5056 | GRAPHICS_MONITOR_NO_LONGER_EXISTS = 0xC01E058D, | 3446 | GRAPHICS_MONITOR_NO_LONGER_EXISTS = 0xC01E058D, |
| 5057 | |||
| 5058 | /// This function can be used only if a program is running in the local console session. | 3447 | /// This function can be used only if a program is running in the local console session. |
| 5059 | /// It cannot be used if a program is running on a remote desktop session or on a terminal server session. | 3448 | /// It cannot be used if a program is running on a remote desktop session or on a terminal server session. |
| 5060 | GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED = 0xC01E05E0, | 3449 | GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED = 0xC01E05E0, |
| 5061 | |||
| 5062 | /// This function cannot find an actual GDI display device that corresponds to the specified GDI display device name. | 3450 | /// This function cannot find an actual GDI display device that corresponds to the specified GDI display device name. |
| 5063 | GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E05E1, | 3451 | GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E05E1, |
| 5064 | |||
| 5065 | /// The function failed because the specified GDI display device was not attached to the Windows desktop. | 3452 | /// The function failed because the specified GDI display device was not attached to the Windows desktop. |
| 5066 | GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E05E2, | 3453 | GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E05E2, |
| 5067 | |||
| 5068 | /// This function does not support GDI mirroring display devices because GDI mirroring display devices do not have any physical monitors associated with them. | 3454 | /// This function does not support GDI mirroring display devices because GDI mirroring display devices do not have any physical monitors associated with them. |
| 5069 | GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E05E3, | 3455 | GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E05E3, |
| 5070 | |||
| 5071 | /// The function failed because an invalid pointer parameter was passed to it. | 3456 | /// The function failed because an invalid pointer parameter was passed to it. |
| 5072 | /// A pointer parameter is invalid if it is null, is not correctly aligned, or points to an invalid address or to a kernel mode address. | 3457 | /// A pointer parameter is invalid if it is null, is not correctly aligned, or points to an invalid address or to a kernel mode address. |
| 5073 | GRAPHICS_INVALID_POINTER = 0xC01E05E4, | 3458 | GRAPHICS_INVALID_POINTER = 0xC01E05E4, |
| 5074 | |||
| 5075 | /// This function failed because the GDI device passed to it did not have a monitor associated with it. | 3459 | /// This function failed because the GDI device passed to it did not have a monitor associated with it. |
| 5076 | GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E05E5, | 3460 | GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E05E5, |
| 5077 | |||
| 5078 | /// An array passed to the function cannot hold all of the data that the function must copy into the array. | 3461 | /// An array passed to the function cannot hold all of the data that the function must copy into the array. |
| 5079 | GRAPHICS_PARAMETER_ARRAY_TOO_SMALL = 0xC01E05E6, | 3462 | GRAPHICS_PARAMETER_ARRAY_TOO_SMALL = 0xC01E05E6, |
| 5080 | |||
| 5081 | /// An internal error caused an operation to fail. | 3463 | /// An internal error caused an operation to fail. |
| 5082 | GRAPHICS_INTERNAL_ERROR = 0xC01E05E7, | 3464 | GRAPHICS_INTERNAL_ERROR = 0xC01E05E7, |
| 5083 | |||
| 5084 | /// The function failed because the current session is changing its type. | 3465 | /// The function failed because the current session is changing its type. |
| 5085 | /// This function cannot be called when the current session is changing its type. | 3466 | /// This function cannot be called when the current session is changing its type. |
| 5086 | /// Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA). | 3467 | /// Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA). |
| 5087 | GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E05E8, | 3468 | GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E05E8, |
| 5088 | |||
| 5089 | /// The volume must be unlocked before it can be used. | 3469 | /// The volume must be unlocked before it can be used. |
| 5090 | FVE_LOCKED_VOLUME = 0xC0210000, | 3470 | FVE_LOCKED_VOLUME = 0xC0210000, |
| 5091 | |||
| 5092 | /// The volume is fully decrypted and no key is available. | 3471 | /// The volume is fully decrypted and no key is available. |
| 5093 | FVE_NOT_ENCRYPTED = 0xC0210001, | 3472 | FVE_NOT_ENCRYPTED = 0xC0210001, |
| 5094 | |||
| 5095 | /// The control block for the encrypted volume is not valid. | 3473 | /// The control block for the encrypted volume is not valid. |
| 5096 | FVE_BAD_INFORMATION = 0xC0210002, | 3474 | FVE_BAD_INFORMATION = 0xC0210002, |
| 5097 | |||
| 5098 | /// Not enough free space remains on the volume to allow encryption. | 3475 | /// Not enough free space remains on the volume to allow encryption. |
| 5099 | FVE_TOO_SMALL = 0xC0210003, | 3476 | FVE_TOO_SMALL = 0xC0210003, |
| 5100 | |||
| 5101 | /// The partition cannot be encrypted because the file system is not supported. | 3477 | /// The partition cannot be encrypted because the file system is not supported. |
| 5102 | FVE_FAILED_WRONG_FS = 0xC0210004, | 3478 | FVE_FAILED_WRONG_FS = 0xC0210004, |
| 5103 | |||
| 5104 | /// The file system is inconsistent. Run the Check Disk utility. | 3479 | /// The file system is inconsistent. Run the Check Disk utility. |
| 5105 | FVE_FAILED_BAD_FS = 0xC0210005, | 3480 | FVE_FAILED_BAD_FS = 0xC0210005, |
| 5106 | |||
| 5107 | /// The file system does not extend to the end of the volume. | 3481 | /// The file system does not extend to the end of the volume. |
| 5108 | FVE_FS_NOT_EXTENDED = 0xC0210006, | 3482 | FVE_FS_NOT_EXTENDED = 0xC0210006, |
| 5109 | |||
| 5110 | /// This operation cannot be performed while a file system is mounted on the volume. | 3483 | /// This operation cannot be performed while a file system is mounted on the volume. |
| 5111 | FVE_FS_MOUNTED = 0xC0210007, | 3484 | FVE_FS_MOUNTED = 0xC0210007, |
| 5112 | |||
| 5113 | /// BitLocker Drive Encryption is not included with this version of Windows. | 3485 | /// BitLocker Drive Encryption is not included with this version of Windows. |
| 5114 | FVE_NO_LICENSE = 0xC0210008, | 3486 | FVE_NO_LICENSE = 0xC0210008, |
| 5115 | |||
| 5116 | /// The requested action was denied by the FVE control engine. | 3487 | /// The requested action was denied by the FVE control engine. |
| 5117 | FVE_ACTION_NOT_ALLOWED = 0xC0210009, | 3488 | FVE_ACTION_NOT_ALLOWED = 0xC0210009, |
| 5118 | |||
| 5119 | /// The data supplied is malformed. | 3489 | /// The data supplied is malformed. |
| 5120 | FVE_BAD_DATA = 0xC021000A, | 3490 | FVE_BAD_DATA = 0xC021000A, |
| 5121 | |||
| 5122 | /// The volume is not bound to the system. | 3491 | /// The volume is not bound to the system. |
| 5123 | FVE_VOLUME_NOT_BOUND = 0xC021000B, | 3492 | FVE_VOLUME_NOT_BOUND = 0xC021000B, |
| 5124 | |||
| 5125 | /// The volume specified is not a data volume. | 3493 | /// The volume specified is not a data volume. |
| 5126 | FVE_NOT_DATA_VOLUME = 0xC021000C, | 3494 | FVE_NOT_DATA_VOLUME = 0xC021000C, |
| 5127 | |||
| 5128 | /// A read operation failed while converting the volume. | 3495 | /// A read operation failed while converting the volume. |
| 5129 | FVE_CONV_READ_ERROR = 0xC021000D, | 3496 | FVE_CONV_READ_ERROR = 0xC021000D, |
| 5130 | |||
| 5131 | /// A write operation failed while converting the volume. | 3497 | /// A write operation failed while converting the volume. |
| 5132 | FVE_CONV_WRITE_ERROR = 0xC021000E, | 3498 | FVE_CONV_WRITE_ERROR = 0xC021000E, |
| 5133 | |||
| 5134 | /// The control block for the encrypted volume was updated by another thread. Try again. | 3499 | /// The control block for the encrypted volume was updated by another thread. Try again. |
| 5135 | FVE_OVERLAPPED_UPDATE = 0xC021000F, | 3500 | FVE_OVERLAPPED_UPDATE = 0xC021000F, |
| 5136 | |||
| 5137 | /// The volume encryption algorithm cannot be used on this sector size. | 3501 | /// The volume encryption algorithm cannot be used on this sector size. |
| 5138 | FVE_FAILED_SECTOR_SIZE = 0xC0210010, | 3502 | FVE_FAILED_SECTOR_SIZE = 0xC0210010, |
| 5139 | |||
| 5140 | /// BitLocker recovery authentication failed. | 3503 | /// BitLocker recovery authentication failed. |
| 5141 | FVE_FAILED_AUTHENTICATION = 0xC0210011, | 3504 | FVE_FAILED_AUTHENTICATION = 0xC0210011, |
| 5142 | |||
| 5143 | /// The volume specified is not the boot operating system volume. | 3505 | /// The volume specified is not the boot operating system volume. |
| 5144 | FVE_NOT_OS_VOLUME = 0xC0210012, | 3506 | FVE_NOT_OS_VOLUME = 0xC0210012, |
| 5145 | |||
| 5146 | /// The BitLocker startup key or recovery password could not be read from external media. | 3507 | /// The BitLocker startup key or recovery password could not be read from external media. |
| 5147 | FVE_KEYFILE_NOT_FOUND = 0xC0210013, | 3508 | FVE_KEYFILE_NOT_FOUND = 0xC0210013, |
| 5148 | |||
| 5149 | /// The BitLocker startup key or recovery password file is corrupt or invalid. | 3509 | /// The BitLocker startup key or recovery password file is corrupt or invalid. |
| 5150 | FVE_KEYFILE_INVALID = 0xC0210014, | 3510 | FVE_KEYFILE_INVALID = 0xC0210014, |
| 5151 | |||
| 5152 | /// The BitLocker encryption key could not be obtained from the startup key or the recovery password. | 3511 | /// The BitLocker encryption key could not be obtained from the startup key or the recovery password. |
| 5153 | FVE_KEYFILE_NO_VMK = 0xC0210015, | 3512 | FVE_KEYFILE_NO_VMK = 0xC0210015, |
| 5154 | |||
| 5155 | /// The TPM is disabled. | 3513 | /// The TPM is disabled. |
| 5156 | FVE_TPM_DISABLED = 0xC0210016, | 3514 | FVE_TPM_DISABLED = 0xC0210016, |
| 5157 | |||
| 5158 | /// The authorization data for the SRK of the TPM is not zero. | 3515 | /// The authorization data for the SRK of the TPM is not zero. |
| 5159 | FVE_TPM_SRK_AUTH_NOT_ZERO = 0xC0210017, | 3516 | FVE_TPM_SRK_AUTH_NOT_ZERO = 0xC0210017, |
| 5160 | |||
| 5161 | /// The system boot information changed or the TPM locked out access to BitLocker encryption keys until the computer is restarted. | 3517 | /// The system boot information changed or the TPM locked out access to BitLocker encryption keys until the computer is restarted. |
| 5162 | FVE_TPM_INVALID_PCR = 0xC0210018, | 3518 | FVE_TPM_INVALID_PCR = 0xC0210018, |
| 5163 | |||
| 5164 | /// The BitLocker encryption key could not be obtained from the TPM. | 3519 | /// The BitLocker encryption key could not be obtained from the TPM. |
| 5165 | FVE_TPM_NO_VMK = 0xC0210019, | 3520 | FVE_TPM_NO_VMK = 0xC0210019, |
| 5166 | |||
| 5167 | /// The BitLocker encryption key could not be obtained from the TPM and PIN. | 3521 | /// The BitLocker encryption key could not be obtained from the TPM and PIN. |
| 5168 | FVE_PIN_INVALID = 0xC021001A, | 3522 | FVE_PIN_INVALID = 0xC021001A, |
| 5169 | |||
| 5170 | /// A boot application hash does not match the hash computed when BitLocker was turned on. | 3523 | /// A boot application hash does not match the hash computed when BitLocker was turned on. |
| 5171 | FVE_AUTH_INVALID_APPLICATION = 0xC021001B, | 3524 | FVE_AUTH_INVALID_APPLICATION = 0xC021001B, |
| 5172 | |||
| 5173 | /// The Boot Configuration Data (BCD) settings are not supported or have changed because BitLocker was enabled. | 3525 | /// The Boot Configuration Data (BCD) settings are not supported or have changed because BitLocker was enabled. |
| 5174 | FVE_AUTH_INVALID_CONFIG = 0xC021001C, | 3526 | FVE_AUTH_INVALID_CONFIG = 0xC021001C, |
| 5175 | |||
| 5176 | /// Boot debugging is enabled. Run Windows Boot Configuration Data Store Editor (bcdedit.exe) to turn it off. | 3527 | /// Boot debugging is enabled. Run Windows Boot Configuration Data Store Editor (bcdedit.exe) to turn it off. |
| 5177 | FVE_DEBUGGER_ENABLED = 0xC021001D, | 3528 | FVE_DEBUGGER_ENABLED = 0xC021001D, |
| 5178 | |||
| 5179 | /// The BitLocker encryption key could not be obtained. | 3529 | /// The BitLocker encryption key could not be obtained. |
| 5180 | FVE_DRY_RUN_FAILED = 0xC021001E, | 3530 | FVE_DRY_RUN_FAILED = 0xC021001E, |
| 5181 | |||
| 5182 | /// The metadata disk region pointer is incorrect. | 3531 | /// The metadata disk region pointer is incorrect. |
| 5183 | FVE_BAD_METADATA_POINTER = 0xC021001F, | 3532 | FVE_BAD_METADATA_POINTER = 0xC021001F, |
| 5184 | |||
| 5185 | /// The backup copy of the metadata is out of date. | 3533 | /// The backup copy of the metadata is out of date. |
| 5186 | FVE_OLD_METADATA_COPY = 0xC0210020, | 3534 | FVE_OLD_METADATA_COPY = 0xC0210020, |
| 5187 | |||
| 5188 | /// No action was taken because a system restart is required. | 3535 | /// No action was taken because a system restart is required. |
| 5189 | FVE_REBOOT_REQUIRED = 0xC0210021, | 3536 | FVE_REBOOT_REQUIRED = 0xC0210021, |
| 5190 | |||
| 5191 | /// No action was taken because BitLocker Drive Encryption is in RAW access mode. | 3537 | /// No action was taken because BitLocker Drive Encryption is in RAW access mode. |
| 5192 | FVE_RAW_ACCESS = 0xC0210022, | 3538 | FVE_RAW_ACCESS = 0xC0210022, |
| 5193 | |||
| 5194 | /// BitLocker Drive Encryption cannot enter RAW access mode for this volume. | 3539 | /// BitLocker Drive Encryption cannot enter RAW access mode for this volume. |
| 5195 | FVE_RAW_BLOCKED = 0xC0210023, | 3540 | FVE_RAW_BLOCKED = 0xC0210023, |
| 5196 | |||
| 5197 | /// This feature of BitLocker Drive Encryption is not included with this version of Windows. | 3541 | /// This feature of BitLocker Drive Encryption is not included with this version of Windows. |
| 5198 | FVE_NO_FEATURE_LICENSE = 0xC0210026, | 3542 | FVE_NO_FEATURE_LICENSE = 0xC0210026, |
| 5199 | |||
| 5200 | /// Group policy does not permit turning off BitLocker Drive Encryption on roaming data volumes. | 3543 | /// Group policy does not permit turning off BitLocker Drive Encryption on roaming data volumes. |
| 5201 | FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED = 0xC0210027, | 3544 | FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED = 0xC0210027, |
| 5202 | |||
| 5203 | /// Bitlocker Drive Encryption failed to recover from aborted conversion. | 3545 | /// Bitlocker Drive Encryption failed to recover from aborted conversion. |
| 5204 | /// This could be due to either all conversion logs being corrupted or the media being write-protected. | 3546 | /// This could be due to either all conversion logs being corrupted or the media being write-protected. |
| 5205 | FVE_CONV_RECOVERY_FAILED = 0xC0210028, | 3547 | FVE_CONV_RECOVERY_FAILED = 0xC0210028, |
| 5206 | |||
| 5207 | /// The requested virtualization size is too big. | 3548 | /// The requested virtualization size is too big. |
| 5208 | FVE_VIRTUALIZED_SPACE_TOO_BIG = 0xC0210029, | 3549 | FVE_VIRTUALIZED_SPACE_TOO_BIG = 0xC0210029, |
| 5209 | |||
| 5210 | /// The drive is too small to be protected using BitLocker Drive Encryption. | 3550 | /// The drive is too small to be protected using BitLocker Drive Encryption. |
| 5211 | FVE_VOLUME_TOO_SMALL = 0xC0210030, | 3551 | FVE_VOLUME_TOO_SMALL = 0xC0210030, |
| 5212 | |||
| 5213 | /// The callout does not exist. | 3552 | /// The callout does not exist. |
| 5214 | FWP_CALLOUT_NOT_FOUND = 0xC0220001, | 3553 | FWP_CALLOUT_NOT_FOUND = 0xC0220001, |
| 5215 | |||
| 5216 | /// The filter condition does not exist. | 3554 | /// The filter condition does not exist. |
| 5217 | FWP_CONDITION_NOT_FOUND = 0xC0220002, | 3555 | FWP_CONDITION_NOT_FOUND = 0xC0220002, |
| 5218 | |||
| 5219 | /// The filter does not exist. | 3556 | /// The filter does not exist. |
| 5220 | FWP_FILTER_NOT_FOUND = 0xC0220003, | 3557 | FWP_FILTER_NOT_FOUND = 0xC0220003, |
| 5221 | |||
| 5222 | /// The layer does not exist. | 3558 | /// The layer does not exist. |
| 5223 | FWP_LAYER_NOT_FOUND = 0xC0220004, | 3559 | FWP_LAYER_NOT_FOUND = 0xC0220004, |
| 5224 | |||
| 5225 | /// The provider does not exist. | 3560 | /// The provider does not exist. |
| 5226 | FWP_PROVIDER_NOT_FOUND = 0xC0220005, | 3561 | FWP_PROVIDER_NOT_FOUND = 0xC0220005, |
| 5227 | |||
| 5228 | /// The provider context does not exist. | 3562 | /// The provider context does not exist. |
| 5229 | FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006, | 3563 | FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006, |
| 5230 | |||
| 5231 | /// The sublayer does not exist. | 3564 | /// The sublayer does not exist. |
| 5232 | FWP_SUBLAYER_NOT_FOUND = 0xC0220007, | 3565 | FWP_SUBLAYER_NOT_FOUND = 0xC0220007, |
| 5233 | |||
| 5234 | /// The object does not exist. | 3566 | /// The object does not exist. |
| 5235 | FWP_NOT_FOUND = 0xC0220008, | 3567 | FWP_NOT_FOUND = 0xC0220008, |
| 5236 | |||
| 5237 | /// An object with that GUID or LUID already exists. | 3568 | /// An object with that GUID or LUID already exists. |
| 5238 | FWP_ALREADY_EXISTS = 0xC0220009, | 3569 | FWP_ALREADY_EXISTS = 0xC0220009, |
| 5239 | |||
| 5240 | /// The object is referenced by other objects and cannot be deleted. | 3570 | /// The object is referenced by other objects and cannot be deleted. |
| 5241 | FWP_IN_USE = 0xC022000A, | 3571 | FWP_IN_USE = 0xC022000A, |
| 5242 | |||
| 5243 | /// The call is not allowed from within a dynamic session. | 3572 | /// The call is not allowed from within a dynamic session. |
| 5244 | FWP_DYNAMIC_SESSION_IN_PROGRESS = 0xC022000B, | 3573 | FWP_DYNAMIC_SESSION_IN_PROGRESS = 0xC022000B, |
| 5245 | |||
| 5246 | /// The call was made from the wrong session and cannot be completed. | 3574 | /// The call was made from the wrong session and cannot be completed. |
| 5247 | FWP_WRONG_SESSION = 0xC022000C, | 3575 | FWP_WRONG_SESSION = 0xC022000C, |
| 5248 | |||
| 5249 | /// The call must be made from within an explicit transaction. | 3576 | /// The call must be made from within an explicit transaction. |
| 5250 | FWP_NO_TXN_IN_PROGRESS = 0xC022000D, | 3577 | FWP_NO_TXN_IN_PROGRESS = 0xC022000D, |
| 5251 | |||
| 5252 | /// The call is not allowed from within an explicit transaction. | 3578 | /// The call is not allowed from within an explicit transaction. |
| 5253 | FWP_TXN_IN_PROGRESS = 0xC022000E, | 3579 | FWP_TXN_IN_PROGRESS = 0xC022000E, |
| 5254 | |||
| 5255 | /// The explicit transaction has been forcibly canceled. | 3580 | /// The explicit transaction has been forcibly canceled. |
| 5256 | FWP_TXN_ABORTED = 0xC022000F, | 3581 | FWP_TXN_ABORTED = 0xC022000F, |
| 5257 | |||
| 5258 | /// The session has been canceled. | 3582 | /// The session has been canceled. |
| 5259 | FWP_SESSION_ABORTED = 0xC0220010, | 3583 | FWP_SESSION_ABORTED = 0xC0220010, |
| 5260 | |||
| 5261 | /// The call is not allowed from within a read-only transaction. | 3584 | /// The call is not allowed from within a read-only transaction. |
| 5262 | FWP_INCOMPATIBLE_TXN = 0xC0220011, | 3585 | FWP_INCOMPATIBLE_TXN = 0xC0220011, |
| 5263 | |||
| 5264 | /// The call timed out while waiting to acquire the transaction lock. | 3586 | /// The call timed out while waiting to acquire the transaction lock. |
| 5265 | FWP_TIMEOUT = 0xC0220012, | 3587 | FWP_TIMEOUT = 0xC0220012, |
| 5266 | |||
| 5267 | /// The collection of network diagnostic events is disabled. | 3588 | /// The collection of network diagnostic events is disabled. |
| 5268 | FWP_NET_EVENTS_DISABLED = 0xC0220013, | 3589 | FWP_NET_EVENTS_DISABLED = 0xC0220013, |
| 5269 | |||
| 5270 | /// The operation is not supported by the specified layer. | 3590 | /// The operation is not supported by the specified layer. |
| 5271 | FWP_INCOMPATIBLE_LAYER = 0xC0220014, | 3591 | FWP_INCOMPATIBLE_LAYER = 0xC0220014, |
| 5272 | |||
| 5273 | /// The call is allowed for kernel-mode callers only. | 3592 | /// The call is allowed for kernel-mode callers only. |
| 5274 | FWP_KM_CLIENTS_ONLY = 0xC0220015, | 3593 | FWP_KM_CLIENTS_ONLY = 0xC0220015, |
| 5275 | |||
| 5276 | /// The call tried to associate two objects with incompatible lifetimes. | 3594 | /// The call tried to associate two objects with incompatible lifetimes. |
| 5277 | FWP_LIFETIME_MISMATCH = 0xC0220016, | 3595 | FWP_LIFETIME_MISMATCH = 0xC0220016, |
| 5278 | |||
| 5279 | /// The object is built-in and cannot be deleted. | 3596 | /// The object is built-in and cannot be deleted. |
| 5280 | FWP_BUILTIN_OBJECT = 0xC0220017, | 3597 | FWP_BUILTIN_OBJECT = 0xC0220017, |
| 5281 | |||
| 5282 | /// The maximum number of boot-time filters has been reached. | ||
| 5283 | FWP_TOO_MANY_BOOTTIME_FILTERS = 0xC0220018, | ||
| 5284 | |||
| 5285 | /// The maximum number of callouts has been reached. | 3598 | /// The maximum number of callouts has been reached. |
| 5286 | FWP_TOO_MANY_CALLOUTS = 0xC0220018, | 3599 | FWP_TOO_MANY_CALLOUTS = 0xC0220018, |
| 5287 | |||
| 5288 | /// A notification could not be delivered because a message queue has reached maximum capacity. | 3600 | /// A notification could not be delivered because a message queue has reached maximum capacity. |
| 5289 | FWP_NOTIFICATION_DROPPED = 0xC0220019, | 3601 | FWP_NOTIFICATION_DROPPED = 0xC0220019, |
| 5290 | |||
| 5291 | /// The traffic parameters do not match those for the security association context. | 3602 | /// The traffic parameters do not match those for the security association context. |
| 5292 | FWP_TRAFFIC_MISMATCH = 0xC022001A, | 3603 | FWP_TRAFFIC_MISMATCH = 0xC022001A, |
| 5293 | |||
| 5294 | /// The call is not allowed for the current security association state. | 3604 | /// The call is not allowed for the current security association state. |
| 5295 | FWP_INCOMPATIBLE_SA_STATE = 0xC022001B, | 3605 | FWP_INCOMPATIBLE_SA_STATE = 0xC022001B, |
| 5296 | |||
| 5297 | /// A required pointer is null. | 3606 | /// A required pointer is null. |
| 5298 | FWP_NULL_POINTER = 0xC022001C, | 3607 | FWP_NULL_POINTER = 0xC022001C, |
| 5299 | |||
| 5300 | /// An enumerator is not valid. | 3608 | /// An enumerator is not valid. |
| 5301 | FWP_INVALID_ENUMERATOR = 0xC022001D, | 3609 | FWP_INVALID_ENUMERATOR = 0xC022001D, |
| 5302 | |||
| 5303 | /// The flags field contains an invalid value. | 3610 | /// The flags field contains an invalid value. |
| 5304 | FWP_INVALID_FLAGS = 0xC022001E, | 3611 | FWP_INVALID_FLAGS = 0xC022001E, |
| 5305 | |||
| 5306 | /// A network mask is not valid. | 3612 | /// A network mask is not valid. |
| 5307 | FWP_INVALID_NET_MASK = 0xC022001F, | 3613 | FWP_INVALID_NET_MASK = 0xC022001F, |
| 5308 | |||
| 5309 | /// An FWP_RANGE is not valid. | 3614 | /// An FWP_RANGE is not valid. |
| 5310 | FWP_INVALID_RANGE = 0xC0220020, | 3615 | FWP_INVALID_RANGE = 0xC0220020, |
| 5311 | |||
| 5312 | /// The time interval is not valid. | 3616 | /// The time interval is not valid. |
| 5313 | FWP_INVALID_INTERVAL = 0xC0220021, | 3617 | FWP_INVALID_INTERVAL = 0xC0220021, |
| 5314 | |||
| 5315 | /// An array that must contain at least one element has a zero length. | 3618 | /// An array that must contain at least one element has a zero length. |
| 5316 | FWP_ZERO_LENGTH_ARRAY = 0xC0220022, | 3619 | FWP_ZERO_LENGTH_ARRAY = 0xC0220022, |
| 5317 | |||
| 5318 | /// The displayData.name field cannot be null. | 3620 | /// The displayData.name field cannot be null. |
| 5319 | FWP_NULL_DISPLAY_NAME = 0xC0220023, | 3621 | FWP_NULL_DISPLAY_NAME = 0xC0220023, |
| 5320 | |||
| 5321 | /// The action type is not one of the allowed action types for a filter. | 3622 | /// The action type is not one of the allowed action types for a filter. |
| 5322 | FWP_INVALID_ACTION_TYPE = 0xC0220024, | 3623 | FWP_INVALID_ACTION_TYPE = 0xC0220024, |
| 5323 | |||
| 5324 | /// The filter weight is not valid. | 3624 | /// The filter weight is not valid. |
| 5325 | FWP_INVALID_WEIGHT = 0xC0220025, | 3625 | FWP_INVALID_WEIGHT = 0xC0220025, |
| 5326 | |||
| 5327 | /// A filter condition contains a match type that is not compatible with the operands. | 3626 | /// A filter condition contains a match type that is not compatible with the operands. |
| 5328 | FWP_MATCH_TYPE_MISMATCH = 0xC0220026, | 3627 | FWP_MATCH_TYPE_MISMATCH = 0xC0220026, |
| 5329 | |||
| 5330 | /// An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type. | 3628 | /// An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type. |
| 5331 | FWP_TYPE_MISMATCH = 0xC0220027, | 3629 | FWP_TYPE_MISMATCH = 0xC0220027, |
| 5332 | |||
| 5333 | /// An integer value is outside the allowed range. | 3630 | /// An integer value is outside the allowed range. |
| 5334 | FWP_OUT_OF_BOUNDS = 0xC0220028, | 3631 | FWP_OUT_OF_BOUNDS = 0xC0220028, |
| 5335 | |||
| 5336 | /// A reserved field is nonzero. | 3632 | /// A reserved field is nonzero. |
| 5337 | FWP_RESERVED = 0xC0220029, | 3633 | FWP_RESERVED = 0xC0220029, |
| 5338 | |||
| 5339 | /// A filter cannot contain multiple conditions operating on a single field. | 3634 | /// A filter cannot contain multiple conditions operating on a single field. |
| 5340 | FWP_DUPLICATE_CONDITION = 0xC022002A, | 3635 | FWP_DUPLICATE_CONDITION = 0xC022002A, |
| 5341 | |||
| 5342 | /// A policy cannot contain the same keying module more than once. | 3636 | /// A policy cannot contain the same keying module more than once. |
| 5343 | FWP_DUPLICATE_KEYMOD = 0xC022002B, | 3637 | FWP_DUPLICATE_KEYMOD = 0xC022002B, |
| 5344 | |||
| 5345 | /// The action type is not compatible with the layer. | 3638 | /// The action type is not compatible with the layer. |
| 5346 | FWP_ACTION_INCOMPATIBLE_WITH_LAYER = 0xC022002C, | 3639 | FWP_ACTION_INCOMPATIBLE_WITH_LAYER = 0xC022002C, |
| 5347 | |||
| 5348 | /// The action type is not compatible with the sublayer. | 3640 | /// The action type is not compatible with the sublayer. |
| 5349 | FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER = 0xC022002D, | 3641 | FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER = 0xC022002D, |
| 5350 | |||
| 5351 | /// The raw context or the provider context is not compatible with the layer. | 3642 | /// The raw context or the provider context is not compatible with the layer. |
| 5352 | FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER = 0xC022002E, | 3643 | FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER = 0xC022002E, |
| 5353 | |||
| 5354 | /// The raw context or the provider context is not compatible with the callout. | 3644 | /// The raw context or the provider context is not compatible with the callout. |
| 5355 | FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT = 0xC022002F, | 3645 | FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT = 0xC022002F, |
| 5356 | |||
| 5357 | /// The authentication method is not compatible with the policy type. | 3646 | /// The authentication method is not compatible with the policy type. |
| 5358 | FWP_INCOMPATIBLE_AUTH_METHOD = 0xC0220030, | 3647 | FWP_INCOMPATIBLE_AUTH_METHOD = 0xC0220030, |
| 5359 | |||
| 5360 | /// The Diffie-Hellman group is not compatible with the policy type. | 3648 | /// The Diffie-Hellman group is not compatible with the policy type. |
| 5361 | FWP_INCOMPATIBLE_DH_GROUP = 0xC0220031, | 3649 | FWP_INCOMPATIBLE_DH_GROUP = 0xC0220031, |
| 5362 | |||
| 5363 | /// An IKE policy cannot contain an Extended Mode policy. | 3650 | /// An IKE policy cannot contain an Extended Mode policy. |
| 5364 | FWP_EM_NOT_SUPPORTED = 0xC0220032, | 3651 | FWP_EM_NOT_SUPPORTED = 0xC0220032, |
| 5365 | |||
| 5366 | /// The enumeration template or subscription will never match any objects. | 3652 | /// The enumeration template or subscription will never match any objects. |
| 5367 | FWP_NEVER_MATCH = 0xC0220033, | 3653 | FWP_NEVER_MATCH = 0xC0220033, |
| 5368 | |||
| 5369 | /// The provider context is of the wrong type. | 3654 | /// The provider context is of the wrong type. |
| 5370 | FWP_PROVIDER_CONTEXT_MISMATCH = 0xC0220034, | 3655 | FWP_PROVIDER_CONTEXT_MISMATCH = 0xC0220034, |
| 5371 | |||
| 5372 | /// The parameter is incorrect. | 3656 | /// The parameter is incorrect. |
| 5373 | FWP_INVALID_PARAMETER = 0xC0220035, | 3657 | FWP_INVALID_PARAMETER = 0xC0220035, |
| 5374 | |||
| 5375 | /// The maximum number of sublayers has been reached. | 3658 | /// The maximum number of sublayers has been reached. |
| 5376 | FWP_TOO_MANY_SUBLAYERS = 0xC0220036, | 3659 | FWP_TOO_MANY_SUBLAYERS = 0xC0220036, |
| 5377 | |||
| 5378 | /// The notification function for a callout returned an error. | 3660 | /// The notification function for a callout returned an error. |
| 5379 | FWP_CALLOUT_NOTIFICATION_FAILED = 0xC0220037, | 3661 | FWP_CALLOUT_NOTIFICATION_FAILED = 0xC0220037, |
| 5380 | |||
| 5381 | /// The IPsec authentication configuration is not compatible with the authentication type. | 3662 | /// The IPsec authentication configuration is not compatible with the authentication type. |
| 5382 | FWP_INCOMPATIBLE_AUTH_CONFIG = 0xC0220038, | 3663 | FWP_INCOMPATIBLE_AUTH_CONFIG = 0xC0220038, |
| 5383 | |||
| 5384 | /// The IPsec cipher configuration is not compatible with the cipher type. | 3664 | /// The IPsec cipher configuration is not compatible with the cipher type. |
| 5385 | FWP_INCOMPATIBLE_CIPHER_CONFIG = 0xC0220039, | 3665 | FWP_INCOMPATIBLE_CIPHER_CONFIG = 0xC0220039, |
| 5386 | |||
| 5387 | /// A policy cannot contain the same auth method more than once. | 3666 | /// A policy cannot contain the same auth method more than once. |
| 5388 | FWP_DUPLICATE_AUTH_METHOD = 0xC022003C, | 3667 | FWP_DUPLICATE_AUTH_METHOD = 0xC022003C, |
| 5389 | |||
| 5390 | /// The TCP/IP stack is not ready. | 3668 | /// The TCP/IP stack is not ready. |
| 5391 | FWP_TCPIP_NOT_READY = 0xC0220100, | 3669 | FWP_TCPIP_NOT_READY = 0xC0220100, |
| 5392 | |||
| 5393 | /// The injection handle is being closed by another thread. | 3670 | /// The injection handle is being closed by another thread. |
| 5394 | FWP_INJECT_HANDLE_CLOSING = 0xC0220101, | 3671 | FWP_INJECT_HANDLE_CLOSING = 0xC0220101, |
| 5395 | |||
| 5396 | /// The injection handle is stale. | 3672 | /// The injection handle is stale. |
| 5397 | FWP_INJECT_HANDLE_STALE = 0xC0220102, | 3673 | FWP_INJECT_HANDLE_STALE = 0xC0220102, |
| 5398 | |||
| 5399 | /// The classify cannot be pended. | 3674 | /// The classify cannot be pended. |
| 5400 | FWP_CANNOT_PEND = 0xC0220103, | 3675 | FWP_CANNOT_PEND = 0xC0220103, |
| 5401 | |||
| 5402 | /// The binding to the network interface is being closed. | 3676 | /// The binding to the network interface is being closed. |
| 5403 | NDIS_CLOSING = 0xC0230002, | 3677 | NDIS_CLOSING = 0xC0230002, |
| 5404 | |||
| 5405 | /// An invalid version was specified. | 3678 | /// An invalid version was specified. |
| 5406 | NDIS_BAD_VERSION = 0xC0230004, | 3679 | NDIS_BAD_VERSION = 0xC0230004, |
| 5407 | |||
| 5408 | /// An invalid characteristics table was used. | 3680 | /// An invalid characteristics table was used. |
| 5409 | NDIS_BAD_CHARACTERISTICS = 0xC0230005, | 3681 | NDIS_BAD_CHARACTERISTICS = 0xC0230005, |
| 5410 | |||
| 5411 | /// Failed to find the network interface or the network interface is not ready. | 3682 | /// Failed to find the network interface or the network interface is not ready. |
| 5412 | NDIS_ADAPTER_NOT_FOUND = 0xC0230006, | 3683 | NDIS_ADAPTER_NOT_FOUND = 0xC0230006, |
| 5413 | |||
| 5414 | /// Failed to open the network interface. | 3684 | /// Failed to open the network interface. |
| 5415 | NDIS_OPEN_FAILED = 0xC0230007, | 3685 | NDIS_OPEN_FAILED = 0xC0230007, |
| 5416 | |||
| 5417 | /// The network interface has encountered an internal unrecoverable failure. | 3686 | /// The network interface has encountered an internal unrecoverable failure. |
| 5418 | NDIS_DEVICE_FAILED = 0xC0230008, | 3687 | NDIS_DEVICE_FAILED = 0xC0230008, |
| 5419 | |||
| 5420 | /// The multicast list on the network interface is full. | 3688 | /// The multicast list on the network interface is full. |
| 5421 | NDIS_MULTICAST_FULL = 0xC0230009, | 3689 | NDIS_MULTICAST_FULL = 0xC0230009, |
| 5422 | |||
| 5423 | /// An attempt was made to add a duplicate multicast address to the list. | 3690 | /// An attempt was made to add a duplicate multicast address to the list. |
| 5424 | NDIS_MULTICAST_EXISTS = 0xC023000A, | 3691 | NDIS_MULTICAST_EXISTS = 0xC023000A, |
| 5425 | |||
| 5426 | /// At attempt was made to remove a multicast address that was never added. | 3692 | /// At attempt was made to remove a multicast address that was never added. |
| 5427 | NDIS_MULTICAST_NOT_FOUND = 0xC023000B, | 3693 | NDIS_MULTICAST_NOT_FOUND = 0xC023000B, |
| 5428 | |||
| 5429 | /// The network interface aborted the request. | 3694 | /// The network interface aborted the request. |
| 5430 | NDIS_REQUEST_ABORTED = 0xC023000C, | 3695 | NDIS_REQUEST_ABORTED = 0xC023000C, |
| 5431 | |||
| 5432 | /// The network interface cannot process the request because it is being reset. | 3696 | /// The network interface cannot process the request because it is being reset. |
| 5433 | NDIS_RESET_IN_PROGRESS = 0xC023000D, | 3697 | NDIS_RESET_IN_PROGRESS = 0xC023000D, |
| 5434 | |||
| 5435 | /// An attempt was made to send an invalid packet on a network interface. | 3698 | /// An attempt was made to send an invalid packet on a network interface. |
| 5436 | NDIS_INVALID_PACKET = 0xC023000F, | 3699 | NDIS_INVALID_PACKET = 0xC023000F, |
| 5437 | |||
| 5438 | /// The specified request is not a valid operation for the target device. | 3700 | /// The specified request is not a valid operation for the target device. |
| 5439 | NDIS_INVALID_DEVICE_REQUEST = 0xC0230010, | 3701 | NDIS_INVALID_DEVICE_REQUEST = 0xC0230010, |
| 5440 | |||
| 5441 | /// The network interface is not ready to complete this operation. | 3702 | /// The network interface is not ready to complete this operation. |
| 5442 | NDIS_ADAPTER_NOT_READY = 0xC0230011, | 3703 | NDIS_ADAPTER_NOT_READY = 0xC0230011, |
| 5443 | |||
| 5444 | /// The length of the buffer submitted for this operation is not valid. | 3704 | /// The length of the buffer submitted for this operation is not valid. |
| 5445 | NDIS_INVALID_LENGTH = 0xC0230014, | 3705 | NDIS_INVALID_LENGTH = 0xC0230014, |
| 5446 | |||
| 5447 | /// The data used for this operation is not valid. | 3706 | /// The data used for this operation is not valid. |
| 5448 | NDIS_INVALID_DATA = 0xC0230015, | 3707 | NDIS_INVALID_DATA = 0xC0230015, |
| 5449 | |||
| 5450 | /// The length of the submitted buffer for this operation is too small. | 3708 | /// The length of the submitted buffer for this operation is too small. |
| 5451 | NDIS_BUFFER_TOO_SHORT = 0xC0230016, | 3709 | NDIS_BUFFER_TOO_SHORT = 0xC0230016, |
| 5452 | |||
| 5453 | /// The network interface does not support this object identifier. | 3710 | /// The network interface does not support this object identifier. |
| 5454 | NDIS_INVALID_OID = 0xC0230017, | 3711 | NDIS_INVALID_OID = 0xC0230017, |
| 5455 | |||
| 5456 | /// The network interface has been removed. | 3712 | /// The network interface has been removed. |
| 5457 | NDIS_ADAPTER_REMOVED = 0xC0230018, | 3713 | NDIS_ADAPTER_REMOVED = 0xC0230018, |
| 5458 | |||
| 5459 | /// The network interface does not support this media type. | 3714 | /// The network interface does not support this media type. |
| 5460 | NDIS_UNSUPPORTED_MEDIA = 0xC0230019, | 3715 | NDIS_UNSUPPORTED_MEDIA = 0xC0230019, |
| 5461 | |||
| 5462 | /// An attempt was made to remove a token ring group address that is in use by other components. | 3716 | /// An attempt was made to remove a token ring group address that is in use by other components. |
| 5463 | NDIS_GROUP_ADDRESS_IN_USE = 0xC023001A, | 3717 | NDIS_GROUP_ADDRESS_IN_USE = 0xC023001A, |
| 5464 | |||
| 5465 | /// An attempt was made to map a file that cannot be found. | 3718 | /// An attempt was made to map a file that cannot be found. |
| 5466 | NDIS_FILE_NOT_FOUND = 0xC023001B, | 3719 | NDIS_FILE_NOT_FOUND = 0xC023001B, |
| 5467 | |||
| 5468 | /// An error occurred while NDIS tried to map the file. | 3720 | /// An error occurred while NDIS tried to map the file. |
| 5469 | NDIS_ERROR_READING_FILE = 0xC023001C, | 3721 | NDIS_ERROR_READING_FILE = 0xC023001C, |
| 5470 | |||
| 5471 | /// An attempt was made to map a file that is already mapped. | 3722 | /// An attempt was made to map a file that is already mapped. |
| 5472 | NDIS_ALREADY_MAPPED = 0xC023001D, | 3723 | NDIS_ALREADY_MAPPED = 0xC023001D, |
| 5473 | |||
| 5474 | /// An attempt to allocate a hardware resource failed because the resource is used by another component. | 3724 | /// An attempt to allocate a hardware resource failed because the resource is used by another component. |
| 5475 | NDIS_RESOURCE_CONFLICT = 0xC023001E, | 3725 | NDIS_RESOURCE_CONFLICT = 0xC023001E, |
| 5476 | |||
| 5477 | /// The I/O operation failed because the network media is disconnected or the wireless access point is out of range. | 3726 | /// The I/O operation failed because the network media is disconnected or the wireless access point is out of range. |
| 5478 | NDIS_MEDIA_DISCONNECTED = 0xC023001F, | 3727 | NDIS_MEDIA_DISCONNECTED = 0xC023001F, |
| 5479 | |||
| 5480 | /// The network address used in the request is invalid. | 3728 | /// The network address used in the request is invalid. |
| 5481 | NDIS_INVALID_ADDRESS = 0xC0230022, | 3729 | NDIS_INVALID_ADDRESS = 0xC0230022, |
| 5482 | |||
| 5483 | /// The offload operation on the network interface has been paused. | 3730 | /// The offload operation on the network interface has been paused. |
| 5484 | NDIS_PAUSED = 0xC023002A, | 3731 | NDIS_PAUSED = 0xC023002A, |
| 5485 | |||
| 5486 | /// The network interface was not found. | 3732 | /// The network interface was not found. |
| 5487 | NDIS_INTERFACE_NOT_FOUND = 0xC023002B, | 3733 | NDIS_INTERFACE_NOT_FOUND = 0xC023002B, |
| 5488 | |||
| 5489 | /// The revision number specified in the structure is not supported. | 3734 | /// The revision number specified in the structure is not supported. |
| 5490 | NDIS_UNSUPPORTED_REVISION = 0xC023002C, | 3735 | NDIS_UNSUPPORTED_REVISION = 0xC023002C, |
| 5491 | |||
| 5492 | /// The specified port does not exist on this network interface. | 3736 | /// The specified port does not exist on this network interface. |
| 5493 | NDIS_INVALID_PORT = 0xC023002D, | 3737 | NDIS_INVALID_PORT = 0xC023002D, |
| 5494 | |||
| 5495 | /// The current state of the specified port on this network interface does not support the requested operation. | 3738 | /// The current state of the specified port on this network interface does not support the requested operation. |
| 5496 | NDIS_INVALID_PORT_STATE = 0xC023002E, | 3739 | NDIS_INVALID_PORT_STATE = 0xC023002E, |
| 5497 | |||
| 5498 | /// The miniport adapter is in a lower power state. | 3740 | /// The miniport adapter is in a lower power state. |
| 5499 | NDIS_LOW_POWER_STATE = 0xC023002F, | 3741 | NDIS_LOW_POWER_STATE = 0xC023002F, |
| 5500 | |||
| 5501 | /// The network interface does not support this request. | 3742 | /// The network interface does not support this request. |
| 5502 | NDIS_NOT_SUPPORTED = 0xC02300BB, | 3743 | NDIS_NOT_SUPPORTED = 0xC02300BB, |
| 5503 | |||
| 5504 | /// The TCP connection is not offloadable because of a local policy setting. | 3744 | /// The TCP connection is not offloadable because of a local policy setting. |
| 5505 | NDIS_OFFLOAD_POLICY = 0xC023100F, | 3745 | NDIS_OFFLOAD_POLICY = 0xC023100F, |
| 5506 | |||
| 5507 | /// The TCP connection is not offloadable by the Chimney offload target. | 3746 | /// The TCP connection is not offloadable by the Chimney offload target. |
| 5508 | NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012, | 3747 | NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012, |
| 5509 | |||
| 5510 | /// The IP Path object is not in an offloadable state. | 3748 | /// The IP Path object is not in an offloadable state. |
| 5511 | NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013, | 3749 | NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013, |
| 5512 | |||
| 5513 | /// The wireless LAN interface is in auto-configuration mode and does not support the requested parameter change operation. | 3750 | /// The wireless LAN interface is in auto-configuration mode and does not support the requested parameter change operation. |
| 5514 | NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000, | 3751 | NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000, |
| 5515 | |||
| 5516 | /// The wireless LAN interface is busy and cannot perform the requested operation. | 3752 | /// The wireless LAN interface is busy and cannot perform the requested operation. |
| 5517 | NDIS_DOT11_MEDIA_IN_USE = 0xC0232001, | 3753 | NDIS_DOT11_MEDIA_IN_USE = 0xC0232001, |
| 5518 | |||
| 5519 | /// The wireless LAN interface is power down and does not support the requested operation. | 3754 | /// The wireless LAN interface is power down and does not support the requested operation. |
| 5520 | NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002, | 3755 | NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002, |
| 5521 | |||
| 5522 | /// The list of wake on LAN patterns is full. | 3756 | /// The list of wake on LAN patterns is full. |
| 5523 | NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003, | 3757 | NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003, |
| 5524 | |||
| 5525 | /// The list of low power protocol offloads is full. | 3758 | /// The list of low power protocol offloads is full. |
| 5526 | NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004, | 3759 | NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004, |
| 5527 | |||
| 5528 | /// The SPI in the packet does not match a valid IPsec SA. | 3760 | /// The SPI in the packet does not match a valid IPsec SA. |
| 5529 | IPSEC_BAD_SPI = 0xC0360001, | 3761 | IPSEC_BAD_SPI = 0xC0360001, |
| 5530 | |||
| 5531 | /// The packet was received on an IPsec SA whose lifetime has expired. | 3762 | /// The packet was received on an IPsec SA whose lifetime has expired. |
| 5532 | IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002, | 3763 | IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002, |
| 5533 | |||
| 5534 | /// The packet was received on an IPsec SA that does not match the packet characteristics. | 3764 | /// The packet was received on an IPsec SA that does not match the packet characteristics. |
| 5535 | IPSEC_WRONG_SA = 0xC0360003, | 3765 | IPSEC_WRONG_SA = 0xC0360003, |
| 5536 | |||
| 5537 | /// The packet sequence number replay check failed. | 3766 | /// The packet sequence number replay check failed. |
| 5538 | IPSEC_REPLAY_CHECK_FAILED = 0xC0360004, | 3767 | IPSEC_REPLAY_CHECK_FAILED = 0xC0360004, |
| 5539 | |||
| 5540 | /// The IPsec header and/or trailer in the packet is invalid. | 3768 | /// The IPsec header and/or trailer in the packet is invalid. |
| 5541 | IPSEC_INVALID_PACKET = 0xC0360005, | 3769 | IPSEC_INVALID_PACKET = 0xC0360005, |
| 5542 | |||
| 5543 | /// The IPsec integrity check failed. | 3770 | /// The IPsec integrity check failed. |
| 5544 | IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006, | 3771 | IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006, |
| 5545 | |||
| 5546 | /// IPsec dropped a clear text packet. | 3772 | /// IPsec dropped a clear text packet. |
| 5547 | IPSEC_CLEAR_TEXT_DROP = 0xC0360007, | 3773 | IPSEC_CLEAR_TEXT_DROP = 0xC0360007, |
| 5548 | |||
| 5549 | /// IPsec dropped an incoming ESP packet in authenticated firewall mode. This drop is benign. | 3774 | /// IPsec dropped an incoming ESP packet in authenticated firewall mode. This drop is benign. |
| 5550 | IPSEC_AUTH_FIREWALL_DROP = 0xC0360008, | 3775 | IPSEC_AUTH_FIREWALL_DROP = 0xC0360008, |
| 5551 | |||
| 5552 | /// IPsec dropped a packet due to DOS throttle. | 3776 | /// IPsec dropped a packet due to DOS throttle. |
| 5553 | IPSEC_THROTTLE_DROP = 0xC0360009, | 3777 | IPSEC_THROTTLE_DROP = 0xC0360009, |
| 5554 | |||
| 5555 | /// IPsec Dos Protection matched an explicit block rule. | 3778 | /// IPsec Dos Protection matched an explicit block rule. |
| 5556 | IPSEC_DOSP_BLOCK = 0xC0368000, | 3779 | IPSEC_DOSP_BLOCK = 0xC0368000, |
| 5557 | |||
| 5558 | /// IPsec Dos Protection received an IPsec specific multicast packet which is not allowed. | 3780 | /// IPsec Dos Protection received an IPsec specific multicast packet which is not allowed. |
| 5559 | IPSEC_DOSP_RECEIVED_MULTICAST = 0xC0368001, | 3781 | IPSEC_DOSP_RECEIVED_MULTICAST = 0xC0368001, |
| 5560 | |||
| 5561 | /// IPsec Dos Protection received an incorrectly formatted packet. | 3782 | /// IPsec Dos Protection received an incorrectly formatted packet. |
| 5562 | IPSEC_DOSP_INVALID_PACKET = 0xC0368002, | 3783 | IPSEC_DOSP_INVALID_PACKET = 0xC0368002, |
| 5563 | |||
| 5564 | /// IPsec Dos Protection failed to lookup state. | 3784 | /// IPsec Dos Protection failed to lookup state. |
| 5565 | IPSEC_DOSP_STATE_LOOKUP_FAILED = 0xC0368003, | 3785 | IPSEC_DOSP_STATE_LOOKUP_FAILED = 0xC0368003, |
| 5566 | |||
| 5567 | /// IPsec Dos Protection failed to create state because there are already maximum number of entries allowed by policy. | 3786 | /// IPsec Dos Protection failed to create state because there are already maximum number of entries allowed by policy. |
| 5568 | IPSEC_DOSP_MAX_ENTRIES = 0xC0368004, | 3787 | IPSEC_DOSP_MAX_ENTRIES = 0xC0368004, |
| 5569 | |||
| 5570 | /// IPsec Dos Protection received an IPsec negotiation packet for a keying module which is not allowed by policy. | 3788 | /// IPsec Dos Protection received an IPsec negotiation packet for a keying module which is not allowed by policy. |
| 5571 | IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 0xC0368005, | 3789 | IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 0xC0368005, |
| 5572 | |||
| 5573 | /// IPsec Dos Protection failed to create per internal IP ratelimit queue because there is already maximum number of queues allowed by policy. | 3790 | /// IPsec Dos Protection failed to create per internal IP ratelimit queue because there is already maximum number of queues allowed by policy. |
| 5574 | IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 0xC0368006, | 3791 | IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 0xC0368006, |
| 5575 | |||
| 5576 | /// The system does not support mirrored volumes. | 3792 | /// The system does not support mirrored volumes. |
| 5577 | VOLMGR_MIRROR_NOT_SUPPORTED = 0xC038005B, | 3793 | VOLMGR_MIRROR_NOT_SUPPORTED = 0xC038005B, |
| 5578 | |||
| 5579 | /// The system does not support RAID-5 volumes. | 3794 | /// The system does not support RAID-5 volumes. |
| 5580 | VOLMGR_RAID5_NOT_SUPPORTED = 0xC038005C, | 3795 | VOLMGR_RAID5_NOT_SUPPORTED = 0xC038005C, |
| 5581 | |||
| 5582 | /// A virtual disk support provider for the specified file was not found. | 3796 | /// A virtual disk support provider for the specified file was not found. |
| 5583 | VIRTDISK_PROVIDER_NOT_FOUND = 0xC03A0014, | 3797 | VIRTDISK_PROVIDER_NOT_FOUND = 0xC03A0014, |
| 5584 | |||
| 5585 | /// The specified disk is not a virtual disk. | 3798 | /// The specified disk is not a virtual disk. |
| 5586 | VIRTDISK_NOT_VIRTUAL_DISK = 0xC03A0015, | 3799 | VIRTDISK_NOT_VIRTUAL_DISK = 0xC03A0015, |
| 5587 | |||
| 5588 | /// The chain of virtual hard disks is inaccessible. | 3800 | /// The chain of virtual hard disks is inaccessible. |
| 5589 | /// The process has not been granted access rights to the parent virtual hard disk for the differencing disk. | 3801 | /// The process has not been granted access rights to the parent virtual hard disk for the differencing disk. |
| 5590 | VHD_PARENT_VHD_ACCESS_DENIED = 0xC03A0016, | 3802 | VHD_PARENT_VHD_ACCESS_DENIED = 0xC03A0016, |
| 5591 | |||
| 5592 | /// The chain of virtual hard disks is corrupted. | 3803 | /// The chain of virtual hard disks is corrupted. |
| 5593 | /// There is a mismatch in the virtual sizes of the parent virtual hard disk and differencing disk. | 3804 | /// There is a mismatch in the virtual sizes of the parent virtual hard disk and differencing disk. |
| 5594 | VHD_CHILD_PARENT_SIZE_MISMATCH = 0xC03A0017, | 3805 | VHD_CHILD_PARENT_SIZE_MISMATCH = 0xC03A0017, |
| 5595 | |||
| 5596 | /// The chain of virtual hard disks is corrupted. | 3806 | /// The chain of virtual hard disks is corrupted. |
| 5597 | /// A differencing disk is indicated in its own parent chain. | 3807 | /// A differencing disk is indicated in its own parent chain. |
| 5598 | VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED = 0xC03A0018, | 3808 | VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED = 0xC03A0018, |
| 5599 | |||
| 5600 | /// The chain of virtual hard disks is inaccessible. | 3809 | /// The chain of virtual hard disks is inaccessible. |
| 5601 | /// There was an error opening a virtual hard disk further up the chain. | 3810 | /// There was an error opening a virtual hard disk further up the chain. |
| 5602 | VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT = 0xC03A0019, | 3811 | VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT = 0xC03A0019, |
| 5603 | |||
| 5604 | _, | 3812 | _, |
| 5605 | }; | 3813 | }; |
lib/std/os/windows/user32.zig+1-1| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | usingnamespace @import("bits.zig"); | 6 | usingnamespace @import("bits.zig"); |
| 7 | const std = @import("std"); | 7 | const std = @import("std"); |
| 8 | const builtin = @import("builtin"); | 8 | const builtin = std.builtin; |
| 9 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| 10 | const windows = @import("../windows.zig"); | 10 | const windows = @import("../windows.zig"); |
| 11 | const unexpectedError = windows.unexpectedError; | 11 | const unexpectedError = windows.unexpectedError; |
lib/std/os/windows/win32error.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | // Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d | 6 | // Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d |
| 7 | pub const Win32Error = extern enum(u16) { | 7 | pub const Win32Error = enum(u16) { |
| 8 | /// The operation completed successfully. | 8 | /// The operation completed successfully. |
| 9 | SUCCESS = 0, | 9 | SUCCESS = 0, |
| 10 | 10 |
lib/std/os/windows/ws2_32.zig+1-1| ... | @@ -1209,7 +1209,7 @@ pub const hostent = extern struct { | ... | @@ -1209,7 +1209,7 @@ pub const hostent = extern struct { |
| 1209 | }; | 1209 | }; |
| 1210 | 1210 | ||
| 1211 | // https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2 | 1211 | // https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2 |
| 1212 | pub const WinsockError = extern enum(u16) { | 1212 | pub const WinsockError = enum(u16) { |
| 1213 | /// Specified event object handle is invalid. | 1213 | /// Specified event object handle is invalid. |
| 1214 | /// An application attempts to use an event object, but the specified handle is not valid. | 1214 | /// An application attempts to use an event object, but the specified handle is not valid. |
| 1215 | WSA_INVALID_HANDLE = 6, | 1215 | WSA_INVALID_HANDLE = 6, |
lib/std/packed_int_array.zig+22-20| ... | @@ -7,8 +7,10 @@ const std = @import("std"); | ... | @@ -7,8 +7,10 @@ const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const debug = std.debug; | 8 | const debug = std.debug; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 11 | const Endian = std.builtin.Endian; | ||
| 10 | 12 | ||
| 11 | pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | 13 | pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type { |
| 12 | //The general technique employed here is to cast bytes in the array to a container | 14 | //The general technique employed here is to cast bytes in the array to a container |
| 13 | // integer (having bits % 8 == 0) large enough to contain the number of bits we want, | 15 | // integer (having bits % 8 == 0) large enough to contain the number of bits we want, |
| 14 | // then we can retrieve or store the new value with a relative minimum of masking | 16 | // then we can retrieve or store the new value with a relative minimum of masking |
| ... | @@ -71,7 +73,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | ... | @@ -71,7 +73,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { |
| 71 | const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]); | 73 | const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]); |
| 72 | var value = value_ptr.*; | 74 | var value = value_ptr.*; |
| 73 | 75 | ||
| 74 | if (endian != builtin.endian) value = @byteSwap(Container, value); | 76 | if (endian != native_endian) value = @byteSwap(Container, value); |
| 75 | 77 | ||
| 76 | switch (endian) { | 78 | switch (endian) { |
| 77 | .Big => { | 79 | .Big => { |
| ... | @@ -119,7 +121,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | ... | @@ -119,7 +121,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { |
| 119 | const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]); | 121 | const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]); |
| 120 | var target = target_ptr.*; | 122 | var target = target_ptr.*; |
| 121 | 123 | ||
| 122 | if (endian != builtin.endian) target = @byteSwap(Container, target); | 124 | if (endian != native_endian) target = @byteSwap(Container, target); |
| 123 | 125 | ||
| 124 | //zero the bits we want to replace in the existing bytes | 126 | //zero the bits we want to replace in the existing bytes |
| 125 | const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift; | 127 | const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift; |
| ... | @@ -129,7 +131,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | ... | @@ -129,7 +131,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { |
| 129 | //merge the new value | 131 | //merge the new value |
| 130 | target |= value; | 132 | target |= value; |
| 131 | 133 | ||
| 132 | if (endian != builtin.endian) target = @byteSwap(Container, target); | 134 | if (endian != native_endian) target = @byteSwap(Container, target); |
| 133 | 135 | ||
| 134 | //save it back | 136 | //save it back |
| 135 | target_ptr.* = target; | 137 | target_ptr.* = target; |
| ... | @@ -151,7 +153,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | ... | @@ -151,7 +153,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { |
| 151 | return new_slice; | 153 | return new_slice; |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: builtin.Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) { | 156 | fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) { |
| 155 | const new_int_bits = comptime std.meta.bitCount(NewInt); | 157 | const new_int_bits = comptime std.meta.bitCount(NewInt); |
| 156 | const New = PackedIntSliceEndian(NewInt, new_endian); | 158 | const New = PackedIntSliceEndian(NewInt, new_endian); |
| 157 | 159 | ||
| ... | @@ -172,13 +174,13 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { | ... | @@ -172,13 +174,13 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { |
| 172 | /// are packed using native endianess and without storing any meta | 174 | /// are packed using native endianess and without storing any meta |
| 173 | /// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory. | 175 | /// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory. |
| 174 | pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type { | 176 | pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type { |
| 175 | return PackedIntArrayEndian(Int, builtin.endian, int_count); | 177 | return PackedIntArrayEndian(Int, native_endian, int_count); |
| 176 | } | 178 | } |
| 177 | 179 | ||
| 178 | ///Creates a bit-packed array of integers of type Int. Bits | 180 | ///Creates a bit-packed array of integers of type Int. Bits |
| 179 | /// are packed using specified endianess and without storing any meta | 181 | /// are packed using specified endianess and without storing any meta |
| 180 | /// data. | 182 | /// data. |
| 181 | pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, comptime int_count: usize) type { | 183 | pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptime int_count: usize) type { |
| 182 | const int_bits = comptime std.meta.bitCount(Int); | 184 | const int_bits = comptime std.meta.bitCount(Int); |
| 183 | const total_bits = int_bits * int_count; | 185 | const total_bits = int_bits * int_count; |
| 184 | const total_bytes = (total_bits + 7) / 8; | 186 | const total_bytes = (total_bits + 7) / 8; |
| ... | @@ -247,7 +249,7 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, | ... | @@ -247,7 +249,7 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, |
| 247 | ///Create a PackedIntSlice of the array using NewInt as the bit width integer | 249 | ///Create a PackedIntSlice of the array using NewInt as the bit width integer |
| 248 | /// and new_endian as the new endianess. NewInt's bit width must fit evenly within | 250 | /// and new_endian as the new endianess. NewInt's bit width must fit evenly within |
| 249 | /// the array's Int's total bits. | 251 | /// the array's Int's total bits. |
| 250 | pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian) { | 252 | pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) { |
| 251 | return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count); | 253 | return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count); |
| 252 | } | 254 | } |
| 253 | }; | 255 | }; |
| ... | @@ -257,13 +259,13 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, | ... | @@ -257,13 +259,13 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian, |
| 257 | /// Bits are packed using native endianess and without storing any meta | 259 | /// Bits are packed using native endianess and without storing any meta |
| 258 | /// data. | 260 | /// data. |
| 259 | pub fn PackedIntSlice(comptime Int: type) type { | 261 | pub fn PackedIntSlice(comptime Int: type) type { |
| 260 | return PackedIntSliceEndian(Int, builtin.endian); | 262 | return PackedIntSliceEndian(Int, native_endian); |
| 261 | } | 263 | } |
| 262 | 264 | ||
| 263 | ///Uses a slice as a bit-packed block of int_count integers of type Int. | 265 | ///Uses a slice as a bit-packed block of int_count integers of type Int. |
| 264 | /// Bits are packed using specified endianess and without storing any meta | 266 | /// Bits are packed using specified endianess and without storing any meta |
| 265 | /// data. | 267 | /// data. |
| 266 | pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) type { | 268 | pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: Endian) type { |
| 267 | const int_bits = comptime std.meta.bitCount(Int); | 269 | const int_bits = comptime std.meta.bitCount(Int); |
| 268 | const Io = PackedIntIo(Int, endian); | 270 | const Io = PackedIntIo(Int, endian); |
| 269 | 271 | ||
| ... | @@ -328,7 +330,7 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) | ... | @@ -328,7 +330,7 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) |
| 328 | ///Create a PackedIntSlice of this slice using NewInt as the bit width integer | 330 | ///Create a PackedIntSlice of this slice using NewInt as the bit width integer |
| 329 | /// and new_endian as the new endianess. NewInt's bit width must fit evenly within | 331 | /// and new_endian as the new endianess. NewInt's bit width must fit evenly within |
| 330 | /// this slice's Int's total bits. | 332 | /// this slice's Int's total bits. |
| 331 | pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian) { | 333 | pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) { |
| 332 | return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.int_count); | 334 | return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.int_count); |
| 333 | } | 335 | } |
| 334 | }; | 336 | }; |
| ... | @@ -338,7 +340,7 @@ const we_are_testing_this_with_stage1_which_leaks_comptime_memory = true; | ... | @@ -338,7 +340,7 @@ const we_are_testing_this_with_stage1_which_leaks_comptime_memory = true; |
| 338 | 340 | ||
| 339 | test "PackedIntArray" { | 341 | test "PackedIntArray" { |
| 340 | // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. | 342 | // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. |
| 341 | if (builtin.arch == .wasm32) return error.SkipZigTest; | 343 | if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; |
| 342 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; | 344 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 343 | 345 | ||
| 344 | @setEvalBranchQuota(10000); | 346 | @setEvalBranchQuota(10000); |
| ... | @@ -348,7 +350,7 @@ test "PackedIntArray" { | ... | @@ -348,7 +350,7 @@ test "PackedIntArray" { |
| 348 | comptime var bits = 0; | 350 | comptime var bits = 0; |
| 349 | inline while (bits <= max_bits) : (bits += 1) { | 351 | inline while (bits <= max_bits) : (bits += 1) { |
| 350 | //alternate unsigned and signed | 352 | //alternate unsigned and signed |
| 351 | const sign: builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned; | 353 | const sign: std.builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned; |
| 352 | const I = std.meta.Int(sign, bits); | 354 | const I = std.meta.Int(sign, bits); |
| 353 | 355 | ||
| 354 | const PackedArray = PackedIntArray(I, int_count); | 356 | const PackedArray = PackedIntArray(I, int_count); |
| ... | @@ -394,7 +396,7 @@ test "PackedIntArray initAllTo" { | ... | @@ -394,7 +396,7 @@ test "PackedIntArray initAllTo" { |
| 394 | 396 | ||
| 395 | test "PackedIntSlice" { | 397 | test "PackedIntSlice" { |
| 396 | // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. | 398 | // TODO @setEvalBranchQuota generates panics in wasm32. Investigate. |
| 397 | if (builtin.arch == .wasm32) return error.SkipZigTest; | 399 | if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; |
| 398 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; | 400 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 399 | 401 | ||
| 400 | @setEvalBranchQuota(10000); | 402 | @setEvalBranchQuota(10000); |
| ... | @@ -408,7 +410,7 @@ test "PackedIntSlice" { | ... | @@ -408,7 +410,7 @@ test "PackedIntSlice" { |
| 408 | comptime var bits = 0; | 410 | comptime var bits = 0; |
| 409 | inline while (bits <= max_bits) : (bits += 1) { | 411 | inline while (bits <= max_bits) : (bits += 1) { |
| 410 | //alternate unsigned and signed | 412 | //alternate unsigned and signed |
| 411 | const sign: builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned; | 413 | const sign: std.builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned; |
| 412 | const I = std.meta.Int(sign, bits); | 414 | const I = std.meta.Int(sign, bits); |
| 413 | const P = PackedIntSlice(I); | 415 | const P = PackedIntSlice(I); |
| 414 | 416 | ||
| ... | @@ -539,7 +541,7 @@ test "PackedInt(Array/Slice) sliceCast" { | ... | @@ -539,7 +541,7 @@ test "PackedInt(Array/Slice) sliceCast" { |
| 539 | 541 | ||
| 540 | var i = @as(usize, 0); | 542 | var i = @as(usize, 0); |
| 541 | while (i < packed_slice_cast_2.len()) : (i += 1) { | 543 | while (i < packed_slice_cast_2.len()) : (i += 1) { |
| 542 | const val = switch (builtin.endian) { | 544 | const val = switch (native_endian) { |
| 543 | .Big => 0b01, | 545 | .Big => 0b01, |
| 544 | .Little => 0b10, | 546 | .Little => 0b10, |
| 545 | }; | 547 | }; |
| ... | @@ -547,7 +549,7 @@ test "PackedInt(Array/Slice) sliceCast" { | ... | @@ -547,7 +549,7 @@ test "PackedInt(Array/Slice) sliceCast" { |
| 547 | } | 549 | } |
| 548 | i = 0; | 550 | i = 0; |
| 549 | while (i < packed_slice_cast_4.len()) : (i += 1) { | 551 | while (i < packed_slice_cast_4.len()) : (i += 1) { |
| 550 | const val = switch (builtin.endian) { | 552 | const val = switch (native_endian) { |
| 551 | .Big => 0b0101, | 553 | .Big => 0b0101, |
| 552 | .Little => 0b1010, | 554 | .Little => 0b1010, |
| 553 | }; | 555 | }; |
| ... | @@ -561,7 +563,7 @@ test "PackedInt(Array/Slice) sliceCast" { | ... | @@ -561,7 +563,7 @@ test "PackedInt(Array/Slice) sliceCast" { |
| 561 | } | 563 | } |
| 562 | i = 0; | 564 | i = 0; |
| 563 | while (i < packed_slice_cast_3.len()) : (i += 1) { | 565 | while (i < packed_slice_cast_3.len()) : (i += 1) { |
| 564 | const val = switch (builtin.endian) { | 566 | const val = switch (native_endian) { |
| 565 | .Big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), | 567 | .Big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), |
| 566 | .Little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), | 568 | .Little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), |
| 567 | }; | 569 | }; |
| ... | @@ -641,7 +643,7 @@ test "PackedInt(Array/Slice)Endian" { | ... | @@ -641,7 +643,7 @@ test "PackedInt(Array/Slice)Endian" { |
| 641 | test "PackedIntArray at end of available memory" { | 643 | test "PackedIntArray at end of available memory" { |
| 642 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; | 644 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 643 | 645 | ||
| 644 | switch (builtin.os.tag) { | 646 | switch (builtin.target.os.tag) { |
| 645 | .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, | 647 | .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, |
| 646 | else => return, | 648 | else => return, |
| 647 | } | 649 | } |
| ... | @@ -662,7 +664,7 @@ test "PackedIntArray at end of available memory" { | ... | @@ -662,7 +664,7 @@ test "PackedIntArray at end of available memory" { |
| 662 | test "PackedIntSlice at end of available memory" { | 664 | test "PackedIntSlice at end of available memory" { |
| 663 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; | 665 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 664 | 666 | ||
| 665 | switch (builtin.os.tag) { | 667 | switch (builtin.target.os.tag) { |
| 666 | .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, | 668 | .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, |
| 667 | else => return, | 669 | else => return, |
| 668 | } | 670 | } |
lib/std/pdb.zig+3-3| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | const std = @import("std.zig"); | 7 | const std = @import("std.zig"); |
| 8 | const io = std.io; | 8 | const io = std.io; |
| 9 | const math = std.math; | 9 | const math = std.math; |
| ... | @@ -115,7 +115,7 @@ pub const StreamType = enum(u16) { | ... | @@ -115,7 +115,7 @@ pub const StreamType = enum(u16) { |
| 115 | 115 | ||
| 116 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful | 116 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful |
| 117 | /// for reference purposes and when dealing with unknown record types. | 117 | /// for reference purposes and when dealing with unknown record types. |
| 118 | pub const SymbolKind = packed enum(u16) { | 118 | pub const SymbolKind = enum(u16) { |
| 119 | S_COMPILE = 1, | 119 | S_COMPILE = 1, |
| 120 | S_REGISTER_16t = 2, | 120 | S_REGISTER_16t = 2, |
| 121 | S_CONSTANT_16t = 3, | 121 | S_CONSTANT_16t = 3, |
| ... | @@ -426,7 +426,7 @@ pub const FileChecksumEntryHeader = packed struct { | ... | @@ -426,7 +426,7 @@ pub const FileChecksumEntryHeader = packed struct { |
| 426 | ChecksumKind: u8, | 426 | ChecksumKind: u8, |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | pub const DebugSubsectionKind = packed enum(u32) { | 429 | pub const DebugSubsectionKind = enum(u32) { |
| 430 | None = 0, | 430 | None = 0, |
| 431 | Symbols = 0xf1, | 431 | Symbols = 0xf1, |
| 432 | Lines = 0xf2, | 432 | Lines = 0xf2, |
lib/std/rand.zig+1-1| ... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
| 13 | //! TODO(tiehuis): Benchmark these against other reference implementations. | 13 | //! TODO(tiehuis): Benchmark these against other reference implementations. |
| 14 | 14 | ||
| 15 | const std = @import("std.zig"); | 15 | const std = @import("std.zig"); |
| 16 | const builtin = @import("builtin"); | 16 | const builtin = std.builtin; |
| 17 | const assert = std.debug.assert; | 17 | const assert = std.debug.assert; |
| 18 | const expect = std.testing.expect; | 18 | const expect = std.testing.expect; |
| 19 | const expectEqual = std.testing.expectEqual; | 19 | const expectEqual = std.testing.expectEqual; |
lib/std/sort.zig+1-1| ... | @@ -8,7 +8,7 @@ const assert = std.debug.assert; | ... | @@ -8,7 +8,7 @@ const assert = std.debug.assert; |
| 8 | const testing = std.testing; | 8 | const testing = std.testing; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const builtin = @import("builtin"); | 11 | const builtin = std.builtin; |
| 12 | 12 | ||
| 13 | pub fn binarySearch( | 13 | pub fn binarySearch( |
| 14 | comptime T: type, | 14 | comptime T: type, |
lib/std/special/c.zig+10-7| ... | @@ -10,19 +10,22 @@ | ... | @@ -10,19 +10,22 @@ |
| 10 | // such as memcpy, memset, and some math functions. | 10 | // such as memcpy, memset, and some math functions. |
| 11 | 11 | ||
| 12 | const std = @import("std"); | 12 | const std = @import("std"); |
| 13 | const builtin = @import("builtin"); | 13 | const builtin = std.builtin; |
| 14 | const maxInt = std.math.maxInt; | 14 | const maxInt = std.math.maxInt; |
| 15 | const isNan = std.math.isNan; | 15 | const isNan = std.math.isNan; |
| 16 | const native_arch = std.Target.current.cpu.arch; | ||
| 17 | const native_abi = std.Target.current.abi; | ||
| 18 | const native_os = std.Target.current.os.tag; | ||
| 16 | 19 | ||
| 17 | const is_wasm = switch (builtin.arch) { | 20 | const is_wasm = switch (native_arch) { |
| 18 | .wasm32, .wasm64 => true, | 21 | .wasm32, .wasm64 => true, |
| 19 | else => false, | 22 | else => false, |
| 20 | }; | 23 | }; |
| 21 | const is_msvc = switch (builtin.abi) { | 24 | const is_msvc = switch (native_abi) { |
| 22 | .msvc => true, | 25 | .msvc => true, |
| 23 | else => false, | 26 | else => false, |
| 24 | }; | 27 | }; |
| 25 | const is_freestanding = switch (builtin.os.tag) { | 28 | const is_freestanding = switch (native_os) { |
| 26 | .freestanding => true, | 29 | .freestanding => true, |
| 27 | else => false, | 30 | else => false, |
| 28 | }; | 31 | }; |
| ... | @@ -174,7 +177,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn | ... | @@ -174,7 +177,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn |
| 174 | @setCold(true); | 177 | @setCold(true); |
| 175 | std.debug.panic("{s}", .{msg}); | 178 | std.debug.panic("{s}", .{msg}); |
| 176 | } | 179 | } |
| 177 | if (builtin.os.tag != .freestanding and builtin.os.tag != .other) { | 180 | if (native_os != .freestanding and native_os != .other) { |
| 178 | std.os.abort(); | 181 | std.os.abort(); |
| 179 | } | 182 | } |
| 180 | while (true) {} | 183 | while (true) {} |
| ... | @@ -275,7 +278,7 @@ test "bcmp" { | ... | @@ -275,7 +278,7 @@ test "bcmp" { |
| 275 | } | 278 | } |
| 276 | 279 | ||
| 277 | comptime { | 280 | comptime { |
| 278 | if (builtin.os.tag == .linux) { | 281 | if (native_os == .linux) { |
| 279 | @export(clone, .{ .name = "clone" }); | 282 | @export(clone, .{ .name = "clone" }); |
| 280 | } | 283 | } |
| 281 | } | 284 | } |
| ... | @@ -284,7 +287,7 @@ comptime { | ... | @@ -284,7 +287,7 @@ comptime { |
| 284 | // it causes a segfault in release mode. this is a workaround of calling it | 287 | // it causes a segfault in release mode. this is a workaround of calling it |
| 285 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. | 288 | // across .o file boundaries. fix comptime @ptrCast of nakedcc functions. |
| 286 | fn clone() callconv(.Naked) void { | 289 | fn clone() callconv(.Naked) void { |
| 287 | switch (builtin.arch) { | 290 | switch (native_arch) { |
| 288 | .i386 => { | 291 | .i386 => { |
| 289 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | 292 | // __clone(func, stack, flags, arg, ptid, tls, ctid) |
| 290 | // +8, +12, +16, +20, +24, +28, +32 | 293 | // +8, +12, +16, +20, +24, +28, +32 |
lib/std/special/compiler_rt.zig+13-10| ... | @@ -6,15 +6,18 @@ | ... | @@ -6,15 +6,18 @@ |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | 7 | const builtin = std.builtin; |
| 8 | const is_test = builtin.is_test; | 8 | const is_test = builtin.is_test; |
| 9 | const os_tag = std.Target.current.os.tag; | ||
| 10 | const arch = std.Target.current.cpu.arch; | ||
| 11 | const abi = std.Target.current.abi; | ||
| 9 | 12 | ||
| 10 | const is_gnu = std.Target.current.abi.isGnu(); | 13 | const is_gnu = abi.isGnu(); |
| 11 | const is_mingw = builtin.os.tag == .windows and is_gnu; | 14 | const is_mingw = os_tag == .windows and is_gnu; |
| 12 | 15 | ||
| 13 | comptime { | 16 | comptime { |
| 14 | const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; | 17 | const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; |
| 15 | const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; | 18 | const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; |
| 16 | 19 | ||
| 17 | switch (builtin.arch) { | 20 | switch (arch) { |
| 18 | .i386, | 21 | .i386, |
| 19 | .x86_64, | 22 | .x86_64, |
| 20 | => @export(@import("compiler_rt/stack_probe.zig").zig_probe_stack, .{ | 23 | => @export(@import("compiler_rt/stack_probe.zig").zig_probe_stack, .{ |
| ... | @@ -169,11 +172,11 @@ comptime { | ... | @@ -169,11 +172,11 @@ comptime { |
| 169 | 172 | ||
| 170 | @export(@import("compiler_rt/clzsi2.zig").__clzsi2, .{ .name = "__clzsi2", .linkage = linkage }); | 173 | @export(@import("compiler_rt/clzsi2.zig").__clzsi2, .{ .name = "__clzsi2", .linkage = linkage }); |
| 171 | 174 | ||
| 172 | if (builtin.link_libc and builtin.os.tag == .openbsd) { | 175 | if (builtin.link_libc and os_tag == .openbsd) { |
| 173 | @export(@import("compiler_rt/emutls.zig").__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = linkage }); | 176 | @export(@import("compiler_rt/emutls.zig").__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = linkage }); |
| 174 | } | 177 | } |
| 175 | 178 | ||
| 176 | if ((builtin.arch.isARM() or builtin.arch.isThumb()) and !is_test) { | 179 | if ((arch.isARM() or arch.isThumb()) and !is_test) { |
| 177 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage }); | 180 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage }); |
| 178 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage }); | 181 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage }); |
| 179 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage }); | 182 | @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage }); |
| ... | @@ -204,7 +207,7 @@ comptime { | ... | @@ -204,7 +207,7 @@ comptime { |
| 204 | @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage }); | 207 | @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage }); |
| 205 | @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage }); | 208 | @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage }); |
| 206 | 209 | ||
| 207 | if (builtin.os.tag == .linux) { | 210 | if (os_tag == .linux) { |
| 208 | @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage }); | 211 | @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage }); |
| 209 | } | 212 | } |
| 210 | 213 | ||
| ... | @@ -271,7 +274,7 @@ comptime { | ... | @@ -271,7 +274,7 @@ comptime { |
| 271 | @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage }); | 274 | @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage }); |
| 272 | } | 275 | } |
| 273 | 276 | ||
| 274 | if (builtin.arch == .i386 and builtin.abi == .msvc) { | 277 | if (arch == .i386 and abi == .msvc) { |
| 275 | // Don't let LLVM apply the stdcall name mangling on those MSVC builtins | 278 | // Don't let LLVM apply the stdcall name mangling on those MSVC builtins |
| 276 | @export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage }); | 279 | @export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage }); |
| 277 | @export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage }); | 280 | @export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage }); |
| ... | @@ -279,7 +282,7 @@ comptime { | ... | @@ -279,7 +282,7 @@ comptime { |
| 279 | @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage }); | 282 | @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage }); |
| 280 | } | 283 | } |
| 281 | 284 | ||
| 282 | if (builtin.arch.isSPARC()) { | 285 | if (arch.isSPARC()) { |
| 283 | // SPARC systems use a different naming scheme | 286 | // SPARC systems use a different naming scheme |
| 284 | @export(@import("compiler_rt/sparc.zig")._Qp_add, .{ .name = "_Qp_add", .linkage = linkage }); | 287 | @export(@import("compiler_rt/sparc.zig")._Qp_add, .{ .name = "_Qp_add", .linkage = linkage }); |
| 285 | @export(@import("compiler_rt/sparc.zig")._Qp_div, .{ .name = "_Qp_div", .linkage = linkage }); | 288 | @export(@import("compiler_rt/sparc.zig")._Qp_div, .{ .name = "_Qp_div", .linkage = linkage }); |
| ... | @@ -308,7 +311,7 @@ comptime { | ... | @@ -308,7 +311,7 @@ comptime { |
| 308 | @export(@import("compiler_rt/sparc.zig")._Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage }); | 311 | @export(@import("compiler_rt/sparc.zig")._Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage }); |
| 309 | } | 312 | } |
| 310 | 313 | ||
| 311 | if ((builtin.arch == .powerpc or builtin.arch.isPPC64()) and !is_test) { | 314 | if ((arch == .powerpc or arch.isPPC64()) and !is_test) { |
| 312 | @export(@import("compiler_rt/addXf3.zig").__addtf3, .{ .name = "__addkf3", .linkage = linkage }); | 315 | @export(@import("compiler_rt/addXf3.zig").__addtf3, .{ .name = "__addkf3", .linkage = linkage }); |
| 313 | @export(@import("compiler_rt/addXf3.zig").__subtf3, .{ .name = "__subkf3", .linkage = linkage }); | 316 | @export(@import("compiler_rt/addXf3.zig").__subtf3, .{ .name = "__subkf3", .linkage = linkage }); |
| 314 | @export(@import("compiler_rt/mulXf3.zig").__multf3, .{ .name = "__mulkf3", .linkage = linkage }); | 317 | @export(@import("compiler_rt/mulXf3.zig").__multf3, .{ .name = "__mulkf3", .linkage = linkage }); |
| ... | @@ -346,7 +349,7 @@ comptime { | ... | @@ -346,7 +349,7 @@ comptime { |
| 346 | @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); | 349 | @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); |
| 347 | } | 350 | } |
| 348 | 351 | ||
| 349 | switch (builtin.arch) { | 352 | switch (arch) { |
| 350 | .i386 => { | 353 | .i386 => { |
| 351 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); | 354 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); |
| 352 | @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage }); | 355 | @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage }); |
lib/std/special/compiler_rt/atomics.zig+3-2| ... | @@ -5,6 +5,7 @@ | ... | @@ -5,6 +5,7 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | 7 | const builtin = std.builtin; |
| 8 | const arch = std.Target.current.cpu.arch; | ||
| 8 | 9 | ||
| 9 | const linkage: builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; | 10 | const linkage: builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; |
| 10 | 11 | ||
| ... | @@ -13,7 +14,7 @@ const linkage: builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak | ... | @@ -13,7 +14,7 @@ const linkage: builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak |
| 13 | // Some architectures support atomic load/stores but no CAS, but we ignore this | 14 | // Some architectures support atomic load/stores but no CAS, but we ignore this |
| 14 | // detail to keep the export logic clean and because we need some kind of CAS to | 15 | // detail to keep the export logic clean and because we need some kind of CAS to |
| 15 | // implement the spinlocks. | 16 | // implement the spinlocks. |
| 16 | const supports_atomic_ops = switch (builtin.arch) { | 17 | const supports_atomic_ops = switch (arch) { |
| 17 | .msp430, .avr => false, | 18 | .msp430, .avr => false, |
| 18 | .arm, .armeb, .thumb, .thumbeb => | 19 | .arm, .armeb, .thumb, .thumbeb => |
| 19 | // The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS | 20 | // The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS |
| ... | @@ -27,7 +28,7 @@ const supports_atomic_ops = switch (builtin.arch) { | ... | @@ -27,7 +28,7 @@ const supports_atomic_ops = switch (builtin.arch) { |
| 27 | // The size (in bytes) of the biggest object that the architecture can | 28 | // The size (in bytes) of the biggest object that the architecture can |
| 28 | // load/store atomically. | 29 | // load/store atomically. |
| 29 | // Objects bigger than this threshold require the use of a lock. | 30 | // Objects bigger than this threshold require the use of a lock. |
| 30 | const largest_atomic_size = switch (builtin.arch) { | 31 | const largest_atomic_size = switch (arch) { |
| 31 | // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b | 32 | // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b |
| 32 | // and set this parameter accordingly. | 33 | // and set this parameter accordingly. |
| 33 | else => @sizeOf(usize), | 34 | else => @sizeOf(usize), |
lib/std/special/compiler_rt/compareXf2.zig+7-5| ... | @@ -10,18 +10,20 @@ | ... | @@ -10,18 +10,20 @@ |
| 10 | const std = @import("std"); | 10 | const std = @import("std"); |
| 11 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 12 | 12 | ||
| 13 | const LE = extern enum(i32) { | 13 | const LE = enum(i32) { |
| 14 | Less = -1, | 14 | Less = -1, |
| 15 | Equal = 0, | 15 | Equal = 0, |
| 16 | Greater = 1, | 16 | Greater = 1, |
| 17 | Unordered = 1, | 17 | |
| 18 | const Unordered: LE = .Greater; | ||
| 18 | }; | 19 | }; |
| 19 | 20 | ||
| 20 | const GE = extern enum(i32) { | 21 | const GE = enum(i32) { |
| 21 | Less = -1, | 22 | Less = -1, |
| 22 | Equal = 0, | 23 | Equal = 0, |
| 23 | Greater = 1, | 24 | Greater = 1, |
| 24 | Unordered = -1, | 25 | |
| 26 | const Unordered: GE = .Less; | ||
| 25 | }; | 27 | }; |
| 26 | 28 | ||
| 27 | pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { | 29 | pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { |
| ... | @@ -43,7 +45,7 @@ pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { | ... | @@ -43,7 +45,7 @@ pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { |
| 43 | const bAbs = @bitCast(rep_t, bInt) & absMask; | 45 | const bAbs = @bitCast(rep_t, bInt) & absMask; |
| 44 | 46 | ||
| 45 | // If either a or b is NaN, they are unordered. | 47 | // If either a or b is NaN, they are unordered. |
| 46 | if (aAbs > infRep or bAbs > infRep) return .Unordered; | 48 | if (aAbs > infRep or bAbs > infRep) return RT.Unordered; |
| 47 | 49 | ||
| 48 | // If a and b are both zeros, they are equal. | 50 | // If a and b are both zeros, they are equal. |
| 49 | if ((aAbs | bAbs) == 0) return .Equal; | 51 | if ((aAbs | bAbs) == 0) return .Equal; |
lib/std/special/compiler_rt/extendXfYf2_test.zig+1-1| ... | @@ -96,7 +96,7 @@ test "extendhfsf2" { | ... | @@ -96,7 +96,7 @@ test "extendhfsf2" { |
| 96 | try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN | 96 | try test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN |
| 97 | // On x86 the NaN becomes quiet because the return is pushed on the x87 | 97 | // On x86 the NaN becomes quiet because the return is pushed on the x87 |
| 98 | // stack due to ABI requirements | 98 | // stack due to ABI requirements |
| 99 | if (builtin.arch != .i386 and builtin.os.tag == .windows) | 99 | if (builtin.target.cpu.arch != .i386 and builtin.target.os.tag == .windows) |
| 100 | try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN | 100 | try test__extendhfsf2(0x7c01, 0x7f802000); // sNaN |
| 101 | 101 | ||
| 102 | try test__extendhfsf2(0, 0); // 0 | 102 | try test__extendhfsf2(0, 0); // 0 |
lib/std/special/compiler_rt/muldi3.zig+6-4| ... | @@ -3,14 +3,16 @@ | ... | @@ -3,14 +3,16 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const std = @import("std"); |
| 7 | const is_test = std.builtin.is_test; | ||
| 8 | const native_endian = std.Target.current.cpu.arch.endian(); | ||
| 7 | 9 | ||
| 8 | // Ported from | 10 | // Ported from |
| 9 | // https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c | 11 | // https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c |
| 10 | 12 | ||
| 11 | const dwords = extern union { | 13 | const dwords = extern union { |
| 12 | all: i64, | 14 | all: i64, |
| 13 | s: switch (builtin.endian) { | 15 | s: switch (native_endian) { |
| 14 | .Little => extern struct { | 16 | .Little => extern struct { |
| 15 | low: u32, | 17 | low: u32, |
| 16 | high: u32, | 18 | high: u32, |
| ... | @@ -23,7 +25,7 @@ const dwords = extern union { | ... | @@ -23,7 +25,7 @@ const dwords = extern union { |
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| 25 | fn __muldsi3(a: u32, b: u32) i64 { | 27 | fn __muldsi3(a: u32, b: u32) i64 { |
| 26 | @setRuntimeSafety(builtin.is_test); | 28 | @setRuntimeSafety(is_test); |
| 27 | 29 | ||
| 28 | const bits_in_word_2 = @sizeOf(i32) * 8 / 2; | 30 | const bits_in_word_2 = @sizeOf(i32) * 8 / 2; |
| 29 | const lower_mask = (~@as(u32, 0)) >> bits_in_word_2; | 31 | const lower_mask = (~@as(u32, 0)) >> bits_in_word_2; |
| ... | @@ -45,7 +47,7 @@ fn __muldsi3(a: u32, b: u32) i64 { | ... | @@ -45,7 +47,7 @@ fn __muldsi3(a: u32, b: u32) i64 { |
| 45 | } | 47 | } |
| 46 | 48 | ||
| 47 | pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { | 49 | pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { |
| 48 | @setRuntimeSafety(builtin.is_test); | 50 | @setRuntimeSafety(is_test); |
| 49 | 51 | ||
| 50 | const x = dwords{ .all = a }; | 52 | const x = dwords{ .all = a }; |
| 51 | const y = dwords{ .all = b }; | 53 | const y = dwords{ .all = b }; |
lib/std/special/compiler_rt/multi3.zig+5-3| ... | @@ -3,15 +3,17 @@ | ... | @@ -3,15 +3,17 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | ||
| 7 | const compiler_rt = @import("../compiler_rt.zig"); | 6 | const compiler_rt = @import("../compiler_rt.zig"); |
| 7 | const std = @import("std"); | ||
| 8 | const is_test = std.builtin.is_test; | ||
| 9 | const native_endian = std.Target.current.cpu.arch.endian(); | ||
| 8 | 10 | ||
| 9 | // Ported from git@github.com:llvm-project/llvm-project-20170507.git | 11 | // Ported from git@github.com:llvm-project/llvm-project-20170507.git |
| 10 | // ae684fad6d34858c014c94da69c15e7774a633c3 | 12 | // ae684fad6d34858c014c94da69c15e7774a633c3 |
| 11 | // 2018-08-13 | 13 | // 2018-08-13 |
| 12 | 14 | ||
| 13 | pub fn __multi3(a: i128, b: i128) callconv(.C) i128 { | 15 | pub fn __multi3(a: i128, b: i128) callconv(.C) i128 { |
| 14 | @setRuntimeSafety(builtin.is_test); | 16 | @setRuntimeSafety(is_test); |
| 15 | const x = twords{ .all = a }; | 17 | const x = twords{ .all = a }; |
| 16 | const y = twords{ .all = b }; | 18 | const y = twords{ .all = b }; |
| 17 | var r = twords{ .all = __mulddi3(x.s.low, y.s.low) }; | 19 | var r = twords{ .all = __mulddi3(x.s.low, y.s.low) }; |
| ... | @@ -50,7 +52,7 @@ const twords = extern union { | ... | @@ -50,7 +52,7 @@ const twords = extern union { |
| 50 | all: i128, | 52 | all: i128, |
| 51 | s: S, | 53 | s: S, |
| 52 | 54 | ||
| 53 | const S = if (builtin.endian == .Little) | 55 | const S = if (native_endian == .Little) |
| 54 | struct { | 56 | struct { |
| 55 | low: u64, | 57 | low: u64, |
| 56 | high: u64, | 58 | high: u64, |
lib/std/special/compiler_rt/shift.zig+2-2| ... | @@ -4,8 +4,8 @@ | ... | @@ -4,8 +4,8 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | ||
| 8 | const Log2Int = std.math.Log2Int; | 7 | const Log2Int = std.math.Log2Int; |
| 8 | const native_endian = std.Target.current.cpu.arch.endian(); | ||
| 9 | 9 | ||
| 10 | fn Dwords(comptime T: type, comptime signed_half: bool) type { | 10 | fn Dwords(comptime T: type, comptime signed_half: bool) type { |
| 11 | return extern union { | 11 | return extern union { |
| ... | @@ -15,7 +15,7 @@ fn Dwords(comptime T: type, comptime signed_half: bool) type { | ... | @@ -15,7 +15,7 @@ fn Dwords(comptime T: type, comptime signed_half: bool) type { |
| 15 | pub const HalfT = if (signed_half) HalfTS else HalfTU; | 15 | pub const HalfT = if (signed_half) HalfTS else HalfTU; |
| 16 | 16 | ||
| 17 | all: T, | 17 | all: T, |
| 18 | s: if (builtin.endian == .Little) | 18 | s: if (native_endian == .Little) |
| 19 | struct { low: HalfT, high: HalfT } | 19 | struct { low: HalfT, high: HalfT } |
| 20 | else | 20 | else |
| 21 | struct { high: HalfT, low: HalfT }, | 21 | struct { high: HalfT, low: HalfT }, |
lib/std/special/compiler_rt/sparc.zig+1-1| ... | @@ -11,7 +11,7 @@ const builtin = @import("builtin"); | ... | @@ -11,7 +11,7 @@ const builtin = @import("builtin"); |
| 11 | 11 | ||
| 12 | // The SPARC Architecture Manual, Version 9: | 12 | // The SPARC Architecture Manual, Version 9: |
| 13 | // A.13 Floating-Point Compare | 13 | // A.13 Floating-Point Compare |
| 14 | const FCMP = extern enum(i32) { | 14 | const FCMP = enum(i32) { |
| 15 | Equal = 0, | 15 | Equal = 0, |
| 16 | Less = 1, | 16 | Less = 1, |
| 17 | Greater = 2, | 17 | Greater = 2, |
lib/std/special/compiler_rt/stack_probe.zig+5-5| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const native_arch = @import("std").Target.current.cpu.arch; |
| 7 | 7 | ||
| 8 | // Zig's own stack-probe routine (available only on x86 and x86_64) | 8 | // Zig's own stack-probe routine (available only on x86 and x86_64) |
| 9 | pub fn zig_probe_stack() callconv(.Naked) void { | 9 | pub fn zig_probe_stack() callconv(.Naked) void { |
| ... | @@ -13,7 +13,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { | ... | @@ -13,7 +13,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { |
| 13 | // invalid so let's update it on the go, otherwise we'll get a segfault | 13 | // invalid so let's update it on the go, otherwise we'll get a segfault |
| 14 | // instead of triggering the stack growth. | 14 | // instead of triggering the stack growth. |
| 15 | 15 | ||
| 16 | switch (builtin.arch) { | 16 | switch (native_arch) { |
| 17 | .x86_64 => { | 17 | .x86_64 => { |
| 18 | // %rax = probe length, %rsp = stack pointer | 18 | // %rax = probe length, %rsp = stack pointer |
| 19 | asm volatile ( | 19 | asm volatile ( |
| ... | @@ -65,7 +65,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { | ... | @@ -65,7 +65,7 @@ pub fn zig_probe_stack() callconv(.Naked) void { |
| 65 | fn win_probe_stack_only() void { | 65 | fn win_probe_stack_only() void { |
| 66 | @setRuntimeSafety(false); | 66 | @setRuntimeSafety(false); |
| 67 | 67 | ||
| 68 | switch (builtin.arch) { | 68 | switch (native_arch) { |
| 69 | .x86_64 => { | 69 | .x86_64 => { |
| 70 | asm volatile ( | 70 | asm volatile ( |
| 71 | \\ push %%rcx | 71 | \\ push %%rcx |
| ... | @@ -117,7 +117,7 @@ fn win_probe_stack_only() void { | ... | @@ -117,7 +117,7 @@ fn win_probe_stack_only() void { |
| 117 | fn win_probe_stack_adjust_sp() void { | 117 | fn win_probe_stack_adjust_sp() void { |
| 118 | @setRuntimeSafety(false); | 118 | @setRuntimeSafety(false); |
| 119 | 119 | ||
| 120 | switch (builtin.arch) { | 120 | switch (native_arch) { |
| 121 | .x86_64 => { | 121 | .x86_64 => { |
| 122 | asm volatile ( | 122 | asm volatile ( |
| 123 | \\ push %%rcx | 123 | \\ push %%rcx |
| ... | @@ -191,7 +191,7 @@ pub fn _chkstk() callconv(.Naked) void { | ... | @@ -191,7 +191,7 @@ pub fn _chkstk() callconv(.Naked) void { |
| 191 | } | 191 | } |
| 192 | pub fn __chkstk() callconv(.Naked) void { | 192 | pub fn __chkstk() callconv(.Naked) void { |
| 193 | @setRuntimeSafety(false); | 193 | @setRuntimeSafety(false); |
| 194 | switch (builtin.arch) { | 194 | switch (native_arch) { |
| 195 | .i386 => @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}), | 195 | .i386 => @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}), |
| 196 | .x86_64 => @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}), | 196 | .x86_64 => @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}), |
| 197 | else => unreachable, | 197 | else => unreachable, |
lib/std/special/compiler_rt/udivmod.zig+2-1| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const is_test = builtin.is_test; | 7 | const is_test = builtin.is_test; |
| 8 | const native_endian = @import("std").Target.current.cpu.arch.endian(); | ||
| 8 | 9 | ||
| 9 | const low = switch (builtin.endian) { | 10 | const low = switch (native_endian) { |
| 10 | .Big => 1, | 11 | .Big => 1, |
| 11 | .Little => 0, | 12 | .Little => 0, |
| 12 | }; | 13 | }; |
lib/std/special/test_runner.zig+10| ... | @@ -22,6 +22,9 @@ fn processArgs() void { | ... | @@ -22,6 +22,9 @@ fn processArgs() void { |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | pub fn main() anyerror!void { | 24 | pub fn main() anyerror!void { |
| 25 | if (builtin.zig_is_stage2) { | ||
| 26 | return main2(); | ||
| 27 | } | ||
| 25 | processArgs(); | 28 | processArgs(); |
| 26 | const test_fn_list = builtin.test_functions; | 29 | const test_fn_list = builtin.test_functions; |
| 27 | var ok_count: usize = 0; | 30 | var ok_count: usize = 0; |
| ... | @@ -123,3 +126,10 @@ pub fn log( | ... | @@ -123,3 +126,10 @@ pub fn log( |
| 123 | std.debug.print("[{s}] ({s}): " ++ format ++ "\n", .{ @tagName(scope), @tagName(message_level) } ++ args); | 126 | std.debug.print("[{s}] ({s}): " ++ format ++ "\n", .{ @tagName(scope), @tagName(message_level) } ++ args); |
| 124 | } | 127 | } |
| 125 | } | 128 | } |
| 129 | |||
| 130 | pub fn main2() anyerror!void { | ||
| 131 | // Simpler main(), exercising fewer language features, so that stage2 can handle it. | ||
| 132 | for (builtin.test_functions) |test_fn| { | ||
| 133 | try test_fn.func(); | ||
| 134 | } | ||
| 135 | } |
lib/std/start.zig+73-35| ... | @@ -11,30 +11,36 @@ const builtin = @import("builtin"); | ... | @@ -11,30 +11,36 @@ const builtin = @import("builtin"); |
| 11 | const assert = std.debug.assert; | 11 | const assert = std.debug.assert; |
| 12 | const uefi = std.os.uefi; | 12 | const uefi = std.os.uefi; |
| 13 | const tlcsprng = @import("crypto/tlcsprng.zig"); | 13 | const tlcsprng = @import("crypto/tlcsprng.zig"); |
| 14 | const native_arch = builtin.cpu.arch; | ||
| 15 | const native_os = builtin.os.tag; | ||
| 14 | 16 | ||
| 15 | var argc_argv_ptr: [*]usize = undefined; | 17 | var argc_argv_ptr: [*]usize = undefined; |
| 16 | 18 | ||
| 17 | const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start"; | 19 | const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start"; |
| 18 | 20 | ||
| 19 | comptime { | 21 | comptime { |
| 22 | // No matter what, we import the root file, so that any export, test, comptime | ||
| 23 | // decls there get run. | ||
| 24 | _ = root; | ||
| 25 | |||
| 20 | // The self-hosted compiler is not fully capable of handling all of this start.zig file. | 26 | // The self-hosted compiler is not fully capable of handling all of this start.zig file. |
| 21 | // Until then, we have simplified logic here for self-hosted. TODO remove this once | 27 | // Until then, we have simplified logic here for self-hosted. TODO remove this once |
| 22 | // self-hosted is capable enough to handle all of the real start.zig logic. | 28 | // self-hosted is capable enough to handle all of the real start.zig logic. |
| 23 | if (builtin.zig_is_stage2) { | 29 | if (builtin.zig_is_stage2) { |
| 24 | if (builtin.output_mode == .Exe) { | 30 | if (builtin.output_mode == .Exe) { |
| 25 | if (builtin.link_libc or builtin.object_format == .c) { | 31 | if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) { |
| 26 | if (!@hasDecl(root, "main")) { | 32 | if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { |
| 27 | @export(main2, "main"); | 33 | @export(main2, .{ .name = "main" }); |
| 28 | } | 34 | } |
| 29 | } else { | 35 | } else { |
| 30 | if (!@hasDecl(root, "_start")) { | 36 | if (!@hasDecl(root, "_start")) { |
| 31 | @export(_start2, "_start"); | 37 | @export(_start2, .{ .name = "_start" }); |
| 32 | } | 38 | } |
| 33 | } | 39 | } |
| 34 | } | 40 | } |
| 35 | } else { | 41 | } else { |
| 36 | if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { | 42 | if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { |
| 37 | if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { | 43 | if (native_os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { |
| 38 | @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); | 44 | @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); |
| 39 | } | 45 | } |
| 40 | } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { | 46 | } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { |
| ... | @@ -42,7 +48,7 @@ comptime { | ... | @@ -42,7 +48,7 @@ comptime { |
| 42 | if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { | 48 | if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { |
| 43 | @export(main, .{ .name = "main" }); | 49 | @export(main, .{ .name = "main" }); |
| 44 | } | 50 | } |
| 45 | } else if (builtin.os.tag == .windows) { | 51 | } else if (native_os == .windows) { |
| 46 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and | 52 | if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and |
| 47 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) | 53 | !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) |
| 48 | { | 54 | { |
| ... | @@ -56,11 +62,11 @@ comptime { | ... | @@ -56,11 +62,11 @@ comptime { |
| 56 | { | 62 | { |
| 57 | @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); | 63 | @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); |
| 58 | } | 64 | } |
| 59 | } else if (builtin.os.tag == .uefi) { | 65 | } else if (native_os == .uefi) { |
| 60 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); | 66 | if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); |
| 61 | } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) { | 67 | } else if (native_arch.isWasm() and native_os == .freestanding) { |
| 62 | if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); | 68 | if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); |
| 63 | } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) { | 69 | } else if (native_os != .other and native_os != .freestanding) { |
| 64 | if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); | 70 | if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); |
| 65 | } | 71 | } |
| 66 | } | 72 | } |
| ... | @@ -79,8 +85,8 @@ fn _start2() callconv(.Naked) noreturn { | ... | @@ -79,8 +85,8 @@ fn _start2() callconv(.Naked) noreturn { |
| 79 | exit2(0); | 85 | exit2(0); |
| 80 | } | 86 | } |
| 81 | 87 | ||
| 82 | fn exit2(code: u8) noreturn { | 88 | fn exit2(code: usize) noreturn { |
| 83 | switch (builtin.arch) { | 89 | switch (builtin.stage2_arch) { |
| 84 | .x86_64 => { | 90 | .x86_64 => { |
| 85 | asm volatile ("syscall" | 91 | asm volatile ("syscall" |
| 86 | : | 92 | : |
| ... | @@ -157,13 +163,13 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv | ... | @@ -157,13 +163,13 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv |
| 157 | } | 163 | } |
| 158 | 164 | ||
| 159 | fn _start() callconv(.Naked) noreturn { | 165 | fn _start() callconv(.Naked) noreturn { |
| 160 | if (builtin.os.tag == .wasi) { | 166 | if (native_os == .wasi) { |
| 161 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 167 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 162 | // and we want fewer call frames in stack traces. | 168 | // and we want fewer call frames in stack traces. |
| 163 | std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); | 169 | std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); |
| 164 | } | 170 | } |
| 165 | 171 | ||
| 166 | switch (builtin.arch) { | 172 | switch (native_arch) { |
| 167 | .x86_64 => { | 173 | .x86_64 => { |
| 168 | argc_argv_ptr = asm volatile ( | 174 | argc_argv_ptr = asm volatile ( |
| 169 | \\ xor %%rbp, %%rbp | 175 | \\ xor %%rbp, %%rbp |
| ... | @@ -273,7 +279,7 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -273,7 +279,7 @@ fn posixCallMainAndExit() noreturn { |
| 273 | while (envp_optional[envp_count]) |_| : (envp_count += 1) {} | 279 | while (envp_optional[envp_count]) |_| : (envp_count += 1) {} |
| 274 | const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; | 280 | const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; |
| 275 | 281 | ||
| 276 | if (builtin.os.tag == .linux) { | 282 | if (native_os == .linux) { |
| 277 | // Find the beginning of the auxiliary vector | 283 | // Find the beginning of the auxiliary vector |
| 278 | const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); | 284 | const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); |
| 279 | std.os.linux.elf_aux_maybe = auxv; | 285 | std.os.linux.elf_aux_maybe = auxv; |
| ... | @@ -291,31 +297,56 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -291,31 +297,56 @@ fn posixCallMainAndExit() noreturn { |
| 291 | std.os.linux.tls.initStaticTLS(); | 297 | std.os.linux.tls.initStaticTLS(); |
| 292 | } | 298 | } |
| 293 | 299 | ||
| 294 | // TODO This is disabled because what should we do when linking libc and this code | 300 | // Linux ignores the stack size from the ELF file, and instead always gives 8 MiB. |
| 295 | // does not execute? And also it's causing a test failure in stack traces in release modes. | 301 | // Here we look for the stack size in our program headers and tell the kernel, |
| 296 | 302 | // no, seriously, give me that stack space, I wasn't joking. | |
| 297 | //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further | 303 | { |
| 298 | //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down | 304 | var i: usize = 0; |
| 299 | //// the stack and requires "probing". So here we allocate our own stack. | 305 | var at_phdr: usize = undefined; |
| 300 | //const wanted_stack_size = gnu_stack_phdr.p_memsz; | 306 | var at_phnum: usize = undefined; |
| 301 | //assert(wanted_stack_size % std.mem.page_size == 0); | 307 | while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { |
| 302 | //// Allocate an extra page as the guard page. | 308 | switch (auxv[i].a_type) { |
| 303 | //const total_size = wanted_stack_size + std.mem.page_size; | 309 | std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, |
| 304 | //const new_stack = std.os.mmap( | 310 | std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, |
| 305 | // null, | 311 | else => continue, |
| 306 | // total_size, | 312 | } |
| 307 | // std.os.PROT_READ | std.os.PROT_WRITE, | 313 | } |
| 308 | // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, | 314 | expandStackSize(at_phdr, at_phnum); |
| 309 | // -1, | 315 | } |
| 310 | // 0, | ||
| 311 | //) catch @panic("out of memory"); | ||
| 312 | //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; | ||
| 313 | //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); | ||
| 314 | } | 316 | } |
| 315 | 317 | ||
| 316 | std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); | 318 | std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); |
| 317 | } | 319 | } |
| 318 | 320 | ||
| 321 | fn expandStackSize(at_phdr: usize, at_phnum: usize) void { | ||
| 322 | const phdrs = (@intToPtr([*]std.elf.Phdr, at_phdr))[0..at_phnum]; | ||
| 323 | for (phdrs) |*phdr| { | ||
| 324 | switch (phdr.p_type) { | ||
| 325 | std.elf.PT_GNU_STACK => { | ||
| 326 | const wanted_stack_size = phdr.p_memsz; | ||
| 327 | assert(wanted_stack_size % std.mem.page_size == 0); | ||
| 328 | |||
| 329 | std.os.setrlimit(.STACK, .{ | ||
| 330 | .cur = wanted_stack_size, | ||
| 331 | .max = wanted_stack_size, | ||
| 332 | }) catch { | ||
| 333 | // If this is a debug build, it will be useful to find out | ||
| 334 | // why this failed. If it is a release build, we allow the | ||
| 335 | // stack overflow to cause a segmentation fault. Memory safety | ||
| 336 | // is not compromised, however, depending on runtime state, | ||
| 337 | // the application may crash due to provided stack space not | ||
| 338 | // matching the known upper bound. | ||
| 339 | if (builtin.mode == .Debug) { | ||
| 340 | @panic("unable to increase stack size"); | ||
| 341 | } | ||
| 342 | }; | ||
| 343 | break; | ||
| 344 | }, | ||
| 345 | else => {}, | ||
| 346 | } | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 319 | fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { | 350 | fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| 320 | std.os.argv = argv[0..argc]; | 351 | std.os.argv = argv[0..argc]; |
| 321 | std.os.environ = envp; | 352 | std.os.environ = envp; |
| ... | @@ -329,6 +360,13 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) | ... | @@ -329,6 +360,13 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) |
| 329 | var env_count: usize = 0; | 360 | var env_count: usize = 0; |
| 330 | while (c_envp[env_count] != null) : (env_count += 1) {} | 361 | while (c_envp[env_count] != null) : (env_count += 1) {} |
| 331 | const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; | 362 | const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; |
| 363 | |||
| 364 | if (builtin.os.tag == .linux) { | ||
| 365 | const at_phdr = std.c.getauxval(std.elf.AT_PHDR); | ||
| 366 | const at_phnum = std.c.getauxval(std.elf.AT_PHNUM); | ||
| 367 | expandStackSize(at_phdr, at_phnum); | ||
| 368 | } | ||
| 369 | |||
| 332 | return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); | 370 | return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); |
| 333 | } | 371 | } |
| 334 | 372 |
lib/std/start_windows_tls.zig+2-2| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = std.builtin; | 7 | const builtin = @import("builtin"); |
| 8 | 8 | ||
| 9 | export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; | 9 | export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; |
| 10 | export var _tls_start: u8 linksection(".tls") = 0; | 10 | export var _tls_start: u8 linksection(".tls") = 0; |
| ... | @@ -13,7 +13,7 @@ export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = | ... | @@ -13,7 +13,7 @@ export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = |
| 13 | export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; | 13 | export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; |
| 14 | 14 | ||
| 15 | comptime { | 15 | comptime { |
| 16 | if (builtin.arch == .i386) { | 16 | if (builtin.target.cpu.arch == .i386) { |
| 17 | // The __tls_array is the offset of the ThreadLocalStoragePointer field | 17 | // The __tls_array is the offset of the ThreadLocalStoragePointer field |
| 18 | // in the TEB block whose base address held in the %fs segment. | 18 | // in the TEB block whose base address held in the %fs segment. |
| 19 | asm ( | 19 | asm ( |
lib/std/target.zig+1-5| ... | @@ -1242,11 +1242,7 @@ pub const Target = struct { | ... | @@ -1242,11 +1242,7 @@ pub const Target = struct { |
| 1242 | } | 1242 | } |
| 1243 | }; | 1243 | }; |
| 1244 | 1244 | ||
| 1245 | pub const current = Target{ | 1245 | pub const current = builtin.target; |
| 1246 | .cpu = builtin.cpu, | ||
| 1247 | .os = builtin.os, | ||
| 1248 | .abi = builtin.abi, | ||
| 1249 | }; | ||
| 1250 | 1246 | ||
| 1251 | pub const stack_align = 16; | 1247 | pub const stack_align = 16; |
| 1252 | 1248 |
lib/std/testing.zig+1-1| ... | @@ -327,7 +327,7 @@ pub const TmpDir = struct { | ... | @@ -327,7 +327,7 @@ pub const TmpDir = struct { |
| 327 | }; | 327 | }; |
| 328 | 328 | ||
| 329 | fn getCwdOrWasiPreopen() std.fs.Dir { | 329 | fn getCwdOrWasiPreopen() std.fs.Dir { |
| 330 | if (@import("builtin").os.tag == .wasi) { | 330 | if (std.builtin.os.tag == .wasi) { |
| 331 | var preopens = std.fs.wasi.PreopenList.init(allocator); | 331 | var preopens = std.fs.wasi.PreopenList.init(allocator); |
| 332 | defer preopens.deinit(); | 332 | defer preopens.deinit(); |
| 333 | preopens.populate() catch | 333 | preopens.populate() catch |
lib/std/unicode.zig+1-1| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | // The MIT license requires this copyright notice to be included in all copies | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("./std.zig"); | 6 | const std = @import("./std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = std.builtin; |
| 8 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
lib/std/valgrind.zig+5-5| ... | @@ -12,7 +12,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3: | ... | @@ -12,7 +12,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3: |
| 12 | return default; | 12 | return default; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | switch (builtin.arch) { | 15 | switch (builtin.target.cpu.arch) { |
| 16 | .i386 => { | 16 | .i386 => { |
| 17 | return asm volatile ( | 17 | return asm volatile ( |
| 18 | \\ roll $3, %%edi ; roll $13, %%edi | 18 | \\ roll $3, %%edi ; roll $13, %%edi |
| ... | @@ -48,7 +48,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3: | ... | @@ -48,7 +48,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3: |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | pub const ClientRequest = extern enum { | 51 | pub const ClientRequest = enum(u32) { |
| 52 | RunningOnValgrind = 4097, | 52 | RunningOnValgrind = 4097, |
| 53 | DiscardTranslations = 4098, | 53 | DiscardTranslations = 4098, |
| 54 | ClientCall0 = 4353, | 54 | ClientCall0 = 4353, |
| ... | @@ -156,9 +156,9 @@ pub fn freeLikeBlock(addr: [*]u8, rzB: usize) void { | ... | @@ -156,9 +156,9 @@ pub fn freeLikeBlock(addr: [*]u8, rzB: usize) void { |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | /// Create a memory pool. | 158 | /// Create a memory pool. |
| 159 | pub const MempoolFlags = extern enum { | 159 | pub const MempoolFlags = struct { |
| 160 | AutoFree = 1, | 160 | pub const AutoFree = 1; |
| 161 | MetaPool = 2, | 161 | pub const MetaPool = 2; |
| 162 | }; | 162 | }; |
| 163 | pub fn createMempool(pool: [*]u8, rzB: usize, is_zeroed: bool, flags: usize) void { | 163 | pub fn createMempool(pool: [*]u8, rzB: usize, is_zeroed: bool, flags: usize) void { |
| 164 | doClientRequestStmt(.CreateMempool, @ptrToInt(pool), rzB, @boolToInt(is_zeroed), flags, 0); | 164 | doClientRequestStmt(.CreateMempool, @ptrToInt(pool), rzB, @boolToInt(is_zeroed), flags, 0); |
lib/std/valgrind/callgrind.zig+1-1| ... | @@ -6,7 +6,7 @@ | ... | @@ -6,7 +6,7 @@ |
| 6 | const std = @import("../std.zig"); | 6 | const std = @import("../std.zig"); |
| 7 | const valgrind = std.valgrind; | 7 | const valgrind = std.valgrind; |
| 8 | 8 | ||
| 9 | pub const CallgrindClientRequest = extern enum { | 9 | pub const CallgrindClientRequest = enum(usize) { |
| 10 | DumpStats = valgrind.ToolBase("CT"), | 10 | DumpStats = valgrind.ToolBase("CT"), |
| 11 | ZeroStats, | 11 | ZeroStats, |
| 12 | ToggleCollect, | 12 | ToggleCollect, |
lib/std/valgrind/memcheck.zig+2-2| ... | @@ -7,7 +7,7 @@ const std = @import("../std.zig"); | ... | @@ -7,7 +7,7 @@ const std = @import("../std.zig"); |
| 7 | const testing = std.testing; | 7 | const testing = std.testing; |
| 8 | const valgrind = std.valgrind; | 8 | const valgrind = std.valgrind; |
| 9 | 9 | ||
| 10 | pub const MemCheckClientRequest = extern enum { | 10 | pub const MemCheckClientRequest = enum(usize) { |
| 11 | MakeMemNoAccess = valgrind.ToolBase("MC".*), | 11 | MakeMemNoAccess = valgrind.ToolBase("MC".*), |
| 12 | MakeMemUndefined, | 12 | MakeMemUndefined, |
| 13 | MakeMemDefined, | 13 | MakeMemDefined, |
| ... | @@ -76,7 +76,7 @@ pub fn createBlock(qzz: []u8, desc: [*]u8) usize { | ... | @@ -76,7 +76,7 @@ pub fn createBlock(qzz: []u8, desc: [*]u8) usize { |
| 76 | 76 | ||
| 77 | /// Discard a block-description-handle. Returns 1 for an | 77 | /// Discard a block-description-handle. Returns 1 for an |
| 78 | /// invalid handle, 0 for a valid handle. | 78 | /// invalid handle, 0 for a valid handle. |
| 79 | pub fn discard(blkindex) bool { | 79 | pub fn discard(blkindex: usize) bool { |
| 80 | return doMemCheckClientRequestExpr(0, // default return | 80 | return doMemCheckClientRequestExpr(0, // default return |
| 81 | .Discard, 0, blkindex, 0, 0, 0) != 0; | 81 | .Discard, 0, blkindex, 0, 0, 0) != 0; |
| 82 | } | 82 | } |
lib/std/x/net/tcp.zig+1-1| ... | @@ -50,7 +50,7 @@ pub const Connection = struct { | ... | @@ -50,7 +50,7 @@ pub const Connection = struct { |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | /// Possible domains that a TCP client/listener may operate over. | 52 | /// Possible domains that a TCP client/listener may operate over. |
| 53 | pub const Domain = extern enum(u16) { | 53 | pub const Domain = enum(u16) { |
| 54 | ip = os.AF_INET, | 54 | ip = os.AF_INET, |
| 55 | ipv6 = os.AF_INET6, | 55 | ipv6 = os.AF_INET6, |
| 56 | }; | 56 | }; |
lib/std/x/os/net.zig+1-1| ... | @@ -352,7 +352,7 @@ pub const IPv6 = extern struct { | ... | @@ -352,7 +352,7 @@ pub const IPv6 = extern struct { |
| 352 | opts: fmt.FormatOptions, | 352 | opts: fmt.FormatOptions, |
| 353 | writer: anytype, | 353 | writer: anytype, |
| 354 | ) !void { | 354 | ) !void { |
| 355 | comptime const specifier = &[_]u8{if (layout.len == 0) 'x' else switch (layout[0]) { | 355 | const specifier = comptime &[_]u8{if (layout.len == 0) 'x' else switch (layout[0]) { |
| 356 | 'x', 'X' => |specifier| specifier, | 356 | 'x', 'X' => |specifier| specifier, |
| 357 | 's' => 'x', | 357 | 's' => 'x', |
| 358 | 'S' => 'X', | 358 | 'S' => 'X', |
lib/std/zig.zig+4| ... | @@ -24,6 +24,10 @@ pub fn hashSrc(src: []const u8) SrcHash { | ... | @@ -24,6 +24,10 @@ pub fn hashSrc(src: []const u8) SrcHash { |
| 24 | return out; | 24 | return out; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | pub fn srcHashEql(a: SrcHash, b: SrcHash) bool { | ||
| 28 | return @bitCast(u128, a) == @bitCast(u128, b); | ||
| 29 | } | ||
| 30 | |||
| 27 | pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash { | 31 | pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash { |
| 28 | var out: SrcHash = undefined; | 32 | var out: SrcHash = undefined; |
| 29 | var hasher = std.crypto.hash.Blake3.init(.{}); | 33 | var hasher = std.crypto.hash.Blake3.init(.{}); |
lib/std/zig/ast.zig+7-6| ... | @@ -2178,6 +2178,10 @@ pub const full = struct { | ... | @@ -2178,6 +2178,10 @@ pub const full = struct { |
| 2178 | }; | 2178 | }; |
| 2179 | it.param_i += 1; | 2179 | it.param_i += 1; |
| 2180 | it.tok_i = it.tree.lastToken(param_type) + 1; | 2180 | it.tok_i = it.tree.lastToken(param_type) + 1; |
| 2181 | // Look for anytype and ... params afterwards. | ||
| 2182 | if (token_tags[it.tok_i] == .comma) { | ||
| 2183 | it.tok_i += 1; | ||
| 2184 | } | ||
| 2181 | it.tok_flag = true; | 2185 | it.tok_flag = true; |
| 2182 | return Param{ | 2186 | return Param{ |
| 2183 | .first_doc_comment = first_doc_comment, | 2187 | .first_doc_comment = first_doc_comment, |
| ... | @@ -2187,10 +2191,7 @@ pub const full = struct { | ... | @@ -2187,10 +2191,7 @@ pub const full = struct { |
| 2187 | .type_expr = param_type, | 2191 | .type_expr = param_type, |
| 2188 | }; | 2192 | }; |
| 2189 | } | 2193 | } |
| 2190 | // Look for anytype and ... params afterwards. | 2194 | if (token_tags[it.tok_i] == .r_paren) { |
| 2191 | if (token_tags[it.tok_i] == .comma) { | ||
| 2192 | it.tok_i += 1; | ||
| 2193 | } else { | ||
| 2194 | return null; | 2195 | return null; |
| 2195 | } | 2196 | } |
| 2196 | if (token_tags[it.tok_i] == .doc_comment) { | 2197 | if (token_tags[it.tok_i] == .doc_comment) { |
| ... | @@ -2242,8 +2243,8 @@ pub const full = struct { | ... | @@ -2242,8 +2243,8 @@ pub const full = struct { |
| 2242 | .tree = &tree, | 2243 | .tree = &tree, |
| 2243 | .fn_proto = &fn_proto, | 2244 | .fn_proto = &fn_proto, |
| 2244 | .param_i = 0, | 2245 | .param_i = 0, |
| 2245 | .tok_i = undefined, | 2246 | .tok_i = fn_proto.lparen + 1, |
| 2246 | .tok_flag = false, | 2247 | .tok_flag = true, |
| 2247 | }; | 2248 | }; |
| 2248 | } | 2249 | } |
| 2249 | }; | 2250 | }; |
lib/std/zig/render.zig-1| ... | @@ -1595,7 +1595,6 @@ fn renderStructInit( | ... | @@ -1595,7 +1595,6 @@ fn renderStructInit( |
| 1595 | return renderToken(ais, tree, rbrace, space); | 1595 | return renderToken(ais, tree, rbrace, space); |
| 1596 | } | 1596 | } |
| 1597 | 1597 | ||
| 1598 | // TODO: handle comments between elements | ||
| 1599 | fn renderArrayInit( | 1598 | fn renderArrayInit( |
| 1600 | gpa: *Allocator, | 1599 | gpa: *Allocator, |
| 1601 | ais: *Ais, | 1600 | ais: *Ais, |
lib/std/zig/system.zig+2-1| ... | @@ -14,6 +14,7 @@ const process = std.process; | ... | @@ -14,6 +14,7 @@ const process = std.process; |
| 14 | const Target = std.Target; | 14 | const Target = std.Target; |
| 15 | const CrossTarget = std.zig.CrossTarget; | 15 | const CrossTarget = std.zig.CrossTarget; |
| 16 | const macos = @import("system/macos.zig"); | 16 | const macos = @import("system/macos.zig"); |
| 17 | const native_endian = std.Target.current.cpu.arch.endian(); | ||
| 17 | const linux = @import("system/linux.zig"); | 18 | const linux = @import("system/linux.zig"); |
| 18 | pub const windows = @import("system/windows.zig"); | 19 | pub const windows = @import("system/windows.zig"); |
| 19 | 20 | ||
| ... | @@ -662,7 +663,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -662,7 +663,7 @@ pub const NativeTargetInfo = struct { |
| 662 | elf.ELFDATA2MSB => .Big, | 663 | elf.ELFDATA2MSB => .Big, |
| 663 | else => return error.InvalidElfEndian, | 664 | else => return error.InvalidElfEndian, |
| 664 | }; | 665 | }; |
| 665 | const need_bswap = elf_endian != std.builtin.endian; | 666 | const need_bswap = elf_endian != native_endian; |
| 666 | if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; | 667 | if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; |
| 667 | 668 | ||
| 668 | const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { | 669 | const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { |
src/AstGen.zig+7876-3488| ... | @@ -1,8 +1,4 @@ | ... | @@ -1,8 +1,4 @@ |
| 1 | //! A Work-In-Progress `zir.Code`. This is a shared parent of all | 1 | //! Ingests an AST and produces ZIR code. |
| 2 | //! `GenZir` scopes. Once the `zir.Code` is produced, this struct | ||
| 3 | //! is deinitialized. | ||
| 4 | //! The `GenZir.finish` function converts this to a `zir.Code`. | ||
| 5 | |||
| 6 | const AstGen = @This(); | 2 | const AstGen = @This(); |
| 7 | 3 | ||
| 8 | const std = @import("std"); | 4 | const std = @import("std"); |
| ... | @@ -12,102 +8,160 @@ const Allocator = std.mem.Allocator; | ... | @@ -12,102 +8,160 @@ const Allocator = std.mem.Allocator; |
| 12 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 13 | const ArrayListUnmanaged = std.ArrayListUnmanaged; | 9 | const ArrayListUnmanaged = std.ArrayListUnmanaged; |
| 14 | 10 | ||
| 15 | const Value = @import("value.zig").Value; | 11 | const Zir = @import("Zir.zig"); |
| 16 | const Type = @import("type.zig").Type; | ||
| 17 | const TypedValue = @import("TypedValue.zig"); | ||
| 18 | const zir = @import("zir.zig"); | ||
| 19 | const Module = @import("Module.zig"); | ||
| 20 | const trace = @import("tracy.zig").trace; | 12 | const trace = @import("tracy.zig").trace; |
| 21 | const Scope = Module.Scope; | ||
| 22 | const GenZir = Scope.GenZir; | ||
| 23 | const InnerError = Module.InnerError; | ||
| 24 | const Decl = Module.Decl; | ||
| 25 | const LazySrcLoc = Module.LazySrcLoc; | ||
| 26 | const BuiltinFn = @import("BuiltinFn.zig"); | 13 | const BuiltinFn = @import("BuiltinFn.zig"); |
| 27 | 14 | ||
| 28 | instructions: std.MultiArrayList(zir.Inst) = .{}, | 15 | gpa: *Allocator, |
| 29 | string_bytes: ArrayListUnmanaged(u8) = .{}, | 16 | tree: *const ast.Tree, |
| 17 | instructions: std.MultiArrayList(Zir.Inst) = .{}, | ||
| 30 | extra: ArrayListUnmanaged(u32) = .{}, | 18 | extra: ArrayListUnmanaged(u32) = .{}, |
| 31 | /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert | 19 | string_bytes: ArrayListUnmanaged(u8) = .{}, |
| 32 | /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters. | 20 | /// Used for temporary allocations; freed after AstGen is complete. |
| 33 | ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len, | 21 | /// The resulting ZIR code has no references to anything in this arena. |
| 34 | mod: *Module, | ||
| 35 | decl: *Decl, | ||
| 36 | arena: *Allocator, | 22 | arena: *Allocator, |
| 23 | string_table: std.StringHashMapUnmanaged(u32) = .{}, | ||
| 24 | compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, | ||
| 25 | /// The topmost block of the current function. | ||
| 26 | fn_block: ?*GenZir = null, | ||
| 27 | /// String table indexes, keeps track of all `@import` operands. | ||
| 28 | imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, | ||
| 37 | 29 | ||
| 38 | /// Call `deinit` on the result. | 30 | const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 39 | pub fn init(mod: *Module, decl: *Decl, arena: *Allocator) !AstGen { | ||
| 40 | var astgen: AstGen = .{ | ||
| 41 | .mod = mod, | ||
| 42 | .decl = decl, | ||
| 43 | .arena = arena, | ||
| 44 | }; | ||
| 45 | // Must be a block instruction at index 0 with the root body. | ||
| 46 | try astgen.instructions.append(mod.gpa, .{ | ||
| 47 | .tag = .block, | ||
| 48 | .data = .{ .pl_node = .{ | ||
| 49 | .src_node = 0, | ||
| 50 | .payload_index = undefined, | ||
| 51 | } }, | ||
| 52 | }); | ||
| 53 | return astgen; | ||
| 54 | } | ||
| 55 | 31 | ||
| 56 | pub fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { | 32 | fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { |
| 57 | const fields = std.meta.fields(@TypeOf(extra)); | 33 | const fields = std.meta.fields(@TypeOf(extra)); |
| 58 | try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len + fields.len); | 34 | try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + fields.len); |
| 59 | return addExtraAssumeCapacity(astgen, extra); | 35 | return addExtraAssumeCapacity(astgen, extra); |
| 60 | } | 36 | } |
| 61 | 37 | ||
| 62 | pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { | 38 | fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { |
| 63 | const fields = std.meta.fields(@TypeOf(extra)); | 39 | const fields = std.meta.fields(@TypeOf(extra)); |
| 64 | const result = @intCast(u32, astgen.extra.items.len); | 40 | const result = @intCast(u32, astgen.extra.items.len); |
| 65 | inline for (fields) |field| { | 41 | inline for (fields) |field| { |
| 66 | astgen.extra.appendAssumeCapacity(switch (field.field_type) { | 42 | astgen.extra.appendAssumeCapacity(switch (field.field_type) { |
| 67 | u32 => @field(extra, field.name), | 43 | u32 => @field(extra, field.name), |
| 68 | zir.Inst.Ref => @enumToInt(@field(extra, field.name)), | 44 | Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), |
| 45 | i32 => @bitCast(u32, @field(extra, field.name)), | ||
| 69 | else => @compileError("bad field type"), | 46 | else => @compileError("bad field type"), |
| 70 | }); | 47 | }); |
| 71 | } | 48 | } |
| 72 | return result; | 49 | return result; |
| 73 | } | 50 | } |
| 74 | 51 | ||
| 75 | pub fn appendRefs(astgen: *AstGen, refs: []const zir.Inst.Ref) !void { | 52 | fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { |
| 76 | const coerced = @bitCast([]const u32, refs); | 53 | const coerced = @bitCast([]const u32, refs); |
| 77 | return astgen.extra.appendSlice(astgen.mod.gpa, coerced); | 54 | return astgen.extra.appendSlice(astgen.gpa, coerced); |
| 78 | } | 55 | } |
| 79 | 56 | ||
| 80 | pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const zir.Inst.Ref) void { | 57 | fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { |
| 81 | const coerced = @bitCast([]const u32, refs); | 58 | const coerced = @bitCast([]const u32, refs); |
| 82 | astgen.extra.appendSliceAssumeCapacity(coerced); | 59 | astgen.extra.appendSliceAssumeCapacity(coerced); |
| 83 | } | 60 | } |
| 84 | 61 | ||
| 85 | pub fn refIsNoReturn(astgen: AstGen, inst_ref: zir.Inst.Ref) bool { | 62 | pub fn generate(gpa: *Allocator, tree: ast.Tree) InnerError!Zir { |
| 86 | if (inst_ref == .unreachable_value) return true; | 63 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 87 | if (astgen.refToIndex(inst_ref)) |inst_index| { | 64 | defer arena.deinit(); |
| 88 | return astgen.instructions.items(.tag)[inst_index].isNoReturn(); | 65 | |
| 66 | var astgen: AstGen = .{ | ||
| 67 | .gpa = gpa, | ||
| 68 | .arena = &arena.allocator, | ||
| 69 | .tree = &tree, | ||
| 70 | }; | ||
| 71 | defer astgen.deinit(gpa); | ||
| 72 | |||
| 73 | // String table indexes 0 and 1 are reserved for special meaning. | ||
| 74 | try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0 }); | ||
| 75 | |||
| 76 | // We expect at least as many ZIR instructions and extra data items | ||
| 77 | // as AST nodes. | ||
| 78 | try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len); | ||
| 79 | |||
| 80 | // First few indexes of extra are reserved and set at the end. | ||
| 81 | const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len; | ||
| 82 | try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count); | ||
| 83 | astgen.extra.items.len += reserved_count; | ||
| 84 | |||
| 85 | var top_scope: Scope.Top = .{}; | ||
| 86 | |||
| 87 | var gen_scope: GenZir = .{ | ||
| 88 | .force_comptime = true, | ||
| 89 | .parent = &top_scope.base, | ||
| 90 | .anon_name_strategy = .parent, | ||
| 91 | .decl_node_index = 0, | ||
| 92 | .decl_line = 0, | ||
| 93 | .astgen = &astgen, | ||
| 94 | }; | ||
| 95 | defer gen_scope.instructions.deinit(gpa); | ||
| 96 | |||
| 97 | const container_decl: ast.full.ContainerDecl = .{ | ||
| 98 | .layout_token = null, | ||
| 99 | .ast = .{ | ||
| 100 | .main_token = undefined, | ||
| 101 | .enum_token = null, | ||
| 102 | .members = tree.rootDecls(), | ||
| 103 | .arg = 0, | ||
| 104 | }, | ||
| 105 | }; | ||
| 106 | if (AstGen.structDeclInner( | ||
| 107 | &gen_scope, | ||
| 108 | &gen_scope.base, | ||
| 109 | 0, | ||
| 110 | container_decl, | ||
| 111 | .Auto, | ||
| 112 | )) |struct_decl_ref| { | ||
| 113 | astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref); | ||
| 114 | } else |err| switch (err) { | ||
| 115 | error.OutOfMemory => return error.OutOfMemory, | ||
| 116 | error.AnalysisFail => {}, // Handled via compile_errors below. | ||
| 89 | } | 117 | } |
| 90 | return false; | ||
| 91 | } | ||
| 92 | 118 | ||
| 93 | pub fn indexToRef(astgen: AstGen, inst: zir.Inst.Index) zir.Inst.Ref { | 119 | const err_index = @enumToInt(Zir.ExtraIndex.compile_errors); |
| 94 | return @intToEnum(zir.Inst.Ref, astgen.ref_start_index + inst); | 120 | if (astgen.compile_errors.items.len == 0) { |
| 95 | } | 121 | astgen.extra.items[err_index] = 0; |
| 122 | } else { | ||
| 123 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 124 | 1 + astgen.compile_errors.items.len * | ||
| 125 | @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len); | ||
| 126 | |||
| 127 | astgen.extra.items[err_index] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{ | ||
| 128 | .items_len = @intCast(u32, astgen.compile_errors.items.len), | ||
| 129 | }); | ||
| 96 | 130 | ||
| 97 | pub fn refToIndex(astgen: AstGen, inst: zir.Inst.Ref) ?zir.Inst.Index { | 131 | for (astgen.compile_errors.items) |item| { |
| 98 | const ref_int = @enumToInt(inst); | 132 | _ = astgen.addExtraAssumeCapacity(item); |
| 99 | if (ref_int >= astgen.ref_start_index) { | 133 | } |
| 100 | return ref_int - astgen.ref_start_index; | 134 | } |
| 135 | |||
| 136 | const imports_index = @enumToInt(Zir.ExtraIndex.imports); | ||
| 137 | if (astgen.imports.count() == 0) { | ||
| 138 | astgen.extra.items[imports_index] = 0; | ||
| 101 | } else { | 139 | } else { |
| 102 | return null; | 140 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + |
| 141 | @typeInfo(Zir.Inst.Imports).Struct.fields.len + astgen.imports.count()); | ||
| 142 | |||
| 143 | astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{ | ||
| 144 | .imports_len = @intCast(u32, astgen.imports.count()), | ||
| 145 | }); | ||
| 146 | for (astgen.imports.items()) |entry| { | ||
| 147 | astgen.extra.appendAssumeCapacity(entry.key); | ||
| 148 | } | ||
| 103 | } | 149 | } |
| 150 | |||
| 151 | return Zir{ | ||
| 152 | .instructions = astgen.instructions.toOwnedSlice(), | ||
| 153 | .string_bytes = astgen.string_bytes.toOwnedSlice(gpa), | ||
| 154 | .extra = astgen.extra.toOwnedSlice(gpa), | ||
| 155 | }; | ||
| 104 | } | 156 | } |
| 105 | 157 | ||
| 106 | pub fn deinit(astgen: *AstGen) void { | 158 | pub fn deinit(astgen: *AstGen, gpa: *Allocator) void { |
| 107 | const gpa = astgen.mod.gpa; | ||
| 108 | astgen.instructions.deinit(gpa); | 159 | astgen.instructions.deinit(gpa); |
| 109 | astgen.extra.deinit(gpa); | 160 | astgen.extra.deinit(gpa); |
| 161 | astgen.string_table.deinit(gpa); | ||
| 110 | astgen.string_bytes.deinit(gpa); | 162 | astgen.string_bytes.deinit(gpa); |
| 163 | astgen.compile_errors.deinit(gpa); | ||
| 164 | astgen.imports.deinit(gpa); | ||
| 111 | } | 165 | } |
| 112 | 166 | ||
| 113 | pub const ResultLoc = union(enum) { | 167 | pub const ResultLoc = union(enum) { |
| ... | @@ -124,16 +178,16 @@ pub const ResultLoc = union(enum) { | ... | @@ -124,16 +178,16 @@ pub const ResultLoc = union(enum) { |
| 124 | /// may be treated as `none` instead. | 178 | /// may be treated as `none` instead. |
| 125 | none_or_ref, | 179 | none_or_ref, |
| 126 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. | 180 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 127 | ty: zir.Inst.Ref, | 181 | ty: Zir.Inst.Ref, |
| 128 | /// The expression must store its result into this typed pointer. The result instruction | 182 | /// The expression must store its result into this typed pointer. The result instruction |
| 129 | /// from the expression must be ignored. | 183 | /// from the expression must be ignored. |
| 130 | ptr: zir.Inst.Ref, | 184 | ptr: Zir.Inst.Ref, |
| 131 | /// The expression must store its result into this allocation, which has an inferred type. | 185 | /// The expression must store its result into this allocation, which has an inferred type. |
| 132 | /// The result instruction from the expression must be ignored. | 186 | /// The result instruction from the expression must be ignored. |
| 133 | /// Always an instruction with tag `alloc_inferred`. | 187 | /// Always an instruction with tag `alloc_inferred`. |
| 134 | inferred_ptr: zir.Inst.Ref, | 188 | inferred_ptr: Zir.Inst.Ref, |
| 135 | /// There is a pointer for the expression to store its result into, however, its type | 189 | /// There is a pointer for the expression to store its result into, however, its type |
| 136 | /// is inferred based on peer type resolution for a `zir.Inst.Block`. | 190 | /// is inferred based on peer type resolution for a `Zir.Inst.Block`. |
| 137 | /// The result instruction from the expression must be ignored. | 191 | /// The result instruction from the expression must be ignored. |
| 138 | block_ptr: *GenZir, | 192 | block_ptr: *GenZir, |
| 139 | 193 | ||
| ... | @@ -188,12 +242,20 @@ pub const ResultLoc = union(enum) { | ... | @@ -188,12 +242,20 @@ pub const ResultLoc = union(enum) { |
| 188 | } | 242 | } |
| 189 | }; | 243 | }; |
| 190 | 244 | ||
| 191 | pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref { | 245 | pub const align_rl: ResultLoc = .{ .ty = .u16_type }; |
| 192 | return expr(gz, scope, .{ .ty = .type_type }, type_node); | 246 | pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; |
| 247 | |||
| 248 | fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { | ||
| 249 | const prev_force_comptime = gz.force_comptime; | ||
| 250 | gz.force_comptime = true; | ||
| 251 | const e = expr(gz, scope, .{ .ty = .type_type }, type_node); | ||
| 252 | gz.force_comptime = prev_force_comptime; | ||
| 253 | return e; | ||
| 193 | } | 254 | } |
| 194 | 255 | ||
| 195 | fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 256 | fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 196 | const tree = gz.tree(); | 257 | const astgen = gz.astgen; |
| 258 | const tree = astgen.tree; | ||
| 197 | const node_tags = tree.nodes.items(.tag); | 259 | const node_tags = tree.nodes.items(.tag); |
| 198 | const main_tokens = tree.nodes.items(.main_token); | 260 | const main_tokens = tree.nodes.items(.main_token); |
| 199 | switch (node_tags[node]) { | 261 | switch (node_tags[node]) { |
| ... | @@ -351,7 +413,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins | ... | @@ -351,7 +413,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins |
| 351 | .@"comptime", | 413 | .@"comptime", |
| 352 | .@"nosuspend", | 414 | .@"nosuspend", |
| 353 | .error_value, | 415 | .error_value, |
| 354 | => return gz.astgen.mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), | 416 | => return astgen.failNode(node, "invalid left-hand side to assignment", .{}), |
| 355 | 417 | ||
| 356 | .builtin_call, | 418 | .builtin_call, |
| 357 | .builtin_call_comma, | 419 | .builtin_call_comma, |
| ... | @@ -364,7 +426,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins | ... | @@ -364,7 +426,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins |
| 364 | // let it pass, and the error will be "invalid builtin function" later. | 426 | // let it pass, and the error will be "invalid builtin function" later. |
| 365 | if (BuiltinFn.list.get(builtin_name)) |info| { | 427 | if (BuiltinFn.list.get(builtin_name)) |info| { |
| 366 | if (!info.allows_lvalue) { | 428 | if (!info.allows_lvalue) { |
| 367 | return gz.astgen.mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); | 429 | return astgen.failNode(node, "invalid left-hand side to assignment", .{}); |
| 368 | } | 430 | } |
| 369 | } | 431 | } |
| 370 | }, | 432 | }, |
| ... | @@ -386,9 +448,9 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins | ... | @@ -386,9 +448,9 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins |
| 386 | /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the | 448 | /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the |
| 387 | /// result instruction can be used to inspect whether it is isNoReturn() but that is it, | 449 | /// result instruction can be used to inspect whether it is isNoReturn() but that is it, |
| 388 | /// it must otherwise not be used. | 450 | /// it must otherwise not be used. |
| 389 | pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 451 | fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 390 | const mod = gz.astgen.mod; | 452 | const astgen = gz.astgen; |
| 391 | const tree = gz.tree(); | 453 | const tree = astgen.tree; |
| 392 | const main_tokens = tree.nodes.items(.main_token); | 454 | const main_tokens = tree.nodes.items(.main_token); |
| 393 | const token_tags = tree.tokens.items(.tag); | 455 | const token_tags = tree.tokens.items(.tag); |
| 394 | const node_datas = tree.nodes.items(.data); | 456 | const node_datas = tree.nodes.items(.data); |
| ... | @@ -407,6 +469,8 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -407,6 +469,8 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 407 | .local_var_decl => unreachable, // Handled in `blockExpr`. | 469 | .local_var_decl => unreachable, // Handled in `blockExpr`. |
| 408 | .simple_var_decl => unreachable, // Handled in `blockExpr`. | 470 | .simple_var_decl => unreachable, // Handled in `blockExpr`. |
| 409 | .aligned_var_decl => unreachable, // Handled in `blockExpr`. | 471 | .aligned_var_decl => unreachable, // Handled in `blockExpr`. |
| 472 | .@"defer" => unreachable, // Handled in `blockExpr`. | ||
| 473 | .@"errdefer" => unreachable, // Handled in `blockExpr`. | ||
| 410 | 474 | ||
| 411 | .switch_case => unreachable, // Handled in `switchExpr`. | 475 | .switch_case => unreachable, // Handled in `switchExpr`. |
| 412 | .switch_case_one => unreachable, // Handled in `switchExpr`. | 476 | .switch_case_one => unreachable, // Handled in `switchExpr`. |
| ... | @@ -415,24 +479,28 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -415,24 +479,28 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 415 | .asm_output => unreachable, // Handled in `asmExpr`. | 479 | .asm_output => unreachable, // Handled in `asmExpr`. |
| 416 | .asm_input => unreachable, // Handled in `asmExpr`. | 480 | .asm_input => unreachable, // Handled in `asmExpr`. |
| 417 | 481 | ||
| 482 | .@"anytype" => unreachable, // Handled in `containerDecl`. | ||
| 483 | |||
| 418 | .assign => { | 484 | .assign => { |
| 419 | try assign(gz, scope, node); | 485 | try assign(gz, scope, node); |
| 420 | return rvalue(gz, scope, rl, .void_value, node); | 486 | return rvalue(gz, scope, rl, .void_value, node); |
| 421 | }, | 487 | }, |
| 422 | .assign_bit_and => { | 488 | |
| 423 | try assignOp(gz, scope, node, .bit_and); | 489 | .assign_bit_shift_left => { |
| 490 | try assignShift(gz, scope, node, .shl); | ||
| 424 | return rvalue(gz, scope, rl, .void_value, node); | 491 | return rvalue(gz, scope, rl, .void_value, node); |
| 425 | }, | 492 | }, |
| 426 | .assign_bit_or => { | 493 | .assign_bit_shift_right => { |
| 427 | try assignOp(gz, scope, node, .bit_or); | 494 | try assignShift(gz, scope, node, .shr); |
| 428 | return rvalue(gz, scope, rl, .void_value, node); | 495 | return rvalue(gz, scope, rl, .void_value, node); |
| 429 | }, | 496 | }, |
| 430 | .assign_bit_shift_left => { | 497 | |
| 431 | try assignOp(gz, scope, node, .shl); | 498 | .assign_bit_and => { |
| 499 | try assignOp(gz, scope, node, .bit_and); | ||
| 432 | return rvalue(gz, scope, rl, .void_value, node); | 500 | return rvalue(gz, scope, rl, .void_value, node); |
| 433 | }, | 501 | }, |
| 434 | .assign_bit_shift_right => { | 502 | .assign_bit_or => { |
| 435 | try assignOp(gz, scope, node, .shr); | 503 | try assignOp(gz, scope, node, .bit_or); |
| 436 | return rvalue(gz, scope, rl, .void_value, node); | 504 | return rvalue(gz, scope, rl, .void_value, node); |
| 437 | }, | 505 | }, |
| 438 | .assign_bit_xor => { | 506 | .assign_bit_xor => { |
| ... | @@ -472,51 +540,54 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -472,51 +540,54 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 472 | return rvalue(gz, scope, rl, .void_value, node); | 540 | return rvalue(gz, scope, rl, .void_value, node); |
| 473 | }, | 541 | }, |
| 474 | 542 | ||
| 475 | .add => return simpleBinOp(gz, scope, rl, node, .add), | 543 | // zig fmt: off |
| 544 | .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl), | ||
| 545 | .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), | ||
| 546 | |||
| 547 | .add => return simpleBinOp(gz, scope, rl, node, .add), | ||
| 476 | .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap), | 548 | .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap), |
| 477 | .sub => return simpleBinOp(gz, scope, rl, node, .sub), | 549 | .sub => return simpleBinOp(gz, scope, rl, node, .sub), |
| 478 | .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap), | 550 | .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap), |
| 479 | .mul => return simpleBinOp(gz, scope, rl, node, .mul), | 551 | .mul => return simpleBinOp(gz, scope, rl, node, .mul), |
| 480 | .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), | 552 | .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), |
| 481 | .div => return simpleBinOp(gz, scope, rl, node, .div), | 553 | .div => return simpleBinOp(gz, scope, rl, node, .div), |
| 482 | .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), | 554 | .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), |
| 483 | .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), | 555 | .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), |
| 484 | .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), | 556 | .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), |
| 485 | .bit_shift_left => return simpleBinOp(gz, scope, rl, node, .shl), | 557 | .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), |
| 486 | .bit_shift_right => return simpleBinOp(gz, scope, rl, node, .shr), | 558 | |
| 487 | .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), | 559 | .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), |
| 488 | 560 | .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), | |
| 489 | .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), | 561 | .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), |
| 490 | .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), | ||
| 491 | .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), | ||
| 492 | .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), | 562 | .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), |
| 493 | .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), | 563 | .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), |
| 494 | .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), | 564 | .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), |
| 495 | 565 | ||
| 496 | .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), | 566 | .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), |
| 497 | .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), | 567 | .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), |
| 498 | 568 | ||
| 499 | .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), | 569 | .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), |
| 500 | .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), | 570 | .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), |
| 501 | 571 | ||
| 502 | .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and), | 572 | .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and), |
| 503 | .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), | 573 | .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), |
| 504 | 574 | ||
| 505 | .bool_not => return boolNot(gz, scope, rl, node), | 575 | .bool_not => return boolNot(gz, scope, rl, node), |
| 506 | .bit_not => return bitNot(gz, scope, rl, node), | 576 | .bit_not => return bitNot(gz, scope, rl, node), |
| 507 | 577 | ||
| 508 | .negation => return negation(gz, scope, rl, node, .negate), | 578 | .negation => return negation(gz, scope, rl, node, .negate), |
| 509 | .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap), | 579 | .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap), |
| 510 | 580 | ||
| 511 | .identifier => return identifier(gz, scope, rl, node), | 581 | .identifier => return identifier(gz, scope, rl, node), |
| 512 | 582 | ||
| 513 | .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)), | 583 | .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)), |
| 514 | .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), | 584 | .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), |
| 515 | 585 | ||
| 516 | .string_literal => return stringLiteral(gz, scope, rl, node), | 586 | .string_literal => return stringLiteral(gz, scope, rl, node), |
| 517 | .multiline_string_literal => return multilineStringLiteral(gz, scope, rl, node), | 587 | .multiline_string_literal => return multilineStringLiteral(gz, scope, rl, node), |
| 518 | 588 | ||
| 519 | .integer_literal => return integerLiteral(gz, scope, rl, node), | 589 | .integer_literal => return integerLiteral(gz, scope, rl, node), |
| 590 | // zig fmt: on | ||
| 520 | 591 | ||
| 521 | .builtin_call_two, .builtin_call_two_comma => { | 592 | .builtin_call_two, .builtin_call_two_comma => { |
| 522 | if (node_datas[node].lhs == 0) { | 593 | if (node_datas[node].lhs == 0) { |
| ... | @@ -548,10 +619,10 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -548,10 +619,10 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 548 | .tag = .@"unreachable", | 619 | .tag = .@"unreachable", |
| 549 | .data = .{ .@"unreachable" = .{ | 620 | .data = .{ .@"unreachable" = .{ |
| 550 | .safety = true, | 621 | .safety = true, |
| 551 | .src_node = gz.astgen.decl.nodeIndexToRelative(node), | 622 | .src_node = gz.nodeIndexToRelative(node), |
| 552 | } }, | 623 | } }, |
| 553 | }); | 624 | }); |
| 554 | return zir.Inst.Ref.unreachable_value; | 625 | return Zir.Inst.Ref.unreachable_value; |
| 555 | }, | 626 | }, |
| 556 | .@"return" => return ret(gz, scope, node), | 627 | .@"return" => return ret(gz, scope, node), |
| 557 | .field_access => return fieldAccess(gz, scope, rl, node), | 628 | .field_access => return fieldAccess(gz, scope, rl, node), |
| ... | @@ -570,7 +641,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -570,7 +641,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 570 | .slice_open => { | 641 | .slice_open => { |
| 571 | const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); | 642 | const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); |
| 572 | const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs); | 643 | const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs); |
| 573 | const result = try gz.addPlNode(.slice_start, node, zir.Inst.SliceStart{ | 644 | const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{ |
| 574 | .lhs = lhs, | 645 | .lhs = lhs, |
| 575 | .start = start, | 646 | .start = start, |
| 576 | }); | 647 | }); |
| ... | @@ -581,7 +652,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -581,7 +652,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 581 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice); | 652 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice); |
| 582 | const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); | 653 | const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); |
| 583 | const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); | 654 | const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); |
| 584 | const result = try gz.addPlNode(.slice_end, node, zir.Inst.SliceEnd{ | 655 | const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{ |
| 585 | .lhs = lhs, | 656 | .lhs = lhs, |
| 586 | .start = start, | 657 | .start = start, |
| 587 | .end = end, | 658 | .end = end, |
| ... | @@ -594,7 +665,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -594,7 +665,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 594 | const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); | 665 | const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); |
| 595 | const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); | 666 | const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); |
| 596 | const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel); | 667 | const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel); |
| 597 | const result = try gz.addPlNode(.slice_sentinel, node, zir.Inst.SliceSentinel{ | 668 | const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ |
| 598 | .lhs = lhs, | 669 | .lhs = lhs, |
| 599 | .start = start, | 670 | .start = start, |
| 600 | .end = end, | 671 | .end = end, |
| ... | @@ -654,8 +725,12 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -654,8 +725,12 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 654 | }, | 725 | }, |
| 655 | .enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal), | 726 | .enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal), |
| 656 | .error_value => return simpleStrTok(gz, scope, rl, node_datas[node].rhs, node, .error_value), | 727 | .error_value => return simpleStrTok(gz, scope, rl, node_datas[node].rhs, node, .error_value), |
| 657 | .anyframe_literal => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 728 | .anyframe_literal => return rvalue(gz, scope, rl, .anyframe_type, node), |
| 658 | .anyframe_type => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 729 | .anyframe_type => { |
| 730 | const return_type = try typeExpr(gz, scope, node_datas[node].rhs); | ||
| 731 | const result = try gz.addUnNode(.anyframe_type, return_type, node); | ||
| 732 | return rvalue(gz, scope, rl, result, node); | ||
| 733 | }, | ||
| 659 | .@"catch" => { | 734 | .@"catch" => { |
| 660 | const catch_token = main_tokens[node]; | 735 | const catch_token = main_tokens[node]; |
| 661 | const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) | 736 | const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) |
| ... | @@ -751,27 +826,30 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -751,27 +826,30 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 751 | .char_literal => return charLiteral(gz, scope, rl, node), | 826 | .char_literal => return charLiteral(gz, scope, rl, node), |
| 752 | .error_set_decl => return errorSetDecl(gz, scope, rl, node), | 827 | .error_set_decl => return errorSetDecl(gz, scope, rl, node), |
| 753 | .array_access => return arrayAccess(gz, scope, rl, node), | 828 | .array_access => return arrayAccess(gz, scope, rl, node), |
| 754 | .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs), | 829 | .@"comptime" => return comptimeExprAst(gz, scope, rl, node), |
| 755 | .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node), | 830 | .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node), |
| 756 | 831 | ||
| 757 | .@"nosuspend" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 832 | .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node), |
| 758 | .@"suspend" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 833 | .@"suspend" => return suspendExpr(gz, scope, rl, node), |
| 759 | .@"await" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 834 | .@"await" => return awaitExpr(gz, scope, rl, node), |
| 760 | .@"resume" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 835 | .@"resume" => return resumeExpr(gz, scope, rl, node), |
| 761 | 836 | ||
| 762 | .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}), | 837 | .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs), |
| 763 | .@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}), | ||
| 764 | .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), | ||
| 765 | 838 | ||
| 766 | .array_init_one, | 839 | .array_init_one, .array_init_one_comma => { |
| 767 | .array_init_one_comma, | 840 | var elements: [1]ast.Node.Index = undefined; |
| 768 | .array_init_dot_two, | 841 | return arrayInitExpr(gz, scope, rl, node, tree.arrayInitOne(&elements, node)); |
| 769 | .array_init_dot_two_comma, | 842 | }, |
| 843 | .array_init_dot_two, .array_init_dot_two_comma => { | ||
| 844 | var elements: [2]ast.Node.Index = undefined; | ||
| 845 | return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDotTwo(&elements, node)); | ||
| 846 | }, | ||
| 770 | .array_init_dot, | 847 | .array_init_dot, |
| 771 | .array_init_dot_comma, | 848 | .array_init_dot_comma, |
| 849 | => return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDot(node)), | ||
| 772 | .array_init, | 850 | .array_init, |
| 773 | .array_init_comma, | 851 | .array_init_comma, |
| 774 | => return mod.failNode(scope, node, "TODO implement astgen.expr for array literals", .{}), | 852 | => return arrayInitExpr(gz, scope, rl, node, tree.arrayInit(node)), |
| 775 | 853 | ||
| 776 | .struct_init_one, .struct_init_one_comma => { | 854 | .struct_init_one, .struct_init_one_comma => { |
| 777 | var fields: [1]ast.Node.Index = undefined; | 855 | var fields: [1]ast.Node.Index = undefined; |
| ... | @@ -788,3655 +866,6498 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn | ... | @@ -788,3655 +866,6498 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 788 | .struct_init_comma, | 866 | .struct_init_comma, |
| 789 | => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), | 867 | => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), |
| 790 | 868 | ||
| 791 | .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}), | 869 | .fn_proto_simple => { |
| 792 | .fn_proto_simple, | 870 | var params: [1]ast.Node.Index = undefined; |
| 793 | .fn_proto_multi, | 871 | return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(&params, node)); |
| 794 | .fn_proto_one, | 872 | }, |
| 795 | .fn_proto, | 873 | .fn_proto_multi => { |
| 796 | => return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}), | 874 | return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node)); |
| 875 | }, | ||
| 876 | .fn_proto_one => { | ||
| 877 | var params: [1]ast.Node.Index = undefined; | ||
| 878 | return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(&params, node)); | ||
| 879 | }, | ||
| 880 | .fn_proto => { | ||
| 881 | return fnProtoExpr(gz, scope, rl, tree.fnProto(node)); | ||
| 882 | }, | ||
| 797 | } | 883 | } |
| 798 | } | 884 | } |
| 799 | 885 | ||
| 800 | pub fn structInitExpr( | 886 | fn nosuspendExpr( |
| 801 | gz: *GenZir, | 887 | gz: *GenZir, |
| 802 | scope: *Scope, | 888 | scope: *Scope, |
| 803 | rl: ResultLoc, | 889 | rl: ResultLoc, |
| 804 | node: ast.Node.Index, | 890 | node: ast.Node.Index, |
| 805 | struct_init: ast.full.StructInit, | 891 | ) InnerError!Zir.Inst.Ref { |
| 806 | ) InnerError!zir.Inst.Ref { | ||
| 807 | const tree = gz.tree(); | ||
| 808 | const astgen = gz.astgen; | 892 | const astgen = gz.astgen; |
| 809 | const mod = astgen.mod; | 893 | const gpa = astgen.gpa; |
| 810 | const gpa = mod.gpa; | 894 | const tree = astgen.tree; |
| 895 | const node_datas = tree.nodes.items(.data); | ||
| 896 | const body_node = node_datas[node].lhs; | ||
| 897 | assert(body_node != 0); | ||
| 898 | if (gz.nosuspend_node != 0) { | ||
| 899 | return astgen.failNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ | ||
| 900 | try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), | ||
| 901 | }); | ||
| 902 | } | ||
| 903 | gz.nosuspend_node = node; | ||
| 904 | const result = try expr(gz, scope, rl, body_node); | ||
| 905 | gz.nosuspend_node = 0; | ||
| 906 | return rvalue(gz, scope, rl, result, node); | ||
| 907 | } | ||
| 811 | 908 | ||
| 812 | if (struct_init.ast.fields.len == 0) { | 909 | fn suspendExpr( |
| 813 | if (struct_init.ast.type_expr == 0) { | 910 | gz: *GenZir, |
| 814 | return rvalue(gz, scope, rl, .empty_struct, node); | 911 | scope: *Scope, |
| 815 | } else { | 912 | rl: ResultLoc, |
| 816 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 913 | node: ast.Node.Index, |
| 817 | const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); | 914 | ) InnerError!Zir.Inst.Ref { |
| 818 | return rvalue(gz, scope, rl, result, node); | 915 | const astgen = gz.astgen; |
| 819 | } | 916 | const gpa = astgen.gpa; |
| 917 | const tree = astgen.tree; | ||
| 918 | const node_datas = tree.nodes.items(.data); | ||
| 919 | const body_node = node_datas[node].lhs; | ||
| 920 | |||
| 921 | if (gz.nosuspend_node != 0) { | ||
| 922 | return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{ | ||
| 923 | try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}), | ||
| 924 | }); | ||
| 820 | } | 925 | } |
| 821 | switch (rl) { | 926 | if (gz.suspend_node != 0) { |
| 822 | .discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}), | 927 | return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{ |
| 823 | .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}), | 928 | try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}), |
| 824 | .ref => unreachable, // struct literal not valid as l-value | 929 | }); |
| 825 | .ty => |ty_inst| { | 930 | } |
| 826 | const fields_list = try gpa.alloc(zir.Inst.StructInit.Item, struct_init.ast.fields.len); | 931 | assert(body_node != 0); |
| 827 | defer gpa.free(fields_list); | ||
| 828 | 932 | ||
| 829 | for (struct_init.ast.fields) |field_init, i| { | 933 | const suspend_inst = try gz.addBlock(.suspend_block, node); |
| 830 | const name_token = tree.firstToken(field_init) - 2; | 934 | try gz.instructions.append(gpa, suspend_inst); |
| 831 | const str_index = try gz.identAsString(name_token); | ||
| 832 | 935 | ||
| 833 | const field_ty_inst = try gz.addPlNode(.field_type, field_init, zir.Inst.FieldType{ | 936 | var suspend_scope = gz.makeSubBlock(scope); |
| 834 | .container_type = ty_inst, | 937 | suspend_scope.suspend_node = node; |
| 835 | .name_start = str_index, | 938 | defer suspend_scope.instructions.deinit(gpa); |
| 836 | }); | 939 | |
| 837 | fields_list[i] = .{ | 940 | const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node); |
| 838 | .field_type = astgen.refToIndex(field_ty_inst).?, | 941 | if (!gz.refIsNoReturn(body_result)) { |
| 839 | .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init), | 942 | _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value); |
| 840 | }; | ||
| 841 | } | ||
| 842 | const init_inst = try gz.addPlNode(.struct_init, node, zir.Inst.StructInit{ | ||
| 843 | .fields_len = @intCast(u32, fields_list.len), | ||
| 844 | }); | ||
| 845 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 846 | fields_list.len * @typeInfo(zir.Inst.StructInit.Item).Struct.fields.len); | ||
| 847 | for (fields_list) |field| { | ||
| 848 | _ = gz.astgen.addExtraAssumeCapacity(field); | ||
| 849 | } | ||
| 850 | return rvalue(gz, scope, rl, init_inst, node); | ||
| 851 | }, | ||
| 852 | .ptr => |ptr_inst| { | ||
| 853 | const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len); | ||
| 854 | defer gpa.free(field_ptr_list); | ||
| 855 | |||
| 856 | for (struct_init.ast.fields) |field_init, i| { | ||
| 857 | const name_token = tree.firstToken(field_init) - 2; | ||
| 858 | const str_index = try gz.identAsString(name_token); | ||
| 859 | const field_ptr = try gz.addPlNode(.field_ptr, field_init, zir.Inst.Field{ | ||
| 860 | .lhs = ptr_inst, | ||
| 861 | .field_name_start = str_index, | ||
| 862 | }); | ||
| 863 | field_ptr_list[i] = astgen.refToIndex(field_ptr).?; | ||
| 864 | _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); | ||
| 865 | } | ||
| 866 | const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, zir.Inst.Block{ | ||
| 867 | .body_len = @intCast(u32, field_ptr_list.len), | ||
| 868 | }); | ||
| 869 | try astgen.extra.appendSlice(gpa, field_ptr_list); | ||
| 870 | return validate_inst; | ||
| 871 | }, | ||
| 872 | .inferred_ptr => |ptr_inst| { | ||
| 873 | return mod.failNode(scope, node, "TODO implement structInitExpr inferred_ptr", .{}); | ||
| 874 | }, | ||
| 875 | .block_ptr => |block_gz| { | ||
| 876 | return mod.failNode(scope, node, "TODO implement structInitExpr block", .{}); | ||
| 877 | }, | ||
| 878 | } | 943 | } |
| 944 | try suspend_scope.setBlockBody(suspend_inst); | ||
| 945 | |||
| 946 | return gz.indexToRef(suspend_inst); | ||
| 879 | } | 947 | } |
| 880 | 948 | ||
| 881 | pub fn comptimeExpr( | 949 | fn awaitExpr( |
| 882 | gz: *GenZir, | 950 | gz: *GenZir, |
| 883 | scope: *Scope, | 951 | scope: *Scope, |
| 884 | rl: ResultLoc, | 952 | rl: ResultLoc, |
| 885 | node: ast.Node.Index, | 953 | node: ast.Node.Index, |
| 886 | ) InnerError!zir.Inst.Ref { | 954 | ) InnerError!Zir.Inst.Ref { |
| 887 | const prev_force_comptime = gz.force_comptime; | 955 | const astgen = gz.astgen; |
| 888 | gz.force_comptime = true; | 956 | const tree = astgen.tree; |
| 889 | const result = try expr(gz, scope, rl, node); | ||
| 890 | gz.force_comptime = prev_force_comptime; | ||
| 891 | return result; | ||
| 892 | } | ||
| 893 | |||
| 894 | fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { | ||
| 895 | const mod = parent_gz.astgen.mod; | ||
| 896 | const tree = parent_gz.tree(); | ||
| 897 | const node_datas = tree.nodes.items(.data); | 957 | const node_datas = tree.nodes.items(.data); |
| 898 | const break_label = node_datas[node].lhs; | 958 | const rhs_node = node_datas[node].lhs; |
| 899 | const rhs = node_datas[node].rhs; | ||
| 900 | 959 | ||
| 901 | // Look for the label in the scope. | 960 | if (gz.suspend_node != 0) { |
| 902 | var scope = parent_scope; | 961 | return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{ |
| 903 | while (true) { | 962 | try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}), |
| 904 | switch (scope.tag) { | 963 | }); |
| 905 | .gen_zir => { | 964 | } |
| 906 | const block_gz = scope.cast(GenZir).?; | 965 | const operand = try expr(gz, scope, .none, rhs_node); |
| 966 | const tag: Zir.Inst.Tag = if (gz.nosuspend_node != 0) .await_nosuspend else .@"await"; | ||
| 967 | const result = try gz.addUnNode(tag, operand, node); | ||
| 968 | return rvalue(gz, scope, rl, result, node); | ||
| 969 | } | ||
| 907 | 970 | ||
| 908 | const block_inst = blk: { | 971 | fn resumeExpr( |
| 909 | if (break_label != 0) { | 972 | gz: *GenZir, |
| 910 | if (block_gz.label) |*label| { | 973 | scope: *Scope, |
| 911 | if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { | 974 | rl: ResultLoc, |
| 912 | label.used = true; | 975 | node: ast.Node.Index, |
| 913 | break :blk label.block_inst; | 976 | ) InnerError!Zir.Inst.Ref { |
| 914 | } | 977 | const astgen = gz.astgen; |
| 915 | } | 978 | const tree = astgen.tree; |
| 916 | } else if (block_gz.break_block != 0) { | 979 | const node_datas = tree.nodes.items(.data); |
| 917 | break :blk block_gz.break_block; | 980 | const rhs_node = node_datas[node].lhs; |
| 918 | } | 981 | const operand = try expr(gz, scope, .none, rhs_node); |
| 919 | scope = block_gz.parent; | 982 | const result = try gz.addUnNode(.@"resume", operand, node); |
| 920 | continue; | 983 | return rvalue(gz, scope, rl, result, node); |
| 921 | }; | 984 | } |
| 922 | 985 | ||
| 923 | if (rhs == 0) { | 986 | fn fnProtoExpr( |
| 924 | _ = try parent_gz.addBreak(.@"break", block_inst, .void_value); | 987 | gz: *GenZir, |
| 925 | return zir.Inst.Ref.unreachable_value; | 988 | scope: *Scope, |
| 926 | } | 989 | rl: ResultLoc, |
| 927 | block_gz.break_count += 1; | 990 | fn_proto: ast.full.FnProto, |
| 928 | const prev_rvalue_rl_count = block_gz.rvalue_rl_count; | 991 | ) InnerError!Zir.Inst.Ref { |
| 929 | const operand = try expr(parent_gz, parent_scope, block_gz.break_result_loc, rhs); | 992 | const astgen = gz.astgen; |
| 930 | const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count; | 993 | const gpa = astgen.gpa; |
| 994 | const tree = astgen.tree; | ||
| 995 | const token_tags = tree.tokens.items(.tag); | ||
| 931 | 996 | ||
| 932 | const br = try parent_gz.addBreak(.@"break", block_inst, operand); | 997 | const is_extern = blk: { |
| 998 | const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; | ||
| 999 | break :blk token_tags[maybe_extern_token] == .keyword_extern; | ||
| 1000 | }; | ||
| 1001 | assert(!is_extern); | ||
| 933 | 1002 | ||
| 934 | if (block_gz.break_result_loc == .block_ptr) { | 1003 | // The AST params array does not contain anytype and ... parameters. |
| 935 | try block_gz.labeled_breaks.append(mod.gpa, br); | 1004 | // We must iterate to count how many param types to allocate. |
| 1005 | const param_count = blk: { | ||
| 1006 | var count: usize = 0; | ||
| 1007 | var it = fn_proto.iterate(tree.*); | ||
| 1008 | while (it.next()) |param| { | ||
| 1009 | if (param.anytype_ellipsis3) |token| switch (token_tags[token]) { | ||
| 1010 | .ellipsis3 => break, | ||
| 1011 | .keyword_anytype => {}, | ||
| 1012 | else => unreachable, | ||
| 1013 | }; | ||
| 1014 | count += 1; | ||
| 1015 | } | ||
| 1016 | break :blk count; | ||
| 1017 | }; | ||
| 1018 | const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); | ||
| 1019 | defer gpa.free(param_types); | ||
| 936 | 1020 | ||
| 937 | if (have_store_to_block) { | 1021 | var is_var_args = false; |
| 938 | const zir_tags = parent_gz.astgen.instructions.items(.tag); | 1022 | { |
| 939 | const zir_datas = parent_gz.astgen.instructions.items(.data); | 1023 | var param_type_i: usize = 0; |
| 940 | const store_inst = @intCast(u32, zir_tags.len - 2); | 1024 | var it = fn_proto.iterate(tree.*); |
| 941 | assert(zir_tags[store_inst] == .store_to_block_ptr); | 1025 | while (it.next()) |param| : (param_type_i += 1) { |
| 942 | assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr); | 1026 | if (param.anytype_ellipsis3) |token| { |
| 943 | try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst); | 1027 | switch (token_tags[token]) { |
| 944 | } | 1028 | .keyword_anytype => { |
| 1029 | param_types[param_type_i] = .none; | ||
| 1030 | continue; | ||
| 1031 | }, | ||
| 1032 | .ellipsis3 => { | ||
| 1033 | is_var_args = true; | ||
| 1034 | break; | ||
| 1035 | }, | ||
| 1036 | else => unreachable, | ||
| 945 | } | 1037 | } |
| 946 | return zir.Inst.Ref.unreachable_value; | 1038 | } |
| 947 | }, | 1039 | const param_type_node = param.type_expr; |
| 948 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | 1040 | assert(param_type_node != 0); |
| 949 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | 1041 | param_types[param_type_i] = |
| 950 | else => if (break_label != 0) { | 1042 | try expr(gz, scope, .{ .ty = .type_type }, param_type_node); |
| 951 | const label_name = try mod.identifierTokenString(parent_scope, break_label); | ||
| 952 | return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); | ||
| 953 | } else { | ||
| 954 | return mod.failNode(parent_scope, node, "break expression outside loop", .{}); | ||
| 955 | }, | ||
| 956 | } | 1043 | } |
| 1044 | assert(param_type_i == param_count); | ||
| 957 | } | 1045 | } |
| 958 | } | ||
| 959 | |||
| 960 | fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { | ||
| 961 | const mod = parent_gz.astgen.mod; | ||
| 962 | const tree = parent_gz.tree(); | ||
| 963 | const node_datas = tree.nodes.items(.data); | ||
| 964 | const break_label = node_datas[node].lhs; | ||
| 965 | 1046 | ||
| 966 | // Look for the label in the scope. | 1047 | const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { |
| 967 | var scope = parent_scope; | 1048 | break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); |
| 968 | while (true) { | 1049 | }; |
| 969 | switch (scope.tag) { | 1050 | if (fn_proto.ast.section_expr != 0) { |
| 970 | .gen_zir => { | 1051 | return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); |
| 971 | const gen_zir = scope.cast(GenZir).?; | 1052 | } |
| 972 | const continue_block = gen_zir.continue_block; | ||
| 973 | if (continue_block == 0) { | ||
| 974 | scope = gen_zir.parent; | ||
| 975 | continue; | ||
| 976 | } | ||
| 977 | if (break_label != 0) blk: { | ||
| 978 | if (gen_zir.label) |*label| { | ||
| 979 | if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { | ||
| 980 | label.used = true; | ||
| 981 | break :blk; | ||
| 982 | } | ||
| 983 | } | ||
| 984 | // found continue but either it has a different label, or no label | ||
| 985 | scope = gen_zir.parent; | ||
| 986 | continue; | ||
| 987 | } | ||
| 988 | 1053 | ||
| 989 | // TODO emit a break_inline if the loop being continued is inline | 1054 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 990 | _ = try parent_gz.addBreak(.@"break", continue_block, .void_value); | 1055 | const is_inferred_error = token_tags[maybe_bang] == .bang; |
| 991 | return zir.Inst.Ref.unreachable_value; | 1056 | if (is_inferred_error) { |
| 992 | }, | 1057 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); |
| 993 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 994 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 995 | else => if (break_label != 0) { | ||
| 996 | const label_name = try mod.identifierTokenString(parent_scope, break_label); | ||
| 997 | return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); | ||
| 998 | } else { | ||
| 999 | return mod.failNode(parent_scope, node, "continue expression outside loop", .{}); | ||
| 1000 | }, | ||
| 1001 | } | ||
| 1002 | } | 1058 | } |
| 1059 | const return_type_inst = try AstGen.expr( | ||
| 1060 | gz, | ||
| 1061 | scope, | ||
| 1062 | .{ .ty = .type_type }, | ||
| 1063 | fn_proto.ast.return_type, | ||
| 1064 | ); | ||
| 1065 | |||
| 1066 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) | ||
| 1067 | try AstGen.expr( | ||
| 1068 | gz, | ||
| 1069 | scope, | ||
| 1070 | .{ .ty = .calling_convention_type }, | ||
| 1071 | fn_proto.ast.callconv_expr, | ||
| 1072 | ) | ||
| 1073 | else | ||
| 1074 | Zir.Inst.Ref.none; | ||
| 1075 | |||
| 1076 | const result = try gz.addFunc(.{ | ||
| 1077 | .src_node = fn_proto.ast.proto_node, | ||
| 1078 | .ret_ty = return_type_inst, | ||
| 1079 | .param_types = param_types, | ||
| 1080 | .body = &[0]Zir.Inst.Index{}, | ||
| 1081 | .cc = cc, | ||
| 1082 | .align_inst = align_inst, | ||
| 1083 | .lib_name = 0, | ||
| 1084 | .is_var_args = is_var_args, | ||
| 1085 | .is_inferred_error = false, | ||
| 1086 | .is_test = false, | ||
| 1087 | .is_extern = false, | ||
| 1088 | }); | ||
| 1089 | return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node); | ||
| 1003 | } | 1090 | } |
| 1004 | 1091 | ||
| 1005 | pub fn blockExpr( | 1092 | fn arrayInitExpr( |
| 1006 | gz: *GenZir, | 1093 | gz: *GenZir, |
| 1007 | scope: *Scope, | 1094 | scope: *Scope, |
| 1008 | rl: ResultLoc, | 1095 | rl: ResultLoc, |
| 1009 | block_node: ast.Node.Index, | 1096 | node: ast.Node.Index, |
| 1010 | statements: []const ast.Node.Index, | 1097 | array_init: ast.full.ArrayInit, |
| 1011 | ) InnerError!zir.Inst.Ref { | 1098 | ) InnerError!Zir.Inst.Ref { |
| 1012 | const tracy = trace(@src()); | 1099 | const astgen = gz.astgen; |
| 1013 | defer tracy.end(); | 1100 | const tree = astgen.tree; |
| 1014 | 1101 | const gpa = astgen.gpa; | |
| 1015 | const tree = gz.tree(); | 1102 | const node_tags = tree.nodes.items(.tag); |
| 1016 | const main_tokens = tree.nodes.items(.main_token); | 1103 | const main_tokens = tree.nodes.items(.main_token); |
| 1017 | const token_tags = tree.tokens.items(.tag); | ||
| 1018 | 1104 | ||
| 1019 | const lbrace = main_tokens[block_node]; | 1105 | assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init. |
| 1020 | if (token_tags[lbrace - 1] == .colon and | ||
| 1021 | token_tags[lbrace - 2] == .identifier) | ||
| 1022 | { | ||
| 1023 | return labeledBlockExpr(gz, scope, rl, block_node, statements, .block); | ||
| 1024 | } | ||
| 1025 | 1106 | ||
| 1026 | try blockExprStmts(gz, scope, block_node, statements); | 1107 | const types: struct { |
| 1027 | return rvalue(gz, scope, rl, .void_value, block_node); | 1108 | array: Zir.Inst.Ref, |
| 1028 | } | 1109 | elem: Zir.Inst.Ref, |
| 1110 | } = inst: { | ||
| 1111 | if (array_init.ast.type_expr == 0) break :inst .{ | ||
| 1112 | .array = .none, | ||
| 1113 | .elem = .none, | ||
| 1114 | }; | ||
| 1029 | 1115 | ||
| 1030 | fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void { | 1116 | infer: { |
| 1031 | // Look for the label in the scope. | 1117 | const array_type: ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { |
| 1032 | var scope = parent_scope; | 1118 | .array_type => tree.arrayType(array_init.ast.type_expr), |
| 1033 | while (true) { | 1119 | .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr), |
| 1034 | switch (scope.tag) { | 1120 | else => break :infer, |
| 1035 | .gen_zir => { | 1121 | }; |
| 1036 | const gen_zir = scope.cast(GenZir).?; | 1122 | // This intentionally does not support `@"_"` syntax. |
| 1037 | if (gen_zir.label) |prev_label| { | 1123 | if (node_tags[array_type.ast.elem_count] == .identifier and |
| 1038 | if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) { | 1124 | mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) |
| 1039 | const tree = parent_scope.tree(); | 1125 | { |
| 1040 | const main_tokens = tree.nodes.items(.main_token); | 1126 | const len_inst = try gz.addInt(array_init.ast.elements.len); |
| 1041 | 1127 | const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); | |
| 1042 | const label_name = try mod.identifierTokenString(parent_scope, label); | 1128 | if (array_type.ast.sentinel == 0) { |
| 1043 | const msg = msg: { | 1129 | const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type); |
| 1044 | const msg = try mod.errMsg( | 1130 | break :inst .{ |
| 1045 | parent_scope, | 1131 | .array = array_type_inst, |
| 1046 | gen_zir.tokSrcLoc(label), | 1132 | .elem = elem_type, |
| 1047 | "redefinition of label '{s}'", | 1133 | }; |
| 1048 | .{label_name}, | 1134 | } else { |
| 1049 | ); | 1135 | const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); |
| 1050 | errdefer msg.destroy(mod.gpa); | 1136 | const array_type_inst = try gz.addArrayTypeSentinel(len_inst, elem_type, sentinel); |
| 1051 | try mod.errNote( | 1137 | break :inst .{ |
| 1052 | parent_scope, | 1138 | .array = array_type_inst, |
| 1053 | gen_zir.tokSrcLoc(prev_label.token), | 1139 | .elem = elem_type, |
| 1054 | msg, | 1140 | }; |
| 1055 | "previous definition is here", | ||
| 1056 | .{}, | ||
| 1057 | ); | ||
| 1058 | break :msg msg; | ||
| 1059 | }; | ||
| 1060 | return mod.failWithOwnedErrorMsg(parent_scope, msg); | ||
| 1061 | } | ||
| 1062 | } | 1141 | } |
| 1063 | scope = gen_zir.parent; | 1142 | } |
| 1064 | }, | ||
| 1065 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 1066 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 1067 | else => return, | ||
| 1068 | } | 1143 | } |
| 1144 | const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); | ||
| 1145 | const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr); | ||
| 1146 | break :inst .{ | ||
| 1147 | .array = array_type_inst, | ||
| 1148 | .elem = elem_type, | ||
| 1149 | }; | ||
| 1150 | }; | ||
| 1151 | |||
| 1152 | switch (rl) { | ||
| 1153 | .discard => { | ||
| 1154 | for (array_init.ast.elements) |elem_init| { | ||
| 1155 | _ = try expr(gz, scope, .discard, elem_init); | ||
| 1156 | } | ||
| 1157 | return Zir.Inst.Ref.void_value; | ||
| 1158 | }, | ||
| 1159 | .ref => { | ||
| 1160 | if (types.array != .none) { | ||
| 1161 | return arrayInitExprRlTy(gz, scope, rl, node, array_init.ast.elements, types.array, types.elem, .array_init_ref); | ||
| 1162 | } else { | ||
| 1163 | return arrayInitExprRlNone(gz, scope, rl, node, array_init.ast.elements, .array_init_anon_ref); | ||
| 1164 | } | ||
| 1165 | }, | ||
| 1166 | .none, .none_or_ref => { | ||
| 1167 | if (types.array != .none) { | ||
| 1168 | return arrayInitExprRlTy(gz, scope, rl, node, array_init.ast.elements, types.array, types.elem, .array_init); | ||
| 1169 | } else { | ||
| 1170 | return arrayInitExprRlNone(gz, scope, rl, node, array_init.ast.elements, .array_init_anon); | ||
| 1171 | } | ||
| 1172 | }, | ||
| 1173 | .ty => |ty_inst| { | ||
| 1174 | if (types.array != .none) { | ||
| 1175 | const result = try arrayInitExprRlTy(gz, scope, rl, node, array_init.ast.elements, types.array, types.elem, .array_init); | ||
| 1176 | return rvalue(gz, scope, rl, result, node); | ||
| 1177 | } else { | ||
| 1178 | const elem_type = try gz.addUnNode(.elem_type, ty_inst, node); | ||
| 1179 | return arrayInitExprRlTy(gz, scope, rl, node, array_init.ast.elements, ty_inst, elem_type, .array_init); | ||
| 1180 | } | ||
| 1181 | }, | ||
| 1182 | .ptr, .inferred_ptr => |ptr_inst| { | ||
| 1183 | return arrayInitExprRlPtr(gz, scope, rl, node, array_init.ast.elements, ptr_inst); | ||
| 1184 | }, | ||
| 1185 | .block_ptr => |block_gz| { | ||
| 1186 | return arrayInitExprRlPtr(gz, scope, rl, node, array_init.ast.elements, block_gz.rl_ptr); | ||
| 1187 | }, | ||
| 1069 | } | 1188 | } |
| 1070 | } | 1189 | } |
| 1071 | 1190 | ||
| 1072 | fn labeledBlockExpr( | 1191 | fn arrayInitExprRlNone( |
| 1073 | gz: *GenZir, | 1192 | gz: *GenZir, |
| 1074 | parent_scope: *Scope, | 1193 | scope: *Scope, |
| 1075 | rl: ResultLoc, | 1194 | rl: ResultLoc, |
| 1076 | block_node: ast.Node.Index, | 1195 | node: ast.Node.Index, |
| 1077 | statements: []const ast.Node.Index, | 1196 | elements: []const ast.Node.Index, |
| 1078 | zir_tag: zir.Inst.Tag, | 1197 | tag: Zir.Inst.Tag, |
| 1079 | ) InnerError!zir.Inst.Ref { | 1198 | ) InnerError!Zir.Inst.Ref { |
| 1080 | const tracy = trace(@src()); | 1199 | const astgen = gz.astgen; |
| 1081 | defer tracy.end(); | 1200 | const gpa = astgen.gpa; |
| 1201 | const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len); | ||
| 1202 | defer gpa.free(elem_list); | ||
| 1082 | 1203 | ||
| 1083 | assert(zir_tag == .block); | 1204 | for (elements) |elem_init, i| { |
| 1205 | elem_list[i] = try expr(gz, scope, .none, elem_init); | ||
| 1206 | } | ||
| 1207 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{ | ||
| 1208 | .operands_len = @intCast(u32, elem_list.len), | ||
| 1209 | }); | ||
| 1210 | try astgen.appendRefs(elem_list); | ||
| 1211 | return init_inst; | ||
| 1212 | } | ||
| 1084 | 1213 | ||
| 1085 | const mod = gz.astgen.mod; | 1214 | fn arrayInitExprRlTy( |
| 1086 | const tree = gz.tree(); | 1215 | gz: *GenZir, |
| 1087 | const main_tokens = tree.nodes.items(.main_token); | 1216 | scope: *Scope, |
| 1088 | const token_tags = tree.tokens.items(.tag); | 1217 | rl: ResultLoc, |
| 1218 | node: ast.Node.Index, | ||
| 1219 | elements: []const ast.Node.Index, | ||
| 1220 | array_ty_inst: Zir.Inst.Ref, | ||
| 1221 | elem_ty_inst: Zir.Inst.Ref, | ||
| 1222 | tag: Zir.Inst.Tag, | ||
| 1223 | ) InnerError!Zir.Inst.Ref { | ||
| 1224 | const astgen = gz.astgen; | ||
| 1225 | const gpa = astgen.gpa; | ||
| 1089 | 1226 | ||
| 1090 | const lbrace = main_tokens[block_node]; | 1227 | const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len); |
| 1091 | const label_token = lbrace - 2; | 1228 | defer gpa.free(elem_list); |
| 1092 | assert(token_tags[label_token] == .identifier); | ||
| 1093 | 1229 | ||
| 1094 | try checkLabelRedefinition(mod, parent_scope, label_token); | 1230 | const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; |
| 1095 | 1231 | ||
| 1096 | // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct | 1232 | for (elements) |elem_init, i| { |
| 1097 | // so that break statements can reference it. | 1233 | elem_list[i] = try expr(gz, scope, elem_rl, elem_init); |
| 1098 | const block_inst = try gz.addBlock(zir_tag, block_node); | 1234 | } |
| 1099 | try gz.instructions.append(mod.gpa, block_inst); | 1235 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{ |
| 1236 | .operands_len = @intCast(u32, elem_list.len), | ||
| 1237 | }); | ||
| 1238 | try astgen.appendRefs(elem_list); | ||
| 1239 | return init_inst; | ||
| 1240 | } | ||
| 1100 | 1241 | ||
| 1101 | var block_scope: GenZir = .{ | 1242 | fn arrayInitExprRlPtr( |
| 1102 | .parent = parent_scope, | 1243 | gz: *GenZir, |
| 1103 | .astgen = gz.astgen, | 1244 | scope: *Scope, |
| 1104 | .force_comptime = gz.force_comptime, | 1245 | rl: ResultLoc, |
| 1105 | .instructions = .{}, | 1246 | node: ast.Node.Index, |
| 1106 | // TODO @as here is working around a stage1 miscompilation bug :( | 1247 | elements: []const ast.Node.Index, |
| 1107 | .label = @as(?GenZir.Label, GenZir.Label{ | 1248 | result_ptr: Zir.Inst.Ref, |
| 1108 | .token = label_token, | 1249 | ) InnerError!Zir.Inst.Ref { |
| 1109 | .block_inst = block_inst, | 1250 | const astgen = gz.astgen; |
| 1110 | }), | 1251 | const gpa = astgen.gpa; |
| 1111 | }; | ||
| 1112 | block_scope.setBreakResultLoc(rl); | ||
| 1113 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 1114 | defer block_scope.labeled_breaks.deinit(mod.gpa); | ||
| 1115 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); | ||
| 1116 | 1252 | ||
| 1117 | try blockExprStmts(&block_scope, &block_scope.base, block_node, statements); | 1253 | const elem_ptr_list = try gpa.alloc(Zir.Inst.Index, elements.len); |
| 1254 | defer gpa.free(elem_ptr_list); | ||
| 1118 | 1255 | ||
| 1119 | if (!block_scope.label.?.used) { | 1256 | for (elements) |elem_init, i| { |
| 1120 | return mod.failTok(parent_scope, label_token, "unused block label", .{}); | 1257 | const index_inst = try gz.addInt(i); |
| 1258 | const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{ | ||
| 1259 | .lhs = result_ptr, | ||
| 1260 | .rhs = index_inst, | ||
| 1261 | }); | ||
| 1262 | elem_ptr_list[i] = gz.refToIndex(elem_ptr).?; | ||
| 1263 | _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init); | ||
| 1121 | } | 1264 | } |
| 1265 | _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{ | ||
| 1266 | .body_len = @intCast(u32, elem_ptr_list.len), | ||
| 1267 | }); | ||
| 1268 | try astgen.extra.appendSlice(gpa, elem_ptr_list); | ||
| 1269 | return .void_value; | ||
| 1270 | } | ||
| 1122 | 1271 | ||
| 1123 | const zir_tags = gz.astgen.instructions.items(.tag); | 1272 | fn structInitExpr( |
| 1124 | const zir_datas = gz.astgen.instructions.items(.data); | 1273 | gz: *GenZir, |
| 1274 | scope: *Scope, | ||
| 1275 | rl: ResultLoc, | ||
| 1276 | node: ast.Node.Index, | ||
| 1277 | struct_init: ast.full.StructInit, | ||
| 1278 | ) InnerError!Zir.Inst.Ref { | ||
| 1279 | const astgen = gz.astgen; | ||
| 1280 | const tree = astgen.tree; | ||
| 1281 | const gpa = astgen.gpa; | ||
| 1125 | 1282 | ||
| 1126 | const strat = rl.strategy(&block_scope); | 1283 | if (struct_init.ast.fields.len == 0) { |
| 1127 | switch (strat.tag) { | 1284 | if (struct_init.ast.type_expr == 0) { |
| 1128 | .break_void => { | 1285 | return rvalue(gz, scope, rl, .empty_struct, node); |
| 1129 | // The code took advantage of the result location as a pointer. | 1286 | } |
| 1130 | // Turn the break instruction operands into void. | 1287 | array: { |
| 1131 | for (block_scope.labeled_breaks.items) |br| { | 1288 | const node_tags = tree.nodes.items(.tag); |
| 1132 | zir_datas[br].@"break".operand = .void_value; | 1289 | const main_tokens = tree.nodes.items(.main_token); |
| 1290 | const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { | ||
| 1291 | .array_type => tree.arrayType(struct_init.ast.type_expr), | ||
| 1292 | .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), | ||
| 1293 | else => break :array, | ||
| 1294 | }; | ||
| 1295 | // This intentionally does not support `@"_"` syntax. | ||
| 1296 | if (node_tags[array_type.ast.elem_count] == .identifier and | ||
| 1297 | mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) | ||
| 1298 | { | ||
| 1299 | const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); | ||
| 1300 | const array_type_inst = if (array_type.ast.sentinel == 0) blk: { | ||
| 1301 | break :blk try gz.addBin(.array_type, .zero_usize, elem_type); | ||
| 1302 | } else blk: { | ||
| 1303 | const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); | ||
| 1304 | break :blk try gz.addArrayTypeSentinel(.zero_usize, elem_type, sentinel); | ||
| 1305 | }; | ||
| 1306 | const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); | ||
| 1307 | return rvalue(gz, scope, rl, result, node); | ||
| 1133 | } | 1308 | } |
| 1134 | try block_scope.setBlockBody(block_inst); | 1309 | } |
| 1135 | 1310 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | |
| 1136 | return gz.astgen.indexToRef(block_inst); | 1311 | const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); |
| 1312 | return rvalue(gz, scope, rl, result, node); | ||
| 1313 | } | ||
| 1314 | switch (rl) { | ||
| 1315 | .discard => { | ||
| 1316 | for (struct_init.ast.fields) |field_init| { | ||
| 1317 | _ = try expr(gz, scope, .discard, field_init); | ||
| 1318 | } | ||
| 1319 | return Zir.Inst.Ref.void_value; | ||
| 1137 | }, | 1320 | }, |
| 1138 | .break_operand => { | 1321 | .ref => { |
| 1139 | // All break operands are values that did not use the result location pointer. | 1322 | if (struct_init.ast.type_expr != 0) { |
| 1140 | if (strat.elide_store_to_block_ptr_instructions) { | 1323 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1141 | for (block_scope.labeled_store_to_block_ptr_list.items) |inst| { | 1324 | return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init_ref); |
| 1142 | zir_tags[inst] = .elided; | 1325 | } else { |
| 1143 | zir_datas[inst] = undefined; | 1326 | return structInitExprRlNone(gz, scope, rl, node, struct_init, .struct_init_anon_ref); |
| 1144 | } | ||
| 1145 | // TODO technically not needed since we changed the tag to elided but | ||
| 1146 | // would be better still to elide the ones that are in this list. | ||
| 1147 | } | 1327 | } |
| 1148 | try block_scope.setBlockBody(block_inst); | 1328 | }, |
| 1149 | const block_ref = gz.astgen.indexToRef(block_inst); | 1329 | .none, .none_or_ref => { |
| 1150 | switch (rl) { | 1330 | if (struct_init.ast.type_expr != 0) { |
| 1151 | .ref => return block_ref, | 1331 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1152 | else => return rvalue(gz, parent_scope, rl, block_ref, block_node), | 1332 | return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init); |
| 1333 | } else { | ||
| 1334 | return structInitExprRlNone(gz, scope, rl, node, struct_init, .struct_init_anon); | ||
| 1335 | } | ||
| 1336 | }, | ||
| 1337 | .ty => |ty_inst| { | ||
| 1338 | if (struct_init.ast.type_expr == 0) { | ||
| 1339 | return structInitExprRlTy(gz, scope, rl, node, struct_init, ty_inst, .struct_init); | ||
| 1153 | } | 1340 | } |
| 1341 | const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | ||
| 1342 | const result = try structInitExprRlTy(gz, scope, rl, node, struct_init, inner_ty_inst, .struct_init); | ||
| 1343 | return rvalue(gz, scope, rl, result, node); | ||
| 1154 | }, | 1344 | }, |
| 1345 | .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst), | ||
| 1346 | .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr), | ||
| 1155 | } | 1347 | } |
| 1156 | } | 1348 | } |
| 1157 | 1349 | ||
| 1158 | fn blockExprStmts( | 1350 | fn structInitExprRlNone( |
| 1159 | gz: *GenZir, | 1351 | gz: *GenZir, |
| 1160 | parent_scope: *Scope, | 1352 | scope: *Scope, |
| 1353 | rl: ResultLoc, | ||
| 1161 | node: ast.Node.Index, | 1354 | node: ast.Node.Index, |
| 1162 | statements: []const ast.Node.Index, | 1355 | struct_init: ast.full.StructInit, |
| 1163 | ) !void { | 1356 | tag: Zir.Inst.Tag, |
| 1164 | const tree = gz.tree(); | 1357 | ) InnerError!Zir.Inst.Ref { |
| 1165 | const main_tokens = tree.nodes.items(.main_token); | 1358 | const astgen = gz.astgen; |
| 1166 | const node_tags = tree.nodes.items(.tag); | 1359 | const gpa = astgen.gpa; |
| 1167 | 1360 | const tree = astgen.tree; | |
| 1168 | var block_arena = std.heap.ArenaAllocator.init(gz.astgen.mod.gpa); | ||
| 1169 | defer block_arena.deinit(); | ||
| 1170 | 1361 | ||
| 1171 | var scope = parent_scope; | 1362 | const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len); |
| 1172 | for (statements) |statement| { | 1363 | defer gpa.free(fields_list); |
| 1173 | if (!gz.force_comptime) { | ||
| 1174 | _ = try gz.addNode(.dbg_stmt_node, statement); | ||
| 1175 | } | ||
| 1176 | switch (node_tags[statement]) { | ||
| 1177 | .global_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)), | ||
| 1178 | .local_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)), | ||
| 1179 | .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), | ||
| 1180 | .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), | ||
| 1181 | 1364 | ||
| 1182 | .assign => try assign(gz, scope, statement), | 1365 | for (struct_init.ast.fields) |field_init, i| { |
| 1183 | .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), | 1366 | const name_token = tree.firstToken(field_init) - 2; |
| 1184 | .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), | 1367 | const str_index = try astgen.identAsString(name_token); |
| 1185 | .assign_bit_shift_left => try assignOp(gz, scope, statement, .shl), | ||
| 1186 | .assign_bit_shift_right => try assignOp(gz, scope, statement, .shr), | ||
| 1187 | .assign_bit_xor => try assignOp(gz, scope, statement, .xor), | ||
| 1188 | .assign_div => try assignOp(gz, scope, statement, .div), | ||
| 1189 | .assign_sub => try assignOp(gz, scope, statement, .sub), | ||
| 1190 | .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), | ||
| 1191 | .assign_mod => try assignOp(gz, scope, statement, .mod_rem), | ||
| 1192 | .assign_add => try assignOp(gz, scope, statement, .add), | ||
| 1193 | .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), | ||
| 1194 | .assign_mul => try assignOp(gz, scope, statement, .mul), | ||
| 1195 | .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), | ||
| 1196 | 1368 | ||
| 1197 | else => { | 1369 | fields_list[i] = .{ |
| 1198 | // We need to emit an error if the result is not `noreturn` or `void`, but | 1370 | .field_name = str_index, |
| 1199 | // we want to avoid adding the ZIR instruction if possible for performance. | 1371 | .init = try expr(gz, scope, .none, field_init), |
| 1200 | const maybe_unused_result = try expr(gz, scope, .none, statement); | 1372 | }; |
| 1201 | const elide_check = if (gz.astgen.refToIndex(maybe_unused_result)) |inst| b: { | 1373 | } |
| 1202 | // Note that this array becomes invalid after appending more items to it | 1374 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{ |
| 1203 | // in the above while loop. | 1375 | .fields_len = @intCast(u32, fields_list.len), |
| 1204 | const zir_tags = gz.astgen.instructions.items(.tag); | 1376 | }); |
| 1205 | switch (zir_tags[inst]) { | 1377 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + |
| 1206 | // For some instructions, swap in a slightly different ZIR tag | 1378 | fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len); |
| 1207 | // so we can avoid a separate ensure_result_used instruction. | 1379 | for (fields_list) |field| { |
| 1208 | .call_none_chkused => unreachable, | 1380 | _ = gz.astgen.addExtraAssumeCapacity(field); |
| 1209 | .call_none => { | 1381 | } |
| 1210 | zir_tags[inst] = .call_none_chkused; | 1382 | return init_inst; |
| 1211 | break :b true; | 1383 | } |
| 1212 | }, | ||
| 1213 | .call_chkused => unreachable, | ||
| 1214 | .call => { | ||
| 1215 | zir_tags[inst] = .call_chkused; | ||
| 1216 | break :b true; | ||
| 1217 | }, | ||
| 1218 | 1384 | ||
| 1219 | // ZIR instructions that might be a type other than `noreturn` or `void`. | 1385 | fn structInitExprRlPtr( |
| 1220 | .add, | 1386 | gz: *GenZir, |
| 1221 | .addwrap, | 1387 | scope: *Scope, |
| 1222 | .alloc, | 1388 | rl: ResultLoc, |
| 1223 | .alloc_mut, | 1389 | node: ast.Node.Index, |
| 1224 | .alloc_inferred, | 1390 | struct_init: ast.full.StructInit, |
| 1225 | .alloc_inferred_mut, | 1391 | result_ptr: Zir.Inst.Ref, |
| 1226 | .array_cat, | 1392 | ) InnerError!Zir.Inst.Ref { |
| 1227 | .array_mul, | 1393 | const astgen = gz.astgen; |
| 1228 | .array_type, | 1394 | const gpa = astgen.gpa; |
| 1229 | .array_type_sentinel, | 1395 | const tree = astgen.tree; |
| 1230 | .indexable_ptr_len, | ||
| 1231 | .as, | ||
| 1232 | .as_node, | ||
| 1233 | .@"asm", | ||
| 1234 | .asm_volatile, | ||
| 1235 | .bit_and, | ||
| 1236 | .bitcast, | ||
| 1237 | .bitcast_result_ptr, | ||
| 1238 | .bit_or, | ||
| 1239 | .block, | ||
| 1240 | .block_inline, | ||
| 1241 | .loop, | ||
| 1242 | .bool_br_and, | ||
| 1243 | .bool_br_or, | ||
| 1244 | .bool_not, | ||
| 1245 | .bool_and, | ||
| 1246 | .bool_or, | ||
| 1247 | .call_compile_time, | ||
| 1248 | .cmp_lt, | ||
| 1249 | .cmp_lte, | ||
| 1250 | .cmp_eq, | ||
| 1251 | .cmp_gte, | ||
| 1252 | .cmp_gt, | ||
| 1253 | .cmp_neq, | ||
| 1254 | .coerce_result_ptr, | ||
| 1255 | .decl_ref, | ||
| 1256 | .decl_val, | ||
| 1257 | .load, | ||
| 1258 | .div, | ||
| 1259 | .elem_ptr, | ||
| 1260 | .elem_val, | ||
| 1261 | .elem_ptr_node, | ||
| 1262 | .elem_val_node, | ||
| 1263 | .floatcast, | ||
| 1264 | .field_ptr, | ||
| 1265 | .field_val, | ||
| 1266 | .field_ptr_named, | ||
| 1267 | .field_val_named, | ||
| 1268 | .fn_type, | ||
| 1269 | .fn_type_var_args, | ||
| 1270 | .fn_type_cc, | ||
| 1271 | .fn_type_cc_var_args, | ||
| 1272 | .has_decl, | ||
| 1273 | .int, | ||
| 1274 | .float, | ||
| 1275 | .float128, | ||
| 1276 | .intcast, | ||
| 1277 | .int_type, | ||
| 1278 | .is_non_null, | ||
| 1279 | .is_null, | ||
| 1280 | .is_non_null_ptr, | ||
| 1281 | .is_null_ptr, | ||
| 1282 | .is_err, | ||
| 1283 | .is_err_ptr, | ||
| 1284 | .mod_rem, | ||
| 1285 | .mul, | ||
| 1286 | .mulwrap, | ||
| 1287 | .param_type, | ||
| 1288 | .ptrtoint, | ||
| 1289 | .ref, | ||
| 1290 | .ret_ptr, | ||
| 1291 | .ret_type, | ||
| 1292 | .shl, | ||
| 1293 | .shr, | ||
| 1294 | .str, | ||
| 1295 | .sub, | ||
| 1296 | .subwrap, | ||
| 1297 | .negate, | ||
| 1298 | .negate_wrap, | ||
| 1299 | .typeof, | ||
| 1300 | .typeof_elem, | ||
| 1301 | .xor, | ||
| 1302 | .optional_type, | ||
| 1303 | .optional_type_from_ptr_elem, | ||
| 1304 | .optional_payload_safe, | ||
| 1305 | .optional_payload_unsafe, | ||
| 1306 | .optional_payload_safe_ptr, | ||
| 1307 | .optional_payload_unsafe_ptr, | ||
| 1308 | .err_union_payload_safe, | ||
| 1309 | .err_union_payload_unsafe, | ||
| 1310 | .err_union_payload_safe_ptr, | ||
| 1311 | .err_union_payload_unsafe_ptr, | ||
| 1312 | .err_union_code, | ||
| 1313 | .err_union_code_ptr, | ||
| 1314 | .ptr_type, | ||
| 1315 | .ptr_type_simple, | ||
| 1316 | .enum_literal, | ||
| 1317 | .enum_literal_small, | ||
| 1318 | .merge_error_sets, | ||
| 1319 | .error_union_type, | ||
| 1320 | .bit_not, | ||
| 1321 | .error_value, | ||
| 1322 | .error_to_int, | ||
| 1323 | .int_to_error, | ||
| 1324 | .slice_start, | ||
| 1325 | .slice_end, | ||
| 1326 | .slice_sentinel, | ||
| 1327 | .import, | ||
| 1328 | .typeof_peer, | ||
| 1329 | .switch_block, | ||
| 1330 | .switch_block_multi, | ||
| 1331 | .switch_block_else, | ||
| 1332 | .switch_block_else_multi, | ||
| 1333 | .switch_block_under, | ||
| 1334 | .switch_block_under_multi, | ||
| 1335 | .switch_block_ref, | ||
| 1336 | .switch_block_ref_multi, | ||
| 1337 | .switch_block_ref_else, | ||
| 1338 | .switch_block_ref_else_multi, | ||
| 1339 | .switch_block_ref_under, | ||
| 1340 | .switch_block_ref_under_multi, | ||
| 1341 | .switch_capture, | ||
| 1342 | .switch_capture_ref, | ||
| 1343 | .switch_capture_multi, | ||
| 1344 | .switch_capture_multi_ref, | ||
| 1345 | .switch_capture_else, | ||
| 1346 | .switch_capture_else_ref, | ||
| 1347 | .struct_init_empty, | ||
| 1348 | .struct_init, | ||
| 1349 | .field_type, | ||
| 1350 | .struct_decl, | ||
| 1351 | .struct_decl_packed, | ||
| 1352 | .struct_decl_extern, | ||
| 1353 | .union_decl, | ||
| 1354 | .enum_decl, | ||
| 1355 | .enum_decl_nonexhaustive, | ||
| 1356 | .opaque_decl, | ||
| 1357 | .int_to_enum, | ||
| 1358 | .enum_to_int, | ||
| 1359 | .type_info, | ||
| 1360 | => break :b false, | ||
| 1361 | |||
| 1362 | // ZIR instructions that are always either `noreturn` or `void`. | ||
| 1363 | .breakpoint, | ||
| 1364 | .dbg_stmt_node, | ||
| 1365 | .ensure_result_used, | ||
| 1366 | .ensure_result_non_error, | ||
| 1367 | .@"export", | ||
| 1368 | .set_eval_branch_quota, | ||
| 1369 | .compile_log, | ||
| 1370 | .ensure_err_payload_void, | ||
| 1371 | .@"break", | ||
| 1372 | .break_inline, | ||
| 1373 | .condbr, | ||
| 1374 | .condbr_inline, | ||
| 1375 | .compile_error, | ||
| 1376 | .ret_node, | ||
| 1377 | .ret_tok, | ||
| 1378 | .ret_coerce, | ||
| 1379 | .@"unreachable", | ||
| 1380 | .elided, | ||
| 1381 | .store, | ||
| 1382 | .store_node, | ||
| 1383 | .store_to_block_ptr, | ||
| 1384 | .store_to_inferred_ptr, | ||
| 1385 | .resolve_inferred_alloc, | ||
| 1386 | .repeat, | ||
| 1387 | .repeat_inline, | ||
| 1388 | .validate_struct_init_ptr, | ||
| 1389 | => break :b true, | ||
| 1390 | } | ||
| 1391 | } else switch (maybe_unused_result) { | ||
| 1392 | .none => unreachable, | ||
| 1393 | 1396 | ||
| 1394 | .void_value, | 1397 | const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len); |
| 1395 | .unreachable_value, | 1398 | defer gpa.free(field_ptr_list); |
| 1396 | => true, | ||
| 1397 | 1399 | ||
| 1398 | else => false, | 1400 | for (struct_init.ast.fields) |field_init, i| { |
| 1399 | }; | 1401 | const name_token = tree.firstToken(field_init) - 2; |
| 1400 | if (!elide_check) { | 1402 | const str_index = try astgen.identAsString(name_token); |
| 1401 | _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); | 1403 | const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{ |
| 1402 | } | 1404 | .lhs = result_ptr, |
| 1403 | }, | 1405 | .field_name_start = str_index, |
| 1404 | } | 1406 | }); |
| 1407 | field_ptr_list[i] = gz.refToIndex(field_ptr).?; | ||
| 1408 | _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); | ||
| 1405 | } | 1409 | } |
| 1410 | _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{ | ||
| 1411 | .body_len = @intCast(u32, field_ptr_list.len), | ||
| 1412 | }); | ||
| 1413 | try astgen.extra.appendSlice(gpa, field_ptr_list); | ||
| 1414 | return .void_value; | ||
| 1406 | } | 1415 | } |
| 1407 | 1416 | ||
| 1408 | fn varDecl( | 1417 | fn structInitExprRlTy( |
| 1409 | gz: *GenZir, | 1418 | gz: *GenZir, |
| 1410 | scope: *Scope, | 1419 | scope: *Scope, |
| 1420 | rl: ResultLoc, | ||
| 1411 | node: ast.Node.Index, | 1421 | node: ast.Node.Index, |
| 1412 | block_arena: *Allocator, | 1422 | struct_init: ast.full.StructInit, |
| 1413 | var_decl: ast.full.VarDecl, | 1423 | ty_inst: Zir.Inst.Ref, |
| 1414 | ) InnerError!*Scope { | 1424 | tag: Zir.Inst.Tag, |
| 1415 | const mod = gz.astgen.mod; | 1425 | ) InnerError!Zir.Inst.Ref { |
| 1416 | if (var_decl.comptime_token) |comptime_token| { | ||
| 1417 | return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{}); | ||
| 1418 | } | ||
| 1419 | if (var_decl.ast.align_node != 0) { | ||
| 1420 | return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{}); | ||
| 1421 | } | ||
| 1422 | const astgen = gz.astgen; | 1426 | const astgen = gz.astgen; |
| 1423 | const tree = gz.tree(); | 1427 | const gpa = astgen.gpa; |
| 1424 | const token_tags = tree.tokens.items(.tag); | 1428 | const tree = astgen.tree; |
| 1425 | 1429 | ||
| 1426 | const name_token = var_decl.ast.mut_token + 1; | 1430 | const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len); |
| 1427 | const name_src = gz.tokSrcLoc(name_token); | 1431 | defer gpa.free(fields_list); |
| 1428 | const ident_name = try mod.identifierTokenString(scope, name_token); | ||
| 1429 | 1432 | ||
| 1430 | // Local variables shadowing detection, including function parameters. | 1433 | for (struct_init.ast.fields) |field_init, i| { |
| 1431 | { | 1434 | const name_token = tree.firstToken(field_init) - 2; |
| 1432 | var s = scope; | 1435 | const str_index = try astgen.identAsString(name_token); |
| 1433 | while (true) switch (s.tag) { | ||
| 1434 | .local_val => { | ||
| 1435 | const local_val = s.cast(Scope.LocalVal).?; | ||
| 1436 | if (mem.eql(u8, local_val.name, ident_name)) { | ||
| 1437 | const msg = msg: { | ||
| 1438 | const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ | ||
| 1439 | ident_name, | ||
| 1440 | }); | ||
| 1441 | errdefer msg.destroy(mod.gpa); | ||
| 1442 | try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{}); | ||
| 1443 | break :msg msg; | ||
| 1444 | }; | ||
| 1445 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 1446 | } | ||
| 1447 | s = local_val.parent; | ||
| 1448 | }, | ||
| 1449 | .local_ptr => { | ||
| 1450 | const local_ptr = s.cast(Scope.LocalPtr).?; | ||
| 1451 | if (mem.eql(u8, local_ptr.name, ident_name)) { | ||
| 1452 | const msg = msg: { | ||
| 1453 | const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ | ||
| 1454 | ident_name, | ||
| 1455 | }); | ||
| 1456 | errdefer msg.destroy(mod.gpa); | ||
| 1457 | try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{}); | ||
| 1458 | break :msg msg; | ||
| 1459 | }; | ||
| 1460 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 1461 | } | ||
| 1462 | s = local_ptr.parent; | ||
| 1463 | }, | ||
| 1464 | .gen_zir => s = s.cast(GenZir).?.parent, | ||
| 1465 | else => break, | ||
| 1466 | }; | ||
| 1467 | } | ||
| 1468 | 1436 | ||
| 1469 | // Namespace vars shadowing detection | 1437 | const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ |
| 1470 | if (mod.lookupDeclName(scope, ident_name)) |_| { | 1438 | .container_type = ty_inst, |
| 1471 | // TODO add note for other definition | 1439 | .name_start = str_index, |
| 1472 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); | 1440 | }); |
| 1441 | fields_list[i] = .{ | ||
| 1442 | .field_type = gz.refToIndex(field_ty_inst).?, | ||
| 1443 | .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init), | ||
| 1444 | }; | ||
| 1473 | } | 1445 | } |
| 1474 | if (var_decl.ast.init_node == 0) { | 1446 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{ |
| 1475 | return mod.fail(scope, name_src, "variables must be initialized", .{}); | 1447 | .fields_len = @intCast(u32, fields_list.len), |
| 1448 | }); | ||
| 1449 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 1450 | fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len); | ||
| 1451 | for (fields_list) |field| { | ||
| 1452 | _ = gz.astgen.addExtraAssumeCapacity(field); | ||
| 1476 | } | 1453 | } |
| 1454 | return init_inst; | ||
| 1455 | } | ||
| 1477 | 1456 | ||
| 1478 | switch (token_tags[var_decl.ast.mut_token]) { | 1457 | /// This calls expr in a comptime scope, and is intended to be called as a helper function. |
| 1479 | .keyword_const => { | 1458 | /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`. |
| 1480 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 1459 | fn comptimeExpr( |
| 1481 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as | 1460 | gz: *GenZir, |
| 1482 | // the variable, no memory location needed. | 1461 | scope: *Scope, |
| 1483 | if (!nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) { | 1462 | rl: ResultLoc, |
| 1484 | const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{ | 1463 | node: ast.Node.Index, |
| 1485 | .ty = try typeExpr(gz, scope, var_decl.ast.type_node), | 1464 | ) InnerError!Zir.Inst.Ref { |
| 1486 | } else .none; | 1465 | const prev_force_comptime = gz.force_comptime; |
| 1487 | const init_inst = try expr(gz, scope, result_loc, var_decl.ast.init_node); | 1466 | gz.force_comptime = true; |
| 1488 | const sub_scope = try block_arena.create(Scope.LocalVal); | 1467 | const result = try expr(gz, scope, rl, node); |
| 1489 | sub_scope.* = .{ | 1468 | gz.force_comptime = prev_force_comptime; |
| 1490 | .parent = scope, | 1469 | return result; |
| 1491 | .gen_zir = gz, | 1470 | } |
| 1492 | .name = ident_name, | ||
| 1493 | .inst = init_inst, | ||
| 1494 | .src = name_src, | ||
| 1495 | }; | ||
| 1496 | return &sub_scope.base; | ||
| 1497 | } | ||
| 1498 | 1471 | ||
| 1499 | // Detect whether the initialization expression actually uses the | 1472 | /// This one is for an actual `comptime` syntax, and will emit a compile error if |
| 1500 | // result location pointer. | 1473 | /// the scope already has `force_comptime=true`. |
| 1501 | var init_scope: GenZir = .{ | 1474 | /// See `comptimeExpr` for the helper function for calling expr in a comptime scope. |
| 1502 | .parent = scope, | 1475 | fn comptimeExprAst( |
| 1503 | .force_comptime = gz.force_comptime, | 1476 | gz: *GenZir, |
| 1504 | .astgen = astgen, | 1477 | scope: *Scope, |
| 1505 | }; | 1478 | rl: ResultLoc, |
| 1506 | defer init_scope.instructions.deinit(mod.gpa); | 1479 | node: ast.Node.Index, |
| 1480 | ) InnerError!Zir.Inst.Ref { | ||
| 1481 | const astgen = gz.astgen; | ||
| 1482 | if (gz.force_comptime) { | ||
| 1483 | return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); | ||
| 1484 | } | ||
| 1485 | const tree = astgen.tree; | ||
| 1486 | const node_datas = tree.nodes.items(.data); | ||
| 1487 | const body_node = node_datas[node].lhs; | ||
| 1488 | gz.force_comptime = true; | ||
| 1489 | const result = try expr(gz, scope, rl, body_node); | ||
| 1490 | gz.force_comptime = false; | ||
| 1491 | return result; | ||
| 1492 | } | ||
| 1507 | 1493 | ||
| 1508 | var resolve_inferred_alloc: zir.Inst.Ref = .none; | 1494 | fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 1509 | var opt_type_inst: zir.Inst.Ref = .none; | 1495 | const astgen = parent_gz.astgen; |
| 1510 | if (var_decl.ast.type_node != 0) { | 1496 | const tree = astgen.tree; |
| 1511 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); | 1497 | const node_datas = tree.nodes.items(.data); |
| 1512 | opt_type_inst = type_inst; | 1498 | const break_label = node_datas[node].lhs; |
| 1513 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); | 1499 | const rhs = node_datas[node].rhs; |
| 1514 | init_scope.rl_ty_inst = type_inst; | ||
| 1515 | } else { | ||
| 1516 | const alloc = try init_scope.addNode(.alloc_inferred, node); | ||
| 1517 | resolve_inferred_alloc = alloc; | ||
| 1518 | init_scope.rl_ptr = alloc; | ||
| 1519 | } | ||
| 1520 | const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; | ||
| 1521 | const init_inst = try expr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node); | ||
| 1522 | const zir_tags = astgen.instructions.items(.tag); | ||
| 1523 | const zir_datas = astgen.instructions.items(.data); | ||
| 1524 | 1500 | ||
| 1525 | const parent_zir = &gz.instructions; | 1501 | // Look for the label in the scope. |
| 1526 | if (init_scope.rvalue_rl_count == 1) { | 1502 | var scope = parent_scope; |
| 1527 | // Result location pointer not used. We don't need an alloc for this | 1503 | while (true) { |
| 1528 | // const local, and type inference becomes trivial. | 1504 | switch (scope.tag) { |
| 1529 | // Move the init_scope instructions into the parent scope, eliding | 1505 | .gen_zir => { |
| 1530 | // the alloc instruction and the store_to_block_ptr instruction. | 1506 | const block_gz = scope.cast(GenZir).?; |
| 1531 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2; | 1507 | |
| 1532 | try parent_zir.ensureCapacity(mod.gpa, expected_len); | 1508 | const block_inst = blk: { |
| 1533 | for (init_scope.instructions.items) |src_inst| { | 1509 | if (break_label != 0) { |
| 1534 | if (astgen.indexToRef(src_inst) == init_scope.rl_ptr) continue; | 1510 | if (block_gz.label) |*label| { |
| 1535 | if (zir_tags[src_inst] == .store_to_block_ptr) { | 1511 | if (try astgen.tokenIdentEql(label.token, break_label)) { |
| 1536 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; | 1512 | label.used = true; |
| 1513 | break :blk label.block_inst; | ||
| 1514 | } | ||
| 1515 | } | ||
| 1516 | } else if (block_gz.break_block != 0) { | ||
| 1517 | break :blk block_gz.break_block; | ||
| 1537 | } | 1518 | } |
| 1538 | parent_zir.appendAssumeCapacity(src_inst); | 1519 | scope = block_gz.parent; |
| 1520 | continue; | ||
| 1521 | }; | ||
| 1522 | |||
| 1523 | if (rhs == 0) { | ||
| 1524 | _ = try parent_gz.addBreak(.@"break", block_inst, .void_value); | ||
| 1525 | return Zir.Inst.Ref.unreachable_value; | ||
| 1539 | } | 1526 | } |
| 1540 | assert(parent_zir.items.len == expected_len); | 1527 | block_gz.break_count += 1; |
| 1528 | const prev_rvalue_rl_count = block_gz.rvalue_rl_count; | ||
| 1529 | const operand = try expr(parent_gz, parent_scope, block_gz.break_result_loc, rhs); | ||
| 1530 | const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count; | ||
| 1541 | 1531 | ||
| 1542 | const sub_scope = try block_arena.create(Scope.LocalVal); | 1532 | const br = try parent_gz.addBreak(.@"break", block_inst, operand); |
| 1543 | sub_scope.* = .{ | 1533 | |
| 1544 | .parent = scope, | 1534 | if (block_gz.break_result_loc == .block_ptr) { |
| 1545 | .gen_zir = gz, | 1535 | try block_gz.labeled_breaks.append(astgen.gpa, br); |
| 1546 | .name = ident_name, | 1536 | |
| 1547 | .inst = init_inst, | 1537 | if (have_store_to_block) { |
| 1548 | .src = name_src, | 1538 | const zir_tags = parent_gz.astgen.instructions.items(.tag); |
| 1549 | }; | 1539 | const zir_datas = parent_gz.astgen.instructions.items(.data); |
| 1550 | return &sub_scope.base; | 1540 | const store_inst = @intCast(u32, zir_tags.len - 2); |
| 1551 | } | 1541 | assert(zir_tags[store_inst] == .store_to_block_ptr); |
| 1552 | // The initialization expression took advantage of the result location | 1542 | assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr); |
| 1553 | // of the const local. In this case we will create an alloc and a LocalPtr for it. | 1543 | try block_gz.labeled_store_to_block_ptr_list.append(astgen.gpa, store_inst); |
| 1554 | // Move the init_scope instructions into the parent scope, swapping | ||
| 1555 | // store_to_block_ptr for store_to_inferred_ptr. | ||
| 1556 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; | ||
| 1557 | try parent_zir.ensureCapacity(mod.gpa, expected_len); | ||
| 1558 | for (init_scope.instructions.items) |src_inst| { | ||
| 1559 | if (zir_tags[src_inst] == .store_to_block_ptr) { | ||
| 1560 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { | ||
| 1561 | zir_tags[src_inst] = .store_to_inferred_ptr; | ||
| 1562 | } | 1544 | } |
| 1563 | } | 1545 | } |
| 1564 | parent_zir.appendAssumeCapacity(src_inst); | 1546 | return Zir.Inst.Ref.unreachable_value; |
| 1565 | } | 1547 | }, |
| 1566 | assert(parent_zir.items.len == expected_len); | 1548 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 1567 | if (resolve_inferred_alloc != .none) { | 1549 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| 1568 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); | 1550 | .namespace => break, |
| 1569 | } | 1551 | .defer_normal => { |
| 1570 | const sub_scope = try block_arena.create(Scope.LocalPtr); | 1552 | const defer_scope = scope.cast(Scope.Defer).?; |
| 1571 | sub_scope.* = .{ | 1553 | scope = defer_scope.parent; |
| 1572 | .parent = scope, | 1554 | const expr_node = node_datas[defer_scope.defer_node].rhs; |
| 1573 | .gen_zir = gz, | 1555 | try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); |
| 1574 | .name = ident_name, | 1556 | }, |
| 1575 | .ptr = init_scope.rl_ptr, | 1557 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, |
| 1576 | .src = name_src, | 1558 | .top => unreachable, |
| 1577 | }; | 1559 | } |
| 1578 | return &sub_scope.base; | 1560 | } |
| 1579 | }, | 1561 | if (break_label != 0) { |
| 1580 | .keyword_var => { | 1562 | const label_name = try astgen.identifierTokenString(break_label); |
| 1581 | var resolve_inferred_alloc: zir.Inst.Ref = .none; | 1563 | return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); |
| 1582 | const var_data: struct { | 1564 | } else { |
| 1583 | result_loc: ResultLoc, | 1565 | return astgen.failNode(node, "break expression outside loop", .{}); |
| 1584 | alloc: zir.Inst.Ref, | ||
| 1585 | } = if (var_decl.ast.type_node != 0) a: { | ||
| 1586 | const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); | ||
| 1587 | |||
| 1588 | const alloc = try gz.addUnNode(.alloc_mut, type_inst, node); | ||
| 1589 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; | ||
| 1590 | } else a: { | ||
| 1591 | const alloc = try gz.addNode(.alloc_inferred_mut, node); | ||
| 1592 | resolve_inferred_alloc = alloc; | ||
| 1593 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } }; | ||
| 1594 | }; | ||
| 1595 | const init_inst = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node); | ||
| 1596 | if (resolve_inferred_alloc != .none) { | ||
| 1597 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); | ||
| 1598 | } | ||
| 1599 | const sub_scope = try block_arena.create(Scope.LocalPtr); | ||
| 1600 | sub_scope.* = .{ | ||
| 1601 | .parent = scope, | ||
| 1602 | .gen_zir = gz, | ||
| 1603 | .name = ident_name, | ||
| 1604 | .ptr = var_data.alloc, | ||
| 1605 | .src = name_src, | ||
| 1606 | }; | ||
| 1607 | return &sub_scope.base; | ||
| 1608 | }, | ||
| 1609 | else => unreachable, | ||
| 1610 | } | 1566 | } |
| 1611 | } | 1567 | } |
| 1612 | 1568 | ||
| 1613 | fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { | 1569 | fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 1614 | const tree = gz.tree(); | 1570 | const astgen = parent_gz.astgen; |
| 1571 | const tree = astgen.tree; | ||
| 1615 | const node_datas = tree.nodes.items(.data); | 1572 | const node_datas = tree.nodes.items(.data); |
| 1616 | const main_tokens = tree.nodes.items(.main_token); | 1573 | const break_label = node_datas[node].lhs; |
| 1617 | const node_tags = tree.nodes.items(.tag); | ||
| 1618 | 1574 | ||
| 1619 | const lhs = node_datas[infix_node].lhs; | 1575 | // Look for the label in the scope. |
| 1620 | const rhs = node_datas[infix_node].rhs; | 1576 | var scope = parent_scope; |
| 1621 | if (node_tags[lhs] == .identifier) { | 1577 | while (true) { |
| 1622 | // This intentionally does not support `@"_"` syntax. | 1578 | switch (scope.tag) { |
| 1623 | const ident_name = tree.tokenSlice(main_tokens[lhs]); | 1579 | .gen_zir => { |
| 1624 | if (mem.eql(u8, ident_name, "_")) { | 1580 | const gen_zir = scope.cast(GenZir).?; |
| 1625 | _ = try expr(gz, scope, .discard, rhs); | 1581 | const continue_block = gen_zir.continue_block; |
| 1626 | return; | 1582 | if (continue_block == 0) { |
| 1583 | scope = gen_zir.parent; | ||
| 1584 | continue; | ||
| 1585 | } | ||
| 1586 | if (break_label != 0) blk: { | ||
| 1587 | if (gen_zir.label) |*label| { | ||
| 1588 | if (try astgen.tokenIdentEql(label.token, break_label)) { | ||
| 1589 | label.used = true; | ||
| 1590 | break :blk; | ||
| 1591 | } | ||
| 1592 | } | ||
| 1593 | // found continue but either it has a different label, or no label | ||
| 1594 | scope = gen_zir.parent; | ||
| 1595 | continue; | ||
| 1596 | } | ||
| 1597 | |||
| 1598 | // TODO emit a break_inline if the loop being continued is inline | ||
| 1599 | _ = try parent_gz.addBreak(.@"break", continue_block, .void_value); | ||
| 1600 | return Zir.Inst.Ref.unreachable_value; | ||
| 1601 | }, | ||
| 1602 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 1603 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 1604 | .defer_normal => { | ||
| 1605 | const defer_scope = scope.cast(Scope.Defer).?; | ||
| 1606 | scope = defer_scope.parent; | ||
| 1607 | const expr_node = node_datas[defer_scope.defer_node].rhs; | ||
| 1608 | try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); | ||
| 1609 | }, | ||
| 1610 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, | ||
| 1611 | .namespace => break, | ||
| 1612 | .top => unreachable, | ||
| 1627 | } | 1613 | } |
| 1628 | } | 1614 | } |
| 1629 | const lvalue = try lvalExpr(gz, scope, lhs); | 1615 | if (break_label != 0) { |
| 1630 | _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs); | 1616 | const label_name = try astgen.identifierTokenString(break_label); |
| 1617 | return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); | ||
| 1618 | } else { | ||
| 1619 | return astgen.failNode(node, "continue expression outside loop", .{}); | ||
| 1620 | } | ||
| 1631 | } | 1621 | } |
| 1632 | 1622 | ||
| 1633 | fn assignOp( | 1623 | fn blockExpr( |
| 1634 | gz: *GenZir, | 1624 | gz: *GenZir, |
| 1635 | scope: *Scope, | 1625 | scope: *Scope, |
| 1636 | infix_node: ast.Node.Index, | 1626 | rl: ResultLoc, |
| 1637 | op_inst_tag: zir.Inst.Tag, | 1627 | block_node: ast.Node.Index, |
| 1638 | ) InnerError!void { | 1628 | statements: []const ast.Node.Index, |
| 1639 | const tree = gz.tree(); | 1629 | ) InnerError!Zir.Inst.Ref { |
| 1640 | const node_datas = tree.nodes.items(.data); | 1630 | const tracy = trace(@src()); |
| 1641 | 1631 | defer tracy.end(); | |
| 1642 | const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); | ||
| 1643 | const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); | ||
| 1644 | const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); | ||
| 1645 | const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs); | ||
| 1646 | 1632 | ||
| 1647 | const result = try gz.addPlNode(op_inst_tag, infix_node, zir.Inst.Bin{ | 1633 | const astgen = gz.astgen; |
| 1648 | .lhs = lhs, | 1634 | const tree = astgen.tree; |
| 1649 | .rhs = rhs, | 1635 | const main_tokens = tree.nodes.items(.main_token); |
| 1650 | }); | 1636 | const token_tags = tree.tokens.items(.tag); |
| 1651 | _ = try gz.addBin(.store, lhs_ptr, result); | ||
| 1652 | } | ||
| 1653 | 1637 | ||
| 1654 | fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 1638 | const lbrace = main_tokens[block_node]; |
| 1655 | const tree = gz.tree(); | 1639 | if (token_tags[lbrace - 1] == .colon and |
| 1656 | const node_datas = tree.nodes.items(.data); | 1640 | token_tags[lbrace - 2] == .identifier) |
| 1641 | { | ||
| 1642 | return labeledBlockExpr(gz, scope, rl, block_node, statements, .block); | ||
| 1643 | } | ||
| 1657 | 1644 | ||
| 1658 | const operand = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs); | 1645 | try blockExprStmts(gz, scope, block_node, statements); |
| 1659 | const result = try gz.addUnNode(.bool_not, operand, node); | 1646 | return rvalue(gz, scope, rl, .void_value, block_node); |
| 1660 | return rvalue(gz, scope, rl, result, node); | ||
| 1661 | } | 1647 | } |
| 1662 | 1648 | ||
| 1663 | fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 1649 | fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void { |
| 1664 | const tree = gz.tree(); | 1650 | // Look for the label in the scope. |
| 1665 | const node_datas = tree.nodes.items(.data); | 1651 | var scope = parent_scope; |
| 1652 | while (true) { | ||
| 1653 | switch (scope.tag) { | ||
| 1654 | .gen_zir => { | ||
| 1655 | const gen_zir = scope.cast(GenZir).?; | ||
| 1656 | if (gen_zir.label) |prev_label| { | ||
| 1657 | if (try astgen.tokenIdentEql(label, prev_label.token)) { | ||
| 1658 | const tree = astgen.tree; | ||
| 1659 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1666 | 1660 | ||
| 1667 | const operand = try expr(gz, scope, .none, node_datas[node].lhs); | 1661 | const label_name = try astgen.identifierTokenString(label); |
| 1668 | const result = try gz.addUnNode(.bit_not, operand, node); | 1662 | return astgen.failTokNotes(label, "redefinition of label '{s}'", .{ |
| 1669 | return rvalue(gz, scope, rl, result, node); | 1663 | label_name, |
| 1664 | }, &[_]u32{ | ||
| 1665 | try astgen.errNoteTok( | ||
| 1666 | prev_label.token, | ||
| 1667 | "previous definition is here", | ||
| 1668 | .{}, | ||
| 1669 | ), | ||
| 1670 | }); | ||
| 1671 | } | ||
| 1672 | } | ||
| 1673 | scope = gen_zir.parent; | ||
| 1674 | }, | ||
| 1675 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 1676 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 1677 | .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, | ||
| 1678 | .namespace => break, | ||
| 1679 | .top => unreachable, | ||
| 1680 | } | ||
| 1681 | } | ||
| 1670 | } | 1682 | } |
| 1671 | 1683 | ||
| 1672 | fn negation( | 1684 | fn labeledBlockExpr( |
| 1673 | gz: *GenZir, | 1685 | gz: *GenZir, |
| 1674 | scope: *Scope, | 1686 | parent_scope: *Scope, |
| 1675 | rl: ResultLoc, | 1687 | rl: ResultLoc, |
| 1676 | node: ast.Node.Index, | 1688 | block_node: ast.Node.Index, |
| 1677 | tag: zir.Inst.Tag, | 1689 | statements: []const ast.Node.Index, |
| 1678 | ) InnerError!zir.Inst.Ref { | 1690 | zir_tag: Zir.Inst.Tag, |
| 1679 | const tree = gz.tree(); | 1691 | ) InnerError!Zir.Inst.Ref { |
| 1680 | const node_datas = tree.nodes.items(.data); | 1692 | const tracy = trace(@src()); |
| 1693 | defer tracy.end(); | ||
| 1681 | 1694 | ||
| 1682 | const operand = try expr(gz, scope, .none, node_datas[node].lhs); | 1695 | assert(zir_tag == .block); |
| 1683 | const result = try gz.addUnNode(tag, operand, node); | ||
| 1684 | return rvalue(gz, scope, rl, result, node); | ||
| 1685 | } | ||
| 1686 | 1696 | ||
| 1687 | fn ptrType( | 1697 | const astgen = gz.astgen; |
| 1688 | gz: *GenZir, | 1698 | const tree = astgen.tree; |
| 1689 | scope: *Scope, | 1699 | const main_tokens = tree.nodes.items(.main_token); |
| 1690 | rl: ResultLoc, | 1700 | const token_tags = tree.tokens.items(.tag); |
| 1691 | node: ast.Node.Index, | ||
| 1692 | ptr_info: ast.full.PtrType, | ||
| 1693 | ) InnerError!zir.Inst.Ref { | ||
| 1694 | const tree = gz.tree(); | ||
| 1695 | 1701 | ||
| 1696 | const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); | 1702 | const lbrace = main_tokens[block_node]; |
| 1703 | const label_token = lbrace - 2; | ||
| 1704 | assert(token_tags[label_token] == .identifier); | ||
| 1697 | 1705 | ||
| 1698 | const simple = ptr_info.ast.align_node == 0 and | 1706 | try astgen.checkLabelRedefinition(parent_scope, label_token); |
| 1699 | ptr_info.ast.sentinel == 0 and | ||
| 1700 | ptr_info.ast.bit_range_start == 0; | ||
| 1701 | 1707 | ||
| 1702 | if (simple) { | 1708 | // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct |
| 1703 | const result = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | 1709 | // so that break statements can reference it. |
| 1704 | .ptr_type_simple = .{ | 1710 | const block_inst = try gz.addBlock(zir_tag, block_node); |
| 1705 | .is_allowzero = ptr_info.allowzero_token != null, | 1711 | try gz.instructions.append(astgen.gpa, block_inst); |
| 1706 | .is_mutable = ptr_info.const_token == null, | ||
| 1707 | .is_volatile = ptr_info.volatile_token != null, | ||
| 1708 | .size = ptr_info.size, | ||
| 1709 | .elem_type = elem_type, | ||
| 1710 | }, | ||
| 1711 | } }); | ||
| 1712 | return rvalue(gz, scope, rl, result, node); | ||
| 1713 | } | ||
| 1714 | 1712 | ||
| 1715 | var sentinel_ref: zir.Inst.Ref = .none; | 1713 | var block_scope = gz.makeSubBlock(parent_scope); |
| 1716 | var align_ref: zir.Inst.Ref = .none; | 1714 | block_scope.label = GenZir.Label{ |
| 1717 | var bit_start_ref: zir.Inst.Ref = .none; | 1715 | .token = label_token, |
| 1718 | var bit_end_ref: zir.Inst.Ref = .none; | 1716 | .block_inst = block_inst, |
| 1719 | var trailing_count: u32 = 0; | 1717 | }; |
| 1718 | block_scope.setBreakResultLoc(rl); | ||
| 1719 | defer block_scope.instructions.deinit(astgen.gpa); | ||
| 1720 | defer block_scope.labeled_breaks.deinit(astgen.gpa); | ||
| 1721 | defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); | ||
| 1720 | 1722 | ||
| 1721 | if (ptr_info.ast.sentinel != 0) { | 1723 | try blockExprStmts(&block_scope, &block_scope.base, block_node, statements); |
| 1722 | sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel); | 1724 | |
| 1723 | trailing_count += 1; | 1725 | if (!block_scope.label.?.used) { |
| 1724 | } | 1726 | return astgen.failTok(label_token, "unused block label", .{}); |
| 1725 | if (ptr_info.ast.align_node != 0) { | ||
| 1726 | align_ref = try expr(gz, scope, .none, ptr_info.ast.align_node); | ||
| 1727 | trailing_count += 1; | ||
| 1728 | } | ||
| 1729 | if (ptr_info.ast.bit_range_start != 0) { | ||
| 1730 | assert(ptr_info.ast.bit_range_end != 0); | ||
| 1731 | bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start); | ||
| 1732 | bit_end_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_end); | ||
| 1733 | trailing_count += 2; | ||
| 1734 | } | 1727 | } |
| 1735 | 1728 | ||
| 1736 | const gpa = gz.astgen.mod.gpa; | 1729 | const zir_tags = gz.astgen.instructions.items(.tag); |
| 1737 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | 1730 | const zir_datas = gz.astgen.instructions.items(.data); |
| 1738 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1739 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1740 | @typeInfo(zir.Inst.PtrType).Struct.fields.len + trailing_count); | ||
| 1741 | 1731 | ||
| 1742 | const payload_index = gz.astgen.addExtraAssumeCapacity(zir.Inst.PtrType{ .elem_type = elem_type }); | 1732 | const strat = rl.strategy(&block_scope); |
| 1743 | if (sentinel_ref != .none) { | 1733 | switch (strat.tag) { |
| 1744 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); | 1734 | .break_void => { |
| 1745 | } | 1735 | // The code took advantage of the result location as a pointer. |
| 1746 | if (align_ref != .none) { | 1736 | // Turn the break instruction operands into void. |
| 1747 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); | 1737 | for (block_scope.labeled_breaks.items) |br| { |
| 1748 | } | 1738 | zir_datas[br].@"break".operand = .void_value; |
| 1749 | if (bit_start_ref != .none) { | 1739 | } |
| 1750 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); | 1740 | try block_scope.setBlockBody(block_inst); |
| 1751 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); | ||
| 1752 | } | ||
| 1753 | 1741 | ||
| 1754 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | 1742 | return gz.indexToRef(block_inst); |
| 1755 | const result = gz.astgen.indexToRef(new_index); | ||
| 1756 | gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ | ||
| 1757 | .ptr_type = .{ | ||
| 1758 | .flags = .{ | ||
| 1759 | .is_allowzero = ptr_info.allowzero_token != null, | ||
| 1760 | .is_mutable = ptr_info.const_token == null, | ||
| 1761 | .is_volatile = ptr_info.volatile_token != null, | ||
| 1762 | .has_sentinel = sentinel_ref != .none, | ||
| 1763 | .has_align = align_ref != .none, | ||
| 1764 | .has_bit_range = bit_start_ref != .none, | ||
| 1765 | }, | ||
| 1766 | .size = ptr_info.size, | ||
| 1767 | .payload_index = payload_index, | ||
| 1768 | }, | 1743 | }, |
| 1769 | } }); | 1744 | .break_operand => { |
| 1770 | gz.instructions.appendAssumeCapacity(new_index); | 1745 | // All break operands are values that did not use the result location pointer. |
| 1746 | if (strat.elide_store_to_block_ptr_instructions) { | ||
| 1747 | for (block_scope.labeled_store_to_block_ptr_list.items) |inst| { | ||
| 1748 | // Mark as elided for removal below. | ||
| 1749 | assert(zir_tags[inst] == .store_to_block_ptr); | ||
| 1750 | zir_datas[inst].bin.lhs = .none; | ||
| 1751 | } | ||
| 1752 | try block_scope.setBlockBodyEliding(block_inst); | ||
| 1753 | } else { | ||
| 1754 | try block_scope.setBlockBody(block_inst); | ||
| 1755 | } | ||
| 1756 | const block_ref = gz.indexToRef(block_inst); | ||
| 1757 | switch (rl) { | ||
| 1758 | .ref => return block_ref, | ||
| 1759 | else => return rvalue(gz, parent_scope, rl, block_ref, block_node), | ||
| 1760 | } | ||
| 1761 | }, | ||
| 1762 | } | ||
| 1763 | } | ||
| 1771 | 1764 | ||
| 1772 | return rvalue(gz, scope, rl, result, node); | 1765 | fn blockExprStmts( |
| 1766 | gz: *GenZir, | ||
| 1767 | parent_scope: *Scope, | ||
| 1768 | node: ast.Node.Index, | ||
| 1769 | statements: []const ast.Node.Index, | ||
| 1770 | ) !void { | ||
| 1771 | const astgen = gz.astgen; | ||
| 1772 | const tree = astgen.tree; | ||
| 1773 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1774 | const node_tags = tree.nodes.items(.tag); | ||
| 1775 | |||
| 1776 | var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); | ||
| 1777 | defer block_arena.deinit(); | ||
| 1778 | |||
| 1779 | var scope = parent_scope; | ||
| 1780 | for (statements) |statement| { | ||
| 1781 | switch (node_tags[statement]) { | ||
| 1782 | // zig fmt: off | ||
| 1783 | .global_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)), | ||
| 1784 | .local_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)), | ||
| 1785 | .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), | ||
| 1786 | .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), | ||
| 1787 | |||
| 1788 | .@"defer" => scope = try deferStmt(gz, scope, statement, &block_arena.allocator, .defer_normal), | ||
| 1789 | .@"errdefer" => scope = try deferStmt(gz, scope, statement, &block_arena.allocator, .defer_error), | ||
| 1790 | |||
| 1791 | .assign => try assign(gz, scope, statement), | ||
| 1792 | |||
| 1793 | .assign_bit_shift_left => try assignShift(gz, scope, statement, .shl), | ||
| 1794 | .assign_bit_shift_right => try assignShift(gz, scope, statement, .shr), | ||
| 1795 | |||
| 1796 | .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), | ||
| 1797 | .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), | ||
| 1798 | .assign_bit_xor => try assignOp(gz, scope, statement, .xor), | ||
| 1799 | .assign_div => try assignOp(gz, scope, statement, .div), | ||
| 1800 | .assign_sub => try assignOp(gz, scope, statement, .sub), | ||
| 1801 | .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), | ||
| 1802 | .assign_mod => try assignOp(gz, scope, statement, .mod_rem), | ||
| 1803 | .assign_add => try assignOp(gz, scope, statement, .add), | ||
| 1804 | .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), | ||
| 1805 | .assign_mul => try assignOp(gz, scope, statement, .mul), | ||
| 1806 | .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), | ||
| 1807 | |||
| 1808 | else => try unusedResultExpr(gz, scope, statement), | ||
| 1809 | // zig fmt: on | ||
| 1810 | } | ||
| 1811 | } | ||
| 1812 | |||
| 1813 | try genDefers(gz, parent_scope, scope, .none); | ||
| 1773 | } | 1814 | } |
| 1774 | 1815 | ||
| 1775 | fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref { | 1816 | fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void { |
| 1776 | const tree = gz.tree(); | 1817 | try emitDbgNode(gz, statement); |
| 1777 | const node_datas = tree.nodes.items(.data); | 1818 | // We need to emit an error if the result is not `noreturn` or `void`, but |
| 1819 | // we want to avoid adding the ZIR instruction if possible for performance. | ||
| 1820 | const maybe_unused_result = try expr(gz, scope, .none, statement); | ||
| 1821 | const elide_check = if (gz.refToIndex(maybe_unused_result)) |inst| b: { | ||
| 1822 | // Note that this array becomes invalid after appending more items to it | ||
| 1823 | // in the above while loop. | ||
| 1824 | const zir_tags = gz.astgen.instructions.items(.tag); | ||
| 1825 | switch (zir_tags[inst]) { | ||
| 1826 | // For some instructions, swap in a slightly different ZIR tag | ||
| 1827 | // so we can avoid a separate ensure_result_used instruction. | ||
| 1828 | .call_chkused => unreachable, | ||
| 1829 | .call => { | ||
| 1830 | zir_tags[inst] = .call_chkused; | ||
| 1831 | break :b true; | ||
| 1832 | }, | ||
| 1778 | 1833 | ||
| 1779 | // TODO check for [_]T | 1834 | // ZIR instructions that might be a type other than `noreturn` or `void`. |
| 1780 | const len = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].lhs); | 1835 | .add, |
| 1781 | const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); | 1836 | .addwrap, |
| 1837 | .arg, | ||
| 1838 | .alloc, | ||
| 1839 | .alloc_mut, | ||
| 1840 | .alloc_comptime, | ||
| 1841 | .alloc_inferred, | ||
| 1842 | .alloc_inferred_mut, | ||
| 1843 | .alloc_inferred_comptime, | ||
| 1844 | .array_cat, | ||
| 1845 | .array_mul, | ||
| 1846 | .array_type, | ||
| 1847 | .array_type_sentinel, | ||
| 1848 | .vector_type, | ||
| 1849 | .elem_type, | ||
| 1850 | .indexable_ptr_len, | ||
| 1851 | .anyframe_type, | ||
| 1852 | .as, | ||
| 1853 | .as_node, | ||
| 1854 | .bit_and, | ||
| 1855 | .bitcast, | ||
| 1856 | .bitcast_result_ptr, | ||
| 1857 | .bit_or, | ||
| 1858 | .block, | ||
| 1859 | .block_inline, | ||
| 1860 | .suspend_block, | ||
| 1861 | .loop, | ||
| 1862 | .bool_br_and, | ||
| 1863 | .bool_br_or, | ||
| 1864 | .bool_not, | ||
| 1865 | .bool_and, | ||
| 1866 | .bool_or, | ||
| 1867 | .call_compile_time, | ||
| 1868 | .call_nosuspend, | ||
| 1869 | .call_async, | ||
| 1870 | .cmp_lt, | ||
| 1871 | .cmp_lte, | ||
| 1872 | .cmp_eq, | ||
| 1873 | .cmp_gte, | ||
| 1874 | .cmp_gt, | ||
| 1875 | .cmp_neq, | ||
| 1876 | .coerce_result_ptr, | ||
| 1877 | .decl_ref, | ||
| 1878 | .decl_val, | ||
| 1879 | .load, | ||
| 1880 | .div, | ||
| 1881 | .elem_ptr, | ||
| 1882 | .elem_val, | ||
| 1883 | .elem_ptr_node, | ||
| 1884 | .elem_val_node, | ||
| 1885 | .field_ptr, | ||
| 1886 | .field_val, | ||
| 1887 | .field_ptr_named, | ||
| 1888 | .field_val_named, | ||
| 1889 | .func, | ||
| 1890 | .func_inferred, | ||
| 1891 | .int, | ||
| 1892 | .int_big, | ||
| 1893 | .float, | ||
| 1894 | .float128, | ||
| 1895 | .int_type, | ||
| 1896 | .is_non_null, | ||
| 1897 | .is_null, | ||
| 1898 | .is_non_null_ptr, | ||
| 1899 | .is_null_ptr, | ||
| 1900 | .is_err, | ||
| 1901 | .is_err_ptr, | ||
| 1902 | .mod_rem, | ||
| 1903 | .mul, | ||
| 1904 | .mulwrap, | ||
| 1905 | .param_type, | ||
| 1906 | .ref, | ||
| 1907 | .shl, | ||
| 1908 | .shr, | ||
| 1909 | .str, | ||
| 1910 | .sub, | ||
| 1911 | .subwrap, | ||
| 1912 | .negate, | ||
| 1913 | .negate_wrap, | ||
| 1914 | .typeof, | ||
| 1915 | .typeof_elem, | ||
| 1916 | .xor, | ||
| 1917 | .optional_type, | ||
| 1918 | .optional_payload_safe, | ||
| 1919 | .optional_payload_unsafe, | ||
| 1920 | .optional_payload_safe_ptr, | ||
| 1921 | .optional_payload_unsafe_ptr, | ||
| 1922 | .err_union_payload_safe, | ||
| 1923 | .err_union_payload_unsafe, | ||
| 1924 | .err_union_payload_safe_ptr, | ||
| 1925 | .err_union_payload_unsafe_ptr, | ||
| 1926 | .err_union_code, | ||
| 1927 | .err_union_code_ptr, | ||
| 1928 | .ptr_type, | ||
| 1929 | .ptr_type_simple, | ||
| 1930 | .enum_literal, | ||
| 1931 | .merge_error_sets, | ||
| 1932 | .error_union_type, | ||
| 1933 | .bit_not, | ||
| 1934 | .error_value, | ||
| 1935 | .error_to_int, | ||
| 1936 | .int_to_error, | ||
| 1937 | .slice_start, | ||
| 1938 | .slice_end, | ||
| 1939 | .slice_sentinel, | ||
| 1940 | .import, | ||
| 1941 | .switch_block, | ||
| 1942 | .switch_block_multi, | ||
| 1943 | .switch_block_else, | ||
| 1944 | .switch_block_else_multi, | ||
| 1945 | .switch_block_under, | ||
| 1946 | .switch_block_under_multi, | ||
| 1947 | .switch_block_ref, | ||
| 1948 | .switch_block_ref_multi, | ||
| 1949 | .switch_block_ref_else, | ||
| 1950 | .switch_block_ref_else_multi, | ||
| 1951 | .switch_block_ref_under, | ||
| 1952 | .switch_block_ref_under_multi, | ||
| 1953 | .switch_capture, | ||
| 1954 | .switch_capture_ref, | ||
| 1955 | .switch_capture_multi, | ||
| 1956 | .switch_capture_multi_ref, | ||
| 1957 | .switch_capture_else, | ||
| 1958 | .switch_capture_else_ref, | ||
| 1959 | .struct_init_empty, | ||
| 1960 | .struct_init, | ||
| 1961 | .struct_init_ref, | ||
| 1962 | .struct_init_anon, | ||
| 1963 | .struct_init_anon_ref, | ||
| 1964 | .array_init, | ||
| 1965 | .array_init_anon, | ||
| 1966 | .array_init_ref, | ||
| 1967 | .array_init_anon_ref, | ||
| 1968 | .union_init_ptr, | ||
| 1969 | .field_type, | ||
| 1970 | .field_type_ref, | ||
| 1971 | .opaque_decl, | ||
| 1972 | .opaque_decl_anon, | ||
| 1973 | .opaque_decl_func, | ||
| 1974 | .error_set_decl, | ||
| 1975 | .error_set_decl_anon, | ||
| 1976 | .error_set_decl_func, | ||
| 1977 | .int_to_enum, | ||
| 1978 | .enum_to_int, | ||
| 1979 | .type_info, | ||
| 1980 | .size_of, | ||
| 1981 | .bit_size_of, | ||
| 1982 | .log2_int_type, | ||
| 1983 | .typeof_log2_int_type, | ||
| 1984 | .ptr_to_int, | ||
| 1985 | .align_of, | ||
| 1986 | .bool_to_int, | ||
| 1987 | .embed_file, | ||
| 1988 | .error_name, | ||
| 1989 | .sqrt, | ||
| 1990 | .sin, | ||
| 1991 | .cos, | ||
| 1992 | .exp, | ||
| 1993 | .exp2, | ||
| 1994 | .log, | ||
| 1995 | .log2, | ||
| 1996 | .log10, | ||
| 1997 | .fabs, | ||
| 1998 | .floor, | ||
| 1999 | .ceil, | ||
| 2000 | .trunc, | ||
| 2001 | .round, | ||
| 2002 | .tag_name, | ||
| 2003 | .reify, | ||
| 2004 | .type_name, | ||
| 2005 | .frame_type, | ||
| 2006 | .frame_size, | ||
| 2007 | .float_to_int, | ||
| 2008 | .int_to_float, | ||
| 2009 | .int_to_ptr, | ||
| 2010 | .float_cast, | ||
| 2011 | .int_cast, | ||
| 2012 | .err_set_cast, | ||
| 2013 | .ptr_cast, | ||
| 2014 | .truncate, | ||
| 2015 | .align_cast, | ||
| 2016 | .has_decl, | ||
| 2017 | .has_field, | ||
| 2018 | .clz, | ||
| 2019 | .ctz, | ||
| 2020 | .pop_count, | ||
| 2021 | .byte_swap, | ||
| 2022 | .bit_reverse, | ||
| 2023 | .div_exact, | ||
| 2024 | .div_floor, | ||
| 2025 | .div_trunc, | ||
| 2026 | .mod, | ||
| 2027 | .rem, | ||
| 2028 | .shl_exact, | ||
| 2029 | .shr_exact, | ||
| 2030 | .bit_offset_of, | ||
| 2031 | .byte_offset_of, | ||
| 2032 | .cmpxchg_strong, | ||
| 2033 | .cmpxchg_weak, | ||
| 2034 | .splat, | ||
| 2035 | .reduce, | ||
| 2036 | .shuffle, | ||
| 2037 | .atomic_load, | ||
| 2038 | .atomic_rmw, | ||
| 2039 | .atomic_store, | ||
| 2040 | .mul_add, | ||
| 2041 | .builtin_call, | ||
| 2042 | .field_ptr_type, | ||
| 2043 | .field_parent_ptr, | ||
| 2044 | .memcpy, | ||
| 2045 | .memset, | ||
| 2046 | .builtin_async_call, | ||
| 2047 | .c_import, | ||
| 2048 | .@"resume", | ||
| 2049 | .@"await", | ||
| 2050 | .await_nosuspend, | ||
| 2051 | .extended, | ||
| 2052 | => break :b false, | ||
| 2053 | |||
| 2054 | // ZIR instructions that are always either `noreturn` or `void`. | ||
| 2055 | .breakpoint, | ||
| 2056 | .fence, | ||
| 2057 | .dbg_stmt, | ||
| 2058 | .ensure_result_used, | ||
| 2059 | .ensure_result_non_error, | ||
| 2060 | .@"export", | ||
| 2061 | .set_eval_branch_quota, | ||
| 2062 | .ensure_err_payload_void, | ||
| 2063 | .@"break", | ||
| 2064 | .break_inline, | ||
| 2065 | .condbr, | ||
| 2066 | .condbr_inline, | ||
| 2067 | .compile_error, | ||
| 2068 | .ret_node, | ||
| 2069 | .ret_coerce, | ||
| 2070 | .@"unreachable", | ||
| 2071 | .store, | ||
| 2072 | .store_node, | ||
| 2073 | .store_to_block_ptr, | ||
| 2074 | .store_to_inferred_ptr, | ||
| 2075 | .resolve_inferred_alloc, | ||
| 2076 | .repeat, | ||
| 2077 | .repeat_inline, | ||
| 2078 | .validate_struct_init_ptr, | ||
| 2079 | .validate_array_init_ptr, | ||
| 2080 | .panic, | ||
| 2081 | .set_align_stack, | ||
| 2082 | .set_cold, | ||
| 2083 | .set_float_mode, | ||
| 2084 | .set_runtime_safety, | ||
| 2085 | => break :b true, | ||
| 2086 | } | ||
| 2087 | } else switch (maybe_unused_result) { | ||
| 2088 | .none => unreachable, | ||
| 1782 | 2089 | ||
| 1783 | const result = try gz.addBin(.array_type, len, elem_type); | 2090 | .void_value, |
| 1784 | return rvalue(gz, scope, rl, result, node); | 2091 | .unreachable_value, |
| 2092 | => true, | ||
| 2093 | |||
| 2094 | else => false, | ||
| 2095 | }; | ||
| 2096 | if (!elide_check) { | ||
| 2097 | _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); | ||
| 2098 | } | ||
| 1785 | } | 2099 | } |
| 1786 | 2100 | ||
| 1787 | fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref { | 2101 | fn genDefers( |
| 1788 | const tree = gz.tree(); | 2102 | gz: *GenZir, |
| 2103 | outer_scope: *Scope, | ||
| 2104 | inner_scope: *Scope, | ||
| 2105 | err_code: Zir.Inst.Ref, | ||
| 2106 | ) InnerError!void { | ||
| 2107 | const astgen = gz.astgen; | ||
| 2108 | const tree = astgen.tree; | ||
| 1789 | const node_datas = tree.nodes.items(.data); | 2109 | const node_datas = tree.nodes.items(.data); |
| 1790 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); | ||
| 1791 | 2110 | ||
| 1792 | // TODO check for [_]T | 2111 | var scope = inner_scope; |
| 1793 | const len = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].lhs); | 2112 | while (scope != outer_scope) { |
| 1794 | const elem_type = try typeExpr(gz, scope, extra.elem_type); | 2113 | switch (scope.tag) { |
| 1795 | const sentinel = try expr(gz, scope, .{ .ty = elem_type }, extra.sentinel); | 2114 | .gen_zir => scope = scope.cast(GenZir).?.parent, |
| 2115 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 2116 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 2117 | .defer_normal => { | ||
| 2118 | const defer_scope = scope.cast(Scope.Defer).?; | ||
| 2119 | scope = defer_scope.parent; | ||
| 2120 | const expr_node = node_datas[defer_scope.defer_node].rhs; | ||
| 2121 | try unusedResultExpr(gz, defer_scope.parent, expr_node); | ||
| 2122 | }, | ||
| 2123 | .defer_error => { | ||
| 2124 | const defer_scope = scope.cast(Scope.Defer).?; | ||
| 2125 | scope = defer_scope.parent; | ||
| 2126 | if (err_code == .none) continue; | ||
| 2127 | const expr_node = node_datas[defer_scope.defer_node].rhs; | ||
| 2128 | try unusedResultExpr(gz, defer_scope.parent, expr_node); | ||
| 2129 | }, | ||
| 2130 | .namespace => unreachable, | ||
| 2131 | .top => unreachable, | ||
| 2132 | } | ||
| 2133 | } | ||
| 2134 | } | ||
| 1796 | 2135 | ||
| 1797 | const result = try gz.addArrayTypeSentinel(len, elem_type, sentinel); | 2136 | fn deferStmt( |
| 1798 | return rvalue(gz, scope, rl, result, node); | 2137 | gz: *GenZir, |
| 2138 | scope: *Scope, | ||
| 2139 | node: ast.Node.Index, | ||
| 2140 | block_arena: *Allocator, | ||
| 2141 | scope_tag: Scope.Tag, | ||
| 2142 | ) InnerError!*Scope { | ||
| 2143 | const defer_scope = try block_arena.create(Scope.Defer); | ||
| 2144 | defer_scope.* = .{ | ||
| 2145 | .base = .{ .tag = scope_tag }, | ||
| 2146 | .parent = scope, | ||
| 2147 | .defer_node = node, | ||
| 2148 | }; | ||
| 2149 | return &defer_scope.base; | ||
| 1799 | } | 2150 | } |
| 1800 | 2151 | ||
| 1801 | fn containerDecl( | 2152 | fn varDecl( |
| 1802 | gz: *GenZir, | 2153 | gz: *GenZir, |
| 1803 | scope: *Scope, | 2154 | scope: *Scope, |
| 1804 | rl: ResultLoc, | ||
| 1805 | node: ast.Node.Index, | 2155 | node: ast.Node.Index, |
| 1806 | container_decl: ast.full.ContainerDecl, | 2156 | block_arena: *Allocator, |
| 1807 | ) InnerError!zir.Inst.Ref { | 2157 | var_decl: ast.full.VarDecl, |
| 2158 | ) InnerError!*Scope { | ||
| 2159 | try emitDbgNode(gz, node); | ||
| 1808 | const astgen = gz.astgen; | 2160 | const astgen = gz.astgen; |
| 1809 | const mod = astgen.mod; | 2161 | const gpa = astgen.gpa; |
| 1810 | const gpa = mod.gpa; | 2162 | const tree = astgen.tree; |
| 1811 | const tree = gz.tree(); | ||
| 1812 | const token_tags = tree.tokens.items(.tag); | 2163 | const token_tags = tree.tokens.items(.tag); |
| 1813 | const node_tags = tree.nodes.items(.tag); | ||
| 1814 | |||
| 1815 | // We must not create any types until Sema. Here the goal is only to generate | ||
| 1816 | // ZIR for all the field types, alignments, and default value expressions. | ||
| 1817 | |||
| 1818 | const arg_inst: zir.Inst.Ref = if (container_decl.ast.arg != 0) | ||
| 1819 | try comptimeExpr(gz, scope, .none, container_decl.ast.arg) | ||
| 1820 | else | ||
| 1821 | .none; | ||
| 1822 | |||
| 1823 | switch (token_tags[container_decl.ast.main_token]) { | ||
| 1824 | .keyword_struct => { | ||
| 1825 | const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) { | ||
| 1826 | .keyword_packed => zir.Inst.Tag.struct_decl_packed, | ||
| 1827 | .keyword_extern => zir.Inst.Tag.struct_decl_extern, | ||
| 1828 | else => unreachable, | ||
| 1829 | } else zir.Inst.Tag.struct_decl; | ||
| 1830 | if (container_decl.ast.members.len == 0) { | ||
| 1831 | const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{ | ||
| 1832 | .fields_len = 0, | ||
| 1833 | }); | ||
| 1834 | return rvalue(gz, scope, rl, result, node); | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | assert(arg_inst == .none); | ||
| 1838 | var fields_data = ArrayListUnmanaged(u32){}; | ||
| 1839 | defer fields_data.deinit(gpa); | ||
| 1840 | 2164 | ||
| 1841 | // field_name and field_type are both mandatory | 2165 | const name_token = var_decl.ast.mut_token + 1; |
| 1842 | try fields_data.ensureCapacity(gpa, container_decl.ast.members.len * 2); | 2166 | const ident_name = try astgen.identAsString(name_token); |
| 1843 | |||
| 1844 | // We only need this if there are greater than 16 fields. | ||
| 1845 | var bit_bag = ArrayListUnmanaged(u32){}; | ||
| 1846 | defer bit_bag.deinit(gpa); | ||
| 1847 | 2167 | ||
| 1848 | var cur_bit_bag: u32 = 0; | 2168 | // Local variables shadowing detection, including function parameters. |
| 1849 | var field_index: usize = 0; | 2169 | { |
| 1850 | for (container_decl.ast.members) |member_node| { | 2170 | var s = scope; |
| 1851 | const member = switch (node_tags[member_node]) { | 2171 | while (true) switch (s.tag) { |
| 1852 | .container_field_init => tree.containerFieldInit(member_node), | 2172 | .local_val => { |
| 1853 | .container_field_align => tree.containerFieldAlign(member_node), | 2173 | const local_val = s.cast(Scope.LocalVal).?; |
| 1854 | .container_field => tree.containerField(member_node), | 2174 | if (local_val.name == ident_name) { |
| 1855 | else => continue, | 2175 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); |
| 1856 | }; | 2176 | defer gpa.free(name); |
| 1857 | if (field_index % 16 == 0 and field_index != 0) { | 2177 | return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{ |
| 1858 | try bit_bag.append(gpa, cur_bit_bag); | 2178 | name, |
| 1859 | cur_bit_bag = 0; | 2179 | }, &[_]u32{ |
| 2180 | try astgen.errNoteTok( | ||
| 2181 | local_val.token_src, | ||
| 2182 | "previously declared here", | ||
| 2183 | .{}, | ||
| 2184 | ), | ||
| 2185 | }); | ||
| 1860 | } | 2186 | } |
| 1861 | if (member.comptime_token) |comptime_token| { | 2187 | s = local_val.parent; |
| 1862 | return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{}); | 2188 | }, |
| 2189 | .local_ptr => { | ||
| 2190 | const local_ptr = s.cast(Scope.LocalPtr).?; | ||
| 2191 | if (local_ptr.name == ident_name) { | ||
| 2192 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); | ||
| 2193 | defer gpa.free(name); | ||
| 2194 | return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{ | ||
| 2195 | name, | ||
| 2196 | }, &[_]u32{ | ||
| 2197 | try astgen.errNoteTok( | ||
| 2198 | local_ptr.token_src, | ||
| 2199 | "previously declared here", | ||
| 2200 | .{}, | ||
| 2201 | ), | ||
| 2202 | }); | ||
| 1863 | } | 2203 | } |
| 1864 | try fields_data.ensureCapacity(gpa, fields_data.items.len + 4); | 2204 | s = local_ptr.parent; |
| 1865 | 2205 | }, | |
| 1866 | const field_name = try gz.identAsString(member.ast.name_token); | 2206 | .namespace => { |
| 1867 | fields_data.appendAssumeCapacity(field_name); | 2207 | const ns = s.cast(Scope.Namespace).?; |
| 1868 | 2208 | const decl_node = ns.decls.get(ident_name) orelse { | |
| 1869 | const field_type = try typeExpr(gz, scope, member.ast.type_expr); | 2209 | s = ns.parent; |
| 1870 | fields_data.appendAssumeCapacity(@enumToInt(field_type)); | 2210 | continue; |
| 2211 | }; | ||
| 2212 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name))); | ||
| 2213 | defer gpa.free(name); | ||
| 2214 | return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ | ||
| 2215 | name, | ||
| 2216 | }, &[_]u32{ | ||
| 2217 | try astgen.errNoteNode(decl_node, "declared here", .{}), | ||
| 2218 | }); | ||
| 2219 | }, | ||
| 2220 | .gen_zir => s = s.cast(GenZir).?.parent, | ||
| 2221 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, | ||
| 2222 | .top => break, | ||
| 2223 | }; | ||
| 2224 | } | ||
| 1871 | 2225 | ||
| 1872 | const have_align = member.ast.align_expr != 0; | 2226 | if (var_decl.ast.init_node == 0) { |
| 1873 | const have_value = member.ast.value_expr != 0; | 2227 | return astgen.failNode(node, "variables must be initialized", .{}); |
| 1874 | cur_bit_bag = (cur_bit_bag >> 2) | | 2228 | } |
| 1875 | (@as(u32, @boolToInt(have_align)) << 30) | | ||
| 1876 | (@as(u32, @boolToInt(have_value)) << 31); | ||
| 1877 | 2229 | ||
| 1878 | if (have_align) { | 2230 | const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) |
| 1879 | const align_inst = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, member.ast.align_expr); | 2231 | try expr(gz, scope, align_rl, var_decl.ast.align_node) |
| 1880 | fields_data.appendAssumeCapacity(@enumToInt(align_inst)); | 2232 | else |
| 1881 | } | 2233 | .none; |
| 1882 | if (have_value) { | ||
| 1883 | const default_inst = try comptimeExpr(gz, scope, .{ .ty = field_type }, member.ast.value_expr); | ||
| 1884 | fields_data.appendAssumeCapacity(@enumToInt(default_inst)); | ||
| 1885 | } | ||
| 1886 | 2234 | ||
| 1887 | field_index += 1; | 2235 | switch (token_tags[var_decl.ast.mut_token]) { |
| 2236 | .keyword_const => { | ||
| 2237 | if (var_decl.comptime_token) |comptime_token| { | ||
| 2238 | return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); | ||
| 1888 | } | 2239 | } |
| 1889 | const empty_slot_count = 16 - (field_index % 16); | ||
| 1890 | cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); | ||
| 1891 | 2240 | ||
| 1892 | const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{ | 2241 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 1893 | .fields_len = @intCast(u32, container_decl.ast.members.len), | 2242 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 1894 | }); | 2243 | // the variable, no memory location needed. |
| 1895 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | 2244 | if (align_inst == .none and !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) { |
| 1896 | bit_bag.items.len + 1 + fields_data.items.len); | 2245 | const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{ |
| 1897 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. | 2246 | .ty = try typeExpr(gz, scope, var_decl.ast.type_node), |
| 1898 | astgen.extra.appendAssumeCapacity(cur_bit_bag); | 2247 | } else .none; |
| 1899 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); | 2248 | const init_inst = try expr(gz, scope, result_loc, var_decl.ast.init_node); |
| 1900 | return rvalue(gz, scope, rl, result, node); | 2249 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 1901 | }, | 2250 | sub_scope.* = .{ |
| 1902 | .keyword_union => { | 2251 | .parent = scope, |
| 1903 | return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{}); | 2252 | .gen_zir = gz, |
| 1904 | }, | 2253 | .name = ident_name, |
| 1905 | .keyword_enum => { | 2254 | .inst = init_inst, |
| 1906 | if (container_decl.layout_token) |t| { | 2255 | .token_src = name_token, |
| 1907 | return mod.failTok(scope, t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); | 2256 | }; |
| 2257 | return &sub_scope.base; | ||
| 1908 | } | 2258 | } |
| 1909 | // Count total fields as well as how many have explicitly provided tag values. | ||
| 1910 | const counts = blk: { | ||
| 1911 | var values: usize = 0; | ||
| 1912 | var total_fields: usize = 0; | ||
| 1913 | var decls: usize = 0; | ||
| 1914 | var nonexhaustive_node: ast.Node.Index = 0; | ||
| 1915 | for (container_decl.ast.members) |member_node| { | ||
| 1916 | const member = switch (node_tags[member_node]) { | ||
| 1917 | .container_field_init => tree.containerFieldInit(member_node), | ||
| 1918 | .container_field_align => tree.containerFieldAlign(member_node), | ||
| 1919 | .container_field => tree.containerField(member_node), | ||
| 1920 | else => { | ||
| 1921 | decls += 1; | ||
| 1922 | continue; | ||
| 1923 | }, | ||
| 1924 | }; | ||
| 1925 | if (member.comptime_token) |comptime_token| { | ||
| 1926 | return mod.failTok(scope, comptime_token, "enum fields cannot be marked comptime", .{}); | ||
| 1927 | } | ||
| 1928 | if (member.ast.type_expr != 0) { | ||
| 1929 | return mod.failNode(scope, member.ast.type_expr, "enum fields do not have types", .{}); | ||
| 1930 | } | ||
| 1931 | // Alignment expressions in enums are caught by the parser. | ||
| 1932 | assert(member.ast.align_expr == 0); | ||
| 1933 | 2259 | ||
| 1934 | const name_token = member.ast.name_token; | 2260 | // Detect whether the initialization expression actually uses the |
| 1935 | if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { | 2261 | // result location pointer. |
| 1936 | if (nonexhaustive_node != 0) { | 2262 | var init_scope = gz.makeSubBlock(scope); |
| 1937 | const msg = msg: { | 2263 | defer init_scope.instructions.deinit(gpa); |
| 1938 | const msg = try mod.errMsg( | 2264 | |
| 1939 | scope, | 2265 | var resolve_inferred_alloc: Zir.Inst.Ref = .none; |
| 1940 | gz.nodeSrcLoc(member_node), | 2266 | var opt_type_inst: Zir.Inst.Ref = .none; |
| 1941 | "redundant non-exhaustive enum mark", | 2267 | if (var_decl.ast.type_node != 0) { |
| 1942 | .{}, | 2268 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); |
| 1943 | ); | 2269 | opt_type_inst = type_inst; |
| 1944 | errdefer msg.destroy(gpa); | 2270 | if (align_inst == .none) { |
| 1945 | const other_src = gz.nodeSrcLoc(nonexhaustive_node); | 2271 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); |
| 1946 | try mod.errNote(scope, other_src, msg, "other mark here", .{}); | 2272 | } else { |
| 1947 | break :msg msg; | 2273 | init_scope.rl_ptr = try gz.addAllocExtended(.{ |
| 1948 | }; | 2274 | .node = node, |
| 1949 | return mod.failWithOwnedErrorMsg(scope, msg); | 2275 | .type_inst = type_inst, |
| 1950 | } | 2276 | .align_inst = align_inst, |
| 1951 | nonexhaustive_node = member_node; | 2277 | .is_const = true, |
| 1952 | if (member.ast.value_expr != 0) { | 2278 | .is_comptime = false, |
| 1953 | return mod.failNode(scope, member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); | 2279 | }); |
| 1954 | } | ||
| 1955 | continue; | ||
| 1956 | } | ||
| 1957 | total_fields += 1; | ||
| 1958 | if (member.ast.value_expr != 0) { | ||
| 1959 | values += 1; | ||
| 1960 | } | ||
| 1961 | } | 2280 | } |
| 1962 | break :blk .{ | 2281 | init_scope.rl_ty_inst = type_inst; |
| 1963 | .total_fields = total_fields, | 2282 | } else { |
| 1964 | .values = values, | 2283 | const alloc = if (align_inst == .none) |
| 1965 | .decls = decls, | 2284 | try init_scope.addNode(.alloc_inferred, node) |
| 1966 | .nonexhaustive_node = nonexhaustive_node, | 2285 | else |
| 1967 | }; | 2286 | try gz.addAllocExtended(.{ |
| 1968 | }; | 2287 | .node = node, |
| 1969 | if (counts.total_fields == 0) { | 2288 | .type_inst = .none, |
| 1970 | // One can construct an enum with no tags, and it functions the same as `noreturn`. But | 2289 | .align_inst = align_inst, |
| 1971 | // this is only useful for generic code; when explicitly using `enum {}` syntax, there | 2290 | .is_const = true, |
| 1972 | // must be at least one tag. | 2291 | .is_comptime = false, |
| 1973 | return mod.failNode(scope, node, "enum declarations must have at least one tag", .{}); | 2292 | }); |
| 2293 | resolve_inferred_alloc = alloc; | ||
| 2294 | init_scope.rl_ptr = alloc; | ||
| 1974 | } | 2295 | } |
| 1975 | if (counts.nonexhaustive_node != 0 and arg_inst == .none) { | 2296 | const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; |
| 1976 | const msg = msg: { | 2297 | const init_inst = try expr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node); |
| 1977 | const msg = try mod.errMsg( | 2298 | const zir_tags = astgen.instructions.items(.tag); |
| 1978 | scope, | 2299 | const zir_datas = astgen.instructions.items(.data); |
| 1979 | gz.nodeSrcLoc(node), | 2300 | |
| 1980 | "non-exhaustive enum missing integer tag type", | 2301 | const parent_zir = &gz.instructions; |
| 1981 | .{}, | 2302 | if (align_inst == .none and init_scope.rvalue_rl_count == 1) { |
| 1982 | ); | 2303 | // Result location pointer not used. We don't need an alloc for this |
| 1983 | errdefer msg.destroy(gpa); | 2304 | // const local, and type inference becomes trivial. |
| 1984 | const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node); | 2305 | // Move the init_scope instructions into the parent scope, eliding |
| 1985 | try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{}); | 2306 | // the alloc instruction and the store_to_block_ptr instruction. |
| 1986 | break :msg msg; | 2307 | try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len); |
| 2308 | for (init_scope.instructions.items) |src_inst| { | ||
| 2309 | if (gz.indexToRef(src_inst) == init_scope.rl_ptr) continue; | ||
| 2310 | if (zir_tags[src_inst] == .store_to_block_ptr) { | ||
| 2311 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; | ||
| 2312 | } | ||
| 2313 | parent_zir.appendAssumeCapacity(src_inst); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | const sub_scope = try block_arena.create(Scope.LocalVal); | ||
| 2317 | sub_scope.* = .{ | ||
| 2318 | .parent = scope, | ||
| 2319 | .gen_zir = gz, | ||
| 2320 | .name = ident_name, | ||
| 2321 | .inst = init_inst, | ||
| 2322 | .token_src = name_token, | ||
| 1987 | }; | 2323 | }; |
| 1988 | return mod.failWithOwnedErrorMsg(scope, msg); | 2324 | return &sub_scope.base; |
| 1989 | } | 2325 | } |
| 1990 | if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) { | 2326 | // The initialization expression took advantage of the result location |
| 1991 | // No explicitly provided tag values and no top level declarations! In this case, | 2327 | // of the const local. In this case we will create an alloc and a LocalPtr for it. |
| 1992 | // we can construct the enum type in AstGen and it will be correctly shared by all | 2328 | // Move the init_scope instructions into the parent scope, swapping |
| 1993 | // generic function instantiations and comptime function calls. | 2329 | // store_to_block_ptr for store_to_inferred_ptr. |
| 1994 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 2330 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; |
| 1995 | errdefer new_decl_arena.deinit(); | 2331 | try parent_zir.ensureCapacity(gpa, expected_len); |
| 1996 | const arena = &new_decl_arena.allocator; | 2332 | for (init_scope.instructions.items) |src_inst| { |
| 1997 | 2333 | if (zir_tags[src_inst] == .store_to_block_ptr) { | |
| 1998 | var fields_map: std.StringArrayHashMapUnmanaged(void) = .{}; | 2334 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { |
| 1999 | try fields_map.ensureCapacity(arena, counts.total_fields); | 2335 | zir_tags[src_inst] = .store_to_inferred_ptr; |
| 2000 | for (container_decl.ast.members) |member_node| { | ||
| 2001 | if (member_node == counts.nonexhaustive_node) | ||
| 2002 | continue; | ||
| 2003 | const member = switch (node_tags[member_node]) { | ||
| 2004 | .container_field_init => tree.containerFieldInit(member_node), | ||
| 2005 | .container_field_align => tree.containerFieldAlign(member_node), | ||
| 2006 | .container_field => tree.containerField(member_node), | ||
| 2007 | else => unreachable, // We checked earlier. | ||
| 2008 | }; | ||
| 2009 | const name_token = member.ast.name_token; | ||
| 2010 | const tag_name = try mod.identifierTokenStringTreeArena( | ||
| 2011 | scope, | ||
| 2012 | name_token, | ||
| 2013 | tree, | ||
| 2014 | arena, | ||
| 2015 | ); | ||
| 2016 | const gop = fields_map.getOrPutAssumeCapacity(tag_name); | ||
| 2017 | if (gop.found_existing) { | ||
| 2018 | const msg = msg: { | ||
| 2019 | const msg = try mod.errMsg( | ||
| 2020 | scope, | ||
| 2021 | gz.tokSrcLoc(name_token), | ||
| 2022 | "duplicate enum tag", | ||
| 2023 | .{}, | ||
| 2024 | ); | ||
| 2025 | errdefer msg.destroy(gpa); | ||
| 2026 | // Iterate to find the other tag. We don't eagerly store it in a hash | ||
| 2027 | // map because in the hot path there will be no compile error and we | ||
| 2028 | // don't need to waste time with a hash map. | ||
| 2029 | const bad_node = for (container_decl.ast.members) |other_member_node| { | ||
| 2030 | const other_member = switch (node_tags[other_member_node]) { | ||
| 2031 | .container_field_init => tree.containerFieldInit(other_member_node), | ||
| 2032 | .container_field_align => tree.containerFieldAlign(other_member_node), | ||
| 2033 | .container_field => tree.containerField(other_member_node), | ||
| 2034 | else => unreachable, // We checked earlier. | ||
| 2035 | }; | ||
| 2036 | const other_tag_name = try mod.identifierTokenStringTreeArena( | ||
| 2037 | scope, | ||
| 2038 | other_member.ast.name_token, | ||
| 2039 | tree, | ||
| 2040 | arena, | ||
| 2041 | ); | ||
| 2042 | if (mem.eql(u8, tag_name, other_tag_name)) | ||
| 2043 | break other_member_node; | ||
| 2044 | } else unreachable; | ||
| 2045 | const other_src = gz.nodeSrcLoc(bad_node); | ||
| 2046 | try mod.errNote(scope, other_src, msg, "other tag here", .{}); | ||
| 2047 | break :msg msg; | ||
| 2048 | }; | ||
| 2049 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 2050 | } | 2336 | } |
| 2051 | } | 2337 | } |
| 2052 | const enum_simple = try arena.create(Module.EnumSimple); | 2338 | parent_zir.appendAssumeCapacity(src_inst); |
| 2053 | enum_simple.* = .{ | ||
| 2054 | .owner_decl = astgen.decl, | ||
| 2055 | .node_offset = astgen.decl.nodeIndexToRelative(node), | ||
| 2056 | .fields = fields_map, | ||
| 2057 | }; | ||
| 2058 | const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple); | ||
| 2059 | const enum_val = try Value.Tag.ty.create(arena, enum_ty); | ||
| 2060 | const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ | ||
| 2061 | .ty = Type.initTag(.type), | ||
| 2062 | .val = enum_val, | ||
| 2063 | }); | ||
| 2064 | const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl); | ||
| 2065 | const result = try gz.addDecl(.decl_val, decl_index, node); | ||
| 2066 | return rvalue(gz, scope, rl, result, node); | ||
| 2067 | } | 2339 | } |
| 2068 | // In this case we must generate ZIR code for the tag values, similar to | 2340 | assert(parent_zir.items.len == expected_len); |
| 2069 | // how structs are handled above. The new anonymous Decl will be created in | 2341 | if (resolve_inferred_alloc != .none) { |
| 2070 | // Sema, not AstGen. | 2342 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); |
| 2071 | return mod.failNode(scope, node, "TODO AstGen for enum decl with decls or explicitly provided field values", .{}); | 2343 | } |
| 2344 | const sub_scope = try block_arena.create(Scope.LocalPtr); | ||
| 2345 | sub_scope.* = .{ | ||
| 2346 | .parent = scope, | ||
| 2347 | .gen_zir = gz, | ||
| 2348 | .name = ident_name, | ||
| 2349 | .ptr = init_scope.rl_ptr, | ||
| 2350 | .token_src = name_token, | ||
| 2351 | }; | ||
| 2352 | return &sub_scope.base; | ||
| 2072 | }, | 2353 | }, |
| 2073 | .keyword_opaque => { | 2354 | .keyword_var => { |
| 2074 | const result = try gz.addNode(.opaque_decl, node); | 2355 | const is_comptime = var_decl.comptime_token != null; |
| 2075 | return rvalue(gz, scope, rl, result, node); | 2356 | var resolve_inferred_alloc: Zir.Inst.Ref = .none; |
| 2357 | const var_data: struct { | ||
| 2358 | result_loc: ResultLoc, | ||
| 2359 | alloc: Zir.Inst.Ref, | ||
| 2360 | } = if (var_decl.ast.type_node != 0) a: { | ||
| 2361 | const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); | ||
| 2362 | const alloc = alloc: { | ||
| 2363 | if (align_inst == .none) { | ||
| 2364 | const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut; | ||
| 2365 | break :alloc try gz.addUnNode(tag, type_inst, node); | ||
| 2366 | } else { | ||
| 2367 | break :alloc try gz.addAllocExtended(.{ | ||
| 2368 | .node = node, | ||
| 2369 | .type_inst = type_inst, | ||
| 2370 | .align_inst = align_inst, | ||
| 2371 | .is_const = false, | ||
| 2372 | .is_comptime = is_comptime, | ||
| 2373 | }); | ||
| 2374 | } | ||
| 2375 | }; | ||
| 2376 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; | ||
| 2377 | } else a: { | ||
| 2378 | const alloc = alloc: { | ||
| 2379 | if (align_inst == .none) { | ||
| 2380 | const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut; | ||
| 2381 | break :alloc try gz.addNode(tag, node); | ||
| 2382 | } else { | ||
| 2383 | break :alloc try gz.addAllocExtended(.{ | ||
| 2384 | .node = node, | ||
| 2385 | .type_inst = .none, | ||
| 2386 | .align_inst = align_inst, | ||
| 2387 | .is_const = false, | ||
| 2388 | .is_comptime = is_comptime, | ||
| 2389 | }); | ||
| 2390 | } | ||
| 2391 | }; | ||
| 2392 | resolve_inferred_alloc = alloc; | ||
| 2393 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } }; | ||
| 2394 | }; | ||
| 2395 | const init_inst = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node); | ||
| 2396 | if (resolve_inferred_alloc != .none) { | ||
| 2397 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); | ||
| 2398 | } | ||
| 2399 | const sub_scope = try block_arena.create(Scope.LocalPtr); | ||
| 2400 | sub_scope.* = .{ | ||
| 2401 | .parent = scope, | ||
| 2402 | .gen_zir = gz, | ||
| 2403 | .name = ident_name, | ||
| 2404 | .ptr = var_data.alloc, | ||
| 2405 | .token_src = name_token, | ||
| 2406 | }; | ||
| 2407 | return &sub_scope.base; | ||
| 2076 | }, | 2408 | }, |
| 2077 | else => unreachable, | 2409 | else => unreachable, |
| 2078 | } | 2410 | } |
| 2079 | } | 2411 | } |
| 2080 | 2412 | ||
| 2081 | fn errorSetDecl( | 2413 | fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { |
| 2082 | gz: *GenZir, | 2414 | // The instruction emitted here is for debugging runtime code. |
| 2083 | scope: *Scope, | 2415 | // If the current block will be evaluated only during semantic analysis |
| 2084 | rl: ResultLoc, | 2416 | // then no dbg_stmt ZIR instruction is needed. |
| 2085 | node: ast.Node.Index, | 2417 | if (gz.force_comptime) return; |
| 2086 | ) InnerError!zir.Inst.Ref { | ||
| 2087 | const astgen = gz.astgen; | ||
| 2088 | const mod = astgen.mod; | ||
| 2089 | const tree = gz.tree(); | ||
| 2090 | const main_tokens = tree.nodes.items(.main_token); | ||
| 2091 | const token_tags = tree.tokens.items(.tag); | ||
| 2092 | 2418 | ||
| 2093 | // Count how many fields there are. | 2419 | const astgen = gz.astgen; |
| 2094 | const error_token = main_tokens[node]; | 2420 | const tree = astgen.tree; |
| 2095 | const count: usize = count: { | 2421 | const node_tags = tree.nodes.items(.tag); |
| 2096 | var tok_i = error_token + 2; | 2422 | const token_starts = tree.tokens.items(.start); |
| 2097 | var count: usize = 0; | 2423 | const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; |
| 2098 | while (true) : (tok_i += 1) { | 2424 | const node_start = token_starts[tree.firstToken(node)]; |
| 2099 | switch (token_tags[tok_i]) { | 2425 | const source = tree.source[decl_start..node_start]; |
| 2100 | .doc_comment, .comma => {}, | 2426 | const loc = std.zig.findLineColumn(source, source.len); |
| 2101 | .identifier => count += 1, | 2427 | _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ |
| 2102 | .r_brace => break :count count, | 2428 | .dbg_stmt = .{ |
| 2103 | else => unreachable, | 2429 | .line = @intCast(u32, loc.line), |
| 2104 | } | 2430 | .column = @intCast(u32, loc.column), |
| 2105 | } else unreachable; // TODO should not need else unreachable here | 2431 | }, |
| 2106 | }; | 2432 | } }); |
| 2433 | } | ||
| 2107 | 2434 | ||
| 2108 | const gpa = mod.gpa; | 2435 | fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { |
| 2109 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 2436 | try emitDbgNode(gz, infix_node); |
| 2110 | errdefer new_decl_arena.deinit(); | 2437 | const astgen = gz.astgen; |
| 2111 | const arena = &new_decl_arena.allocator; | 2438 | const tree = astgen.tree; |
| 2439 | const node_datas = tree.nodes.items(.data); | ||
| 2440 | const main_tokens = tree.nodes.items(.main_token); | ||
| 2441 | const node_tags = tree.nodes.items(.tag); | ||
| 2112 | 2442 | ||
| 2113 | const fields = try arena.alloc([]const u8, count); | 2443 | const lhs = node_datas[infix_node].lhs; |
| 2114 | { | 2444 | const rhs = node_datas[infix_node].rhs; |
| 2115 | var tok_i = error_token + 2; | 2445 | if (node_tags[lhs] == .identifier) { |
| 2116 | var field_i: usize = 0; | 2446 | // This intentionally does not support `@"_"` syntax. |
| 2117 | while (true) : (tok_i += 1) { | 2447 | const ident_name = tree.tokenSlice(main_tokens[lhs]); |
| 2118 | switch (token_tags[tok_i]) { | 2448 | if (mem.eql(u8, ident_name, "_")) { |
| 2119 | .doc_comment, .comma => {}, | 2449 | _ = try expr(gz, scope, .discard, rhs); |
| 2120 | .identifier => { | 2450 | return; |
| 2121 | fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena); | ||
| 2122 | field_i += 1; | ||
| 2123 | }, | ||
| 2124 | .r_brace => break, | ||
| 2125 | else => unreachable, | ||
| 2126 | } | ||
| 2127 | } | 2451 | } |
| 2128 | } | 2452 | } |
| 2129 | const error_set = try arena.create(Module.ErrorSet); | 2453 | const lvalue = try lvalExpr(gz, scope, lhs); |
| 2130 | error_set.* = .{ | 2454 | _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs); |
| 2131 | .owner_decl = astgen.decl, | ||
| 2132 | .node_offset = astgen.decl.nodeIndexToRelative(node), | ||
| 2133 | .names_ptr = fields.ptr, | ||
| 2134 | .names_len = @intCast(u32, fields.len), | ||
| 2135 | }; | ||
| 2136 | const error_set_ty = try Type.Tag.error_set.create(arena, error_set); | ||
| 2137 | const error_set_val = try Value.Tag.ty.create(arena, error_set_ty); | ||
| 2138 | const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ | ||
| 2139 | .ty = Type.initTag(.type), | ||
| 2140 | .val = error_set_val, | ||
| 2141 | }); | ||
| 2142 | const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl); | ||
| 2143 | const result = try gz.addDecl(.decl_val, decl_index, node); | ||
| 2144 | return rvalue(gz, scope, rl, result, node); | ||
| 2145 | } | 2455 | } |
| 2146 | 2456 | ||
| 2147 | fn orelseCatchExpr( | 2457 | fn assignOp( |
| 2148 | parent_gz: *GenZir, | 2458 | gz: *GenZir, |
| 2149 | scope: *Scope, | 2459 | scope: *Scope, |
| 2150 | rl: ResultLoc, | 2460 | infix_node: ast.Node.Index, |
| 2151 | node: ast.Node.Index, | 2461 | op_inst_tag: Zir.Inst.Tag, |
| 2152 | lhs: ast.Node.Index, | 2462 | ) InnerError!void { |
| 2153 | cond_op: zir.Inst.Tag, | 2463 | try emitDbgNode(gz, infix_node); |
| 2154 | unwrap_op: zir.Inst.Tag, | 2464 | const astgen = gz.astgen; |
| 2155 | unwrap_code_op: zir.Inst.Tag, | 2465 | const tree = astgen.tree; |
| 2156 | rhs: ast.Node.Index, | 2466 | const node_datas = tree.nodes.items(.data); |
| 2157 | payload_token: ?ast.TokenIndex, | ||
| 2158 | ) InnerError!zir.Inst.Ref { | ||
| 2159 | const mod = parent_gz.astgen.mod; | ||
| 2160 | const tree = parent_gz.tree(); | ||
| 2161 | 2467 | ||
| 2162 | var block_scope: GenZir = .{ | 2468 | const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); |
| 2163 | .parent = scope, | 2469 | const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); |
| 2164 | .astgen = parent_gz.astgen, | 2470 | const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); |
| 2165 | .force_comptime = parent_gz.force_comptime, | 2471 | const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs); |
| 2166 | .instructions = .{}, | ||
| 2167 | }; | ||
| 2168 | block_scope.setBreakResultLoc(rl); | ||
| 2169 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 2170 | 2472 | ||
| 2171 | // This could be a pointer or value depending on the `operand_rl` parameter. | 2473 | const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ |
| 2172 | // We cannot use `block_scope.break_result_loc` because that has the bare | 2474 | .lhs = lhs, |
| 2173 | // type, whereas this expression has the optional type. Later we make | 2475 | .rhs = rhs, |
| 2174 | // up for this fact by calling rvalue on the else branch. | 2476 | }); |
| 2175 | block_scope.break_count += 1; | 2477 | _ = try gz.addBin(.store, lhs_ptr, result); |
| 2478 | } | ||
| 2176 | 2479 | ||
| 2177 | // TODO handle catch | 2480 | fn assignShift( |
| 2178 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { | ||
| 2179 | .ref => .ref, | ||
| 2180 | .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none, | ||
| 2181 | .ty => |elem_ty| blk: { | ||
| 2182 | const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node); | ||
| 2183 | break :blk .{ .ty = wrapped_ty }; | ||
| 2184 | }, | ||
| 2185 | .ptr => |ptr_ty| blk: { | ||
| 2186 | const wrapped_ty = try block_scope.addUnNode(.optional_type_from_ptr_elem, ptr_ty, node); | ||
| 2187 | break :blk .{ .ty = wrapped_ty }; | ||
| 2188 | }, | ||
| 2189 | }; | ||
| 2190 | const operand = try expr(&block_scope, &block_scope.base, operand_rl, lhs); | ||
| 2191 | const cond = try block_scope.addUnNode(cond_op, operand, node); | ||
| 2192 | const condbr = try block_scope.addCondBr(.condbr, node); | ||
| 2193 | |||
| 2194 | const block = try parent_gz.addBlock(.block, node); | ||
| 2195 | try parent_gz.instructions.append(mod.gpa, block); | ||
| 2196 | try block_scope.setBlockBody(block); | ||
| 2197 | |||
| 2198 | var then_scope: GenZir = .{ | ||
| 2199 | .parent = scope, | ||
| 2200 | .astgen = parent_gz.astgen, | ||
| 2201 | .force_comptime = block_scope.force_comptime, | ||
| 2202 | .instructions = .{}, | ||
| 2203 | }; | ||
| 2204 | defer then_scope.instructions.deinit(mod.gpa); | ||
| 2205 | |||
| 2206 | var err_val_scope: Scope.LocalVal = undefined; | ||
| 2207 | const then_sub_scope = blk: { | ||
| 2208 | const payload = payload_token orelse break :blk &then_scope.base; | ||
| 2209 | if (mem.eql(u8, tree.tokenSlice(payload), "_")) { | ||
| 2210 | return mod.failTok(&then_scope.base, payload, "discard of error capture; omit it instead", .{}); | ||
| 2211 | } | ||
| 2212 | const err_name = try mod.identifierTokenString(scope, payload); | ||
| 2213 | err_val_scope = .{ | ||
| 2214 | .parent = &then_scope.base, | ||
| 2215 | .gen_zir = &then_scope, | ||
| 2216 | .name = err_name, | ||
| 2217 | .inst = try then_scope.addUnNode(unwrap_code_op, operand, node), | ||
| 2218 | .src = parent_gz.tokSrcLoc(payload), | ||
| 2219 | }; | ||
| 2220 | break :blk &err_val_scope.base; | ||
| 2221 | }; | ||
| 2222 | |||
| 2223 | block_scope.break_count += 1; | ||
| 2224 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs); | ||
| 2225 | // We hold off on the break instructions as well as copying the then/else | ||
| 2226 | // instructions into place until we know whether to keep store_to_block_ptr | ||
| 2227 | // instructions or not. | ||
| 2228 | |||
| 2229 | var else_scope: GenZir = .{ | ||
| 2230 | .parent = scope, | ||
| 2231 | .astgen = parent_gz.astgen, | ||
| 2232 | .force_comptime = block_scope.force_comptime, | ||
| 2233 | .instructions = .{}, | ||
| 2234 | }; | ||
| 2235 | defer else_scope.instructions.deinit(mod.gpa); | ||
| 2236 | |||
| 2237 | // This could be a pointer or value depending on `unwrap_op`. | ||
| 2238 | const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node); | ||
| 2239 | const else_result = switch (rl) { | ||
| 2240 | .ref => unwrapped_payload, | ||
| 2241 | else => try rvalue(&else_scope, &else_scope.base, block_scope.break_result_loc, unwrapped_payload, node), | ||
| 2242 | }; | ||
| 2243 | |||
| 2244 | return finishThenElseBlock( | ||
| 2245 | parent_gz, | ||
| 2246 | scope, | ||
| 2247 | rl, | ||
| 2248 | node, | ||
| 2249 | &block_scope, | ||
| 2250 | &then_scope, | ||
| 2251 | &else_scope, | ||
| 2252 | condbr, | ||
| 2253 | cond, | ||
| 2254 | node, | ||
| 2255 | node, | ||
| 2256 | then_result, | ||
| 2257 | else_result, | ||
| 2258 | block, | ||
| 2259 | block, | ||
| 2260 | .@"break", | ||
| 2261 | ); | ||
| 2262 | } | ||
| 2263 | |||
| 2264 | fn finishThenElseBlock( | ||
| 2265 | parent_gz: *GenZir, | ||
| 2266 | parent_scope: *Scope, | ||
| 2267 | rl: ResultLoc, | ||
| 2268 | node: ast.Node.Index, | ||
| 2269 | block_scope: *GenZir, | ||
| 2270 | then_scope: *GenZir, | ||
| 2271 | else_scope: *GenZir, | ||
| 2272 | condbr: zir.Inst.Index, | ||
| 2273 | cond: zir.Inst.Ref, | ||
| 2274 | then_src: ast.Node.Index, | ||
| 2275 | else_src: ast.Node.Index, | ||
| 2276 | then_result: zir.Inst.Ref, | ||
| 2277 | else_result: zir.Inst.Ref, | ||
| 2278 | main_block: zir.Inst.Index, | ||
| 2279 | then_break_block: zir.Inst.Index, | ||
| 2280 | break_tag: zir.Inst.Tag, | ||
| 2281 | ) InnerError!zir.Inst.Ref { | ||
| 2282 | // We now have enough information to decide whether the result instruction should | ||
| 2283 | // be communicated via result location pointer or break instructions. | ||
| 2284 | const strat = rl.strategy(block_scope); | ||
| 2285 | const astgen = block_scope.astgen; | ||
| 2286 | switch (strat.tag) { | ||
| 2287 | .break_void => { | ||
| 2288 | if (!astgen.refIsNoReturn(then_result)) { | ||
| 2289 | _ = try then_scope.addBreak(break_tag, then_break_block, .void_value); | ||
| 2290 | } | ||
| 2291 | const elide_else = if (else_result != .none) astgen.refIsNoReturn(else_result) else false; | ||
| 2292 | if (!elide_else) { | ||
| 2293 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); | ||
| 2294 | } | ||
| 2295 | assert(!strat.elide_store_to_block_ptr_instructions); | ||
| 2296 | try setCondBrPayload(condbr, cond, then_scope, else_scope); | ||
| 2297 | return astgen.indexToRef(main_block); | ||
| 2298 | }, | ||
| 2299 | .break_operand => { | ||
| 2300 | if (!astgen.refIsNoReturn(then_result)) { | ||
| 2301 | _ = try then_scope.addBreak(break_tag, then_break_block, then_result); | ||
| 2302 | } | ||
| 2303 | if (else_result != .none) { | ||
| 2304 | if (!astgen.refIsNoReturn(else_result)) { | ||
| 2305 | _ = try else_scope.addBreak(break_tag, main_block, else_result); | ||
| 2306 | } | ||
| 2307 | } else { | ||
| 2308 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); | ||
| 2309 | } | ||
| 2310 | if (strat.elide_store_to_block_ptr_instructions) { | ||
| 2311 | try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope); | ||
| 2312 | } else { | ||
| 2313 | try setCondBrPayload(condbr, cond, then_scope, else_scope); | ||
| 2314 | } | ||
| 2315 | const block_ref = astgen.indexToRef(main_block); | ||
| 2316 | switch (rl) { | ||
| 2317 | .ref => return block_ref, | ||
| 2318 | else => return rvalue(parent_gz, parent_scope, rl, block_ref, node), | ||
| 2319 | } | ||
| 2320 | }, | ||
| 2321 | } | ||
| 2322 | } | ||
| 2323 | |||
| 2324 | /// Return whether the identifier names of two tokens are equal. Resolves @"" | ||
| 2325 | /// tokens without allocating. | ||
| 2326 | /// OK in theory it could do it without allocating. This implementation | ||
| 2327 | /// allocates when the @"" form is used. | ||
| 2328 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { | ||
| 2329 | const ident_name_1 = try mod.identifierTokenString(scope, token1); | ||
| 2330 | const ident_name_2 = try mod.identifierTokenString(scope, token2); | ||
| 2331 | return mem.eql(u8, ident_name_1, ident_name_2); | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | pub fn fieldAccess( | ||
| 2335 | gz: *GenZir, | 2481 | gz: *GenZir, |
| 2336 | scope: *Scope, | 2482 | scope: *Scope, |
| 2337 | rl: ResultLoc, | 2483 | infix_node: ast.Node.Index, |
| 2338 | node: ast.Node.Index, | 2484 | op_inst_tag: Zir.Inst.Tag, |
| 2339 | ) InnerError!zir.Inst.Ref { | 2485 | ) InnerError!void { |
| 2486 | try emitDbgNode(gz, infix_node); | ||
| 2340 | const astgen = gz.astgen; | 2487 | const astgen = gz.astgen; |
| 2341 | const mod = astgen.mod; | 2488 | const tree = astgen.tree; |
| 2342 | const tree = gz.tree(); | ||
| 2343 | const main_tokens = tree.nodes.items(.main_token); | ||
| 2344 | const node_datas = tree.nodes.items(.data); | 2489 | const node_datas = tree.nodes.items(.data); |
| 2345 | 2490 | ||
| 2346 | const object_node = node_datas[node].lhs; | 2491 | const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); |
| 2347 | const dot_token = main_tokens[node]; | 2492 | const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); |
| 2348 | const field_ident = dot_token + 1; | 2493 | const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); |
| 2349 | const str_index = try gz.identAsString(field_ident); | 2494 | const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs); |
| 2350 | switch (rl) { | 2495 | |
| 2351 | .ref => return gz.addPlNode(.field_ptr, node, zir.Inst.Field{ | 2496 | const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ |
| 2352 | .lhs = try expr(gz, scope, .ref, object_node), | 2497 | .lhs = lhs, |
| 2353 | .field_name_start = str_index, | 2498 | .rhs = rhs, |
| 2354 | }), | 2499 | }); |
| 2355 | else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, zir.Inst.Field{ | 2500 | _ = try gz.addBin(.store, lhs_ptr, result); |
| 2356 | .lhs = try expr(gz, scope, .none_or_ref, object_node), | ||
| 2357 | .field_name_start = str_index, | ||
| 2358 | }), node), | ||
| 2359 | } | ||
| 2360 | } | 2501 | } |
| 2361 | 2502 | ||
| 2362 | fn arrayAccess( | 2503 | fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 2363 | gz: *GenZir, | 2504 | const astgen = gz.astgen; |
| 2364 | scope: *Scope, | 2505 | const tree = astgen.tree; |
| 2365 | rl: ResultLoc, | ||
| 2366 | node: ast.Node.Index, | ||
| 2367 | ) InnerError!zir.Inst.Ref { | ||
| 2368 | const tree = gz.tree(); | ||
| 2369 | const main_tokens = tree.nodes.items(.main_token); | ||
| 2370 | const node_datas = tree.nodes.items(.data); | 2506 | const node_datas = tree.nodes.items(.data); |
| 2371 | switch (rl) { | 2507 | |
| 2372 | .ref => return gz.addBin( | 2508 | const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs); |
| 2373 | .elem_ptr, | 2509 | const result = try gz.addUnNode(.bool_not, operand, node); |
| 2374 | try expr(gz, scope, .ref, node_datas[node].lhs), | 2510 | return rvalue(gz, scope, rl, result, node); |
| 2375 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | ||
| 2376 | ), | ||
| 2377 | else => return rvalue(gz, scope, rl, try gz.addBin( | ||
| 2378 | .elem_val, | ||
| 2379 | try expr(gz, scope, .none_or_ref, node_datas[node].lhs), | ||
| 2380 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | ||
| 2381 | ), node), | ||
| 2382 | } | ||
| 2383 | } | 2511 | } |
| 2384 | 2512 | ||
| 2385 | fn simpleBinOp( | 2513 | fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 2386 | gz: *GenZir, | 2514 | const astgen = gz.astgen; |
| 2387 | scope: *Scope, | 2515 | const tree = astgen.tree; |
| 2388 | rl: ResultLoc, | ||
| 2389 | node: ast.Node.Index, | ||
| 2390 | op_inst_tag: zir.Inst.Tag, | ||
| 2391 | ) InnerError!zir.Inst.Ref { | ||
| 2392 | const tree = gz.tree(); | ||
| 2393 | const node_datas = tree.nodes.items(.data); | 2516 | const node_datas = tree.nodes.items(.data); |
| 2394 | 2517 | ||
| 2395 | const result = try gz.addPlNode(op_inst_tag, node, zir.Inst.Bin{ | 2518 | const operand = try expr(gz, scope, .none, node_datas[node].lhs); |
| 2396 | .lhs = try expr(gz, scope, .none, node_datas[node].lhs), | 2519 | const result = try gz.addUnNode(.bit_not, operand, node); |
| 2397 | .rhs = try expr(gz, scope, .none, node_datas[node].rhs), | ||
| 2398 | }); | ||
| 2399 | return rvalue(gz, scope, rl, result, node); | 2520 | return rvalue(gz, scope, rl, result, node); |
| 2400 | } | 2521 | } |
| 2401 | 2522 | ||
| 2402 | fn simpleStrTok( | 2523 | fn negation( |
| 2403 | gz: *GenZir, | 2524 | gz: *GenZir, |
| 2404 | scope: *Scope, | 2525 | scope: *Scope, |
| 2405 | rl: ResultLoc, | 2526 | rl: ResultLoc, |
| 2406 | ident_token: ast.TokenIndex, | ||
| 2407 | node: ast.Node.Index, | 2527 | node: ast.Node.Index, |
| 2408 | op_inst_tag: zir.Inst.Tag, | 2528 | tag: Zir.Inst.Tag, |
| 2409 | ) InnerError!zir.Inst.Ref { | 2529 | ) InnerError!Zir.Inst.Ref { |
| 2410 | const str_index = try gz.identAsString(ident_token); | 2530 | const astgen = gz.astgen; |
| 2411 | const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); | 2531 | const tree = astgen.tree; |
| 2532 | const node_datas = tree.nodes.items(.data); | ||
| 2533 | |||
| 2534 | const operand = try expr(gz, scope, .none, node_datas[node].lhs); | ||
| 2535 | const result = try gz.addUnNode(tag, operand, node); | ||
| 2412 | return rvalue(gz, scope, rl, result, node); | 2536 | return rvalue(gz, scope, rl, result, node); |
| 2413 | } | 2537 | } |
| 2414 | 2538 | ||
| 2415 | fn boolBinOp( | 2539 | fn ptrType( |
| 2416 | gz: *GenZir, | 2540 | gz: *GenZir, |
| 2417 | scope: *Scope, | 2541 | scope: *Scope, |
| 2418 | rl: ResultLoc, | 2542 | rl: ResultLoc, |
| 2419 | node: ast.Node.Index, | 2543 | node: ast.Node.Index, |
| 2420 | zir_tag: zir.Inst.Tag, | 2544 | ptr_info: ast.full.PtrType, |
| 2421 | ) InnerError!zir.Inst.Ref { | 2545 | ) InnerError!Zir.Inst.Ref { |
| 2422 | const node_datas = gz.tree().nodes.items(.data); | 2546 | const astgen = gz.astgen; |
| 2423 | 2547 | const tree = astgen.tree; | |
| 2424 | const lhs = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs); | ||
| 2425 | const bool_br = try gz.addBoolBr(zir_tag, lhs); | ||
| 2426 | |||
| 2427 | var rhs_scope: GenZir = .{ | ||
| 2428 | .parent = scope, | ||
| 2429 | .astgen = gz.astgen, | ||
| 2430 | .force_comptime = gz.force_comptime, | ||
| 2431 | }; | ||
| 2432 | defer rhs_scope.instructions.deinit(gz.astgen.mod.gpa); | ||
| 2433 | const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs); | ||
| 2434 | _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); | ||
| 2435 | try rhs_scope.setBoolBrBody(bool_br); | ||
| 2436 | |||
| 2437 | const block_ref = gz.astgen.indexToRef(bool_br); | ||
| 2438 | return rvalue(gz, scope, rl, block_ref, node); | ||
| 2439 | } | ||
| 2440 | 2548 | ||
| 2441 | fn ifExpr( | 2549 | const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); |
| 2442 | parent_gz: *GenZir, | ||
| 2443 | scope: *Scope, | ||
| 2444 | rl: ResultLoc, | ||
| 2445 | node: ast.Node.Index, | ||
| 2446 | if_full: ast.full.If, | ||
| 2447 | ) InnerError!zir.Inst.Ref { | ||
| 2448 | const mod = parent_gz.astgen.mod; | ||
| 2449 | 2550 | ||
| 2450 | var block_scope: GenZir = .{ | 2551 | const simple = ptr_info.ast.align_node == 0 and |
| 2451 | .parent = scope, | 2552 | ptr_info.ast.sentinel == 0 and |
| 2452 | .astgen = parent_gz.astgen, | 2553 | ptr_info.ast.bit_range_start == 0; |
| 2453 | .force_comptime = parent_gz.force_comptime, | ||
| 2454 | .instructions = .{}, | ||
| 2455 | }; | ||
| 2456 | block_scope.setBreakResultLoc(rl); | ||
| 2457 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 2458 | 2554 | ||
| 2459 | const cond = c: { | 2555 | if (simple) { |
| 2460 | // TODO https://github.com/ziglang/zig/issues/7929 | 2556 | const result = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ |
| 2461 | if (if_full.error_token) |error_token| { | 2557 | .ptr_type_simple = .{ |
| 2462 | return mod.failTok(scope, error_token, "TODO implement if error union", .{}); | 2558 | .is_allowzero = ptr_info.allowzero_token != null, |
| 2463 | } else if (if_full.payload_token) |payload_token| { | 2559 | .is_mutable = ptr_info.const_token == null, |
| 2464 | return mod.failTok(scope, payload_token, "TODO implement if optional", .{}); | 2560 | .is_volatile = ptr_info.volatile_token != null, |
| 2465 | } else { | 2561 | .size = ptr_info.size, |
| 2466 | break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr); | 2562 | .elem_type = elem_type, |
| 2467 | } | 2563 | }, |
| 2468 | }; | 2564 | } }); |
| 2565 | return rvalue(gz, scope, rl, result, node); | ||
| 2566 | } | ||
| 2469 | 2567 | ||
| 2470 | const condbr = try block_scope.addCondBr(.condbr, node); | 2568 | var sentinel_ref: Zir.Inst.Ref = .none; |
| 2569 | var align_ref: Zir.Inst.Ref = .none; | ||
| 2570 | var bit_start_ref: Zir.Inst.Ref = .none; | ||
| 2571 | var bit_end_ref: Zir.Inst.Ref = .none; | ||
| 2572 | var trailing_count: u32 = 0; | ||
| 2471 | 2573 | ||
| 2472 | const block = try parent_gz.addBlock(.block, node); | 2574 | if (ptr_info.ast.sentinel != 0) { |
| 2473 | try parent_gz.instructions.append(mod.gpa, block); | 2575 | sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel); |
| 2474 | try block_scope.setBlockBody(block); | 2576 | trailing_count += 1; |
| 2577 | } | ||
| 2578 | if (ptr_info.ast.align_node != 0) { | ||
| 2579 | align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node); | ||
| 2580 | trailing_count += 1; | ||
| 2581 | } | ||
| 2582 | if (ptr_info.ast.bit_range_start != 0) { | ||
| 2583 | assert(ptr_info.ast.bit_range_end != 0); | ||
| 2584 | bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start); | ||
| 2585 | bit_end_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_end); | ||
| 2586 | trailing_count += 2; | ||
| 2587 | } | ||
| 2475 | 2588 | ||
| 2476 | var then_scope: GenZir = .{ | 2589 | const gpa = gz.astgen.gpa; |
| 2477 | .parent = scope, | 2590 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); |
| 2478 | .astgen = parent_gz.astgen, | 2591 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); |
| 2479 | .force_comptime = block_scope.force_comptime, | 2592 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + |
| 2480 | .instructions = .{}, | 2593 | @typeInfo(Zir.Inst.PtrType).Struct.fields.len + trailing_count); |
| 2481 | }; | ||
| 2482 | defer then_scope.instructions.deinit(mod.gpa); | ||
| 2483 | 2594 | ||
| 2484 | // declare payload to the then_scope | 2595 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type }); |
| 2485 | const then_sub_scope = &then_scope.base; | 2596 | if (sentinel_ref != .none) { |
| 2597 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); | ||
| 2598 | } | ||
| 2599 | if (align_ref != .none) { | ||
| 2600 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); | ||
| 2601 | } | ||
| 2602 | if (bit_start_ref != .none) { | ||
| 2603 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); | ||
| 2604 | gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); | ||
| 2605 | } | ||
| 2486 | 2606 | ||
| 2487 | block_scope.break_count += 1; | 2607 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| 2488 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); | 2608 | const result = gz.indexToRef(new_index); |
| 2489 | // We hold off on the break instructions as well as copying the then/else | 2609 | gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ |
| 2490 | // instructions into place until we know whether to keep store_to_block_ptr | 2610 | .ptr_type = .{ |
| 2491 | // instructions or not. | 2611 | .flags = .{ |
| 2492 | 2612 | .is_allowzero = ptr_info.allowzero_token != null, | |
| 2493 | var else_scope: GenZir = .{ | 2613 | .is_mutable = ptr_info.const_token == null, |
| 2494 | .parent = scope, | 2614 | .is_volatile = ptr_info.volatile_token != null, |
| 2495 | .astgen = parent_gz.astgen, | 2615 | .has_sentinel = sentinel_ref != .none, |
| 2496 | .force_comptime = block_scope.force_comptime, | 2616 | .has_align = align_ref != .none, |
| 2497 | .instructions = .{}, | 2617 | .has_bit_range = bit_start_ref != .none, |
| 2498 | }; | 2618 | }, |
| 2499 | defer else_scope.instructions.deinit(mod.gpa); | 2619 | .size = ptr_info.size, |
| 2500 | 2620 | .payload_index = payload_index, | |
| 2501 | const else_node = if_full.ast.else_expr; | 2621 | }, |
| 2502 | const else_info: struct { | 2622 | } }); |
| 2503 | src: ast.Node.Index, | 2623 | gz.instructions.appendAssumeCapacity(new_index); |
| 2504 | result: zir.Inst.Ref, | ||
| 2505 | } = if (else_node != 0) blk: { | ||
| 2506 | block_scope.break_count += 1; | ||
| 2507 | const sub_scope = &else_scope.base; | ||
| 2508 | break :blk .{ | ||
| 2509 | .src = else_node, | ||
| 2510 | .result = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node), | ||
| 2511 | }; | ||
| 2512 | } else .{ | ||
| 2513 | .src = if_full.ast.then_expr, | ||
| 2514 | .result = .none, | ||
| 2515 | }; | ||
| 2516 | 2624 | ||
| 2517 | return finishThenElseBlock( | 2625 | return rvalue(gz, scope, rl, result, node); |
| 2518 | parent_gz, | ||
| 2519 | scope, | ||
| 2520 | rl, | ||
| 2521 | node, | ||
| 2522 | &block_scope, | ||
| 2523 | &then_scope, | ||
| 2524 | &else_scope, | ||
| 2525 | condbr, | ||
| 2526 | cond, | ||
| 2527 | if_full.ast.then_expr, | ||
| 2528 | else_info.src, | ||
| 2529 | then_result, | ||
| 2530 | else_info.result, | ||
| 2531 | block, | ||
| 2532 | block, | ||
| 2533 | .@"break", | ||
| 2534 | ); | ||
| 2535 | } | 2626 | } |
| 2536 | 2627 | ||
| 2537 | fn setCondBrPayload( | 2628 | fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { |
| 2538 | condbr: zir.Inst.Index, | 2629 | const astgen = gz.astgen; |
| 2539 | cond: zir.Inst.Ref, | 2630 | const tree = astgen.tree; |
| 2540 | then_scope: *GenZir, | 2631 | const node_datas = tree.nodes.items(.data); |
| 2541 | else_scope: *GenZir, | 2632 | const node_tags = tree.nodes.items(.tag); |
| 2542 | ) !void { | 2633 | const main_tokens = tree.nodes.items(.main_token); |
| 2543 | const astgen = then_scope.astgen; | ||
| 2544 | 2634 | ||
| 2545 | try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len + | 2635 | const len_node = node_datas[node].lhs; |
| 2546 | @typeInfo(zir.Inst.CondBr).Struct.fields.len + | 2636 | if (node_tags[len_node] == .identifier and |
| 2547 | then_scope.instructions.items.len + else_scope.instructions.items.len); | 2637 | mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) |
| 2638 | { | ||
| 2639 | return astgen.failNode(len_node, "unable to infer array size", .{}); | ||
| 2640 | } | ||
| 2641 | const len = try expr(gz, scope, .{ .ty = .usize_type }, len_node); | ||
| 2642 | const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); | ||
| 2548 | 2643 | ||
| 2549 | const zir_datas = astgen.instructions.items(.data); | 2644 | const result = try gz.addBin(.array_type, len, elem_type); |
| 2550 | zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.CondBr{ | 2645 | return rvalue(gz, scope, rl, result, node); |
| 2551 | .condition = cond, | ||
| 2552 | .then_body_len = @intCast(u32, then_scope.instructions.items.len), | ||
| 2553 | .else_body_len = @intCast(u32, else_scope.instructions.items.len), | ||
| 2554 | }); | ||
| 2555 | astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items); | ||
| 2556 | astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items); | ||
| 2557 | } | 2646 | } |
| 2558 | 2647 | ||
| 2559 | /// If `elide_block_store_ptr` is set, expects to find exactly 1 .store_to_block_ptr instruction. | 2648 | fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { |
| 2560 | fn setCondBrPayloadElideBlockStorePtr( | 2649 | const astgen = gz.astgen; |
| 2561 | condbr: zir.Inst.Index, | 2650 | const tree = astgen.tree; |
| 2562 | cond: zir.Inst.Ref, | 2651 | const node_datas = tree.nodes.items(.data); |
| 2563 | then_scope: *GenZir, | 2652 | const node_tags = tree.nodes.items(.tag); |
| 2564 | else_scope: *GenZir, | 2653 | const main_tokens = tree.nodes.items(.main_token); |
| 2565 | ) !void { | 2654 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); |
| 2566 | const astgen = then_scope.astgen; | ||
| 2567 | 2655 | ||
| 2568 | try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len + | 2656 | const len_node = node_datas[node].lhs; |
| 2569 | @typeInfo(zir.Inst.CondBr).Struct.fields.len + | 2657 | if (node_tags[len_node] == .identifier and |
| 2570 | then_scope.instructions.items.len + else_scope.instructions.items.len - 2); | 2658 | mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) |
| 2659 | { | ||
| 2660 | return astgen.failNode(len_node, "unable to infer array size", .{}); | ||
| 2661 | } | ||
| 2662 | const len = try expr(gz, scope, .{ .ty = .usize_type }, len_node); | ||
| 2663 | const elem_type = try typeExpr(gz, scope, extra.elem_type); | ||
| 2664 | const sentinel = try expr(gz, scope, .{ .ty = elem_type }, extra.sentinel); | ||
| 2571 | 2665 | ||
| 2572 | const zir_datas = astgen.instructions.items(.data); | 2666 | const result = try gz.addArrayTypeSentinel(len, elem_type, sentinel); |
| 2573 | zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.CondBr{ | 2667 | return rvalue(gz, scope, rl, result, node); |
| 2574 | .condition = cond, | 2668 | } |
| 2575 | .then_body_len = @intCast(u32, then_scope.instructions.items.len - 1), | ||
| 2576 | .else_body_len = @intCast(u32, else_scope.instructions.items.len - 1), | ||
| 2577 | }); | ||
| 2578 | 2669 | ||
| 2579 | const zir_tags = astgen.instructions.items(.tag); | 2670 | const WipDecls = struct { |
| 2580 | for ([_]*GenZir{ then_scope, else_scope }) |scope| { | 2671 | decl_index: usize = 0, |
| 2581 | for (scope.instructions.items) |src_inst| { | 2672 | cur_bit_bag: u32 = 0, |
| 2582 | if (zir_tags[src_inst] != .store_to_block_ptr) { | 2673 | bit_bag: ArrayListUnmanaged(u32) = .{}, |
| 2583 | astgen.extra.appendAssumeCapacity(src_inst); | 2674 | payload: ArrayListUnmanaged(u32) = .{}, |
| 2584 | } | 2675 | |
| 2676 | const bits_per_field = 4; | ||
| 2677 | const fields_per_u32 = 32 / bits_per_field; | ||
| 2678 | |||
| 2679 | fn next( | ||
| 2680 | wip_decls: *WipDecls, | ||
| 2681 | gpa: *Allocator, | ||
| 2682 | is_pub: bool, | ||
| 2683 | is_export: bool, | ||
| 2684 | has_align: bool, | ||
| 2685 | has_section: bool, | ||
| 2686 | ) Allocator.Error!void { | ||
| 2687 | if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) { | ||
| 2688 | try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag); | ||
| 2689 | wip_decls.cur_bit_bag = 0; | ||
| 2585 | } | 2690 | } |
| 2691 | wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> bits_per_field) | | ||
| 2692 | (@as(u32, @boolToInt(is_pub)) << 28) | | ||
| 2693 | (@as(u32, @boolToInt(is_export)) << 29) | | ||
| 2694 | (@as(u32, @boolToInt(has_align)) << 30) | | ||
| 2695 | (@as(u32, @boolToInt(has_section)) << 31); | ||
| 2696 | wip_decls.decl_index += 1; | ||
| 2586 | } | 2697 | } |
| 2587 | } | ||
| 2588 | 2698 | ||
| 2589 | fn whileExpr( | 2699 | fn deinit(wip_decls: *WipDecls, gpa: *Allocator) void { |
| 2590 | parent_gz: *GenZir, | 2700 | wip_decls.bit_bag.deinit(gpa); |
| 2591 | scope: *Scope, | 2701 | wip_decls.payload.deinit(gpa); |
| 2592 | rl: ResultLoc, | ||
| 2593 | node: ast.Node.Index, | ||
| 2594 | while_full: ast.full.While, | ||
| 2595 | ) InnerError!zir.Inst.Ref { | ||
| 2596 | const mod = parent_gz.astgen.mod; | ||
| 2597 | if (while_full.label_token) |label_token| { | ||
| 2598 | try checkLabelRedefinition(mod, scope, label_token); | ||
| 2599 | } | 2702 | } |
| 2703 | }; | ||
| 2600 | 2704 | ||
| 2601 | const is_inline = parent_gz.force_comptime or while_full.inline_token != null; | 2705 | fn fnDecl( |
| 2602 | const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop; | 2706 | astgen: *AstGen, |
| 2603 | const loop_block = try parent_gz.addBlock(loop_tag, node); | 2707 | gz: *GenZir, |
| 2604 | try parent_gz.instructions.append(mod.gpa, loop_block); | 2708 | scope: *Scope, |
| 2709 | wip_decls: *WipDecls, | ||
| 2710 | decl_node: ast.Node.Index, | ||
| 2711 | body_node: ast.Node.Index, | ||
| 2712 | fn_proto: ast.full.FnProto, | ||
| 2713 | ) InnerError!void { | ||
| 2714 | const gpa = astgen.gpa; | ||
| 2715 | const tree = astgen.tree; | ||
| 2716 | const token_tags = tree.tokens.items(.tag); | ||
| 2717 | |||
| 2718 | const fn_name_token = fn_proto.name_token orelse { | ||
| 2719 | return astgen.failTok(fn_proto.ast.fn_token, "missing function name", .{}); | ||
| 2720 | }; | ||
| 2721 | const fn_name_str_index = try astgen.identAsString(fn_name_token); | ||
| 2605 | 2722 | ||
| 2606 | var loop_scope: GenZir = .{ | 2723 | try astgen.declareNewName(scope, fn_name_str_index, decl_node); |
| 2724 | |||
| 2725 | // We insert this at the beginning so that its instruction index marks the | ||
| 2726 | // start of the top level declaration. | ||
| 2727 | const block_inst = try gz.addBlock(.block_inline, fn_proto.ast.proto_node); | ||
| 2728 | |||
| 2729 | var decl_gz: GenZir = .{ | ||
| 2730 | .force_comptime = true, | ||
| 2731 | .decl_node_index = fn_proto.ast.proto_node, | ||
| 2732 | .decl_line = gz.calcLine(decl_node), | ||
| 2607 | .parent = scope, | 2733 | .parent = scope, |
| 2608 | .astgen = parent_gz.astgen, | 2734 | .astgen = astgen, |
| 2609 | .force_comptime = parent_gz.force_comptime, | ||
| 2610 | .instructions = .{}, | ||
| 2611 | }; | 2735 | }; |
| 2612 | loop_scope.setBreakResultLoc(rl); | 2736 | defer decl_gz.instructions.deinit(gpa); |
| 2613 | defer loop_scope.instructions.deinit(mod.gpa); | ||
| 2614 | 2737 | ||
| 2615 | var continue_scope: GenZir = .{ | 2738 | const is_pub = fn_proto.visib_token != null; |
| 2616 | .parent = &loop_scope.base, | 2739 | const is_export = blk: { |
| 2617 | .astgen = parent_gz.astgen, | 2740 | const maybe_export_token = fn_proto.extern_export_token orelse break :blk false; |
| 2618 | .force_comptime = loop_scope.force_comptime, | 2741 | break :blk token_tags[maybe_export_token] == .keyword_export; |
| 2619 | .instructions = .{}, | 2742 | }; |
| 2743 | const is_extern = blk: { | ||
| 2744 | const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; | ||
| 2745 | break :blk token_tags[maybe_extern_token] == .keyword_extern; | ||
| 2746 | }; | ||
| 2747 | const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { | ||
| 2748 | break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr); | ||
| 2749 | }; | ||
| 2750 | const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { | ||
| 2751 | break :inst try comptimeExpr(&decl_gz, &decl_gz.base, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr); | ||
| 2620 | }; | 2752 | }; |
| 2621 | defer continue_scope.instructions.deinit(mod.gpa); | ||
| 2622 | 2753 | ||
| 2623 | const cond = c: { | 2754 | try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none); |
| 2624 | // TODO https://github.com/ziglang/zig/issues/7929 | 2755 | |
| 2625 | if (while_full.error_token) |error_token| { | 2756 | // The AST params array does not contain anytype and ... parameters. |
| 2626 | return mod.failTok(scope, error_token, "TODO implement while error union", .{}); | 2757 | // We must iterate to count how many param types to allocate. |
| 2627 | } else if (while_full.payload_token) |payload_token| { | 2758 | const param_count = blk: { |
| 2628 | return mod.failTok(scope, payload_token, "TODO implement while optional", .{}); | 2759 | var count: usize = 0; |
| 2629 | } else { | 2760 | var it = fn_proto.iterate(tree.*); |
| 2630 | const bool_type_rl: ResultLoc = .{ .ty = .bool_type }; | 2761 | while (it.next()) |param| { |
| 2631 | break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr); | 2762 | if (param.anytype_ellipsis3) |token| switch (token_tags[token]) { |
| 2763 | .ellipsis3 => break, | ||
| 2764 | .keyword_anytype => {}, | ||
| 2765 | else => unreachable, | ||
| 2766 | }; | ||
| 2767 | count += 1; | ||
| 2632 | } | 2768 | } |
| 2769 | break :blk count; | ||
| 2633 | }; | 2770 | }; |
| 2771 | const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); | ||
| 2772 | defer gpa.free(param_types); | ||
| 2634 | 2773 | ||
| 2635 | const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; | 2774 | var is_var_args = false; |
| 2636 | const condbr = try continue_scope.addCondBr(condbr_tag, node); | 2775 | { |
| 2637 | const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block; | 2776 | var param_type_i: usize = 0; |
| 2638 | const cond_block = try loop_scope.addBlock(block_tag, node); | 2777 | var it = fn_proto.iterate(tree.*); |
| 2639 | try loop_scope.instructions.append(mod.gpa, cond_block); | 2778 | while (it.next()) |param| : (param_type_i += 1) { |
| 2640 | try continue_scope.setBlockBody(cond_block); | 2779 | if (param.anytype_ellipsis3) |token| { |
| 2641 | 2780 | switch (token_tags[token]) { | |
| 2642 | // TODO avoid emitting the continue expr when there | 2781 | .keyword_anytype => { |
| 2643 | // are no jumps to it. This happens when the last statement of a while body is noreturn | 2782 | param_types[param_type_i] = .none; |
| 2644 | // and there are no `continue` statements. | 2783 | continue; |
| 2645 | if (while_full.ast.cont_expr != 0) { | 2784 | }, |
| 2646 | _ = try expr(&loop_scope, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr); | 2785 | .ellipsis3 => { |
| 2786 | is_var_args = true; | ||
| 2787 | break; | ||
| 2788 | }, | ||
| 2789 | else => unreachable, | ||
| 2790 | } | ||
| 2791 | } | ||
| 2792 | const param_type_node = param.type_expr; | ||
| 2793 | assert(param_type_node != 0); | ||
| 2794 | param_types[param_type_i] = | ||
| 2795 | try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node); | ||
| 2796 | } | ||
| 2797 | assert(param_type_i == param_count); | ||
| 2647 | } | 2798 | } |
| 2648 | const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | ||
| 2649 | _ = try loop_scope.addNode(repeat_tag, node); | ||
| 2650 | 2799 | ||
| 2651 | try loop_scope.setBlockBody(loop_block); | 2800 | const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { |
| 2652 | loop_scope.break_block = loop_block; | 2801 | const lib_name_str = try astgen.strLitAsString(lib_name_token); |
| 2653 | loop_scope.continue_block = cond_block; | 2802 | break :blk lib_name_str.index; |
| 2654 | if (while_full.label_token) |label_token| { | 2803 | } else 0; |
| 2655 | loop_scope.label = @as(?GenZir.Label, GenZir.Label{ | 2804 | |
| 2656 | .token = label_token, | 2805 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 2657 | .block_inst = loop_block, | 2806 | const is_inferred_error = token_tags[maybe_bang] == .bang; |
| 2807 | |||
| 2808 | const return_type_inst = try AstGen.expr( | ||
| 2809 | &decl_gz, | ||
| 2810 | &decl_gz.base, | ||
| 2811 | .{ .ty = .type_type }, | ||
| 2812 | fn_proto.ast.return_type, | ||
| 2813 | ); | ||
| 2814 | |||
| 2815 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) | ||
| 2816 | try AstGen.expr( | ||
| 2817 | &decl_gz, | ||
| 2818 | &decl_gz.base, | ||
| 2819 | .{ .ty = .calling_convention_type }, | ||
| 2820 | fn_proto.ast.callconv_expr, | ||
| 2821 | ) | ||
| 2822 | else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269 | ||
| 2823 | Zir.Inst.Ref.calling_convention_c | ||
| 2824 | else | ||
| 2825 | Zir.Inst.Ref.none; | ||
| 2826 | |||
| 2827 | const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { | ||
| 2828 | if (!is_extern) { | ||
| 2829 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); | ||
| 2830 | } | ||
| 2831 | if (is_inferred_error) { | ||
| 2832 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); | ||
| 2833 | } | ||
| 2834 | break :func try decl_gz.addFunc(.{ | ||
| 2835 | .src_node = decl_node, | ||
| 2836 | .ret_ty = return_type_inst, | ||
| 2837 | .param_types = param_types, | ||
| 2838 | .body = &[0]Zir.Inst.Index{}, | ||
| 2839 | .cc = cc, | ||
| 2840 | .align_inst = .none, // passed in the per-decl data | ||
| 2841 | .lib_name = lib_name, | ||
| 2842 | .is_var_args = is_var_args, | ||
| 2843 | .is_inferred_error = false, | ||
| 2844 | .is_test = false, | ||
| 2845 | .is_extern = true, | ||
| 2658 | }); | 2846 | }); |
| 2659 | } | 2847 | } else func: { |
| 2848 | if (is_var_args) { | ||
| 2849 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); | ||
| 2850 | } | ||
| 2660 | 2851 | ||
| 2661 | var then_scope: GenZir = .{ | 2852 | var fn_gz: GenZir = .{ |
| 2662 | .parent = &continue_scope.base, | 2853 | .force_comptime = false, |
| 2663 | .astgen = parent_gz.astgen, | 2854 | .decl_node_index = fn_proto.ast.proto_node, |
| 2664 | .force_comptime = continue_scope.force_comptime, | 2855 | .decl_line = decl_gz.decl_line, |
| 2665 | .instructions = .{}, | 2856 | .parent = &decl_gz.base, |
| 2666 | }; | 2857 | .astgen = astgen, |
| 2667 | defer then_scope.instructions.deinit(mod.gpa); | 2858 | }; |
| 2859 | defer fn_gz.instructions.deinit(gpa); | ||
| 2668 | 2860 | ||
| 2669 | const then_sub_scope = &then_scope.base; | 2861 | const prev_fn_block = astgen.fn_block; |
| 2862 | astgen.fn_block = &fn_gz; | ||
| 2670 | 2863 | ||
| 2671 | loop_scope.break_count += 1; | 2864 | // Iterate over the parameters. We put the param names as the first N |
| 2672 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); | 2865 | // items inside `extra` so that debug info later can refer to the parameter names |
| 2866 | // even while the respective source code is unloaded. | ||
| 2867 | try astgen.extra.ensureUnusedCapacity(gpa, param_count); | ||
| 2673 | 2868 | ||
| 2674 | var else_scope: GenZir = .{ | 2869 | { |
| 2675 | .parent = &continue_scope.base, | 2870 | var params_scope = &fn_gz.base; |
| 2676 | .astgen = parent_gz.astgen, | 2871 | var i: usize = 0; |
| 2677 | .force_comptime = continue_scope.force_comptime, | 2872 | var it = fn_proto.iterate(tree.*); |
| 2678 | .instructions = .{}, | 2873 | while (it.next()) |param| : (i += 1) { |
| 2679 | }; | 2874 | const name_token = param.name_token orelse { |
| 2680 | defer else_scope.instructions.deinit(mod.gpa); | 2875 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); |
| 2876 | }; | ||
| 2877 | const param_name = try astgen.identAsString(name_token); | ||
| 2878 | // Create an arg instruction. This is needed to emit a semantic analysis | ||
| 2879 | // error for shadowing decls. | ||
| 2880 | // TODO emit a compile error here for shadowing locals. | ||
| 2881 | const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token); | ||
| 2882 | const sub_scope = try astgen.arena.create(Scope.LocalVal); | ||
| 2883 | sub_scope.* = .{ | ||
| 2884 | .parent = params_scope, | ||
| 2885 | .gen_zir = &fn_gz, | ||
| 2886 | .name = param_name, | ||
| 2887 | .inst = arg_inst, | ||
| 2888 | .token_src = name_token, | ||
| 2889 | }; | ||
| 2890 | params_scope = &sub_scope.base; | ||
| 2681 | 2891 | ||
| 2682 | const else_node = while_full.ast.else_expr; | 2892 | // Additionally put the param name into `string_bytes` and reference it with |
| 2683 | const else_info: struct { | 2893 | // `extra` so that we have access to the data in codegen, for debug info. |
| 2684 | src: ast.Node.Index, | 2894 | const str_index = try astgen.identAsString(name_token); |
| 2685 | result: zir.Inst.Ref, | 2895 | astgen.extra.appendAssumeCapacity(str_index); |
| 2686 | } = if (else_node != 0) blk: { | 2896 | } |
| 2687 | loop_scope.break_count += 1; | 2897 | |
| 2688 | const sub_scope = &else_scope.base; | 2898 | _ = try expr(&fn_gz, params_scope, .none, body_node); |
| 2689 | break :blk .{ | 2899 | } |
| 2690 | .src = else_node, | 2900 | |
| 2691 | .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), | 2901 | const need_implicit_ret = blk: { |
| 2902 | if (fn_gz.instructions.items.len == 0) | ||
| 2903 | break :blk true; | ||
| 2904 | const last = fn_gz.instructions.items[fn_gz.instructions.items.len - 1]; | ||
| 2905 | const zir_tags = astgen.instructions.items(.tag); | ||
| 2906 | break :blk !zir_tags[last].isNoReturn(); | ||
| 2692 | }; | 2907 | }; |
| 2693 | } else .{ | 2908 | if (need_implicit_ret) { |
| 2694 | .src = while_full.ast.then_expr, | 2909 | // Since we are adding the return instruction here, we must handle the coercion. |
| 2695 | .result = .none, | 2910 | // We do this by using the `ret_coerce` instruction. |
| 2911 | _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); | ||
| 2912 | } | ||
| 2913 | |||
| 2914 | astgen.fn_block = prev_fn_block; | ||
| 2915 | |||
| 2916 | break :func try decl_gz.addFunc(.{ | ||
| 2917 | .src_node = decl_node, | ||
| 2918 | .ret_ty = return_type_inst, | ||
| 2919 | .param_types = param_types, | ||
| 2920 | .body = fn_gz.instructions.items, | ||
| 2921 | .cc = cc, | ||
| 2922 | .align_inst = .none, // passed in the per-decl data | ||
| 2923 | .lib_name = lib_name, | ||
| 2924 | .is_var_args = is_var_args, | ||
| 2925 | .is_inferred_error = is_inferred_error, | ||
| 2926 | .is_test = false, | ||
| 2927 | .is_extern = false, | ||
| 2928 | }); | ||
| 2696 | }; | 2929 | }; |
| 2697 | 2930 | ||
| 2698 | if (loop_scope.label) |some| { | 2931 | // We add this at the end so that its instruction index marks the end range |
| 2699 | if (!some.used) { | 2932 | // of the top level declaration. |
| 2700 | return mod.failTok(scope, some.token, "unused while loop label", .{}); | 2933 | _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); |
| 2701 | } | 2934 | try decl_gz.setBlockBody(block_inst); |
| 2935 | |||
| 2936 | try wip_decls.payload.ensureUnusedCapacity(gpa, 9); | ||
| 2937 | { | ||
| 2938 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); | ||
| 2939 | const casted = @bitCast([4]u32, contents_hash); | ||
| 2940 | wip_decls.payload.appendSliceAssumeCapacity(&casted); | ||
| 2941 | } | ||
| 2942 | { | ||
| 2943 | const line_delta = decl_gz.decl_line - gz.decl_line; | ||
| 2944 | wip_decls.payload.appendAssumeCapacity(line_delta); | ||
| 2945 | } | ||
| 2946 | wip_decls.payload.appendAssumeCapacity(fn_name_str_index); | ||
| 2947 | wip_decls.payload.appendAssumeCapacity(block_inst); | ||
| 2948 | if (align_inst != .none) { | ||
| 2949 | wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); | ||
| 2950 | } | ||
| 2951 | if (section_inst != .none) { | ||
| 2952 | wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); | ||
| 2702 | } | 2953 | } |
| 2703 | const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | ||
| 2704 | return finishThenElseBlock( | ||
| 2705 | parent_gz, | ||
| 2706 | scope, | ||
| 2707 | rl, | ||
| 2708 | node, | ||
| 2709 | &loop_scope, | ||
| 2710 | &then_scope, | ||
| 2711 | &else_scope, | ||
| 2712 | condbr, | ||
| 2713 | cond, | ||
| 2714 | while_full.ast.then_expr, | ||
| 2715 | else_info.src, | ||
| 2716 | then_result, | ||
| 2717 | else_info.result, | ||
| 2718 | loop_block, | ||
| 2719 | cond_block, | ||
| 2720 | break_tag, | ||
| 2721 | ); | ||
| 2722 | } | 2954 | } |
| 2723 | 2955 | ||
| 2724 | fn forExpr( | 2956 | fn globalVarDecl( |
| 2725 | parent_gz: *GenZir, | 2957 | astgen: *AstGen, |
| 2958 | gz: *GenZir, | ||
| 2726 | scope: *Scope, | 2959 | scope: *Scope, |
| 2727 | rl: ResultLoc, | 2960 | wip_decls: *WipDecls, |
| 2728 | node: ast.Node.Index, | 2961 | node: ast.Node.Index, |
| 2729 | for_full: ast.full.While, | 2962 | var_decl: ast.full.VarDecl, |
| 2730 | ) InnerError!zir.Inst.Ref { | 2963 | ) InnerError!void { |
| 2731 | const mod = parent_gz.astgen.mod; | 2964 | const gpa = astgen.gpa; |
| 2732 | if (for_full.label_token) |label_token| { | 2965 | const tree = astgen.tree; |
| 2733 | try checkLabelRedefinition(mod, scope, label_token); | ||
| 2734 | } | ||
| 2735 | // Set up variables and constants. | ||
| 2736 | const is_inline = parent_gz.force_comptime or for_full.inline_token != null; | ||
| 2737 | const tree = parent_gz.tree(); | ||
| 2738 | const token_tags = tree.tokens.items(.tag); | 2966 | const token_tags = tree.tokens.items(.tag); |
| 2739 | 2967 | ||
| 2740 | const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr); | 2968 | const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; |
| 2741 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); | 2969 | // We do this at the beginning so that the instruction index marks the range start |
| 2970 | // of the top level declaration. | ||
| 2971 | const block_inst = try gz.addBlock(.block_inline, node); | ||
| 2742 | 2972 | ||
| 2743 | const index_ptr = blk: { | 2973 | const name_token = var_decl.ast.mut_token + 1; |
| 2744 | const index_ptr = try parent_gz.addUnNode(.alloc, .usize_type, node); | 2974 | const name_str_index = try astgen.identAsString(name_token); |
| 2745 | // initialize to zero | ||
| 2746 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); | ||
| 2747 | break :blk index_ptr; | ||
| 2748 | }; | ||
| 2749 | 2975 | ||
| 2750 | const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop; | 2976 | try astgen.declareNewName(scope, name_str_index, node); |
| 2751 | const loop_block = try parent_gz.addBlock(loop_tag, node); | ||
| 2752 | try parent_gz.instructions.append(mod.gpa, loop_block); | ||
| 2753 | 2977 | ||
| 2754 | var loop_scope: GenZir = .{ | 2978 | var block_scope: GenZir = .{ |
| 2755 | .parent = scope, | 2979 | .parent = scope, |
| 2756 | .astgen = parent_gz.astgen, | 2980 | .decl_node_index = node, |
| 2757 | .force_comptime = parent_gz.force_comptime, | 2981 | .decl_line = gz.calcLine(node), |
| 2758 | .instructions = .{}, | 2982 | .astgen = astgen, |
| 2983 | .force_comptime = true, | ||
| 2984 | .anon_name_strategy = .parent, | ||
| 2759 | }; | 2985 | }; |
| 2760 | loop_scope.setBreakResultLoc(rl); | 2986 | defer block_scope.instructions.deinit(gpa); |
| 2761 | defer loop_scope.instructions.deinit(mod.gpa); | ||
| 2762 | 2987 | ||
| 2763 | var cond_scope: GenZir = .{ | 2988 | const is_pub = var_decl.visib_token != null; |
| 2764 | .parent = &loop_scope.base, | 2989 | const is_export = blk: { |
| 2765 | .astgen = parent_gz.astgen, | 2990 | const maybe_export_token = var_decl.extern_export_token orelse break :blk false; |
| 2766 | .force_comptime = loop_scope.force_comptime, | 2991 | break :blk token_tags[maybe_export_token] == .keyword_export; |
| 2767 | .instructions = .{}, | 2992 | }; |
| 2993 | const is_extern = blk: { | ||
| 2994 | const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; | ||
| 2995 | break :blk token_tags[maybe_extern_token] == .keyword_extern; | ||
| 2768 | }; | 2996 | }; |
| 2769 | defer cond_scope.instructions.deinit(mod.gpa); | 2997 | const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { |
| 2998 | break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); | ||
| 2999 | }; | ||
| 3000 | const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { | ||
| 3001 | break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); | ||
| 3002 | }; | ||
| 3003 | try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none); | ||
| 2770 | 3004 | ||
| 2771 | // check condition i < array_expr.len | 3005 | const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { |
| 2772 | const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); | 3006 | if (!is_mutable) { |
| 2773 | const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, zir.Inst.Bin{ | 3007 | return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); |
| 2774 | .lhs = index, | 3008 | } |
| 2775 | .rhs = len, | 3009 | break :blk true; |
| 2776 | }); | 3010 | } else false; |
| 3011 | |||
| 3012 | const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: { | ||
| 3013 | const lib_name_str = try astgen.strLitAsString(lib_name_token); | ||
| 3014 | break :blk lib_name_str.index; | ||
| 3015 | } else 0; | ||
| 3016 | |||
| 3017 | assert(var_decl.comptime_token == null); // handled by parser | ||
| 3018 | |||
| 3019 | const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { | ||
| 3020 | if (is_extern) { | ||
| 3021 | return astgen.failNode( | ||
| 3022 | var_decl.ast.init_node, | ||
| 3023 | "extern variables have no initializers", | ||
| 3024 | .{}, | ||
| 3025 | ); | ||
| 3026 | } | ||
| 2777 | 3027 | ||
| 2778 | const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; | 3028 | const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0) |
| 2779 | const condbr = try cond_scope.addCondBr(condbr_tag, node); | 3029 | try expr( |
| 2780 | const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block; | 3030 | &block_scope, |
| 2781 | const cond_block = try loop_scope.addBlock(block_tag, node); | 3031 | &block_scope.base, |
| 2782 | try loop_scope.instructions.append(mod.gpa, cond_block); | 3032 | .{ .ty = .type_type }, |
| 2783 | try cond_scope.setBlockBody(cond_block); | 3033 | var_decl.ast.type_node, |
| 2784 | 3034 | ) | |
| 2785 | // Increment the index variable. | 3035 | else |
| 2786 | const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); | 3036 | .none; |
| 2787 | const index_plus_one = try loop_scope.addPlNode(.add, node, zir.Inst.Bin{ | 3037 | |
| 2788 | .lhs = index_2, | 3038 | const init_inst = try expr( |
| 2789 | .rhs = .one_usize, | 3039 | &block_scope, |
| 2790 | }); | 3040 | &block_scope.base, |
| 2791 | _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); | 3041 | if (type_inst != .none) .{ .ty = type_inst } else .none, |
| 2792 | const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | 3042 | var_decl.ast.init_node, |
| 2793 | _ = try loop_scope.addNode(repeat_tag, node); | 3043 | ); |
| 2794 | 3044 | ||
| 2795 | try loop_scope.setBlockBody(loop_block); | 3045 | if (is_mutable) { |
| 2796 | loop_scope.break_block = loop_block; | 3046 | const var_inst = try block_scope.addVar(.{ |
| 2797 | loop_scope.continue_block = cond_block; | 3047 | .var_type = type_inst, |
| 2798 | if (for_full.label_token) |label_token| { | 3048 | .lib_name = 0, |
| 2799 | loop_scope.label = @as(?GenZir.Label, GenZir.Label{ | 3049 | .align_inst = .none, // passed via the decls data |
| 2800 | .token = label_token, | 3050 | .init = init_inst, |
| 2801 | .block_inst = loop_block, | 3051 | .is_extern = false, |
| 3052 | .is_threadlocal = is_threadlocal, | ||
| 3053 | }); | ||
| 3054 | break :vi var_inst; | ||
| 3055 | } else { | ||
| 3056 | break :vi init_inst; | ||
| 3057 | } | ||
| 3058 | } else if (!is_extern) { | ||
| 3059 | return astgen.failNode(node, "variables must be initialized", .{}); | ||
| 3060 | } else if (var_decl.ast.type_node != 0) vi: { | ||
| 3061 | // Extern variable which has an explicit type. | ||
| 3062 | const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); | ||
| 3063 | |||
| 3064 | const var_inst = try block_scope.addVar(.{ | ||
| 3065 | .var_type = type_inst, | ||
| 3066 | .lib_name = lib_name, | ||
| 3067 | .align_inst = .none, // passed via the decls data | ||
| 3068 | .init = .none, | ||
| 3069 | .is_extern = true, | ||
| 3070 | .is_threadlocal = is_threadlocal, | ||
| 2802 | }); | 3071 | }); |
| 2803 | } | 3072 | break :vi var_inst; |
| 2804 | 3073 | } else { | |
| 2805 | var then_scope: GenZir = .{ | 3074 | return astgen.failNode(node, "unable to infer variable type", .{}); |
| 2806 | .parent = &cond_scope.base, | ||
| 2807 | .astgen = parent_gz.astgen, | ||
| 2808 | .force_comptime = cond_scope.force_comptime, | ||
| 2809 | .instructions = .{}, | ||
| 2810 | }; | 3075 | }; |
| 2811 | defer then_scope.instructions.deinit(mod.gpa); | 3076 | // We do this at the end so that the instruction index marks the end |
| 3077 | // range of a top level declaration. | ||
| 3078 | _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); | ||
| 3079 | try block_scope.setBlockBody(block_inst); | ||
| 2812 | 3080 | ||
| 2813 | var index_scope: Scope.LocalPtr = undefined; | 3081 | try wip_decls.payload.ensureUnusedCapacity(gpa, 9); |
| 2814 | const then_sub_scope = blk: { | 3082 | { |
| 2815 | const payload_token = for_full.payload_token.?; | 3083 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); |
| 2816 | const ident = if (token_tags[payload_token] == .asterisk) | 3084 | const casted = @bitCast([4]u32, contents_hash); |
| 2817 | payload_token + 1 | 3085 | wip_decls.payload.appendSliceAssumeCapacity(&casted); |
| 2818 | else | 3086 | } |
| 2819 | payload_token; | 3087 | { |
| 2820 | const is_ptr = ident != payload_token; | 3088 | const line_delta = block_scope.decl_line - gz.decl_line; |
| 2821 | const value_name = tree.tokenSlice(ident); | 3089 | wip_decls.payload.appendAssumeCapacity(line_delta); |
| 2822 | if (!mem.eql(u8, value_name, "_")) { | 3090 | } |
| 2823 | return mod.failNode(&then_scope.base, ident, "TODO implement for loop value payload", .{}); | 3091 | wip_decls.payload.appendAssumeCapacity(name_str_index); |
| 2824 | } else if (is_ptr) { | 3092 | wip_decls.payload.appendAssumeCapacity(block_inst); |
| 2825 | return mod.failTok(&then_scope.base, payload_token, "pointer modifier invalid on discard", .{}); | 3093 | if (align_inst != .none) { |
| 2826 | } | 3094 | wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); |
| 3095 | } | ||
| 3096 | if (section_inst != .none) { | ||
| 3097 | wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); | ||
| 3098 | } | ||
| 3099 | } | ||
| 2827 | 3100 | ||
| 2828 | const index_token = if (token_tags[ident + 1] == .comma) | 3101 | fn comptimeDecl( |
| 2829 | ident + 2 | 3102 | astgen: *AstGen, |
| 2830 | else | 3103 | gz: *GenZir, |
| 2831 | break :blk &then_scope.base; | 3104 | scope: *Scope, |
| 2832 | if (mem.eql(u8, tree.tokenSlice(index_token), "_")) { | 3105 | wip_decls: *WipDecls, |
| 2833 | return mod.failTok(&then_scope.base, index_token, "discard of index capture; omit it instead", .{}); | 3106 | node: ast.Node.Index, |
| 2834 | } | 3107 | ) InnerError!void { |
| 2835 | const index_name = try mod.identifierTokenString(&then_scope.base, index_token); | 3108 | const gpa = astgen.gpa; |
| 2836 | index_scope = .{ | 3109 | const tree = astgen.tree; |
| 2837 | .parent = &then_scope.base, | 3110 | const node_datas = tree.nodes.items(.data); |
| 2838 | .gen_zir = &then_scope, | 3111 | const body_node = node_datas[node].lhs; |
| 2839 | .name = index_name, | ||
| 2840 | .ptr = index_ptr, | ||
| 2841 | .src = parent_gz.tokSrcLoc(index_token), | ||
| 2842 | }; | ||
| 2843 | break :blk &index_scope.base; | ||
| 2844 | }; | ||
| 2845 | 3112 | ||
| 2846 | loop_scope.break_count += 1; | 3113 | // Up top so the ZIR instruction index marks the start range of this |
| 2847 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); | 3114 | // top-level declaration. |
| 3115 | const block_inst = try gz.addBlock(.block_inline, node); | ||
| 3116 | try wip_decls.next(gpa, false, false, false, false); | ||
| 2848 | 3117 | ||
| 2849 | var else_scope: GenZir = .{ | 3118 | var decl_block: GenZir = .{ |
| 2850 | .parent = &cond_scope.base, | 3119 | .force_comptime = true, |
| 2851 | .astgen = parent_gz.astgen, | 3120 | .decl_node_index = node, |
| 2852 | .force_comptime = cond_scope.force_comptime, | 3121 | .decl_line = gz.calcLine(node), |
| 2853 | .instructions = .{}, | 3122 | .parent = scope, |
| 3123 | .astgen = astgen, | ||
| 2854 | }; | 3124 | }; |
| 2855 | defer else_scope.instructions.deinit(mod.gpa); | 3125 | defer decl_block.instructions.deinit(gpa); |
| 2856 | 3126 | ||
| 2857 | const else_node = for_full.ast.else_expr; | 3127 | const block_result = try expr(&decl_block, &decl_block.base, .none, body_node); |
| 2858 | const else_info: struct { | 3128 | if (decl_block.instructions.items.len == 0 or !decl_block.refIsNoReturn(block_result)) { |
| 2859 | src: ast.Node.Index, | 3129 | _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); |
| 2860 | result: zir.Inst.Ref, | 3130 | } |
| 2861 | } = if (else_node != 0) blk: { | 3131 | try decl_block.setBlockBody(block_inst); |
| 2862 | loop_scope.break_count += 1; | ||
| 2863 | const sub_scope = &else_scope.base; | ||
| 2864 | break :blk .{ | ||
| 2865 | .src = else_node, | ||
| 2866 | .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), | ||
| 2867 | }; | ||
| 2868 | } else .{ | ||
| 2869 | .src = for_full.ast.then_expr, | ||
| 2870 | .result = .none, | ||
| 2871 | }; | ||
| 2872 | 3132 | ||
| 2873 | if (loop_scope.label) |some| { | 3133 | try wip_decls.payload.ensureUnusedCapacity(gpa, 7); |
| 2874 | if (!some.used) { | 3134 | { |
| 2875 | return mod.failTok(scope, some.token, "unused for loop label", .{}); | 3135 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); |
| 2876 | } | 3136 | const casted = @bitCast([4]u32, contents_hash); |
| 3137 | wip_decls.payload.appendSliceAssumeCapacity(&casted); | ||
| 2877 | } | 3138 | } |
| 2878 | const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | 3139 | { |
| 2879 | return finishThenElseBlock( | 3140 | const line_delta = decl_block.decl_line - gz.decl_line; |
| 2880 | parent_gz, | 3141 | wip_decls.payload.appendAssumeCapacity(line_delta); |
| 2881 | scope, | 3142 | } |
| 2882 | rl, | 3143 | wip_decls.payload.appendAssumeCapacity(0); |
| 2883 | node, | 3144 | wip_decls.payload.appendAssumeCapacity(block_inst); |
| 2884 | &loop_scope, | ||
| 2885 | &then_scope, | ||
| 2886 | &else_scope, | ||
| 2887 | condbr, | ||
| 2888 | cond, | ||
| 2889 | for_full.ast.then_expr, | ||
| 2890 | else_info.src, | ||
| 2891 | then_result, | ||
| 2892 | else_info.result, | ||
| 2893 | loop_block, | ||
| 2894 | cond_block, | ||
| 2895 | break_tag, | ||
| 2896 | ); | ||
| 2897 | } | 3145 | } |
| 2898 | 3146 | ||
| 2899 | fn getRangeNode( | 3147 | fn usingnamespaceDecl( |
| 2900 | node_tags: []const ast.Node.Tag, | 3148 | astgen: *AstGen, |
| 2901 | node_datas: []const ast.Node.Data, | 3149 | gz: *GenZir, |
| 3150 | scope: *Scope, | ||
| 3151 | wip_decls: *WipDecls, | ||
| 2902 | node: ast.Node.Index, | 3152 | node: ast.Node.Index, |
| 2903 | ) ?ast.Node.Index { | 3153 | ) InnerError!void { |
| 2904 | switch (node_tags[node]) { | 3154 | const gpa = astgen.gpa; |
| 2905 | .switch_range => return node, | 3155 | const tree = astgen.tree; |
| 2906 | .grouped_expression => unreachable, | 3156 | const node_datas = tree.nodes.items(.data); |
| 2907 | else => return null, | 3157 | |
| 3158 | const type_expr = node_datas[node].lhs; | ||
| 3159 | const is_pub = blk: { | ||
| 3160 | const main_tokens = tree.nodes.items(.main_token); | ||
| 3161 | const token_tags = tree.tokens.items(.tag); | ||
| 3162 | const main_token = main_tokens[node]; | ||
| 3163 | break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub); | ||
| 3164 | }; | ||
| 3165 | // Up top so the ZIR instruction index marks the start range of this | ||
| 3166 | // top-level declaration. | ||
| 3167 | const block_inst = try gz.addBlock(.block_inline, node); | ||
| 3168 | try wip_decls.next(gpa, is_pub, true, false, false); | ||
| 3169 | |||
| 3170 | var decl_block: GenZir = .{ | ||
| 3171 | .force_comptime = true, | ||
| 3172 | .decl_node_index = node, | ||
| 3173 | .decl_line = gz.calcLine(node), | ||
| 3174 | .parent = scope, | ||
| 3175 | .astgen = astgen, | ||
| 3176 | }; | ||
| 3177 | defer decl_block.instructions.deinit(gpa); | ||
| 3178 | |||
| 3179 | const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); | ||
| 3180 | _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); | ||
| 3181 | try decl_block.setBlockBody(block_inst); | ||
| 3182 | |||
| 3183 | try wip_decls.payload.ensureUnusedCapacity(gpa, 7); | ||
| 3184 | { | ||
| 3185 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); | ||
| 3186 | const casted = @bitCast([4]u32, contents_hash); | ||
| 3187 | wip_decls.payload.appendSliceAssumeCapacity(&casted); | ||
| 3188 | } | ||
| 3189 | { | ||
| 3190 | const line_delta = decl_block.decl_line - gz.decl_line; | ||
| 3191 | wip_decls.payload.appendAssumeCapacity(line_delta); | ||
| 2908 | } | 3192 | } |
| 3193 | wip_decls.payload.appendAssumeCapacity(0); | ||
| 3194 | wip_decls.payload.appendAssumeCapacity(block_inst); | ||
| 2909 | } | 3195 | } |
| 2910 | 3196 | ||
| 2911 | pub const SwitchProngSrc = union(enum) { | 3197 | fn testDecl( |
| 2912 | scalar: u32, | 3198 | astgen: *AstGen, |
| 2913 | multi: Multi, | 3199 | gz: *GenZir, |
| 2914 | range: Multi, | 3200 | scope: *Scope, |
| 3201 | wip_decls: *WipDecls, | ||
| 3202 | node: ast.Node.Index, | ||
| 3203 | ) InnerError!void { | ||
| 3204 | const gpa = astgen.gpa; | ||
| 3205 | const tree = astgen.tree; | ||
| 3206 | const node_datas = tree.nodes.items(.data); | ||
| 3207 | const body_node = node_datas[node].rhs; | ||
| 3208 | |||
| 3209 | // Up top so the ZIR instruction index marks the start range of this | ||
| 3210 | // top-level declaration. | ||
| 3211 | const block_inst = try gz.addBlock(.block_inline, node); | ||
| 3212 | |||
| 3213 | try wip_decls.next(gpa, false, false, false, false); | ||
| 2915 | 3214 | ||
| 2916 | pub const Multi = struct { | 3215 | var decl_block: GenZir = .{ |
| 2917 | prong: u32, | 3216 | .force_comptime = true, |
| 2918 | item: u32, | 3217 | .decl_node_index = node, |
| 3218 | .decl_line = gz.calcLine(node), | ||
| 3219 | .parent = scope, | ||
| 3220 | .astgen = astgen, | ||
| 2919 | }; | 3221 | }; |
| 3222 | defer decl_block.instructions.deinit(gpa); | ||
| 2920 | 3223 | ||
| 2921 | pub const RangeExpand = enum { none, first, last }; | 3224 | const test_name: u32 = blk: { |
| 2922 | |||
| 2923 | /// This function is intended to be called only when it is certain that we need | ||
| 2924 | /// the LazySrcLoc in order to emit a compile error. | ||
| 2925 | pub fn resolve( | ||
| 2926 | prong_src: SwitchProngSrc, | ||
| 2927 | decl: *Decl, | ||
| 2928 | switch_node_offset: i32, | ||
| 2929 | range_expand: RangeExpand, | ||
| 2930 | ) LazySrcLoc { | ||
| 2931 | @setCold(true); | ||
| 2932 | const switch_node = decl.relativeToNodeIndex(switch_node_offset); | ||
| 2933 | const tree = decl.container.file_scope.base.tree(); | ||
| 2934 | const main_tokens = tree.nodes.items(.main_token); | 3225 | const main_tokens = tree.nodes.items(.main_token); |
| 2935 | const node_datas = tree.nodes.items(.data); | 3226 | const token_tags = tree.tokens.items(.tag); |
| 2936 | const node_tags = tree.nodes.items(.tag); | 3227 | const test_token = main_tokens[node]; |
| 2937 | const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); | 3228 | const str_lit_token = test_token + 1; |
| 2938 | const case_nodes = tree.extra_data[extra.start..extra.end]; | 3229 | if (token_tags[str_lit_token] == .string_literal) { |
| 2939 | 3230 | break :blk try astgen.testNameString(str_lit_token); | |
| 2940 | var multi_i: u32 = 0; | 3231 | } |
| 2941 | var scalar_i: u32 = 0; | 3232 | // String table index 1 has a special meaning here of test decl with no name. |
| 2942 | for (case_nodes) |case_node| { | 3233 | break :blk 1; |
| 2943 | const case = switch (node_tags[case_node]) { | 3234 | }; |
| 2944 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 2945 | .switch_case => tree.switchCase(case_node), | ||
| 2946 | else => unreachable, | ||
| 2947 | }; | ||
| 2948 | if (case.ast.values.len == 0) | ||
| 2949 | continue; | ||
| 2950 | if (case.ast.values.len == 1 and | ||
| 2951 | node_tags[case.ast.values[0]] == .identifier and | ||
| 2952 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) | ||
| 2953 | { | ||
| 2954 | continue; | ||
| 2955 | } | ||
| 2956 | const is_multi = case.ast.values.len != 1 or | ||
| 2957 | getRangeNode(node_tags, node_datas, case.ast.values[0]) != null; | ||
| 2958 | 3235 | ||
| 2959 | switch (prong_src) { | 3236 | var fn_block: GenZir = .{ |
| 2960 | .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc{ | 3237 | .force_comptime = false, |
| 2961 | .node_offset = decl.nodeIndexToRelative(case.ast.values[0]), | 3238 | .decl_node_index = node, |
| 2962 | }, | 3239 | .decl_line = decl_block.decl_line, |
| 2963 | .multi => |s| if (is_multi and s.prong == multi_i) { | 3240 | .parent = &decl_block.base, |
| 2964 | var item_i: u32 = 0; | 3241 | .astgen = astgen, |
| 2965 | for (case.ast.values) |item_node| { | 3242 | }; |
| 2966 | if (getRangeNode(node_tags, node_datas, item_node) != null) | 3243 | defer fn_block.instructions.deinit(gpa); |
| 2967 | continue; | ||
| 2968 | 3244 | ||
| 2969 | if (item_i == s.item) return LazySrcLoc{ | 3245 | const prev_fn_block = astgen.fn_block; |
| 2970 | .node_offset = decl.nodeIndexToRelative(item_node), | 3246 | astgen.fn_block = &fn_block; |
| 2971 | }; | 3247 | |
| 2972 | item_i += 1; | 3248 | const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); |
| 2973 | } else unreachable; | 3249 | if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) { |
| 2974 | }, | 3250 | // Since we are adding the return instruction here, we must handle the coercion. |
| 2975 | .range => |s| if (is_multi and s.prong == multi_i) { | 3251 | // We do this by using the `ret_coerce` instruction. |
| 2976 | var range_i: u32 = 0; | 3252 | _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); |
| 2977 | for (case.ast.values) |item_node| { | ||
| 2978 | const range = getRangeNode(node_tags, node_datas, item_node) orelse continue; | ||
| 2979 | |||
| 2980 | if (range_i == s.item) switch (range_expand) { | ||
| 2981 | .none => return LazySrcLoc{ | ||
| 2982 | .node_offset = decl.nodeIndexToRelative(item_node), | ||
| 2983 | }, | ||
| 2984 | .first => return LazySrcLoc{ | ||
| 2985 | .node_offset = decl.nodeIndexToRelative(node_datas[range].lhs), | ||
| 2986 | }, | ||
| 2987 | .last => return LazySrcLoc{ | ||
| 2988 | .node_offset = decl.nodeIndexToRelative(node_datas[range].rhs), | ||
| 2989 | }, | ||
| 2990 | }; | ||
| 2991 | range_i += 1; | ||
| 2992 | } else unreachable; | ||
| 2993 | }, | ||
| 2994 | } | ||
| 2995 | if (is_multi) { | ||
| 2996 | multi_i += 1; | ||
| 2997 | } else { | ||
| 2998 | scalar_i += 1; | ||
| 2999 | } | ||
| 3000 | } else unreachable; | ||
| 3001 | } | 3253 | } |
| 3002 | }; | ||
| 3003 | 3254 | ||
| 3004 | fn switchExpr( | 3255 | astgen.fn_block = prev_fn_block; |
| 3005 | parent_gz: *GenZir, | 3256 | |
| 3006 | scope: *Scope, | 3257 | const func_inst = try decl_block.addFunc(.{ |
| 3007 | rl: ResultLoc, | 3258 | .src_node = node, |
| 3008 | switch_node: ast.Node.Index, | 3259 | .ret_ty = .void_type, |
| 3009 | ) InnerError!zir.Inst.Ref { | 3260 | .param_types = &[0]Zir.Inst.Ref{}, |
| 3010 | const astgen = parent_gz.astgen; | 3261 | .body = fn_block.instructions.items, |
| 3011 | const mod = astgen.mod; | 3262 | .cc = .none, |
| 3012 | const gpa = mod.gpa; | 3263 | .align_inst = .none, |
| 3013 | const tree = parent_gz.tree(); | 3264 | .lib_name = 0, |
| 3014 | const node_datas = tree.nodes.items(.data); | 3265 | .is_var_args = false, |
| 3015 | const node_tags = tree.nodes.items(.tag); | 3266 | .is_inferred_error = true, |
| 3016 | const main_tokens = tree.nodes.items(.main_token); | 3267 | .is_test = true, |
| 3017 | const token_tags = tree.tokens.items(.tag); | 3268 | .is_extern = false, |
| 3018 | const operand_node = node_datas[switch_node].lhs; | 3269 | }); |
| 3019 | const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); | ||
| 3020 | const case_nodes = tree.extra_data[extra.start..extra.end]; | ||
| 3021 | 3270 | ||
| 3022 | // We perform two passes over the AST. This first pass is to collect information | 3271 | _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); |
| 3023 | // for the following variables, make note of the special prong AST node index, | 3272 | try decl_block.setBlockBody(block_inst); |
| 3024 | // and bail out with a compile error if there are multiple special prongs present. | ||
| 3025 | var any_payload_is_ref = false; | ||
| 3026 | var scalar_cases_len: u32 = 0; | ||
| 3027 | var multi_cases_len: u32 = 0; | ||
| 3028 | var special_prong: zir.SpecialProng = .none; | ||
| 3029 | var special_node: ast.Node.Index = 0; | ||
| 3030 | var else_src: ?LazySrcLoc = null; | ||
| 3031 | var underscore_src: ?LazySrcLoc = null; | ||
| 3032 | for (case_nodes) |case_node| { | ||
| 3033 | const case = switch (node_tags[case_node]) { | ||
| 3034 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 3035 | .switch_case => tree.switchCase(case_node), | ||
| 3036 | else => unreachable, | ||
| 3037 | }; | ||
| 3038 | if (case.payload_token) |payload_token| { | ||
| 3039 | if (token_tags[payload_token] == .asterisk) { | ||
| 3040 | any_payload_is_ref = true; | ||
| 3041 | } | ||
| 3042 | } | ||
| 3043 | // Check for else/`_` prong. | ||
| 3044 | if (case.ast.values.len == 0) { | ||
| 3045 | const case_src = parent_gz.tokSrcLoc(case.ast.arrow_token - 1); | ||
| 3046 | if (else_src) |src| { | ||
| 3047 | const msg = msg: { | ||
| 3048 | const msg = try mod.errMsg( | ||
| 3049 | scope, | ||
| 3050 | case_src, | ||
| 3051 | "multiple else prongs in switch expression", | ||
| 3052 | .{}, | ||
| 3053 | ); | ||
| 3054 | errdefer msg.destroy(gpa); | ||
| 3055 | try mod.errNote(scope, src, msg, "previous else prong is here", .{}); | ||
| 3056 | break :msg msg; | ||
| 3057 | }; | ||
| 3058 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 3059 | } else if (underscore_src) |some_underscore| { | ||
| 3060 | const msg = msg: { | ||
| 3061 | const msg = try mod.errMsg( | ||
| 3062 | scope, | ||
| 3063 | parent_gz.nodeSrcLoc(switch_node), | ||
| 3064 | "else and '_' prong in switch expression", | ||
| 3065 | .{}, | ||
| 3066 | ); | ||
| 3067 | errdefer msg.destroy(gpa); | ||
| 3068 | try mod.errNote(scope, case_src, msg, "else prong is here", .{}); | ||
| 3069 | try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{}); | ||
| 3070 | break :msg msg; | ||
| 3071 | }; | ||
| 3072 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 3073 | } | ||
| 3074 | special_node = case_node; | ||
| 3075 | special_prong = .@"else"; | ||
| 3076 | else_src = case_src; | ||
| 3077 | continue; | ||
| 3078 | } else if (case.ast.values.len == 1 and | ||
| 3079 | node_tags[case.ast.values[0]] == .identifier and | ||
| 3080 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) | ||
| 3081 | { | ||
| 3082 | const case_src = parent_gz.tokSrcLoc(case.ast.arrow_token - 1); | ||
| 3083 | if (underscore_src) |src| { | ||
| 3084 | const msg = msg: { | ||
| 3085 | const msg = try mod.errMsg( | ||
| 3086 | scope, | ||
| 3087 | case_src, | ||
| 3088 | "multiple '_' prongs in switch expression", | ||
| 3089 | .{}, | ||
| 3090 | ); | ||
| 3091 | errdefer msg.destroy(gpa); | ||
| 3092 | try mod.errNote(scope, src, msg, "previous '_' prong is here", .{}); | ||
| 3093 | break :msg msg; | ||
| 3094 | }; | ||
| 3095 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 3096 | } else if (else_src) |some_else| { | ||
| 3097 | const msg = msg: { | ||
| 3098 | const msg = try mod.errMsg( | ||
| 3099 | scope, | ||
| 3100 | parent_gz.nodeSrcLoc(switch_node), | ||
| 3101 | "else and '_' prong in switch expression", | ||
| 3102 | .{}, | ||
| 3103 | ); | ||
| 3104 | errdefer msg.destroy(gpa); | ||
| 3105 | try mod.errNote(scope, some_else, msg, "else prong is here", .{}); | ||
| 3106 | try mod.errNote(scope, case_src, msg, "'_' prong is here", .{}); | ||
| 3107 | break :msg msg; | ||
| 3108 | }; | ||
| 3109 | return mod.failWithOwnedErrorMsg(scope, msg); | ||
| 3110 | } | ||
| 3111 | special_node = case_node; | ||
| 3112 | special_prong = .under; | ||
| 3113 | underscore_src = case_src; | ||
| 3114 | continue; | ||
| 3115 | } | ||
| 3116 | 3273 | ||
| 3117 | if (case.ast.values.len == 1 and | 3274 | try wip_decls.payload.ensureUnusedCapacity(gpa, 7); |
| 3118 | getRangeNode(node_tags, node_datas, case.ast.values[0]) == null) | 3275 | { |
| 3119 | { | 3276 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); |
| 3120 | scalar_cases_len += 1; | 3277 | const casted = @bitCast([4]u32, contents_hash); |
| 3121 | } else { | 3278 | wip_decls.payload.appendSliceAssumeCapacity(&casted); |
| 3122 | multi_cases_len += 1; | ||
| 3123 | } | ||
| 3124 | } | 3279 | } |
| 3280 | { | ||
| 3281 | const line_delta = decl_block.decl_line - gz.decl_line; | ||
| 3282 | wip_decls.payload.appendAssumeCapacity(line_delta); | ||
| 3283 | } | ||
| 3284 | wip_decls.payload.appendAssumeCapacity(test_name); | ||
| 3285 | wip_decls.payload.appendAssumeCapacity(block_inst); | ||
| 3286 | } | ||
| 3125 | 3287 | ||
| 3126 | const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; | 3288 | fn structDeclInner( |
| 3127 | const operand = try expr(parent_gz, scope, operand_rl, operand_node); | 3289 | gz: *GenZir, |
| 3128 | // We need the type of the operand to use as the result location for all the prong items. | 3290 | scope: *Scope, |
| 3129 | const typeof_tag: zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof; | 3291 | node: ast.Node.Index, |
| 3130 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); | 3292 | container_decl: ast.full.ContainerDecl, |
| 3131 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; | 3293 | layout: std.builtin.TypeInfo.ContainerLayout, |
| 3294 | ) InnerError!Zir.Inst.Ref { | ||
| 3295 | if (container_decl.ast.members.len == 0) { | ||
| 3296 | const decl_inst = try gz.reserveInstructionIndex(); | ||
| 3297 | try gz.setStruct(decl_inst, .{ | ||
| 3298 | .src_node = node, | ||
| 3299 | .layout = layout, | ||
| 3300 | .fields_len = 0, | ||
| 3301 | .body_len = 0, | ||
| 3302 | .decls_len = 0, | ||
| 3303 | }); | ||
| 3304 | return gz.indexToRef(decl_inst); | ||
| 3305 | } | ||
| 3132 | 3306 | ||
| 3133 | // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. | 3307 | const astgen = gz.astgen; |
| 3134 | // This is the header as well as the optional else prong body, as well as all the | 3308 | const gpa = astgen.gpa; |
| 3135 | // scalar cases. | 3309 | const tree = astgen.tree; |
| 3136 | // At the end we will memcpy this into place. | 3310 | const node_tags = tree.nodes.items(.tag); |
| 3137 | var scalar_cases_payload = ArrayListUnmanaged(u32){}; | 3311 | const node_datas = tree.nodes.items(.data); |
| 3138 | defer scalar_cases_payload.deinit(gpa); | ||
| 3139 | // Same deal, but this is only the `extra` data for the multi cases. | ||
| 3140 | var multi_cases_payload = ArrayListUnmanaged(u32){}; | ||
| 3141 | defer multi_cases_payload.deinit(gpa); | ||
| 3142 | 3312 | ||
| 3313 | // The struct_decl instruction introduces a scope in which the decls of the struct | ||
| 3314 | // are in scope, so that field types, alignments, and default value expressions | ||
| 3315 | // can refer to decls within the struct itself. | ||
| 3143 | var block_scope: GenZir = .{ | 3316 | var block_scope: GenZir = .{ |
| 3144 | .parent = scope, | 3317 | .parent = scope, |
| 3318 | .decl_node_index = node, | ||
| 3319 | .decl_line = gz.calcLine(node), | ||
| 3145 | .astgen = astgen, | 3320 | .astgen = astgen, |
| 3146 | .force_comptime = parent_gz.force_comptime, | 3321 | .force_comptime = true, |
| 3147 | .instructions = .{}, | 3322 | .ref_start_index = gz.ref_start_index, |
| 3148 | }; | 3323 | }; |
| 3149 | block_scope.setBreakResultLoc(rl); | ||
| 3150 | defer block_scope.instructions.deinit(gpa); | 3324 | defer block_scope.instructions.deinit(gpa); |
| 3151 | 3325 | ||
| 3152 | // This gets added to the parent block later, after the item expressions. | 3326 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; |
| 3153 | const switch_block = try parent_gz.addBlock(undefined, switch_node); | 3327 | defer namespace.decls.deinit(gpa); |
| 3154 | 3328 | ||
| 3155 | // We re-use this same scope for all cases, including the special prong, if any. | 3329 | var wip_decls: WipDecls = .{}; |
| 3156 | var case_scope: GenZir = .{ | 3330 | defer wip_decls.deinit(gpa); |
| 3157 | .parent = &block_scope.base, | 3331 | |
| 3158 | .astgen = astgen, | 3332 | // We don't know which members are fields until we iterate, so cannot do |
| 3159 | .force_comptime = parent_gz.force_comptime, | 3333 | // an accurate ensureCapacity yet. |
| 3160 | .instructions = .{}, | 3334 | var fields_data = ArrayListUnmanaged(u32){}; |
| 3161 | }; | 3335 | defer fields_data.deinit(gpa); |
| 3162 | defer case_scope.instructions.deinit(gpa); | 3336 | |
| 3163 | 3337 | const bits_per_field = 4; | |
| 3164 | // Do the else/`_` first because it goes first in the payload. | 3338 | const fields_per_u32 = 32 / bits_per_field; |
| 3165 | var capture_val_scope: Scope.LocalVal = undefined; | 3339 | // We only need this if there are greater than fields_per_u32 fields. |
| 3166 | if (special_node != 0) { | 3340 | var bit_bag = ArrayListUnmanaged(u32){}; |
| 3167 | const case = switch (node_tags[special_node]) { | 3341 | defer bit_bag.deinit(gpa); |
| 3168 | .switch_case_one => tree.switchCaseOne(special_node), | 3342 | |
| 3169 | .switch_case => tree.switchCase(special_node), | 3343 | var cur_bit_bag: u32 = 0; |
| 3170 | else => unreachable, | 3344 | var field_index: usize = 0; |
| 3171 | }; | 3345 | for (container_decl.ast.members) |member_node| { |
| 3172 | const sub_scope = blk: { | 3346 | const member = switch (node_tags[member_node]) { |
| 3173 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | 3347 | .container_field_init => tree.containerFieldInit(member_node), |
| 3174 | const ident = if (token_tags[payload_token] == .asterisk) | 3348 | .container_field_align => tree.containerFieldAlign(member_node), |
| 3175 | payload_token + 1 | 3349 | .container_field => tree.containerField(member_node), |
| 3176 | else | 3350 | |
| 3177 | payload_token; | 3351 | .fn_decl => { |
| 3178 | const is_ptr = ident != payload_token; | 3352 | const fn_proto = node_datas[member_node].lhs; |
| 3179 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | 3353 | const body = node_datas[member_node].rhs; |
| 3180 | if (is_ptr) { | 3354 | switch (node_tags[fn_proto]) { |
| 3181 | return mod.failTok(&case_scope.base, payload_token, "pointer modifier invalid on discard", .{}); | 3355 | .fn_proto_simple => { |
| 3356 | var params: [1]ast.Node.Index = undefined; | ||
| 3357 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) { | ||
| 3358 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3359 | error.AnalysisFail => {}, | ||
| 3360 | }; | ||
| 3361 | continue; | ||
| 3362 | }, | ||
| 3363 | .fn_proto_multi => { | ||
| 3364 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { | ||
| 3365 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3366 | error.AnalysisFail => {}, | ||
| 3367 | }; | ||
| 3368 | continue; | ||
| 3369 | }, | ||
| 3370 | .fn_proto_one => { | ||
| 3371 | var params: [1]ast.Node.Index = undefined; | ||
| 3372 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) { | ||
| 3373 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3374 | error.AnalysisFail => {}, | ||
| 3375 | }; | ||
| 3376 | continue; | ||
| 3377 | }, | ||
| 3378 | .fn_proto => { | ||
| 3379 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { | ||
| 3380 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3381 | error.AnalysisFail => {}, | ||
| 3382 | }; | ||
| 3383 | continue; | ||
| 3384 | }, | ||
| 3385 | else => unreachable, | ||
| 3182 | } | 3386 | } |
| 3183 | break :blk &case_scope.base; | 3387 | }, |
| 3184 | } | 3388 | .fn_proto_simple => { |
| 3185 | const capture_tag: zir.Inst.Tag = if (is_ptr) | 3389 | var params: [1]ast.Node.Index = undefined; |
| 3186 | .switch_capture_else_ref | 3390 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) { |
| 3187 | else | 3391 | error.OutOfMemory => return error.OutOfMemory, |
| 3188 | .switch_capture_else; | 3392 | error.AnalysisFail => {}, |
| 3189 | const capture = try case_scope.add(.{ | 3393 | }; |
| 3190 | .tag = capture_tag, | 3394 | continue; |
| 3191 | .data = .{ .switch_capture = .{ | 3395 | }, |
| 3192 | .switch_inst = switch_block, | 3396 | .fn_proto_multi => { |
| 3193 | .prong_index = undefined, | 3397 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { |
| 3194 | } }, | 3398 | error.OutOfMemory => return error.OutOfMemory, |
| 3195 | }); | 3399 | error.AnalysisFail => {}, |
| 3196 | const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token); | 3400 | }; |
| 3197 | capture_val_scope = .{ | 3401 | continue; |
| 3198 | .parent = &case_scope.base, | 3402 | }, |
| 3199 | .gen_zir = &case_scope, | 3403 | .fn_proto_one => { |
| 3200 | .name = capture_name, | 3404 | var params: [1]ast.Node.Index = undefined; |
| 3201 | .inst = capture, | 3405 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) { |
| 3202 | .src = parent_gz.tokSrcLoc(payload_token), | 3406 | error.OutOfMemory => return error.OutOfMemory, |
| 3203 | }; | 3407 | error.AnalysisFail => {}, |
| 3204 | break :blk &capture_val_scope.base; | 3408 | }; |
| 3409 | continue; | ||
| 3410 | }, | ||
| 3411 | .fn_proto => { | ||
| 3412 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { | ||
| 3413 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3414 | error.AnalysisFail => {}, | ||
| 3415 | }; | ||
| 3416 | continue; | ||
| 3417 | }, | ||
| 3418 | |||
| 3419 | .global_var_decl => { | ||
| 3420 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { | ||
| 3421 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3422 | error.AnalysisFail => {}, | ||
| 3423 | }; | ||
| 3424 | continue; | ||
| 3425 | }, | ||
| 3426 | .local_var_decl => { | ||
| 3427 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { | ||
| 3428 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3429 | error.AnalysisFail => {}, | ||
| 3430 | }; | ||
| 3431 | continue; | ||
| 3432 | }, | ||
| 3433 | .simple_var_decl => { | ||
| 3434 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { | ||
| 3435 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3436 | error.AnalysisFail => {}, | ||
| 3437 | }; | ||
| 3438 | continue; | ||
| 3439 | }, | ||
| 3440 | .aligned_var_decl => { | ||
| 3441 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { | ||
| 3442 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3443 | error.AnalysisFail => {}, | ||
| 3444 | }; | ||
| 3445 | continue; | ||
| 3446 | }, | ||
| 3447 | |||
| 3448 | .@"comptime" => { | ||
| 3449 | astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3450 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3451 | error.AnalysisFail => {}, | ||
| 3452 | }; | ||
| 3453 | continue; | ||
| 3454 | }, | ||
| 3455 | .@"usingnamespace" => { | ||
| 3456 | astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3457 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3458 | error.AnalysisFail => {}, | ||
| 3459 | }; | ||
| 3460 | continue; | ||
| 3461 | }, | ||
| 3462 | .test_decl => { | ||
| 3463 | astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3464 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3465 | error.AnalysisFail => {}, | ||
| 3466 | }; | ||
| 3467 | continue; | ||
| 3468 | }, | ||
| 3469 | else => unreachable, | ||
| 3205 | }; | 3470 | }; |
| 3206 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 3471 | if (field_index % fields_per_u32 == 0 and field_index != 0) { |
| 3207 | if (!astgen.refIsNoReturn(case_result)) { | 3472 | try bit_bag.append(gpa, cur_bit_bag); |
| 3208 | block_scope.break_count += 1; | 3473 | cur_bit_bag = 0; |
| 3209 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | ||
| 3210 | } | 3474 | } |
| 3211 | // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`. | 3475 | try fields_data.ensureUnusedCapacity(gpa, 4); |
| 3212 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | 3476 | |
| 3213 | 3 + // operand, scalar_cases_len, else body len | 3477 | const field_name = try astgen.identAsString(member.ast.name_token); |
| 3214 | @boolToInt(multi_cases_len != 0) + | 3478 | fields_data.appendAssumeCapacity(field_name); |
| 3215 | case_scope.instructions.items.len); | 3479 | |
| 3216 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | 3480 | const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype") |
| 3217 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | 3481 | .none |
| 3218 | if (multi_cases_len != 0) { | 3482 | else |
| 3219 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | 3483 | try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr); |
| 3484 | fields_data.appendAssumeCapacity(@enumToInt(field_type)); | ||
| 3485 | |||
| 3486 | const have_align = member.ast.align_expr != 0; | ||
| 3487 | const have_value = member.ast.value_expr != 0; | ||
| 3488 | const is_comptime = member.comptime_token != null; | ||
| 3489 | const unused = false; | ||
| 3490 | cur_bit_bag = (cur_bit_bag >> bits_per_field) | | ||
| 3491 | (@as(u32, @boolToInt(have_align)) << 28) | | ||
| 3492 | (@as(u32, @boolToInt(have_value)) << 29) | | ||
| 3493 | (@as(u32, @boolToInt(is_comptime)) << 30) | | ||
| 3494 | (@as(u32, @boolToInt(unused)) << 31); | ||
| 3495 | |||
| 3496 | if (have_align) { | ||
| 3497 | const align_inst = try expr(&block_scope, &block_scope.base, align_rl, member.ast.align_expr); | ||
| 3498 | fields_data.appendAssumeCapacity(@enumToInt(align_inst)); | ||
| 3220 | } | 3499 | } |
| 3221 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | 3500 | if (have_value) { |
| 3222 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | 3501 | const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type }; |
| 3223 | } else { | 3502 | |
| 3224 | // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`. | 3503 | const default_inst = try expr(&block_scope, &block_scope.base, rl, member.ast.value_expr); |
| 3225 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | 3504 | fields_data.appendAssumeCapacity(@enumToInt(default_inst)); |
| 3226 | 2 + // operand, scalar_cases_len | 3505 | } else if (member.comptime_token) |comptime_token| { |
| 3227 | @boolToInt(multi_cases_len != 0)); | 3506 | return astgen.failTok(comptime_token, "comptime field without default initialization value", .{}); |
| 3228 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | 3507 | } |
| 3229 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | 3508 | |
| 3230 | if (multi_cases_len != 0) { | 3509 | field_index += 1; |
| 3231 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | 3510 | } |
| 3511 | { | ||
| 3512 | const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32); | ||
| 3513 | if (empty_slot_count < fields_per_u32) { | ||
| 3514 | cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field); | ||
| 3515 | } | ||
| 3516 | } | ||
| 3517 | { | ||
| 3518 | const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); | ||
| 3519 | if (empty_slot_count < WipDecls.fields_per_u32) { | ||
| 3520 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); | ||
| 3232 | } | 3521 | } |
| 3233 | } | 3522 | } |
| 3234 | 3523 | ||
| 3235 | // In this pass we generate all the item and prong expressions except the special case. | 3524 | const decl_inst = try gz.reserveInstructionIndex(); |
| 3236 | var multi_case_index: u32 = 0; | 3525 | if (block_scope.instructions.items.len != 0) { |
| 3237 | var scalar_case_index: u32 = 0; | 3526 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 3238 | for (case_nodes) |case_node| { | 3527 | } |
| 3239 | if (case_node == special_node) | ||
| 3240 | continue; | ||
| 3241 | const case = switch (node_tags[case_node]) { | ||
| 3242 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 3243 | .switch_case => tree.switchCase(case_node), | ||
| 3244 | else => unreachable, | ||
| 3245 | }; | ||
| 3246 | 3528 | ||
| 3247 | // Reset the scope. | 3529 | try gz.setStruct(decl_inst, .{ |
| 3248 | case_scope.instructions.shrinkRetainingCapacity(0); | 3530 | .src_node = node, |
| 3531 | .layout = layout, | ||
| 3532 | .body_len = @intCast(u32, block_scope.instructions.items.len), | ||
| 3533 | .fields_len = @intCast(u32, field_index), | ||
| 3534 | .decls_len = @intCast(u32, wip_decls.decl_index), | ||
| 3535 | }); | ||
| 3249 | 3536 | ||
| 3250 | const is_multi_case = case.ast.values.len != 1 or | 3537 | try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + |
| 3251 | getRangeNode(node_tags, node_datas, case.ast.values[0]) != null; | 3538 | @boolToInt(field_index != 0) + fields_data.items.len + |
| 3539 | block_scope.instructions.items.len + | ||
| 3540 | wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + | ||
| 3541 | wip_decls.payload.items.len); | ||
| 3542 | astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. | ||
| 3543 | if (wip_decls.decl_index != 0) { | ||
| 3544 | astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); | ||
| 3545 | } | ||
| 3546 | astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); | ||
| 3252 | 3547 | ||
| 3253 | const sub_scope = blk: { | 3548 | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 3254 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | ||
| 3255 | const ident = if (token_tags[payload_token] == .asterisk) | ||
| 3256 | payload_token + 1 | ||
| 3257 | else | ||
| 3258 | payload_token; | ||
| 3259 | const is_ptr = ident != payload_token; | ||
| 3260 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | ||
| 3261 | if (is_ptr) { | ||
| 3262 | return mod.failTok(&case_scope.base, payload_token, "pointer modifier invalid on discard", .{}); | ||
| 3263 | } | ||
| 3264 | break :blk &case_scope.base; | ||
| 3265 | } | ||
| 3266 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | ||
| 3267 | const is_ptr_bits: u2 = @boolToInt(is_ptr); | ||
| 3268 | const capture_tag: zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { | ||
| 3269 | 0b00 => .switch_capture, | ||
| 3270 | 0b01 => .switch_capture_ref, | ||
| 3271 | 0b10 => .switch_capture_multi, | ||
| 3272 | 0b11 => .switch_capture_multi_ref, | ||
| 3273 | }; | ||
| 3274 | const capture_index = if (is_multi_case) ci: { | ||
| 3275 | multi_case_index += 1; | ||
| 3276 | break :ci multi_case_index - 1; | ||
| 3277 | } else ci: { | ||
| 3278 | scalar_case_index += 1; | ||
| 3279 | break :ci scalar_case_index - 1; | ||
| 3280 | }; | ||
| 3281 | const capture = try case_scope.add(.{ | ||
| 3282 | .tag = capture_tag, | ||
| 3283 | .data = .{ .switch_capture = .{ | ||
| 3284 | .switch_inst = switch_block, | ||
| 3285 | .prong_index = capture_index, | ||
| 3286 | } }, | ||
| 3287 | }); | ||
| 3288 | const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token); | ||
| 3289 | capture_val_scope = .{ | ||
| 3290 | .parent = &case_scope.base, | ||
| 3291 | .gen_zir = &case_scope, | ||
| 3292 | .name = capture_name, | ||
| 3293 | .inst = capture, | ||
| 3294 | .src = parent_gz.tokSrcLoc(payload_token), | ||
| 3295 | }; | ||
| 3296 | break :blk &capture_val_scope.base; | ||
| 3297 | }; | ||
| 3298 | 3549 | ||
| 3299 | if (is_multi_case) { | 3550 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. |
| 3300 | // items_len, ranges_len, body_len | 3551 | if (field_index != 0) { |
| 3301 | const header_index = multi_cases_payload.items.len; | 3552 | astgen.extra.appendAssumeCapacity(cur_bit_bag); |
| 3302 | try multi_cases_payload.resize(gpa, multi_cases_payload.items.len + 3); | 3553 | } |
| 3554 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); | ||
| 3303 | 3555 | ||
| 3304 | // items | 3556 | return gz.indexToRef(decl_inst); |
| 3305 | var items_len: u32 = 0; | 3557 | } |
| 3306 | for (case.ast.values) |item_node| { | ||
| 3307 | if (getRangeNode(node_tags, node_datas, item_node) != null) continue; | ||
| 3308 | items_len += 1; | ||
| 3309 | 3558 | ||
| 3310 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | 3559 | fn unionDeclInner( |
| 3311 | try multi_cases_payload.append(gpa, @enumToInt(item_inst)); | 3560 | gz: *GenZir, |
| 3312 | } | 3561 | scope: *Scope, |
| 3562 | node: ast.Node.Index, | ||
| 3563 | members: []const ast.Node.Index, | ||
| 3564 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 3565 | arg_inst: Zir.Inst.Ref, | ||
| 3566 | have_auto_enum: bool, | ||
| 3567 | ) InnerError!Zir.Inst.Ref { | ||
| 3568 | const astgen = gz.astgen; | ||
| 3569 | const gpa = astgen.gpa; | ||
| 3570 | const tree = astgen.tree; | ||
| 3571 | const node_tags = tree.nodes.items(.tag); | ||
| 3572 | const node_datas = tree.nodes.items(.data); | ||
| 3313 | 3573 | ||
| 3314 | // ranges | 3574 | // The union_decl instruction introduces a scope in which the decls of the union |
| 3315 | var ranges_len: u32 = 0; | 3575 | // are in scope, so that field types, alignments, and default value expressions |
| 3316 | for (case.ast.values) |item_node| { | 3576 | // can refer to decls within the union itself. |
| 3317 | const range = getRangeNode(node_tags, node_datas, item_node) orelse continue; | 3577 | var block_scope: GenZir = .{ |
| 3318 | ranges_len += 1; | 3578 | .parent = scope, |
| 3579 | .decl_node_index = node, | ||
| 3580 | .decl_line = gz.calcLine(node), | ||
| 3581 | .astgen = astgen, | ||
| 3582 | .force_comptime = true, | ||
| 3583 | .ref_start_index = gz.ref_start_index, | ||
| 3584 | }; | ||
| 3585 | defer block_scope.instructions.deinit(gpa); | ||
| 3319 | 3586 | ||
| 3320 | const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); | 3587 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; |
| 3321 | const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs); | 3588 | defer namespace.decls.deinit(gpa); |
| 3322 | try multi_cases_payload.appendSlice(gpa, &[_]u32{ | 3589 | |
| 3323 | @enumToInt(first), @enumToInt(last), | 3590 | var wip_decls: WipDecls = .{}; |
| 3324 | }); | 3591 | defer wip_decls.deinit(gpa); |
| 3325 | } | 3592 | |
| 3593 | // We don't know which members are fields until we iterate, so cannot do | ||
| 3594 | // an accurate ensureCapacity yet. | ||
| 3595 | var fields_data = ArrayListUnmanaged(u32){}; | ||
| 3596 | defer fields_data.deinit(gpa); | ||
| 3597 | |||
| 3598 | const bits_per_field = 4; | ||
| 3599 | const fields_per_u32 = 32 / bits_per_field; | ||
| 3600 | // We only need this if there are greater than fields_per_u32 fields. | ||
| 3601 | var bit_bag = ArrayListUnmanaged(u32){}; | ||
| 3602 | defer bit_bag.deinit(gpa); | ||
| 3603 | |||
| 3604 | var cur_bit_bag: u32 = 0; | ||
| 3605 | var field_index: usize = 0; | ||
| 3606 | for (members) |member_node| { | ||
| 3607 | const member = switch (node_tags[member_node]) { | ||
| 3608 | .container_field_init => tree.containerFieldInit(member_node), | ||
| 3609 | .container_field_align => tree.containerFieldAlign(member_node), | ||
| 3610 | .container_field => tree.containerField(member_node), | ||
| 3611 | |||
| 3612 | .fn_decl => { | ||
| 3613 | const fn_proto = node_datas[member_node].lhs; | ||
| 3614 | const body = node_datas[member_node].rhs; | ||
| 3615 | switch (node_tags[fn_proto]) { | ||
| 3616 | .fn_proto_simple => { | ||
| 3617 | var params: [1]ast.Node.Index = undefined; | ||
| 3618 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) { | ||
| 3619 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3620 | error.AnalysisFail => {}, | ||
| 3621 | }; | ||
| 3622 | continue; | ||
| 3623 | }, | ||
| 3624 | .fn_proto_multi => { | ||
| 3625 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { | ||
| 3626 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3627 | error.AnalysisFail => {}, | ||
| 3628 | }; | ||
| 3629 | continue; | ||
| 3630 | }, | ||
| 3631 | .fn_proto_one => { | ||
| 3632 | var params: [1]ast.Node.Index = undefined; | ||
| 3633 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) { | ||
| 3634 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3635 | error.AnalysisFail => {}, | ||
| 3636 | }; | ||
| 3637 | continue; | ||
| 3638 | }, | ||
| 3639 | .fn_proto => { | ||
| 3640 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { | ||
| 3641 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3642 | error.AnalysisFail => {}, | ||
| 3643 | }; | ||
| 3644 | continue; | ||
| 3645 | }, | ||
| 3646 | else => unreachable, | ||
| 3647 | } | ||
| 3648 | }, | ||
| 3649 | .fn_proto_simple => { | ||
| 3650 | var params: [1]ast.Node.Index = undefined; | ||
| 3651 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) { | ||
| 3652 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3653 | error.AnalysisFail => {}, | ||
| 3654 | }; | ||
| 3655 | continue; | ||
| 3656 | }, | ||
| 3657 | .fn_proto_multi => { | ||
| 3658 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { | ||
| 3659 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3660 | error.AnalysisFail => {}, | ||
| 3661 | }; | ||
| 3662 | continue; | ||
| 3663 | }, | ||
| 3664 | .fn_proto_one => { | ||
| 3665 | var params: [1]ast.Node.Index = undefined; | ||
| 3666 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) { | ||
| 3667 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3668 | error.AnalysisFail => {}, | ||
| 3669 | }; | ||
| 3670 | continue; | ||
| 3671 | }, | ||
| 3672 | .fn_proto => { | ||
| 3673 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { | ||
| 3674 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3675 | error.AnalysisFail => {}, | ||
| 3676 | }; | ||
| 3677 | continue; | ||
| 3678 | }, | ||
| 3326 | 3679 | ||
| 3327 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 3680 | .global_var_decl => { |
| 3328 | if (!astgen.refIsNoReturn(case_result)) { | 3681 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { |
| 3329 | block_scope.break_count += 1; | 3682 | error.OutOfMemory => return error.OutOfMemory, |
| 3330 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 3683 | error.AnalysisFail => {}, |
| 3684 | }; | ||
| 3685 | continue; | ||
| 3686 | }, | ||
| 3687 | .local_var_decl => { | ||
| 3688 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { | ||
| 3689 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3690 | error.AnalysisFail => {}, | ||
| 3691 | }; | ||
| 3692 | continue; | ||
| 3693 | }, | ||
| 3694 | .simple_var_decl => { | ||
| 3695 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { | ||
| 3696 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3697 | error.AnalysisFail => {}, | ||
| 3698 | }; | ||
| 3699 | continue; | ||
| 3700 | }, | ||
| 3701 | .aligned_var_decl => { | ||
| 3702 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { | ||
| 3703 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3704 | error.AnalysisFail => {}, | ||
| 3705 | }; | ||
| 3706 | continue; | ||
| 3707 | }, | ||
| 3708 | |||
| 3709 | .@"comptime" => { | ||
| 3710 | astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3711 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3712 | error.AnalysisFail => {}, | ||
| 3713 | }; | ||
| 3714 | continue; | ||
| 3715 | }, | ||
| 3716 | .@"usingnamespace" => { | ||
| 3717 | astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3718 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3719 | error.AnalysisFail => {}, | ||
| 3720 | }; | ||
| 3721 | continue; | ||
| 3722 | }, | ||
| 3723 | .test_decl => { | ||
| 3724 | astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 3725 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3726 | error.AnalysisFail => {}, | ||
| 3727 | }; | ||
| 3728 | continue; | ||
| 3729 | }, | ||
| 3730 | else => unreachable, | ||
| 3731 | }; | ||
| 3732 | if (field_index % fields_per_u32 == 0 and field_index != 0) { | ||
| 3733 | try bit_bag.append(gpa, cur_bit_bag); | ||
| 3734 | cur_bit_bag = 0; | ||
| 3735 | } | ||
| 3736 | if (member.comptime_token) |comptime_token| { | ||
| 3737 | return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); | ||
| 3738 | } | ||
| 3739 | try fields_data.ensureUnusedCapacity(gpa, 4); | ||
| 3740 | |||
| 3741 | const field_name = try astgen.identAsString(member.ast.name_token); | ||
| 3742 | fields_data.appendAssumeCapacity(field_name); | ||
| 3743 | |||
| 3744 | const have_type = member.ast.type_expr != 0; | ||
| 3745 | const have_align = member.ast.align_expr != 0; | ||
| 3746 | const have_value = member.ast.value_expr != 0; | ||
| 3747 | const unused = false; | ||
| 3748 | cur_bit_bag = (cur_bit_bag >> bits_per_field) | | ||
| 3749 | (@as(u32, @boolToInt(have_type)) << 28) | | ||
| 3750 | (@as(u32, @boolToInt(have_align)) << 29) | | ||
| 3751 | (@as(u32, @boolToInt(have_value)) << 30) | | ||
| 3752 | (@as(u32, @boolToInt(unused)) << 31); | ||
| 3753 | |||
| 3754 | if (have_type) { | ||
| 3755 | const field_type = try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr); | ||
| 3756 | fields_data.appendAssumeCapacity(@enumToInt(field_type)); | ||
| 3757 | } | ||
| 3758 | if (have_align) { | ||
| 3759 | const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); | ||
| 3760 | fields_data.appendAssumeCapacity(@enumToInt(align_inst)); | ||
| 3761 | } | ||
| 3762 | if (have_value) { | ||
| 3763 | if (arg_inst == .none) { | ||
| 3764 | return astgen.failNodeNotes( | ||
| 3765 | node, | ||
| 3766 | "explicitly valued tagged union missing integer tag type", | ||
| 3767 | .{}, | ||
| 3768 | &[_]u32{ | ||
| 3769 | try astgen.errNoteNode( | ||
| 3770 | member.ast.value_expr, | ||
| 3771 | "tag value specified here", | ||
| 3772 | .{}, | ||
| 3773 | ), | ||
| 3774 | }, | ||
| 3775 | ); | ||
| 3331 | } | 3776 | } |
| 3777 | const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); | ||
| 3778 | fields_data.appendAssumeCapacity(@enumToInt(tag_value)); | ||
| 3779 | } | ||
| 3332 | 3780 | ||
| 3333 | multi_cases_payload.items[header_index + 0] = items_len; | 3781 | field_index += 1; |
| 3334 | multi_cases_payload.items[header_index + 1] = ranges_len; | 3782 | } |
| 3335 | multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); | 3783 | if (field_index == 0) { |
| 3336 | try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items); | 3784 | return astgen.failNode(node, "union declarations must have at least one tag", .{}); |
| 3337 | } else { | 3785 | } |
| 3338 | const item_node = case.ast.values[0]; | 3786 | { |
| 3339 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | 3787 | const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32); |
| 3340 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 3788 | if (empty_slot_count < fields_per_u32) { |
| 3341 | if (!astgen.refIsNoReturn(case_result)) { | 3789 | cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field); |
| 3342 | block_scope.break_count += 1; | 3790 | } |
| 3343 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 3791 | } |
| 3344 | } | 3792 | { |
| 3345 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | 3793 | const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); |
| 3346 | 2 + case_scope.instructions.items.len); | 3794 | if (empty_slot_count < WipDecls.fields_per_u32) { |
| 3347 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); | 3795 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); |
| 3348 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | ||
| 3349 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | ||
| 3350 | } | 3796 | } |
| 3351 | } | 3797 | } |
| 3352 | // Now that the item expressions are generated we can add this. | ||
| 3353 | try parent_gz.instructions.append(gpa, switch_block); | ||
| 3354 | 3798 | ||
| 3355 | const ref_bit: u4 = @boolToInt(any_payload_is_ref); | 3799 | const decl_inst = try gz.reserveInstructionIndex(); |
| 3356 | const multi_bit: u4 = @boolToInt(multi_cases_len != 0); | 3800 | if (block_scope.instructions.items.len != 0) { |
| 3357 | const special_prong_bits: u4 = @enumToInt(special_prong); | 3801 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 3358 | comptime { | ||
| 3359 | assert(@enumToInt(zir.SpecialProng.none) == 0b00); | ||
| 3360 | assert(@enumToInt(zir.SpecialProng.@"else") == 0b01); | ||
| 3361 | assert(@enumToInt(zir.SpecialProng.under) == 0b10); | ||
| 3362 | } | 3802 | } |
| 3363 | const zir_tags = astgen.instructions.items(.tag); | ||
| 3364 | zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) { | ||
| 3365 | 0b0_00_0 => .switch_block, | ||
| 3366 | 0b0_00_1 => .switch_block_multi, | ||
| 3367 | 0b0_01_0 => .switch_block_else, | ||
| 3368 | 0b0_01_1 => .switch_block_else_multi, | ||
| 3369 | 0b0_10_0 => .switch_block_under, | ||
| 3370 | 0b0_10_1 => .switch_block_under_multi, | ||
| 3371 | 0b1_00_0 => .switch_block_ref, | ||
| 3372 | 0b1_00_1 => .switch_block_ref_multi, | ||
| 3373 | 0b1_01_0 => .switch_block_ref_else, | ||
| 3374 | 0b1_01_1 => .switch_block_ref_else_multi, | ||
| 3375 | 0b1_10_0 => .switch_block_ref_under, | ||
| 3376 | 0b1_10_1 => .switch_block_ref_under_multi, | ||
| 3377 | else => unreachable, | ||
| 3378 | }; | ||
| 3379 | const payload_index = astgen.extra.items.len; | ||
| 3380 | const zir_datas = astgen.instructions.items(.data); | ||
| 3381 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); | ||
| 3382 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 3383 | scalar_cases_payload.items.len + multi_cases_payload.items.len); | ||
| 3384 | const strat = rl.strategy(&block_scope); | ||
| 3385 | switch (strat.tag) { | ||
| 3386 | .break_operand => { | ||
| 3387 | // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus | ||
| 3388 | // `elide_store_to_block_ptr_instructions` will either be true, | ||
| 3389 | // or all prongs are noreturn. | ||
| 3390 | if (!strat.elide_store_to_block_ptr_instructions) { | ||
| 3391 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | ||
| 3392 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | ||
| 3393 | return astgen.indexToRef(switch_block); | ||
| 3394 | } | ||
| 3395 | 3803 | ||
| 3396 | // There will necessarily be a store_to_block_ptr for | 3804 | try gz.setUnion(decl_inst, .{ |
| 3397 | // all prongs, except for prongs that ended with a noreturn instruction. | 3805 | .src_node = node, |
| 3398 | // Elide all the `store_to_block_ptr` instructions. | 3806 | .layout = layout, |
| 3807 | .tag_type = arg_inst, | ||
| 3808 | .body_len = @intCast(u32, block_scope.instructions.items.len), | ||
| 3809 | .fields_len = @intCast(u32, field_index), | ||
| 3810 | .decls_len = @intCast(u32, wip_decls.decl_index), | ||
| 3811 | .auto_enum_tag = have_auto_enum, | ||
| 3812 | }); | ||
| 3399 | 3813 | ||
| 3400 | // The break instructions need to have their operands coerced if the | 3814 | try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + |
| 3401 | // switch's result location is a `ty`. In this case we overwrite the | 3815 | 1 + fields_data.items.len + |
| 3402 | // `store_to_block_ptr` instruction with an `as` instruction and repurpose | 3816 | block_scope.instructions.items.len + |
| 3403 | // it as the break operand. | 3817 | wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + |
| 3818 | wip_decls.payload.items.len); | ||
| 3819 | astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. | ||
| 3820 | if (wip_decls.decl_index != 0) { | ||
| 3821 | astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); | ||
| 3822 | } | ||
| 3823 | astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); | ||
| 3404 | 3824 | ||
| 3405 | var extra_index: usize = 0; | 3825 | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 3406 | extra_index += 2; | ||
| 3407 | extra_index += @boolToInt(multi_cases_len != 0); | ||
| 3408 | if (special_prong != .none) special_prong: { | ||
| 3409 | const body_len_index = extra_index; | ||
| 3410 | const body_len = scalar_cases_payload.items[extra_index]; | ||
| 3411 | extra_index += 1; | ||
| 3412 | if (body_len < 2) { | ||
| 3413 | extra_index += body_len; | ||
| 3414 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3415 | break :special_prong; | ||
| 3416 | } | ||
| 3417 | extra_index += body_len - 2; | ||
| 3418 | const store_inst = scalar_cases_payload.items[extra_index]; | ||
| 3419 | if (zir_tags[store_inst] != .store_to_block_ptr) { | ||
| 3420 | extra_index += 2; | ||
| 3421 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3422 | break :special_prong; | ||
| 3423 | } | ||
| 3424 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 3425 | if (block_scope.rl_ty_inst != .none) { | ||
| 3426 | extra_index += 1; | ||
| 3427 | const break_inst = scalar_cases_payload.items[extra_index]; | ||
| 3428 | extra_index += 1; | ||
| 3429 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3430 | zir_tags[store_inst] = .as; | ||
| 3431 | zir_datas[store_inst].bin = .{ | ||
| 3432 | .lhs = block_scope.rl_ty_inst, | ||
| 3433 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3434 | }; | ||
| 3435 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3436 | } else { | ||
| 3437 | scalar_cases_payload.items[body_len_index] -= 1; | ||
| 3438 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3439 | extra_index += 1; | ||
| 3440 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | ||
| 3441 | extra_index += 1; | ||
| 3442 | } | ||
| 3443 | } else { | ||
| 3444 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 3445 | } | ||
| 3446 | var scalar_i: u32 = 0; | ||
| 3447 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | ||
| 3448 | const start_index = extra_index; | ||
| 3449 | extra_index += 1; | ||
| 3450 | const body_len_index = extra_index; | ||
| 3451 | const body_len = scalar_cases_payload.items[extra_index]; | ||
| 3452 | extra_index += 1; | ||
| 3453 | if (body_len < 2) { | ||
| 3454 | extra_index += body_len; | ||
| 3455 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3456 | continue; | ||
| 3457 | } | ||
| 3458 | extra_index += body_len - 2; | ||
| 3459 | const store_inst = scalar_cases_payload.items[extra_index]; | ||
| 3460 | if (zir_tags[store_inst] != .store_to_block_ptr) { | ||
| 3461 | extra_index += 2; | ||
| 3462 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3463 | continue; | ||
| 3464 | } | ||
| 3465 | if (block_scope.rl_ty_inst != .none) { | ||
| 3466 | extra_index += 1; | ||
| 3467 | const break_inst = scalar_cases_payload.items[extra_index]; | ||
| 3468 | extra_index += 1; | ||
| 3469 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3470 | zir_tags[store_inst] = .as; | ||
| 3471 | zir_datas[store_inst].bin = .{ | ||
| 3472 | .lhs = block_scope.rl_ty_inst, | ||
| 3473 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3474 | }; | ||
| 3475 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3476 | } else { | ||
| 3477 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 3478 | scalar_cases_payload.items[body_len_index] -= 1; | ||
| 3479 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 3480 | extra_index += 1; | ||
| 3481 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | ||
| 3482 | extra_index += 1; | ||
| 3483 | } | ||
| 3484 | } | ||
| 3485 | extra_index = 0; | ||
| 3486 | var multi_i: u32 = 0; | ||
| 3487 | while (multi_i < multi_cases_len) : (multi_i += 1) { | ||
| 3488 | const start_index = extra_index; | ||
| 3489 | const items_len = multi_cases_payload.items[extra_index]; | ||
| 3490 | extra_index += 1; | ||
| 3491 | const ranges_len = multi_cases_payload.items[extra_index]; | ||
| 3492 | extra_index += 1; | ||
| 3493 | const body_len_index = extra_index; | ||
| 3494 | const body_len = multi_cases_payload.items[extra_index]; | ||
| 3495 | extra_index += 1; | ||
| 3496 | extra_index += items_len; | ||
| 3497 | extra_index += 2 * ranges_len; | ||
| 3498 | if (body_len < 2) { | ||
| 3499 | extra_index += body_len; | ||
| 3500 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3501 | continue; | ||
| 3502 | } | ||
| 3503 | extra_index += body_len - 2; | ||
| 3504 | const store_inst = multi_cases_payload.items[extra_index]; | ||
| 3505 | if (zir_tags[store_inst] != .store_to_block_ptr) { | ||
| 3506 | extra_index += 2; | ||
| 3507 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3508 | continue; | ||
| 3509 | } | ||
| 3510 | if (block_scope.rl_ty_inst != .none) { | ||
| 3511 | extra_index += 1; | ||
| 3512 | const break_inst = multi_cases_payload.items[extra_index]; | ||
| 3513 | extra_index += 1; | ||
| 3514 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3515 | zir_tags[store_inst] = .as; | ||
| 3516 | zir_datas[store_inst].bin = .{ | ||
| 3517 | .lhs = block_scope.rl_ty_inst, | ||
| 3518 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 3519 | }; | ||
| 3520 | zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst); | ||
| 3521 | } else { | ||
| 3522 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 3523 | multi_cases_payload.items[body_len_index] -= 1; | ||
| 3524 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 3525 | extra_index += 1; | ||
| 3526 | astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); | ||
| 3527 | extra_index += 1; | ||
| 3528 | } | ||
| 3529 | } | ||
| 3530 | 3826 | ||
| 3531 | const block_ref = astgen.indexToRef(switch_block); | 3827 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. |
| 3532 | switch (rl) { | 3828 | astgen.extra.appendAssumeCapacity(cur_bit_bag); |
| 3533 | .ref => return block_ref, | 3829 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); |
| 3534 | else => return rvalue(parent_gz, scope, rl, block_ref, switch_node), | ||
| 3535 | } | ||
| 3536 | }, | ||
| 3537 | .break_void => { | ||
| 3538 | assert(!strat.elide_store_to_block_ptr_instructions); | ||
| 3539 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | ||
| 3540 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | ||
| 3541 | // Modify all the terminating instruction tags to become `break` variants. | ||
| 3542 | var extra_index: usize = payload_index; | ||
| 3543 | extra_index += 2; | ||
| 3544 | extra_index += @boolToInt(multi_cases_len != 0); | ||
| 3545 | if (special_prong != .none) { | ||
| 3546 | const body_len = astgen.extra.items[extra_index]; | ||
| 3547 | extra_index += 1; | ||
| 3548 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 3549 | extra_index += body_len; | ||
| 3550 | const last = body[body.len - 1]; | ||
| 3551 | if (zir_tags[last] == .@"break" and | ||
| 3552 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 3553 | { | ||
| 3554 | zir_datas[last].@"break".operand = .void_value; | ||
| 3555 | } | ||
| 3556 | } | ||
| 3557 | var scalar_i: u32 = 0; | ||
| 3558 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | ||
| 3559 | extra_index += 1; | ||
| 3560 | const body_len = astgen.extra.items[extra_index]; | ||
| 3561 | extra_index += 1; | ||
| 3562 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 3563 | extra_index += body_len; | ||
| 3564 | const last = body[body.len - 1]; | ||
| 3565 | if (zir_tags[last] == .@"break" and | ||
| 3566 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 3567 | { | ||
| 3568 | zir_datas[last].@"break".operand = .void_value; | ||
| 3569 | } | ||
| 3570 | } | ||
| 3571 | var multi_i: u32 = 0; | ||
| 3572 | while (multi_i < multi_cases_len) : (multi_i += 1) { | ||
| 3573 | const items_len = astgen.extra.items[extra_index]; | ||
| 3574 | extra_index += 1; | ||
| 3575 | const ranges_len = astgen.extra.items[extra_index]; | ||
| 3576 | extra_index += 1; | ||
| 3577 | const body_len = astgen.extra.items[extra_index]; | ||
| 3578 | extra_index += 1; | ||
| 3579 | extra_index += items_len; | ||
| 3580 | extra_index += 2 * ranges_len; | ||
| 3581 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 3582 | extra_index += body_len; | ||
| 3583 | const last = body[body.len - 1]; | ||
| 3584 | if (zir_tags[last] == .@"break" and | ||
| 3585 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 3586 | { | ||
| 3587 | zir_datas[last].@"break".operand = .void_value; | ||
| 3588 | } | ||
| 3589 | } | ||
| 3590 | 3830 | ||
| 3591 | return astgen.indexToRef(switch_block); | 3831 | return gz.indexToRef(decl_inst); |
| 3592 | }, | ||
| 3593 | } | ||
| 3594 | } | 3832 | } |
| 3595 | 3833 | ||
| 3596 | fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref { | 3834 | fn containerDecl( |
| 3597 | const tree = gz.tree(); | 3835 | gz: *GenZir, |
| 3836 | scope: *Scope, | ||
| 3837 | rl: ResultLoc, | ||
| 3838 | node: ast.Node.Index, | ||
| 3839 | container_decl: ast.full.ContainerDecl, | ||
| 3840 | ) InnerError!Zir.Inst.Ref { | ||
| 3841 | const astgen = gz.astgen; | ||
| 3842 | const gpa = astgen.gpa; | ||
| 3843 | const tree = astgen.tree; | ||
| 3844 | const token_tags = tree.tokens.items(.tag); | ||
| 3845 | const node_tags = tree.nodes.items(.tag); | ||
| 3598 | const node_datas = tree.nodes.items(.data); | 3846 | const node_datas = tree.nodes.items(.data); |
| 3599 | const main_tokens = tree.nodes.items(.main_token); | ||
| 3600 | 3847 | ||
| 3601 | const operand_node = node_datas[node].lhs; | 3848 | // We must not create any types until Sema. Here the goal is only to generate |
| 3602 | const operand: zir.Inst.Ref = if (operand_node != 0) operand: { | 3849 | // ZIR for all the field types, alignments, and default value expressions. |
| 3603 | const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{ | ||
| 3604 | .ptr = try gz.addNode(.ret_ptr, node), | ||
| 3605 | } else .{ | ||
| 3606 | .ty = try gz.addNode(.ret_type, node), | ||
| 3607 | }; | ||
| 3608 | break :operand try expr(gz, scope, rl, operand_node); | ||
| 3609 | } else .void_value; | ||
| 3610 | _ = try gz.addUnNode(.ret_node, operand, node); | ||
| 3611 | return zir.Inst.Ref.unreachable_value; | ||
| 3612 | } | ||
| 3613 | 3850 | ||
| 3614 | fn identifier( | 3851 | const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) |
| 3615 | gz: *GenZir, | 3852 | try comptimeExpr(gz, scope, .{ .ty = .type_type }, container_decl.ast.arg) |
| 3616 | scope: *Scope, | 3853 | else |
| 3617 | rl: ResultLoc, | 3854 | .none; |
| 3618 | ident: ast.Node.Index, | ||
| 3619 | ) InnerError!zir.Inst.Ref { | ||
| 3620 | const tracy = trace(@src()); | ||
| 3621 | defer tracy.end(); | ||
| 3622 | 3855 | ||
| 3623 | const astgen = gz.astgen; | 3856 | switch (token_tags[container_decl.ast.main_token]) { |
| 3624 | const mod = astgen.mod; | 3857 | .keyword_struct => { |
| 3625 | const tree = gz.tree(); | 3858 | const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { |
| 3626 | const main_tokens = tree.nodes.items(.main_token); | 3859 | .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed, |
| 3860 | .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern, | ||
| 3861 | else => unreachable, | ||
| 3862 | } else std.builtin.TypeInfo.ContainerLayout.Auto; | ||
| 3627 | 3863 | ||
| 3628 | const ident_token = main_tokens[ident]; | 3864 | assert(arg_inst == .none); |
| 3629 | const ident_name = try mod.identifierTokenString(scope, ident_token); | ||
| 3630 | if (mem.eql(u8, ident_name, "_")) { | ||
| 3631 | return mod.failNode(scope, ident, "TODO implement '_' identifier", .{}); | ||
| 3632 | } | ||
| 3633 | 3865 | ||
| 3634 | if (simple_types.get(ident_name)) |zir_const_ref| { | 3866 | const result = try structDeclInner(gz, scope, node, container_decl, layout); |
| 3635 | return rvalue(gz, scope, rl, zir_const_ref, ident); | 3867 | return rvalue(gz, scope, rl, result, node); |
| 3636 | } | 3868 | }, |
| 3869 | .keyword_union => { | ||
| 3870 | const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { | ||
| 3871 | .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed, | ||
| 3872 | .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern, | ||
| 3873 | else => unreachable, | ||
| 3874 | } else std.builtin.TypeInfo.ContainerLayout.Auto; | ||
| 3637 | 3875 | ||
| 3638 | if (ident_name.len >= 2) integer: { | 3876 | const have_auto_enum = container_decl.ast.enum_token != null; |
| 3639 | const first_c = ident_name[0]; | ||
| 3640 | if (first_c == 'i' or first_c == 'u') { | ||
| 3641 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { | ||
| 3642 | true => .signed, | ||
| 3643 | false => .unsigned, | ||
| 3644 | }; | ||
| 3645 | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { | ||
| 3646 | error.Overflow => return mod.failNode( | ||
| 3647 | scope, | ||
| 3648 | ident, | ||
| 3649 | "primitive integer type '{s}' exceeds maximum bit width of 65535", | ||
| 3650 | .{ident_name}, | ||
| 3651 | ), | ||
| 3652 | error.InvalidCharacter => break :integer, | ||
| 3653 | }; | ||
| 3654 | const result = try gz.add(.{ | ||
| 3655 | .tag = .int_type, | ||
| 3656 | .data = .{ .int_type = .{ | ||
| 3657 | .src_node = astgen.decl.nodeIndexToRelative(ident), | ||
| 3658 | .signedness = signedness, | ||
| 3659 | .bit_count = bit_count, | ||
| 3660 | } }, | ||
| 3661 | }); | ||
| 3662 | return rvalue(gz, scope, rl, result, ident); | ||
| 3663 | } | ||
| 3664 | } | ||
| 3665 | 3877 | ||
| 3666 | // Local variables, including function parameters. | 3878 | const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, arg_inst, have_auto_enum); |
| 3667 | { | 3879 | return rvalue(gz, scope, rl, result, node); |
| 3668 | var s = scope; | 3880 | }, |
| 3669 | while (true) switch (s.tag) { | 3881 | .keyword_enum => { |
| 3670 | .local_val => { | 3882 | if (container_decl.layout_token) |t| { |
| 3671 | const local_val = s.cast(Scope.LocalVal).?; | 3883 | return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); |
| 3672 | if (mem.eql(u8, local_val.name, ident_name)) { | 3884 | } |
| 3673 | return rvalue(gz, scope, rl, local_val.inst, ident); | 3885 | // Count total fields as well as how many have explicitly provided tag values. |
| 3674 | } | 3886 | const counts = blk: { |
| 3675 | s = local_val.parent; | 3887 | var values: usize = 0; |
| 3676 | }, | 3888 | var total_fields: usize = 0; |
| 3677 | .local_ptr => { | 3889 | var decls: usize = 0; |
| 3678 | const local_ptr = s.cast(Scope.LocalPtr).?; | 3890 | var nonexhaustive_node: ast.Node.Index = 0; |
| 3679 | if (mem.eql(u8, local_ptr.name, ident_name)) { | 3891 | for (container_decl.ast.members) |member_node| { |
| 3680 | switch (rl) { | 3892 | const member = switch (node_tags[member_node]) { |
| 3681 | .ref, .none_or_ref => return local_ptr.ptr, | 3893 | .container_field_init => tree.containerFieldInit(member_node), |
| 3894 | .container_field_align => tree.containerFieldAlign(member_node), | ||
| 3895 | .container_field => tree.containerField(member_node), | ||
| 3682 | else => { | 3896 | else => { |
| 3683 | const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident); | 3897 | decls += 1; |
| 3684 | return rvalue(gz, scope, rl, loaded, ident); | 3898 | continue; |
| 3685 | }, | 3899 | }, |
| 3900 | }; | ||
| 3901 | if (member.comptime_token) |comptime_token| { | ||
| 3902 | return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); | ||
| 3686 | } | 3903 | } |
| 3687 | } | 3904 | if (member.ast.type_expr != 0) { |
| 3688 | s = local_ptr.parent; | 3905 | return astgen.failNode(member.ast.type_expr, "enum fields do not have types", .{}); |
| 3689 | }, | 3906 | } |
| 3690 | .gen_zir => s = s.cast(GenZir).?.parent, | 3907 | // Alignment expressions in enums are caught by the parser. |
| 3691 | else => break, | 3908 | assert(member.ast.align_expr == 0); |
| 3692 | }; | ||
| 3693 | } | ||
| 3694 | 3909 | ||
| 3695 | const decl = mod.lookupDeclName(scope, ident_name) orelse { | 3910 | const name_token = member.ast.name_token; |
| 3696 | // TODO insert a "dependency on the non-existence of a decl" here to make this | 3911 | if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { |
| 3697 | // compile error go away when the decl is introduced. This data should be in a global | 3912 | if (nonexhaustive_node != 0) { |
| 3698 | // sparse map since it is only relevant when a compile error occurs. | 3913 | return astgen.failNodeNotes( |
| 3699 | return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name}); | 3914 | member_node, |
| 3700 | }; | 3915 | "redundant non-exhaustive enum mark", |
| 3701 | const decl_index = try mod.declareDeclDependency(astgen.decl, decl); | 3916 | .{}, |
| 3702 | switch (rl) { | 3917 | &[_]u32{ |
| 3703 | .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident), | 3918 | try astgen.errNoteNode( |
| 3704 | else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident), | 3919 | nonexhaustive_node, |
| 3705 | } | 3920 | "other mark here", |
| 3706 | } | 3921 | .{}, |
| 3922 | ), | ||
| 3923 | }, | ||
| 3924 | ); | ||
| 3925 | } | ||
| 3926 | nonexhaustive_node = member_node; | ||
| 3927 | if (member.ast.value_expr != 0) { | ||
| 3928 | return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); | ||
| 3929 | } | ||
| 3930 | continue; | ||
| 3931 | } | ||
| 3932 | total_fields += 1; | ||
| 3933 | if (member.ast.value_expr != 0) { | ||
| 3934 | if (arg_inst == .none) { | ||
| 3935 | return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); | ||
| 3936 | } | ||
| 3937 | values += 1; | ||
| 3938 | } | ||
| 3939 | } | ||
| 3940 | break :blk .{ | ||
| 3941 | .total_fields = total_fields, | ||
| 3942 | .values = values, | ||
| 3943 | .decls = decls, | ||
| 3944 | .nonexhaustive_node = nonexhaustive_node, | ||
| 3945 | }; | ||
| 3946 | }; | ||
| 3947 | if (counts.total_fields == 0) { | ||
| 3948 | // One can construct an enum with no tags, and it functions the same as `noreturn`. But | ||
| 3949 | // this is only useful for generic code; when explicitly using `enum {}` syntax, there | ||
| 3950 | // must be at least one tag. | ||
| 3951 | return astgen.failNode(node, "enum declarations must have at least one tag", .{}); | ||
| 3952 | } | ||
| 3953 | if (counts.nonexhaustive_node != 0 and arg_inst == .none) { | ||
| 3954 | return astgen.failNodeNotes( | ||
| 3955 | node, | ||
| 3956 | "non-exhaustive enum missing integer tag type", | ||
| 3957 | .{}, | ||
| 3958 | &[_]u32{ | ||
| 3959 | try astgen.errNoteNode( | ||
| 3960 | counts.nonexhaustive_node, | ||
| 3961 | "marked non-exhaustive here", | ||
| 3962 | .{}, | ||
| 3963 | ), | ||
| 3964 | }, | ||
| 3965 | ); | ||
| 3966 | } | ||
| 3967 | // In this case we must generate ZIR code for the tag values, similar to | ||
| 3968 | // how structs are handled above. | ||
| 3969 | const nonexhaustive = counts.nonexhaustive_node != 0; | ||
| 3707 | 3970 | ||
| 3708 | fn stringLiteral( | 3971 | // The enum_decl instruction introduces a scope in which the decls of the enum |
| 3709 | gz: *GenZir, | 3972 | // are in scope, so that tag values can refer to decls within the enum itself. |
| 3710 | scope: *Scope, | 3973 | var block_scope: GenZir = .{ |
| 3711 | rl: ResultLoc, | 3974 | .parent = scope, |
| 3712 | node: ast.Node.Index, | 3975 | .decl_node_index = node, |
| 3713 | ) InnerError!zir.Inst.Ref { | 3976 | .decl_line = gz.calcLine(node), |
| 3714 | const tree = gz.tree(); | 3977 | .astgen = astgen, |
| 3715 | const main_tokens = tree.nodes.items(.main_token); | 3978 | .force_comptime = true, |
| 3716 | const string_bytes = &gz.astgen.string_bytes; | 3979 | .ref_start_index = gz.ref_start_index, |
| 3717 | const str_index = string_bytes.items.len; | 3980 | }; |
| 3718 | const str_lit_token = main_tokens[node]; | 3981 | defer block_scope.instructions.deinit(gpa); |
| 3719 | const token_bytes = tree.tokenSlice(str_lit_token); | ||
| 3720 | try gz.astgen.mod.parseStrLit(scope, str_lit_token, string_bytes, token_bytes, 0); | ||
| 3721 | const str_len = string_bytes.items.len - str_index; | ||
| 3722 | const result = try gz.add(.{ | ||
| 3723 | .tag = .str, | ||
| 3724 | .data = .{ .str = .{ | ||
| 3725 | .start = @intCast(u32, str_index), | ||
| 3726 | .len = @intCast(u32, str_len), | ||
| 3727 | } }, | ||
| 3728 | }); | ||
| 3729 | return rvalue(gz, scope, rl, result, node); | ||
| 3730 | } | ||
| 3731 | 3982 | ||
| 3732 | fn multilineStringLiteral( | 3983 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; |
| 3733 | gz: *GenZir, | 3984 | defer namespace.decls.deinit(gpa); |
| 3734 | scope: *Scope, | ||
| 3735 | rl: ResultLoc, | ||
| 3736 | node: ast.Node.Index, | ||
| 3737 | ) InnerError!zir.Inst.Ref { | ||
| 3738 | const tree = gz.tree(); | ||
| 3739 | const node_datas = tree.nodes.items(.data); | ||
| 3740 | const main_tokens = tree.nodes.items(.main_token); | ||
| 3741 | 3985 | ||
| 3742 | const start = node_datas[node].lhs; | 3986 | var wip_decls: WipDecls = .{}; |
| 3743 | const end = node_datas[node].rhs; | 3987 | defer wip_decls.deinit(gpa); |
| 3744 | 3988 | ||
| 3745 | const gpa = gz.astgen.mod.gpa; | 3989 | var fields_data = ArrayListUnmanaged(u32){}; |
| 3746 | const string_bytes = &gz.astgen.string_bytes; | 3990 | defer fields_data.deinit(gpa); |
| 3747 | const str_index = string_bytes.items.len; | ||
| 3748 | 3991 | ||
| 3749 | // First line: do not append a newline. | 3992 | try fields_data.ensureCapacity(gpa, counts.total_fields + counts.values); |
| 3750 | var tok_i = start; | ||
| 3751 | { | ||
| 3752 | const slice = tree.tokenSlice(tok_i); | ||
| 3753 | const line_bytes = slice[2 .. slice.len - 1]; | ||
| 3754 | try string_bytes.appendSlice(gpa, line_bytes); | ||
| 3755 | tok_i += 1; | ||
| 3756 | } | ||
| 3757 | // Following lines: each line prepends a newline. | ||
| 3758 | while (tok_i <= end) : (tok_i += 1) { | ||
| 3759 | const slice = tree.tokenSlice(tok_i); | ||
| 3760 | const line_bytes = slice[2 .. slice.len - 1]; | ||
| 3761 | try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1); | ||
| 3762 | string_bytes.appendAssumeCapacity('\n'); | ||
| 3763 | string_bytes.appendSliceAssumeCapacity(line_bytes); | ||
| 3764 | } | ||
| 3765 | const result = try gz.add(.{ | ||
| 3766 | .tag = .str, | ||
| 3767 | .data = .{ .str = .{ | ||
| 3768 | .start = @intCast(u32, str_index), | ||
| 3769 | .len = @intCast(u32, string_bytes.items.len - str_index), | ||
| 3770 | } }, | ||
| 3771 | }); | ||
| 3772 | return rvalue(gz, scope, rl, result, node); | ||
| 3773 | } | ||
| 3774 | 3993 | ||
| 3775 | fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref { | 3994 | // We only need this if there are greater than 32 fields. |
| 3776 | const mod = gz.astgen.mod; | 3995 | var bit_bag = ArrayListUnmanaged(u32){}; |
| 3777 | const tree = gz.tree(); | 3996 | defer bit_bag.deinit(gpa); |
| 3778 | const main_tokens = tree.nodes.items(.main_token); | ||
| 3779 | const main_token = main_tokens[node]; | ||
| 3780 | const slice = tree.tokenSlice(main_token); | ||
| 3781 | 3997 | ||
| 3782 | var bad_index: usize = undefined; | 3998 | var cur_bit_bag: u32 = 0; |
| 3783 | const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { | 3999 | var field_index: usize = 0; |
| 3784 | error.InvalidCharacter => { | 4000 | for (container_decl.ast.members) |member_node| { |
| 3785 | const bad_byte = slice[bad_index]; | 4001 | if (member_node == counts.nonexhaustive_node) |
| 3786 | const token_starts = tree.tokens.items(.start); | 4002 | continue; |
| 3787 | const src_off = @intCast(u32, token_starts[main_token] + bad_index); | 4003 | const member = switch (node_tags[member_node]) { |
| 3788 | return mod.failOff(scope, src_off, "invalid character: '{c}'\n", .{bad_byte}); | 4004 | .container_field_init => tree.containerFieldInit(member_node), |
| 3789 | }, | 4005 | .container_field_align => tree.containerFieldAlign(member_node), |
| 3790 | }; | 4006 | .container_field => tree.containerField(member_node), |
| 3791 | const result = try gz.addInt(value); | ||
| 3792 | return rvalue(gz, scope, rl, result, node); | ||
| 3793 | } | ||
| 3794 | 4007 | ||
| 3795 | fn integerLiteral( | 4008 | .fn_decl => { |
| 3796 | gz: *GenZir, | 4009 | const fn_proto = node_datas[member_node].lhs; |
| 3797 | scope: *Scope, | 4010 | const body = node_datas[member_node].rhs; |
| 3798 | rl: ResultLoc, | 4011 | switch (node_tags[fn_proto]) { |
| 3799 | node: ast.Node.Index, | 4012 | .fn_proto_simple => { |
| 3800 | ) InnerError!zir.Inst.Ref { | 4013 | var params: [1]ast.Node.Index = undefined; |
| 3801 | const tree = gz.tree(); | 4014 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) { |
| 3802 | const main_tokens = tree.nodes.items(.main_token); | 4015 | error.OutOfMemory => return error.OutOfMemory, |
| 3803 | const int_token = main_tokens[node]; | 4016 | error.AnalysisFail => {}, |
| 3804 | const prefixed_bytes = tree.tokenSlice(int_token); | 4017 | }; |
| 3805 | if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| { | 4018 | continue; |
| 3806 | const result: zir.Inst.Ref = switch (small_int) { | 4019 | }, |
| 3807 | 0 => .zero, | 4020 | .fn_proto_multi => { |
| 3808 | 1 => .one, | 4021 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { |
| 3809 | else => try gz.addInt(small_int), | 4022 | error.OutOfMemory => return error.OutOfMemory, |
| 3810 | }; | 4023 | error.AnalysisFail => {}, |
| 3811 | return rvalue(gz, scope, rl, result, node); | 4024 | }; |
| 3812 | } else |err| { | 4025 | continue; |
| 3813 | return gz.astgen.mod.failNode(scope, node, "TODO implement int literals that don't fit in a u64", .{}); | 4026 | }, |
| 3814 | } | 4027 | .fn_proto_one => { |
| 3815 | } | 4028 | var params: [1]ast.Node.Index = undefined; |
| 4029 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) { | ||
| 4030 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4031 | error.AnalysisFail => {}, | ||
| 4032 | }; | ||
| 4033 | continue; | ||
| 4034 | }, | ||
| 4035 | .fn_proto => { | ||
| 4036 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { | ||
| 4037 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4038 | error.AnalysisFail => {}, | ||
| 4039 | }; | ||
| 4040 | continue; | ||
| 4041 | }, | ||
| 4042 | else => unreachable, | ||
| 4043 | } | ||
| 4044 | }, | ||
| 4045 | .fn_proto_simple => { | ||
| 4046 | var params: [1]ast.Node.Index = undefined; | ||
| 4047 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) { | ||
| 4048 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4049 | error.AnalysisFail => {}, | ||
| 4050 | }; | ||
| 4051 | continue; | ||
| 4052 | }, | ||
| 4053 | .fn_proto_multi => { | ||
| 4054 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { | ||
| 4055 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4056 | error.AnalysisFail => {}, | ||
| 4057 | }; | ||
| 4058 | continue; | ||
| 4059 | }, | ||
| 4060 | .fn_proto_one => { | ||
| 4061 | var params: [1]ast.Node.Index = undefined; | ||
| 4062 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) { | ||
| 4063 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4064 | error.AnalysisFail => {}, | ||
| 4065 | }; | ||
| 4066 | continue; | ||
| 4067 | }, | ||
| 4068 | .fn_proto => { | ||
| 4069 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { | ||
| 4070 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4071 | error.AnalysisFail => {}, | ||
| 4072 | }; | ||
| 4073 | continue; | ||
| 4074 | }, | ||
| 3816 | 4075 | ||
| 3817 | fn floatLiteral( | 4076 | .global_var_decl => { |
| 3818 | gz: *GenZir, | 4077 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { |
| 3819 | scope: *Scope, | 4078 | error.OutOfMemory => return error.OutOfMemory, |
| 3820 | rl: ResultLoc, | 4079 | error.AnalysisFail => {}, |
| 3821 | node: ast.Node.Index, | 4080 | }; |
| 3822 | ) InnerError!zir.Inst.Ref { | 4081 | continue; |
| 3823 | const arena = gz.astgen.arena; | 4082 | }, |
| 3824 | const tree = gz.tree(); | 4083 | .local_var_decl => { |
| 3825 | const main_tokens = tree.nodes.items(.main_token); | 4084 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { |
| 3826 | 4085 | error.OutOfMemory => return error.OutOfMemory, | |
| 3827 | const main_token = main_tokens[node]; | 4086 | error.AnalysisFail => {}, |
| 3828 | const bytes = tree.tokenSlice(main_token); | 4087 | }; |
| 3829 | if (bytes.len > 2 and bytes[1] == 'x') { | 4088 | continue; |
| 3830 | assert(bytes[0] == '0'); // validated by tokenizer | 4089 | }, |
| 3831 | return gz.astgen.mod.failTok(scope, main_token, "TODO implement hex floats", .{}); | 4090 | .simple_var_decl => { |
| 3832 | } | 4091 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { |
| 3833 | const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) { | 4092 | error.OutOfMemory => return error.OutOfMemory, |
| 3834 | error.InvalidCharacter => unreachable, // validated by tokenizer | 4093 | error.AnalysisFail => {}, |
| 3835 | }; | 4094 | }; |
| 3836 | // If the value fits into a f32 without losing any precision, store it that way. | 4095 | continue; |
| 3837 | @setFloatMode(.Strict); | 4096 | }, |
| 3838 | const smaller_float = @floatCast(f32, float_number); | 4097 | .aligned_var_decl => { |
| 3839 | const bigger_again: f128 = smaller_float; | 4098 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { |
| 3840 | if (bigger_again == float_number) { | 4099 | error.OutOfMemory => return error.OutOfMemory, |
| 3841 | const result = try gz.addFloat(smaller_float, node); | 4100 | error.AnalysisFail => {}, |
| 3842 | return rvalue(gz, scope, rl, result, node); | 4101 | }; |
| 3843 | } | 4102 | continue; |
| 3844 | // We need to use 128 bits. Break the float into 4 u32 values so we can | 4103 | }, |
| 3845 | // put it into the `extra` array. | ||
| 3846 | const int_bits = @bitCast(u128, float_number); | ||
| 3847 | const result = try gz.addPlNode(.float128, node, zir.Inst.Float128{ | ||
| 3848 | .piece0 = @truncate(u32, int_bits), | ||
| 3849 | .piece1 = @truncate(u32, int_bits >> 32), | ||
| 3850 | .piece2 = @truncate(u32, int_bits >> 64), | ||
| 3851 | .piece3 = @truncate(u32, int_bits >> 96), | ||
| 3852 | }); | ||
| 3853 | return rvalue(gz, scope, rl, result, node); | ||
| 3854 | } | ||
| 3855 | 4104 | ||
| 3856 | fn asmExpr( | 4105 | .@"comptime" => { |
| 3857 | gz: *GenZir, | 4106 | astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { |
| 3858 | scope: *Scope, | 4107 | error.OutOfMemory => return error.OutOfMemory, |
| 3859 | rl: ResultLoc, | 4108 | error.AnalysisFail => {}, |
| 3860 | node: ast.Node.Index, | 4109 | }; |
| 3861 | full: ast.full.Asm, | 4110 | continue; |
| 3862 | ) InnerError!zir.Inst.Ref { | 4111 | }, |
| 3863 | const mod = gz.astgen.mod; | 4112 | .@"usingnamespace" => { |
| 3864 | const arena = gz.astgen.arena; | 4113 | astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { |
| 3865 | const tree = gz.tree(); | 4114 | error.OutOfMemory => return error.OutOfMemory, |
| 3866 | const main_tokens = tree.nodes.items(.main_token); | 4115 | error.AnalysisFail => {}, |
| 3867 | const node_datas = tree.nodes.items(.data); | 4116 | }; |
| 4117 | continue; | ||
| 4118 | }, | ||
| 4119 | .test_decl => { | ||
| 4120 | astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 4121 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4122 | error.AnalysisFail => {}, | ||
| 4123 | }; | ||
| 4124 | continue; | ||
| 4125 | }, | ||
| 4126 | else => unreachable, | ||
| 4127 | }; | ||
| 4128 | if (field_index % 32 == 0 and field_index != 0) { | ||
| 4129 | try bit_bag.append(gpa, cur_bit_bag); | ||
| 4130 | cur_bit_bag = 0; | ||
| 4131 | } | ||
| 4132 | assert(member.comptime_token == null); | ||
| 4133 | assert(member.ast.type_expr == 0); | ||
| 4134 | assert(member.ast.align_expr == 0); | ||
| 3868 | 4135 | ||
| 3869 | const asm_source = try expr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template); | 4136 | const field_name = try astgen.identAsString(member.ast.name_token); |
| 4137 | fields_data.appendAssumeCapacity(field_name); | ||
| 3870 | 4138 | ||
| 3871 | if (full.outputs.len != 0) { | 4139 | const have_value = member.ast.value_expr != 0; |
| 3872 | // when implementing this be sure to add test coverage for the asm return type | 4140 | cur_bit_bag = (cur_bit_bag >> 1) | |
| 3873 | // not resolving into a type (the node_offset_asm_ret_ty field of LazySrcLoc) | 4141 | (@as(u32, @boolToInt(have_value)) << 31); |
| 3874 | return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{}); | ||
| 3875 | } | ||
| 3876 | 4142 | ||
| 3877 | const constraints = try arena.alloc(u32, full.inputs.len); | 4143 | if (have_value) { |
| 3878 | const args = try arena.alloc(zir.Inst.Ref, full.inputs.len); | 4144 | if (arg_inst == .none) { |
| 4145 | return astgen.failNodeNotes( | ||
| 4146 | node, | ||
| 4147 | "explicitly valued enum missing integer tag type", | ||
| 4148 | .{}, | ||
| 4149 | &[_]u32{ | ||
| 4150 | try astgen.errNoteNode( | ||
| 4151 | member.ast.value_expr, | ||
| 4152 | "tag value specified here", | ||
| 4153 | .{}, | ||
| 4154 | ), | ||
| 4155 | }, | ||
| 4156 | ); | ||
| 4157 | } | ||
| 4158 | const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); | ||
| 4159 | fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); | ||
| 4160 | } | ||
| 3879 | 4161 | ||
| 3880 | for (full.inputs) |input, i| { | 4162 | field_index += 1; |
| 3881 | const constraint_token = main_tokens[input] + 2; | 4163 | } |
| 3882 | const string_bytes = &gz.astgen.string_bytes; | 4164 | { |
| 3883 | constraints[i] = @intCast(u32, string_bytes.items.len); | 4165 | const empty_slot_count = 32 - (field_index % 32); |
| 3884 | const token_bytes = tree.tokenSlice(constraint_token); | 4166 | if (empty_slot_count < 32) { |
| 3885 | try mod.parseStrLit(scope, constraint_token, string_bytes, token_bytes, 0); | 4167 | cur_bit_bag >>= @intCast(u5, empty_slot_count); |
| 3886 | try string_bytes.append(mod.gpa, 0); | 4168 | } |
| 4169 | } | ||
| 4170 | { | ||
| 4171 | const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); | ||
| 4172 | if (empty_slot_count < WipDecls.fields_per_u32) { | ||
| 4173 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); | ||
| 4174 | } | ||
| 4175 | } | ||
| 3887 | 4176 | ||
| 3888 | args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs); | 4177 | const decl_inst = try gz.reserveInstructionIndex(); |
| 3889 | } | 4178 | if (block_scope.instructions.items.len != 0) { |
| 4179 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); | ||
| 4180 | } | ||
| 3890 | 4181 | ||
| 3891 | const tag: zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm"; | 4182 | try gz.setEnum(decl_inst, .{ |
| 3892 | const result = try gz.addPlNode(tag, node, zir.Inst.Asm{ | 4183 | .src_node = node, |
| 3893 | .asm_source = asm_source, | 4184 | .nonexhaustive = nonexhaustive, |
| 3894 | .return_type = .void_type, | 4185 | .tag_type = arg_inst, |
| 3895 | .output = .none, | 4186 | .body_len = @intCast(u32, block_scope.instructions.items.len), |
| 3896 | .args_len = @intCast(u32, full.inputs.len), | 4187 | .fields_len = @intCast(u32, field_index), |
| 3897 | .clobbers_len = 0, // TODO implement asm clobbers | 4188 | .decls_len = @intCast(u32, wip_decls.decl_index), |
| 3898 | }); | 4189 | }); |
| 3899 | 4190 | ||
| 3900 | try gz.astgen.extra.ensureCapacity(mod.gpa, gz.astgen.extra.items.len + | 4191 | try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + |
| 3901 | args.len + constraints.len); | 4192 | 1 + fields_data.items.len + |
| 3902 | gz.astgen.appendRefsAssumeCapacity(args); | 4193 | block_scope.instructions.items.len + |
| 3903 | gz.astgen.extra.appendSliceAssumeCapacity(constraints); | 4194 | wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + |
| 4195 | wip_decls.payload.items.len); | ||
| 4196 | astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. | ||
| 4197 | if (wip_decls.decl_index != 0) { | ||
| 4198 | astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); | ||
| 4199 | } | ||
| 4200 | astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); | ||
| 3904 | 4201 | ||
| 3905 | return rvalue(gz, scope, rl, result, node); | 4202 | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 3906 | } | 4203 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. |
| 4204 | astgen.extra.appendAssumeCapacity(cur_bit_bag); | ||
| 4205 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); | ||
| 3907 | 4206 | ||
| 3908 | fn as( | 4207 | return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); |
| 3909 | gz: *GenZir, | ||
| 3910 | scope: *Scope, | ||
| 3911 | rl: ResultLoc, | ||
| 3912 | node: ast.Node.Index, | ||
| 3913 | lhs: ast.Node.Index, | ||
| 3914 | rhs: ast.Node.Index, | ||
| 3915 | ) InnerError!zir.Inst.Ref { | ||
| 3916 | const dest_type = try typeExpr(gz, scope, lhs); | ||
| 3917 | switch (rl) { | ||
| 3918 | .none, .none_or_ref, .discard, .ref, .ty => { | ||
| 3919 | const result = try expr(gz, scope, .{ .ty = dest_type }, rhs); | ||
| 3920 | return rvalue(gz, scope, rl, result, node); | ||
| 3921 | }, | 4208 | }, |
| 4209 | .keyword_opaque => { | ||
| 4210 | var namespace: Scope.Namespace = .{ .parent = &gz.base }; | ||
| 4211 | defer namespace.decls.deinit(gpa); | ||
| 3922 | 4212 | ||
| 3923 | .ptr => |result_ptr| { | 4213 | var wip_decls: WipDecls = .{}; |
| 3924 | return asRlPtr(gz, scope, rl, result_ptr, rhs, dest_type); | 4214 | defer wip_decls.deinit(gpa); |
| 3925 | }, | ||
| 3926 | .block_ptr => |block_scope| { | ||
| 3927 | return asRlPtr(gz, scope, rl, block_scope.rl_ptr, rhs, dest_type); | ||
| 3928 | }, | ||
| 3929 | 4215 | ||
| 3930 | .inferred_ptr => |result_alloc| { | 4216 | for (container_decl.ast.members) |member_node| { |
| 3931 | // TODO here we should be able to resolve the inference; we now have a type for the result. | 4217 | const member = switch (node_tags[member_node]) { |
| 3932 | return gz.astgen.mod.failNode(scope, node, "TODO implement @as with inferred-type result location pointer", .{}); | 4218 | .container_field_init => tree.containerFieldInit(member_node), |
| 3933 | }, | 4219 | .container_field_align => tree.containerFieldAlign(member_node), |
| 3934 | } | 4220 | .container_field => tree.containerField(member_node), |
| 3935 | } | ||
| 3936 | 4221 | ||
| 3937 | fn asRlPtr( | 4222 | .fn_decl => { |
| 3938 | parent_gz: *GenZir, | 4223 | const fn_proto = node_datas[member_node].lhs; |
| 3939 | scope: *Scope, | 4224 | const body = node_datas[member_node].rhs; |
| 3940 | rl: ResultLoc, | 4225 | switch (node_tags[fn_proto]) { |
| 3941 | result_ptr: zir.Inst.Ref, | 4226 | .fn_proto_simple => { |
| 3942 | operand_node: ast.Node.Index, | 4227 | var params: [1]ast.Node.Index = undefined; |
| 3943 | dest_type: zir.Inst.Ref, | 4228 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(&params, fn_proto)) catch |err| switch (err) { |
| 3944 | ) InnerError!zir.Inst.Ref { | 4229 | error.OutOfMemory => return error.OutOfMemory, |
| 3945 | // Detect whether this expr() call goes into rvalue() to store the result into the | 4230 | error.AnalysisFail => {}, |
| 3946 | // result location. If it does, elide the coerce_result_ptr instruction | 4231 | }; |
| 3947 | // as well as the store instruction, instead passing the result as an rvalue. | 4232 | continue; |
| 3948 | const astgen = parent_gz.astgen; | 4233 | }, |
| 4234 | .fn_proto_multi => { | ||
| 4235 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { | ||
| 4236 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4237 | error.AnalysisFail => {}, | ||
| 4238 | }; | ||
| 4239 | continue; | ||
| 4240 | }, | ||
| 4241 | .fn_proto_one => { | ||
| 4242 | var params: [1]ast.Node.Index = undefined; | ||
| 4243 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(&params, fn_proto)) catch |err| switch (err) { | ||
| 4244 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4245 | error.AnalysisFail => {}, | ||
| 4246 | }; | ||
| 4247 | continue; | ||
| 4248 | }, | ||
| 4249 | .fn_proto => { | ||
| 4250 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { | ||
| 4251 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4252 | error.AnalysisFail => {}, | ||
| 4253 | }; | ||
| 4254 | continue; | ||
| 4255 | }, | ||
| 4256 | else => unreachable, | ||
| 4257 | } | ||
| 4258 | }, | ||
| 4259 | .fn_proto_simple => { | ||
| 4260 | var params: [1]ast.Node.Index = undefined; | ||
| 4261 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(&params, member_node)) catch |err| switch (err) { | ||
| 4262 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4263 | error.AnalysisFail => {}, | ||
| 4264 | }; | ||
| 4265 | continue; | ||
| 4266 | }, | ||
| 4267 | .fn_proto_multi => { | ||
| 4268 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { | ||
| 4269 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4270 | error.AnalysisFail => {}, | ||
| 4271 | }; | ||
| 4272 | continue; | ||
| 4273 | }, | ||
| 4274 | .fn_proto_one => { | ||
| 4275 | var params: [1]ast.Node.Index = undefined; | ||
| 4276 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(&params, member_node)) catch |err| switch (err) { | ||
| 4277 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4278 | error.AnalysisFail => {}, | ||
| 4279 | }; | ||
| 4280 | continue; | ||
| 4281 | }, | ||
| 4282 | .fn_proto => { | ||
| 4283 | astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { | ||
| 4284 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4285 | error.AnalysisFail => {}, | ||
| 4286 | }; | ||
| 4287 | continue; | ||
| 4288 | }, | ||
| 3949 | 4289 | ||
| 3950 | var as_scope: GenZir = .{ | 4290 | .global_var_decl => { |
| 3951 | .parent = scope, | 4291 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { |
| 3952 | .astgen = astgen, | 4292 | error.OutOfMemory => return error.OutOfMemory, |
| 3953 | .force_comptime = parent_gz.force_comptime, | 4293 | error.AnalysisFail => {}, |
| 3954 | .instructions = .{}, | 4294 | }; |
| 3955 | }; | 4295 | continue; |
| 3956 | defer as_scope.instructions.deinit(astgen.mod.gpa); | 4296 | }, |
| 4297 | .local_var_decl => { | ||
| 4298 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { | ||
| 4299 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4300 | error.AnalysisFail => {}, | ||
| 4301 | }; | ||
| 4302 | continue; | ||
| 4303 | }, | ||
| 4304 | .simple_var_decl => { | ||
| 4305 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { | ||
| 4306 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4307 | error.AnalysisFail => {}, | ||
| 4308 | }; | ||
| 4309 | continue; | ||
| 4310 | }, | ||
| 4311 | .aligned_var_decl => { | ||
| 4312 | astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { | ||
| 4313 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4314 | error.AnalysisFail => {}, | ||
| 4315 | }; | ||
| 4316 | continue; | ||
| 4317 | }, | ||
| 3957 | 4318 | ||
| 3958 | as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); | 4319 | .@"comptime" => { |
| 3959 | const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); | 4320 | astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { |
| 3960 | const parent_zir = &parent_gz.instructions; | 4321 | error.OutOfMemory => return error.OutOfMemory, |
| 3961 | if (as_scope.rvalue_rl_count == 1) { | 4322 | error.AnalysisFail => {}, |
| 3962 | // Busted! This expression didn't actually need a pointer. | 4323 | }; |
| 3963 | const zir_tags = astgen.instructions.items(.tag); | 4324 | continue; |
| 3964 | const zir_datas = astgen.instructions.items(.data); | 4325 | }, |
| 3965 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; | 4326 | .@"usingnamespace" => { |
| 3966 | try parent_zir.ensureCapacity(astgen.mod.gpa, expected_len); | 4327 | astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { |
| 3967 | for (as_scope.instructions.items) |src_inst| { | 4328 | error.OutOfMemory => return error.OutOfMemory, |
| 3968 | if (astgen.indexToRef(src_inst) == as_scope.rl_ptr) continue; | 4329 | error.AnalysisFail => {}, |
| 3969 | if (zir_tags[src_inst] == .store_to_block_ptr) { | 4330 | }; |
| 3970 | if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; | 4331 | continue; |
| 4332 | }, | ||
| 4333 | .test_decl => { | ||
| 4334 | astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { | ||
| 4335 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4336 | error.AnalysisFail => {}, | ||
| 4337 | }; | ||
| 4338 | continue; | ||
| 4339 | }, | ||
| 4340 | else => unreachable, | ||
| 4341 | }; | ||
| 3971 | } | 4342 | } |
| 3972 | parent_zir.appendAssumeCapacity(src_inst); | 4343 | { |
| 3973 | } | 4344 | const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); |
| 3974 | assert(parent_zir.items.len == expected_len); | 4345 | if (empty_slot_count < WipDecls.fields_per_u32) { |
| 3975 | const casted_result = try parent_gz.addBin(.as, dest_type, result); | 4346 | wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); |
| 3976 | return rvalue(parent_gz, scope, rl, casted_result, operand_node); | 4347 | } |
| 3977 | } else { | 4348 | } |
| 3978 | try parent_zir.appendSlice(astgen.mod.gpa, as_scope.instructions.items); | 4349 | const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) { |
| 3979 | return result; | 4350 | .parent => .opaque_decl, |
| 3980 | } | 4351 | .anon => .opaque_decl_anon, |
| 3981 | } | 4352 | .func => .opaque_decl_func, |
| 4353 | }; | ||
| 4354 | const decl_inst = try gz.addBlock(tag, node); | ||
| 4355 | try gz.instructions.append(gpa, decl_inst); | ||
| 3982 | 4356 | ||
| 3983 | fn bitCast( | 4357 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + |
| 3984 | gz: *GenZir, | 4358 | wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + |
| 3985 | scope: *Scope, | 4359 | wip_decls.payload.items.len); |
| 3986 | rl: ResultLoc, | 4360 | const zir_datas = astgen.instructions.items(.data); |
| 3987 | node: ast.Node.Index, | 4361 | zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{ |
| 3988 | lhs: ast.Node.Index, | 4362 | .decls_len = @intCast(u32, wip_decls.decl_index), |
| 3989 | rhs: ast.Node.Index, | ||
| 3990 | ) InnerError!zir.Inst.Ref { | ||
| 3991 | const mod = gz.astgen.mod; | ||
| 3992 | const dest_type = try typeExpr(gz, scope, lhs); | ||
| 3993 | switch (rl) { | ||
| 3994 | .none, .discard, .ty => { | ||
| 3995 | const operand = try expr(gz, scope, .none, rhs); | ||
| 3996 | const result = try gz.addPlNode(.bitcast, node, zir.Inst.Bin{ | ||
| 3997 | .lhs = dest_type, | ||
| 3998 | .rhs = operand, | ||
| 3999 | }); | 4363 | }); |
| 4000 | return rvalue(gz, scope, rl, result, node); | 4364 | astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. |
| 4001 | }, | 4365 | if (wip_decls.decl_index != 0) { |
| 4002 | .ref, .none_or_ref => unreachable, // `@bitCast` is not allowed as an r-value. | 4366 | astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); |
| 4003 | .ptr => |result_ptr| { | 4367 | } |
| 4004 | const casted_result_ptr = try gz.addUnNode(.bitcast_result_ptr, result_ptr, node); | 4368 | astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); |
| 4005 | return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs); | 4369 | |
| 4006 | }, | 4370 | return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); |
| 4007 | .block_ptr => |block_ptr| { | ||
| 4008 | return mod.failNode(scope, node, "TODO implement @bitCast with result location inferred peer types", .{}); | ||
| 4009 | }, | ||
| 4010 | .inferred_ptr => |result_alloc| { | ||
| 4011 | // TODO here we should be able to resolve the inference; we now have a type for the result. | ||
| 4012 | return mod.failNode(scope, node, "TODO implement @bitCast with inferred-type result location pointer", .{}); | ||
| 4013 | }, | 4371 | }, |
| 4372 | else => unreachable, | ||
| 4014 | } | 4373 | } |
| 4015 | } | 4374 | } |
| 4016 | 4375 | ||
| 4017 | fn typeOf( | 4376 | fn errorSetDecl( |
| 4018 | gz: *GenZir, | 4377 | gz: *GenZir, |
| 4019 | scope: *Scope, | 4378 | scope: *Scope, |
| 4020 | rl: ResultLoc, | 4379 | rl: ResultLoc, |
| 4021 | node: ast.Node.Index, | 4380 | node: ast.Node.Index, |
| 4022 | params: []const ast.Node.Index, | 4381 | ) InnerError!Zir.Inst.Ref { |
| 4023 | ) InnerError!zir.Inst.Ref { | 4382 | const astgen = gz.astgen; |
| 4024 | if (params.len < 1) { | 4383 | const gpa = astgen.gpa; |
| 4025 | return gz.astgen.mod.failNode(scope, node, "expected at least 1 argument, found 0", .{}); | 4384 | const tree = astgen.tree; |
| 4026 | } | 4385 | const main_tokens = tree.nodes.items(.main_token); |
| 4027 | if (params.len == 1) { | 4386 | const token_tags = tree.tokens.items(.tag); |
| 4028 | const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node); | 4387 | |
| 4029 | return rvalue(gz, scope, rl, result, node); | 4388 | var field_names: std.ArrayListUnmanaged(u32) = .{}; |
| 4030 | } | 4389 | defer field_names.deinit(gpa); |
| 4031 | const arena = gz.astgen.arena; | 4390 | |
| 4032 | var items = try arena.alloc(zir.Inst.Ref, params.len); | 4391 | { |
| 4033 | for (params) |param, param_i| { | 4392 | const error_token = main_tokens[node]; |
| 4034 | items[param_i] = try expr(gz, scope, .none, param); | 4393 | var tok_i = error_token + 2; |
| 4394 | var field_i: usize = 0; | ||
| 4395 | while (true) : (tok_i += 1) { | ||
| 4396 | switch (token_tags[tok_i]) { | ||
| 4397 | .doc_comment, .comma => {}, | ||
| 4398 | .identifier => { | ||
| 4399 | const str_index = try astgen.identAsString(tok_i); | ||
| 4400 | try field_names.append(gpa, str_index); | ||
| 4401 | field_i += 1; | ||
| 4402 | }, | ||
| 4403 | .r_brace => break, | ||
| 4404 | else => unreachable, | ||
| 4405 | } | ||
| 4406 | } | ||
| 4035 | } | 4407 | } |
| 4036 | 4408 | ||
| 4037 | const result = try gz.addPlNode(.typeof_peer, node, zir.Inst.MultiOp{ | 4409 | const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) { |
| 4038 | .operands_len = @intCast(u32, params.len), | 4410 | .parent => .error_set_decl, |
| 4411 | .anon => .error_set_decl_anon, | ||
| 4412 | .func => .error_set_decl_func, | ||
| 4413 | }; | ||
| 4414 | const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{ | ||
| 4415 | .fields_len = @intCast(u32, field_names.items.len), | ||
| 4039 | }); | 4416 | }); |
| 4040 | try gz.astgen.appendRefs(items); | 4417 | try astgen.extra.appendSlice(gpa, field_names.items); |
| 4041 | |||
| 4042 | return rvalue(gz, scope, rl, result, node); | 4418 | return rvalue(gz, scope, rl, result, node); |
| 4043 | } | 4419 | } |
| 4044 | 4420 | ||
| 4045 | fn builtinCall( | 4421 | fn tryExpr( |
| 4046 | gz: *GenZir, | 4422 | parent_gz: *GenZir, |
| 4047 | scope: *Scope, | 4423 | scope: *Scope, |
| 4048 | rl: ResultLoc, | 4424 | rl: ResultLoc, |
| 4049 | node: ast.Node.Index, | 4425 | node: ast.Node.Index, |
| 4050 | params: []const ast.Node.Index, | 4426 | operand_node: ast.Node.Index, |
| 4051 | ) InnerError!zir.Inst.Ref { | 4427 | ) InnerError!Zir.Inst.Ref { |
| 4052 | const mod = gz.astgen.mod; | 4428 | const astgen = parent_gz.astgen; |
| 4053 | const tree = gz.tree(); | 4429 | const tree = astgen.tree; |
| 4054 | const main_tokens = tree.nodes.items(.main_token); | ||
| 4055 | 4430 | ||
| 4056 | const builtin_token = main_tokens[node]; | 4431 | const fn_block = astgen.fn_block orelse { |
| 4057 | const builtin_name = tree.tokenSlice(builtin_token); | 4432 | return astgen.failNode(node, "invalid 'try' outside function scope", .{}); |
| 4433 | }; | ||
| 4058 | 4434 | ||
| 4059 | // We handle the different builtins manually because they have different semantics depending | 4435 | var block_scope = parent_gz.makeSubBlock(scope); |
| 4060 | // on the function. For example, `@as` and others participate in result location semantics, | 4436 | block_scope.setBreakResultLoc(rl); |
| 4061 | // and `@cImport` creates a special scope that collects a .c source code text buffer. | 4437 | defer block_scope.instructions.deinit(astgen.gpa); |
| 4062 | // Also, some builtins have a variable number of parameters. | ||
| 4063 | 4438 | ||
| 4064 | const info = BuiltinFn.list.get(builtin_name) orelse { | 4439 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 4065 | return mod.failNode(scope, node, "invalid builtin function: '{s}'", .{ | 4440 | .ref => .ref, |
| 4066 | builtin_name, | 4441 | else => .none, |
| 4067 | }); | ||
| 4068 | }; | 4442 | }; |
| 4069 | if (info.param_count) |expected| { | 4443 | const err_ops = switch (rl) { |
| 4070 | if (expected != params.len) { | 4444 | // zig fmt: off |
| 4071 | const s = if (expected == 1) "" else "s"; | 4445 | .ref => [3]Zir.Inst.Tag{ .is_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr }, |
| 4072 | return mod.failNode(scope, node, "expected {d} parameter{s}, found {d}", .{ | 4446 | else => [3]Zir.Inst.Tag{ .is_err, .err_union_code, .err_union_payload_unsafe }, |
| 4073 | expected, s, params.len, | 4447 | // zig fmt: on |
| 4074 | }); | 4448 | }; |
| 4075 | } | 4449 | // This could be a pointer or value depending on the `operand_rl` parameter. |
| 4076 | } | 4450 | // We cannot use `block_scope.break_result_loc` because that has the bare |
| 4077 | 4451 | // type, whereas this expression has the optional type. Later we make | |
| 4078 | switch (info.tag) { | 4452 | // up for this fact by calling rvalue on the else branch. |
| 4079 | .ptr_to_int => { | 4453 | const operand = try expr(&block_scope, &block_scope.base, operand_rl, operand_node); |
| 4080 | const operand = try expr(gz, scope, .none, params[0]); | 4454 | const cond = try block_scope.addUnNode(err_ops[0], operand, node); |
| 4081 | const result = try gz.addUnNode(.ptrtoint, operand, node); | 4455 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 4082 | return rvalue(gz, scope, rl, result, node); | ||
| 4083 | }, | ||
| 4084 | .float_cast => { | ||
| 4085 | const dest_type = try typeExpr(gz, scope, params[0]); | ||
| 4086 | const rhs = try expr(gz, scope, .none, params[1]); | ||
| 4087 | const result = try gz.addPlNode(.floatcast, node, zir.Inst.Bin{ | ||
| 4088 | .lhs = dest_type, | ||
| 4089 | .rhs = rhs, | ||
| 4090 | }); | ||
| 4091 | return rvalue(gz, scope, rl, result, node); | ||
| 4092 | }, | ||
| 4093 | .int_cast => { | ||
| 4094 | const dest_type = try typeExpr(gz, scope, params[0]); | ||
| 4095 | const rhs = try expr(gz, scope, .none, params[1]); | ||
| 4096 | const result = try gz.addPlNode(.intcast, node, zir.Inst.Bin{ | ||
| 4097 | .lhs = dest_type, | ||
| 4098 | .rhs = rhs, | ||
| 4099 | }); | ||
| 4100 | return rvalue(gz, scope, rl, result, node); | ||
| 4101 | }, | ||
| 4102 | .breakpoint => { | ||
| 4103 | _ = try gz.add(.{ | ||
| 4104 | .tag = .breakpoint, | ||
| 4105 | .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) }, | ||
| 4106 | }); | ||
| 4107 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 4108 | }, | ||
| 4109 | .import => { | ||
| 4110 | const target = try expr(gz, scope, .none, params[0]); | ||
| 4111 | const result = try gz.addUnNode(.import, target, node); | ||
| 4112 | return rvalue(gz, scope, rl, result, node); | ||
| 4113 | }, | ||
| 4114 | .error_to_int => { | ||
| 4115 | const target = try expr(gz, scope, .none, params[0]); | ||
| 4116 | const result = try gz.addUnNode(.error_to_int, target, node); | ||
| 4117 | return rvalue(gz, scope, rl, result, node); | ||
| 4118 | }, | ||
| 4119 | .int_to_error => { | ||
| 4120 | const target = try expr(gz, scope, .{ .ty = .u16_type }, params[0]); | ||
| 4121 | const result = try gz.addUnNode(.int_to_error, target, node); | ||
| 4122 | return rvalue(gz, scope, rl, result, node); | ||
| 4123 | }, | ||
| 4124 | .compile_error => { | ||
| 4125 | const target = try expr(gz, scope, .none, params[0]); | ||
| 4126 | const result = try gz.addUnNode(.compile_error, target, node); | ||
| 4127 | return rvalue(gz, scope, rl, result, node); | ||
| 4128 | }, | ||
| 4129 | .set_eval_branch_quota => { | ||
| 4130 | const quota = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); | ||
| 4131 | const result = try gz.addUnNode(.set_eval_branch_quota, quota, node); | ||
| 4132 | return rvalue(gz, scope, rl, result, node); | ||
| 4133 | }, | ||
| 4134 | .compile_log => { | ||
| 4135 | const arg_refs = try mod.gpa.alloc(zir.Inst.Ref, params.len); | ||
| 4136 | defer mod.gpa.free(arg_refs); | ||
| 4137 | |||
| 4138 | for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param); | ||
| 4139 | |||
| 4140 | const result = try gz.addPlNode(.compile_log, node, zir.Inst.MultiOp{ | ||
| 4141 | .operands_len = @intCast(u32, params.len), | ||
| 4142 | }); | ||
| 4143 | try gz.astgen.appendRefs(arg_refs); | ||
| 4144 | return rvalue(gz, scope, rl, result, node); | ||
| 4145 | }, | ||
| 4146 | .field => { | ||
| 4147 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | ||
| 4148 | if (rl == .ref) { | ||
| 4149 | return try gz.addPlNode(.field_ptr_named, node, zir.Inst.FieldNamed{ | ||
| 4150 | .lhs = try expr(gz, scope, .ref, params[0]), | ||
| 4151 | .field_name = field_name, | ||
| 4152 | }); | ||
| 4153 | } | ||
| 4154 | const result = try gz.addPlNode(.field_val_named, node, zir.Inst.FieldNamed{ | ||
| 4155 | .lhs = try expr(gz, scope, .none, params[0]), | ||
| 4156 | .field_name = field_name, | ||
| 4157 | }); | ||
| 4158 | return rvalue(gz, scope, rl, result, node); | ||
| 4159 | }, | ||
| 4160 | .as => return as(gz, scope, rl, node, params[0], params[1]), | ||
| 4161 | .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]), | ||
| 4162 | .TypeOf => return typeOf(gz, scope, rl, node, params), | ||
| 4163 | |||
| 4164 | .int_to_enum => { | ||
| 4165 | const result = try gz.addPlNode(.int_to_enum, node, zir.Inst.Bin{ | ||
| 4166 | .lhs = try typeExpr(gz, scope, params[0]), | ||
| 4167 | .rhs = try expr(gz, scope, .none, params[1]), | ||
| 4168 | }); | ||
| 4169 | return rvalue(gz, scope, rl, result, node); | ||
| 4170 | }, | ||
| 4171 | 4456 | ||
| 4172 | .enum_to_int => { | 4457 | const block = try parent_gz.addBlock(.block, node); |
| 4173 | const operand = try expr(gz, scope, .none, params[0]); | 4458 | try parent_gz.instructions.append(astgen.gpa, block); |
| 4174 | const result = try gz.addUnNode(.enum_to_int, operand, node); | 4459 | try block_scope.setBlockBody(block); |
| 4175 | return rvalue(gz, scope, rl, result, node); | ||
| 4176 | }, | ||
| 4177 | 4460 | ||
| 4178 | .@"export" => { | 4461 | var then_scope = parent_gz.makeSubBlock(scope); |
| 4179 | // TODO: @export is supposed to be able to export things other than functions. | 4462 | defer then_scope.instructions.deinit(astgen.gpa); |
| 4180 | // Instead of `comptimeExpr` here we need `decl_ref`. | ||
| 4181 | const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]); | ||
| 4182 | // TODO: the second parameter here is supposed to be | ||
| 4183 | // `std.builtin.ExportOptions`, not a string. | ||
| 4184 | const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | ||
| 4185 | _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{ | ||
| 4186 | .lhs = fn_to_export, | ||
| 4187 | .rhs = export_name, | ||
| 4188 | }); | ||
| 4189 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 4190 | }, | ||
| 4191 | 4463 | ||
| 4192 | .has_decl => { | 4464 | const err_code = try then_scope.addUnNode(err_ops[1], operand, node); |
| 4193 | const container_type = try typeExpr(gz, scope, params[0]); | 4465 | try genDefers(&then_scope, &fn_block.base, scope, err_code); |
| 4194 | const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | 4466 | const then_result = try then_scope.addUnNode(.ret_node, err_code, node); |
| 4195 | const result = try gz.addPlNode(.has_decl, node, zir.Inst.Bin{ | ||
| 4196 | .lhs = container_type, | ||
| 4197 | .rhs = name, | ||
| 4198 | }); | ||
| 4199 | return rvalue(gz, scope, rl, result, node); | ||
| 4200 | }, | ||
| 4201 | 4467 | ||
| 4202 | .type_info => { | 4468 | var else_scope = parent_gz.makeSubBlock(scope); |
| 4203 | const operand = try typeExpr(gz, scope, params[0]); | 4469 | defer else_scope.instructions.deinit(astgen.gpa); |
| 4204 | const result = try gz.addUnNode(.type_info, operand, node); | ||
| 4205 | return rvalue(gz, scope, rl, result, node); | ||
| 4206 | }, | ||
| 4207 | 4470 | ||
| 4208 | .add_with_overflow, | 4471 | block_scope.break_count += 1; |
| 4209 | .align_cast, | 4472 | // This could be a pointer or value depending on `err_ops[2]`. |
| 4210 | .align_of, | 4473 | const unwrapped_payload = try else_scope.addUnNode(err_ops[2], operand, node); |
| 4211 | .atomic_load, | 4474 | const else_result = switch (rl) { |
| 4212 | .atomic_rmw, | 4475 | .ref => unwrapped_payload, |
| 4213 | .atomic_store, | 4476 | else => try rvalue(&else_scope, &else_scope.base, block_scope.break_result_loc, unwrapped_payload, node), |
| 4214 | .bit_offset_of, | 4477 | }; |
| 4215 | .bool_to_int, | ||
| 4216 | .bit_size_of, | ||
| 4217 | .mul_add, | ||
| 4218 | .byte_swap, | ||
| 4219 | .bit_reverse, | ||
| 4220 | .byte_offset_of, | ||
| 4221 | .call, | ||
| 4222 | .c_define, | ||
| 4223 | .c_import, | ||
| 4224 | .c_include, | ||
| 4225 | .clz, | ||
| 4226 | .cmpxchg_strong, | ||
| 4227 | .cmpxchg_weak, | ||
| 4228 | .ctz, | ||
| 4229 | .c_undef, | ||
| 4230 | .div_exact, | ||
| 4231 | .div_floor, | ||
| 4232 | .div_trunc, | ||
| 4233 | .embed_file, | ||
| 4234 | .error_name, | ||
| 4235 | .error_return_trace, | ||
| 4236 | .err_set_cast, | ||
| 4237 | .fence, | ||
| 4238 | .field_parent_ptr, | ||
| 4239 | .float_to_int, | ||
| 4240 | .has_field, | ||
| 4241 | .int_to_float, | ||
| 4242 | .int_to_ptr, | ||
| 4243 | .memcpy, | ||
| 4244 | .memset, | ||
| 4245 | .wasm_memory_size, | ||
| 4246 | .wasm_memory_grow, | ||
| 4247 | .mod, | ||
| 4248 | .mul_with_overflow, | ||
| 4249 | .panic, | ||
| 4250 | .pop_count, | ||
| 4251 | .ptr_cast, | ||
| 4252 | .rem, | ||
| 4253 | .return_address, | ||
| 4254 | .set_align_stack, | ||
| 4255 | .set_cold, | ||
| 4256 | .set_float_mode, | ||
| 4257 | .set_runtime_safety, | ||
| 4258 | .shl_exact, | ||
| 4259 | .shl_with_overflow, | ||
| 4260 | .shr_exact, | ||
| 4261 | .shuffle, | ||
| 4262 | .size_of, | ||
| 4263 | .splat, | ||
| 4264 | .reduce, | ||
| 4265 | .src, | ||
| 4266 | .sqrt, | ||
| 4267 | .sin, | ||
| 4268 | .cos, | ||
| 4269 | .exp, | ||
| 4270 | .exp2, | ||
| 4271 | .log, | ||
| 4272 | .log2, | ||
| 4273 | .log10, | ||
| 4274 | .fabs, | ||
| 4275 | .floor, | ||
| 4276 | .ceil, | ||
| 4277 | .trunc, | ||
| 4278 | .round, | ||
| 4279 | .sub_with_overflow, | ||
| 4280 | .tag_name, | ||
| 4281 | .This, | ||
| 4282 | .truncate, | ||
| 4283 | .Type, | ||
| 4284 | .type_name, | ||
| 4285 | .union_init, | ||
| 4286 | => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{ | ||
| 4287 | builtin_name, | ||
| 4288 | }), | ||
| 4289 | 4478 | ||
| 4290 | .async_call, | 4479 | return finishThenElseBlock( |
| 4291 | .frame, | 4480 | parent_gz, |
| 4292 | .Frame, | 4481 | scope, |
| 4293 | .frame_address, | 4482 | rl, |
| 4294 | .frame_size, | 4483 | node, |
| 4295 | => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 4484 | &block_scope, |
| 4296 | } | 4485 | &then_scope, |
| 4486 | &else_scope, | ||
| 4487 | condbr, | ||
| 4488 | cond, | ||
| 4489 | node, | ||
| 4490 | node, | ||
| 4491 | then_result, | ||
| 4492 | else_result, | ||
| 4493 | block, | ||
| 4494 | block, | ||
| 4495 | .@"break", | ||
| 4496 | ); | ||
| 4297 | } | 4497 | } |
| 4298 | 4498 | ||
| 4299 | fn callExpr( | 4499 | fn orelseCatchExpr( |
| 4300 | gz: *GenZir, | 4500 | parent_gz: *GenZir, |
| 4301 | scope: *Scope, | 4501 | scope: *Scope, |
| 4302 | rl: ResultLoc, | 4502 | rl: ResultLoc, |
| 4303 | node: ast.Node.Index, | 4503 | node: ast.Node.Index, |
| 4304 | call: ast.full.Call, | 4504 | lhs: ast.Node.Index, |
| 4305 | ) InnerError!zir.Inst.Ref { | 4505 | cond_op: Zir.Inst.Tag, |
| 4306 | const mod = gz.astgen.mod; | 4506 | unwrap_op: Zir.Inst.Tag, |
| 4307 | if (call.async_token) |async_token| { | 4507 | unwrap_code_op: Zir.Inst.Tag, |
| 4308 | return mod.failTok(scope, async_token, "async and related features are not yet supported", .{}); | 4508 | rhs: ast.Node.Index, |
| 4309 | } | 4509 | payload_token: ?ast.TokenIndex, |
| 4310 | const lhs = try expr(gz, scope, .none, call.ast.fn_expr); | 4510 | ) InnerError!Zir.Inst.Ref { |
| 4311 | 4511 | const astgen = parent_gz.astgen; | |
| 4312 | const args = try mod.gpa.alloc(zir.Inst.Ref, call.ast.params.len); | 4512 | const tree = astgen.tree; |
| 4313 | defer mod.gpa.free(args); | ||
| 4314 | 4513 | ||
| 4315 | for (call.ast.params) |param_node, i| { | 4514 | var block_scope = parent_gz.makeSubBlock(scope); |
| 4316 | const param_type = try gz.add(.{ | 4515 | block_scope.setBreakResultLoc(rl); |
| 4317 | .tag = .param_type, | 4516 | defer block_scope.instructions.deinit(astgen.gpa); |
| 4318 | .data = .{ .param_type = .{ | ||
| 4319 | .callee = lhs, | ||
| 4320 | .param_index = @intCast(u32, i), | ||
| 4321 | } }, | ||
| 4322 | }); | ||
| 4323 | args[i] = try expr(gz, scope, .{ .ty = param_type }, param_node); | ||
| 4324 | } | ||
| 4325 | 4517 | ||
| 4326 | const modifier: std.builtin.CallOptions.Modifier = switch (call.async_token != null) { | 4518 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 4327 | true => .async_kw, | 4519 | .ref => .ref, |
| 4328 | false => .auto, | 4520 | else => .none, |
| 4329 | }; | 4521 | }; |
| 4330 | const result: zir.Inst.Ref = res: { | 4522 | block_scope.break_count += 1; |
| 4331 | const tag: zir.Inst.Tag = switch (modifier) { | 4523 | // This could be a pointer or value depending on the `operand_rl` parameter. |
| 4332 | .auto => switch (args.len == 0) { | 4524 | // We cannot use `block_scope.break_result_loc` because that has the bare |
| 4333 | true => break :res try gz.addUnNode(.call_none, lhs, node), | 4525 | // type, whereas this expression has the optional type. Later we make |
| 4334 | false => .call, | 4526 | // up for this fact by calling rvalue on the else branch. |
| 4335 | }, | 4527 | const operand = try expr(&block_scope, &block_scope.base, operand_rl, lhs); |
| 4336 | .async_kw => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 4528 | const cond = try block_scope.addUnNode(cond_op, operand, node); |
| 4337 | .never_tail => unreachable, | 4529 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 4338 | .never_inline => unreachable, | 4530 | |
| 4339 | .no_async => return mod.failNode(scope, node, "async and related features are not yet supported", .{}), | 4531 | const block = try parent_gz.addBlock(.block, node); |
| 4340 | .always_tail => unreachable, | 4532 | try parent_gz.instructions.append(astgen.gpa, block); |
| 4341 | .always_inline => unreachable, | 4533 | try block_scope.setBlockBody(block); |
| 4342 | .compile_time => .call_compile_time, | 4534 | |
| 4535 | var then_scope = parent_gz.makeSubBlock(scope); | ||
| 4536 | defer then_scope.instructions.deinit(astgen.gpa); | ||
| 4537 | |||
| 4538 | var err_val_scope: Scope.LocalVal = undefined; | ||
| 4539 | const then_sub_scope = blk: { | ||
| 4540 | const payload = payload_token orelse break :blk &then_scope.base; | ||
| 4541 | if (mem.eql(u8, tree.tokenSlice(payload), "_")) { | ||
| 4542 | return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); | ||
| 4543 | } | ||
| 4544 | const err_name = try astgen.identAsString(payload); | ||
| 4545 | err_val_scope = .{ | ||
| 4546 | .parent = &then_scope.base, | ||
| 4547 | .gen_zir = &then_scope, | ||
| 4548 | .name = err_name, | ||
| 4549 | .inst = try then_scope.addUnNode(unwrap_code_op, operand, node), | ||
| 4550 | .token_src = payload, | ||
| 4343 | }; | 4551 | }; |
| 4344 | break :res try gz.addCall(tag, lhs, args, node); | 4552 | break :blk &err_val_scope.base; |
| 4345 | }; | 4553 | }; |
| 4346 | return rvalue(gz, scope, rl, result, node); // TODO function call with result location | ||
| 4347 | } | ||
| 4348 | 4554 | ||
| 4349 | pub const simple_types = std.ComptimeStringMap(zir.Inst.Ref, .{ | 4555 | block_scope.break_count += 1; |
| 4350 | .{ "u8", .u8_type }, | 4556 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, rhs); |
| 4351 | .{ "i8", .i8_type }, | 4557 | // We hold off on the break instructions as well as copying the then/else |
| 4352 | .{ "u16", .u16_type }, | 4558 | // instructions into place until we know whether to keep store_to_block_ptr |
| 4353 | .{ "i16", .i16_type }, | 4559 | // instructions or not. |
| 4354 | .{ "u32", .u32_type }, | ||
| 4355 | .{ "i32", .i32_type }, | ||
| 4356 | .{ "u64", .u64_type }, | ||
| 4357 | .{ "i64", .i64_type }, | ||
| 4358 | .{ "usize", .usize_type }, | ||
| 4359 | .{ "isize", .isize_type }, | ||
| 4360 | .{ "c_short", .c_short_type }, | ||
| 4361 | .{ "c_ushort", .c_ushort_type }, | ||
| 4362 | .{ "c_int", .c_int_type }, | ||
| 4363 | .{ "c_uint", .c_uint_type }, | ||
| 4364 | .{ "c_long", .c_long_type }, | ||
| 4365 | .{ "c_ulong", .c_ulong_type }, | ||
| 4366 | .{ "c_longlong", .c_longlong_type }, | ||
| 4367 | .{ "c_ulonglong", .c_ulonglong_type }, | ||
| 4368 | .{ "c_longdouble", .c_longdouble_type }, | ||
| 4369 | .{ "f16", .f16_type }, | ||
| 4370 | .{ "f32", .f32_type }, | ||
| 4371 | .{ "f64", .f64_type }, | ||
| 4372 | .{ "f128", .f128_type }, | ||
| 4373 | .{ "c_void", .c_void_type }, | ||
| 4374 | .{ "bool", .bool_type }, | ||
| 4375 | .{ "void", .void_type }, | ||
| 4376 | .{ "type", .type_type }, | ||
| 4377 | .{ "anyerror", .anyerror_type }, | ||
| 4378 | .{ "comptime_int", .comptime_int_type }, | ||
| 4379 | .{ "comptime_float", .comptime_float_type }, | ||
| 4380 | .{ "noreturn", .noreturn_type }, | ||
| 4381 | .{ "null", .null_type }, | ||
| 4382 | .{ "undefined", .undefined_type }, | ||
| 4383 | .{ "undefined", .undef }, | ||
| 4384 | .{ "null", .null_value }, | ||
| 4385 | .{ "true", .bool_true }, | ||
| 4386 | .{ "false", .bool_false }, | ||
| 4387 | }); | ||
| 4388 | 4560 | ||
| 4389 | fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool { | 4561 | var else_scope = parent_gz.makeSubBlock(scope); |
| 4390 | const node_tags = tree.nodes.items(.tag); | 4562 | defer else_scope.instructions.deinit(astgen.gpa); |
| 4391 | const node_datas = tree.nodes.items(.data); | ||
| 4392 | const main_tokens = tree.nodes.items(.main_token); | ||
| 4393 | const token_tags = tree.tokens.items(.tag); | ||
| 4394 | 4563 | ||
| 4395 | var node = start_node; | 4564 | // This could be a pointer or value depending on `unwrap_op`. |
| 4396 | while (true) { | 4565 | const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node); |
| 4397 | switch (node_tags[node]) { | 4566 | const else_result = switch (rl) { |
| 4398 | .root, | 4567 | .ref => unwrapped_payload, |
| 4399 | .@"usingnamespace", | 4568 | else => try rvalue(&else_scope, &else_scope.base, block_scope.break_result_loc, unwrapped_payload, node), |
| 4400 | .test_decl, | 4569 | }; |
| 4401 | .switch_case, | ||
| 4402 | .switch_case_one, | ||
| 4403 | .container_field_init, | ||
| 4404 | .container_field_align, | ||
| 4405 | .container_field, | ||
| 4406 | .asm_output, | ||
| 4407 | .asm_input, | ||
| 4408 | => unreachable, | ||
| 4409 | 4570 | ||
| 4410 | .@"return", | 4571 | return finishThenElseBlock( |
| 4411 | .@"break", | 4572 | parent_gz, |
| 4412 | .@"continue", | 4573 | scope, |
| 4413 | .bit_not, | 4574 | rl, |
| 4414 | .bool_not, | 4575 | node, |
| 4415 | .global_var_decl, | 4576 | &block_scope, |
| 4416 | .local_var_decl, | 4577 | &then_scope, |
| 4417 | .simple_var_decl, | 4578 | &else_scope, |
| 4418 | .aligned_var_decl, | 4579 | condbr, |
| 4419 | .@"defer", | 4580 | cond, |
| 4420 | .@"errdefer", | 4581 | node, |
| 4421 | .address_of, | 4582 | node, |
| 4422 | .optional_type, | 4583 | then_result, |
| 4423 | .negation, | 4584 | else_result, |
| 4424 | .negation_wrap, | 4585 | block, |
| 4425 | .@"resume", | 4586 | block, |
| 4426 | .array_type, | 4587 | .@"break", |
| 4427 | .array_type_sentinel, | 4588 | ); |
| 4428 | .ptr_type_aligned, | 4589 | } |
| 4429 | .ptr_type_sentinel, | 4590 | |
| 4430 | .ptr_type, | 4591 | fn finishThenElseBlock( |
| 4431 | .ptr_type_bit_range, | 4592 | parent_gz: *GenZir, |
| 4432 | .@"suspend", | 4593 | parent_scope: *Scope, |
| 4433 | .@"anytype", | 4594 | rl: ResultLoc, |
| 4434 | .fn_proto_simple, | 4595 | node: ast.Node.Index, |
| 4435 | .fn_proto_multi, | 4596 | block_scope: *GenZir, |
| 4436 | .fn_proto_one, | 4597 | then_scope: *GenZir, |
| 4437 | .fn_proto, | 4598 | else_scope: *GenZir, |
| 4438 | .fn_decl, | 4599 | condbr: Zir.Inst.Index, |
| 4439 | .anyframe_type, | 4600 | cond: Zir.Inst.Ref, |
| 4601 | then_src: ast.Node.Index, | ||
| 4602 | else_src: ast.Node.Index, | ||
| 4603 | then_result: Zir.Inst.Ref, | ||
| 4604 | else_result: Zir.Inst.Ref, | ||
| 4605 | main_block: Zir.Inst.Index, | ||
| 4606 | then_break_block: Zir.Inst.Index, | ||
| 4607 | break_tag: Zir.Inst.Tag, | ||
| 4608 | ) InnerError!Zir.Inst.Ref { | ||
| 4609 | // We now have enough information to decide whether the result instruction should | ||
| 4610 | // be communicated via result location pointer or break instructions. | ||
| 4611 | const strat = rl.strategy(block_scope); | ||
| 4612 | const astgen = block_scope.astgen; | ||
| 4613 | switch (strat.tag) { | ||
| 4614 | .break_void => { | ||
| 4615 | if (!parent_gz.refIsNoReturn(then_result)) { | ||
| 4616 | _ = try then_scope.addBreak(break_tag, then_break_block, .void_value); | ||
| 4617 | } | ||
| 4618 | const elide_else = if (else_result != .none) parent_gz.refIsNoReturn(else_result) else false; | ||
| 4619 | if (!elide_else) { | ||
| 4620 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); | ||
| 4621 | } | ||
| 4622 | assert(!strat.elide_store_to_block_ptr_instructions); | ||
| 4623 | try setCondBrPayload(condbr, cond, then_scope, else_scope); | ||
| 4624 | return parent_gz.indexToRef(main_block); | ||
| 4625 | }, | ||
| 4626 | .break_operand => { | ||
| 4627 | if (!parent_gz.refIsNoReturn(then_result)) { | ||
| 4628 | _ = try then_scope.addBreak(break_tag, then_break_block, then_result); | ||
| 4629 | } | ||
| 4630 | if (else_result != .none) { | ||
| 4631 | if (!parent_gz.refIsNoReturn(else_result)) { | ||
| 4632 | _ = try else_scope.addBreak(break_tag, main_block, else_result); | ||
| 4633 | } | ||
| 4634 | } else { | ||
| 4635 | _ = try else_scope.addBreak(break_tag, main_block, .void_value); | ||
| 4636 | } | ||
| 4637 | if (strat.elide_store_to_block_ptr_instructions) { | ||
| 4638 | try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope, block_scope.rl_ptr); | ||
| 4639 | } else { | ||
| 4640 | try setCondBrPayload(condbr, cond, then_scope, else_scope); | ||
| 4641 | } | ||
| 4642 | const block_ref = parent_gz.indexToRef(main_block); | ||
| 4643 | switch (rl) { | ||
| 4644 | .ref => return block_ref, | ||
| 4645 | else => return rvalue(parent_gz, parent_scope, rl, block_ref, node), | ||
| 4646 | } | ||
| 4647 | }, | ||
| 4648 | } | ||
| 4649 | } | ||
| 4650 | |||
| 4651 | /// Return whether the identifier names of two tokens are equal. Resolves @"" | ||
| 4652 | /// tokens without allocating. | ||
| 4653 | /// OK in theory it could do it without allocating. This implementation | ||
| 4654 | /// allocates when the @"" form is used. | ||
| 4655 | fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { | ||
| 4656 | const ident_name_1 = try astgen.identifierTokenString(token1); | ||
| 4657 | const ident_name_2 = try astgen.identifierTokenString(token2); | ||
| 4658 | return mem.eql(u8, ident_name_1, ident_name_2); | ||
| 4659 | } | ||
| 4660 | |||
| 4661 | fn fieldAccess( | ||
| 4662 | gz: *GenZir, | ||
| 4663 | scope: *Scope, | ||
| 4664 | rl: ResultLoc, | ||
| 4665 | node: ast.Node.Index, | ||
| 4666 | ) InnerError!Zir.Inst.Ref { | ||
| 4667 | const astgen = gz.astgen; | ||
| 4668 | const tree = astgen.tree; | ||
| 4669 | const main_tokens = tree.nodes.items(.main_token); | ||
| 4670 | const node_datas = tree.nodes.items(.data); | ||
| 4671 | |||
| 4672 | const object_node = node_datas[node].lhs; | ||
| 4673 | const dot_token = main_tokens[node]; | ||
| 4674 | const field_ident = dot_token + 1; | ||
| 4675 | const str_index = try astgen.identAsString(field_ident); | ||
| 4676 | switch (rl) { | ||
| 4677 | .ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{ | ||
| 4678 | .lhs = try expr(gz, scope, .ref, object_node), | ||
| 4679 | .field_name_start = str_index, | ||
| 4680 | }), | ||
| 4681 | else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, Zir.Inst.Field{ | ||
| 4682 | .lhs = try expr(gz, scope, .none_or_ref, object_node), | ||
| 4683 | .field_name_start = str_index, | ||
| 4684 | }), node), | ||
| 4685 | } | ||
| 4686 | } | ||
| 4687 | |||
| 4688 | fn arrayAccess( | ||
| 4689 | gz: *GenZir, | ||
| 4690 | scope: *Scope, | ||
| 4691 | rl: ResultLoc, | ||
| 4692 | node: ast.Node.Index, | ||
| 4693 | ) InnerError!Zir.Inst.Ref { | ||
| 4694 | const astgen = gz.astgen; | ||
| 4695 | const tree = astgen.tree; | ||
| 4696 | const main_tokens = tree.nodes.items(.main_token); | ||
| 4697 | const node_datas = tree.nodes.items(.data); | ||
| 4698 | switch (rl) { | ||
| 4699 | .ref => return gz.addBin( | ||
| 4700 | .elem_ptr, | ||
| 4701 | try expr(gz, scope, .ref, node_datas[node].lhs), | ||
| 4702 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | ||
| 4703 | ), | ||
| 4704 | else => return rvalue(gz, scope, rl, try gz.addBin( | ||
| 4705 | .elem_val, | ||
| 4706 | try expr(gz, scope, .none_or_ref, node_datas[node].lhs), | ||
| 4707 | try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | ||
| 4708 | ), node), | ||
| 4709 | } | ||
| 4710 | } | ||
| 4711 | |||
| 4712 | fn simpleBinOp( | ||
| 4713 | gz: *GenZir, | ||
| 4714 | scope: *Scope, | ||
| 4715 | rl: ResultLoc, | ||
| 4716 | node: ast.Node.Index, | ||
| 4717 | op_inst_tag: Zir.Inst.Tag, | ||
| 4718 | ) InnerError!Zir.Inst.Ref { | ||
| 4719 | const astgen = gz.astgen; | ||
| 4720 | const tree = astgen.tree; | ||
| 4721 | const node_datas = tree.nodes.items(.data); | ||
| 4722 | |||
| 4723 | const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ | ||
| 4724 | .lhs = try expr(gz, scope, .none, node_datas[node].lhs), | ||
| 4725 | .rhs = try expr(gz, scope, .none, node_datas[node].rhs), | ||
| 4726 | }); | ||
| 4727 | return rvalue(gz, scope, rl, result, node); | ||
| 4728 | } | ||
| 4729 | |||
| 4730 | fn simpleStrTok( | ||
| 4731 | gz: *GenZir, | ||
| 4732 | scope: *Scope, | ||
| 4733 | rl: ResultLoc, | ||
| 4734 | ident_token: ast.TokenIndex, | ||
| 4735 | node: ast.Node.Index, | ||
| 4736 | op_inst_tag: Zir.Inst.Tag, | ||
| 4737 | ) InnerError!Zir.Inst.Ref { | ||
| 4738 | const astgen = gz.astgen; | ||
| 4739 | const str_index = try astgen.identAsString(ident_token); | ||
| 4740 | const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); | ||
| 4741 | return rvalue(gz, scope, rl, result, node); | ||
| 4742 | } | ||
| 4743 | |||
| 4744 | fn boolBinOp( | ||
| 4745 | gz: *GenZir, | ||
| 4746 | scope: *Scope, | ||
| 4747 | rl: ResultLoc, | ||
| 4748 | node: ast.Node.Index, | ||
| 4749 | zir_tag: Zir.Inst.Tag, | ||
| 4750 | ) InnerError!Zir.Inst.Ref { | ||
| 4751 | const astgen = gz.astgen; | ||
| 4752 | const tree = astgen.tree; | ||
| 4753 | const node_datas = tree.nodes.items(.data); | ||
| 4754 | |||
| 4755 | const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); | ||
| 4756 | const bool_br = try gz.addBoolBr(zir_tag, lhs); | ||
| 4757 | |||
| 4758 | var rhs_scope = gz.makeSubBlock(scope); | ||
| 4759 | defer rhs_scope.instructions.deinit(gz.astgen.gpa); | ||
| 4760 | const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); | ||
| 4761 | if (!gz.refIsNoReturn(rhs)) { | ||
| 4762 | _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); | ||
| 4763 | } | ||
| 4764 | try rhs_scope.setBoolBrBody(bool_br); | ||
| 4765 | |||
| 4766 | const block_ref = gz.indexToRef(bool_br); | ||
| 4767 | return rvalue(gz, scope, rl, block_ref, node); | ||
| 4768 | } | ||
| 4769 | |||
| 4770 | fn ifExpr( | ||
| 4771 | parent_gz: *GenZir, | ||
| 4772 | scope: *Scope, | ||
| 4773 | rl: ResultLoc, | ||
| 4774 | node: ast.Node.Index, | ||
| 4775 | if_full: ast.full.If, | ||
| 4776 | ) InnerError!Zir.Inst.Ref { | ||
| 4777 | const astgen = parent_gz.astgen; | ||
| 4778 | const tree = astgen.tree; | ||
| 4779 | const token_tags = tree.tokens.items(.tag); | ||
| 4780 | |||
| 4781 | var block_scope = parent_gz.makeSubBlock(scope); | ||
| 4782 | block_scope.setBreakResultLoc(rl); | ||
| 4783 | defer block_scope.instructions.deinit(astgen.gpa); | ||
| 4784 | |||
| 4785 | const payload_is_ref = if (if_full.payload_token) |payload_token| | ||
| 4786 | token_tags[payload_token] == .asterisk | ||
| 4787 | else | ||
| 4788 | false; | ||
| 4789 | |||
| 4790 | const cond: struct { | ||
| 4791 | inst: Zir.Inst.Ref, | ||
| 4792 | bool_bit: Zir.Inst.Ref, | ||
| 4793 | } = c: { | ||
| 4794 | if (if_full.error_token) |error_token| { | ||
| 4795 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; | ||
| 4796 | const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); | ||
| 4797 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_err_ptr else .is_err; | ||
| 4798 | break :c .{ | ||
| 4799 | .inst = err_union, | ||
| 4800 | .bool_bit = try block_scope.addUnNode(tag, err_union, node), | ||
| 4801 | }; | ||
| 4802 | } else if (if_full.payload_token) |payload_token| { | ||
| 4803 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; | ||
| 4804 | const optional = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); | ||
| 4805 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; | ||
| 4806 | break :c .{ | ||
| 4807 | .inst = optional, | ||
| 4808 | .bool_bit = try block_scope.addUnNode(tag, optional, node), | ||
| 4809 | }; | ||
| 4810 | } else { | ||
| 4811 | const cond = try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr); | ||
| 4812 | break :c .{ | ||
| 4813 | .inst = cond, | ||
| 4814 | .bool_bit = cond, | ||
| 4815 | }; | ||
| 4816 | } | ||
| 4817 | }; | ||
| 4818 | |||
| 4819 | const condbr = try block_scope.addCondBr(.condbr, node); | ||
| 4820 | |||
| 4821 | const block = try parent_gz.addBlock(.block, node); | ||
| 4822 | try parent_gz.instructions.append(astgen.gpa, block); | ||
| 4823 | try block_scope.setBlockBody(block); | ||
| 4824 | |||
| 4825 | var then_scope = parent_gz.makeSubBlock(scope); | ||
| 4826 | defer then_scope.instructions.deinit(astgen.gpa); | ||
| 4827 | |||
| 4828 | var payload_val_scope: Scope.LocalVal = undefined; | ||
| 4829 | |||
| 4830 | const then_sub_scope = s: { | ||
| 4831 | if (if_full.error_token) |error_token| { | ||
| 4832 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 4833 | .err_union_payload_unsafe_ptr | ||
| 4834 | else | ||
| 4835 | .err_union_payload_unsafe; | ||
| 4836 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | ||
| 4837 | const ident_name = try astgen.identAsString(error_token); | ||
| 4838 | payload_val_scope = .{ | ||
| 4839 | .parent = &then_scope.base, | ||
| 4840 | .gen_zir = &then_scope, | ||
| 4841 | .name = ident_name, | ||
| 4842 | .inst = payload_inst, | ||
| 4843 | .token_src = error_token, | ||
| 4844 | }; | ||
| 4845 | break :s &payload_val_scope.base; | ||
| 4846 | } else if (if_full.payload_token) |payload_token| { | ||
| 4847 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; | ||
| 4848 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 4849 | .optional_payload_unsafe_ptr | ||
| 4850 | else | ||
| 4851 | .optional_payload_unsafe; | ||
| 4852 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | ||
| 4853 | const ident_name = try astgen.identAsString(ident_token); | ||
| 4854 | payload_val_scope = .{ | ||
| 4855 | .parent = &then_scope.base, | ||
| 4856 | .gen_zir = &then_scope, | ||
| 4857 | .name = ident_name, | ||
| 4858 | .inst = payload_inst, | ||
| 4859 | .token_src = ident_token, | ||
| 4860 | }; | ||
| 4861 | break :s &payload_val_scope.base; | ||
| 4862 | } else { | ||
| 4863 | break :s &then_scope.base; | ||
| 4864 | } | ||
| 4865 | }; | ||
| 4866 | |||
| 4867 | block_scope.break_count += 1; | ||
| 4868 | const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); | ||
| 4869 | // We hold off on the break instructions as well as copying the then/else | ||
| 4870 | // instructions into place until we know whether to keep store_to_block_ptr | ||
| 4871 | // instructions or not. | ||
| 4872 | |||
| 4873 | var else_scope = parent_gz.makeSubBlock(scope); | ||
| 4874 | defer else_scope.instructions.deinit(astgen.gpa); | ||
| 4875 | |||
| 4876 | const else_node = if_full.ast.else_expr; | ||
| 4877 | const else_info: struct { | ||
| 4878 | src: ast.Node.Index, | ||
| 4879 | result: Zir.Inst.Ref, | ||
| 4880 | } = if (else_node != 0) blk: { | ||
| 4881 | block_scope.break_count += 1; | ||
| 4882 | const sub_scope = s: { | ||
| 4883 | if (if_full.error_token) |error_token| { | ||
| 4884 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 4885 | .err_union_code_ptr | ||
| 4886 | else | ||
| 4887 | .err_union_code; | ||
| 4888 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); | ||
| 4889 | const ident_name = try astgen.identAsString(error_token); | ||
| 4890 | payload_val_scope = .{ | ||
| 4891 | .parent = &else_scope.base, | ||
| 4892 | .gen_zir = &else_scope, | ||
| 4893 | .name = ident_name, | ||
| 4894 | .inst = payload_inst, | ||
| 4895 | .token_src = error_token, | ||
| 4896 | }; | ||
| 4897 | break :s &payload_val_scope.base; | ||
| 4898 | } else { | ||
| 4899 | break :s &else_scope.base; | ||
| 4900 | } | ||
| 4901 | }; | ||
| 4902 | break :blk .{ | ||
| 4903 | .src = else_node, | ||
| 4904 | .result = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node), | ||
| 4905 | }; | ||
| 4906 | } else .{ | ||
| 4907 | .src = if_full.ast.then_expr, | ||
| 4908 | .result = .none, | ||
| 4909 | }; | ||
| 4910 | |||
| 4911 | return finishThenElseBlock( | ||
| 4912 | parent_gz, | ||
| 4913 | scope, | ||
| 4914 | rl, | ||
| 4915 | node, | ||
| 4916 | &block_scope, | ||
| 4917 | &then_scope, | ||
| 4918 | &else_scope, | ||
| 4919 | condbr, | ||
| 4920 | cond.bool_bit, | ||
| 4921 | if_full.ast.then_expr, | ||
| 4922 | else_info.src, | ||
| 4923 | then_result, | ||
| 4924 | else_info.result, | ||
| 4925 | block, | ||
| 4926 | block, | ||
| 4927 | .@"break", | ||
| 4928 | ); | ||
| 4929 | } | ||
| 4930 | |||
| 4931 | fn setCondBrPayload( | ||
| 4932 | condbr: Zir.Inst.Index, | ||
| 4933 | cond: Zir.Inst.Ref, | ||
| 4934 | then_scope: *GenZir, | ||
| 4935 | else_scope: *GenZir, | ||
| 4936 | ) !void { | ||
| 4937 | const astgen = then_scope.astgen; | ||
| 4938 | |||
| 4939 | try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + | ||
| 4940 | @typeInfo(Zir.Inst.CondBr).Struct.fields.len + | ||
| 4941 | then_scope.instructions.items.len + else_scope.instructions.items.len); | ||
| 4942 | |||
| 4943 | const zir_datas = astgen.instructions.items(.data); | ||
| 4944 | zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ | ||
| 4945 | .condition = cond, | ||
| 4946 | .then_body_len = @intCast(u32, then_scope.instructions.items.len), | ||
| 4947 | .else_body_len = @intCast(u32, else_scope.instructions.items.len), | ||
| 4948 | }); | ||
| 4949 | astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items); | ||
| 4950 | astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items); | ||
| 4951 | } | ||
| 4952 | |||
| 4953 | fn setCondBrPayloadElideBlockStorePtr( | ||
| 4954 | condbr: Zir.Inst.Index, | ||
| 4955 | cond: Zir.Inst.Ref, | ||
| 4956 | then_scope: *GenZir, | ||
| 4957 | else_scope: *GenZir, | ||
| 4958 | block_ptr: Zir.Inst.Ref, | ||
| 4959 | ) !void { | ||
| 4960 | const astgen = then_scope.astgen; | ||
| 4961 | |||
| 4962 | try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len + | ||
| 4963 | then_scope.instructions.items.len + else_scope.instructions.items.len); | ||
| 4964 | |||
| 4965 | const zir_tags = astgen.instructions.items(.tag); | ||
| 4966 | const zir_datas = astgen.instructions.items(.data); | ||
| 4967 | |||
| 4968 | const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ | ||
| 4969 | .condition = cond, | ||
| 4970 | .then_body_len = @intCast(u32, then_scope.instructions.items.len), | ||
| 4971 | .else_body_len = @intCast(u32, else_scope.instructions.items.len), | ||
| 4972 | }); | ||
| 4973 | zir_datas[condbr].pl_node.payload_index = condbr_pl; | ||
| 4974 | const then_body_len_index = condbr_pl + 1; | ||
| 4975 | const else_body_len_index = condbr_pl + 2; | ||
| 4976 | |||
| 4977 | for (then_scope.instructions.items) |src_inst| { | ||
| 4978 | if (zir_tags[src_inst] == .store_to_block_ptr) { | ||
| 4979 | if (zir_datas[src_inst].bin.lhs == block_ptr) { | ||
| 4980 | astgen.extra.items[then_body_len_index] -= 1; | ||
| 4981 | continue; | ||
| 4982 | } | ||
| 4983 | } | ||
| 4984 | astgen.extra.appendAssumeCapacity(src_inst); | ||
| 4985 | } | ||
| 4986 | for (else_scope.instructions.items) |src_inst| { | ||
| 4987 | if (zir_tags[src_inst] == .store_to_block_ptr) { | ||
| 4988 | if (zir_datas[src_inst].bin.lhs == block_ptr) { | ||
| 4989 | astgen.extra.items[else_body_len_index] -= 1; | ||
| 4990 | continue; | ||
| 4991 | } | ||
| 4992 | } | ||
| 4993 | astgen.extra.appendAssumeCapacity(src_inst); | ||
| 4994 | } | ||
| 4995 | } | ||
| 4996 | |||
| 4997 | fn whileExpr( | ||
| 4998 | parent_gz: *GenZir, | ||
| 4999 | scope: *Scope, | ||
| 5000 | rl: ResultLoc, | ||
| 5001 | node: ast.Node.Index, | ||
| 5002 | while_full: ast.full.While, | ||
| 5003 | ) InnerError!Zir.Inst.Ref { | ||
| 5004 | const astgen = parent_gz.astgen; | ||
| 5005 | const tree = astgen.tree; | ||
| 5006 | const token_tags = tree.tokens.items(.tag); | ||
| 5007 | |||
| 5008 | if (while_full.label_token) |label_token| { | ||
| 5009 | try astgen.checkLabelRedefinition(scope, label_token); | ||
| 5010 | } | ||
| 5011 | |||
| 5012 | const is_inline = parent_gz.force_comptime or while_full.inline_token != null; | ||
| 5013 | const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; | ||
| 5014 | const loop_block = try parent_gz.addBlock(loop_tag, node); | ||
| 5015 | try parent_gz.instructions.append(astgen.gpa, loop_block); | ||
| 5016 | |||
| 5017 | var loop_scope = parent_gz.makeSubBlock(scope); | ||
| 5018 | loop_scope.setBreakResultLoc(rl); | ||
| 5019 | defer loop_scope.instructions.deinit(astgen.gpa); | ||
| 5020 | defer loop_scope.labeled_breaks.deinit(astgen.gpa); | ||
| 5021 | defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); | ||
| 5022 | |||
| 5023 | var continue_scope = parent_gz.makeSubBlock(&loop_scope.base); | ||
| 5024 | defer continue_scope.instructions.deinit(astgen.gpa); | ||
| 5025 | |||
| 5026 | const payload_is_ref = if (while_full.payload_token) |payload_token| | ||
| 5027 | token_tags[payload_token] == .asterisk | ||
| 5028 | else | ||
| 5029 | false; | ||
| 5030 | |||
| 5031 | const cond: struct { | ||
| 5032 | inst: Zir.Inst.Ref, | ||
| 5033 | bool_bit: Zir.Inst.Ref, | ||
| 5034 | } = c: { | ||
| 5035 | if (while_full.error_token) |error_token| { | ||
| 5036 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; | ||
| 5037 | const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); | ||
| 5038 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_err_ptr else .is_err; | ||
| 5039 | break :c .{ | ||
| 5040 | .inst = err_union, | ||
| 5041 | .bool_bit = try continue_scope.addUnNode(tag, err_union, node), | ||
| 5042 | }; | ||
| 5043 | } else if (while_full.payload_token) |payload_token| { | ||
| 5044 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; | ||
| 5045 | const optional = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); | ||
| 5046 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; | ||
| 5047 | break :c .{ | ||
| 5048 | .inst = optional, | ||
| 5049 | .bool_bit = try continue_scope.addUnNode(tag, optional, node), | ||
| 5050 | }; | ||
| 5051 | } else { | ||
| 5052 | const cond = try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr); | ||
| 5053 | break :c .{ | ||
| 5054 | .inst = cond, | ||
| 5055 | .bool_bit = cond, | ||
| 5056 | }; | ||
| 5057 | } | ||
| 5058 | }; | ||
| 5059 | |||
| 5060 | const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; | ||
| 5061 | const condbr = try continue_scope.addCondBr(condbr_tag, node); | ||
| 5062 | const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; | ||
| 5063 | const cond_block = try loop_scope.addBlock(block_tag, node); | ||
| 5064 | try loop_scope.instructions.append(astgen.gpa, cond_block); | ||
| 5065 | try continue_scope.setBlockBody(cond_block); | ||
| 5066 | |||
| 5067 | // TODO avoid emitting the continue expr when there | ||
| 5068 | // are no jumps to it. This happens when the last statement of a while body is noreturn | ||
| 5069 | // and there are no `continue` statements. | ||
| 5070 | if (while_full.ast.cont_expr != 0) { | ||
| 5071 | _ = try expr(&loop_scope, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr); | ||
| 5072 | } | ||
| 5073 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | ||
| 5074 | _ = try loop_scope.addNode(repeat_tag, node); | ||
| 5075 | |||
| 5076 | try loop_scope.setBlockBody(loop_block); | ||
| 5077 | loop_scope.break_block = loop_block; | ||
| 5078 | loop_scope.continue_block = cond_block; | ||
| 5079 | if (while_full.label_token) |label_token| { | ||
| 5080 | loop_scope.label = @as(?GenZir.Label, GenZir.Label{ | ||
| 5081 | .token = label_token, | ||
| 5082 | .block_inst = loop_block, | ||
| 5083 | }); | ||
| 5084 | } | ||
| 5085 | |||
| 5086 | var then_scope = parent_gz.makeSubBlock(&continue_scope.base); | ||
| 5087 | defer then_scope.instructions.deinit(astgen.gpa); | ||
| 5088 | |||
| 5089 | var payload_val_scope: Scope.LocalVal = undefined; | ||
| 5090 | |||
| 5091 | const then_sub_scope = s: { | ||
| 5092 | if (while_full.error_token) |error_token| { | ||
| 5093 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 5094 | .err_union_payload_unsafe_ptr | ||
| 5095 | else | ||
| 5096 | .err_union_payload_unsafe; | ||
| 5097 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | ||
| 5098 | const ident_name = try astgen.identAsString(error_token); | ||
| 5099 | payload_val_scope = .{ | ||
| 5100 | .parent = &then_scope.base, | ||
| 5101 | .gen_zir = &then_scope, | ||
| 5102 | .name = ident_name, | ||
| 5103 | .inst = payload_inst, | ||
| 5104 | .token_src = error_token, | ||
| 5105 | }; | ||
| 5106 | break :s &payload_val_scope.base; | ||
| 5107 | } else if (while_full.payload_token) |payload_token| { | ||
| 5108 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; | ||
| 5109 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 5110 | .optional_payload_unsafe_ptr | ||
| 5111 | else | ||
| 5112 | .optional_payload_unsafe; | ||
| 5113 | const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); | ||
| 5114 | const ident_name = try astgen.identAsString(ident_token); | ||
| 5115 | payload_val_scope = .{ | ||
| 5116 | .parent = &then_scope.base, | ||
| 5117 | .gen_zir = &then_scope, | ||
| 5118 | .name = ident_name, | ||
| 5119 | .inst = payload_inst, | ||
| 5120 | .token_src = ident_token, | ||
| 5121 | }; | ||
| 5122 | break :s &payload_val_scope.base; | ||
| 5123 | } else { | ||
| 5124 | break :s &then_scope.base; | ||
| 5125 | } | ||
| 5126 | }; | ||
| 5127 | |||
| 5128 | loop_scope.break_count += 1; | ||
| 5129 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); | ||
| 5130 | |||
| 5131 | var else_scope = parent_gz.makeSubBlock(&continue_scope.base); | ||
| 5132 | defer else_scope.instructions.deinit(astgen.gpa); | ||
| 5133 | |||
| 5134 | const else_node = while_full.ast.else_expr; | ||
| 5135 | const else_info: struct { | ||
| 5136 | src: ast.Node.Index, | ||
| 5137 | result: Zir.Inst.Ref, | ||
| 5138 | } = if (else_node != 0) blk: { | ||
| 5139 | loop_scope.break_count += 1; | ||
| 5140 | const sub_scope = s: { | ||
| 5141 | if (while_full.error_token) |error_token| { | ||
| 5142 | const tag: Zir.Inst.Tag = if (payload_is_ref) | ||
| 5143 | .err_union_code_ptr | ||
| 5144 | else | ||
| 5145 | .err_union_code; | ||
| 5146 | const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); | ||
| 5147 | const ident_name = try astgen.identAsString(error_token); | ||
| 5148 | payload_val_scope = .{ | ||
| 5149 | .parent = &else_scope.base, | ||
| 5150 | .gen_zir = &else_scope, | ||
| 5151 | .name = ident_name, | ||
| 5152 | .inst = payload_inst, | ||
| 5153 | .token_src = error_token, | ||
| 5154 | }; | ||
| 5155 | break :s &payload_val_scope.base; | ||
| 5156 | } else { | ||
| 5157 | break :s &else_scope.base; | ||
| 5158 | } | ||
| 5159 | }; | ||
| 5160 | break :blk .{ | ||
| 5161 | .src = else_node, | ||
| 5162 | .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), | ||
| 5163 | }; | ||
| 5164 | } else .{ | ||
| 5165 | .src = while_full.ast.then_expr, | ||
| 5166 | .result = .none, | ||
| 5167 | }; | ||
| 5168 | |||
| 5169 | if (loop_scope.label) |some| { | ||
| 5170 | if (!some.used) { | ||
| 5171 | return astgen.failTok(some.token, "unused while loop label", .{}); | ||
| 5172 | } | ||
| 5173 | } | ||
| 5174 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | ||
| 5175 | return finishThenElseBlock( | ||
| 5176 | parent_gz, | ||
| 5177 | scope, | ||
| 5178 | rl, | ||
| 5179 | node, | ||
| 5180 | &loop_scope, | ||
| 5181 | &then_scope, | ||
| 5182 | &else_scope, | ||
| 5183 | condbr, | ||
| 5184 | cond.bool_bit, | ||
| 5185 | while_full.ast.then_expr, | ||
| 5186 | else_info.src, | ||
| 5187 | then_result, | ||
| 5188 | else_info.result, | ||
| 5189 | loop_block, | ||
| 5190 | cond_block, | ||
| 5191 | break_tag, | ||
| 5192 | ); | ||
| 5193 | } | ||
| 5194 | |||
| 5195 | fn forExpr( | ||
| 5196 | parent_gz: *GenZir, | ||
| 5197 | scope: *Scope, | ||
| 5198 | rl: ResultLoc, | ||
| 5199 | node: ast.Node.Index, | ||
| 5200 | for_full: ast.full.While, | ||
| 5201 | ) InnerError!Zir.Inst.Ref { | ||
| 5202 | const astgen = parent_gz.astgen; | ||
| 5203 | |||
| 5204 | if (for_full.label_token) |label_token| { | ||
| 5205 | try astgen.checkLabelRedefinition(scope, label_token); | ||
| 5206 | } | ||
| 5207 | // Set up variables and constants. | ||
| 5208 | const is_inline = parent_gz.force_comptime or for_full.inline_token != null; | ||
| 5209 | const tree = astgen.tree; | ||
| 5210 | const token_tags = tree.tokens.items(.tag); | ||
| 5211 | |||
| 5212 | const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr); | ||
| 5213 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); | ||
| 5214 | |||
| 5215 | const index_ptr = blk: { | ||
| 5216 | const index_ptr = try parent_gz.addUnNode(.alloc, .usize_type, node); | ||
| 5217 | // initialize to zero | ||
| 5218 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); | ||
| 5219 | break :blk index_ptr; | ||
| 5220 | }; | ||
| 5221 | |||
| 5222 | const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; | ||
| 5223 | const loop_block = try parent_gz.addBlock(loop_tag, node); | ||
| 5224 | try parent_gz.instructions.append(astgen.gpa, loop_block); | ||
| 5225 | |||
| 5226 | var loop_scope = parent_gz.makeSubBlock(scope); | ||
| 5227 | loop_scope.setBreakResultLoc(rl); | ||
| 5228 | defer loop_scope.instructions.deinit(astgen.gpa); | ||
| 5229 | defer loop_scope.labeled_breaks.deinit(astgen.gpa); | ||
| 5230 | defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); | ||
| 5231 | |||
| 5232 | var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); | ||
| 5233 | defer cond_scope.instructions.deinit(astgen.gpa); | ||
| 5234 | |||
| 5235 | // check condition i < array_expr.len | ||
| 5236 | const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); | ||
| 5237 | const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{ | ||
| 5238 | .lhs = index, | ||
| 5239 | .rhs = len, | ||
| 5240 | }); | ||
| 5241 | |||
| 5242 | const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; | ||
| 5243 | const condbr = try cond_scope.addCondBr(condbr_tag, node); | ||
| 5244 | const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; | ||
| 5245 | const cond_block = try loop_scope.addBlock(block_tag, node); | ||
| 5246 | try loop_scope.instructions.append(astgen.gpa, cond_block); | ||
| 5247 | try cond_scope.setBlockBody(cond_block); | ||
| 5248 | |||
| 5249 | // Increment the index variable. | ||
| 5250 | const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); | ||
| 5251 | const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ | ||
| 5252 | .lhs = index_2, | ||
| 5253 | .rhs = .one_usize, | ||
| 5254 | }); | ||
| 5255 | _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); | ||
| 5256 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | ||
| 5257 | _ = try loop_scope.addNode(repeat_tag, node); | ||
| 5258 | |||
| 5259 | try loop_scope.setBlockBody(loop_block); | ||
| 5260 | loop_scope.break_block = loop_block; | ||
| 5261 | loop_scope.continue_block = cond_block; | ||
| 5262 | if (for_full.label_token) |label_token| { | ||
| 5263 | loop_scope.label = @as(?GenZir.Label, GenZir.Label{ | ||
| 5264 | .token = label_token, | ||
| 5265 | .block_inst = loop_block, | ||
| 5266 | }); | ||
| 5267 | } | ||
| 5268 | |||
| 5269 | var then_scope = parent_gz.makeSubBlock(&cond_scope.base); | ||
| 5270 | defer then_scope.instructions.deinit(astgen.gpa); | ||
| 5271 | |||
| 5272 | var payload_val_scope: Scope.LocalVal = undefined; | ||
| 5273 | var index_scope: Scope.LocalPtr = undefined; | ||
| 5274 | const then_sub_scope = blk: { | ||
| 5275 | const payload_token = for_full.payload_token.?; | ||
| 5276 | const ident = if (token_tags[payload_token] == .asterisk) | ||
| 5277 | payload_token + 1 | ||
| 5278 | else | ||
| 5279 | payload_token; | ||
| 5280 | const is_ptr = ident != payload_token; | ||
| 5281 | const value_name = tree.tokenSlice(ident); | ||
| 5282 | var payload_sub_scope: *Scope = undefined; | ||
| 5283 | if (!mem.eql(u8, value_name, "_")) { | ||
| 5284 | const name_str_index = try astgen.identAsString(ident); | ||
| 5285 | const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; | ||
| 5286 | const payload_inst = try then_scope.addBin(tag, array_ptr, index); | ||
| 5287 | payload_val_scope = .{ | ||
| 5288 | .parent = &then_scope.base, | ||
| 5289 | .gen_zir = &then_scope, | ||
| 5290 | .name = name_str_index, | ||
| 5291 | .inst = payload_inst, | ||
| 5292 | .token_src = ident, | ||
| 5293 | }; | ||
| 5294 | payload_sub_scope = &payload_val_scope.base; | ||
| 5295 | } else if (is_ptr) { | ||
| 5296 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | ||
| 5297 | } else { | ||
| 5298 | payload_sub_scope = &then_scope.base; | ||
| 5299 | } | ||
| 5300 | |||
| 5301 | const index_token = if (token_tags[ident + 1] == .comma) | ||
| 5302 | ident + 2 | ||
| 5303 | else | ||
| 5304 | break :blk payload_sub_scope; | ||
| 5305 | if (mem.eql(u8, tree.tokenSlice(index_token), "_")) { | ||
| 5306 | return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); | ||
| 5307 | } | ||
| 5308 | const index_name = try astgen.identAsString(index_token); | ||
| 5309 | index_scope = .{ | ||
| 5310 | .parent = payload_sub_scope, | ||
| 5311 | .gen_zir = &then_scope, | ||
| 5312 | .name = index_name, | ||
| 5313 | .ptr = index_ptr, | ||
| 5314 | .token_src = index_token, | ||
| 5315 | }; | ||
| 5316 | break :blk &index_scope.base; | ||
| 5317 | }; | ||
| 5318 | |||
| 5319 | loop_scope.break_count += 1; | ||
| 5320 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); | ||
| 5321 | |||
| 5322 | var else_scope = parent_gz.makeSubBlock(&cond_scope.base); | ||
| 5323 | defer else_scope.instructions.deinit(astgen.gpa); | ||
| 5324 | |||
| 5325 | const else_node = for_full.ast.else_expr; | ||
| 5326 | const else_info: struct { | ||
| 5327 | src: ast.Node.Index, | ||
| 5328 | result: Zir.Inst.Ref, | ||
| 5329 | } = if (else_node != 0) blk: { | ||
| 5330 | loop_scope.break_count += 1; | ||
| 5331 | const sub_scope = &else_scope.base; | ||
| 5332 | break :blk .{ | ||
| 5333 | .src = else_node, | ||
| 5334 | .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), | ||
| 5335 | }; | ||
| 5336 | } else .{ | ||
| 5337 | .src = for_full.ast.then_expr, | ||
| 5338 | .result = .none, | ||
| 5339 | }; | ||
| 5340 | |||
| 5341 | if (loop_scope.label) |some| { | ||
| 5342 | if (!some.used) { | ||
| 5343 | return astgen.failTok(some.token, "unused for loop label", .{}); | ||
| 5344 | } | ||
| 5345 | } | ||
| 5346 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | ||
| 5347 | return finishThenElseBlock( | ||
| 5348 | parent_gz, | ||
| 5349 | scope, | ||
| 5350 | rl, | ||
| 5351 | node, | ||
| 5352 | &loop_scope, | ||
| 5353 | &then_scope, | ||
| 5354 | &else_scope, | ||
| 5355 | condbr, | ||
| 5356 | cond, | ||
| 5357 | for_full.ast.then_expr, | ||
| 5358 | else_info.src, | ||
| 5359 | then_result, | ||
| 5360 | else_info.result, | ||
| 5361 | loop_block, | ||
| 5362 | cond_block, | ||
| 5363 | break_tag, | ||
| 5364 | ); | ||
| 5365 | } | ||
| 5366 | |||
| 5367 | fn switchExpr( | ||
| 5368 | parent_gz: *GenZir, | ||
| 5369 | scope: *Scope, | ||
| 5370 | rl: ResultLoc, | ||
| 5371 | switch_node: ast.Node.Index, | ||
| 5372 | ) InnerError!Zir.Inst.Ref { | ||
| 5373 | const astgen = parent_gz.astgen; | ||
| 5374 | const gpa = astgen.gpa; | ||
| 5375 | const tree = astgen.tree; | ||
| 5376 | const node_datas = tree.nodes.items(.data); | ||
| 5377 | const node_tags = tree.nodes.items(.tag); | ||
| 5378 | const main_tokens = tree.nodes.items(.main_token); | ||
| 5379 | const token_tags = tree.tokens.items(.tag); | ||
| 5380 | const operand_node = node_datas[switch_node].lhs; | ||
| 5381 | const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); | ||
| 5382 | const case_nodes = tree.extra_data[extra.start..extra.end]; | ||
| 5383 | |||
| 5384 | // We perform two passes over the AST. This first pass is to collect information | ||
| 5385 | // for the following variables, make note of the special prong AST node index, | ||
| 5386 | // and bail out with a compile error if there are multiple special prongs present. | ||
| 5387 | var any_payload_is_ref = false; | ||
| 5388 | var scalar_cases_len: u32 = 0; | ||
| 5389 | var multi_cases_len: u32 = 0; | ||
| 5390 | var special_prong: Zir.SpecialProng = .none; | ||
| 5391 | var special_node: ast.Node.Index = 0; | ||
| 5392 | var else_src: ?ast.TokenIndex = null; | ||
| 5393 | var underscore_src: ?ast.TokenIndex = null; | ||
| 5394 | for (case_nodes) |case_node| { | ||
| 5395 | const case = switch (node_tags[case_node]) { | ||
| 5396 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 5397 | .switch_case => tree.switchCase(case_node), | ||
| 5398 | else => unreachable, | ||
| 5399 | }; | ||
| 5400 | if (case.payload_token) |payload_token| { | ||
| 5401 | if (token_tags[payload_token] == .asterisk) { | ||
| 5402 | any_payload_is_ref = true; | ||
| 5403 | } | ||
| 5404 | } | ||
| 5405 | // Check for else/`_` prong. | ||
| 5406 | if (case.ast.values.len == 0) { | ||
| 5407 | const case_src = case.ast.arrow_token - 1; | ||
| 5408 | if (else_src) |src| { | ||
| 5409 | return astgen.failTokNotes( | ||
| 5410 | case_src, | ||
| 5411 | "multiple else prongs in switch expression", | ||
| 5412 | .{}, | ||
| 5413 | &[_]u32{ | ||
| 5414 | try astgen.errNoteTok( | ||
| 5415 | src, | ||
| 5416 | "previous else prong is here", | ||
| 5417 | .{}, | ||
| 5418 | ), | ||
| 5419 | }, | ||
| 5420 | ); | ||
| 5421 | } else if (underscore_src) |some_underscore| { | ||
| 5422 | return astgen.failNodeNotes( | ||
| 5423 | switch_node, | ||
| 5424 | "else and '_' prong in switch expression", | ||
| 5425 | .{}, | ||
| 5426 | &[_]u32{ | ||
| 5427 | try astgen.errNoteTok( | ||
| 5428 | case_src, | ||
| 5429 | "else prong is here", | ||
| 5430 | .{}, | ||
| 5431 | ), | ||
| 5432 | try astgen.errNoteTok( | ||
| 5433 | some_underscore, | ||
| 5434 | "'_' prong is here", | ||
| 5435 | .{}, | ||
| 5436 | ), | ||
| 5437 | }, | ||
| 5438 | ); | ||
| 5439 | } | ||
| 5440 | special_node = case_node; | ||
| 5441 | special_prong = .@"else"; | ||
| 5442 | else_src = case_src; | ||
| 5443 | continue; | ||
| 5444 | } else if (case.ast.values.len == 1 and | ||
| 5445 | node_tags[case.ast.values[0]] == .identifier and | ||
| 5446 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) | ||
| 5447 | { | ||
| 5448 | const case_src = case.ast.arrow_token - 1; | ||
| 5449 | if (underscore_src) |src| { | ||
| 5450 | return astgen.failTokNotes( | ||
| 5451 | case_src, | ||
| 5452 | "multiple '_' prongs in switch expression", | ||
| 5453 | .{}, | ||
| 5454 | &[_]u32{ | ||
| 5455 | try astgen.errNoteTok( | ||
| 5456 | src, | ||
| 5457 | "previous '_' prong is here", | ||
| 5458 | .{}, | ||
| 5459 | ), | ||
| 5460 | }, | ||
| 5461 | ); | ||
| 5462 | } else if (else_src) |some_else| { | ||
| 5463 | return astgen.failNodeNotes( | ||
| 5464 | switch_node, | ||
| 5465 | "else and '_' prong in switch expression", | ||
| 5466 | .{}, | ||
| 5467 | &[_]u32{ | ||
| 5468 | try astgen.errNoteTok( | ||
| 5469 | some_else, | ||
| 5470 | "else prong is here", | ||
| 5471 | .{}, | ||
| 5472 | ), | ||
| 5473 | try astgen.errNoteTok( | ||
| 5474 | case_src, | ||
| 5475 | "'_' prong is here", | ||
| 5476 | .{}, | ||
| 5477 | ), | ||
| 5478 | }, | ||
| 5479 | ); | ||
| 5480 | } | ||
| 5481 | special_node = case_node; | ||
| 5482 | special_prong = .under; | ||
| 5483 | underscore_src = case_src; | ||
| 5484 | continue; | ||
| 5485 | } | ||
| 5486 | |||
| 5487 | if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { | ||
| 5488 | scalar_cases_len += 1; | ||
| 5489 | } else { | ||
| 5490 | multi_cases_len += 1; | ||
| 5491 | } | ||
| 5492 | } | ||
| 5493 | |||
| 5494 | const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; | ||
| 5495 | const operand = try expr(parent_gz, scope, operand_rl, operand_node); | ||
| 5496 | // We need the type of the operand to use as the result location for all the prong items. | ||
| 5497 | const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof; | ||
| 5498 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); | ||
| 5499 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; | ||
| 5500 | |||
| 5501 | // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. | ||
| 5502 | // This is the header as well as the optional else prong body, as well as all the | ||
| 5503 | // scalar cases. | ||
| 5504 | // At the end we will memcpy this into place. | ||
| 5505 | var scalar_cases_payload = ArrayListUnmanaged(u32){}; | ||
| 5506 | defer scalar_cases_payload.deinit(gpa); | ||
| 5507 | // Same deal, but this is only the `extra` data for the multi cases. | ||
| 5508 | var multi_cases_payload = ArrayListUnmanaged(u32){}; | ||
| 5509 | defer multi_cases_payload.deinit(gpa); | ||
| 5510 | |||
| 5511 | var block_scope = parent_gz.makeSubBlock(scope); | ||
| 5512 | block_scope.setBreakResultLoc(rl); | ||
| 5513 | defer block_scope.instructions.deinit(gpa); | ||
| 5514 | |||
| 5515 | // This gets added to the parent block later, after the item expressions. | ||
| 5516 | const switch_block = try parent_gz.addBlock(undefined, switch_node); | ||
| 5517 | |||
| 5518 | // We re-use this same scope for all cases, including the special prong, if any. | ||
| 5519 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); | ||
| 5520 | defer case_scope.instructions.deinit(gpa); | ||
| 5521 | |||
| 5522 | // Do the else/`_` first because it goes first in the payload. | ||
| 5523 | var capture_val_scope: Scope.LocalVal = undefined; | ||
| 5524 | if (special_node != 0) { | ||
| 5525 | const case = switch (node_tags[special_node]) { | ||
| 5526 | .switch_case_one => tree.switchCaseOne(special_node), | ||
| 5527 | .switch_case => tree.switchCase(special_node), | ||
| 5528 | else => unreachable, | ||
| 5529 | }; | ||
| 5530 | const sub_scope = blk: { | ||
| 5531 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | ||
| 5532 | const ident = if (token_tags[payload_token] == .asterisk) | ||
| 5533 | payload_token + 1 | ||
| 5534 | else | ||
| 5535 | payload_token; | ||
| 5536 | const is_ptr = ident != payload_token; | ||
| 5537 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | ||
| 5538 | if (is_ptr) { | ||
| 5539 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | ||
| 5540 | } | ||
| 5541 | break :blk &case_scope.base; | ||
| 5542 | } | ||
| 5543 | const capture_tag: Zir.Inst.Tag = if (is_ptr) | ||
| 5544 | .switch_capture_else_ref | ||
| 5545 | else | ||
| 5546 | .switch_capture_else; | ||
| 5547 | const capture = try case_scope.add(.{ | ||
| 5548 | .tag = capture_tag, | ||
| 5549 | .data = .{ .switch_capture = .{ | ||
| 5550 | .switch_inst = switch_block, | ||
| 5551 | .prong_index = undefined, | ||
| 5552 | } }, | ||
| 5553 | }); | ||
| 5554 | const capture_name = try astgen.identAsString(payload_token); | ||
| 5555 | capture_val_scope = .{ | ||
| 5556 | .parent = &case_scope.base, | ||
| 5557 | .gen_zir = &case_scope, | ||
| 5558 | .name = capture_name, | ||
| 5559 | .inst = capture, | ||
| 5560 | .token_src = payload_token, | ||
| 5561 | }; | ||
| 5562 | break :blk &capture_val_scope.base; | ||
| 5563 | }; | ||
| 5564 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | ||
| 5565 | if (!parent_gz.refIsNoReturn(case_result)) { | ||
| 5566 | block_scope.break_count += 1; | ||
| 5567 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | ||
| 5568 | } | ||
| 5569 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. | ||
| 5570 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | ||
| 5571 | 3 + // operand, scalar_cases_len, else body len | ||
| 5572 | @boolToInt(multi_cases_len != 0) + | ||
| 5573 | case_scope.instructions.items.len); | ||
| 5574 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | ||
| 5575 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | ||
| 5576 | if (multi_cases_len != 0) { | ||
| 5577 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | ||
| 5578 | } | ||
| 5579 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | ||
| 5580 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | ||
| 5581 | } else { | ||
| 5582 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. | ||
| 5583 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | ||
| 5584 | 2 + // operand, scalar_cases_len | ||
| 5585 | @boolToInt(multi_cases_len != 0)); | ||
| 5586 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | ||
| 5587 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | ||
| 5588 | if (multi_cases_len != 0) { | ||
| 5589 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | ||
| 5590 | } | ||
| 5591 | } | ||
| 5592 | |||
| 5593 | // In this pass we generate all the item and prong expressions except the special case. | ||
| 5594 | var multi_case_index: u32 = 0; | ||
| 5595 | var scalar_case_index: u32 = 0; | ||
| 5596 | for (case_nodes) |case_node| { | ||
| 5597 | if (case_node == special_node) | ||
| 5598 | continue; | ||
| 5599 | const case = switch (node_tags[case_node]) { | ||
| 5600 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 5601 | .switch_case => tree.switchCase(case_node), | ||
| 5602 | else => unreachable, | ||
| 5603 | }; | ||
| 5604 | |||
| 5605 | // Reset the scope. | ||
| 5606 | case_scope.instructions.shrinkRetainingCapacity(0); | ||
| 5607 | |||
| 5608 | const is_multi_case = case.ast.values.len != 1 or | ||
| 5609 | node_tags[case.ast.values[0]] == .switch_range; | ||
| 5610 | |||
| 5611 | const sub_scope = blk: { | ||
| 5612 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | ||
| 5613 | const ident = if (token_tags[payload_token] == .asterisk) | ||
| 5614 | payload_token + 1 | ||
| 5615 | else | ||
| 5616 | payload_token; | ||
| 5617 | const is_ptr = ident != payload_token; | ||
| 5618 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | ||
| 5619 | if (is_ptr) { | ||
| 5620 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | ||
| 5621 | } | ||
| 5622 | break :blk &case_scope.base; | ||
| 5623 | } | ||
| 5624 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | ||
| 5625 | const is_ptr_bits: u2 = @boolToInt(is_ptr); | ||
| 5626 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { | ||
| 5627 | 0b00 => .switch_capture, | ||
| 5628 | 0b01 => .switch_capture_ref, | ||
| 5629 | 0b10 => .switch_capture_multi, | ||
| 5630 | 0b11 => .switch_capture_multi_ref, | ||
| 5631 | }; | ||
| 5632 | const capture_index = if (is_multi_case) ci: { | ||
| 5633 | multi_case_index += 1; | ||
| 5634 | break :ci multi_case_index - 1; | ||
| 5635 | } else ci: { | ||
| 5636 | scalar_case_index += 1; | ||
| 5637 | break :ci scalar_case_index - 1; | ||
| 5638 | }; | ||
| 5639 | const capture = try case_scope.add(.{ | ||
| 5640 | .tag = capture_tag, | ||
| 5641 | .data = .{ .switch_capture = .{ | ||
| 5642 | .switch_inst = switch_block, | ||
| 5643 | .prong_index = capture_index, | ||
| 5644 | } }, | ||
| 5645 | }); | ||
| 5646 | const capture_name = try astgen.identAsString(ident); | ||
| 5647 | capture_val_scope = .{ | ||
| 5648 | .parent = &case_scope.base, | ||
| 5649 | .gen_zir = &case_scope, | ||
| 5650 | .name = capture_name, | ||
| 5651 | .inst = capture, | ||
| 5652 | .token_src = payload_token, | ||
| 5653 | }; | ||
| 5654 | break :blk &capture_val_scope.base; | ||
| 5655 | }; | ||
| 5656 | |||
| 5657 | if (is_multi_case) { | ||
| 5658 | // items_len, ranges_len, body_len | ||
| 5659 | const header_index = multi_cases_payload.items.len; | ||
| 5660 | try multi_cases_payload.resize(gpa, multi_cases_payload.items.len + 3); | ||
| 5661 | |||
| 5662 | // items | ||
| 5663 | var items_len: u32 = 0; | ||
| 5664 | for (case.ast.values) |item_node| { | ||
| 5665 | if (node_tags[item_node] == .switch_range) continue; | ||
| 5666 | items_len += 1; | ||
| 5667 | |||
| 5668 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | ||
| 5669 | try multi_cases_payload.append(gpa, @enumToInt(item_inst)); | ||
| 5670 | } | ||
| 5671 | |||
| 5672 | // ranges | ||
| 5673 | var ranges_len: u32 = 0; | ||
| 5674 | for (case.ast.values) |range| { | ||
| 5675 | if (node_tags[range] != .switch_range) continue; | ||
| 5676 | ranges_len += 1; | ||
| 5677 | |||
| 5678 | const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); | ||
| 5679 | const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs); | ||
| 5680 | try multi_cases_payload.appendSlice(gpa, &[_]u32{ | ||
| 5681 | @enumToInt(first), @enumToInt(last), | ||
| 5682 | }); | ||
| 5683 | } | ||
| 5684 | |||
| 5685 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | ||
| 5686 | if (!parent_gz.refIsNoReturn(case_result)) { | ||
| 5687 | block_scope.break_count += 1; | ||
| 5688 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | ||
| 5689 | } | ||
| 5690 | |||
| 5691 | multi_cases_payload.items[header_index + 0] = items_len; | ||
| 5692 | multi_cases_payload.items[header_index + 1] = ranges_len; | ||
| 5693 | multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); | ||
| 5694 | try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items); | ||
| 5695 | } else { | ||
| 5696 | const item_node = case.ast.values[0]; | ||
| 5697 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | ||
| 5698 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | ||
| 5699 | if (!parent_gz.refIsNoReturn(case_result)) { | ||
| 5700 | block_scope.break_count += 1; | ||
| 5701 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | ||
| 5702 | } | ||
| 5703 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | ||
| 5704 | 2 + case_scope.instructions.items.len); | ||
| 5705 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); | ||
| 5706 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | ||
| 5707 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | ||
| 5708 | } | ||
| 5709 | } | ||
| 5710 | // Now that the item expressions are generated we can add this. | ||
| 5711 | try parent_gz.instructions.append(gpa, switch_block); | ||
| 5712 | |||
| 5713 | const ref_bit: u4 = @boolToInt(any_payload_is_ref); | ||
| 5714 | const multi_bit: u4 = @boolToInt(multi_cases_len != 0); | ||
| 5715 | const special_prong_bits: u4 = @enumToInt(special_prong); | ||
| 5716 | comptime { | ||
| 5717 | assert(@enumToInt(Zir.SpecialProng.none) == 0b00); | ||
| 5718 | assert(@enumToInt(Zir.SpecialProng.@"else") == 0b01); | ||
| 5719 | assert(@enumToInt(Zir.SpecialProng.under) == 0b10); | ||
| 5720 | } | ||
| 5721 | const zir_tags = astgen.instructions.items(.tag); | ||
| 5722 | zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) { | ||
| 5723 | 0b0_00_0 => .switch_block, | ||
| 5724 | 0b0_00_1 => .switch_block_multi, | ||
| 5725 | 0b0_01_0 => .switch_block_else, | ||
| 5726 | 0b0_01_1 => .switch_block_else_multi, | ||
| 5727 | 0b0_10_0 => .switch_block_under, | ||
| 5728 | 0b0_10_1 => .switch_block_under_multi, | ||
| 5729 | 0b1_00_0 => .switch_block_ref, | ||
| 5730 | 0b1_00_1 => .switch_block_ref_multi, | ||
| 5731 | 0b1_01_0 => .switch_block_ref_else, | ||
| 5732 | 0b1_01_1 => .switch_block_ref_else_multi, | ||
| 5733 | 0b1_10_0 => .switch_block_ref_under, | ||
| 5734 | 0b1_10_1 => .switch_block_ref_under_multi, | ||
| 5735 | else => unreachable, | ||
| 5736 | }; | ||
| 5737 | const payload_index = astgen.extra.items.len; | ||
| 5738 | const zir_datas = astgen.instructions.items(.data); | ||
| 5739 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); | ||
| 5740 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 5741 | scalar_cases_payload.items.len + multi_cases_payload.items.len); | ||
| 5742 | const strat = rl.strategy(&block_scope); | ||
| 5743 | switch (strat.tag) { | ||
| 5744 | .break_operand => { | ||
| 5745 | // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus | ||
| 5746 | // `elide_store_to_block_ptr_instructions` will either be true, | ||
| 5747 | // or all prongs are noreturn. | ||
| 5748 | if (!strat.elide_store_to_block_ptr_instructions) { | ||
| 5749 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | ||
| 5750 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | ||
| 5751 | return parent_gz.indexToRef(switch_block); | ||
| 5752 | } | ||
| 5753 | |||
| 5754 | // There will necessarily be a store_to_block_ptr for | ||
| 5755 | // all prongs, except for prongs that ended with a noreturn instruction. | ||
| 5756 | // Elide all the `store_to_block_ptr` instructions. | ||
| 5757 | |||
| 5758 | // The break instructions need to have their operands coerced if the | ||
| 5759 | // switch's result location is a `ty`. In this case we overwrite the | ||
| 5760 | // `store_to_block_ptr` instruction with an `as` instruction and repurpose | ||
| 5761 | // it as the break operand. | ||
| 5762 | |||
| 5763 | var extra_index: usize = 0; | ||
| 5764 | extra_index += 2; | ||
| 5765 | extra_index += @boolToInt(multi_cases_len != 0); | ||
| 5766 | if (special_prong != .none) special_prong: { | ||
| 5767 | const body_len_index = extra_index; | ||
| 5768 | const body_len = scalar_cases_payload.items[extra_index]; | ||
| 5769 | extra_index += 1; | ||
| 5770 | if (body_len < 2) { | ||
| 5771 | extra_index += body_len; | ||
| 5772 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 5773 | break :special_prong; | ||
| 5774 | } | ||
| 5775 | extra_index += body_len - 2; | ||
| 5776 | const store_inst = scalar_cases_payload.items[extra_index]; | ||
| 5777 | if (zir_tags[store_inst] != .store_to_block_ptr or | ||
| 5778 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) | ||
| 5779 | { | ||
| 5780 | extra_index += 2; | ||
| 5781 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 5782 | break :special_prong; | ||
| 5783 | } | ||
| 5784 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 5785 | if (block_scope.rl_ty_inst != .none) { | ||
| 5786 | extra_index += 1; | ||
| 5787 | const break_inst = scalar_cases_payload.items[extra_index]; | ||
| 5788 | extra_index += 1; | ||
| 5789 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 5790 | zir_tags[store_inst] = .as; | ||
| 5791 | zir_datas[store_inst].bin = .{ | ||
| 5792 | .lhs = block_scope.rl_ty_inst, | ||
| 5793 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 5794 | }; | ||
| 5795 | zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst); | ||
| 5796 | } else { | ||
| 5797 | scalar_cases_payload.items[body_len_index] -= 1; | ||
| 5798 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 5799 | extra_index += 1; | ||
| 5800 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | ||
| 5801 | extra_index += 1; | ||
| 5802 | } | ||
| 5803 | } else { | ||
| 5804 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | ||
| 5805 | } | ||
| 5806 | var scalar_i: u32 = 0; | ||
| 5807 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | ||
| 5808 | const start_index = extra_index; | ||
| 5809 | extra_index += 1; | ||
| 5810 | const body_len_index = extra_index; | ||
| 5811 | const body_len = scalar_cases_payload.items[extra_index]; | ||
| 5812 | extra_index += 1; | ||
| 5813 | if (body_len < 2) { | ||
| 5814 | extra_index += body_len; | ||
| 5815 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 5816 | continue; | ||
| 5817 | } | ||
| 5818 | extra_index += body_len - 2; | ||
| 5819 | const store_inst = scalar_cases_payload.items[extra_index]; | ||
| 5820 | if (zir_tags[store_inst] != .store_to_block_ptr or | ||
| 5821 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) | ||
| 5822 | { | ||
| 5823 | extra_index += 2; | ||
| 5824 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 5825 | continue; | ||
| 5826 | } | ||
| 5827 | if (block_scope.rl_ty_inst != .none) { | ||
| 5828 | extra_index += 1; | ||
| 5829 | const break_inst = scalar_cases_payload.items[extra_index]; | ||
| 5830 | extra_index += 1; | ||
| 5831 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 5832 | zir_tags[store_inst] = .as; | ||
| 5833 | zir_datas[store_inst].bin = .{ | ||
| 5834 | .lhs = block_scope.rl_ty_inst, | ||
| 5835 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 5836 | }; | ||
| 5837 | zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst); | ||
| 5838 | } else { | ||
| 5839 | scalar_cases_payload.items[body_len_index] -= 1; | ||
| 5840 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); | ||
| 5841 | extra_index += 1; | ||
| 5842 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | ||
| 5843 | extra_index += 1; | ||
| 5844 | } | ||
| 5845 | } | ||
| 5846 | extra_index = 0; | ||
| 5847 | var multi_i: u32 = 0; | ||
| 5848 | while (multi_i < multi_cases_len) : (multi_i += 1) { | ||
| 5849 | const start_index = extra_index; | ||
| 5850 | const items_len = multi_cases_payload.items[extra_index]; | ||
| 5851 | extra_index += 1; | ||
| 5852 | const ranges_len = multi_cases_payload.items[extra_index]; | ||
| 5853 | extra_index += 1; | ||
| 5854 | const body_len_index = extra_index; | ||
| 5855 | const body_len = multi_cases_payload.items[extra_index]; | ||
| 5856 | extra_index += 1; | ||
| 5857 | extra_index += items_len; | ||
| 5858 | extra_index += 2 * ranges_len; | ||
| 5859 | if (body_len < 2) { | ||
| 5860 | extra_index += body_len; | ||
| 5861 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 5862 | continue; | ||
| 5863 | } | ||
| 5864 | extra_index += body_len - 2; | ||
| 5865 | const store_inst = multi_cases_payload.items[extra_index]; | ||
| 5866 | if (zir_tags[store_inst] != .store_to_block_ptr or | ||
| 5867 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) | ||
| 5868 | { | ||
| 5869 | extra_index += 2; | ||
| 5870 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 5871 | continue; | ||
| 5872 | } | ||
| 5873 | if (block_scope.rl_ty_inst != .none) { | ||
| 5874 | extra_index += 1; | ||
| 5875 | const break_inst = multi_cases_payload.items[extra_index]; | ||
| 5876 | extra_index += 1; | ||
| 5877 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 5878 | zir_tags[store_inst] = .as; | ||
| 5879 | zir_datas[store_inst].bin = .{ | ||
| 5880 | .lhs = block_scope.rl_ty_inst, | ||
| 5881 | .rhs = zir_datas[break_inst].@"break".operand, | ||
| 5882 | }; | ||
| 5883 | zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst); | ||
| 5884 | } else { | ||
| 5885 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | ||
| 5886 | multi_cases_payload.items[body_len_index] -= 1; | ||
| 5887 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); | ||
| 5888 | extra_index += 1; | ||
| 5889 | astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); | ||
| 5890 | extra_index += 1; | ||
| 5891 | } | ||
| 5892 | } | ||
| 5893 | |||
| 5894 | const block_ref = parent_gz.indexToRef(switch_block); | ||
| 5895 | switch (rl) { | ||
| 5896 | .ref => return block_ref, | ||
| 5897 | else => return rvalue(parent_gz, scope, rl, block_ref, switch_node), | ||
| 5898 | } | ||
| 5899 | }, | ||
| 5900 | .break_void => { | ||
| 5901 | assert(!strat.elide_store_to_block_ptr_instructions); | ||
| 5902 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | ||
| 5903 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | ||
| 5904 | // Modify all the terminating instruction tags to become `break` variants. | ||
| 5905 | var extra_index: usize = payload_index; | ||
| 5906 | extra_index += 2; | ||
| 5907 | extra_index += @boolToInt(multi_cases_len != 0); | ||
| 5908 | if (special_prong != .none) { | ||
| 5909 | const body_len = astgen.extra.items[extra_index]; | ||
| 5910 | extra_index += 1; | ||
| 5911 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 5912 | extra_index += body_len; | ||
| 5913 | const last = body[body.len - 1]; | ||
| 5914 | if (zir_tags[last] == .@"break" and | ||
| 5915 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 5916 | { | ||
| 5917 | zir_datas[last].@"break".operand = .void_value; | ||
| 5918 | } | ||
| 5919 | } | ||
| 5920 | var scalar_i: u32 = 0; | ||
| 5921 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | ||
| 5922 | extra_index += 1; | ||
| 5923 | const body_len = astgen.extra.items[extra_index]; | ||
| 5924 | extra_index += 1; | ||
| 5925 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 5926 | extra_index += body_len; | ||
| 5927 | const last = body[body.len - 1]; | ||
| 5928 | if (zir_tags[last] == .@"break" and | ||
| 5929 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 5930 | { | ||
| 5931 | zir_datas[last].@"break".operand = .void_value; | ||
| 5932 | } | ||
| 5933 | } | ||
| 5934 | var multi_i: u32 = 0; | ||
| 5935 | while (multi_i < multi_cases_len) : (multi_i += 1) { | ||
| 5936 | const items_len = astgen.extra.items[extra_index]; | ||
| 5937 | extra_index += 1; | ||
| 5938 | const ranges_len = astgen.extra.items[extra_index]; | ||
| 5939 | extra_index += 1; | ||
| 5940 | const body_len = astgen.extra.items[extra_index]; | ||
| 5941 | extra_index += 1; | ||
| 5942 | extra_index += items_len; | ||
| 5943 | extra_index += 2 * ranges_len; | ||
| 5944 | const body = astgen.extra.items[extra_index..][0..body_len]; | ||
| 5945 | extra_index += body_len; | ||
| 5946 | const last = body[body.len - 1]; | ||
| 5947 | if (zir_tags[last] == .@"break" and | ||
| 5948 | zir_datas[last].@"break".block_inst == switch_block) | ||
| 5949 | { | ||
| 5950 | zir_datas[last].@"break".operand = .void_value; | ||
| 5951 | } | ||
| 5952 | } | ||
| 5953 | |||
| 5954 | return parent_gz.indexToRef(switch_block); | ||
| 5955 | }, | ||
| 5956 | } | ||
| 5957 | } | ||
| 5958 | |||
| 5959 | fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { | ||
| 5960 | const astgen = gz.astgen; | ||
| 5961 | const tree = astgen.tree; | ||
| 5962 | const node_datas = tree.nodes.items(.data); | ||
| 5963 | const main_tokens = tree.nodes.items(.main_token); | ||
| 5964 | |||
| 5965 | const operand_node = node_datas[node].lhs; | ||
| 5966 | if (operand_node != 0) { | ||
| 5967 | const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{ | ||
| 5968 | .ptr = try gz.addNodeExtended(.ret_ptr, node), | ||
| 5969 | } else .{ | ||
| 5970 | .ty = try gz.addNodeExtended(.ret_type, node), | ||
| 5971 | }; | ||
| 5972 | const operand = try expr(gz, scope, rl, operand_node); | ||
| 5973 | // TODO check operand to see if we need to generate errdefers | ||
| 5974 | try genDefers(gz, &astgen.fn_block.?.base, scope, .none); | ||
| 5975 | _ = try gz.addUnNode(.ret_node, operand, node); | ||
| 5976 | return Zir.Inst.Ref.unreachable_value; | ||
| 5977 | } | ||
| 5978 | // Returning a void value; skip error defers. | ||
| 5979 | try genDefers(gz, &astgen.fn_block.?.base, scope, .none); | ||
| 5980 | _ = try gz.addUnNode(.ret_node, .void_value, node); | ||
| 5981 | return Zir.Inst.Ref.unreachable_value; | ||
| 5982 | } | ||
| 5983 | |||
| 5984 | fn identifier( | ||
| 5985 | gz: *GenZir, | ||
| 5986 | scope: *Scope, | ||
| 5987 | rl: ResultLoc, | ||
| 5988 | ident: ast.Node.Index, | ||
| 5989 | ) InnerError!Zir.Inst.Ref { | ||
| 5990 | const tracy = trace(@src()); | ||
| 5991 | defer tracy.end(); | ||
| 5992 | |||
| 5993 | const astgen = gz.astgen; | ||
| 5994 | const tree = astgen.tree; | ||
| 5995 | const main_tokens = tree.nodes.items(.main_token); | ||
| 5996 | |||
| 5997 | const ident_token = main_tokens[ident]; | ||
| 5998 | const ident_name = try astgen.identifierTokenString(ident_token); | ||
| 5999 | if (mem.eql(u8, ident_name, "_")) { | ||
| 6000 | return astgen.failNode(ident, "'_' may not be used as an identifier", .{}); | ||
| 6001 | } | ||
| 6002 | |||
| 6003 | if (simple_types.get(ident_name)) |zir_const_ref| { | ||
| 6004 | return rvalue(gz, scope, rl, zir_const_ref, ident); | ||
| 6005 | } | ||
| 6006 | |||
| 6007 | if (ident_name.len >= 2) integer: { | ||
| 6008 | const first_c = ident_name[0]; | ||
| 6009 | if (first_c == 'i' or first_c == 'u') { | ||
| 6010 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { | ||
| 6011 | true => .signed, | ||
| 6012 | false => .unsigned, | ||
| 6013 | }; | ||
| 6014 | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { | ||
| 6015 | error.Overflow => return astgen.failNode( | ||
| 6016 | ident, | ||
| 6017 | "primitive integer type '{s}' exceeds maximum bit width of 65535", | ||
| 6018 | .{ident_name}, | ||
| 6019 | ), | ||
| 6020 | error.InvalidCharacter => break :integer, | ||
| 6021 | }; | ||
| 6022 | const result = try gz.add(.{ | ||
| 6023 | .tag = .int_type, | ||
| 6024 | .data = .{ .int_type = .{ | ||
| 6025 | .src_node = gz.nodeIndexToRelative(ident), | ||
| 6026 | .signedness = signedness, | ||
| 6027 | .bit_count = bit_count, | ||
| 6028 | } }, | ||
| 6029 | }); | ||
| 6030 | return rvalue(gz, scope, rl, result, ident); | ||
| 6031 | } | ||
| 6032 | } | ||
| 6033 | |||
| 6034 | // Local variables, including function parameters. | ||
| 6035 | const name_str_index = try astgen.identAsString(ident_token); | ||
| 6036 | { | ||
| 6037 | var s = scope; | ||
| 6038 | while (true) switch (s.tag) { | ||
| 6039 | .local_val => { | ||
| 6040 | const local_val = s.cast(Scope.LocalVal).?; | ||
| 6041 | if (local_val.name == name_str_index) { | ||
| 6042 | return rvalue(gz, scope, rl, local_val.inst, ident); | ||
| 6043 | } | ||
| 6044 | s = local_val.parent; | ||
| 6045 | }, | ||
| 6046 | .local_ptr => { | ||
| 6047 | const local_ptr = s.cast(Scope.LocalPtr).?; | ||
| 6048 | if (local_ptr.name == name_str_index) { | ||
| 6049 | switch (rl) { | ||
| 6050 | .ref, .none_or_ref => return local_ptr.ptr, | ||
| 6051 | else => { | ||
| 6052 | const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident); | ||
| 6053 | return rvalue(gz, scope, rl, loaded, ident); | ||
| 6054 | }, | ||
| 6055 | } | ||
| 6056 | } | ||
| 6057 | s = local_ptr.parent; | ||
| 6058 | }, | ||
| 6059 | .gen_zir => s = s.cast(GenZir).?.parent, | ||
| 6060 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, | ||
| 6061 | .namespace, .top => break, // TODO look for ambiguous references to decls | ||
| 6062 | }; | ||
| 6063 | } | ||
| 6064 | |||
| 6065 | // We can't look up Decls until Sema because the same ZIR code is supposed to be | ||
| 6066 | // used for multiple generic instantiations, and this may refer to a different Decl | ||
| 6067 | // depending on the scope, determined by the generic instantiation. | ||
| 6068 | switch (rl) { | ||
| 6069 | .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | ||
| 6070 | else => { | ||
| 6071 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); | ||
| 6072 | return rvalue(gz, scope, rl, result, ident); | ||
| 6073 | }, | ||
| 6074 | } | ||
| 6075 | } | ||
| 6076 | |||
| 6077 | fn stringLiteral( | ||
| 6078 | gz: *GenZir, | ||
| 6079 | scope: *Scope, | ||
| 6080 | rl: ResultLoc, | ||
| 6081 | node: ast.Node.Index, | ||
| 6082 | ) InnerError!Zir.Inst.Ref { | ||
| 6083 | const astgen = gz.astgen; | ||
| 6084 | const tree = astgen.tree; | ||
| 6085 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6086 | const str_lit_token = main_tokens[node]; | ||
| 6087 | const str = try astgen.strLitAsString(str_lit_token); | ||
| 6088 | const result = try gz.add(.{ | ||
| 6089 | .tag = .str, | ||
| 6090 | .data = .{ .str = .{ | ||
| 6091 | .start = str.index, | ||
| 6092 | .len = str.len, | ||
| 6093 | } }, | ||
| 6094 | }); | ||
| 6095 | return rvalue(gz, scope, rl, result, node); | ||
| 6096 | } | ||
| 6097 | |||
| 6098 | fn multilineStringLiteral( | ||
| 6099 | gz: *GenZir, | ||
| 6100 | scope: *Scope, | ||
| 6101 | rl: ResultLoc, | ||
| 6102 | node: ast.Node.Index, | ||
| 6103 | ) InnerError!Zir.Inst.Ref { | ||
| 6104 | const astgen = gz.astgen; | ||
| 6105 | const tree = astgen.tree; | ||
| 6106 | const node_datas = tree.nodes.items(.data); | ||
| 6107 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6108 | |||
| 6109 | const start = node_datas[node].lhs; | ||
| 6110 | const end = node_datas[node].rhs; | ||
| 6111 | |||
| 6112 | const gpa = gz.astgen.gpa; | ||
| 6113 | const string_bytes = &gz.astgen.string_bytes; | ||
| 6114 | const str_index = string_bytes.items.len; | ||
| 6115 | |||
| 6116 | // First line: do not append a newline. | ||
| 6117 | var tok_i = start; | ||
| 6118 | { | ||
| 6119 | const slice = tree.tokenSlice(tok_i); | ||
| 6120 | const line_bytes = slice[2 .. slice.len - 1]; | ||
| 6121 | try string_bytes.appendSlice(gpa, line_bytes); | ||
| 6122 | tok_i += 1; | ||
| 6123 | } | ||
| 6124 | // Following lines: each line prepends a newline. | ||
| 6125 | while (tok_i <= end) : (tok_i += 1) { | ||
| 6126 | const slice = tree.tokenSlice(tok_i); | ||
| 6127 | const line_bytes = slice[2 .. slice.len - 1]; | ||
| 6128 | try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1); | ||
| 6129 | string_bytes.appendAssumeCapacity('\n'); | ||
| 6130 | string_bytes.appendSliceAssumeCapacity(line_bytes); | ||
| 6131 | } | ||
| 6132 | const result = try gz.add(.{ | ||
| 6133 | .tag = .str, | ||
| 6134 | .data = .{ .str = .{ | ||
| 6135 | .start = @intCast(u32, str_index), | ||
| 6136 | .len = @intCast(u32, string_bytes.items.len - str_index), | ||
| 6137 | } }, | ||
| 6138 | }); | ||
| 6139 | return rvalue(gz, scope, rl, result, node); | ||
| 6140 | } | ||
| 6141 | |||
| 6142 | fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { | ||
| 6143 | const astgen = gz.astgen; | ||
| 6144 | const tree = astgen.tree; | ||
| 6145 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6146 | const main_token = main_tokens[node]; | ||
| 6147 | const slice = tree.tokenSlice(main_token); | ||
| 6148 | |||
| 6149 | var bad_index: usize = undefined; | ||
| 6150 | const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { | ||
| 6151 | error.InvalidCharacter => { | ||
| 6152 | const bad_byte = slice[bad_index]; | ||
| 6153 | return astgen.failOff( | ||
| 6154 | main_token, | ||
| 6155 | @intCast(u32, bad_index), | ||
| 6156 | "invalid character: '{c}'\n", | ||
| 6157 | .{bad_byte}, | ||
| 6158 | ); | ||
| 6159 | }, | ||
| 6160 | }; | ||
| 6161 | const result = try gz.addInt(value); | ||
| 6162 | return rvalue(gz, scope, rl, result, node); | ||
| 6163 | } | ||
| 6164 | |||
| 6165 | fn integerLiteral( | ||
| 6166 | gz: *GenZir, | ||
| 6167 | scope: *Scope, | ||
| 6168 | rl: ResultLoc, | ||
| 6169 | node: ast.Node.Index, | ||
| 6170 | ) InnerError!Zir.Inst.Ref { | ||
| 6171 | const astgen = gz.astgen; | ||
| 6172 | const tree = astgen.tree; | ||
| 6173 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6174 | const int_token = main_tokens[node]; | ||
| 6175 | const prefixed_bytes = tree.tokenSlice(int_token); | ||
| 6176 | if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| { | ||
| 6177 | const result: Zir.Inst.Ref = switch (small_int) { | ||
| 6178 | 0 => .zero, | ||
| 6179 | 1 => .one, | ||
| 6180 | else => try gz.addInt(small_int), | ||
| 6181 | }; | ||
| 6182 | return rvalue(gz, scope, rl, result, node); | ||
| 6183 | } else |err| switch (err) { | ||
| 6184 | error.InvalidCharacter => unreachable, // Caught by the parser. | ||
| 6185 | error.Overflow => {}, | ||
| 6186 | } | ||
| 6187 | |||
| 6188 | var base: u8 = 10; | ||
| 6189 | var non_prefixed: []const u8 = prefixed_bytes; | ||
| 6190 | if (mem.startsWith(u8, prefixed_bytes, "0x")) { | ||
| 6191 | base = 16; | ||
| 6192 | non_prefixed = prefixed_bytes[2..]; | ||
| 6193 | } else if (mem.startsWith(u8, prefixed_bytes, "0o")) { | ||
| 6194 | base = 8; | ||
| 6195 | non_prefixed = prefixed_bytes[2..]; | ||
| 6196 | } else if (mem.startsWith(u8, prefixed_bytes, "0b")) { | ||
| 6197 | base = 2; | ||
| 6198 | non_prefixed = prefixed_bytes[2..]; | ||
| 6199 | } | ||
| 6200 | |||
| 6201 | const gpa = astgen.gpa; | ||
| 6202 | var big_int = try std.math.big.int.Managed.init(gpa); | ||
| 6203 | defer big_int.deinit(); | ||
| 6204 | big_int.setString(base, non_prefixed) catch |err| switch (err) { | ||
| 6205 | error.InvalidCharacter => unreachable, // caught by parser | ||
| 6206 | error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above | ||
| 6207 | error.OutOfMemory => return error.OutOfMemory, | ||
| 6208 | }; | ||
| 6209 | |||
| 6210 | const limbs = big_int.limbs[0..big_int.len()]; | ||
| 6211 | assert(big_int.isPositive()); | ||
| 6212 | const result = try gz.addIntBig(limbs); | ||
| 6213 | return rvalue(gz, scope, rl, result, node); | ||
| 6214 | } | ||
| 6215 | |||
| 6216 | fn floatLiteral( | ||
| 6217 | gz: *GenZir, | ||
| 6218 | scope: *Scope, | ||
| 6219 | rl: ResultLoc, | ||
| 6220 | node: ast.Node.Index, | ||
| 6221 | ) InnerError!Zir.Inst.Ref { | ||
| 6222 | const astgen = gz.astgen; | ||
| 6223 | const arena = astgen.arena; | ||
| 6224 | const tree = astgen.tree; | ||
| 6225 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6226 | |||
| 6227 | const main_token = main_tokens[node]; | ||
| 6228 | const bytes = tree.tokenSlice(main_token); | ||
| 6229 | const float_number: f128 = if (bytes.len > 2 and bytes[1] == 'x') hex: { | ||
| 6230 | assert(bytes[0] == '0'); // validated by tokenizer | ||
| 6231 | break :hex std.fmt.parseHexFloat(f128, bytes) catch |err| switch (err) { | ||
| 6232 | error.InvalidCharacter => unreachable, // validated by tokenizer | ||
| 6233 | error.Overflow => return astgen.failNode(node, "number literal cannot be represented in a 128-bit floating point", .{}), | ||
| 6234 | }; | ||
| 6235 | } else std.fmt.parseFloat(f128, bytes) catch |err| switch (err) { | ||
| 6236 | error.InvalidCharacter => unreachable, // validated by tokenizer | ||
| 6237 | }; | ||
| 6238 | // If the value fits into a f32 without losing any precision, store it that way. | ||
| 6239 | @setFloatMode(.Strict); | ||
| 6240 | const smaller_float = @floatCast(f32, float_number); | ||
| 6241 | const bigger_again: f128 = smaller_float; | ||
| 6242 | if (bigger_again == float_number) { | ||
| 6243 | const result = try gz.addFloat(smaller_float, node); | ||
| 6244 | return rvalue(gz, scope, rl, result, node); | ||
| 6245 | } | ||
| 6246 | // We need to use 128 bits. Break the float into 4 u32 values so we can | ||
| 6247 | // put it into the `extra` array. | ||
| 6248 | const int_bits = @bitCast(u128, float_number); | ||
| 6249 | const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{ | ||
| 6250 | .piece0 = @truncate(u32, int_bits), | ||
| 6251 | .piece1 = @truncate(u32, int_bits >> 32), | ||
| 6252 | .piece2 = @truncate(u32, int_bits >> 64), | ||
| 6253 | .piece3 = @truncate(u32, int_bits >> 96), | ||
| 6254 | }); | ||
| 6255 | return rvalue(gz, scope, rl, result, node); | ||
| 6256 | } | ||
| 6257 | |||
| 6258 | fn asmExpr( | ||
| 6259 | gz: *GenZir, | ||
| 6260 | scope: *Scope, | ||
| 6261 | rl: ResultLoc, | ||
| 6262 | node: ast.Node.Index, | ||
| 6263 | full: ast.full.Asm, | ||
| 6264 | ) InnerError!Zir.Inst.Ref { | ||
| 6265 | const astgen = gz.astgen; | ||
| 6266 | const arena = astgen.arena; | ||
| 6267 | const tree = astgen.tree; | ||
| 6268 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6269 | const node_datas = tree.nodes.items(.data); | ||
| 6270 | const token_tags = tree.tokens.items(.tag); | ||
| 6271 | |||
| 6272 | const asm_source = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template); | ||
| 6273 | |||
| 6274 | // See https://github.com/ziglang/zig/issues/215 and related issues discussing | ||
| 6275 | // possible inline assembly improvements. Until then here is status quo AstGen | ||
| 6276 | // for assembly syntax. It's used by std lib crypto aesni.zig. | ||
| 6277 | |||
| 6278 | if (full.outputs.len > 32) { | ||
| 6279 | return astgen.failNode(full.outputs[32], "too many asm outputs", .{}); | ||
| 6280 | } | ||
| 6281 | var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined; | ||
| 6282 | const outputs = outputs_buffer[0..full.outputs.len]; | ||
| 6283 | |||
| 6284 | var output_type_bits: u32 = 0; | ||
| 6285 | |||
| 6286 | for (full.outputs) |output_node, i| { | ||
| 6287 | const symbolic_name = main_tokens[output_node]; | ||
| 6288 | const name = try astgen.identAsString(symbolic_name); | ||
| 6289 | const constraint_token = symbolic_name + 2; | ||
| 6290 | const constraint = (try astgen.strLitAsString(constraint_token)).index; | ||
| 6291 | const has_arrow = token_tags[symbolic_name + 4] == .arrow; | ||
| 6292 | if (has_arrow) { | ||
| 6293 | output_type_bits |= @as(u32, 1) << @intCast(u5, i); | ||
| 6294 | const out_type_node = node_datas[output_node].lhs; | ||
| 6295 | const out_type_inst = try typeExpr(gz, scope, out_type_node); | ||
| 6296 | outputs[i] = .{ | ||
| 6297 | .name = name, | ||
| 6298 | .constraint = constraint, | ||
| 6299 | .operand = out_type_inst, | ||
| 6300 | }; | ||
| 6301 | } else { | ||
| 6302 | const ident_token = symbolic_name + 4; | ||
| 6303 | const str_index = try astgen.identAsString(ident_token); | ||
| 6304 | // TODO this needs extra code for local variables. Have a look at #215 and related | ||
| 6305 | // issues and decide how to handle outputs. Do we want this to be identifiers? | ||
| 6306 | // Or maybe we want to force this to be expressions with a pointer type. | ||
| 6307 | // Until that is figured out this is only hooked up for referencing Decls. | ||
| 6308 | const operand = try gz.addStrTok(.decl_ref, str_index, ident_token); | ||
| 6309 | outputs[i] = .{ | ||
| 6310 | .name = name, | ||
| 6311 | .constraint = constraint, | ||
| 6312 | .operand = operand, | ||
| 6313 | }; | ||
| 6314 | } | ||
| 6315 | } | ||
| 6316 | |||
| 6317 | if (full.inputs.len > 32) { | ||
| 6318 | return astgen.failNode(full.inputs[32], "too many asm inputs", .{}); | ||
| 6319 | } | ||
| 6320 | var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined; | ||
| 6321 | const inputs = inputs_buffer[0..full.inputs.len]; | ||
| 6322 | |||
| 6323 | for (full.inputs) |input_node, i| { | ||
| 6324 | const symbolic_name = main_tokens[input_node]; | ||
| 6325 | const name = try astgen.identAsString(symbolic_name); | ||
| 6326 | const constraint_token = symbolic_name + 2; | ||
| 6327 | const constraint = (try astgen.strLitAsString(constraint_token)).index; | ||
| 6328 | const has_arrow = token_tags[symbolic_name + 4] == .arrow; | ||
| 6329 | const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs); | ||
| 6330 | inputs[i] = .{ | ||
| 6331 | .name = name, | ||
| 6332 | .constraint = constraint, | ||
| 6333 | .operand = operand, | ||
| 6334 | }; | ||
| 6335 | } | ||
| 6336 | |||
| 6337 | var clobbers_buffer: [32]u32 = undefined; | ||
| 6338 | var clobber_i: usize = 0; | ||
| 6339 | if (full.first_clobber) |first_clobber| clobbers: { | ||
| 6340 | // asm ("foo" ::: "a", "b") | ||
| 6341 | // asm ("foo" ::: "a", "b",) | ||
| 6342 | var tok_i = first_clobber; | ||
| 6343 | while (true) : (tok_i += 1) { | ||
| 6344 | if (clobber_i >= clobbers_buffer.len) { | ||
| 6345 | return astgen.failTok(tok_i, "too many asm clobbers", .{}); | ||
| 6346 | } | ||
| 6347 | clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index; | ||
| 6348 | clobber_i += 1; | ||
| 6349 | tok_i += 1; | ||
| 6350 | switch (token_tags[tok_i]) { | ||
| 6351 | .r_paren => break :clobbers, | ||
| 6352 | .comma => { | ||
| 6353 | if (token_tags[tok_i + 1] == .r_paren) { | ||
| 6354 | break :clobbers; | ||
| 6355 | } else { | ||
| 6356 | continue; | ||
| 6357 | } | ||
| 6358 | }, | ||
| 6359 | else => unreachable, | ||
| 6360 | } | ||
| 6361 | } | ||
| 6362 | } | ||
| 6363 | |||
| 6364 | const result = try gz.addAsm(.{ | ||
| 6365 | .node = node, | ||
| 6366 | .asm_source = asm_source, | ||
| 6367 | .is_volatile = full.volatile_token != null, | ||
| 6368 | .output_type_bits = output_type_bits, | ||
| 6369 | .outputs = outputs, | ||
| 6370 | .inputs = inputs, | ||
| 6371 | .clobbers = clobbers_buffer[0..clobber_i], | ||
| 6372 | }); | ||
| 6373 | return rvalue(gz, scope, rl, result, node); | ||
| 6374 | } | ||
| 6375 | |||
| 6376 | fn as( | ||
| 6377 | gz: *GenZir, | ||
| 6378 | scope: *Scope, | ||
| 6379 | rl: ResultLoc, | ||
| 6380 | node: ast.Node.Index, | ||
| 6381 | lhs: ast.Node.Index, | ||
| 6382 | rhs: ast.Node.Index, | ||
| 6383 | ) InnerError!Zir.Inst.Ref { | ||
| 6384 | const dest_type = try typeExpr(gz, scope, lhs); | ||
| 6385 | switch (rl) { | ||
| 6386 | .none, .none_or_ref, .discard, .ref, .ty => { | ||
| 6387 | const result = try expr(gz, scope, .{ .ty = dest_type }, rhs); | ||
| 6388 | return rvalue(gz, scope, rl, result, node); | ||
| 6389 | }, | ||
| 6390 | .ptr, .inferred_ptr => |result_ptr| { | ||
| 6391 | return asRlPtr(gz, scope, rl, result_ptr, rhs, dest_type); | ||
| 6392 | }, | ||
| 6393 | .block_ptr => |block_scope| { | ||
| 6394 | return asRlPtr(gz, scope, rl, block_scope.rl_ptr, rhs, dest_type); | ||
| 6395 | }, | ||
| 6396 | } | ||
| 6397 | } | ||
| 6398 | |||
| 6399 | fn unionInit( | ||
| 6400 | gz: *GenZir, | ||
| 6401 | scope: *Scope, | ||
| 6402 | rl: ResultLoc, | ||
| 6403 | node: ast.Node.Index, | ||
| 6404 | params: []const ast.Node.Index, | ||
| 6405 | ) InnerError!Zir.Inst.Ref { | ||
| 6406 | const union_type = try typeExpr(gz, scope, params[0]); | ||
| 6407 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | ||
| 6408 | switch (rl) { | ||
| 6409 | .none, .none_or_ref, .discard, .ref, .ty, .inferred_ptr => { | ||
| 6410 | const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ | ||
| 6411 | .container_type = union_type, | ||
| 6412 | .field_name = field_name, | ||
| 6413 | }); | ||
| 6414 | const result = try expr(gz, scope, .{ .ty = union_type }, params[2]); | ||
| 6415 | return rvalue(gz, scope, rl, result, node); | ||
| 6416 | }, | ||
| 6417 | .ptr => |result_ptr| { | ||
| 6418 | return unionInitRlPtr(gz, scope, rl, node, result_ptr, params[2], union_type, field_name); | ||
| 6419 | }, | ||
| 6420 | .block_ptr => |block_scope| { | ||
| 6421 | return unionInitRlPtr(gz, scope, rl, node, block_scope.rl_ptr, params[2], union_type, field_name); | ||
| 6422 | }, | ||
| 6423 | } | ||
| 6424 | } | ||
| 6425 | |||
| 6426 | fn unionInitRlPtr( | ||
| 6427 | parent_gz: *GenZir, | ||
| 6428 | scope: *Scope, | ||
| 6429 | rl: ResultLoc, | ||
| 6430 | node: ast.Node.Index, | ||
| 6431 | result_ptr: Zir.Inst.Ref, | ||
| 6432 | expr_node: ast.Node.Index, | ||
| 6433 | union_type: Zir.Inst.Ref, | ||
| 6434 | field_name: Zir.Inst.Ref, | ||
| 6435 | ) InnerError!Zir.Inst.Ref { | ||
| 6436 | const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{ | ||
| 6437 | .result_ptr = result_ptr, | ||
| 6438 | .union_type = union_type, | ||
| 6439 | .field_name = field_name, | ||
| 6440 | }); | ||
| 6441 | // TODO check if we need to do the elision like below in asRlPtr | ||
| 6442 | return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node); | ||
| 6443 | } | ||
| 6444 | |||
| 6445 | fn asRlPtr( | ||
| 6446 | parent_gz: *GenZir, | ||
| 6447 | scope: *Scope, | ||
| 6448 | rl: ResultLoc, | ||
| 6449 | result_ptr: Zir.Inst.Ref, | ||
| 6450 | operand_node: ast.Node.Index, | ||
| 6451 | dest_type: Zir.Inst.Ref, | ||
| 6452 | ) InnerError!Zir.Inst.Ref { | ||
| 6453 | // Detect whether this expr() call goes into rvalue() to store the result into the | ||
| 6454 | // result location. If it does, elide the coerce_result_ptr instruction | ||
| 6455 | // as well as the store instruction, instead passing the result as an rvalue. | ||
| 6456 | const astgen = parent_gz.astgen; | ||
| 6457 | |||
| 6458 | var as_scope = parent_gz.makeSubBlock(scope); | ||
| 6459 | defer as_scope.instructions.deinit(astgen.gpa); | ||
| 6460 | |||
| 6461 | as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); | ||
| 6462 | const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); | ||
| 6463 | const parent_zir = &parent_gz.instructions; | ||
| 6464 | if (as_scope.rvalue_rl_count == 1) { | ||
| 6465 | // Busted! This expression didn't actually need a pointer. | ||
| 6466 | const zir_tags = astgen.instructions.items(.tag); | ||
| 6467 | const zir_datas = astgen.instructions.items(.data); | ||
| 6468 | try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len); | ||
| 6469 | for (as_scope.instructions.items) |src_inst| { | ||
| 6470 | if (parent_gz.indexToRef(src_inst) == as_scope.rl_ptr) continue; | ||
| 6471 | if (zir_tags[src_inst] == .store_to_block_ptr) { | ||
| 6472 | if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; | ||
| 6473 | } | ||
| 6474 | parent_zir.appendAssumeCapacity(src_inst); | ||
| 6475 | } | ||
| 6476 | const casted_result = try parent_gz.addBin(.as, dest_type, result); | ||
| 6477 | return rvalue(parent_gz, scope, rl, casted_result, operand_node); | ||
| 6478 | } else { | ||
| 6479 | try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items); | ||
| 6480 | return result; | ||
| 6481 | } | ||
| 6482 | } | ||
| 6483 | |||
| 6484 | fn bitCast( | ||
| 6485 | gz: *GenZir, | ||
| 6486 | scope: *Scope, | ||
| 6487 | rl: ResultLoc, | ||
| 6488 | node: ast.Node.Index, | ||
| 6489 | lhs: ast.Node.Index, | ||
| 6490 | rhs: ast.Node.Index, | ||
| 6491 | ) InnerError!Zir.Inst.Ref { | ||
| 6492 | const astgen = gz.astgen; | ||
| 6493 | const dest_type = try typeExpr(gz, scope, lhs); | ||
| 6494 | switch (rl) { | ||
| 6495 | .none, .none_or_ref, .discard, .ty => { | ||
| 6496 | const operand = try expr(gz, scope, .none, rhs); | ||
| 6497 | const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ | ||
| 6498 | .lhs = dest_type, | ||
| 6499 | .rhs = operand, | ||
| 6500 | }); | ||
| 6501 | return rvalue(gz, scope, rl, result, node); | ||
| 6502 | }, | ||
| 6503 | .ref => { | ||
| 6504 | return astgen.failNode(node, "cannot take address of `@bitCast` result", .{}); | ||
| 6505 | }, | ||
| 6506 | .ptr, .inferred_ptr => |result_ptr| { | ||
| 6507 | return bitCastRlPtr(gz, scope, rl, node, dest_type, result_ptr, rhs); | ||
| 6508 | }, | ||
| 6509 | .block_ptr => |block| { | ||
| 6510 | return bitCastRlPtr(gz, scope, rl, node, dest_type, block.rl_ptr, rhs); | ||
| 6511 | }, | ||
| 6512 | } | ||
| 6513 | } | ||
| 6514 | |||
| 6515 | fn bitCastRlPtr( | ||
| 6516 | gz: *GenZir, | ||
| 6517 | scope: *Scope, | ||
| 6518 | rl: ResultLoc, | ||
| 6519 | node: ast.Node.Index, | ||
| 6520 | dest_type: Zir.Inst.Ref, | ||
| 6521 | result_ptr: Zir.Inst.Ref, | ||
| 6522 | rhs: ast.Node.Index, | ||
| 6523 | ) InnerError!Zir.Inst.Ref { | ||
| 6524 | const casted_result_ptr = try gz.addPlNode(.bitcast_result_ptr, node, Zir.Inst.Bin{ | ||
| 6525 | .lhs = dest_type, | ||
| 6526 | .rhs = result_ptr, | ||
| 6527 | }); | ||
| 6528 | return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs); | ||
| 6529 | } | ||
| 6530 | |||
| 6531 | fn typeOf( | ||
| 6532 | gz: *GenZir, | ||
| 6533 | scope: *Scope, | ||
| 6534 | rl: ResultLoc, | ||
| 6535 | node: ast.Node.Index, | ||
| 6536 | params: []const ast.Node.Index, | ||
| 6537 | ) InnerError!Zir.Inst.Ref { | ||
| 6538 | if (params.len < 1) { | ||
| 6539 | return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{}); | ||
| 6540 | } | ||
| 6541 | if (params.len == 1) { | ||
| 6542 | const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node); | ||
| 6543 | return rvalue(gz, scope, rl, result, node); | ||
| 6544 | } | ||
| 6545 | const arena = gz.astgen.arena; | ||
| 6546 | var items = try arena.alloc(Zir.Inst.Ref, params.len); | ||
| 6547 | for (params) |param, param_i| { | ||
| 6548 | items[param_i] = try expr(gz, scope, .none, param); | ||
| 6549 | } | ||
| 6550 | |||
| 6551 | const result = try gz.addExtendedMultiOp(.typeof_peer, node, items); | ||
| 6552 | return rvalue(gz, scope, rl, result, node); | ||
| 6553 | } | ||
| 6554 | |||
| 6555 | fn builtinCall( | ||
| 6556 | gz: *GenZir, | ||
| 6557 | scope: *Scope, | ||
| 6558 | rl: ResultLoc, | ||
| 6559 | node: ast.Node.Index, | ||
| 6560 | params: []const ast.Node.Index, | ||
| 6561 | ) InnerError!Zir.Inst.Ref { | ||
| 6562 | const astgen = gz.astgen; | ||
| 6563 | const tree = astgen.tree; | ||
| 6564 | const main_tokens = tree.nodes.items(.main_token); | ||
| 6565 | |||
| 6566 | const builtin_token = main_tokens[node]; | ||
| 6567 | const builtin_name = tree.tokenSlice(builtin_token); | ||
| 6568 | |||
| 6569 | // We handle the different builtins manually because they have different semantics depending | ||
| 6570 | // on the function. For example, `@as` and others participate in result location semantics, | ||
| 6571 | // and `@cImport` creates a special scope that collects a .c source code text buffer. | ||
| 6572 | // Also, some builtins have a variable number of parameters. | ||
| 6573 | |||
| 6574 | const info = BuiltinFn.list.get(builtin_name) orelse { | ||
| 6575 | return astgen.failNode(node, "invalid builtin function: '{s}'", .{ | ||
| 6576 | builtin_name, | ||
| 6577 | }); | ||
| 6578 | }; | ||
| 6579 | if (info.param_count) |expected| { | ||
| 6580 | if (expected != params.len) { | ||
| 6581 | const s = if (expected == 1) "" else "s"; | ||
| 6582 | return astgen.failNode(node, "expected {d} parameter{s}, found {d}", .{ | ||
| 6583 | expected, s, params.len, | ||
| 6584 | }); | ||
| 6585 | } | ||
| 6586 | } | ||
| 6587 | |||
| 6588 | // zig fmt: off | ||
| 6589 | switch (info.tag) { | ||
| 6590 | .import => { | ||
| 6591 | const node_tags = tree.nodes.items(.tag); | ||
| 6592 | const node_datas = tree.nodes.items(.data); | ||
| 6593 | const operand_node = params[0]; | ||
| 6594 | |||
| 6595 | if (node_tags[operand_node] != .string_literal) { | ||
| 6596 | // Spec reference: https://github.com/ziglang/zig/issues/2206 | ||
| 6597 | return astgen.failNode(operand_node, "@import operand must be a string literal", .{}); | ||
| 6598 | } | ||
| 6599 | const str_lit_token = main_tokens[operand_node]; | ||
| 6600 | const str = try astgen.strLitAsString(str_lit_token); | ||
| 6601 | try astgen.imports.put(astgen.gpa, str.index, {}); | ||
| 6602 | const result = try gz.addStrTok(.import, str.index, str_lit_token); | ||
| 6603 | return rvalue(gz, scope, rl, result, node); | ||
| 6604 | }, | ||
| 6605 | .compile_log => { | ||
| 6606 | const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len); | ||
| 6607 | defer astgen.gpa.free(arg_refs); | ||
| 6608 | |||
| 6609 | for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param); | ||
| 6610 | |||
| 6611 | const result = try gz.addExtendedMultiOp(.compile_log, node, arg_refs); | ||
| 6612 | return rvalue(gz, scope, rl, result, node); | ||
| 6613 | }, | ||
| 6614 | .field => { | ||
| 6615 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | ||
| 6616 | if (rl == .ref) { | ||
| 6617 | return try gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ | ||
| 6618 | .lhs = try expr(gz, scope, .ref, params[0]), | ||
| 6619 | .field_name = field_name, | ||
| 6620 | }); | ||
| 6621 | } | ||
| 6622 | const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ | ||
| 6623 | .lhs = try expr(gz, scope, .none, params[0]), | ||
| 6624 | .field_name = field_name, | ||
| 6625 | }); | ||
| 6626 | return rvalue(gz, scope, rl, result, node); | ||
| 6627 | }, | ||
| 6628 | .as => return as( gz, scope, rl, node, params[0], params[1]), | ||
| 6629 | .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), | ||
| 6630 | .TypeOf => return typeOf( gz, scope, rl, node, params), | ||
| 6631 | .union_init => return unionInit(gz, scope, rl, node, params), | ||
| 6632 | .c_import => return cImport( gz, scope, rl, node, params[0]), | ||
| 6633 | |||
| 6634 | .@"export" => { | ||
| 6635 | const node_tags = tree.nodes.items(.tag); | ||
| 6636 | // This function causes a Decl to be exported. The first parameter is not an expression, | ||
| 6637 | // but an identifier of the Decl to be exported. | ||
| 6638 | if (node_tags[params[0]] != .identifier) { | ||
| 6639 | return astgen.failNode(params[0], "the first @export parameter must be an identifier", .{}); | ||
| 6640 | } | ||
| 6641 | const ident_token = main_tokens[params[0]]; | ||
| 6642 | const decl_name = try astgen.identAsString(ident_token); | ||
| 6643 | // TODO look for local variables in scope matching `decl_name` and emit a compile | ||
| 6644 | // error. Only top-level declarations can be exported. Until this is done, the | ||
| 6645 | // compile error will end up being "use of undeclared identifier" in Sema. | ||
| 6646 | const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); | ||
| 6647 | _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ | ||
| 6648 | .decl_name = decl_name, | ||
| 6649 | .options = options, | ||
| 6650 | }); | ||
| 6651 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 6652 | }, | ||
| 6653 | .@"extern" => { | ||
| 6654 | const type_inst = try typeExpr(gz, scope, params[0]); | ||
| 6655 | const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]); | ||
| 6656 | const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ | ||
| 6657 | .node = gz.nodeIndexToRelative(node), | ||
| 6658 | .lhs = type_inst, | ||
| 6659 | .rhs = options, | ||
| 6660 | }); | ||
| 6661 | return rvalue(gz, scope, rl, result, node); | ||
| 6662 | }, | ||
| 6663 | |||
| 6664 | .breakpoint => return simpleNoOpVoid(gz, scope, rl, node, .breakpoint), | ||
| 6665 | .fence => return simpleNoOpVoid(gz, scope, rl, node, .fence), | ||
| 6666 | |||
| 6667 | .This => return rvalue(gz, scope, rl, try gz.addNodeExtended(.this, node), node), | ||
| 6668 | .return_address => return rvalue(gz, scope, rl, try gz.addNodeExtended(.ret_addr, node), node), | ||
| 6669 | .src => return rvalue(gz, scope, rl, try gz.addNodeExtended(.builtin_src, node), node), | ||
| 6670 | .error_return_trace => return rvalue(gz, scope, rl, try gz.addNodeExtended(.error_return_trace, node), node), | ||
| 6671 | .frame => return rvalue(gz, scope, rl, try gz.addNodeExtended(.frame, node), node), | ||
| 6672 | .frame_address => return rvalue(gz, scope, rl, try gz.addNodeExtended(.frame_address, node), node), | ||
| 6673 | |||
| 6674 | .type_info => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info), | ||
| 6675 | .size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of), | ||
| 6676 | .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of), | ||
| 6677 | .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of), | ||
| 6678 | |||
| 6679 | .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int), | ||
| 6680 | .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int), | ||
| 6681 | .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type }, params[0], .int_to_error), | ||
| 6682 | .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error), | ||
| 6683 | .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type }, params[0], .set_eval_branch_quota), | ||
| 6684 | .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int), | ||
| 6685 | .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int), | ||
| 6686 | .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file), | ||
| 6687 | .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name), | ||
| 6688 | .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic), | ||
| 6689 | .set_align_stack => return simpleUnOp(gz, scope, rl, node, align_rl, params[0], .set_align_stack), | ||
| 6690 | .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold), | ||
| 6691 | .set_float_mode => return simpleUnOp(gz, scope, rl, node, .{ .ty = .float_mode_type }, params[0], .set_float_mode), | ||
| 6692 | .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety), | ||
| 6693 | .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), | ||
| 6694 | .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), | ||
| 6695 | .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), | ||
| 6696 | .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), | ||
| 6697 | .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), | ||
| 6698 | .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), | ||
| 6699 | .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2), | ||
| 6700 | .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10), | ||
| 6701 | .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs), | ||
| 6702 | .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor), | ||
| 6703 | .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil), | ||
| 6704 | .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), | ||
| 6705 | .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), | ||
| 6706 | .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), | ||
| 6707 | .Type => return simpleUnOp(gz, scope, rl, node, .none, params[0], .reify), | ||
| 6708 | .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), | ||
| 6709 | .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), | ||
| 6710 | .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), | ||
| 6711 | |||
| 6712 | .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int), | ||
| 6713 | .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float), | ||
| 6714 | .int_to_ptr => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr), | ||
| 6715 | .int_to_enum => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum), | ||
| 6716 | .float_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast), | ||
| 6717 | .int_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast), | ||
| 6718 | .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast), | ||
| 6719 | .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), | ||
| 6720 | .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), | ||
| 6721 | .align_cast => { | ||
| 6722 | const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); | ||
| 6723 | const rhs = try expr(gz, scope, .none, params[1]); | ||
| 6724 | const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ | ||
| 6725 | .lhs = dest_align, | ||
| 6726 | .rhs = rhs, | ||
| 6727 | }); | ||
| 6728 | return rvalue(gz, scope, rl, result, node); | ||
| 6729 | }, | ||
| 6730 | |||
| 6731 | .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), | ||
| 6732 | .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), | ||
| 6733 | |||
| 6734 | .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz), | ||
| 6735 | .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz), | ||
| 6736 | .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count), | ||
| 6737 | .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap), | ||
| 6738 | .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse), | ||
| 6739 | |||
| 6740 | .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact), | ||
| 6741 | .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor), | ||
| 6742 | .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc), | ||
| 6743 | .mod => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod), | ||
| 6744 | .rem => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem), | ||
| 6745 | |||
| 6746 | .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact), | ||
| 6747 | .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact), | ||
| 6748 | |||
| 6749 | .bit_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of), | ||
| 6750 | .byte_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .byte_offset_of), | ||
| 6751 | |||
| 6752 | .c_undef => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef), | ||
| 6753 | .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include), | ||
| 6754 | |||
| 6755 | .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), | ||
| 6756 | .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), | ||
| 6757 | |||
| 6758 | .wasm_memory_size => { | ||
| 6759 | const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); | ||
| 6760 | const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ | ||
| 6761 | .node = gz.nodeIndexToRelative(node), | ||
| 6762 | .operand = operand, | ||
| 6763 | }); | ||
| 6764 | return rvalue(gz, scope, rl, result, node); | ||
| 6765 | }, | ||
| 6766 | .wasm_memory_grow => { | ||
| 6767 | const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); | ||
| 6768 | const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]); | ||
| 6769 | const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ | ||
| 6770 | .node = gz.nodeIndexToRelative(node), | ||
| 6771 | .lhs = index_arg, | ||
| 6772 | .rhs = delta_arg, | ||
| 6773 | }); | ||
| 6774 | return rvalue(gz, scope, rl, result, node); | ||
| 6775 | }, | ||
| 6776 | .c_define => { | ||
| 6777 | const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); | ||
| 6778 | const value = try comptimeExpr(gz, scope, .none, params[1]); | ||
| 6779 | const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ | ||
| 6780 | .node = gz.nodeIndexToRelative(node), | ||
| 6781 | .lhs = name, | ||
| 6782 | .rhs = value, | ||
| 6783 | }); | ||
| 6784 | return rvalue(gz, scope, rl, result, node); | ||
| 6785 | }, | ||
| 6786 | |||
| 6787 | .splat => { | ||
| 6788 | const len = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); | ||
| 6789 | const scalar = try expr(gz, scope, .none, params[1]); | ||
| 6790 | const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ | ||
| 6791 | .lhs = len, | ||
| 6792 | .rhs = scalar, | ||
| 6793 | }); | ||
| 6794 | return rvalue(gz, scope, rl, result, node); | ||
| 6795 | }, | ||
| 6796 | .reduce => { | ||
| 6797 | const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]); | ||
| 6798 | const scalar = try expr(gz, scope, .none, params[1]); | ||
| 6799 | const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ | ||
| 6800 | .lhs = op, | ||
| 6801 | .rhs = scalar, | ||
| 6802 | }); | ||
| 6803 | return rvalue(gz, scope, rl, result, node); | ||
| 6804 | }, | ||
| 6805 | |||
| 6806 | .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), | ||
| 6807 | .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), | ||
| 6808 | .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), | ||
| 6809 | .shl_with_overflow => { | ||
| 6810 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 6811 | const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); | ||
| 6812 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 6813 | .ptr_type_simple = .{ | ||
| 6814 | .is_allowzero = false, | ||
| 6815 | .is_mutable = true, | ||
| 6816 | .is_volatile = false, | ||
| 6817 | .size = .One, | ||
| 6818 | .elem_type = int_type, | ||
| 6819 | }, | ||
| 6820 | } }); | ||
| 6821 | const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); | ||
| 6822 | const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]); | ||
| 6823 | const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); | ||
| 6824 | const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ | ||
| 6825 | .node = gz.nodeIndexToRelative(node), | ||
| 6826 | .lhs = lhs, | ||
| 6827 | .rhs = rhs, | ||
| 6828 | .ptr = ptr, | ||
| 6829 | }); | ||
| 6830 | return rvalue(gz, scope, rl, result, node); | ||
| 6831 | }, | ||
| 6832 | |||
| 6833 | .atomic_load => { | ||
| 6834 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 6835 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 6836 | .ptr_type_simple = .{ | ||
| 6837 | .is_allowzero = false, | ||
| 6838 | .is_mutable = false, | ||
| 6839 | .is_volatile = false, | ||
| 6840 | .size = .One, | ||
| 6841 | .elem_type = int_type, | ||
| 6842 | }, | ||
| 6843 | } }); | ||
| 6844 | const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); | ||
| 6845 | const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[2]); | ||
| 6846 | const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{ | ||
| 6847 | .lhs = ptr, | ||
| 6848 | .rhs = ordering, | ||
| 6849 | }); | ||
| 6850 | return rvalue(gz, scope, rl, result, node); | ||
| 6851 | }, | ||
| 6852 | .atomic_rmw => { | ||
| 6853 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 6854 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 6855 | .ptr_type_simple = .{ | ||
| 6856 | .is_allowzero = false, | ||
| 6857 | .is_mutable = true, | ||
| 6858 | .is_volatile = false, | ||
| 6859 | .size = .One, | ||
| 6860 | .elem_type = int_type, | ||
| 6861 | }, | ||
| 6862 | } }); | ||
| 6863 | const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); | ||
| 6864 | const operation = try expr(gz, scope, .{ .ty = .atomic_rmw_op_type }, params[2]); | ||
| 6865 | const operand = try expr(gz, scope, .{ .ty = int_type }, params[3]); | ||
| 6866 | const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]); | ||
| 6867 | const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ | ||
| 6868 | .ptr = ptr, | ||
| 6869 | .operation = operation, | ||
| 6870 | .operand = operand, | ||
| 6871 | .ordering = ordering, | ||
| 6872 | }); | ||
| 6873 | return rvalue(gz, scope, rl, result, node); | ||
| 6874 | }, | ||
| 6875 | .atomic_store => { | ||
| 6876 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 6877 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 6878 | .ptr_type_simple = .{ | ||
| 6879 | .is_allowzero = false, | ||
| 6880 | .is_mutable = true, | ||
| 6881 | .is_volatile = false, | ||
| 6882 | .size = .One, | ||
| 6883 | .elem_type = int_type, | ||
| 6884 | }, | ||
| 6885 | } }); | ||
| 6886 | const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); | ||
| 6887 | const operand = try expr(gz, scope, .{ .ty = int_type }, params[2]); | ||
| 6888 | const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[3]); | ||
| 6889 | const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ | ||
| 6890 | .ptr = ptr, | ||
| 6891 | .operand = operand, | ||
| 6892 | .ordering = ordering, | ||
| 6893 | }); | ||
| 6894 | return rvalue(gz, scope, rl, result, node); | ||
| 6895 | }, | ||
| 6896 | .mul_add => { | ||
| 6897 | const float_type = try typeExpr(gz, scope, params[0]); | ||
| 6898 | const mulend1 = try expr(gz, scope, .{ .ty = float_type }, params[1]); | ||
| 6899 | const mulend2 = try expr(gz, scope, .{ .ty = float_type }, params[2]); | ||
| 6900 | const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]); | ||
| 6901 | const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ | ||
| 6902 | .mulend1 = mulend1, | ||
| 6903 | .mulend2 = mulend2, | ||
| 6904 | .addend = addend, | ||
| 6905 | }); | ||
| 6906 | return rvalue(gz, scope, rl, result, node); | ||
| 6907 | }, | ||
| 6908 | .call => { | ||
| 6909 | const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]); | ||
| 6910 | const callee = try expr(gz, scope, .none, params[1]); | ||
| 6911 | const args = try expr(gz, scope, .none, params[2]); | ||
| 6912 | const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ | ||
| 6913 | .options = options, | ||
| 6914 | .callee = callee, | ||
| 6915 | .args = args, | ||
| 6916 | }); | ||
| 6917 | return rvalue(gz, scope, rl, result, node); | ||
| 6918 | }, | ||
| 6919 | .field_parent_ptr => { | ||
| 6920 | const parent_type = try typeExpr(gz, scope, params[0]); | ||
| 6921 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); | ||
| 6922 | const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name); | ||
| 6923 | const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ | ||
| 6924 | .parent_type = parent_type, | ||
| 6925 | .field_name = field_name, | ||
| 6926 | .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]), | ||
| 6927 | }); | ||
| 6928 | return rvalue(gz, scope, rl, result, node); | ||
| 6929 | }, | ||
| 6930 | .memcpy => { | ||
| 6931 | const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ | ||
| 6932 | .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), | ||
| 6933 | .source = try expr(gz, scope, .{ .ty = .manyptr_const_u8_type }, params[1]), | ||
| 6934 | .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), | ||
| 6935 | }); | ||
| 6936 | return rvalue(gz, scope, rl, result, node); | ||
| 6937 | }, | ||
| 6938 | .memset => { | ||
| 6939 | const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ | ||
| 6940 | .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), | ||
| 6941 | .byte = try expr(gz, scope, .{ .ty = .u8_type }, params[1]), | ||
| 6942 | .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), | ||
| 6943 | }); | ||
| 6944 | return rvalue(gz, scope, rl, result, node); | ||
| 6945 | }, | ||
| 6946 | .shuffle => { | ||
| 6947 | const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ | ||
| 6948 | .elem_type = try typeExpr(gz, scope, params[0]), | ||
| 6949 | .a = try expr(gz, scope, .none, params[1]), | ||
| 6950 | .b = try expr(gz, scope, .none, params[2]), | ||
| 6951 | .mask = try comptimeExpr(gz, scope, .none, params[3]), | ||
| 6952 | }); | ||
| 6953 | return rvalue(gz, scope, rl, result, node); | ||
| 6954 | }, | ||
| 6955 | .async_call => { | ||
| 6956 | const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ | ||
| 6957 | .frame_buffer = try expr(gz, scope, .none, params[0]), | ||
| 6958 | .result_ptr = try expr(gz, scope, .none, params[1]), | ||
| 6959 | .fn_ptr = try expr(gz, scope, .none, params[2]), | ||
| 6960 | .args = try expr(gz, scope, .none, params[3]), | ||
| 6961 | }); | ||
| 6962 | return rvalue(gz, scope, rl, result, node); | ||
| 6963 | }, | ||
| 6964 | .Vector => { | ||
| 6965 | const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ | ||
| 6966 | .lhs = try comptimeExpr(gz, scope, .{.ty = .u32_type}, params[0]), | ||
| 6967 | .rhs = try typeExpr(gz, scope, params[1]), | ||
| 6968 | }); | ||
| 6969 | return rvalue(gz, scope, rl, result, node); | ||
| 6970 | }, | ||
| 6971 | |||
| 6972 | } | ||
| 6973 | // zig fmt: on | ||
| 6974 | } | ||
| 6975 | |||
| 6976 | fn simpleNoOpVoid( | ||
| 6977 | gz: *GenZir, | ||
| 6978 | scope: *Scope, | ||
| 6979 | rl: ResultLoc, | ||
| 6980 | node: ast.Node.Index, | ||
| 6981 | tag: Zir.Inst.Tag, | ||
| 6982 | ) InnerError!Zir.Inst.Ref { | ||
| 6983 | _ = try gz.addNode(tag, node); | ||
| 6984 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 6985 | } | ||
| 6986 | |||
| 6987 | fn hasDeclOrField( | ||
| 6988 | gz: *GenZir, | ||
| 6989 | scope: *Scope, | ||
| 6990 | rl: ResultLoc, | ||
| 6991 | node: ast.Node.Index, | ||
| 6992 | lhs_node: ast.Node.Index, | ||
| 6993 | rhs_node: ast.Node.Index, | ||
| 6994 | tag: Zir.Inst.Tag, | ||
| 6995 | ) InnerError!Zir.Inst.Ref { | ||
| 6996 | const container_type = try typeExpr(gz, scope, lhs_node); | ||
| 6997 | const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); | ||
| 6998 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | ||
| 6999 | .lhs = container_type, | ||
| 7000 | .rhs = name, | ||
| 7001 | }); | ||
| 7002 | return rvalue(gz, scope, rl, result, node); | ||
| 7003 | } | ||
| 7004 | |||
| 7005 | fn typeCast( | ||
| 7006 | gz: *GenZir, | ||
| 7007 | scope: *Scope, | ||
| 7008 | rl: ResultLoc, | ||
| 7009 | node: ast.Node.Index, | ||
| 7010 | lhs_node: ast.Node.Index, | ||
| 7011 | rhs_node: ast.Node.Index, | ||
| 7012 | tag: Zir.Inst.Tag, | ||
| 7013 | ) InnerError!Zir.Inst.Ref { | ||
| 7014 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | ||
| 7015 | .lhs = try typeExpr(gz, scope, lhs_node), | ||
| 7016 | .rhs = try expr(gz, scope, .none, rhs_node), | ||
| 7017 | }); | ||
| 7018 | return rvalue(gz, scope, rl, result, node); | ||
| 7019 | } | ||
| 7020 | |||
| 7021 | fn simpleUnOpType( | ||
| 7022 | gz: *GenZir, | ||
| 7023 | scope: *Scope, | ||
| 7024 | rl: ResultLoc, | ||
| 7025 | node: ast.Node.Index, | ||
| 7026 | operand_node: ast.Node.Index, | ||
| 7027 | tag: Zir.Inst.Tag, | ||
| 7028 | ) InnerError!Zir.Inst.Ref { | ||
| 7029 | const operand = try typeExpr(gz, scope, operand_node); | ||
| 7030 | const result = try gz.addUnNode(tag, operand, node); | ||
| 7031 | return rvalue(gz, scope, rl, result, node); | ||
| 7032 | } | ||
| 7033 | |||
| 7034 | fn simpleUnOp( | ||
| 7035 | gz: *GenZir, | ||
| 7036 | scope: *Scope, | ||
| 7037 | rl: ResultLoc, | ||
| 7038 | node: ast.Node.Index, | ||
| 7039 | operand_rl: ResultLoc, | ||
| 7040 | operand_node: ast.Node.Index, | ||
| 7041 | tag: Zir.Inst.Tag, | ||
| 7042 | ) InnerError!Zir.Inst.Ref { | ||
| 7043 | const operand = try expr(gz, scope, operand_rl, operand_node); | ||
| 7044 | const result = try gz.addUnNode(tag, operand, node); | ||
| 7045 | return rvalue(gz, scope, rl, result, node); | ||
| 7046 | } | ||
| 7047 | |||
| 7048 | fn cmpxchg( | ||
| 7049 | gz: *GenZir, | ||
| 7050 | scope: *Scope, | ||
| 7051 | rl: ResultLoc, | ||
| 7052 | node: ast.Node.Index, | ||
| 7053 | params: []const ast.Node.Index, | ||
| 7054 | tag: Zir.Inst.Tag, | ||
| 7055 | ) InnerError!Zir.Inst.Ref { | ||
| 7056 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 7057 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 7058 | .ptr_type_simple = .{ | ||
| 7059 | .is_allowzero = false, | ||
| 7060 | .is_mutable = true, | ||
| 7061 | .is_volatile = false, | ||
| 7062 | .size = .One, | ||
| 7063 | .elem_type = int_type, | ||
| 7064 | }, | ||
| 7065 | } }); | ||
| 7066 | const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{ | ||
| 7067 | // zig fmt: off | ||
| 7068 | .ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]), | ||
| 7069 | .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]), | ||
| 7070 | .new_value = try expr(gz, scope, .{ .ty = int_type }, params[3]), | ||
| 7071 | .success_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]), | ||
| 7072 | .fail_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[5]), | ||
| 7073 | // zig fmt: on | ||
| 7074 | }); | ||
| 7075 | return rvalue(gz, scope, rl, result, node); | ||
| 7076 | } | ||
| 7077 | |||
| 7078 | fn bitBuiltin( | ||
| 7079 | gz: *GenZir, | ||
| 7080 | scope: *Scope, | ||
| 7081 | rl: ResultLoc, | ||
| 7082 | node: ast.Node.Index, | ||
| 7083 | int_type_node: ast.Node.Index, | ||
| 7084 | operand_node: ast.Node.Index, | ||
| 7085 | tag: Zir.Inst.Tag, | ||
| 7086 | ) InnerError!Zir.Inst.Ref { | ||
| 7087 | const int_type = try typeExpr(gz, scope, int_type_node); | ||
| 7088 | const operand = try expr(gz, scope, .{ .ty = int_type }, operand_node); | ||
| 7089 | const result = try gz.addUnNode(tag, operand, node); | ||
| 7090 | return rvalue(gz, scope, rl, result, node); | ||
| 7091 | } | ||
| 7092 | |||
| 7093 | fn divBuiltin( | ||
| 7094 | gz: *GenZir, | ||
| 7095 | scope: *Scope, | ||
| 7096 | rl: ResultLoc, | ||
| 7097 | node: ast.Node.Index, | ||
| 7098 | lhs_node: ast.Node.Index, | ||
| 7099 | rhs_node: ast.Node.Index, | ||
| 7100 | tag: Zir.Inst.Tag, | ||
| 7101 | ) InnerError!Zir.Inst.Ref { | ||
| 7102 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | ||
| 7103 | .lhs = try expr(gz, scope, .none, lhs_node), | ||
| 7104 | .rhs = try expr(gz, scope, .none, rhs_node), | ||
| 7105 | }); | ||
| 7106 | return rvalue(gz, scope, rl, result, node); | ||
| 7107 | } | ||
| 7108 | |||
| 7109 | fn simpleCBuiltin( | ||
| 7110 | gz: *GenZir, | ||
| 7111 | scope: *Scope, | ||
| 7112 | rl: ResultLoc, | ||
| 7113 | node: ast.Node.Index, | ||
| 7114 | operand_node: ast.Node.Index, | ||
| 7115 | tag: Zir.Inst.Extended, | ||
| 7116 | ) InnerError!Zir.Inst.Ref { | ||
| 7117 | const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); | ||
| 7118 | _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ | ||
| 7119 | .node = gz.nodeIndexToRelative(node), | ||
| 7120 | .operand = operand, | ||
| 7121 | }); | ||
| 7122 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 7123 | } | ||
| 7124 | |||
| 7125 | fn offsetOf( | ||
| 7126 | gz: *GenZir, | ||
| 7127 | scope: *Scope, | ||
| 7128 | rl: ResultLoc, | ||
| 7129 | node: ast.Node.Index, | ||
| 7130 | lhs_node: ast.Node.Index, | ||
| 7131 | rhs_node: ast.Node.Index, | ||
| 7132 | tag: Zir.Inst.Tag, | ||
| 7133 | ) InnerError!Zir.Inst.Ref { | ||
| 7134 | const type_inst = try typeExpr(gz, scope, lhs_node); | ||
| 7135 | const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); | ||
| 7136 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | ||
| 7137 | .lhs = type_inst, | ||
| 7138 | .rhs = field_name, | ||
| 7139 | }); | ||
| 7140 | return rvalue(gz, scope, rl, result, node); | ||
| 7141 | } | ||
| 7142 | |||
| 7143 | fn shiftOp( | ||
| 7144 | gz: *GenZir, | ||
| 7145 | scope: *Scope, | ||
| 7146 | rl: ResultLoc, | ||
| 7147 | node: ast.Node.Index, | ||
| 7148 | lhs_node: ast.Node.Index, | ||
| 7149 | rhs_node: ast.Node.Index, | ||
| 7150 | tag: Zir.Inst.Tag, | ||
| 7151 | ) InnerError!Zir.Inst.Ref { | ||
| 7152 | const lhs = try expr(gz, scope, .none, lhs_node); | ||
| 7153 | const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); | ||
| 7154 | const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); | ||
| 7155 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | ||
| 7156 | .lhs = lhs, | ||
| 7157 | .rhs = rhs, | ||
| 7158 | }); | ||
| 7159 | return rvalue(gz, scope, rl, result, node); | ||
| 7160 | } | ||
| 7161 | |||
| 7162 | fn cImport( | ||
| 7163 | gz: *GenZir, | ||
| 7164 | scope: *Scope, | ||
| 7165 | rl: ResultLoc, | ||
| 7166 | node: ast.Node.Index, | ||
| 7167 | body_node: ast.Node.Index, | ||
| 7168 | ) InnerError!Zir.Inst.Ref { | ||
| 7169 | const astgen = gz.astgen; | ||
| 7170 | const gpa = astgen.gpa; | ||
| 7171 | |||
| 7172 | var block_scope = gz.makeSubBlock(scope); | ||
| 7173 | block_scope.force_comptime = true; | ||
| 7174 | defer block_scope.instructions.deinit(gpa); | ||
| 7175 | |||
| 7176 | const block_inst = try gz.addBlock(.c_import, node); | ||
| 7177 | const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); | ||
| 7178 | if (!gz.refIsNoReturn(block_result)) { | ||
| 7179 | _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); | ||
| 7180 | } | ||
| 7181 | try block_scope.setBlockBody(block_inst); | ||
| 7182 | try gz.instructions.append(gpa, block_inst); | ||
| 7183 | |||
| 7184 | return rvalue(gz, scope, rl, .void_value, node); | ||
| 7185 | } | ||
| 7186 | |||
| 7187 | fn overflowArithmetic( | ||
| 7188 | gz: *GenZir, | ||
| 7189 | scope: *Scope, | ||
| 7190 | rl: ResultLoc, | ||
| 7191 | node: ast.Node.Index, | ||
| 7192 | params: []const ast.Node.Index, | ||
| 7193 | tag: Zir.Inst.Extended, | ||
| 7194 | ) InnerError!Zir.Inst.Ref { | ||
| 7195 | const int_type = try typeExpr(gz, scope, params[0]); | ||
| 7196 | const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ | ||
| 7197 | .ptr_type_simple = .{ | ||
| 7198 | .is_allowzero = false, | ||
| 7199 | .is_mutable = true, | ||
| 7200 | .is_volatile = false, | ||
| 7201 | .size = .One, | ||
| 7202 | .elem_type = int_type, | ||
| 7203 | }, | ||
| 7204 | } }); | ||
| 7205 | const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); | ||
| 7206 | const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]); | ||
| 7207 | const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); | ||
| 7208 | const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ | ||
| 7209 | .node = gz.nodeIndexToRelative(node), | ||
| 7210 | .lhs = lhs, | ||
| 7211 | .rhs = rhs, | ||
| 7212 | .ptr = ptr, | ||
| 7213 | }); | ||
| 7214 | return rvalue(gz, scope, rl, result, node); | ||
| 7215 | } | ||
| 7216 | |||
| 7217 | fn callExpr( | ||
| 7218 | gz: *GenZir, | ||
| 7219 | scope: *Scope, | ||
| 7220 | rl: ResultLoc, | ||
| 7221 | node: ast.Node.Index, | ||
| 7222 | call: ast.full.Call, | ||
| 7223 | ) InnerError!Zir.Inst.Ref { | ||
| 7224 | const astgen = gz.astgen; | ||
| 7225 | const lhs = try expr(gz, scope, .none, call.ast.fn_expr); | ||
| 7226 | |||
| 7227 | const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len); | ||
| 7228 | defer astgen.gpa.free(args); | ||
| 7229 | |||
| 7230 | for (call.ast.params) |param_node, i| { | ||
| 7231 | const param_type = try gz.add(.{ | ||
| 7232 | .tag = .param_type, | ||
| 7233 | .data = .{ .param_type = .{ | ||
| 7234 | .callee = lhs, | ||
| 7235 | .param_index = @intCast(u32, i), | ||
| 7236 | } }, | ||
| 7237 | }); | ||
| 7238 | args[i] = try expr(gz, scope, .{ .ty = param_type }, param_node); | ||
| 7239 | } | ||
| 7240 | |||
| 7241 | const modifier: std.builtin.CallOptions.Modifier = blk: { | ||
| 7242 | if (gz.force_comptime) { | ||
| 7243 | break :blk .compile_time; | ||
| 7244 | } | ||
| 7245 | if (call.async_token != null) { | ||
| 7246 | break :blk .async_kw; | ||
| 7247 | } | ||
| 7248 | if (gz.nosuspend_node != 0) { | ||
| 7249 | break :blk .no_async; | ||
| 7250 | } | ||
| 7251 | break :blk .auto; | ||
| 7252 | }; | ||
| 7253 | const result: Zir.Inst.Ref = res: { | ||
| 7254 | const tag: Zir.Inst.Tag = switch (modifier) { | ||
| 7255 | .auto => .call, | ||
| 7256 | .async_kw => .call_async, | ||
| 7257 | .never_tail => unreachable, | ||
| 7258 | .never_inline => unreachable, | ||
| 7259 | .no_async => .call_nosuspend, | ||
| 7260 | .always_tail => unreachable, | ||
| 7261 | .always_inline => unreachable, | ||
| 7262 | .compile_time => .call_compile_time, | ||
| 7263 | }; | ||
| 7264 | break :res try gz.addCall(tag, lhs, args, node); | ||
| 7265 | }; | ||
| 7266 | return rvalue(gz, scope, rl, result, node); // TODO function call with result location | ||
| 7267 | } | ||
| 7268 | |||
| 7269 | pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{ | ||
| 7270 | .{ "anyerror", .anyerror_type }, | ||
| 7271 | .{ "anyframe", .anyframe_type }, | ||
| 7272 | .{ "bool", .bool_type }, | ||
| 7273 | .{ "c_int", .c_int_type }, | ||
| 7274 | .{ "c_long", .c_long_type }, | ||
| 7275 | .{ "c_longdouble", .c_longdouble_type }, | ||
| 7276 | .{ "c_longlong", .c_longlong_type }, | ||
| 7277 | .{ "c_short", .c_short_type }, | ||
| 7278 | .{ "c_uint", .c_uint_type }, | ||
| 7279 | .{ "c_ulong", .c_ulong_type }, | ||
| 7280 | .{ "c_ulonglong", .c_ulonglong_type }, | ||
| 7281 | .{ "c_ushort", .c_ushort_type }, | ||
| 7282 | .{ "c_void", .c_void_type }, | ||
| 7283 | .{ "comptime_float", .comptime_float_type }, | ||
| 7284 | .{ "comptime_int", .comptime_int_type }, | ||
| 7285 | .{ "f128", .f128_type }, | ||
| 7286 | .{ "f16", .f16_type }, | ||
| 7287 | .{ "f32", .f32_type }, | ||
| 7288 | .{ "f64", .f64_type }, | ||
| 7289 | .{ "false", .bool_false }, | ||
| 7290 | .{ "i16", .i16_type }, | ||
| 7291 | .{ "i32", .i32_type }, | ||
| 7292 | .{ "i64", .i64_type }, | ||
| 7293 | .{ "i128", .i128_type }, | ||
| 7294 | .{ "i8", .i8_type }, | ||
| 7295 | .{ "isize", .isize_type }, | ||
| 7296 | .{ "noreturn", .noreturn_type }, | ||
| 7297 | .{ "null", .null_value }, | ||
| 7298 | .{ "true", .bool_true }, | ||
| 7299 | .{ "type", .type_type }, | ||
| 7300 | .{ "u16", .u16_type }, | ||
| 7301 | .{ "u32", .u32_type }, | ||
| 7302 | .{ "u64", .u64_type }, | ||
| 7303 | .{ "u128", .u128_type }, | ||
| 7304 | .{ "u8", .u8_type }, | ||
| 7305 | .{ "undefined", .undef }, | ||
| 7306 | .{ "usize", .usize_type }, | ||
| 7307 | .{ "void", .void_type }, | ||
| 7308 | }); | ||
| 7309 | |||
| 7310 | fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool { | ||
| 7311 | const node_tags = tree.nodes.items(.tag); | ||
| 7312 | const node_datas = tree.nodes.items(.data); | ||
| 7313 | const main_tokens = tree.nodes.items(.main_token); | ||
| 7314 | const token_tags = tree.tokens.items(.tag); | ||
| 7315 | |||
| 7316 | var node = start_node; | ||
| 7317 | while (true) { | ||
| 7318 | switch (node_tags[node]) { | ||
| 7319 | .root, | ||
| 7320 | .@"usingnamespace", | ||
| 7321 | .test_decl, | ||
| 7322 | .switch_case, | ||
| 7323 | .switch_case_one, | ||
| 7324 | .container_field_init, | ||
| 7325 | .container_field_align, | ||
| 7326 | .container_field, | ||
| 7327 | .asm_output, | ||
| 7328 | .asm_input, | ||
| 7329 | => unreachable, | ||
| 7330 | |||
| 7331 | .@"return", | ||
| 7332 | .@"break", | ||
| 7333 | .@"continue", | ||
| 7334 | .bit_not, | ||
| 7335 | .bool_not, | ||
| 7336 | .global_var_decl, | ||
| 7337 | .local_var_decl, | ||
| 7338 | .simple_var_decl, | ||
| 7339 | .aligned_var_decl, | ||
| 7340 | .@"defer", | ||
| 7341 | .@"errdefer", | ||
| 7342 | .address_of, | ||
| 7343 | .optional_type, | ||
| 7344 | .negation, | ||
| 7345 | .negation_wrap, | ||
| 7346 | .@"resume", | ||
| 7347 | .array_type, | ||
| 7348 | .array_type_sentinel, | ||
| 7349 | .ptr_type_aligned, | ||
| 7350 | .ptr_type_sentinel, | ||
| 7351 | .ptr_type, | ||
| 7352 | .ptr_type_bit_range, | ||
| 7353 | .@"suspend", | ||
| 7354 | .@"anytype", | ||
| 7355 | .fn_proto_simple, | ||
| 7356 | .fn_proto_multi, | ||
| 7357 | .fn_proto_one, | ||
| 7358 | .fn_proto, | ||
| 7359 | .fn_decl, | ||
| 7360 | .anyframe_type, | ||
| 4440 | .anyframe_literal, | 7361 | .anyframe_literal, |
| 4441 | .integer_literal, | 7362 | .integer_literal, |
| 4442 | .float_literal, | 7363 | .float_literal, |
| ... | @@ -4568,140 +7489,1607 @@ fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) | ... | @@ -4568,140 +7489,1607 @@ fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) |
| 4568 | .async_call_comma, | 7489 | .async_call_comma, |
| 4569 | => return true, | 7490 | => return true, |
| 4570 | 7491 | ||
| 4571 | .block_two, | 7492 | .block_two, |
| 4572 | .block_two_semicolon, | 7493 | .block_two_semicolon, |
| 4573 | .block, | 7494 | .block, |
| 4574 | .block_semicolon, | 7495 | .block_semicolon, |
| 4575 | => { | 7496 | => { |
| 4576 | const lbrace = main_tokens[node]; | 7497 | const lbrace = main_tokens[node]; |
| 4577 | if (token_tags[lbrace - 1] == .colon) { | 7498 | if (token_tags[lbrace - 1] == .colon) { |
| 4578 | // Labeled blocks may need a memory location to forward | 7499 | // Labeled blocks may need a memory location to forward |
| 4579 | // to their break statements. | 7500 | // to their break statements. |
| 4580 | return true; | 7501 | return true; |
| 4581 | } else { | 7502 | } else { |
| 4582 | return false; | 7503 | return false; |
| 4583 | } | 7504 | } |
| 7505 | }, | ||
| 7506 | |||
| 7507 | .builtin_call, | ||
| 7508 | .builtin_call_comma, | ||
| 7509 | .builtin_call_two, | ||
| 7510 | .builtin_call_two_comma, | ||
| 7511 | => { | ||
| 7512 | const builtin_token = main_tokens[node]; | ||
| 7513 | const builtin_name = tree.tokenSlice(builtin_token); | ||
| 7514 | // If the builtin is an invalid name, we don't cause an error here; instead | ||
| 7515 | // let it pass, and the error will be "invalid builtin function" later. | ||
| 7516 | const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; | ||
| 7517 | return builtin_info.needs_mem_loc; | ||
| 7518 | }, | ||
| 7519 | } | ||
| 7520 | } | ||
| 7521 | } | ||
| 7522 | |||
| 7523 | /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of | ||
| 7524 | /// result locations must call this function on their result. | ||
| 7525 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. | ||
| 7526 | /// If the `ResultLoc` is `ty`, it will coerce the result to the type. | ||
| 7527 | fn rvalue( | ||
| 7528 | gz: *GenZir, | ||
| 7529 | scope: *Scope, | ||
| 7530 | rl: ResultLoc, | ||
| 7531 | result: Zir.Inst.Ref, | ||
| 7532 | src_node: ast.Node.Index, | ||
| 7533 | ) InnerError!Zir.Inst.Ref { | ||
| 7534 | switch (rl) { | ||
| 7535 | .none, .none_or_ref => return result, | ||
| 7536 | .discard => { | ||
| 7537 | // Emit a compile error for discarding error values. | ||
| 7538 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); | ||
| 7539 | return result; | ||
| 7540 | }, | ||
| 7541 | .ref => { | ||
| 7542 | // We need a pointer but we have a value. | ||
| 7543 | const tree = gz.astgen.tree; | ||
| 7544 | const src_token = tree.firstToken(src_node); | ||
| 7545 | return gz.addUnTok(.ref, result, src_token); | ||
| 7546 | }, | ||
| 7547 | .ty => |ty_inst| { | ||
| 7548 | // Quickly eliminate some common, unnecessary type coercion. | ||
| 7549 | const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; | ||
| 7550 | const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; | ||
| 7551 | const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32; | ||
| 7552 | const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32; | ||
| 7553 | const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32; | ||
| 7554 | switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { | ||
| 7555 | as_ty | @enumToInt(Zir.Inst.Ref.u8_type), | ||
| 7556 | as_ty | @enumToInt(Zir.Inst.Ref.i8_type), | ||
| 7557 | as_ty | @enumToInt(Zir.Inst.Ref.u16_type), | ||
| 7558 | as_ty | @enumToInt(Zir.Inst.Ref.i16_type), | ||
| 7559 | as_ty | @enumToInt(Zir.Inst.Ref.u32_type), | ||
| 7560 | as_ty | @enumToInt(Zir.Inst.Ref.i32_type), | ||
| 7561 | as_ty | @enumToInt(Zir.Inst.Ref.u64_type), | ||
| 7562 | as_ty | @enumToInt(Zir.Inst.Ref.i64_type), | ||
| 7563 | as_ty | @enumToInt(Zir.Inst.Ref.usize_type), | ||
| 7564 | as_ty | @enumToInt(Zir.Inst.Ref.isize_type), | ||
| 7565 | as_ty | @enumToInt(Zir.Inst.Ref.c_short_type), | ||
| 7566 | as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type), | ||
| 7567 | as_ty | @enumToInt(Zir.Inst.Ref.c_int_type), | ||
| 7568 | as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type), | ||
| 7569 | as_ty | @enumToInt(Zir.Inst.Ref.c_long_type), | ||
| 7570 | as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type), | ||
| 7571 | as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type), | ||
| 7572 | as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type), | ||
| 7573 | as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type), | ||
| 7574 | as_ty | @enumToInt(Zir.Inst.Ref.f16_type), | ||
| 7575 | as_ty | @enumToInt(Zir.Inst.Ref.f32_type), | ||
| 7576 | as_ty | @enumToInt(Zir.Inst.Ref.f64_type), | ||
| 7577 | as_ty | @enumToInt(Zir.Inst.Ref.f128_type), | ||
| 7578 | as_ty | @enumToInt(Zir.Inst.Ref.c_void_type), | ||
| 7579 | as_ty | @enumToInt(Zir.Inst.Ref.bool_type), | ||
| 7580 | as_ty | @enumToInt(Zir.Inst.Ref.void_type), | ||
| 7581 | as_ty | @enumToInt(Zir.Inst.Ref.type_type), | ||
| 7582 | as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type), | ||
| 7583 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), | ||
| 7584 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), | ||
| 7585 | as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), | ||
| 7586 | as_ty | @enumToInt(Zir.Inst.Ref.null_type), | ||
| 7587 | as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), | ||
| 7588 | as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), | ||
| 7589 | as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), | ||
| 7590 | as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), | ||
| 7591 | as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), | ||
| 7592 | as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), | ||
| 7593 | as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), | ||
| 7594 | as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), | ||
| 7595 | as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), | ||
| 7596 | as_comptime_int | @enumToInt(Zir.Inst.Ref.one), | ||
| 7597 | as_bool | @enumToInt(Zir.Inst.Ref.bool_true), | ||
| 7598 | as_bool | @enumToInt(Zir.Inst.Ref.bool_false), | ||
| 7599 | as_usize | @enumToInt(Zir.Inst.Ref.zero_usize), | ||
| 7600 | as_usize | @enumToInt(Zir.Inst.Ref.one_usize), | ||
| 7601 | as_void | @enumToInt(Zir.Inst.Ref.void_value), | ||
| 7602 | => return result, // type of result is already correct | ||
| 7603 | |||
| 7604 | // Need an explicit type coercion instruction. | ||
| 7605 | else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{ | ||
| 7606 | .dest_type = ty_inst, | ||
| 7607 | .operand = result, | ||
| 7608 | }), | ||
| 7609 | } | ||
| 7610 | }, | ||
| 7611 | .ptr => |ptr_inst| { | ||
| 7612 | _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{ | ||
| 7613 | .lhs = ptr_inst, | ||
| 7614 | .rhs = result, | ||
| 7615 | }); | ||
| 7616 | return result; | ||
| 7617 | }, | ||
| 7618 | .inferred_ptr => |alloc| { | ||
| 7619 | _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); | ||
| 7620 | return result; | ||
| 7621 | }, | ||
| 7622 | .block_ptr => |block_scope| { | ||
| 7623 | block_scope.rvalue_rl_count += 1; | ||
| 7624 | _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); | ||
| 7625 | return result; | ||
| 7626 | }, | ||
| 7627 | } | ||
| 7628 | } | ||
| 7629 | |||
| 7630 | /// Given an identifier token, obtain the string for it. | ||
| 7631 | /// If the token uses @"" syntax, parses as a string, reports errors if applicable, | ||
| 7632 | /// and allocates the result within `astgen.arena`. | ||
| 7633 | /// Otherwise, returns a reference to the source code bytes directly. | ||
| 7634 | /// See also `appendIdentStr` and `parseStrLit`. | ||
| 7635 | fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 { | ||
| 7636 | const tree = astgen.tree; | ||
| 7637 | const token_tags = tree.tokens.items(.tag); | ||
| 7638 | assert(token_tags[token] == .identifier); | ||
| 7639 | const ident_name = tree.tokenSlice(token); | ||
| 7640 | if (!mem.startsWith(u8, ident_name, "@")) { | ||
| 7641 | return ident_name; | ||
| 7642 | } | ||
| 7643 | var buf: ArrayListUnmanaged(u8) = .{}; | ||
| 7644 | defer buf.deinit(astgen.gpa); | ||
| 7645 | try astgen.parseStrLit(token, &buf, ident_name, 1); | ||
| 7646 | const duped = try astgen.arena.dupe(u8, buf.items); | ||
| 7647 | return duped; | ||
| 7648 | } | ||
| 7649 | |||
| 7650 | /// Given an identifier token, obtain the string for it (possibly parsing as a string | ||
| 7651 | /// literal if it is @"" syntax), and append the string to `buf`. | ||
| 7652 | /// See also `identifierTokenString` and `parseStrLit`. | ||
| 7653 | fn appendIdentStr( | ||
| 7654 | astgen: *AstGen, | ||
| 7655 | token: ast.TokenIndex, | ||
| 7656 | buf: *ArrayListUnmanaged(u8), | ||
| 7657 | ) InnerError!void { | ||
| 7658 | const tree = astgen.tree; | ||
| 7659 | const token_tags = tree.tokens.items(.tag); | ||
| 7660 | assert(token_tags[token] == .identifier); | ||
| 7661 | const ident_name = tree.tokenSlice(token); | ||
| 7662 | if (!mem.startsWith(u8, ident_name, "@")) { | ||
| 7663 | return buf.appendSlice(astgen.gpa, ident_name); | ||
| 7664 | } else { | ||
| 7665 | return astgen.parseStrLit(token, buf, ident_name, 1); | ||
| 7666 | } | ||
| 7667 | } | ||
| 7668 | |||
| 7669 | /// Appends the result to `buf`. | ||
| 7670 | fn parseStrLit( | ||
| 7671 | astgen: *AstGen, | ||
| 7672 | token: ast.TokenIndex, | ||
| 7673 | buf: *ArrayListUnmanaged(u8), | ||
| 7674 | bytes: []const u8, | ||
| 7675 | offset: u32, | ||
| 7676 | ) InnerError!void { | ||
| 7677 | const tree = astgen.tree; | ||
| 7678 | const raw_string = bytes[offset..]; | ||
| 7679 | var buf_managed = buf.toManaged(astgen.gpa); | ||
| 7680 | const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); | ||
| 7681 | buf.* = buf_managed.toUnmanaged(); | ||
| 7682 | switch (try result) { | ||
| 7683 | .success => return, | ||
| 7684 | .invalid_character => |bad_index| { | ||
| 7685 | return astgen.failOff( | ||
| 7686 | token, | ||
| 7687 | offset + @intCast(u32, bad_index), | ||
| 7688 | "invalid string literal character: '{c}'", | ||
| 7689 | .{raw_string[bad_index]}, | ||
| 7690 | ); | ||
| 7691 | }, | ||
| 7692 | .expected_hex_digits => |bad_index| { | ||
| 7693 | return astgen.failOff( | ||
| 7694 | token, | ||
| 7695 | offset + @intCast(u32, bad_index), | ||
| 7696 | "expected hex digits after '\\x'", | ||
| 7697 | .{}, | ||
| 7698 | ); | ||
| 7699 | }, | ||
| 7700 | .invalid_hex_escape => |bad_index| { | ||
| 7701 | return astgen.failOff( | ||
| 7702 | token, | ||
| 7703 | offset + @intCast(u32, bad_index), | ||
| 7704 | "invalid hex digit: '{c}'", | ||
| 7705 | .{raw_string[bad_index]}, | ||
| 7706 | ); | ||
| 7707 | }, | ||
| 7708 | .invalid_unicode_escape => |bad_index| { | ||
| 7709 | return astgen.failOff( | ||
| 7710 | token, | ||
| 7711 | offset + @intCast(u32, bad_index), | ||
| 7712 | "invalid unicode digit: '{c}'", | ||
| 7713 | .{raw_string[bad_index]}, | ||
| 7714 | ); | ||
| 7715 | }, | ||
| 7716 | .missing_matching_rbrace => |bad_index| { | ||
| 7717 | return astgen.failOff( | ||
| 7718 | token, | ||
| 7719 | offset + @intCast(u32, bad_index), | ||
| 7720 | "missing matching '}}' character", | ||
| 7721 | .{}, | ||
| 7722 | ); | ||
| 7723 | }, | ||
| 7724 | .expected_unicode_digits => |bad_index| { | ||
| 7725 | return astgen.failOff( | ||
| 7726 | token, | ||
| 7727 | offset + @intCast(u32, bad_index), | ||
| 7728 | "expected unicode digits after '\\u'", | ||
| 7729 | .{}, | ||
| 7730 | ); | ||
| 7731 | }, | ||
| 7732 | } | ||
| 7733 | } | ||
| 7734 | |||
| 7735 | fn failNode( | ||
| 7736 | astgen: *AstGen, | ||
| 7737 | node: ast.Node.Index, | ||
| 7738 | comptime format: []const u8, | ||
| 7739 | args: anytype, | ||
| 7740 | ) InnerError { | ||
| 7741 | return astgen.failNodeNotes(node, format, args, &[0]u32{}); | ||
| 7742 | } | ||
| 7743 | |||
| 7744 | fn failNodeNotes( | ||
| 7745 | astgen: *AstGen, | ||
| 7746 | node: ast.Node.Index, | ||
| 7747 | comptime format: []const u8, | ||
| 7748 | args: anytype, | ||
| 7749 | notes: []const u32, | ||
| 7750 | ) InnerError { | ||
| 7751 | @setCold(true); | ||
| 7752 | const string_bytes = &astgen.string_bytes; | ||
| 7753 | const msg = @intCast(u32, string_bytes.items.len); | ||
| 7754 | { | ||
| 7755 | var managed = string_bytes.toManaged(astgen.gpa); | ||
| 7756 | defer string_bytes.* = managed.toUnmanaged(); | ||
| 7757 | try managed.writer().print(format ++ "\x00", args); | ||
| 7758 | } | ||
| 7759 | const notes_index: u32 = if (notes.len != 0) blk: { | ||
| 7760 | const notes_start = astgen.extra.items.len; | ||
| 7761 | try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len); | ||
| 7762 | astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); | ||
| 7763 | astgen.extra.appendSliceAssumeCapacity(notes); | ||
| 7764 | break :blk @intCast(u32, notes_start); | ||
| 7765 | } else 0; | ||
| 7766 | try astgen.compile_errors.append(astgen.gpa, .{ | ||
| 7767 | .msg = msg, | ||
| 7768 | .node = node, | ||
| 7769 | .token = 0, | ||
| 7770 | .byte_offset = 0, | ||
| 7771 | .notes = notes_index, | ||
| 7772 | }); | ||
| 7773 | return error.AnalysisFail; | ||
| 7774 | } | ||
| 7775 | |||
| 7776 | fn failTok( | ||
| 7777 | astgen: *AstGen, | ||
| 7778 | token: ast.TokenIndex, | ||
| 7779 | comptime format: []const u8, | ||
| 7780 | args: anytype, | ||
| 7781 | ) InnerError { | ||
| 7782 | return astgen.failTokNotes(token, format, args, &[0]u32{}); | ||
| 7783 | } | ||
| 7784 | |||
| 7785 | fn failTokNotes( | ||
| 7786 | astgen: *AstGen, | ||
| 7787 | token: ast.TokenIndex, | ||
| 7788 | comptime format: []const u8, | ||
| 7789 | args: anytype, | ||
| 7790 | notes: []const u32, | ||
| 7791 | ) InnerError { | ||
| 7792 | @setCold(true); | ||
| 7793 | const string_bytes = &astgen.string_bytes; | ||
| 7794 | const msg = @intCast(u32, string_bytes.items.len); | ||
| 7795 | { | ||
| 7796 | var managed = string_bytes.toManaged(astgen.gpa); | ||
| 7797 | defer string_bytes.* = managed.toUnmanaged(); | ||
| 7798 | try managed.writer().print(format ++ "\x00", args); | ||
| 7799 | } | ||
| 7800 | const notes_index: u32 = if (notes.len != 0) blk: { | ||
| 7801 | const notes_start = astgen.extra.items.len; | ||
| 7802 | try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len); | ||
| 7803 | astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); | ||
| 7804 | astgen.extra.appendSliceAssumeCapacity(notes); | ||
| 7805 | break :blk @intCast(u32, notes_start); | ||
| 7806 | } else 0; | ||
| 7807 | try astgen.compile_errors.append(astgen.gpa, .{ | ||
| 7808 | .msg = msg, | ||
| 7809 | .node = 0, | ||
| 7810 | .token = token, | ||
| 7811 | .byte_offset = 0, | ||
| 7812 | .notes = notes_index, | ||
| 7813 | }); | ||
| 7814 | return error.AnalysisFail; | ||
| 7815 | } | ||
| 7816 | |||
| 7817 | /// Same as `fail`, except given an absolute byte offset. | ||
| 7818 | fn failOff( | ||
| 7819 | astgen: *AstGen, | ||
| 7820 | token: ast.TokenIndex, | ||
| 7821 | byte_offset: u32, | ||
| 7822 | comptime format: []const u8, | ||
| 7823 | args: anytype, | ||
| 7824 | ) InnerError { | ||
| 7825 | @setCold(true); | ||
| 7826 | const string_bytes = &astgen.string_bytes; | ||
| 7827 | const msg = @intCast(u32, string_bytes.items.len); | ||
| 7828 | { | ||
| 7829 | var managed = string_bytes.toManaged(astgen.gpa); | ||
| 7830 | defer string_bytes.* = managed.toUnmanaged(); | ||
| 7831 | try managed.writer().print(format ++ "\x00", args); | ||
| 7832 | } | ||
| 7833 | try astgen.compile_errors.append(astgen.gpa, .{ | ||
| 7834 | .msg = msg, | ||
| 7835 | .node = 0, | ||
| 7836 | .token = token, | ||
| 7837 | .byte_offset = byte_offset, | ||
| 7838 | .notes = 0, | ||
| 7839 | }); | ||
| 7840 | return error.AnalysisFail; | ||
| 7841 | } | ||
| 7842 | |||
| 7843 | fn errNoteTok( | ||
| 7844 | astgen: *AstGen, | ||
| 7845 | token: ast.TokenIndex, | ||
| 7846 | comptime format: []const u8, | ||
| 7847 | args: anytype, | ||
| 7848 | ) Allocator.Error!u32 { | ||
| 7849 | @setCold(true); | ||
| 7850 | const string_bytes = &astgen.string_bytes; | ||
| 7851 | const msg = @intCast(u32, string_bytes.items.len); | ||
| 7852 | { | ||
| 7853 | var managed = string_bytes.toManaged(astgen.gpa); | ||
| 7854 | defer string_bytes.* = managed.toUnmanaged(); | ||
| 7855 | try managed.writer().print(format ++ "\x00", args); | ||
| 7856 | } | ||
| 7857 | return astgen.addExtra(Zir.Inst.CompileErrors.Item{ | ||
| 7858 | .msg = msg, | ||
| 7859 | .node = 0, | ||
| 7860 | .token = token, | ||
| 7861 | .byte_offset = 0, | ||
| 7862 | .notes = 0, | ||
| 7863 | }); | ||
| 7864 | } | ||
| 7865 | |||
| 7866 | fn errNoteNode( | ||
| 7867 | astgen: *AstGen, | ||
| 7868 | node: ast.Node.Index, | ||
| 7869 | comptime format: []const u8, | ||
| 7870 | args: anytype, | ||
| 7871 | ) Allocator.Error!u32 { | ||
| 7872 | @setCold(true); | ||
| 7873 | const string_bytes = &astgen.string_bytes; | ||
| 7874 | const msg = @intCast(u32, string_bytes.items.len); | ||
| 7875 | { | ||
| 7876 | var managed = string_bytes.toManaged(astgen.gpa); | ||
| 7877 | defer string_bytes.* = managed.toUnmanaged(); | ||
| 7878 | try managed.writer().print(format ++ "\x00", args); | ||
| 7879 | } | ||
| 7880 | return astgen.addExtra(Zir.Inst.CompileErrors.Item{ | ||
| 7881 | .msg = msg, | ||
| 7882 | .node = node, | ||
| 7883 | .token = 0, | ||
| 7884 | .byte_offset = 0, | ||
| 7885 | .notes = 0, | ||
| 7886 | }); | ||
| 7887 | } | ||
| 7888 | |||
| 7889 | fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 { | ||
| 7890 | const gpa = astgen.gpa; | ||
| 7891 | const string_bytes = &astgen.string_bytes; | ||
| 7892 | const str_index = @intCast(u32, string_bytes.items.len); | ||
| 7893 | try astgen.appendIdentStr(ident_token, string_bytes); | ||
| 7894 | const key = string_bytes.items[str_index..]; | ||
| 7895 | const gop = try astgen.string_table.getOrPut(gpa, key); | ||
| 7896 | if (gop.found_existing) { | ||
| 7897 | string_bytes.shrinkRetainingCapacity(str_index); | ||
| 7898 | return gop.entry.value; | ||
| 7899 | } else { | ||
| 7900 | // We have to dupe the key into the arena, otherwise the memory | ||
| 7901 | // becomes invalidated when string_bytes gets data appended. | ||
| 7902 | // TODO https://github.com/ziglang/zig/issues/8528 | ||
| 7903 | gop.entry.key = try astgen.arena.dupe(u8, key); | ||
| 7904 | gop.entry.value = str_index; | ||
| 7905 | try string_bytes.append(gpa, 0); | ||
| 7906 | return str_index; | ||
| 7907 | } | ||
| 7908 | } | ||
| 7909 | |||
| 7910 | const IndexSlice = struct { index: u32, len: u32 }; | ||
| 7911 | |||
| 7912 | fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { | ||
| 7913 | const gpa = astgen.gpa; | ||
| 7914 | const string_bytes = &astgen.string_bytes; | ||
| 7915 | const str_index = @intCast(u32, string_bytes.items.len); | ||
| 7916 | const token_bytes = astgen.tree.tokenSlice(str_lit_token); | ||
| 7917 | try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); | ||
| 7918 | const key = string_bytes.items[str_index..]; | ||
| 7919 | const gop = try astgen.string_table.getOrPut(gpa, key); | ||
| 7920 | if (gop.found_existing) { | ||
| 7921 | string_bytes.shrinkRetainingCapacity(str_index); | ||
| 7922 | return IndexSlice{ | ||
| 7923 | .index = gop.entry.value, | ||
| 7924 | .len = @intCast(u32, key.len), | ||
| 7925 | }; | ||
| 7926 | } else { | ||
| 7927 | // We have to dupe the key into the arena, otherwise the memory | ||
| 7928 | // becomes invalidated when string_bytes gets data appended. | ||
| 7929 | // TODO https://github.com/ziglang/zig/issues/8528 | ||
| 7930 | gop.entry.key = try astgen.arena.dupe(u8, key); | ||
| 7931 | gop.entry.value = str_index; | ||
| 7932 | // Still need a null byte because we are using the same table | ||
| 7933 | // to lookup null terminated strings, so if we get a match, it has to | ||
| 7934 | // be null terminated for that to work. | ||
| 7935 | try string_bytes.append(gpa, 0); | ||
| 7936 | return IndexSlice{ | ||
| 7937 | .index = str_index, | ||
| 7938 | .len = @intCast(u32, key.len), | ||
| 7939 | }; | ||
| 7940 | } | ||
| 7941 | } | ||
| 7942 | |||
| 7943 | fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 { | ||
| 7944 | const gpa = astgen.gpa; | ||
| 7945 | const string_bytes = &astgen.string_bytes; | ||
| 7946 | const str_index = @intCast(u32, string_bytes.items.len); | ||
| 7947 | const token_bytes = astgen.tree.tokenSlice(str_lit_token); | ||
| 7948 | try string_bytes.append(gpa, 0); // Indicates this is a test. | ||
| 7949 | try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); | ||
| 7950 | try string_bytes.append(gpa, 0); | ||
| 7951 | return str_index; | ||
| 7952 | } | ||
| 7953 | |||
| 7954 | const Scope = struct { | ||
| 7955 | tag: Tag, | ||
| 7956 | |||
| 7957 | fn cast(base: *Scope, comptime T: type) ?*T { | ||
| 7958 | if (T == Defer) { | ||
| 7959 | switch (base.tag) { | ||
| 7960 | .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), | ||
| 7961 | else => return null, | ||
| 7962 | } | ||
| 7963 | } | ||
| 7964 | if (base.tag != T.base_tag) | ||
| 7965 | return null; | ||
| 7966 | |||
| 7967 | return @fieldParentPtr(T, "base", base); | ||
| 7968 | } | ||
| 7969 | |||
| 7970 | const Tag = enum { | ||
| 7971 | gen_zir, | ||
| 7972 | local_val, | ||
| 7973 | local_ptr, | ||
| 7974 | defer_normal, | ||
| 7975 | defer_error, | ||
| 7976 | namespace, | ||
| 7977 | top, | ||
| 7978 | }; | ||
| 7979 | |||
| 7980 | /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. | ||
| 7981 | /// This structure lives as long as the AST generation of the Block | ||
| 7982 | /// node that contains the variable. | ||
| 7983 | const LocalVal = struct { | ||
| 7984 | const base_tag: Tag = .local_val; | ||
| 7985 | base: Scope = Scope{ .tag = base_tag }, | ||
| 7986 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. | ||
| 7987 | parent: *Scope, | ||
| 7988 | gen_zir: *GenZir, | ||
| 7989 | inst: Zir.Inst.Ref, | ||
| 7990 | /// Source location of the corresponding variable declaration. | ||
| 7991 | token_src: ast.TokenIndex, | ||
| 7992 | /// String table index. | ||
| 7993 | name: u32, | ||
| 7994 | }; | ||
| 7995 | |||
| 7996 | /// This could be a `const` or `var` local. It has a pointer instead of a value. | ||
| 7997 | /// This structure lives as long as the AST generation of the Block | ||
| 7998 | /// node that contains the variable. | ||
| 7999 | const LocalPtr = struct { | ||
| 8000 | const base_tag: Tag = .local_ptr; | ||
| 8001 | base: Scope = Scope{ .tag = base_tag }, | ||
| 8002 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. | ||
| 8003 | parent: *Scope, | ||
| 8004 | gen_zir: *GenZir, | ||
| 8005 | ptr: Zir.Inst.Ref, | ||
| 8006 | /// Source location of the corresponding variable declaration. | ||
| 8007 | token_src: ast.TokenIndex, | ||
| 8008 | /// String table index. | ||
| 8009 | name: u32, | ||
| 8010 | }; | ||
| 8011 | |||
| 8012 | const Defer = struct { | ||
| 8013 | base: Scope, | ||
| 8014 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. | ||
| 8015 | parent: *Scope, | ||
| 8016 | defer_node: ast.Node.Index, | ||
| 8017 | }; | ||
| 8018 | |||
| 8019 | /// Represents a global scope that has any number of declarations in it. | ||
| 8020 | /// Each declaration has this as the parent scope. | ||
| 8021 | const Namespace = struct { | ||
| 8022 | const base_tag: Tag = .namespace; | ||
| 8023 | base: Scope = Scope{ .tag = base_tag }, | ||
| 8024 | |||
| 8025 | parent: *Scope, | ||
| 8026 | /// Maps string table index to the source location of declaration, | ||
| 8027 | /// for the purposes of reporting name shadowing compile errors. | ||
| 8028 | decls: std.AutoHashMapUnmanaged(u32, ast.Node.Index) = .{}, | ||
| 8029 | }; | ||
| 8030 | |||
| 8031 | const Top = struct { | ||
| 8032 | const base_tag: Scope.Tag = .top; | ||
| 8033 | base: Scope = Scope{ .tag = base_tag }, | ||
| 8034 | }; | ||
| 8035 | }; | ||
| 8036 | |||
| 8037 | /// This is a temporary structure; references to it are valid only | ||
| 8038 | /// while constructing a `Zir`. | ||
| 8039 | const GenZir = struct { | ||
| 8040 | const base_tag: Scope.Tag = .gen_zir; | ||
| 8041 | base: Scope = Scope{ .tag = base_tag }, | ||
| 8042 | force_comptime: bool, | ||
| 8043 | /// How decls created in this scope should be named. | ||
| 8044 | anon_name_strategy: Zir.Inst.NameStrategy = .anon, | ||
| 8045 | /// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert | ||
| 8046 | /// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters. | ||
| 8047 | ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len, | ||
| 8048 | /// The containing decl AST node. | ||
| 8049 | decl_node_index: ast.Node.Index, | ||
| 8050 | /// The containing decl line index, absolute. | ||
| 8051 | decl_line: u32, | ||
| 8052 | parent: *Scope, | ||
| 8053 | /// All `GenZir` scopes for the same ZIR share this. | ||
| 8054 | astgen: *AstGen, | ||
| 8055 | /// Keeps track of the list of instructions in this scope only. Indexes | ||
| 8056 | /// to instructions in `astgen`. | ||
| 8057 | instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{}, | ||
| 8058 | label: ?Label = null, | ||
| 8059 | break_block: Zir.Inst.Index = 0, | ||
| 8060 | continue_block: Zir.Inst.Index = 0, | ||
| 8061 | /// Only valid when setBreakResultLoc is called. | ||
| 8062 | break_result_loc: AstGen.ResultLoc = undefined, | ||
| 8063 | /// When a block has a pointer result location, here it is. | ||
| 8064 | rl_ptr: Zir.Inst.Ref = .none, | ||
| 8065 | /// When a block has a type result location, here it is. | ||
| 8066 | rl_ty_inst: Zir.Inst.Ref = .none, | ||
| 8067 | /// Keeps track of how many branches of a block did not actually | ||
| 8068 | /// consume the result location. astgen uses this to figure out | ||
| 8069 | /// whether to rely on break instructions or writing to the result | ||
| 8070 | /// pointer for the result instruction. | ||
| 8071 | rvalue_rl_count: usize = 0, | ||
| 8072 | /// Keeps track of how many break instructions there are. When astgen is finished | ||
| 8073 | /// with a block, it can check this against rvalue_rl_count to find out whether | ||
| 8074 | /// the break instructions should be downgraded to break_void. | ||
| 8075 | break_count: usize = 0, | ||
| 8076 | /// Tracks `break :foo bar` instructions so they can possibly be elided later if | ||
| 8077 | /// the labeled block ends up not needing a result location pointer. | ||
| 8078 | labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{}, | ||
| 8079 | /// Tracks `store_to_block_ptr` instructions that correspond to break instructions | ||
| 8080 | /// so they can possibly be elided later if the labeled block ends up not needing | ||
| 8081 | /// a result location pointer. | ||
| 8082 | labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{}, | ||
| 8083 | |||
| 8084 | suspend_node: ast.Node.Index = 0, | ||
| 8085 | nosuspend_node: ast.Node.Index = 0, | ||
| 8086 | |||
| 8087 | fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { | ||
| 8088 | return .{ | ||
| 8089 | .force_comptime = gz.force_comptime, | ||
| 8090 | .ref_start_index = gz.ref_start_index, | ||
| 8091 | .decl_node_index = gz.decl_node_index, | ||
| 8092 | .decl_line = gz.decl_line, | ||
| 8093 | .parent = scope, | ||
| 8094 | .astgen = gz.astgen, | ||
| 8095 | .suspend_node = gz.suspend_node, | ||
| 8096 | .nosuspend_node = gz.nosuspend_node, | ||
| 8097 | }; | ||
| 8098 | } | ||
| 8099 | |||
| 8100 | const Label = struct { | ||
| 8101 | token: ast.TokenIndex, | ||
| 8102 | block_inst: Zir.Inst.Index, | ||
| 8103 | used: bool = false, | ||
| 8104 | }; | ||
| 8105 | |||
| 8106 | fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { | ||
| 8107 | if (inst_ref == .unreachable_value) return true; | ||
| 8108 | if (gz.refToIndex(inst_ref)) |inst_index| { | ||
| 8109 | return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); | ||
| 8110 | } | ||
| 8111 | return false; | ||
| 8112 | } | ||
| 8113 | |||
| 8114 | fn calcLine(gz: GenZir, node: ast.Node.Index) u32 { | ||
| 8115 | const astgen = gz.astgen; | ||
| 8116 | const tree = astgen.tree; | ||
| 8117 | const node_tags = tree.nodes.items(.tag); | ||
| 8118 | const token_starts = tree.tokens.items(.start); | ||
| 8119 | const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; | ||
| 8120 | const node_start = token_starts[tree.firstToken(node)]; | ||
| 8121 | const source = tree.source[decl_start..node_start]; | ||
| 8122 | const loc = std.zig.findLineColumn(source, source.len); | ||
| 8123 | return @intCast(u32, gz.decl_line + loc.line); | ||
| 8124 | } | ||
| 8125 | |||
| 8126 | fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc { | ||
| 8127 | return .{ .token_offset = token_index - gz.srcToken() }; | ||
| 8128 | } | ||
| 8129 | |||
| 8130 | fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc { | ||
| 8131 | return .{ .node_offset = gz.nodeIndexToRelative(node_index) }; | ||
| 8132 | } | ||
| 8133 | |||
| 8134 | fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 { | ||
| 8135 | return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); | ||
| 8136 | } | ||
| 8137 | |||
| 8138 | fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 { | ||
| 8139 | return token - gz.srcToken(); | ||
| 8140 | } | ||
| 8141 | |||
| 8142 | fn srcToken(gz: GenZir) ast.TokenIndex { | ||
| 8143 | return gz.astgen.tree.firstToken(gz.decl_node_index); | ||
| 8144 | } | ||
| 8145 | |||
| 8146 | fn indexToRef(gz: GenZir, inst: Zir.Inst.Index) Zir.Inst.Ref { | ||
| 8147 | return @intToEnum(Zir.Inst.Ref, gz.ref_start_index + inst); | ||
| 8148 | } | ||
| 8149 | |||
| 8150 | fn refToIndex(gz: GenZir, inst: Zir.Inst.Ref) ?Zir.Inst.Index { | ||
| 8151 | const ref_int = @enumToInt(inst); | ||
| 8152 | if (ref_int >= gz.ref_start_index) { | ||
| 8153 | return ref_int - gz.ref_start_index; | ||
| 8154 | } else { | ||
| 8155 | return null; | ||
| 8156 | } | ||
| 8157 | } | ||
| 8158 | |||
| 8159 | fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { | ||
| 8160 | // Depending on whether the result location is a pointer or value, different | ||
| 8161 | // ZIR needs to be generated. In the former case we rely on storing to the | ||
| 8162 | // pointer to communicate the result, and use breakvoid; in the latter case | ||
| 8163 | // the block break instructions will have the result values. | ||
| 8164 | // One more complication: when the result location is a pointer, we detect | ||
| 8165 | // the scenario where the result location is not consumed. In this case | ||
| 8166 | // we emit ZIR for the block break instructions to have the result values, | ||
| 8167 | // and then rvalue() on that to pass the value to the result location. | ||
| 8168 | switch (parent_rl) { | ||
| 8169 | .ty => |ty_inst| { | ||
| 8170 | gz.rl_ty_inst = ty_inst; | ||
| 8171 | gz.break_result_loc = parent_rl; | ||
| 8172 | }, | ||
| 8173 | .none_or_ref => { | ||
| 8174 | gz.break_result_loc = .ref; | ||
| 8175 | }, | ||
| 8176 | .discard, .none, .ptr, .ref => { | ||
| 8177 | gz.break_result_loc = parent_rl; | ||
| 4584 | }, | 8178 | }, |
| 4585 | 8179 | ||
| 4586 | .builtin_call, | 8180 | .inferred_ptr => |ptr| { |
| 4587 | .builtin_call_comma, | 8181 | gz.rl_ptr = ptr; |
| 4588 | .builtin_call_two, | 8182 | gz.break_result_loc = .{ .block_ptr = gz }; |
| 4589 | .builtin_call_two_comma, | 8183 | }, |
| 4590 | => { | 8184 | |
| 4591 | const builtin_token = main_tokens[node]; | 8185 | .block_ptr => |parent_block_scope| { |
| 4592 | const builtin_name = tree.tokenSlice(builtin_token); | 8186 | gz.rl_ty_inst = parent_block_scope.rl_ty_inst; |
| 4593 | // If the builtin is an invalid name, we don't cause an error here; instead | 8187 | gz.rl_ptr = parent_block_scope.rl_ptr; |
| 4594 | // let it pass, and the error will be "invalid builtin function" later. | 8188 | gz.break_result_loc = .{ .block_ptr = gz }; |
| 4595 | const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; | ||
| 4596 | return builtin_info.needs_mem_loc; | ||
| 4597 | }, | 8189 | }, |
| 4598 | } | 8190 | } |
| 4599 | } | 8191 | } |
| 4600 | } | ||
| 4601 | 8192 | ||
| 4602 | /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of | 8193 | fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void { |
| 4603 | /// result locations must call this function on their result. | 8194 | const gpa = gz.astgen.gpa; |
| 4604 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. | 8195 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + |
| 4605 | /// If the `ResultLoc` is `ty`, it will coerce the result to the type. | 8196 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); |
| 4606 | fn rvalue( | 8197 | const zir_datas = gz.astgen.instructions.items(.data); |
| 4607 | gz: *GenZir, | 8198 | zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( |
| 4608 | scope: *Scope, | 8199 | Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, |
| 4609 | rl: ResultLoc, | 8200 | ); |
| 4610 | result: zir.Inst.Ref, | 8201 | gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); |
| 4611 | src_node: ast.Node.Index, | 8202 | } |
| 4612 | ) InnerError!zir.Inst.Ref { | ||
| 4613 | switch (rl) { | ||
| 4614 | .none, .none_or_ref => return result, | ||
| 4615 | .discard => { | ||
| 4616 | // Emit a compile error for discarding error values. | ||
| 4617 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); | ||
| 4618 | return result; | ||
| 4619 | }, | ||
| 4620 | .ref => { | ||
| 4621 | // We need a pointer but we have a value. | ||
| 4622 | const tree = gz.tree(); | ||
| 4623 | const src_token = tree.firstToken(src_node); | ||
| 4624 | return gz.addUnTok(.ref, result, src_token); | ||
| 4625 | }, | ||
| 4626 | .ty => |ty_inst| { | ||
| 4627 | // Quickly eliminate some common, unnecessary type coercion. | ||
| 4628 | const as_ty = @as(u64, @enumToInt(zir.Inst.Ref.type_type)) << 32; | ||
| 4629 | const as_comptime_int = @as(u64, @enumToInt(zir.Inst.Ref.comptime_int_type)) << 32; | ||
| 4630 | const as_bool = @as(u64, @enumToInt(zir.Inst.Ref.bool_type)) << 32; | ||
| 4631 | const as_usize = @as(u64, @enumToInt(zir.Inst.Ref.usize_type)) << 32; | ||
| 4632 | const as_void = @as(u64, @enumToInt(zir.Inst.Ref.void_type)) << 32; | ||
| 4633 | switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { | ||
| 4634 | as_ty | @enumToInt(zir.Inst.Ref.u8_type), | ||
| 4635 | as_ty | @enumToInt(zir.Inst.Ref.i8_type), | ||
| 4636 | as_ty | @enumToInt(zir.Inst.Ref.u16_type), | ||
| 4637 | as_ty | @enumToInt(zir.Inst.Ref.i16_type), | ||
| 4638 | as_ty | @enumToInt(zir.Inst.Ref.u32_type), | ||
| 4639 | as_ty | @enumToInt(zir.Inst.Ref.i32_type), | ||
| 4640 | as_ty | @enumToInt(zir.Inst.Ref.u64_type), | ||
| 4641 | as_ty | @enumToInt(zir.Inst.Ref.i64_type), | ||
| 4642 | as_ty | @enumToInt(zir.Inst.Ref.usize_type), | ||
| 4643 | as_ty | @enumToInt(zir.Inst.Ref.isize_type), | ||
| 4644 | as_ty | @enumToInt(zir.Inst.Ref.c_short_type), | ||
| 4645 | as_ty | @enumToInt(zir.Inst.Ref.c_ushort_type), | ||
| 4646 | as_ty | @enumToInt(zir.Inst.Ref.c_int_type), | ||
| 4647 | as_ty | @enumToInt(zir.Inst.Ref.c_uint_type), | ||
| 4648 | as_ty | @enumToInt(zir.Inst.Ref.c_long_type), | ||
| 4649 | as_ty | @enumToInt(zir.Inst.Ref.c_ulong_type), | ||
| 4650 | as_ty | @enumToInt(zir.Inst.Ref.c_longlong_type), | ||
| 4651 | as_ty | @enumToInt(zir.Inst.Ref.c_ulonglong_type), | ||
| 4652 | as_ty | @enumToInt(zir.Inst.Ref.c_longdouble_type), | ||
| 4653 | as_ty | @enumToInt(zir.Inst.Ref.f16_type), | ||
| 4654 | as_ty | @enumToInt(zir.Inst.Ref.f32_type), | ||
| 4655 | as_ty | @enumToInt(zir.Inst.Ref.f64_type), | ||
| 4656 | as_ty | @enumToInt(zir.Inst.Ref.f128_type), | ||
| 4657 | as_ty | @enumToInt(zir.Inst.Ref.c_void_type), | ||
| 4658 | as_ty | @enumToInt(zir.Inst.Ref.bool_type), | ||
| 4659 | as_ty | @enumToInt(zir.Inst.Ref.void_type), | ||
| 4660 | as_ty | @enumToInt(zir.Inst.Ref.type_type), | ||
| 4661 | as_ty | @enumToInt(zir.Inst.Ref.anyerror_type), | ||
| 4662 | as_ty | @enumToInt(zir.Inst.Ref.comptime_int_type), | ||
| 4663 | as_ty | @enumToInt(zir.Inst.Ref.comptime_float_type), | ||
| 4664 | as_ty | @enumToInt(zir.Inst.Ref.noreturn_type), | ||
| 4665 | as_ty | @enumToInt(zir.Inst.Ref.null_type), | ||
| 4666 | as_ty | @enumToInt(zir.Inst.Ref.undefined_type), | ||
| 4667 | as_ty | @enumToInt(zir.Inst.Ref.fn_noreturn_no_args_type), | ||
| 4668 | as_ty | @enumToInt(zir.Inst.Ref.fn_void_no_args_type), | ||
| 4669 | as_ty | @enumToInt(zir.Inst.Ref.fn_naked_noreturn_no_args_type), | ||
| 4670 | as_ty | @enumToInt(zir.Inst.Ref.fn_ccc_void_no_args_type), | ||
| 4671 | as_ty | @enumToInt(zir.Inst.Ref.single_const_pointer_to_comptime_int_type), | ||
| 4672 | as_ty | @enumToInt(zir.Inst.Ref.const_slice_u8_type), | ||
| 4673 | as_ty | @enumToInt(zir.Inst.Ref.enum_literal_type), | ||
| 4674 | as_comptime_int | @enumToInt(zir.Inst.Ref.zero), | ||
| 4675 | as_comptime_int | @enumToInt(zir.Inst.Ref.one), | ||
| 4676 | as_bool | @enumToInt(zir.Inst.Ref.bool_true), | ||
| 4677 | as_bool | @enumToInt(zir.Inst.Ref.bool_false), | ||
| 4678 | as_usize | @enumToInt(zir.Inst.Ref.zero_usize), | ||
| 4679 | as_usize | @enumToInt(zir.Inst.Ref.one_usize), | ||
| 4680 | as_void | @enumToInt(zir.Inst.Ref.void_value), | ||
| 4681 | => return result, // type of result is already correct | ||
| 4682 | 8203 | ||
| 4683 | // Need an explicit type coercion instruction. | 8204 | fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void { |
| 4684 | else => return gz.addPlNode(.as_node, src_node, zir.Inst.As{ | 8205 | const gpa = gz.astgen.gpa; |
| 4685 | .dest_type = ty_inst, | 8206 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + |
| 4686 | .operand = result, | 8207 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); |
| 4687 | }), | 8208 | const zir_datas = gz.astgen.instructions.items(.data); |
| 8209 | zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( | ||
| 8210 | Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, | ||
| 8211 | ); | ||
| 8212 | gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); | ||
| 8213 | } | ||
| 8214 | |||
| 8215 | /// Same as `setBlockBody` except we don't copy instructions which are | ||
| 8216 | /// `store_to_block_ptr` instructions with lhs set to .none. | ||
| 8217 | fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { | ||
| 8218 | const gpa = gz.astgen.gpa; | ||
| 8219 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 8220 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | ||
| 8221 | const zir_datas = gz.astgen.instructions.items(.data); | ||
| 8222 | const zir_tags = gz.astgen.instructions.items(.tag); | ||
| 8223 | const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ | ||
| 8224 | .body_len = @intCast(u32, gz.instructions.items.len), | ||
| 8225 | }); | ||
| 8226 | zir_datas[inst].pl_node.payload_index = block_pl_index; | ||
| 8227 | for (gz.instructions.items) |sub_inst| { | ||
| 8228 | if (zir_tags[sub_inst] == .store_to_block_ptr and | ||
| 8229 | zir_datas[sub_inst].bin.lhs == .none) | ||
| 8230 | { | ||
| 8231 | // Decrement `body_len`. | ||
| 8232 | gz.astgen.extra.items[block_pl_index] -= 1; | ||
| 8233 | continue; | ||
| 4688 | } | 8234 | } |
| 4689 | }, | 8235 | gz.astgen.extra.appendAssumeCapacity(sub_inst); |
| 4690 | .ptr => |ptr_inst| { | 8236 | } |
| 4691 | _ = try gz.addPlNode(.store_node, src_node, zir.Inst.Bin{ | 8237 | } |
| 4692 | .lhs = ptr_inst, | 8238 | |
| 4693 | .rhs = result, | 8239 | fn addFunc(gz: *GenZir, args: struct { |
| 8240 | src_node: ast.Node.Index, | ||
| 8241 | param_types: []const Zir.Inst.Ref, | ||
| 8242 | body: []const Zir.Inst.Index, | ||
| 8243 | ret_ty: Zir.Inst.Ref, | ||
| 8244 | cc: Zir.Inst.Ref, | ||
| 8245 | align_inst: Zir.Inst.Ref, | ||
| 8246 | lib_name: u32, | ||
| 8247 | is_var_args: bool, | ||
| 8248 | is_inferred_error: bool, | ||
| 8249 | is_test: bool, | ||
| 8250 | is_extern: bool, | ||
| 8251 | }) !Zir.Inst.Ref { | ||
| 8252 | assert(args.src_node != 0); | ||
| 8253 | assert(args.ret_ty != .none); | ||
| 8254 | const astgen = gz.astgen; | ||
| 8255 | const gpa = astgen.gpa; | ||
| 8256 | |||
| 8257 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8258 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8259 | |||
| 8260 | var src_locs_buffer: [3]u32 = undefined; | ||
| 8261 | var src_locs: []u32 = src_locs_buffer[0..0]; | ||
| 8262 | if (args.body.len != 0) { | ||
| 8263 | const tree = astgen.tree; | ||
| 8264 | const node_tags = tree.nodes.items(.tag); | ||
| 8265 | const node_datas = tree.nodes.items(.data); | ||
| 8266 | const token_starts = tree.tokens.items(.start); | ||
| 8267 | const decl_start = token_starts[tree.firstToken(gz.decl_node_index)]; | ||
| 8268 | const fn_decl = args.src_node; | ||
| 8269 | assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); | ||
| 8270 | const block = node_datas[fn_decl].rhs; | ||
| 8271 | const lbrace_start = token_starts[tree.firstToken(block)]; | ||
| 8272 | const rbrace_start = token_starts[tree.lastToken(block)]; | ||
| 8273 | const lbrace_source = tree.source[decl_start..lbrace_start]; | ||
| 8274 | const lbrace_loc = std.zig.findLineColumn(lbrace_source, lbrace_source.len); | ||
| 8275 | const rbrace_source = tree.source[lbrace_start..rbrace_start]; | ||
| 8276 | const rbrace_loc = std.zig.findLineColumn(rbrace_source, rbrace_source.len); | ||
| 8277 | const lbrace_line = @intCast(u32, lbrace_loc.line); | ||
| 8278 | const rbrace_line = lbrace_line + @intCast(u32, rbrace_loc.line); | ||
| 8279 | const columns = @intCast(u32, lbrace_loc.column) | | ||
| 8280 | (@intCast(u32, rbrace_loc.column) << 16); | ||
| 8281 | src_locs_buffer[0] = lbrace_line; | ||
| 8282 | src_locs_buffer[1] = rbrace_line; | ||
| 8283 | src_locs_buffer[2] = columns; | ||
| 8284 | src_locs = &src_locs_buffer; | ||
| 8285 | } | ||
| 8286 | |||
| 8287 | if (args.cc != .none or args.lib_name != 0 or | ||
| 8288 | args.is_var_args or args.is_test or args.align_inst != .none or | ||
| 8289 | args.is_extern) | ||
| 8290 | { | ||
| 8291 | try astgen.extra.ensureUnusedCapacity( | ||
| 8292 | gpa, | ||
| 8293 | @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + | ||
| 8294 | args.param_types.len + args.body.len + src_locs.len + | ||
| 8295 | @boolToInt(args.lib_name != 0) + | ||
| 8296 | @boolToInt(args.align_inst != .none) + | ||
| 8297 | @boolToInt(args.cc != .none), | ||
| 8298 | ); | ||
| 8299 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ | ||
| 8300 | .src_node = gz.nodeIndexToRelative(args.src_node), | ||
| 8301 | .return_type = args.ret_ty, | ||
| 8302 | .param_types_len = @intCast(u32, args.param_types.len), | ||
| 8303 | .body_len = @intCast(u32, args.body.len), | ||
| 4694 | }); | 8304 | }); |
| 4695 | return result; | 8305 | if (args.lib_name != 0) { |
| 4696 | }, | 8306 | astgen.extra.appendAssumeCapacity(args.lib_name); |
| 4697 | .inferred_ptr => |alloc| { | 8307 | } |
| 4698 | _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); | 8308 | if (args.cc != .none) { |
| 4699 | return result; | 8309 | astgen.extra.appendAssumeCapacity(@enumToInt(args.cc)); |
| 8310 | } | ||
| 8311 | if (args.align_inst != .none) { | ||
| 8312 | astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); | ||
| 8313 | } | ||
| 8314 | astgen.appendRefsAssumeCapacity(args.param_types); | ||
| 8315 | astgen.extra.appendSliceAssumeCapacity(args.body); | ||
| 8316 | astgen.extra.appendSliceAssumeCapacity(src_locs); | ||
| 8317 | |||
| 8318 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8319 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8320 | .tag = .extended, | ||
| 8321 | .data = .{ .extended = .{ | ||
| 8322 | .opcode = .func, | ||
| 8323 | .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{ | ||
| 8324 | .is_var_args = args.is_var_args, | ||
| 8325 | .is_inferred_error = args.is_inferred_error, | ||
| 8326 | .has_lib_name = args.lib_name != 0, | ||
| 8327 | .has_cc = args.cc != .none, | ||
| 8328 | .has_align = args.align_inst != .none, | ||
| 8329 | .is_test = args.is_test, | ||
| 8330 | .is_extern = args.is_extern, | ||
| 8331 | }), | ||
| 8332 | .operand = payload_index, | ||
| 8333 | } }, | ||
| 8334 | }); | ||
| 8335 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8336 | return gz.indexToRef(new_index); | ||
| 8337 | } else { | ||
| 8338 | try gz.astgen.extra.ensureUnusedCapacity( | ||
| 8339 | gpa, | ||
| 8340 | @typeInfo(Zir.Inst.Func).Struct.fields.len + | ||
| 8341 | args.param_types.len + args.body.len + src_locs.len, | ||
| 8342 | ); | ||
| 8343 | |||
| 8344 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{ | ||
| 8345 | .return_type = args.ret_ty, | ||
| 8346 | .param_types_len = @intCast(u32, args.param_types.len), | ||
| 8347 | .body_len = @intCast(u32, args.body.len), | ||
| 8348 | }); | ||
| 8349 | gz.astgen.appendRefsAssumeCapacity(args.param_types); | ||
| 8350 | gz.astgen.extra.appendSliceAssumeCapacity(args.body); | ||
| 8351 | gz.astgen.extra.appendSliceAssumeCapacity(src_locs); | ||
| 8352 | |||
| 8353 | const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; | ||
| 8354 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8355 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8356 | .tag = tag, | ||
| 8357 | .data = .{ .pl_node = .{ | ||
| 8358 | .src_node = gz.nodeIndexToRelative(args.src_node), | ||
| 8359 | .payload_index = payload_index, | ||
| 8360 | } }, | ||
| 8361 | }); | ||
| 8362 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8363 | return gz.indexToRef(new_index); | ||
| 8364 | } | ||
| 8365 | } | ||
| 8366 | |||
| 8367 | fn addVar(gz: *GenZir, args: struct { | ||
| 8368 | align_inst: Zir.Inst.Ref, | ||
| 8369 | lib_name: u32, | ||
| 8370 | var_type: Zir.Inst.Ref, | ||
| 8371 | init: Zir.Inst.Ref, | ||
| 8372 | is_extern: bool, | ||
| 8373 | is_threadlocal: bool, | ||
| 8374 | }) !Zir.Inst.Ref { | ||
| 8375 | const astgen = gz.astgen; | ||
| 8376 | const gpa = astgen.gpa; | ||
| 8377 | |||
| 8378 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8379 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8380 | |||
| 8381 | try astgen.extra.ensureUnusedCapacity( | ||
| 8382 | gpa, | ||
| 8383 | @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + | ||
| 8384 | @boolToInt(args.lib_name != 0) + | ||
| 8385 | @boolToInt(args.align_inst != .none) + | ||
| 8386 | @boolToInt(args.init != .none), | ||
| 8387 | ); | ||
| 8388 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ | ||
| 8389 | .var_type = args.var_type, | ||
| 8390 | }); | ||
| 8391 | if (args.lib_name != 0) { | ||
| 8392 | astgen.extra.appendAssumeCapacity(args.lib_name); | ||
| 8393 | } | ||
| 8394 | if (args.align_inst != .none) { | ||
| 8395 | astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); | ||
| 8396 | } | ||
| 8397 | if (args.init != .none) { | ||
| 8398 | astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); | ||
| 8399 | } | ||
| 8400 | |||
| 8401 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8402 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8403 | .tag = .extended, | ||
| 8404 | .data = .{ .extended = .{ | ||
| 8405 | .opcode = .variable, | ||
| 8406 | .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ | ||
| 8407 | .has_lib_name = args.lib_name != 0, | ||
| 8408 | .has_align = args.align_inst != .none, | ||
| 8409 | .has_init = args.init != .none, | ||
| 8410 | .is_extern = args.is_extern, | ||
| 8411 | .is_threadlocal = args.is_threadlocal, | ||
| 8412 | }), | ||
| 8413 | .operand = payload_index, | ||
| 8414 | } }, | ||
| 8415 | }); | ||
| 8416 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8417 | return gz.indexToRef(new_index); | ||
| 8418 | } | ||
| 8419 | |||
| 8420 | fn addCall( | ||
| 8421 | gz: *GenZir, | ||
| 8422 | tag: Zir.Inst.Tag, | ||
| 8423 | callee: Zir.Inst.Ref, | ||
| 8424 | args: []const Zir.Inst.Ref, | ||
| 8425 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8426 | src_node: ast.Node.Index, | ||
| 8427 | ) !Zir.Inst.Ref { | ||
| 8428 | assert(callee != .none); | ||
| 8429 | assert(src_node != 0); | ||
| 8430 | const gpa = gz.astgen.gpa; | ||
| 8431 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8432 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 8433 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 8434 | @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len); | ||
| 8435 | |||
| 8436 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{ | ||
| 8437 | .callee = callee, | ||
| 8438 | .args_len = @intCast(u32, args.len), | ||
| 8439 | }); | ||
| 8440 | gz.astgen.appendRefsAssumeCapacity(args); | ||
| 8441 | |||
| 8442 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8443 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8444 | .tag = tag, | ||
| 8445 | .data = .{ .pl_node = .{ | ||
| 8446 | .src_node = gz.nodeIndexToRelative(src_node), | ||
| 8447 | .payload_index = payload_index, | ||
| 8448 | } }, | ||
| 8449 | }); | ||
| 8450 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8451 | return gz.indexToRef(new_index); | ||
| 8452 | } | ||
| 8453 | |||
| 8454 | /// Note that this returns a `Zir.Inst.Index` not a ref. | ||
| 8455 | /// Leaves the `payload_index` field undefined. | ||
| 8456 | fn addBoolBr( | ||
| 8457 | gz: *GenZir, | ||
| 8458 | tag: Zir.Inst.Tag, | ||
| 8459 | lhs: Zir.Inst.Ref, | ||
| 8460 | ) !Zir.Inst.Index { | ||
| 8461 | assert(lhs != .none); | ||
| 8462 | const gpa = gz.astgen.gpa; | ||
| 8463 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8464 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 8465 | |||
| 8466 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8467 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8468 | .tag = tag, | ||
| 8469 | .data = .{ .bool_br = .{ | ||
| 8470 | .lhs = lhs, | ||
| 8471 | .payload_index = undefined, | ||
| 8472 | } }, | ||
| 8473 | }); | ||
| 8474 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8475 | return new_index; | ||
| 8476 | } | ||
| 8477 | |||
| 8478 | fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { | ||
| 8479 | return gz.add(.{ | ||
| 8480 | .tag = .int, | ||
| 8481 | .data = .{ .int = integer }, | ||
| 8482 | }); | ||
| 8483 | } | ||
| 8484 | |||
| 8485 | fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { | ||
| 8486 | const astgen = gz.astgen; | ||
| 8487 | const gpa = astgen.gpa; | ||
| 8488 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8489 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8490 | try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); | ||
| 8491 | |||
| 8492 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8493 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8494 | .tag = .int_big, | ||
| 8495 | .data = .{ .str = .{ | ||
| 8496 | .start = @intCast(u32, astgen.string_bytes.items.len), | ||
| 8497 | .len = @intCast(u32, limbs.len), | ||
| 8498 | } }, | ||
| 8499 | }); | ||
| 8500 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8501 | astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); | ||
| 8502 | return gz.indexToRef(new_index); | ||
| 8503 | } | ||
| 8504 | |||
| 8505 | fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !Zir.Inst.Ref { | ||
| 8506 | return gz.add(.{ | ||
| 8507 | .tag = .float, | ||
| 8508 | .data = .{ .float = .{ | ||
| 8509 | .src_node = gz.nodeIndexToRelative(src_node), | ||
| 8510 | .number = number, | ||
| 8511 | } }, | ||
| 8512 | }); | ||
| 8513 | } | ||
| 8514 | |||
| 8515 | fn addUnNode( | ||
| 8516 | gz: *GenZir, | ||
| 8517 | tag: Zir.Inst.Tag, | ||
| 8518 | operand: Zir.Inst.Ref, | ||
| 8519 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8520 | src_node: ast.Node.Index, | ||
| 8521 | ) !Zir.Inst.Ref { | ||
| 8522 | assert(operand != .none); | ||
| 8523 | return gz.add(.{ | ||
| 8524 | .tag = tag, | ||
| 8525 | .data = .{ .un_node = .{ | ||
| 8526 | .operand = operand, | ||
| 8527 | .src_node = gz.nodeIndexToRelative(src_node), | ||
| 8528 | } }, | ||
| 8529 | }); | ||
| 8530 | } | ||
| 8531 | |||
| 8532 | fn addPlNode( | ||
| 8533 | gz: *GenZir, | ||
| 8534 | tag: Zir.Inst.Tag, | ||
| 8535 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8536 | src_node: ast.Node.Index, | ||
| 8537 | extra: anytype, | ||
| 8538 | ) !Zir.Inst.Ref { | ||
| 8539 | const gpa = gz.astgen.gpa; | ||
| 8540 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8541 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 8542 | |||
| 8543 | const payload_index = try gz.astgen.addExtra(extra); | ||
| 8544 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8545 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8546 | .tag = tag, | ||
| 8547 | .data = .{ .pl_node = .{ | ||
| 8548 | .src_node = gz.nodeIndexToRelative(src_node), | ||
| 8549 | .payload_index = payload_index, | ||
| 8550 | } }, | ||
| 8551 | }); | ||
| 8552 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8553 | return gz.indexToRef(new_index); | ||
| 8554 | } | ||
| 8555 | |||
| 8556 | fn addExtendedPayload( | ||
| 8557 | gz: *GenZir, | ||
| 8558 | opcode: Zir.Inst.Extended, | ||
| 8559 | extra: anytype, | ||
| 8560 | ) !Zir.Inst.Ref { | ||
| 8561 | const gpa = gz.astgen.gpa; | ||
| 8562 | |||
| 8563 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8564 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 8565 | |||
| 8566 | const payload_index = try gz.astgen.addExtra(extra); | ||
| 8567 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8568 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8569 | .tag = .extended, | ||
| 8570 | .data = .{ .extended = .{ | ||
| 8571 | .opcode = opcode, | ||
| 8572 | .small = undefined, | ||
| 8573 | .operand = payload_index, | ||
| 8574 | } }, | ||
| 8575 | }); | ||
| 8576 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8577 | return gz.indexToRef(new_index); | ||
| 8578 | } | ||
| 8579 | |||
| 8580 | fn addExtendedMultiOp( | ||
| 8581 | gz: *GenZir, | ||
| 8582 | opcode: Zir.Inst.Extended, | ||
| 8583 | node: ast.Node.Index, | ||
| 8584 | operands: []const Zir.Inst.Ref, | ||
| 8585 | ) !Zir.Inst.Ref { | ||
| 8586 | const astgen = gz.astgen; | ||
| 8587 | const gpa = astgen.gpa; | ||
| 8588 | |||
| 8589 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8590 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8591 | try astgen.extra.ensureUnusedCapacity( | ||
| 8592 | gpa, | ||
| 8593 | @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, | ||
| 8594 | ); | ||
| 8595 | |||
| 8596 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ | ||
| 8597 | .src_node = gz.nodeIndexToRelative(node), | ||
| 8598 | }); | ||
| 8599 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8600 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8601 | .tag = .extended, | ||
| 8602 | .data = .{ .extended = .{ | ||
| 8603 | .opcode = opcode, | ||
| 8604 | .small = @intCast(u16, operands.len), | ||
| 8605 | .operand = payload_index, | ||
| 8606 | } }, | ||
| 8607 | }); | ||
| 8608 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8609 | astgen.appendRefsAssumeCapacity(operands); | ||
| 8610 | return gz.indexToRef(new_index); | ||
| 8611 | } | ||
| 8612 | |||
| 8613 | fn addArrayTypeSentinel( | ||
| 8614 | gz: *GenZir, | ||
| 8615 | len: Zir.Inst.Ref, | ||
| 8616 | sentinel: Zir.Inst.Ref, | ||
| 8617 | elem_type: Zir.Inst.Ref, | ||
| 8618 | ) !Zir.Inst.Ref { | ||
| 8619 | const gpa = gz.astgen.gpa; | ||
| 8620 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8621 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 8622 | |||
| 8623 | const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{ | ||
| 8624 | .sentinel = sentinel, | ||
| 8625 | .elem_type = elem_type, | ||
| 8626 | }); | ||
| 8627 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8628 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 8629 | .tag = .array_type_sentinel, | ||
| 8630 | .data = .{ .array_type_sentinel = .{ | ||
| 8631 | .len = len, | ||
| 8632 | .payload_index = payload_index, | ||
| 8633 | } }, | ||
| 8634 | }); | ||
| 8635 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8636 | return gz.indexToRef(new_index); | ||
| 8637 | } | ||
| 8638 | |||
| 8639 | fn addUnTok( | ||
| 8640 | gz: *GenZir, | ||
| 8641 | tag: Zir.Inst.Tag, | ||
| 8642 | operand: Zir.Inst.Ref, | ||
| 8643 | /// Absolute token index. This function does the conversion to Decl offset. | ||
| 8644 | abs_tok_index: ast.TokenIndex, | ||
| 8645 | ) !Zir.Inst.Ref { | ||
| 8646 | assert(operand != .none); | ||
| 8647 | return gz.add(.{ | ||
| 8648 | .tag = tag, | ||
| 8649 | .data = .{ .un_tok = .{ | ||
| 8650 | .operand = operand, | ||
| 8651 | .src_tok = gz.tokenIndexToRelative(abs_tok_index), | ||
| 8652 | } }, | ||
| 8653 | }); | ||
| 8654 | } | ||
| 8655 | |||
| 8656 | fn addStrTok( | ||
| 8657 | gz: *GenZir, | ||
| 8658 | tag: Zir.Inst.Tag, | ||
| 8659 | str_index: u32, | ||
| 8660 | /// Absolute token index. This function does the conversion to Decl offset. | ||
| 8661 | abs_tok_index: ast.TokenIndex, | ||
| 8662 | ) !Zir.Inst.Ref { | ||
| 8663 | return gz.add(.{ | ||
| 8664 | .tag = tag, | ||
| 8665 | .data = .{ .str_tok = .{ | ||
| 8666 | .start = str_index, | ||
| 8667 | .src_tok = gz.tokenIndexToRelative(abs_tok_index), | ||
| 8668 | } }, | ||
| 8669 | }); | ||
| 8670 | } | ||
| 8671 | |||
| 8672 | fn addBreak( | ||
| 8673 | gz: *GenZir, | ||
| 8674 | tag: Zir.Inst.Tag, | ||
| 8675 | break_block: Zir.Inst.Index, | ||
| 8676 | operand: Zir.Inst.Ref, | ||
| 8677 | ) !Zir.Inst.Index { | ||
| 8678 | return gz.addAsIndex(.{ | ||
| 8679 | .tag = tag, | ||
| 8680 | .data = .{ .@"break" = .{ | ||
| 8681 | .block_inst = break_block, | ||
| 8682 | .operand = operand, | ||
| 8683 | } }, | ||
| 8684 | }); | ||
| 8685 | } | ||
| 8686 | |||
| 8687 | fn addBin( | ||
| 8688 | gz: *GenZir, | ||
| 8689 | tag: Zir.Inst.Tag, | ||
| 8690 | lhs: Zir.Inst.Ref, | ||
| 8691 | rhs: Zir.Inst.Ref, | ||
| 8692 | ) !Zir.Inst.Ref { | ||
| 8693 | assert(lhs != .none); | ||
| 8694 | assert(rhs != .none); | ||
| 8695 | return gz.add(.{ | ||
| 8696 | .tag = tag, | ||
| 8697 | .data = .{ .bin = .{ | ||
| 8698 | .lhs = lhs, | ||
| 8699 | .rhs = rhs, | ||
| 8700 | } }, | ||
| 8701 | }); | ||
| 8702 | } | ||
| 8703 | |||
| 8704 | fn addDecl( | ||
| 8705 | gz: *GenZir, | ||
| 8706 | tag: Zir.Inst.Tag, | ||
| 8707 | decl_index: u32, | ||
| 8708 | src_node: ast.Node.Index, | ||
| 8709 | ) !Zir.Inst.Ref { | ||
| 8710 | return gz.add(.{ | ||
| 8711 | .tag = tag, | ||
| 8712 | .data = .{ .pl_node = .{ | ||
| 8713 | .src_node = gz.nodeIndexToRelative(src_node), | ||
| 8714 | .payload_index = decl_index, | ||
| 8715 | } }, | ||
| 8716 | }); | ||
| 8717 | } | ||
| 8718 | |||
| 8719 | fn addNode( | ||
| 8720 | gz: *GenZir, | ||
| 8721 | tag: Zir.Inst.Tag, | ||
| 8722 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8723 | src_node: ast.Node.Index, | ||
| 8724 | ) !Zir.Inst.Ref { | ||
| 8725 | return gz.add(.{ | ||
| 8726 | .tag = tag, | ||
| 8727 | .data = .{ .node = gz.nodeIndexToRelative(src_node) }, | ||
| 8728 | }); | ||
| 8729 | } | ||
| 8730 | |||
| 8731 | fn addNodeExtended( | ||
| 8732 | gz: *GenZir, | ||
| 8733 | opcode: Zir.Inst.Extended, | ||
| 8734 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8735 | src_node: ast.Node.Index, | ||
| 8736 | ) !Zir.Inst.Ref { | ||
| 8737 | return gz.add(.{ | ||
| 8738 | .tag = .extended, | ||
| 8739 | .data = .{ .extended = .{ | ||
| 8740 | .opcode = opcode, | ||
| 8741 | .small = undefined, | ||
| 8742 | .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), | ||
| 8743 | } }, | ||
| 8744 | }); | ||
| 8745 | } | ||
| 8746 | |||
| 8747 | fn addAllocExtended( | ||
| 8748 | gz: *GenZir, | ||
| 8749 | args: struct { | ||
| 8750 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8751 | node: ast.Node.Index, | ||
| 8752 | type_inst: Zir.Inst.Ref, | ||
| 8753 | align_inst: Zir.Inst.Ref, | ||
| 8754 | is_const: bool, | ||
| 8755 | is_comptime: bool, | ||
| 4700 | }, | 8756 | }, |
| 4701 | .block_ptr => |block_scope| { | 8757 | ) !Zir.Inst.Ref { |
| 4702 | block_scope.rvalue_rl_count += 1; | 8758 | const astgen = gz.astgen; |
| 4703 | _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); | 8759 | const gpa = astgen.gpa; |
| 4704 | return result; | 8760 | |
| 8761 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8762 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8763 | try astgen.extra.ensureUnusedCapacity( | ||
| 8764 | gpa, | ||
| 8765 | @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + | ||
| 8766 | @as(usize, @boolToInt(args.type_inst != .none)) + | ||
| 8767 | @as(usize, @boolToInt(args.align_inst != .none)), | ||
| 8768 | ); | ||
| 8769 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ | ||
| 8770 | .src_node = gz.nodeIndexToRelative(args.node), | ||
| 8771 | }); | ||
| 8772 | if (args.type_inst != .none) { | ||
| 8773 | astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); | ||
| 8774 | } | ||
| 8775 | if (args.align_inst != .none) { | ||
| 8776 | astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); | ||
| 8777 | } | ||
| 8778 | |||
| 8779 | const has_type: u4 = @boolToInt(args.type_inst != .none); | ||
| 8780 | const has_align: u4 = @boolToInt(args.align_inst != .none); | ||
| 8781 | const is_const: u4 = @boolToInt(args.is_const); | ||
| 8782 | const is_comptime: u4 = @boolToInt(args.is_comptime); | ||
| 8783 | const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); | ||
| 8784 | |||
| 8785 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8786 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8787 | .tag = .extended, | ||
| 8788 | .data = .{ .extended = .{ | ||
| 8789 | .opcode = .alloc, | ||
| 8790 | .small = small, | ||
| 8791 | .operand = payload_index, | ||
| 8792 | } }, | ||
| 8793 | }); | ||
| 8794 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8795 | return gz.indexToRef(new_index); | ||
| 8796 | } | ||
| 8797 | |||
| 8798 | fn addAsm( | ||
| 8799 | gz: *GenZir, | ||
| 8800 | args: struct { | ||
| 8801 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 8802 | node: ast.Node.Index, | ||
| 8803 | asm_source: Zir.Inst.Ref, | ||
| 8804 | output_type_bits: u32, | ||
| 8805 | is_volatile: bool, | ||
| 8806 | outputs: []const Zir.Inst.Asm.Output, | ||
| 8807 | inputs: []const Zir.Inst.Asm.Input, | ||
| 8808 | clobbers: []const u32, | ||
| 4705 | }, | 8809 | }, |
| 8810 | ) !Zir.Inst.Ref { | ||
| 8811 | const astgen = gz.astgen; | ||
| 8812 | const gpa = astgen.gpa; | ||
| 8813 | |||
| 8814 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8815 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 8816 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + | ||
| 8817 | args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + | ||
| 8818 | args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + | ||
| 8819 | args.clobbers.len); | ||
| 8820 | |||
| 8821 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ | ||
| 8822 | .src_node = gz.nodeIndexToRelative(args.node), | ||
| 8823 | .asm_source = args.asm_source, | ||
| 8824 | .output_type_bits = args.output_type_bits, | ||
| 8825 | }); | ||
| 8826 | for (args.outputs) |output| { | ||
| 8827 | _ = gz.astgen.addExtraAssumeCapacity(output); | ||
| 8828 | } | ||
| 8829 | for (args.inputs) |input| { | ||
| 8830 | _ = gz.astgen.addExtraAssumeCapacity(input); | ||
| 8831 | } | ||
| 8832 | gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); | ||
| 8833 | |||
| 8834 | // * 0b00000000_000XXXXX - `outputs_len`. | ||
| 8835 | // * 0b000000XX_XXX00000 - `inputs_len`. | ||
| 8836 | // * 0b0XXXXX00_00000000 - `clobbers_len`. | ||
| 8837 | // * 0bX0000000_00000000 - is volatile | ||
| 8838 | const small: u16 = @intCast(u16, args.outputs.len) | | ||
| 8839 | @intCast(u16, args.inputs.len << 5) | | ||
| 8840 | @intCast(u16, args.clobbers.len << 10) | | ||
| 8841 | (@as(u16, @boolToInt(args.is_volatile)) << 15); | ||
| 8842 | |||
| 8843 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8844 | astgen.instructions.appendAssumeCapacity(.{ | ||
| 8845 | .tag = .extended, | ||
| 8846 | .data = .{ .extended = .{ | ||
| 8847 | .opcode = .@"asm", | ||
| 8848 | .small = small, | ||
| 8849 | .operand = payload_index, | ||
| 8850 | } }, | ||
| 8851 | }); | ||
| 8852 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8853 | return gz.indexToRef(new_index); | ||
| 8854 | } | ||
| 8855 | |||
| 8856 | /// Note that this returns a `Zir.Inst.Index` not a ref. | ||
| 8857 | /// Does *not* append the block instruction to the scope. | ||
| 8858 | /// Leaves the `payload_index` field undefined. | ||
| 8859 | fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { | ||
| 8860 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8861 | const gpa = gz.astgen.gpa; | ||
| 8862 | try gz.astgen.instructions.append(gpa, .{ | ||
| 8863 | .tag = tag, | ||
| 8864 | .data = .{ .pl_node = .{ | ||
| 8865 | .src_node = gz.nodeIndexToRelative(node), | ||
| 8866 | .payload_index = undefined, | ||
| 8867 | } }, | ||
| 8868 | }); | ||
| 8869 | return new_index; | ||
| 8870 | } | ||
| 8871 | |||
| 8872 | /// Note that this returns a `Zir.Inst.Index` not a ref. | ||
| 8873 | /// Leaves the `payload_index` field undefined. | ||
| 8874 | fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { | ||
| 8875 | const gpa = gz.astgen.gpa; | ||
| 8876 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 8877 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 8878 | try gz.astgen.instructions.append(gpa, .{ | ||
| 8879 | .tag = tag, | ||
| 8880 | .data = .{ .pl_node = .{ | ||
| 8881 | .src_node = gz.nodeIndexToRelative(node), | ||
| 8882 | .payload_index = undefined, | ||
| 8883 | } }, | ||
| 8884 | }); | ||
| 8885 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 8886 | return new_index; | ||
| 8887 | } | ||
| 8888 | |||
| 8889 | fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { | ||
| 8890 | src_node: ast.Node.Index, | ||
| 8891 | body_len: u32, | ||
| 8892 | fields_len: u32, | ||
| 8893 | decls_len: u32, | ||
| 8894 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 8895 | }) !void { | ||
| 8896 | const astgen = gz.astgen; | ||
| 8897 | const gpa = astgen.gpa; | ||
| 8898 | |||
| 8899 | try astgen.extra.ensureUnusedCapacity(gpa, 4); | ||
| 8900 | const payload_index = @intCast(u32, astgen.extra.items.len); | ||
| 8901 | |||
| 8902 | if (args.src_node != 0) { | ||
| 8903 | const node_offset = gz.nodeIndexToRelative(args.src_node); | ||
| 8904 | astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); | ||
| 8905 | } | ||
| 8906 | if (args.body_len != 0) { | ||
| 8907 | astgen.extra.appendAssumeCapacity(args.body_len); | ||
| 8908 | } | ||
| 8909 | if (args.fields_len != 0) { | ||
| 8910 | astgen.extra.appendAssumeCapacity(args.fields_len); | ||
| 8911 | } | ||
| 8912 | if (args.decls_len != 0) { | ||
| 8913 | astgen.extra.appendAssumeCapacity(args.decls_len); | ||
| 8914 | } | ||
| 8915 | astgen.instructions.set(inst, .{ | ||
| 8916 | .tag = .extended, | ||
| 8917 | .data = .{ .extended = .{ | ||
| 8918 | .opcode = .struct_decl, | ||
| 8919 | .small = @bitCast(u16, Zir.Inst.StructDecl.Small{ | ||
| 8920 | .has_src_node = args.src_node != 0, | ||
| 8921 | .has_body_len = args.body_len != 0, | ||
| 8922 | .has_fields_len = args.fields_len != 0, | ||
| 8923 | .has_decls_len = args.decls_len != 0, | ||
| 8924 | .name_strategy = gz.anon_name_strategy, | ||
| 8925 | .layout = args.layout, | ||
| 8926 | }), | ||
| 8927 | .operand = payload_index, | ||
| 8928 | } }, | ||
| 8929 | }); | ||
| 8930 | } | ||
| 8931 | |||
| 8932 | fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { | ||
| 8933 | src_node: ast.Node.Index, | ||
| 8934 | tag_type: Zir.Inst.Ref, | ||
| 8935 | body_len: u32, | ||
| 8936 | fields_len: u32, | ||
| 8937 | decls_len: u32, | ||
| 8938 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 8939 | auto_enum_tag: bool, | ||
| 8940 | }) !void { | ||
| 8941 | const astgen = gz.astgen; | ||
| 8942 | const gpa = astgen.gpa; | ||
| 8943 | |||
| 8944 | try astgen.extra.ensureUnusedCapacity(gpa, 5); | ||
| 8945 | const payload_index = @intCast(u32, astgen.extra.items.len); | ||
| 8946 | |||
| 8947 | if (args.src_node != 0) { | ||
| 8948 | const node_offset = gz.nodeIndexToRelative(args.src_node); | ||
| 8949 | astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); | ||
| 8950 | } | ||
| 8951 | if (args.tag_type != .none) { | ||
| 8952 | astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); | ||
| 8953 | } | ||
| 8954 | if (args.body_len != 0) { | ||
| 8955 | astgen.extra.appendAssumeCapacity(args.body_len); | ||
| 8956 | } | ||
| 8957 | if (args.fields_len != 0) { | ||
| 8958 | astgen.extra.appendAssumeCapacity(args.fields_len); | ||
| 8959 | } | ||
| 8960 | if (args.decls_len != 0) { | ||
| 8961 | astgen.extra.appendAssumeCapacity(args.decls_len); | ||
| 8962 | } | ||
| 8963 | astgen.instructions.set(inst, .{ | ||
| 8964 | .tag = .extended, | ||
| 8965 | .data = .{ .extended = .{ | ||
| 8966 | .opcode = .union_decl, | ||
| 8967 | .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{ | ||
| 8968 | .has_src_node = args.src_node != 0, | ||
| 8969 | .has_tag_type = args.tag_type != .none, | ||
| 8970 | .has_body_len = args.body_len != 0, | ||
| 8971 | .has_fields_len = args.fields_len != 0, | ||
| 8972 | .has_decls_len = args.decls_len != 0, | ||
| 8973 | .name_strategy = gz.anon_name_strategy, | ||
| 8974 | .layout = args.layout, | ||
| 8975 | .auto_enum_tag = args.auto_enum_tag, | ||
| 8976 | }), | ||
| 8977 | .operand = payload_index, | ||
| 8978 | } }, | ||
| 8979 | }); | ||
| 8980 | } | ||
| 8981 | |||
| 8982 | fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { | ||
| 8983 | src_node: ast.Node.Index, | ||
| 8984 | tag_type: Zir.Inst.Ref, | ||
| 8985 | body_len: u32, | ||
| 8986 | fields_len: u32, | ||
| 8987 | decls_len: u32, | ||
| 8988 | nonexhaustive: bool, | ||
| 8989 | }) !void { | ||
| 8990 | const astgen = gz.astgen; | ||
| 8991 | const gpa = astgen.gpa; | ||
| 8992 | |||
| 8993 | try astgen.extra.ensureUnusedCapacity(gpa, 5); | ||
| 8994 | const payload_index = @intCast(u32, astgen.extra.items.len); | ||
| 8995 | |||
| 8996 | if (args.src_node != 0) { | ||
| 8997 | const node_offset = gz.nodeIndexToRelative(args.src_node); | ||
| 8998 | astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); | ||
| 8999 | } | ||
| 9000 | if (args.tag_type != .none) { | ||
| 9001 | astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); | ||
| 9002 | } | ||
| 9003 | if (args.body_len != 0) { | ||
| 9004 | astgen.extra.appendAssumeCapacity(args.body_len); | ||
| 9005 | } | ||
| 9006 | if (args.fields_len != 0) { | ||
| 9007 | astgen.extra.appendAssumeCapacity(args.fields_len); | ||
| 9008 | } | ||
| 9009 | if (args.decls_len != 0) { | ||
| 9010 | astgen.extra.appendAssumeCapacity(args.decls_len); | ||
| 9011 | } | ||
| 9012 | astgen.instructions.set(inst, .{ | ||
| 9013 | .tag = .extended, | ||
| 9014 | .data = .{ .extended = .{ | ||
| 9015 | .opcode = .enum_decl, | ||
| 9016 | .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{ | ||
| 9017 | .has_src_node = args.src_node != 0, | ||
| 9018 | .has_tag_type = args.tag_type != .none, | ||
| 9019 | .has_body_len = args.body_len != 0, | ||
| 9020 | .has_fields_len = args.fields_len != 0, | ||
| 9021 | .has_decls_len = args.decls_len != 0, | ||
| 9022 | .name_strategy = gz.anon_name_strategy, | ||
| 9023 | .nonexhaustive = args.nonexhaustive, | ||
| 9024 | }), | ||
| 9025 | .operand = payload_index, | ||
| 9026 | } }, | ||
| 9027 | }); | ||
| 9028 | } | ||
| 9029 | |||
| 9030 | fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { | ||
| 9031 | return gz.indexToRef(try gz.addAsIndex(inst)); | ||
| 9032 | } | ||
| 9033 | |||
| 9034 | fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { | ||
| 9035 | const gpa = gz.astgen.gpa; | ||
| 9036 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 9037 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 9038 | |||
| 9039 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 9040 | gz.astgen.instructions.appendAssumeCapacity(inst); | ||
| 9041 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 9042 | return new_index; | ||
| 9043 | } | ||
| 9044 | |||
| 9045 | fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index { | ||
| 9046 | const gpa = gz.astgen.gpa; | ||
| 9047 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 9048 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 9049 | |||
| 9050 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 9051 | gz.astgen.instructions.len += 1; | ||
| 9052 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 9053 | return new_index; | ||
| 9054 | } | ||
| 9055 | }; | ||
| 9056 | |||
| 9057 | /// This can only be for short-lived references; the memory becomes invalidated | ||
| 9058 | /// when another string is added. | ||
| 9059 | fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { | ||
| 9060 | return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; | ||
| 9061 | } | ||
| 9062 | |||
| 9063 | fn declareNewName( | ||
| 9064 | astgen: *AstGen, | ||
| 9065 | start_scope: *Scope, | ||
| 9066 | name_index: u32, | ||
| 9067 | node: ast.Node.Index, | ||
| 9068 | ) !void { | ||
| 9069 | const gpa = astgen.gpa; | ||
| 9070 | var scope = start_scope; | ||
| 9071 | while (true) { | ||
| 9072 | switch (scope.tag) { | ||
| 9073 | .gen_zir => scope = scope.cast(GenZir).?.parent, | ||
| 9074 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | ||
| 9075 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | ||
| 9076 | .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, | ||
| 9077 | .namespace => { | ||
| 9078 | const ns = scope.cast(Scope.Namespace).?; | ||
| 9079 | const gop = try ns.decls.getOrPut(gpa, name_index); | ||
| 9080 | if (gop.found_existing) { | ||
| 9081 | const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(name_index))); | ||
| 9082 | defer gpa.free(name); | ||
| 9083 | return astgen.failNodeNotes(node, "redeclaration of '{s}'", .{ | ||
| 9084 | name, | ||
| 9085 | }, &[_]u32{ | ||
| 9086 | try astgen.errNoteNode(gop.entry.value, "other declaration here", .{}), | ||
| 9087 | }); | ||
| 9088 | } | ||
| 9089 | gop.entry.value = node; | ||
| 9090 | break; | ||
| 9091 | }, | ||
| 9092 | .top => break, | ||
| 9093 | } | ||
| 4706 | } | 9094 | } |
| 4707 | } | 9095 | } |
src/BuiltinFn.zig+20-4| ... | @@ -39,6 +39,7 @@ pub const Tag = enum { | ... | @@ -39,6 +39,7 @@ pub const Tag = enum { |
| 39 | error_to_int, | 39 | error_to_int, |
| 40 | err_set_cast, | 40 | err_set_cast, |
| 41 | @"export", | 41 | @"export", |
| 42 | @"extern", | ||
| 42 | fence, | 43 | fence, |
| 43 | field, | 44 | field, |
| 44 | field_parent_ptr, | 45 | field_parent_ptr, |
| ... | @@ -103,6 +104,7 @@ pub const Tag = enum { | ... | @@ -103,6 +104,7 @@ pub const Tag = enum { |
| 103 | type_name, | 104 | type_name, |
| 104 | TypeOf, | 105 | TypeOf, |
| 105 | union_init, | 106 | union_init, |
| 107 | Vector, | ||
| 106 | }; | 108 | }; |
| 107 | 109 | ||
| 108 | tag: Tag, | 110 | tag: Tag, |
| ... | @@ -129,7 +131,7 @@ pub const list = list: { | ... | @@ -129,7 +131,7 @@ pub const list = list: { |
| 129 | "@alignCast", | 131 | "@alignCast", |
| 130 | .{ | 132 | .{ |
| 131 | .tag = .align_cast, | 133 | .tag = .align_cast, |
| 132 | .param_count = 1, | 134 | .param_count = 2, |
| 133 | }, | 135 | }, |
| 134 | }, | 136 | }, |
| 135 | .{ | 137 | .{ |
| ... | @@ -387,6 +389,13 @@ pub const list = list: { | ... | @@ -387,6 +389,13 @@ pub const list = list: { |
| 387 | .param_count = 2, | 389 | .param_count = 2, |
| 388 | }, | 390 | }, |
| 389 | }, | 391 | }, |
| 392 | .{ | ||
| 393 | "@extern", | ||
| 394 | .{ | ||
| 395 | .tag = .@"extern", | ||
| 396 | .param_count = 2, | ||
| 397 | }, | ||
| 398 | }, | ||
| 390 | .{ | 399 | .{ |
| 391 | "@fence", | 400 | "@fence", |
| 392 | .{ | 401 | .{ |
| ... | @@ -414,14 +423,14 @@ pub const list = list: { | ... | @@ -414,14 +423,14 @@ pub const list = list: { |
| 414 | "@floatCast", | 423 | "@floatCast", |
| 415 | .{ | 424 | .{ |
| 416 | .tag = .float_cast, | 425 | .tag = .float_cast, |
| 417 | .param_count = 1, | 426 | .param_count = 2, |
| 418 | }, | 427 | }, |
| 419 | }, | 428 | }, |
| 420 | .{ | 429 | .{ |
| 421 | "@floatToInt", | 430 | "@floatToInt", |
| 422 | .{ | 431 | .{ |
| 423 | .tag = .float_to_int, | 432 | .tag = .float_to_int, |
| 424 | .param_count = 1, | 433 | .param_count = 2, |
| 425 | }, | 434 | }, |
| 426 | }, | 435 | }, |
| 427 | .{ | 436 | .{ |
| ... | @@ -498,7 +507,7 @@ pub const list = list: { | ... | @@ -498,7 +507,7 @@ pub const list = list: { |
| 498 | "@intToFloat", | 507 | "@intToFloat", |
| 499 | .{ | 508 | .{ |
| 500 | .tag = .int_to_float, | 509 | .tag = .int_to_float, |
| 501 | .param_count = 1, | 510 | .param_count = 2, |
| 502 | }, | 511 | }, |
| 503 | }, | 512 | }, |
| 504 | .{ | 513 | .{ |
| ... | @@ -840,5 +849,12 @@ pub const list = list: { | ... | @@ -840,5 +849,12 @@ pub const list = list: { |
| 840 | .param_count = 3, | 849 | .param_count = 3, |
| 841 | }, | 850 | }, |
| 842 | }, | 851 | }, |
| 852 | .{ | ||
| 853 | "@Vector", | ||
| 854 | .{ | ||
| 855 | .tag = .Vector, | ||
| 856 | .param_count = 2, | ||
| 857 | }, | ||
| 858 | }, | ||
| 843 | }); | 859 | }); |
| 844 | }; | 860 | }; |
src/Compilation.zig+398-143| ... | @@ -30,6 +30,7 @@ const c_codegen = @import("codegen/c.zig"); | ... | @@ -30,6 +30,7 @@ const c_codegen = @import("codegen/c.zig"); |
| 30 | const ThreadPool = @import("ThreadPool.zig"); | 30 | const ThreadPool = @import("ThreadPool.zig"); |
| 31 | const WaitGroup = @import("WaitGroup.zig"); | 31 | const WaitGroup = @import("WaitGroup.zig"); |
| 32 | const libtsan = @import("libtsan.zig"); | 32 | const libtsan = @import("libtsan.zig"); |
| 33 | const Zir = @import("Zir.zig"); | ||
| 33 | 34 | ||
| 34 | /// General-purpose allocator. Used for both temporary and long-term storage. | 35 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 35 | gpa: *Allocator, | 36 | gpa: *Allocator, |
| ... | @@ -49,6 +50,11 @@ work_queue: std.fifo.LinearFifo(Job, .Dynamic), | ... | @@ -49,6 +50,11 @@ work_queue: std.fifo.LinearFifo(Job, .Dynamic), |
| 49 | /// gets linked with the Compilation. | 50 | /// gets linked with the Compilation. |
| 50 | c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic), | 51 | c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic), |
| 51 | 52 | ||
| 53 | /// These jobs are to tokenize, parse, and astgen files, which may be outdated | ||
| 54 | /// since the last compilation, as well as scan for `@import` and queue up | ||
| 55 | /// additional jobs corresponding to those new files. | ||
| 56 | astgen_work_queue: std.fifo.LinearFifo(*Module.Scope.File, .Dynamic), | ||
| 57 | |||
| 52 | /// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator. | 58 | /// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator. |
| 53 | /// This data is accessed by multiple threads and is protected by `mutex`. | 59 | /// This data is accessed by multiple threads and is protected by `mutex`. |
| 54 | failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{}, | 60 | failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{}, |
| ... | @@ -141,6 +147,7 @@ emit_analysis: ?EmitLoc, | ... | @@ -141,6 +147,7 @@ emit_analysis: ?EmitLoc, |
| 141 | emit_docs: ?EmitLoc, | 147 | emit_docs: ?EmitLoc, |
| 142 | 148 | ||
| 143 | work_queue_wait_group: WaitGroup, | 149 | work_queue_wait_group: WaitGroup, |
| 150 | astgen_wait_group: WaitGroup, | ||
| 144 | 151 | ||
| 145 | pub const InnerError = Module.InnerError; | 152 | pub const InnerError = Module.InnerError; |
| 146 | 153 | ||
| ... | @@ -173,6 +180,8 @@ const Job = union(enum) { | ... | @@ -173,6 +180,8 @@ const Job = union(enum) { |
| 173 | /// The source file containing the Decl has been updated, and so the | 180 | /// The source file containing the Decl has been updated, and so the |
| 174 | /// Decl may need its line number information updated in the debug info. | 181 | /// Decl may need its line number information updated in the debug info. |
| 175 | update_line_number: *Module.Decl, | 182 | update_line_number: *Module.Decl, |
| 183 | /// The main source file for the package needs to be analyzed. | ||
| 184 | analyze_pkg: *Package, | ||
| 176 | 185 | ||
| 177 | /// one of the glibc static objects | 186 | /// one of the glibc static objects |
| 178 | glibc_crt_file: glibc.CRTFile, | 187 | glibc_crt_file: glibc.CRTFile, |
| ... | @@ -194,8 +203,6 @@ const Job = union(enum) { | ... | @@ -194,8 +203,6 @@ const Job = union(enum) { |
| 194 | /// calls to, for example, memcpy and memset. | 203 | /// calls to, for example, memcpy and memset. |
| 195 | zig_libc: void, | 204 | zig_libc: void, |
| 196 | 205 | ||
| 197 | /// Generate builtin.zig source code and write it into the correct place. | ||
| 198 | generate_builtin_zig: void, | ||
| 199 | /// Use stage1 C++ code to compile zig code into an object file. | 206 | /// Use stage1 C++ code to compile zig code into an object file. |
| 200 | stage1_module: void, | 207 | stage1_module: void, |
| 201 | 208 | ||
| ... | @@ -272,6 +279,7 @@ pub const MiscTask = enum { | ... | @@ -272,6 +279,7 @@ pub const MiscTask = enum { |
| 272 | compiler_rt, | 279 | compiler_rt, |
| 273 | libssp, | 280 | libssp, |
| 274 | zig_libc, | 281 | zig_libc, |
| 282 | analyze_pkg, | ||
| 275 | }; | 283 | }; |
| 276 | 284 | ||
| 277 | pub const MiscError = struct { | 285 | pub const MiscError = struct { |
| ... | @@ -341,6 +349,7 @@ pub const AllErrors = struct { | ... | @@ -341,6 +349,7 @@ pub const AllErrors = struct { |
| 341 | ttyconf.setColor(stderr, color); | 349 | ttyconf.setColor(stderr, color); |
| 342 | try stderr.writeByteNTimes(' ', indent); | 350 | try stderr.writeByteNTimes(' ', indent); |
| 343 | try stderr.writeAll(kind); | 351 | try stderr.writeAll(kind); |
| 352 | ttyconf.setColor(stderr, .Reset); | ||
| 344 | ttyconf.setColor(stderr, .Bold); | 353 | ttyconf.setColor(stderr, .Bold); |
| 345 | try stderr.print(" {s}\n", .{src.msg}); | 354 | try stderr.print(" {s}\n", .{src.msg}); |
| 346 | ttyconf.setColor(stderr, .Reset); | 355 | ttyconf.setColor(stderr, .Reset); |
| ... | @@ -384,10 +393,10 @@ pub const AllErrors = struct { | ... | @@ -384,10 +393,10 @@ pub const AllErrors = struct { |
| 384 | const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len); | 393 | const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len); |
| 385 | for (notes) |*note, i| { | 394 | for (notes) |*note, i| { |
| 386 | const module_note = module_err_msg.notes[i]; | 395 | const module_note = module_err_msg.notes[i]; |
| 387 | const source = try module_note.src_loc.fileScope().getSource(module); | 396 | const source = try module_note.src_loc.file_scope.getSource(module.gpa); |
| 388 | const byte_offset = try module_note.src_loc.byteOffset(); | 397 | const byte_offset = try module_note.src_loc.byteOffset(module.gpa); |
| 389 | const loc = std.zig.findLineColumn(source, byte_offset); | 398 | const loc = std.zig.findLineColumn(source, byte_offset); |
| 390 | const sub_file_path = module_note.src_loc.fileScope().sub_file_path; | 399 | const sub_file_path = module_note.src_loc.file_scope.sub_file_path; |
| 391 | note.* = .{ | 400 | note.* = .{ |
| 392 | .src = .{ | 401 | .src = .{ |
| 393 | .src_path = try arena.allocator.dupe(u8, sub_file_path), | 402 | .src_path = try arena.allocator.dupe(u8, sub_file_path), |
| ... | @@ -399,10 +408,18 @@ pub const AllErrors = struct { | ... | @@ -399,10 +408,18 @@ pub const AllErrors = struct { |
| 399 | }, | 408 | }, |
| 400 | }; | 409 | }; |
| 401 | } | 410 | } |
| 402 | const source = try module_err_msg.src_loc.fileScope().getSource(module); | 411 | if (module_err_msg.src_loc.lazy == .entire_file) { |
| 403 | const byte_offset = try module_err_msg.src_loc.byteOffset(); | 412 | try errors.append(.{ |
| 413 | .plain = .{ | ||
| 414 | .msg = try arena.allocator.dupe(u8, module_err_msg.msg), | ||
| 415 | }, | ||
| 416 | }); | ||
| 417 | return; | ||
| 418 | } | ||
| 419 | const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa); | ||
| 420 | const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa); | ||
| 404 | const loc = std.zig.findLineColumn(source, byte_offset); | 421 | const loc = std.zig.findLineColumn(source, byte_offset); |
| 405 | const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path; | 422 | const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path; |
| 406 | try errors.append(.{ | 423 | try errors.append(.{ |
| 407 | .src = .{ | 424 | .src = .{ |
| 408 | .src_path = try arena.allocator.dupe(u8, sub_file_path), | 425 | .src_path = try arena.allocator.dupe(u8, sub_file_path), |
| ... | @@ -416,6 +433,84 @@ pub const AllErrors = struct { | ... | @@ -416,6 +433,84 @@ pub const AllErrors = struct { |
| 416 | }); | 433 | }); |
| 417 | } | 434 | } |
| 418 | 435 | ||
| 436 | pub fn addZir( | ||
| 437 | arena: *Allocator, | ||
| 438 | errors: *std.ArrayList(Message), | ||
| 439 | file: *Module.Scope.File, | ||
| 440 | ) !void { | ||
| 441 | assert(file.zir_loaded); | ||
| 442 | assert(file.tree_loaded); | ||
| 443 | assert(file.source_loaded); | ||
| 444 | const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)]; | ||
| 445 | assert(payload_index != 0); | ||
| 446 | |||
| 447 | const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); | ||
| 448 | const items_len = header.data.items_len; | ||
| 449 | var extra_index = header.end; | ||
| 450 | var item_i: usize = 0; | ||
| 451 | while (item_i < items_len) : (item_i += 1) { | ||
| 452 | const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index); | ||
| 453 | extra_index = item.end; | ||
| 454 | |||
| 455 | var notes: []Message = &[0]Message{}; | ||
| 456 | if (item.data.notes != 0) { | ||
| 457 | const block = file.zir.extraData(Zir.Inst.Block, item.data.notes); | ||
| 458 | const body = file.zir.extra[block.end..][0..block.data.body_len]; | ||
| 459 | notes = try arena.alloc(Message, body.len); | ||
| 460 | for (notes) |*note, i| { | ||
| 461 | const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body[i]); | ||
| 462 | const msg = file.zir.nullTerminatedString(note_item.data.msg); | ||
| 463 | const byte_offset = blk: { | ||
| 464 | const token_starts = file.tree.tokens.items(.start); | ||
| 465 | if (note_item.data.node != 0) { | ||
| 466 | const main_tokens = file.tree.nodes.items(.main_token); | ||
| 467 | const main_token = main_tokens[note_item.data.node]; | ||
| 468 | break :blk token_starts[main_token]; | ||
| 469 | } | ||
| 470 | break :blk token_starts[note_item.data.token] + note_item.data.byte_offset; | ||
| 471 | }; | ||
| 472 | const loc = std.zig.findLineColumn(file.source, byte_offset); | ||
| 473 | |||
| 474 | note.* = .{ | ||
| 475 | .src = .{ | ||
| 476 | .src_path = try arena.dupe(u8, file.sub_file_path), | ||
| 477 | .msg = try arena.dupe(u8, msg), | ||
| 478 | .byte_offset = byte_offset, | ||
| 479 | .line = @intCast(u32, loc.line), | ||
| 480 | .column = @intCast(u32, loc.column), | ||
| 481 | .notes = &.{}, // TODO rework this function to be recursive | ||
| 482 | .source_line = try arena.dupe(u8, loc.source_line), | ||
| 483 | }, | ||
| 484 | }; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | const msg = file.zir.nullTerminatedString(item.data.msg); | ||
| 489 | const byte_offset = blk: { | ||
| 490 | const token_starts = file.tree.tokens.items(.start); | ||
| 491 | if (item.data.node != 0) { | ||
| 492 | const main_tokens = file.tree.nodes.items(.main_token); | ||
| 493 | const main_token = main_tokens[item.data.node]; | ||
| 494 | break :blk token_starts[main_token]; | ||
| 495 | } | ||
| 496 | break :blk token_starts[item.data.token] + item.data.byte_offset; | ||
| 497 | }; | ||
| 498 | const loc = std.zig.findLineColumn(file.source, byte_offset); | ||
| 499 | |||
| 500 | try errors.append(.{ | ||
| 501 | .src = .{ | ||
| 502 | .src_path = try arena.dupe(u8, file.sub_file_path), | ||
| 503 | .msg = try arena.dupe(u8, msg), | ||
| 504 | .byte_offset = byte_offset, | ||
| 505 | .line = @intCast(u32, loc.line), | ||
| 506 | .column = @intCast(u32, loc.column), | ||
| 507 | .notes = notes, | ||
| 508 | .source_line = try arena.dupe(u8, loc.source_line), | ||
| 509 | }, | ||
| 510 | }); | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 419 | fn addPlain( | 514 | fn addPlain( |
| 420 | arena: *std.heap.ArenaAllocator, | 515 | arena: *std.heap.ArenaAllocator, |
| 421 | errors: *std.ArrayList(Message), | 516 | errors: *std.ArrayList(Message), |
| ... | @@ -530,7 +625,7 @@ pub const InitOptions = struct { | ... | @@ -530,7 +625,7 @@ pub const InitOptions = struct { |
| 530 | /// is externally modified - essentially anything other than zig-cache - then | 625 | /// is externally modified - essentially anything other than zig-cache - then |
| 531 | /// this flag would be set to disable this machinery to avoid false positives. | 626 | /// this flag would be set to disable this machinery to avoid false positives. |
| 532 | disable_lld_caching: bool = false, | 627 | disable_lld_caching: bool = false, |
| 533 | object_format: ?std.builtin.ObjectFormat = null, | 628 | object_format: ?std.Target.ObjectFormat = null, |
| 534 | optimize_mode: std.builtin.Mode = .Debug, | 629 | optimize_mode: std.builtin.Mode = .Debug, |
| 535 | keep_source_files_loaded: bool = false, | 630 | keep_source_files_loaded: bool = false, |
| 536 | clang_argv: []const []const u8 = &[0][]const u8{}, | 631 | clang_argv: []const []const u8 = &[0][]const u8{}, |
| ... | @@ -1044,45 +1139,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1044,45 +1139,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1044 | 1139 | ||
| 1045 | try std_pkg.add(gpa, "builtin", builtin_pkg); | 1140 | try std_pkg.add(gpa, "builtin", builtin_pkg); |
| 1046 | try std_pkg.add(gpa, "root", root_pkg); | 1141 | try std_pkg.add(gpa, "root", root_pkg); |
| 1142 | try std_pkg.add(gpa, "std", std_pkg); | ||
| 1143 | |||
| 1144 | try builtin_pkg.add(gpa, "std", std_pkg); | ||
| 1145 | try builtin_pkg.add(gpa, "builtin", builtin_pkg); | ||
| 1047 | } | 1146 | } |
| 1048 | 1147 | ||
| 1148 | // Pre-open the directory handles for cached ZIR code so that it does not need | ||
| 1149 | // to redundantly happen for each AstGen operation. | ||
| 1150 | const zir_sub_dir = "z"; | ||
| 1151 | |||
| 1152 | var local_zir_dir = try options.local_cache_directory.handle.makeOpenPath(zir_sub_dir, .{}); | ||
| 1153 | errdefer local_zir_dir.close(); | ||
| 1154 | const local_zir_cache: Directory = .{ | ||
| 1155 | .handle = local_zir_dir, | ||
| 1156 | .path = try options.local_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}), | ||
| 1157 | }; | ||
| 1158 | var global_zir_dir = try options.global_cache_directory.handle.makeOpenPath(zir_sub_dir, .{}); | ||
| 1159 | errdefer global_zir_dir.close(); | ||
| 1160 | const global_zir_cache: Directory = .{ | ||
| 1161 | .handle = global_zir_dir, | ||
| 1162 | .path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}), | ||
| 1163 | }; | ||
| 1164 | |||
| 1165 | const emit_h: ?*Module.GlobalEmitH = if (options.emit_h) |loc| eh: { | ||
| 1166 | const eh = try gpa.create(Module.GlobalEmitH); | ||
| 1167 | eh.* = .{ .loc = loc }; | ||
| 1168 | break :eh eh; | ||
| 1169 | } else null; | ||
| 1170 | errdefer if (emit_h) |eh| gpa.destroy(eh); | ||
| 1171 | |||
| 1049 | // TODO when we implement serialization and deserialization of incremental | 1172 | // TODO when we implement serialization and deserialization of incremental |
| 1050 | // compilation metadata, this is where we would load it. We have open a handle | 1173 | // compilation metadata, this is where we would load it. We have open a handle |
| 1051 | // to the directory where the output either already is, or will be. | 1174 | // to the directory where the output either already is, or will be. |
| 1052 | // However we currently do not have serialization of such metadata, so for now | 1175 | // However we currently do not have serialization of such metadata, so for now |
| 1053 | // we set up an empty Module that does the entire compilation fresh. | 1176 | // we set up an empty Module that does the entire compilation fresh. |
| 1054 | 1177 | ||
| 1055 | const root_scope = try gpa.create(Module.Scope.File); | ||
| 1056 | errdefer gpa.destroy(root_scope); | ||
| 1057 | |||
| 1058 | const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container); | ||
| 1059 | root_scope.* = .{ | ||
| 1060 | // TODO this is duped so it can be freed in Container.deinit | ||
| 1061 | .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path), | ||
| 1062 | .source = .{ .unloaded = {} }, | ||
| 1063 | .tree = undefined, | ||
| 1064 | .status = .never_loaded, | ||
| 1065 | .pkg = root_pkg, | ||
| 1066 | .root_container = .{ | ||
| 1067 | .file_scope = root_scope, | ||
| 1068 | .decls = .{}, | ||
| 1069 | .ty = struct_ty, | ||
| 1070 | .parent_name_hash = root_pkg.namespace_hash, | ||
| 1071 | }, | ||
| 1072 | }; | ||
| 1073 | |||
| 1074 | const module = try arena.create(Module); | 1178 | const module = try arena.create(Module); |
| 1075 | errdefer module.deinit(); | 1179 | errdefer module.deinit(); |
| 1076 | module.* = .{ | 1180 | module.* = .{ |
| 1077 | .gpa = gpa, | 1181 | .gpa = gpa, |
| 1078 | .comp = comp, | 1182 | .comp = comp, |
| 1079 | .root_pkg = root_pkg, | 1183 | .root_pkg = root_pkg, |
| 1080 | .root_scope = root_scope, | ||
| 1081 | .zig_cache_artifact_directory = zig_cache_artifact_directory, | 1184 | .zig_cache_artifact_directory = zig_cache_artifact_directory, |
| 1082 | .emit_h = options.emit_h, | 1185 | .global_zir_cache = global_zir_cache, |
| 1186 | .local_zir_cache = local_zir_cache, | ||
| 1187 | .emit_h = emit_h, | ||
| 1083 | .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), | 1188 | .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), |
| 1084 | }; | 1189 | }; |
| 1085 | module.error_name_list.appendAssumeCapacity("(no error)"); | 1190 | module.error_name_list.appendAssumeCapacity("(no error)"); |
| 1191 | |||
| 1086 | break :blk module; | 1192 | break :blk module; |
| 1087 | } else blk: { | 1193 | } else blk: { |
| 1088 | if (options.emit_h != null) return error.NoZigModuleForCHeader; | 1194 | if (options.emit_h != null) return error.NoZigModuleForCHeader; |
| ... | @@ -1229,6 +1335,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1229,6 +1335,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1229 | .emit_docs = options.emit_docs, | 1335 | .emit_docs = options.emit_docs, |
| 1230 | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), | 1336 | .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), |
| 1231 | .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), | 1337 | .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), |
| 1338 | .astgen_work_queue = std.fifo.LinearFifo(*Module.Scope.File, .Dynamic).init(gpa), | ||
| 1232 | .keep_source_files_loaded = options.keep_source_files_loaded, | 1339 | .keep_source_files_loaded = options.keep_source_files_loaded, |
| 1233 | .use_clang = use_clang, | 1340 | .use_clang = use_clang, |
| 1234 | .clang_argv = options.clang_argv, | 1341 | .clang_argv = options.clang_argv, |
| ... | @@ -1257,6 +1364,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1257,6 +1364,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1257 | .test_evented_io = options.test_evented_io, | 1364 | .test_evented_io = options.test_evented_io, |
| 1258 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, | 1365 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 1259 | .work_queue_wait_group = undefined, | 1366 | .work_queue_wait_group = undefined, |
| 1367 | .astgen_wait_group = undefined, | ||
| 1260 | }; | 1368 | }; |
| 1261 | break :comp comp; | 1369 | break :comp comp; |
| 1262 | }; | 1370 | }; |
| ... | @@ -1265,9 +1373,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1265,9 +1373,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1265 | try comp.work_queue_wait_group.init(); | 1373 | try comp.work_queue_wait_group.init(); |
| 1266 | errdefer comp.work_queue_wait_group.deinit(); | 1374 | errdefer comp.work_queue_wait_group.deinit(); |
| 1267 | 1375 | ||
| 1268 | if (comp.bin_file.options.module) |mod| { | 1376 | try comp.astgen_wait_group.init(); |
| 1269 | try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} }); | 1377 | errdefer comp.astgen_wait_group.deinit(); |
| 1270 | } | ||
| 1271 | 1378 | ||
| 1272 | // Add a `CObject` for each `c_source_files`. | 1379 | // Add a `CObject` for each `c_source_files`. |
| 1273 | try comp.c_object_table.ensureCapacity(gpa, options.c_source_files.len); | 1380 | try comp.c_object_table.ensureCapacity(gpa, options.c_source_files.len); |
| ... | @@ -1400,6 +1507,7 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -1400,6 +1507,7 @@ pub fn destroy(self: *Compilation) void { |
| 1400 | const gpa = self.gpa; | 1507 | const gpa = self.gpa; |
| 1401 | self.work_queue.deinit(); | 1508 | self.work_queue.deinit(); |
| 1402 | self.c_object_work_queue.deinit(); | 1509 | self.c_object_work_queue.deinit(); |
| 1510 | self.astgen_work_queue.deinit(); | ||
| 1403 | 1511 | ||
| 1404 | { | 1512 | { |
| 1405 | var it = self.crt_files.iterator(); | 1513 | var it = self.crt_files.iterator(); |
| ... | @@ -1450,6 +1558,7 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -1450,6 +1558,7 @@ pub fn destroy(self: *Compilation) void { |
| 1450 | if (self.owned_link_dir) |*dir| dir.close(); | 1558 | if (self.owned_link_dir) |*dir| dir.close(); |
| 1451 | 1559 | ||
| 1452 | self.work_queue_wait_group.deinit(); | 1560 | self.work_queue_wait_group.deinit(); |
| 1561 | self.astgen_wait_group.deinit(); | ||
| 1453 | 1562 | ||
| 1454 | // This destroys `self`. | 1563 | // This destroys `self`. |
| 1455 | self.arena_state.promote(gpa).deinit(); | 1564 | self.arena_state.promote(gpa).deinit(); |
| ... | @@ -1489,31 +1598,20 @@ pub fn update(self: *Compilation) !void { | ... | @@ -1489,31 +1598,20 @@ pub fn update(self: *Compilation) !void { |
| 1489 | module.compile_log_text.shrinkAndFree(module.gpa, 0); | 1598 | module.compile_log_text.shrinkAndFree(module.gpa, 0); |
| 1490 | module.generation += 1; | 1599 | module.generation += 1; |
| 1491 | 1600 | ||
| 1492 | // TODO Detect which source files changed. | 1601 | // Make sure std.zig is inside the import_table. We unconditionally need |
| 1493 | // Until then we simulate a full cache miss. Source files could have been loaded | 1602 | // it for start.zig. |
| 1494 | // for any reason; to force a refresh we unload now. | 1603 | const std_pkg = module.root_pkg.table.get("std").?; |
| 1495 | module.unloadFile(module.root_scope); | 1604 | _ = try module.importPkg(module.root_pkg, std_pkg); |
| 1496 | module.failed_root_src_file = null; | ||
| 1497 | module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) { | ||
| 1498 | error.AnalysisFail => { | ||
| 1499 | assert(self.totalErrorCount() != 0); | ||
| 1500 | }, | ||
| 1501 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1502 | else => |e| { | ||
| 1503 | module.failed_root_src_file = e; | ||
| 1504 | }, | ||
| 1505 | }; | ||
| 1506 | 1605 | ||
| 1507 | // TODO only analyze imports if they are still referenced | 1606 | // Put a work item in for every known source file to detect if |
| 1607 | // it changed, and, if so, re-compute ZIR and then queue the job | ||
| 1608 | // to update it. | ||
| 1609 | try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count()); | ||
| 1508 | for (module.import_table.items()) |entry| { | 1610 | for (module.import_table.items()) |entry| { |
| 1509 | module.unloadFile(entry.value); | 1611 | self.astgen_work_queue.writeItemAssumeCapacity(entry.value); |
| 1510 | module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) { | ||
| 1511 | error.AnalysisFail => { | ||
| 1512 | assert(self.totalErrorCount() != 0); | ||
| 1513 | }, | ||
| 1514 | else => |e| return e, | ||
| 1515 | }; | ||
| 1516 | } | 1612 | } |
| 1613 | |||
| 1614 | try self.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); | ||
| 1517 | } | 1615 | } |
| 1518 | } | 1616 | } |
| 1519 | 1617 | ||
| ... | @@ -1522,16 +1620,24 @@ pub fn update(self: *Compilation) !void { | ... | @@ -1522,16 +1620,24 @@ pub fn update(self: *Compilation) !void { |
| 1522 | if (!use_stage1) { | 1620 | if (!use_stage1) { |
| 1523 | if (self.bin_file.options.module) |module| { | 1621 | if (self.bin_file.options.module) |module| { |
| 1524 | // Process the deletion set. We use a while loop here because the | 1622 | // Process the deletion set. We use a while loop here because the |
| 1525 | // deletion set may grow as we call `deleteDecl` within this loop, | 1623 | // deletion set may grow as we call `clearDecl` within this loop, |
| 1526 | // and more unreferenced Decls are revealed. | 1624 | // and more unreferenced Decls are revealed. |
| 1527 | var entry_i: usize = 0; | 1625 | while (module.deletion_set.entries.items.len != 0) { |
| 1528 | while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) { | 1626 | const decl = module.deletion_set.entries.items[0].key; |
| 1529 | const decl = module.deletion_set.entries.items[entry_i].key; | ||
| 1530 | assert(decl.deletion_flag); | 1627 | assert(decl.deletion_flag); |
| 1531 | assert(decl.dependants.items().len == 0); | 1628 | assert(decl.dependants.count() == 0); |
| 1532 | try module.deleteDecl(decl, null); | 1629 | const is_anon = if (decl.zir_decl_index == 0) blk: { |
| 1630 | break :blk decl.namespace.anon_decls.swapRemove(decl) != null; | ||
| 1631 | } else false; | ||
| 1632 | |||
| 1633 | try module.clearDecl(decl, null); | ||
| 1634 | |||
| 1635 | if (is_anon) { | ||
| 1636 | decl.destroy(module); | ||
| 1637 | } | ||
| 1533 | } | 1638 | } |
| 1534 | module.deletion_set.shrinkRetainingCapacity(0); | 1639 | |
| 1640 | try module.processExports(); | ||
| 1535 | } | 1641 | } |
| 1536 | } | 1642 | } |
| 1537 | 1643 | ||
| ... | @@ -1553,9 +1659,16 @@ pub fn update(self: *Compilation) !void { | ... | @@ -1553,9 +1659,16 @@ pub fn update(self: *Compilation) !void { |
| 1553 | 1659 | ||
| 1554 | // If there are any errors, we anticipate the source files being loaded | 1660 | // If there are any errors, we anticipate the source files being loaded |
| 1555 | // to report error messages. Otherwise we unload all source files to save memory. | 1661 | // to report error messages. Otherwise we unload all source files to save memory. |
| 1662 | // The ZIR needs to stay loaded in memory because (1) Decl objects contain references | ||
| 1663 | // to it, and (2) generic instantiations, comptime calls, inline calls will need | ||
| 1664 | // to reference the ZIR. | ||
| 1556 | if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { | 1665 | if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { |
| 1557 | if (self.bin_file.options.module) |module| { | 1666 | if (self.bin_file.options.module) |module| { |
| 1558 | module.root_scope.unload(self.gpa); | 1667 | for (module.import_table.items()) |entry| { |
| 1668 | const file = entry.value; | ||
| 1669 | file.unloadTree(self.gpa); | ||
| 1670 | file.unloadSource(self.gpa); | ||
| 1671 | } | ||
| 1559 | } | 1672 | } |
| 1560 | } | 1673 | } |
| 1561 | } | 1674 | } |
| ... | @@ -1576,24 +1689,36 @@ pub fn totalErrorCount(self: *Compilation) usize { | ... | @@ -1576,24 +1689,36 @@ pub fn totalErrorCount(self: *Compilation) usize { |
| 1576 | var total: usize = self.failed_c_objects.count() + self.misc_failures.count(); | 1689 | var total: usize = self.failed_c_objects.count() + self.misc_failures.count(); |
| 1577 | 1690 | ||
| 1578 | if (self.bin_file.options.module) |module| { | 1691 | if (self.bin_file.options.module) |module| { |
| 1579 | total += module.failed_exports.items().len + | 1692 | total += module.failed_exports.items().len; |
| 1580 | module.failed_files.items().len + | 1693 | |
| 1581 | @boolToInt(module.failed_root_src_file != null); | 1694 | for (module.failed_files.items()) |entry| { |
| 1695 | if (entry.value) |_| { | ||
| 1696 | total += 1; | ||
| 1697 | } else { | ||
| 1698 | const file = entry.key; | ||
| 1699 | assert(file.zir_loaded); | ||
| 1700 | const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)]; | ||
| 1701 | assert(payload_index != 0); | ||
| 1702 | const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); | ||
| 1703 | total += header.data.items_len; | ||
| 1704 | } | ||
| 1705 | } | ||
| 1706 | |||
| 1582 | // Skip errors for Decls within files that failed parsing. | 1707 | // Skip errors for Decls within files that failed parsing. |
| 1583 | // When a parse error is introduced, we keep all the semantic analysis for | 1708 | // When a parse error is introduced, we keep all the semantic analysis for |
| 1584 | // the previous parse success, including compile errors, but we cannot | 1709 | // the previous parse success, including compile errors, but we cannot |
| 1585 | // emit them until the file succeeds parsing. | 1710 | // emit them until the file succeeds parsing. |
| 1586 | for (module.failed_decls.items()) |entry| { | 1711 | for (module.failed_decls.items()) |entry| { |
| 1587 | if (entry.key.container.file_scope.status == .unloaded_parse_failure) { | 1712 | if (entry.key.namespace.file_scope.okToReportErrors()) { |
| 1588 | continue; | 1713 | total += 1; |
| 1589 | } | 1714 | } |
| 1590 | total += 1; | ||
| 1591 | } | 1715 | } |
| 1592 | for (module.emit_h_failed_decls.items()) |entry| { | 1716 | if (module.emit_h) |emit_h| { |
| 1593 | if (entry.key.container.file_scope.status == .unloaded_parse_failure) { | 1717 | for (emit_h.failed_decls.items()) |entry| { |
| 1594 | continue; | 1718 | if (entry.key.namespace.file_scope.okToReportErrors()) { |
| 1719 | total += 1; | ||
| 1720 | } | ||
| 1595 | } | 1721 | } |
| 1596 | total += 1; | ||
| 1597 | } | 1722 | } |
| 1598 | } | 1723 | } |
| 1599 | 1724 | ||
| ... | @@ -1642,36 +1767,35 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { | ... | @@ -1642,36 +1767,35 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { |
| 1642 | } | 1767 | } |
| 1643 | if (self.bin_file.options.module) |module| { | 1768 | if (self.bin_file.options.module) |module| { |
| 1644 | for (module.failed_files.items()) |entry| { | 1769 | for (module.failed_files.items()) |entry| { |
| 1645 | try AllErrors.add(module, &arena, &errors, entry.value.*); | 1770 | if (entry.value) |msg| { |
| 1771 | try AllErrors.add(module, &arena, &errors, msg.*); | ||
| 1772 | } else { | ||
| 1773 | // Must be ZIR errors. In order for ZIR errors to exist, the parsing | ||
| 1774 | // must have completed successfully. | ||
| 1775 | const tree = try entry.key.getTree(module.gpa); | ||
| 1776 | assert(tree.errors.len == 0); | ||
| 1777 | try AllErrors.addZir(&arena.allocator, &errors, entry.key); | ||
| 1778 | } | ||
| 1646 | } | 1779 | } |
| 1647 | for (module.failed_decls.items()) |entry| { | 1780 | for (module.failed_decls.items()) |entry| { |
| 1648 | if (entry.key.container.file_scope.status == .unloaded_parse_failure) { | 1781 | // Skip errors for Decls within files that had a parse failure. |
| 1649 | // Skip errors for Decls within files that had a parse failure. | 1782 | // We'll try again once parsing succeeds. |
| 1650 | // We'll try again once parsing succeeds. | 1783 | if (entry.key.namespace.file_scope.okToReportErrors()) { |
| 1651 | continue; | 1784 | try AllErrors.add(module, &arena, &errors, entry.value.*); |
| 1652 | } | 1785 | } |
| 1653 | try AllErrors.add(module, &arena, &errors, entry.value.*); | ||
| 1654 | } | 1786 | } |
| 1655 | for (module.emit_h_failed_decls.items()) |entry| { | 1787 | if (module.emit_h) |emit_h| { |
| 1656 | if (entry.key.container.file_scope.status == .unloaded_parse_failure) { | 1788 | for (emit_h.failed_decls.items()) |entry| { |
| 1657 | // Skip errors for Decls within files that had a parse failure. | 1789 | // Skip errors for Decls within files that had a parse failure. |
| 1658 | // We'll try again once parsing succeeds. | 1790 | // We'll try again once parsing succeeds. |
| 1659 | continue; | 1791 | if (entry.key.namespace.file_scope.okToReportErrors()) { |
| 1792 | try AllErrors.add(module, &arena, &errors, entry.value.*); | ||
| 1793 | } | ||
| 1660 | } | 1794 | } |
| 1661 | try AllErrors.add(module, &arena, &errors, entry.value.*); | ||
| 1662 | } | 1795 | } |
| 1663 | for (module.failed_exports.items()) |entry| { | 1796 | for (module.failed_exports.items()) |entry| { |
| 1664 | try AllErrors.add(module, &arena, &errors, entry.value.*); | 1797 | try AllErrors.add(module, &arena, &errors, entry.value.*); |
| 1665 | } | 1798 | } |
| 1666 | if (module.failed_root_src_file) |err| { | ||
| 1667 | const file_path = try module.root_pkg.root_src_directory.join(&arena.allocator, &[_][]const u8{ | ||
| 1668 | module.root_pkg.root_src_path, | ||
| 1669 | }); | ||
| 1670 | const msg = try std.fmt.allocPrint(&arena.allocator, "unable to read {s}: {s}", .{ | ||
| 1671 | file_path, @errorName(err), | ||
| 1672 | }); | ||
| 1673 | try AllErrors.addPlain(&arena, &errors, msg); | ||
| 1674 | } | ||
| 1675 | } | 1799 | } |
| 1676 | 1800 | ||
| 1677 | if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) { | 1801 | if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) { |
| ... | @@ -1686,8 +1810,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { | ... | @@ -1686,8 +1810,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { |
| 1686 | const compile_log_items = module.compile_log_decls.items(); | 1810 | const compile_log_items = module.compile_log_decls.items(); |
| 1687 | if (errors.items.len == 0 and compile_log_items.len != 0) { | 1811 | if (errors.items.len == 0 and compile_log_items.len != 0) { |
| 1688 | // First one will be the error; subsequent ones will be notes. | 1812 | // First one will be the error; subsequent ones will be notes. |
| 1813 | const src_loc = compile_log_items[0].key.nodeOffsetSrcLoc(compile_log_items[0].value); | ||
| 1689 | const err_msg = Module.ErrorMsg{ | 1814 | const err_msg = Module.ErrorMsg{ |
| 1690 | .src_loc = compile_log_items[0].value, | 1815 | .src_loc = src_loc, |
| 1691 | .msg = "found compile log statement", | 1816 | .msg = "found compile log statement", |
| 1692 | .notes = try self.gpa.alloc(Module.ErrorMsg, compile_log_items.len - 1), | 1817 | .notes = try self.gpa.alloc(Module.ErrorMsg, compile_log_items.len - 1), |
| 1693 | }; | 1818 | }; |
| ... | @@ -1695,7 +1820,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { | ... | @@ -1695,7 +1820,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { |
| 1695 | 1820 | ||
| 1696 | for (compile_log_items[1..]) |entry, i| { | 1821 | for (compile_log_items[1..]) |entry, i| { |
| 1697 | err_msg.notes[i] = .{ | 1822 | err_msg.notes[i] = .{ |
| 1698 | .src_loc = entry.value, | 1823 | .src_loc = entry.key.nodeOffsetSrcLoc(entry.value), |
| 1699 | .msg = "also here", | 1824 | .msg = "also here", |
| 1700 | }; | 1825 | }; |
| 1701 | } | 1826 | } |
| ... | @@ -1725,17 +1850,51 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1725,17 +1850,51 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1725 | defer main_progress_node.end(); | 1850 | defer main_progress_node.end(); |
| 1726 | if (self.color == .off) progress.terminal = null; | 1851 | if (self.color == .off) progress.terminal = null; |
| 1727 | 1852 | ||
| 1728 | var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len); | 1853 | // If we need to write out builtin.zig, it needs to be done before starting |
| 1729 | defer c_comp_progress_node.end(); | 1854 | // the AstGen tasks. |
| 1855 | if (self.bin_file.options.module) |mod| { | ||
| 1856 | if (mod.job_queued_update_builtin_zig) { | ||
| 1857 | mod.job_queued_update_builtin_zig = false; | ||
| 1858 | try self.updateBuiltinZigFile(mod); | ||
| 1859 | } | ||
| 1860 | } | ||
| 1861 | |||
| 1862 | // Here we queue up all the AstGen tasks first, followed by C object compilation. | ||
| 1863 | // We wait until the AstGen tasks are all completed before proceeding to the | ||
| 1864 | // (at least for now) single-threaded main work queue. However, C object compilation | ||
| 1865 | // only needs to be finished by the end of this function. | ||
| 1866 | |||
| 1867 | var zir_prog_node = main_progress_node.start("AstGen", self.astgen_work_queue.count); | ||
| 1868 | defer zir_prog_node.end(); | ||
| 1869 | |||
| 1870 | var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len); | ||
| 1871 | defer c_obj_prog_node.end(); | ||
| 1730 | 1872 | ||
| 1731 | self.work_queue_wait_group.reset(); | 1873 | self.work_queue_wait_group.reset(); |
| 1732 | defer self.work_queue_wait_group.wait(); | 1874 | defer self.work_queue_wait_group.wait(); |
| 1733 | 1875 | ||
| 1734 | while (self.c_object_work_queue.readItem()) |c_object| { | 1876 | { |
| 1735 | self.work_queue_wait_group.start(); | 1877 | self.astgen_wait_group.reset(); |
| 1736 | try self.thread_pool.spawn(workerUpdateCObject, .{ | 1878 | defer self.astgen_wait_group.wait(); |
| 1737 | self, c_object, &c_comp_progress_node, &self.work_queue_wait_group, | 1879 | |
| 1738 | }); | 1880 | while (self.astgen_work_queue.readItem()) |file| { |
| 1881 | self.astgen_wait_group.start(); | ||
| 1882 | try self.thread_pool.spawn(workerAstGenFile, .{ | ||
| 1883 | self, file, &zir_prog_node, &self.astgen_wait_group, | ||
| 1884 | }); | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | while (self.c_object_work_queue.readItem()) |c_object| { | ||
| 1888 | self.work_queue_wait_group.start(); | ||
| 1889 | try self.thread_pool.spawn(workerUpdateCObject, .{ | ||
| 1890 | self, c_object, &c_obj_prog_node, &self.work_queue_wait_group, | ||
| 1891 | }); | ||
| 1892 | } | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | // Iterate over all the files and look for outdated and deleted declarations. | ||
| 1896 | if (self.bin_file.options.module) |mod| { | ||
| 1897 | try mod.processOutdatedAndDeletedDecls(); | ||
| 1739 | } | 1898 | } |
| 1740 | 1899 | ||
| 1741 | while (self.work_queue.readItem()) |work_item| switch (work_item) { | 1900 | while (self.work_queue.readItem()) |work_item| switch (work_item) { |
| ... | @@ -1744,6 +1903,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1744,6 +1903,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1744 | .in_progress => unreachable, | 1903 | .in_progress => unreachable, |
| 1745 | .outdated => unreachable, | 1904 | .outdated => unreachable, |
| 1746 | 1905 | ||
| 1906 | .file_failure, | ||
| 1747 | .sema_failure, | 1907 | .sema_failure, |
| 1748 | .codegen_failure, | 1908 | .codegen_failure, |
| 1749 | .dependency_failure, | 1909 | .dependency_failure, |
| ... | @@ -1754,7 +1914,8 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1754,7 +1914,8 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1754 | if (build_options.omit_stage2) | 1914 | if (build_options.omit_stage2) |
| 1755 | @panic("sadly stage2 is omitted from this build to save memory on the CI server"); | 1915 | @panic("sadly stage2 is omitted from this build to save memory on the CI server"); |
| 1756 | const module = self.bin_file.options.module.?; | 1916 | const module = self.bin_file.options.module.?; |
| 1757 | if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| { | 1917 | assert(decl.has_tv); |
| 1918 | if (decl.val.castTag(.function)) |payload| { | ||
| 1758 | const func = payload.data; | 1919 | const func = payload.data; |
| 1759 | switch (func.state) { | 1920 | switch (func.state) { |
| 1760 | .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) { | 1921 | .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) { |
| ... | @@ -1771,8 +1932,8 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1771,8 +1932,8 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1771 | } | 1932 | } |
| 1772 | // Here we tack on additional allocations to the Decl's arena. The allocations | 1933 | // Here we tack on additional allocations to the Decl's arena. The allocations |
| 1773 | // are lifetime annotations in the ZIR. | 1934 | // are lifetime annotations in the ZIR. |
| 1774 | var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa); | 1935 | var decl_arena = decl.value_arena.?.promote(module.gpa); |
| 1775 | defer decl.typed_value.most_recent.arena.?.* = decl_arena.state; | 1936 | defer decl.value_arena.?.* = decl_arena.state; |
| 1776 | log.debug("analyze liveness of {s}", .{decl.name}); | 1937 | log.debug("analyze liveness of {s}", .{decl.name}); |
| 1777 | try liveness.analyze(module.gpa, &decl_arena.allocator, func.body); | 1938 | try liveness.analyze(module.gpa, &decl_arena.allocator, func.body); |
| 1778 | 1939 | ||
| ... | @@ -1781,10 +1942,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1781,10 +1942,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1781 | } | 1942 | } |
| 1782 | } | 1943 | } |
| 1783 | 1944 | ||
| 1784 | log.debug("calling updateDecl on '{s}', type={}", .{ | 1945 | assert(decl.ty.hasCodeGenBits()); |
| 1785 | decl.name, decl.typed_value.most_recent.typed_value.ty, | ||
| 1786 | }); | ||
| 1787 | assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits()); | ||
| 1788 | 1946 | ||
| 1789 | self.bin_file.updateDecl(module, decl) catch |err| switch (err) { | 1947 | self.bin_file.updateDecl(module, decl) catch |err| switch (err) { |
| 1790 | error.OutOfMemory => return error.OutOfMemory, | 1948 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -1811,6 +1969,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1811,6 +1969,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1811 | .in_progress => unreachable, | 1969 | .in_progress => unreachable, |
| 1812 | .outdated => unreachable, | 1970 | .outdated => unreachable, |
| 1813 | 1971 | ||
| 1972 | .file_failure, | ||
| 1814 | .sema_failure, | 1973 | .sema_failure, |
| 1815 | .dependency_failure, | 1974 | .dependency_failure, |
| 1816 | .sema_failure_retryable, | 1975 | .sema_failure_retryable, |
| ... | @@ -1822,10 +1981,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1822,10 +1981,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1822 | if (build_options.omit_stage2) | 1981 | if (build_options.omit_stage2) |
| 1823 | @panic("sadly stage2 is omitted from this build to save memory on the CI server"); | 1982 | @panic("sadly stage2 is omitted from this build to save memory on the CI server"); |
| 1824 | const module = self.bin_file.options.module.?; | 1983 | const module = self.bin_file.options.module.?; |
| 1825 | const emit_loc = module.emit_h.?; | 1984 | const emit_h = module.emit_h.?; |
| 1826 | const tv = decl.typed_value.most_recent.typed_value; | 1985 | _ = try emit_h.decl_table.getOrPut(module.gpa, decl); |
| 1827 | const emit_h = decl.getEmitH(module); | 1986 | const decl_emit_h = decl.getEmitH(module); |
| 1828 | const fwd_decl = &emit_h.fwd_decl; | 1987 | const fwd_decl = &decl_emit_h.fwd_decl; |
| 1829 | fwd_decl.shrinkRetainingCapacity(0); | 1988 | fwd_decl.shrinkRetainingCapacity(0); |
| 1830 | 1989 | ||
| 1831 | var dg: c_codegen.DeclGen = .{ | 1990 | var dg: c_codegen.DeclGen = .{ |
| ... | @@ -1840,7 +1999,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1840,7 +1999,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1840 | 1999 | ||
| 1841 | c_codegen.genHeader(&dg) catch |err| switch (err) { | 2000 | c_codegen.genHeader(&dg) catch |err| switch (err) { |
| 1842 | error.AnalysisFail => { | 2001 | error.AnalysisFail => { |
| 1843 | try module.emit_h_failed_decls.put(module.gpa, decl, dg.error_msg.?); | 2002 | try emit_h.failed_decls.put(module.gpa, decl, dg.error_msg.?); |
| 1844 | continue; | 2003 | continue; |
| 1845 | }, | 2004 | }, |
| 1846 | else => |e| return e, | 2005 | else => |e| return e, |
| ... | @@ -1874,6 +2033,22 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -1874,6 +2033,22 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1874 | decl.analysis = .codegen_failure_retryable; | 2033 | decl.analysis = .codegen_failure_retryable; |
| 1875 | }; | 2034 | }; |
| 1876 | }, | 2035 | }, |
| 2036 | .analyze_pkg => |pkg| { | ||
| 2037 | if (build_options.omit_stage2) | ||
| 2038 | @panic("sadly stage2 is omitted from this build to save memory on the CI server"); | ||
| 2039 | const module = self.bin_file.options.module.?; | ||
| 2040 | module.semaPkg(pkg) catch |err| switch (err) { | ||
| 2041 | error.CurrentWorkingDirectoryUnlinked, | ||
| 2042 | error.Unexpected, | ||
| 2043 | => try self.setMiscFailure( | ||
| 2044 | .analyze_pkg, | ||
| 2045 | "unexpected problem analyzing package '{s}'", | ||
| 2046 | .{pkg.root_src_path}, | ||
| 2047 | ), | ||
| 2048 | error.OutOfMemory => return error.OutOfMemory, | ||
| 2049 | error.AnalysisFail => continue, | ||
| 2050 | }; | ||
| 2051 | }, | ||
| 1877 | .glibc_crt_file => |crt_file| { | 2052 | .glibc_crt_file => |crt_file| { |
| 1878 | glibc.buildCRTFile(self, crt_file) catch |err| { | 2053 | glibc.buildCRTFile(self, crt_file) catch |err| { |
| 1879 | // TODO Surface more error details. | 2054 | // TODO Surface more error details. |
| ... | @@ -2027,10 +2202,6 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -2027,10 +2202,6 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 2027 | ), | 2202 | ), |
| 2028 | }; | 2203 | }; |
| 2029 | }, | 2204 | }, |
| 2030 | .generate_builtin_zig => { | ||
| 2031 | // This Job is only queued up if there is a zig module. | ||
| 2032 | try self.updateBuiltinZigFile(self.bin_file.options.module.?); | ||
| 2033 | }, | ||
| 2034 | .stage1_module => { | 2205 | .stage1_module => { |
| 2035 | if (!build_options.is_stage1) | 2206 | if (!build_options.is_stage1) |
| 2036 | unreachable; | 2207 | unreachable; |
| ... | @@ -2042,6 +2213,58 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -2042,6 +2213,58 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 2042 | }; | 2213 | }; |
| 2043 | } | 2214 | } |
| 2044 | 2215 | ||
| 2216 | fn workerAstGenFile( | ||
| 2217 | comp: *Compilation, | ||
| 2218 | file: *Module.Scope.File, | ||
| 2219 | prog_node: *std.Progress.Node, | ||
| 2220 | wg: *WaitGroup, | ||
| 2221 | ) void { | ||
| 2222 | defer wg.finish(); | ||
| 2223 | |||
| 2224 | const mod = comp.bin_file.options.module.?; | ||
| 2225 | mod.astGenFile(file, prog_node) catch |err| switch (err) { | ||
| 2226 | error.AnalysisFail => return, | ||
| 2227 | else => { | ||
| 2228 | file.status = .retryable_failure; | ||
| 2229 | comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) { | ||
| 2230 | // Swallowing this error is OK because it's implied to be OOM when | ||
| 2231 | // there is a missing `failed_files` error message. | ||
| 2232 | error.OutOfMemory => {}, | ||
| 2233 | }; | ||
| 2234 | return; | ||
| 2235 | }, | ||
| 2236 | }; | ||
| 2237 | |||
| 2238 | // Pre-emptively look for `@import` paths and queue them up. | ||
| 2239 | // If we experience an error preemptively fetching the | ||
| 2240 | // file, just ignore it and let it happen again later during Sema. | ||
| 2241 | assert(file.zir_loaded); | ||
| 2242 | const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)]; | ||
| 2243 | if (imports_index != 0) { | ||
| 2244 | const imports_len = file.zir.extra[imports_index]; | ||
| 2245 | |||
| 2246 | for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| { | ||
| 2247 | const import_path = file.zir.nullTerminatedString(str_index); | ||
| 2248 | |||
| 2249 | const import_result = blk: { | ||
| 2250 | const lock = comp.mutex.acquire(); | ||
| 2251 | defer lock.release(); | ||
| 2252 | |||
| 2253 | break :blk mod.importFile(file, import_path) catch continue; | ||
| 2254 | }; | ||
| 2255 | if (import_result.is_new) { | ||
| 2256 | wg.start(); | ||
| 2257 | comp.thread_pool.spawn(workerAstGenFile, .{ | ||
| 2258 | comp, import_result.file, prog_node, wg, | ||
| 2259 | }) catch { | ||
| 2260 | wg.finish(); | ||
| 2261 | continue; | ||
| 2262 | }; | ||
| 2263 | } | ||
| 2264 | } | ||
| 2265 | } | ||
| 2266 | } | ||
| 2267 | |||
| 2045 | pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { | 2268 | pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { |
| 2046 | var man = comp.cache_parent.obtain(); | 2269 | var man = comp.cache_parent.obtain(); |
| 2047 | 2270 | ||
| ... | @@ -2241,7 +2464,33 @@ fn reportRetryableCObjectError( | ... | @@ -2241,7 +2464,33 @@ fn reportRetryableCObjectError( |
| 2241 | } | 2464 | } |
| 2242 | } | 2465 | } |
| 2243 | 2466 | ||
| 2244 | fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void { | 2467 | fn reportRetryableAstGenError( |
| 2468 | comp: *Compilation, | ||
| 2469 | file: *Module.Scope.File, | ||
| 2470 | err: anyerror, | ||
| 2471 | ) error{OutOfMemory}!void { | ||
| 2472 | const mod = comp.bin_file.options.module.?; | ||
| 2473 | const gpa = mod.gpa; | ||
| 2474 | |||
| 2475 | file.status = .retryable_failure; | ||
| 2476 | |||
| 2477 | const err_msg = try Module.ErrorMsg.create(gpa, .{ | ||
| 2478 | .file_scope = file, | ||
| 2479 | .parent_decl_node = 0, | ||
| 2480 | .lazy = .entire_file, | ||
| 2481 | }, "unable to load {s}: {s}", .{ | ||
| 2482 | file.sub_file_path, @errorName(err), | ||
| 2483 | }); | ||
| 2484 | errdefer err_msg.destroy(gpa); | ||
| 2485 | |||
| 2486 | { | ||
| 2487 | const lock = comp.mutex.acquire(); | ||
| 2488 | defer lock.release(); | ||
| 2489 | try mod.failed_files.putNoClobber(gpa, file, err_msg); | ||
| 2490 | } | ||
| 2491 | } | ||
| 2492 | |||
| 2493 | fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void { | ||
| 2245 | if (!build_options.have_llvm) { | 2494 | if (!build_options.have_llvm) { |
| 2246 | return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); | 2495 | return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); |
| 2247 | } | 2496 | } |
| ... | @@ -2292,8 +2541,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: * | ... | @@ -2292,8 +2541,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: * |
| 2292 | 2541 | ||
| 2293 | const c_source_basename = std.fs.path.basename(c_object.src.src_path); | 2542 | const c_source_basename = std.fs.path.basename(c_object.src.src_path); |
| 2294 | 2543 | ||
| 2295 | c_comp_progress_node.activate(); | 2544 | c_obj_prog_node.activate(); |
| 2296 | var child_progress_node = c_comp_progress_node.start(c_source_basename, 0); | 2545 | var child_progress_node = c_obj_prog_node.start(c_source_basename, 0); |
| 2297 | child_progress_node.activate(); | 2546 | child_progress_node.activate(); |
| 2298 | defer child_progress_node.end(); | 2547 | defer child_progress_node.end(); |
| 2299 | 2548 | ||
| ... | @@ -3009,7 +3258,8 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { | ... | @@ -3009,7 +3258,8 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { |
| 3009 | .Exe => true, | 3258 | .Exe => true, |
| 3010 | }; | 3259 | }; |
| 3011 | return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and | 3260 | return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and |
| 3012 | comp.bin_file.options.libc_installation == null; | 3261 | comp.bin_file.options.libc_installation == null and |
| 3262 | comp.bin_file.options.object_format != .c; | ||
| 3013 | } | 3263 | } |
| 3014 | 3264 | ||
| 3015 | fn wantBuildGLibCFromSource(comp: Compilation) bool { | 3265 | fn wantBuildGLibCFromSource(comp: Compilation) bool { |
| ... | @@ -3031,7 +3281,8 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { | ... | @@ -3031,7 +3281,8 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { |
| 3031 | .Lib => comp.bin_file.options.link_mode == .Dynamic, | 3281 | .Lib => comp.bin_file.options.link_mode == .Dynamic, |
| 3032 | .Exe => true, | 3282 | .Exe => true, |
| 3033 | }; | 3283 | }; |
| 3034 | return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind; | 3284 | return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and |
| 3285 | comp.bin_file.options.object_format != .c; | ||
| 3035 | } | 3286 | } |
| 3036 | 3287 | ||
| 3037 | fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) Allocator.Error!void { | 3288 | fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) Allocator.Error!void { |
| ... | @@ -3082,30 +3333,29 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3082,30 +3333,29 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3082 | 3333 | ||
| 3083 | @setEvalBranchQuota(4000); | 3334 | @setEvalBranchQuota(4000); |
| 3084 | try buffer.writer().print( | 3335 | try buffer.writer().print( |
| 3085 | \\usingnamespace @import("std").builtin; | 3336 | \\const std = @import("std"); |
| 3086 | \\/// Deprecated | ||
| 3087 | \\pub const arch = Target.current.cpu.arch; | ||
| 3088 | \\/// Deprecated | ||
| 3089 | \\pub const endian = Target.current.cpu.arch.endian(); | ||
| 3090 | \\ | ||
| 3091 | \\/// Zig version. When writing code that supports multiple versions of Zig, prefer | 3337 | \\/// Zig version. When writing code that supports multiple versions of Zig, prefer |
| 3092 | \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. | 3338 | \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. |
| 3093 | \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}"); | 3339 | \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable; |
| 3340 | \\/// Temporary until self-hosted is feature complete. | ||
| 3094 | \\pub const zig_is_stage2 = {}; | 3341 | \\pub const zig_is_stage2 = {}; |
| 3342 | \\/// Temporary until self-hosted supports the `cpu.arch` value. | ||
| 3343 | \\pub const stage2_arch: std.Target.Cpu.Arch = .{}; | ||
| 3095 | \\ | 3344 | \\ |
| 3096 | \\pub const output_mode = OutputMode.{}; | 3345 | \\pub const output_mode = std.builtin.OutputMode.{}; |
| 3097 | \\pub const link_mode = LinkMode.{}; | 3346 | \\pub const link_mode = std.builtin.LinkMode.{}; |
| 3098 | \\pub const is_test = {}; | 3347 | \\pub const is_test = {}; |
| 3099 | \\pub const single_threaded = {}; | 3348 | \\pub const single_threaded = {}; |
| 3100 | \\pub const abi = Abi.{}; | 3349 | \\pub const abi = std.Target.Abi.{}; |
| 3101 | \\pub const cpu: Cpu = Cpu{{ | 3350 | \\pub const cpu: std.Target.Cpu = .{{ |
| 3102 | \\ .arch = .{}, | 3351 | \\ .arch = .{}, |
| 3103 | \\ .model = &Target.{}.cpu.{}, | 3352 | \\ .model = &std.Target.{}.cpu.{}, |
| 3104 | \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{ | 3353 | \\ .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{ |
| 3105 | \\ | 3354 | \\ |
| 3106 | , .{ | 3355 | , .{ |
| 3107 | build_options.version, | 3356 | build_options.version, |
| 3108 | !use_stage1, | 3357 | !use_stage1, |
| 3358 | std.zig.fmtId(@tagName(target.cpu.arch)), | ||
| 3109 | std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), | 3359 | std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), |
| 3110 | std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), | 3360 | std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), |
| 3111 | comp.bin_file.options.is_test, | 3361 | comp.bin_file.options.is_test, |
| ... | @@ -3129,7 +3379,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3129,7 +3379,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3129 | try buffer.writer().print( | 3379 | try buffer.writer().print( |
| 3130 | \\ }}), | 3380 | \\ }}), |
| 3131 | \\}}; | 3381 | \\}}; |
| 3132 | \\pub const os = Os{{ | 3382 | \\pub const os = std.Target.Os{{ |
| 3133 | \\ .tag = .{}, | 3383 | \\ .tag = .{}, |
| 3134 | \\ .version_range = .{{ | 3384 | \\ .version_range = .{{ |
| 3135 | , | 3385 | , |
| ... | @@ -3216,8 +3466,13 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3216,8 +3466,13 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3216 | (comp.bin_file.options.skip_linker_dependencies and comp.bin_file.options.parent_compilation_link_libc); | 3466 | (comp.bin_file.options.skip_linker_dependencies and comp.bin_file.options.parent_compilation_link_libc); |
| 3217 | 3467 | ||
| 3218 | try buffer.writer().print( | 3468 | try buffer.writer().print( |
| 3219 | \\pub const object_format = ObjectFormat.{}; | 3469 | \\pub const target = std.Target{{ |
| 3220 | \\pub const mode = Mode.{}; | 3470 | \\ .cpu = cpu, |
| 3471 | \\ .os = os, | ||
| 3472 | \\ .abi = abi, | ||
| 3473 | \\}}; | ||
| 3474 | \\pub const object_format = std.Target.ObjectFormat.{}; | ||
| 3475 | \\pub const mode = std.builtin.Mode.{}; | ||
| 3221 | \\pub const link_libc = {}; | 3476 | \\pub const link_libc = {}; |
| 3222 | \\pub const link_libcpp = {}; | 3477 | \\pub const link_libcpp = {}; |
| 3223 | \\pub const have_error_return_tracing = {}; | 3478 | \\pub const have_error_return_tracing = {}; |
| ... | @@ -3225,7 +3480,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3225,7 +3480,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3225 | \\pub const position_independent_code = {}; | 3480 | \\pub const position_independent_code = {}; |
| 3226 | \\pub const position_independent_executable = {}; | 3481 | \\pub const position_independent_executable = {}; |
| 3227 | \\pub const strip_debug_info = {}; | 3482 | \\pub const strip_debug_info = {}; |
| 3228 | \\pub const code_model = CodeModel.{}; | 3483 | \\pub const code_model = std.builtin.CodeModel.{}; |
| 3229 | \\ | 3484 | \\ |
| 3230 | , .{ | 3485 | , .{ |
| 3231 | std.zig.fmtId(@tagName(comp.bin_file.options.object_format)), | 3486 | std.zig.fmtId(@tagName(comp.bin_file.options.object_format)), |
| ... | @@ -3242,7 +3497,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc | ... | @@ -3242,7 +3497,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc |
| 3242 | 3497 | ||
| 3243 | if (comp.bin_file.options.is_test) { | 3498 | if (comp.bin_file.options.is_test) { |
| 3244 | try buffer.appendSlice( | 3499 | try buffer.appendSlice( |
| 3245 | \\pub var test_functions: []TestFn = undefined; // overwritten later | 3500 | \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later |
| 3246 | \\ | 3501 | \\ |
| 3247 | ); | 3502 | ); |
| 3248 | if (comp.test_evented_io) { | 3503 | if (comp.test_evented_io) { |
| ... | @@ -3316,7 +3571,6 @@ fn buildOutputFromZig( | ... | @@ -3316,7 +3571,6 @@ fn buildOutputFromZig( |
| 3316 | .handle = special_dir, | 3571 | .handle = special_dir, |
| 3317 | }, | 3572 | }, |
| 3318 | .root_src_path = src_basename, | 3573 | .root_src_path = src_basename, |
| 3319 | .namespace_hash = Package.root_namespace_hash, | ||
| 3320 | }; | 3574 | }; |
| 3321 | const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; | 3575 | const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; |
| 3322 | const target = comp.getTarget(); | 3576 | const target = comp.getTarget(); |
| ... | @@ -3445,7 +3699,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node | ... | @@ -3445,7 +3699,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 3445 | man.hash.add(comp.bin_file.options.emit != null); | 3699 | man.hash.add(comp.bin_file.options.emit != null); |
| 3446 | man.hash.add(mod.emit_h != null); | 3700 | man.hash.add(mod.emit_h != null); |
| 3447 | if (mod.emit_h) |emit_h| { | 3701 | if (mod.emit_h) |emit_h| { |
| 3448 | man.hash.addEmitLoc(emit_h); | 3702 | man.hash.addEmitLoc(emit_h.loc); |
| 3449 | } | 3703 | } |
| 3450 | man.hash.addOptionalEmitLoc(comp.emit_asm); | 3704 | man.hash.addOptionalEmitLoc(comp.emit_asm); |
| 3451 | man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); | 3705 | man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); |
| ... | @@ -3564,7 +3818,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node | ... | @@ -3564,7 +3818,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 3564 | if (mod.emit_h != null) { | 3818 | if (mod.emit_h != null) { |
| 3565 | log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); | 3819 | log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); |
| 3566 | } | 3820 | } |
| 3567 | const emit_h_path = try stage1LocPath(arena, mod.emit_h, directory); | 3821 | const emit_h_loc: ?EmitLoc = if (mod.emit_h) |emit_h| emit_h.loc else null; |
| 3822 | const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory); | ||
| 3568 | const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); | 3823 | const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); |
| 3569 | const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); | 3824 | const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); |
| 3570 | const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory); | 3825 | const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory); |
src/Module.zig+2576-2403| ... | @@ -15,13 +15,14 @@ const ast = std.zig.ast; | ... | @@ -15,13 +15,14 @@ const ast = std.zig.ast; |
| 15 | 15 | ||
| 16 | const Module = @This(); | 16 | const Module = @This(); |
| 17 | const Compilation = @import("Compilation.zig"); | 17 | const Compilation = @import("Compilation.zig"); |
| 18 | const Cache = @import("Cache.zig"); | ||
| 18 | const Value = @import("value.zig").Value; | 19 | const Value = @import("value.zig").Value; |
| 19 | const Type = @import("type.zig").Type; | 20 | const Type = @import("type.zig").Type; |
| 20 | const TypedValue = @import("TypedValue.zig"); | 21 | const TypedValue = @import("TypedValue.zig"); |
| 21 | const Package = @import("Package.zig"); | 22 | const Package = @import("Package.zig"); |
| 22 | const link = @import("link.zig"); | 23 | const link = @import("link.zig"); |
| 23 | const ir = @import("ir.zig"); | 24 | const ir = @import("ir.zig"); |
| 24 | const zir = @import("zir.zig"); | 25 | const Zir = @import("Zir.zig"); |
| 25 | const trace = @import("tracy.zig").trace; | 26 | const trace = @import("tracy.zig").trace; |
| 26 | const AstGen = @import("AstGen.zig"); | 27 | const AstGen = @import("AstGen.zig"); |
| 27 | const Sema = @import("Sema.zig"); | 28 | const Sema = @import("Sema.zig"); |
| ... | @@ -35,38 +36,39 @@ comp: *Compilation, | ... | @@ -35,38 +36,39 @@ comp: *Compilation, |
| 35 | zig_cache_artifact_directory: Compilation.Directory, | 36 | zig_cache_artifact_directory: Compilation.Directory, |
| 36 | /// Pointer to externally managed resource. `null` if there is no zig file being compiled. | 37 | /// Pointer to externally managed resource. `null` if there is no zig file being compiled. |
| 37 | root_pkg: *Package, | 38 | root_pkg: *Package, |
| 38 | /// Module owns this resource. | 39 | |
| 39 | root_scope: *Scope.File, | 40 | /// Used by AstGen worker to load and store ZIR cache. |
| 40 | /// It's rare for a decl to be exported, so we save memory by having a sparse map of | 41 | global_zir_cache: Compilation.Directory, |
| 41 | /// Decl pointers to details about them being exported. | 42 | /// Used by AstGen worker to load and store ZIR cache. |
| 42 | /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. | 43 | local_zir_cache: Compilation.Directory, |
| 43 | /// The slice is guaranteed to not be empty. | 44 | /// It's rare for a decl to be exported, so we save memory by having a sparse |
| 45 | /// map of Decl pointers to details about them being exported. | ||
| 46 | /// The Export memory is owned by the `export_owners` table; the slice itself | ||
| 47 | /// is owned by this table. The slice is guaranteed to not be empty. | ||
| 44 | decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{}, | 48 | decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{}, |
| 45 | /// We track which export is associated with the given symbol name for quick | ||
| 46 | /// detection of symbol collisions. | ||
| 47 | symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}, | ||
| 48 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl | 49 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl |
| 49 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that | 50 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that |
| 50 | /// is performing the export of another Decl. | 51 | /// is performing the export of another Decl. |
| 51 | /// This table owns the Export memory. | 52 | /// This table owns the Export memory. |
| 52 | export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{}, | 53 | export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{}, |
| 53 | /// Maps fully qualified namespaced names to the Decl struct for them. | 54 | /// The set of all the files in the Module. We keep track of this in order to iterate |
| 54 | decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{}, | 55 | /// over it and check which source files have been modified on the file system when |
| 56 | /// an update is requested, as well as to cache `@import` results. | ||
| 57 | /// Keys are fully resolved file paths. This table owns the keys and values. | ||
| 58 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, | ||
| 59 | |||
| 55 | /// We optimize memory usage for a compilation with no compile errors by storing the | 60 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 56 | /// error messages and mapping outside of `Decl`. | 61 | /// error messages and mapping outside of `Decl`. |
| 57 | /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. | 62 | /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. |
| 58 | /// Note that a Decl can succeed but the Fn it represents can fail. In this case, | 63 | /// Note that a Decl can succeed but the Fn it represents can fail. In this case, |
| 59 | /// a Decl can have a failed_decls entry but have analysis status of success. | 64 | /// a Decl can have a failed_decls entry but have analysis status of success. |
| 60 | failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, | 65 | failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, |
| 61 | /// When emit_h is non-null, each Decl gets one more compile error slot for | ||
| 62 | /// emit-h failing for that Decl. This table is also how we tell if a Decl has | ||
| 63 | /// failed emit-h or succeeded. | ||
| 64 | emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, | ||
| 65 | /// Keep track of one `@compileLog` callsite per owner Decl. | 66 | /// Keep track of one `@compileLog` callsite per owner Decl. |
| 66 | compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{}, | 67 | /// The value is the AST node index offset from the Decl. |
| 68 | compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, i32) = .{}, | ||
| 67 | /// Using a map here for consistency with the other fields here. | 69 | /// Using a map here for consistency with the other fields here. |
| 68 | /// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator. | 70 | /// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator. |
| 69 | failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{}, | 71 | failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{}, |
| 70 | /// Using a map here for consistency with the other fields here. | 72 | /// Using a map here for consistency with the other fields here. |
| 71 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. | 73 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. |
| 72 | failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, | 74 | failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, |
| ... | @@ -85,17 +87,11 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, | ... | @@ -85,17 +87,11 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, |
| 85 | /// Corresponds with `global_error_set`. | 87 | /// Corresponds with `global_error_set`. |
| 86 | error_name_list: ArrayListUnmanaged([]const u8) = .{}, | 88 | error_name_list: ArrayListUnmanaged([]const u8) = .{}, |
| 87 | 89 | ||
| 88 | /// Keys are fully qualified paths | ||
| 89 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, | ||
| 90 | |||
| 91 | /// Incrementing integer used to compare against the corresponding Decl | 90 | /// Incrementing integer used to compare against the corresponding Decl |
| 92 | /// field to determine whether a Decl's status applies to an ongoing update, or a | 91 | /// field to determine whether a Decl's status applies to an ongoing update, or a |
| 93 | /// previous analysis. | 92 | /// previous analysis. |
| 94 | generation: u32 = 0, | 93 | generation: u32 = 0, |
| 95 | 94 | ||
| 96 | /// When populated it means there was an error opening/reading the root source file. | ||
| 97 | failed_root_src_file: ?anyerror = null, | ||
| 98 | |||
| 99 | stage1_flags: packed struct { | 95 | stage1_flags: packed struct { |
| 100 | have_winmain: bool = false, | 96 | have_winmain: bool = false, |
| 101 | have_wwinmain: bool = false, | 97 | have_wwinmain: bool = false, |
| ... | @@ -106,10 +102,24 @@ stage1_flags: packed struct { | ... | @@ -106,10 +102,24 @@ stage1_flags: packed struct { |
| 106 | reserved: u2 = 0, | 102 | reserved: u2 = 0, |
| 107 | } = .{}, | 103 | } = .{}, |
| 108 | 104 | ||
| 109 | emit_h: ?Compilation.EmitLoc, | 105 | job_queued_update_builtin_zig: bool = true, |
| 110 | 106 | ||
| 111 | compile_log_text: ArrayListUnmanaged(u8) = .{}, | 107 | compile_log_text: ArrayListUnmanaged(u8) = .{}, |
| 112 | 108 | ||
| 109 | emit_h: ?*GlobalEmitH, | ||
| 110 | |||
| 111 | /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled. | ||
| 112 | pub const GlobalEmitH = struct { | ||
| 113 | /// Where to put the output. | ||
| 114 | loc: Compilation.EmitLoc, | ||
| 115 | /// When emit_h is non-null, each Decl gets one more compile error slot for | ||
| 116 | /// emit-h failing for that Decl. This table is also how we tell if a Decl has | ||
| 117 | /// failed emit-h or succeeded. | ||
| 118 | failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, | ||
| 119 | /// Tracks all decls in order to iterate over them and emit .h code for them. | ||
| 120 | decl_table: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, | ||
| 121 | }; | ||
| 122 | |||
| 113 | pub const ErrorInt = u32; | 123 | pub const ErrorInt = u32; |
| 114 | 124 | ||
| 115 | pub const Export = struct { | 125 | pub const Export = struct { |
| ... | @@ -129,6 +139,14 @@ pub const Export = struct { | ... | @@ -129,6 +139,14 @@ pub const Export = struct { |
| 129 | failed_retryable, | 139 | failed_retryable, |
| 130 | complete, | 140 | complete, |
| 131 | }, | 141 | }, |
| 142 | |||
| 143 | pub fn getSrcLoc(exp: Export) SrcLoc { | ||
| 144 | return .{ | ||
| 145 | .file_scope = exp.owner_decl.namespace.file_scope, | ||
| 146 | .parent_decl_node = exp.owner_decl.src_node, | ||
| 147 | .lazy = exp.src, | ||
| 148 | }; | ||
| 149 | } | ||
| 132 | }; | 150 | }; |
| 133 | 151 | ||
| 134 | /// When Module emit_h field is non-null, each Decl is allocated via this struct, so that | 152 | /// When Module emit_h field is non-null, each Decl is allocated via this struct, so that |
| ... | @@ -139,31 +157,43 @@ pub const DeclPlusEmitH = struct { | ... | @@ -139,31 +157,43 @@ pub const DeclPlusEmitH = struct { |
| 139 | }; | 157 | }; |
| 140 | 158 | ||
| 141 | pub const Decl = struct { | 159 | pub const Decl = struct { |
| 142 | /// This name is relative to the containing namespace of the decl. It uses | 160 | /// Allocated with Module's allocator; outlives the ZIR code. |
| 143 | /// null-termination to save bytes, since there can be a lot of decls in a | ||
| 144 | /// compilation. The null byte is not allowed in symbol names, because | ||
| 145 | /// executable file formats use null-terminated strings for symbol names. | ||
| 146 | /// All Decls have names, even values that are not bound to a zig namespace. | ||
| 147 | /// This is necessary for mapping them to an address in the output file. | ||
| 148 | /// Memory owned by this decl, using Module's allocator. | ||
| 149 | name: [*:0]const u8, | 161 | name: [*:0]const u8, |
| 150 | /// The direct parent container of the Decl. | 162 | /// The most recent Type of the Decl after a successful semantic analysis. |
| 163 | /// Populated when `has_tv`. | ||
| 164 | ty: Type, | ||
| 165 | /// The most recent Value of the Decl after a successful semantic analysis. | ||
| 166 | /// Populated when `has_tv`. | ||
| 167 | val: Value, | ||
| 168 | /// Populated when `has_tv`. | ||
| 169 | align_val: Value, | ||
| 170 | /// Populated when `has_tv`. | ||
| 171 | linksection_val: Value, | ||
| 172 | /// The memory for ty, val, align_val, linksection_val. | ||
| 173 | /// If this is `null` then there is no memory management needed. | ||
| 174 | value_arena: ?*std.heap.ArenaAllocator.State = null, | ||
| 175 | /// The direct parent namespace of the Decl. | ||
| 151 | /// Reference to externally owned memory. | 176 | /// Reference to externally owned memory. |
| 152 | container: *Scope.Container, | 177 | /// In the case of the Decl corresponding to a file, this is |
| 178 | /// the namespace of the struct, since there is no parent. | ||
| 179 | namespace: *Scope.Namespace, | ||
| 153 | 180 | ||
| 154 | /// An integer that can be checked against the corresponding incrementing | 181 | /// An integer that can be checked against the corresponding incrementing |
| 155 | /// generation field of Module. This is used to determine whether `complete` status | 182 | /// generation field of Module. This is used to determine whether `complete` status |
| 156 | /// represents pre- or post- re-analysis. | 183 | /// represents pre- or post- re-analysis. |
| 157 | generation: u32, | 184 | generation: u32, |
| 158 | /// The AST Node index or ZIR Inst index that contains this declaration. | 185 | /// The AST node index of this declaration. |
| 159 | /// Must be recomputed when the corresponding source file is modified. | 186 | /// Must be recomputed when the corresponding source file is modified. |
| 160 | src_node: ast.Node.Index, | 187 | src_node: ast.Node.Index, |
| 188 | /// Line number corresponding to `src_node`. Stored separately so that source files | ||
| 189 | /// do not need to be loaded into memory in order to compute debug line numbers. | ||
| 190 | src_line: u32, | ||
| 191 | /// Index to ZIR `extra` array to the entry in the parent's decl structure | ||
| 192 | /// (the part that says "for every decls_len"). The first item at this index is | ||
| 193 | /// the contents hash, followed by line, name, etc. | ||
| 194 | /// For anonymous decls and also the root Decl for a File, this is 0. | ||
| 195 | zir_decl_index: Zir.Inst.Index, | ||
| 161 | 196 | ||
| 162 | /// The most recent value of the Decl after a successful semantic analysis. | ||
| 163 | typed_value: union(enum) { | ||
| 164 | never_succeeded: void, | ||
| 165 | most_recent: TypedValue.Managed, | ||
| 166 | }, | ||
| 167 | /// Represents the "shallow" analysis status. For example, for decls that are functions, | 197 | /// Represents the "shallow" analysis status. For example, for decls that are functions, |
| 168 | /// the function type is analyzed with this set to `in_progress`, however, the semantic | 198 | /// the function type is analyzed with this set to `in_progress`, however, the semantic |
| 169 | /// analysis of the function body is performed with this value set to `success`. Functions | 199 | /// analysis of the function body is performed with this value set to `success`. Functions |
| ... | @@ -172,8 +202,12 @@ pub const Decl = struct { | ... | @@ -172,8 +202,12 @@ pub const Decl = struct { |
| 172 | /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore | 202 | /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore |
| 173 | /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced. | 203 | /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced. |
| 174 | unreferenced, | 204 | unreferenced, |
| 175 | /// Semantic analysis for this Decl is running right now. This state detects dependency loops. | 205 | /// Semantic analysis for this Decl is running right now. |
| 206 | /// This state detects dependency loops. | ||
| 176 | in_progress, | 207 | in_progress, |
| 208 | /// The file corresponding to this Decl had a parse error or ZIR error. | ||
| 209 | /// There will be a corresponding ErrorMsg in Module.failed_files. | ||
| 210 | file_failure, | ||
| 177 | /// This Decl might be OK but it depends on another one which did not successfully complete | 211 | /// This Decl might be OK but it depends on another one which did not successfully complete |
| 178 | /// semantic analysis. | 212 | /// semantic analysis. |
| 179 | dependency_failure, | 213 | dependency_failure, |
| ... | @@ -198,11 +232,23 @@ pub const Decl = struct { | ... | @@ -198,11 +232,23 @@ pub const Decl = struct { |
| 198 | /// to require re-analysis. | 232 | /// to require re-analysis. |
| 199 | outdated, | 233 | outdated, |
| 200 | }, | 234 | }, |
| 235 | /// Whether `typed_value`, `align_val`, and `linksection_val` are populated. | ||
| 236 | has_tv: bool, | ||
| 237 | /// If `true` it means the `Decl` is the resource owner of the type/value associated | ||
| 238 | /// with it. That means when `Decl` is destroyed, the cleanup code should additionally | ||
| 239 | /// check if the value owns a `Namespace`, and destroy that too. | ||
| 240 | owns_tv: bool, | ||
| 201 | /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared | 241 | /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared |
| 202 | /// when removed. | 242 | /// when removed. |
| 203 | deletion_flag: bool, | 243 | deletion_flag: bool, |
| 204 | /// Whether the corresponding AST decl has a `pub` keyword. | 244 | /// Whether the corresponding AST decl has a `pub` keyword. |
| 205 | is_pub: bool, | 245 | is_pub: bool, |
| 246 | /// Whether the corresponding AST decl has a `export` keyword. | ||
| 247 | is_exported: bool, | ||
| 248 | /// Whether the ZIR code provides an align instruction. | ||
| 249 | has_align: bool, | ||
| 250 | /// Whether the ZIR code provides a linksection instruction. | ||
| 251 | has_linksection: bool, | ||
| 206 | 252 | ||
| 207 | /// Represents the position of the code in the output file. | 253 | /// Represents the position of the code in the output file. |
| 208 | /// This is populated regardless of semantic analysis and code generation. | 254 | /// This is populated regardless of semantic analysis and code generation. |
| ... | @@ -215,8 +261,6 @@ pub const Decl = struct { | ... | @@ -215,8 +261,6 @@ pub const Decl = struct { |
| 215 | /// to save on memory usage. | 261 | /// to save on memory usage. |
| 216 | fn_link: link.File.LinkFn, | 262 | fn_link: link.File.LinkFn, |
| 217 | 263 | ||
| 218 | contents_hash: std.zig.SrcHash, | ||
| 219 | |||
| 220 | /// The shallow set of other decls whose typed_value could possibly change if this Decl's | 264 | /// The shallow set of other decls whose typed_value could possibly change if this Decl's |
| 221 | /// typed_value is modified. | 265 | /// typed_value is modified. |
| 222 | dependants: DepsTable = .{}, | 266 | dependants: DepsTable = .{}, |
| ... | @@ -226,20 +270,34 @@ pub const Decl = struct { | ... | @@ -226,20 +270,34 @@ pub const Decl = struct { |
| 226 | 270 | ||
| 227 | /// The reason this is not `std.AutoArrayHashMapUnmanaged` is a workaround for | 271 | /// The reason this is not `std.AutoArrayHashMapUnmanaged` is a workaround for |
| 228 | /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself` | 272 | /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself` |
| 229 | pub const DepsTable = std.ArrayHashMapUnmanaged(*Decl, void, std.array_hash_map.getAutoHashFn(*Decl), std.array_hash_map.getAutoEqlFn(*Decl), false); | 273 | pub const DepsTable = std.ArrayHashMapUnmanaged( |
| 274 | *Decl, | ||
| 275 | void, | ||
| 276 | std.array_hash_map.getAutoHashFn(*Decl), | ||
| 277 | std.array_hash_map.getAutoEqlFn(*Decl), | ||
| 278 | false, | ||
| 279 | ); | ||
| 280 | |||
| 281 | pub fn clearName(decl: *Decl, gpa: *Allocator) void { | ||
| 282 | gpa.free(mem.spanZ(decl.name)); | ||
| 283 | decl.name = undefined; | ||
| 284 | } | ||
| 230 | 285 | ||
| 231 | pub fn destroy(decl: *Decl, module: *Module) void { | 286 | pub fn destroy(decl: *Decl, module: *Module) void { |
| 232 | const gpa = module.gpa; | 287 | const gpa = module.gpa; |
| 233 | gpa.free(mem.spanZ(decl.name)); | 288 | log.debug("destroy {*} ({s})", .{ decl, decl.name }); |
| 234 | if (decl.typedValueManaged()) |tvm| { | 289 | if (decl.deletion_flag) { |
| 235 | if (tvm.typed_value.val.castTag(.function)) |payload| { | 290 | module.deletion_set.swapRemoveAssertDiscard(decl); |
| 236 | const func = payload.data; | 291 | } |
| 237 | func.deinit(gpa); | 292 | if (decl.has_tv) { |
| 293 | if (decl.getInnerNamespace()) |namespace| { | ||
| 294 | namespace.destroyDecls(module); | ||
| 238 | } | 295 | } |
| 239 | tvm.deinit(gpa); | 296 | decl.clearValues(gpa); |
| 240 | } | 297 | } |
| 241 | decl.dependants.deinit(gpa); | 298 | decl.dependants.deinit(gpa); |
| 242 | decl.dependencies.deinit(gpa); | 299 | decl.dependencies.deinit(gpa); |
| 300 | decl.clearName(gpa); | ||
| 243 | if (module.emit_h != null) { | 301 | if (module.emit_h != null) { |
| 244 | const decl_plus_emit_h = @fieldParentPtr(DeclPlusEmitH, "decl", decl); | 302 | const decl_plus_emit_h = @fieldParentPtr(DeclPlusEmitH, "decl", decl); |
| 245 | decl_plus_emit_h.emit_h.fwd_decl.deinit(gpa); | 303 | decl_plus_emit_h.emit_h.fwd_decl.deinit(gpa); |
| ... | @@ -249,6 +307,87 @@ pub const Decl = struct { | ... | @@ -249,6 +307,87 @@ pub const Decl = struct { |
| 249 | } | 307 | } |
| 250 | } | 308 | } |
| 251 | 309 | ||
| 310 | pub fn clearValues(decl: *Decl, gpa: *Allocator) void { | ||
| 311 | if (decl.getFunction()) |func| { | ||
| 312 | func.deinit(gpa); | ||
| 313 | gpa.destroy(func); | ||
| 314 | } | ||
| 315 | if (decl.getVariable()) |variable| { | ||
| 316 | gpa.destroy(variable); | ||
| 317 | } | ||
| 318 | if (decl.value_arena) |arena_state| { | ||
| 319 | arena_state.promote(gpa).deinit(); | ||
| 320 | decl.value_arena = null; | ||
| 321 | decl.has_tv = false; | ||
| 322 | decl.owns_tv = false; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { | ||
| 327 | assert(decl.value_arena == null); | ||
| 328 | const arena_state = try arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 329 | arena_state.* = arena.state; | ||
| 330 | decl.value_arena = arena_state; | ||
| 331 | } | ||
| 332 | |||
| 333 | /// This name is relative to the containing namespace of the decl. | ||
| 334 | /// The memory is owned by the containing File ZIR. | ||
| 335 | pub fn getName(decl: Decl) ?[:0]const u8 { | ||
| 336 | const zir = decl.namespace.file_scope.zir; | ||
| 337 | return decl.getNameZir(zir); | ||
| 338 | } | ||
| 339 | |||
| 340 | pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 { | ||
| 341 | assert(decl.zir_decl_index != 0); | ||
| 342 | const name_index = zir.extra[decl.zir_decl_index + 5]; | ||
| 343 | if (name_index <= 1) return null; | ||
| 344 | return zir.nullTerminatedString(name_index); | ||
| 345 | } | ||
| 346 | |||
| 347 | pub fn contentsHash(decl: Decl) std.zig.SrcHash { | ||
| 348 | const zir = decl.namespace.file_scope.zir; | ||
| 349 | return decl.contentsHashZir(zir); | ||
| 350 | } | ||
| 351 | |||
| 352 | pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash { | ||
| 353 | assert(decl.zir_decl_index != 0); | ||
| 354 | const hash_u32s = zir.extra[decl.zir_decl_index..][0..4]; | ||
| 355 | const contents_hash = @bitCast(std.zig.SrcHash, hash_u32s.*); | ||
| 356 | return contents_hash; | ||
| 357 | } | ||
| 358 | |||
| 359 | pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index { | ||
| 360 | assert(decl.zir_decl_index != 0); | ||
| 361 | const zir = decl.namespace.file_scope.zir; | ||
| 362 | return zir.extra[decl.zir_decl_index + 6]; | ||
| 363 | } | ||
| 364 | |||
| 365 | pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref { | ||
| 366 | if (!decl.has_align) return .none; | ||
| 367 | assert(decl.zir_decl_index != 0); | ||
| 368 | const zir = decl.namespace.file_scope.zir; | ||
| 369 | return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]); | ||
| 370 | } | ||
| 371 | |||
| 372 | pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { | ||
| 373 | if (!decl.has_linksection) return .none; | ||
| 374 | assert(decl.zir_decl_index != 0); | ||
| 375 | const zir = decl.namespace.file_scope.zir; | ||
| 376 | const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align); | ||
| 377 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 378 | } | ||
| 379 | |||
| 380 | /// Returns true if and only if the Decl is the top level struct associated with a File. | ||
| 381 | pub fn isRoot(decl: *const Decl) bool { | ||
| 382 | if (decl.namespace.parent != null) | ||
| 383 | return false; | ||
| 384 | return decl == decl.namespace.ty.getOwnerDecl(); | ||
| 385 | } | ||
| 386 | |||
| 387 | pub fn relativeToLine(decl: Decl, offset: u32) u32 { | ||
| 388 | return decl.src_line + offset; | ||
| 389 | } | ||
| 390 | |||
| 252 | pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index { | 391 | pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index { |
| 253 | return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node)); | 392 | return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node)); |
| 254 | } | 393 | } |
| ... | @@ -265,30 +404,31 @@ pub const Decl = struct { | ... | @@ -265,30 +404,31 @@ pub const Decl = struct { |
| 265 | return .{ .node_offset = decl.nodeIndexToRelative(node_index) }; | 404 | return .{ .node_offset = decl.nodeIndexToRelative(node_index) }; |
| 266 | } | 405 | } |
| 267 | 406 | ||
| 268 | pub fn srcLoc(decl: *Decl) SrcLoc { | 407 | pub fn srcLoc(decl: Decl) SrcLoc { |
| 408 | return decl.nodeOffsetSrcLoc(0); | ||
| 409 | } | ||
| 410 | |||
| 411 | pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32) SrcLoc { | ||
| 269 | return .{ | 412 | return .{ |
| 270 | .container = .{ .decl = decl }, | 413 | .file_scope = decl.getFileScope(), |
| 271 | .lazy = .{ .node_offset = 0 }, | 414 | .parent_decl_node = decl.src_node, |
| 415 | .lazy = .{ .node_offset = node_offset }, | ||
| 272 | }; | 416 | }; |
| 273 | } | 417 | } |
| 274 | 418 | ||
| 275 | pub fn srcToken(decl: Decl) u32 { | 419 | pub fn srcToken(decl: Decl) ast.TokenIndex { |
| 276 | const tree = &decl.container.file_scope.tree; | 420 | const tree = &decl.namespace.file_scope.tree; |
| 277 | return tree.firstToken(decl.src_node); | 421 | return tree.firstToken(decl.src_node); |
| 278 | } | 422 | } |
| 279 | 423 | ||
| 280 | pub fn srcByteOffset(decl: Decl) u32 { | 424 | pub fn srcByteOffset(decl: Decl) u32 { |
| 281 | const tree = &decl.container.file_scope.tree; | 425 | const tree = &decl.namespace.file_scope.tree; |
| 282 | return tree.tokens.items(.start)[decl.srcToken()]; | 426 | return tree.tokens.items(.start)[decl.srcToken()]; |
| 283 | } | 427 | } |
| 284 | 428 | ||
| 285 | pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash { | ||
| 286 | return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name)); | ||
| 287 | } | ||
| 288 | |||
| 289 | pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void { | 429 | pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void { |
| 290 | const unqualified_name = mem.spanZ(decl.name); | 430 | const unqualified_name = mem.spanZ(decl.name); |
| 291 | return decl.container.renderFullyQualifiedName(unqualified_name, writer); | 431 | return decl.namespace.renderFullyQualifiedName(unqualified_name, writer); |
| 292 | } | 432 | } |
| 293 | 433 | ||
| 294 | pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 { | 434 | pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 { |
| ... | @@ -298,15 +438,92 @@ pub const Decl = struct { | ... | @@ -298,15 +438,92 @@ pub const Decl = struct { |
| 298 | return buffer.toOwnedSlice(); | 438 | return buffer.toOwnedSlice(); |
| 299 | } | 439 | } |
| 300 | 440 | ||
| 301 | pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue { | 441 | pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { |
| 302 | const tvm = decl.typedValueManaged() orelse return error.AnalysisFail; | 442 | if (!decl.has_tv) return error.AnalysisFail; |
| 303 | return tvm.typed_value; | 443 | return TypedValue{ |
| 444 | .ty = decl.ty, | ||
| 445 | .val = decl.val, | ||
| 446 | }; | ||
| 304 | } | 447 | } |
| 305 | 448 | ||
| 306 | pub fn value(decl: *Decl) error{AnalysisFail}!Value { | 449 | pub fn value(decl: *Decl) error{AnalysisFail}!Value { |
| 307 | return (try decl.typedValue()).val; | 450 | return (try decl.typedValue()).val; |
| 308 | } | 451 | } |
| 309 | 452 | ||
| 453 | pub fn isFunction(decl: *Decl) !bool { | ||
| 454 | const tv = try decl.typedValue(); | ||
| 455 | return tv.ty.zigTypeTag() == .Fn; | ||
| 456 | } | ||
| 457 | |||
| 458 | /// If the Decl has a value and it is a struct, return it, | ||
| 459 | /// otherwise null. | ||
| 460 | pub fn getStruct(decl: *Decl) ?*Struct { | ||
| 461 | if (!decl.owns_tv) return null; | ||
| 462 | const ty = (decl.val.castTag(.ty) orelse return null).data; | ||
| 463 | const struct_obj = (ty.castTag(.@"struct") orelse return null).data; | ||
| 464 | assert(struct_obj.owner_decl == decl); | ||
| 465 | return struct_obj; | ||
| 466 | } | ||
| 467 | |||
| 468 | /// If the Decl has a value and it is a union, return it, | ||
| 469 | /// otherwise null. | ||
| 470 | pub fn getUnion(decl: *Decl) ?*Union { | ||
| 471 | if (!decl.owns_tv) return null; | ||
| 472 | const ty = (decl.val.castTag(.ty) orelse return null).data; | ||
| 473 | const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; | ||
| 474 | assert(union_obj.owner_decl == decl); | ||
| 475 | return union_obj; | ||
| 476 | } | ||
| 477 | |||
| 478 | /// If the Decl has a value and it is a function, return it, | ||
| 479 | /// otherwise null. | ||
| 480 | pub fn getFunction(decl: *Decl) ?*Fn { | ||
| 481 | if (!decl.owns_tv) return null; | ||
| 482 | const func = (decl.val.castTag(.function) orelse return null).data; | ||
| 483 | assert(func.owner_decl == decl); | ||
| 484 | return func; | ||
| 485 | } | ||
| 486 | |||
| 487 | pub fn getVariable(decl: *Decl) ?*Var { | ||
| 488 | if (!decl.owns_tv) return null; | ||
| 489 | const variable = (decl.val.castTag(.variable) orelse return null).data; | ||
| 490 | assert(variable.owner_decl == decl); | ||
| 491 | return variable; | ||
| 492 | } | ||
| 493 | |||
| 494 | /// Gets the namespace that this Decl creates by being a struct, union, | ||
| 495 | /// enum, or opaque. | ||
| 496 | /// Only returns it if the Decl is the owner. | ||
| 497 | pub fn getInnerNamespace(decl: *Decl) ?*Scope.Namespace { | ||
| 498 | if (!decl.owns_tv) return null; | ||
| 499 | const ty = (decl.val.castTag(.ty) orelse return null).data; | ||
| 500 | switch (ty.tag()) { | ||
| 501 | .@"struct" => { | ||
| 502 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 503 | assert(struct_obj.owner_decl == decl); | ||
| 504 | return &struct_obj.namespace; | ||
| 505 | }, | ||
| 506 | .enum_full => { | ||
| 507 | const enum_obj = ty.castTag(.enum_full).?.data; | ||
| 508 | assert(enum_obj.owner_decl == decl); | ||
| 509 | return &enum_obj.namespace; | ||
| 510 | }, | ||
| 511 | .empty_struct => { | ||
| 512 | return ty.castTag(.empty_struct).?.data; | ||
| 513 | }, | ||
| 514 | .@"opaque" => { | ||
| 515 | @panic("TODO opaque types"); | ||
| 516 | }, | ||
| 517 | .@"union", .union_tagged => { | ||
| 518 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 519 | assert(union_obj.owner_decl == decl); | ||
| 520 | return &union_obj.namespace; | ||
| 521 | }, | ||
| 522 | |||
| 523 | else => return null, | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 310 | pub fn dump(decl: *Decl) void { | 527 | pub fn dump(decl: *Decl) void { |
| 311 | const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); | 528 | const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); |
| 312 | std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ | 529 | std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ |
| ... | @@ -316,21 +533,14 @@ pub const Decl = struct { | ... | @@ -316,21 +533,14 @@ pub const Decl = struct { |
| 316 | mem.spanZ(decl.name), | 533 | mem.spanZ(decl.name), |
| 317 | @tagName(decl.analysis), | 534 | @tagName(decl.analysis), |
| 318 | }); | 535 | }); |
| 319 | if (decl.typedValueManaged()) |tvm| { | 536 | if (decl.has_tv) { |
| 320 | std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val }); | 537 | std.debug.print(" ty={} val={}", .{ decl.ty, decl.val }); |
| 321 | } | 538 | } |
| 322 | std.debug.print("\n", .{}); | 539 | std.debug.print("\n", .{}); |
| 323 | } | 540 | } |
| 324 | 541 | ||
| 325 | pub fn typedValueManaged(decl: *Decl) ?*TypedValue.Managed { | ||
| 326 | switch (decl.typed_value) { | ||
| 327 | .most_recent => |*x| return x, | ||
| 328 | .never_succeeded => return null, | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | pub fn getFileScope(decl: Decl) *Scope.File { | 542 | pub fn getFileScope(decl: Decl) *Scope.File { |
| 333 | return decl.container.file_scope; | 543 | return decl.namespace.file_scope; |
| 334 | } | 544 | } |
| 335 | 545 | ||
| 336 | pub fn getEmitH(decl: *Decl, module: *Module) *EmitH { | 546 | pub fn getEmitH(decl: *Decl, module: *Module) *EmitH { |
| ... | @@ -355,17 +565,20 @@ pub const EmitH = struct { | ... | @@ -355,17 +565,20 @@ pub const EmitH = struct { |
| 355 | 565 | ||
| 356 | /// Represents the data that an explicit error set syntax provides. | 566 | /// Represents the data that an explicit error set syntax provides. |
| 357 | pub const ErrorSet = struct { | 567 | pub const ErrorSet = struct { |
| 568 | /// The Decl that corresponds to the error set itself. | ||
| 358 | owner_decl: *Decl, | 569 | owner_decl: *Decl, |
| 359 | /// Offset from Decl node index, points to the error set AST node. | 570 | /// Offset from Decl node index, points to the error set AST node. |
| 360 | node_offset: i32, | 571 | node_offset: i32, |
| 361 | names_len: u32, | 572 | names_len: u32, |
| 362 | /// The string bytes are stored in the owner Decl arena. | 573 | /// The string bytes are stored in the owner Decl arena. |
| 363 | /// They are in the same order they appear in the AST. | 574 | /// They are in the same order they appear in the AST. |
| 575 | /// The length is given by `names_len`. | ||
| 364 | names_ptr: [*]const []const u8, | 576 | names_ptr: [*]const []const u8, |
| 365 | 577 | ||
| 366 | pub fn srcLoc(self: ErrorSet) SrcLoc { | 578 | pub fn srcLoc(self: ErrorSet) SrcLoc { |
| 367 | return .{ | 579 | return .{ |
| 368 | .container = .{ .decl = self.owner_decl }, | 580 | .file_scope = self.owner_decl.getFileScope(), |
| 581 | .parent_decl_node = self.owner_decl.src_node, | ||
| 369 | .lazy = .{ .node_offset = self.node_offset }, | 582 | .lazy = .{ .node_offset = self.node_offset }, |
| 370 | }; | 583 | }; |
| 371 | } | 584 | } |
| ... | @@ -373,20 +586,36 @@ pub const ErrorSet = struct { | ... | @@ -373,20 +586,36 @@ pub const ErrorSet = struct { |
| 373 | 586 | ||
| 374 | /// Represents the data that a struct declaration provides. | 587 | /// Represents the data that a struct declaration provides. |
| 375 | pub const Struct = struct { | 588 | pub const Struct = struct { |
| 589 | /// The Decl that corresponds to the struct itself. | ||
| 376 | owner_decl: *Decl, | 590 | owner_decl: *Decl, |
| 377 | /// Set of field names in declaration order. | 591 | /// Set of field names in declaration order. |
| 378 | fields: std.StringArrayHashMapUnmanaged(Field), | 592 | fields: std.StringArrayHashMapUnmanaged(Field), |
| 379 | /// Represents the declarations inside this struct. | 593 | /// Represents the declarations inside this struct. |
| 380 | container: Scope.Container, | 594 | namespace: Scope.Namespace, |
| 381 | |||
| 382 | /// Offset from `owner_decl`, points to the struct AST node. | 595 | /// Offset from `owner_decl`, points to the struct AST node. |
| 383 | node_offset: i32, | 596 | node_offset: i32, |
| 597 | /// Index of the struct_decl ZIR instruction. | ||
| 598 | zir_index: Zir.Inst.Index, | ||
| 599 | |||
| 600 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 601 | status: enum { | ||
| 602 | none, | ||
| 603 | field_types_wip, | ||
| 604 | have_field_types, | ||
| 605 | layout_wip, | ||
| 606 | have_layout, | ||
| 607 | }, | ||
| 384 | 608 | ||
| 385 | pub const Field = struct { | 609 | pub const Field = struct { |
| 610 | /// Uses `noreturn` to indicate `anytype`. | ||
| 611 | /// undefined until `status` is `have_field_types` or `have_layout`. | ||
| 386 | ty: Type, | 612 | ty: Type, |
| 387 | abi_align: Value, | 613 | abi_align: Value, |
| 388 | /// Uses `unreachable_value` to indicate no default. | 614 | /// Uses `unreachable_value` to indicate no default. |
| 389 | default_val: Value, | 615 | default_val: Value, |
| 616 | /// undefined until `status` is `have_layout`. | ||
| 617 | offset: u32, | ||
| 618 | is_comptime: bool, | ||
| 390 | }; | 619 | }; |
| 391 | 620 | ||
| 392 | pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 { | 621 | pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 { |
| ... | @@ -395,10 +624,23 @@ pub const Struct = struct { | ... | @@ -395,10 +624,23 @@ pub const Struct = struct { |
| 395 | 624 | ||
| 396 | pub fn srcLoc(s: Struct) SrcLoc { | 625 | pub fn srcLoc(s: Struct) SrcLoc { |
| 397 | return .{ | 626 | return .{ |
| 398 | .container = .{ .decl = s.owner_decl }, | 627 | .file_scope = s.owner_decl.getFileScope(), |
| 628 | .parent_decl_node = s.owner_decl.src_node, | ||
| 399 | .lazy = .{ .node_offset = s.node_offset }, | 629 | .lazy = .{ .node_offset = s.node_offset }, |
| 400 | }; | 630 | }; |
| 401 | } | 631 | } |
| 632 | |||
| 633 | pub fn haveFieldTypes(s: Struct) bool { | ||
| 634 | return switch (s.status) { | ||
| 635 | .none, | ||
| 636 | .field_types_wip, | ||
| 637 | => false, | ||
| 638 | .have_field_types, | ||
| 639 | .layout_wip, | ||
| 640 | .have_layout, | ||
| 641 | => true, | ||
| 642 | }; | ||
| 643 | } | ||
| 402 | }; | 644 | }; |
| 403 | 645 | ||
| 404 | /// Represents the data that an enum declaration provides, when the fields | 646 | /// Represents the data that an enum declaration provides, when the fields |
| ... | @@ -406,6 +648,7 @@ pub const Struct = struct { | ... | @@ -406,6 +648,7 @@ pub const Struct = struct { |
| 406 | /// is inferred to be the smallest power of two unsigned int that fits | 648 | /// is inferred to be the smallest power of two unsigned int that fits |
| 407 | /// the number of fields. | 649 | /// the number of fields. |
| 408 | pub const EnumSimple = struct { | 650 | pub const EnumSimple = struct { |
| 651 | /// The Decl that corresponds to the enum itself. | ||
| 409 | owner_decl: *Decl, | 652 | owner_decl: *Decl, |
| 410 | /// Set of field names in declaration order. | 653 | /// Set of field names in declaration order. |
| 411 | fields: std.StringArrayHashMapUnmanaged(void), | 654 | fields: std.StringArrayHashMapUnmanaged(void), |
| ... | @@ -414,7 +657,8 @@ pub const EnumSimple = struct { | ... | @@ -414,7 +657,8 @@ pub const EnumSimple = struct { |
| 414 | 657 | ||
| 415 | pub fn srcLoc(self: EnumSimple) SrcLoc { | 658 | pub fn srcLoc(self: EnumSimple) SrcLoc { |
| 416 | return .{ | 659 | return .{ |
| 417 | .container = .{ .decl = self.owner_decl }, | 660 | .file_scope = self.owner_decl.getFileScope(), |
| 661 | .parent_decl_node = self.owner_decl.src_node, | ||
| 418 | .lazy = .{ .node_offset = self.node_offset }, | 662 | .lazy = .{ .node_offset = self.node_offset }, |
| 419 | }; | 663 | }; |
| 420 | } | 664 | } |
| ... | @@ -423,6 +667,7 @@ pub const EnumSimple = struct { | ... | @@ -423,6 +667,7 @@ pub const EnumSimple = struct { |
| 423 | /// Represents the data that an enum declaration provides, when there is | 667 | /// Represents the data that an enum declaration provides, when there is |
| 424 | /// at least one tag value explicitly specified, or at least one declaration. | 668 | /// at least one tag value explicitly specified, or at least one declaration. |
| 425 | pub const EnumFull = struct { | 669 | pub const EnumFull = struct { |
| 670 | /// The Decl that corresponds to the enum itself. | ||
| 426 | owner_decl: *Decl, | 671 | owner_decl: *Decl, |
| 427 | /// An integer type which is used for the numerical value of the enum. | 672 | /// An integer type which is used for the numerical value of the enum. |
| 428 | /// Whether zig chooses this type or the user specifies it, it is stored here. | 673 | /// Whether zig chooses this type or the user specifies it, it is stored here. |
| ... | @@ -434,7 +679,7 @@ pub const EnumFull = struct { | ... | @@ -434,7 +679,7 @@ pub const EnumFull = struct { |
| 434 | /// If this hash map is empty, it means the enum tags are auto-numbered. | 679 | /// If this hash map is empty, it means the enum tags are auto-numbered. |
| 435 | values: ValueMap, | 680 | values: ValueMap, |
| 436 | /// Represents the declarations inside this struct. | 681 | /// Represents the declarations inside this struct. |
| 437 | container: Scope.Container, | 682 | namespace: Scope.Namespace, |
| 438 | /// Offset from `owner_decl`, points to the enum decl AST node. | 683 | /// Offset from `owner_decl`, points to the enum decl AST node. |
| 439 | node_offset: i32, | 684 | node_offset: i32, |
| 440 | 685 | ||
| ... | @@ -442,7 +687,54 @@ pub const EnumFull = struct { | ... | @@ -442,7 +687,54 @@ pub const EnumFull = struct { |
| 442 | 687 | ||
| 443 | pub fn srcLoc(self: EnumFull) SrcLoc { | 688 | pub fn srcLoc(self: EnumFull) SrcLoc { |
| 444 | return .{ | 689 | return .{ |
| 445 | .container = .{ .decl = self.owner_decl }, | 690 | .file_scope = self.owner_decl.getFileScope(), |
| 691 | .parent_decl_node = self.owner_decl.src_node, | ||
| 692 | .lazy = .{ .node_offset = self.node_offset }, | ||
| 693 | }; | ||
| 694 | } | ||
| 695 | }; | ||
| 696 | |||
| 697 | pub const Union = struct { | ||
| 698 | /// The Decl that corresponds to the union itself. | ||
| 699 | owner_decl: *Decl, | ||
| 700 | /// An enum type which is used for the tag of the union. | ||
| 701 | /// This type is created even for untagged unions, even when the memory | ||
| 702 | /// layout does not store the tag. | ||
| 703 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 704 | /// This will be set to the null type until status is `have_field_types`. | ||
| 705 | tag_ty: Type, | ||
| 706 | /// Set of field names in declaration order. | ||
| 707 | fields: std.StringArrayHashMapUnmanaged(Field), | ||
| 708 | /// Represents the declarations inside this union. | ||
| 709 | namespace: Scope.Namespace, | ||
| 710 | /// Offset from `owner_decl`, points to the union decl AST node. | ||
| 711 | node_offset: i32, | ||
| 712 | /// Index of the union_decl ZIR instruction. | ||
| 713 | zir_index: Zir.Inst.Index, | ||
| 714 | |||
| 715 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 716 | status: enum { | ||
| 717 | none, | ||
| 718 | field_types_wip, | ||
| 719 | have_field_types, | ||
| 720 | layout_wip, | ||
| 721 | have_layout, | ||
| 722 | }, | ||
| 723 | |||
| 724 | pub const Field = struct { | ||
| 725 | /// undefined until `status` is `have_field_types` or `have_layout`. | ||
| 726 | ty: Type, | ||
| 727 | abi_align: Value, | ||
| 728 | }; | ||
| 729 | |||
| 730 | pub fn getFullyQualifiedName(s: *Union, gpa: *Allocator) ![]u8 { | ||
| 731 | return s.owner_decl.getFullyQualifiedName(gpa); | ||
| 732 | } | ||
| 733 | |||
| 734 | pub fn srcLoc(self: Union) SrcLoc { | ||
| 735 | return .{ | ||
| 736 | .file_scope = self.owner_decl.getFileScope(), | ||
| 737 | .parent_decl_node = self.owner_decl.src_node, | ||
| 446 | .lazy = .{ .node_offset = self.node_offset }, | 738 | .lazy = .{ .node_offset = self.node_offset }, |
| 447 | }; | 739 | }; |
| 448 | } | 740 | } |
| ... | @@ -452,19 +744,23 @@ pub const EnumFull = struct { | ... | @@ -452,19 +744,23 @@ pub const EnumFull = struct { |
| 452 | /// Extern functions do not have this data structure; they are represented by | 744 | /// Extern functions do not have this data structure; they are represented by |
| 453 | /// the `Decl` only, with a `Value` tag of `extern_fn`. | 745 | /// the `Decl` only, with a `Value` tag of `extern_fn`. |
| 454 | pub const Fn = struct { | 746 | pub const Fn = struct { |
| 747 | /// The Decl that corresponds to the function itself. | ||
| 455 | owner_decl: *Decl, | 748 | owner_decl: *Decl, |
| 456 | /// Contains un-analyzed ZIR instructions generated from Zig source AST. | ||
| 457 | /// Even after we finish analysis, the ZIR is kept in memory, so that | ||
| 458 | /// comptime and inline function calls can happen. | ||
| 459 | /// Parameter names are stored here so that they may be referenced for debug info, | ||
| 460 | /// without having source code bytes loaded into memory. | ||
| 461 | /// The number of parameters is determined by referring to the type. | ||
| 462 | /// The first N elements of `extra` are indexes into `string_bytes` to | ||
| 463 | /// a null-terminated string. | ||
| 464 | /// This memory is managed with gpa, must be freed when the function is freed. | ||
| 465 | zir: zir.Code, | ||
| 466 | /// undefined unless analysis state is `success`. | 749 | /// undefined unless analysis state is `success`. |
| 467 | body: ir.Body, | 750 | body: ir.Body, |
| 751 | /// The ZIR instruction that is a function instruction. Use this to find | ||
| 752 | /// the body. We store this rather than the body directly so that when ZIR | ||
| 753 | /// is regenerated on update(), we can map this to the new corresponding | ||
| 754 | /// ZIR instruction. | ||
| 755 | zir_body_inst: Zir.Inst.Index, | ||
| 756 | |||
| 757 | /// Relative to owner Decl. | ||
| 758 | lbrace_line: u32, | ||
| 759 | /// Relative to owner Decl. | ||
| 760 | rbrace_line: u32, | ||
| 761 | lbrace_column: u16, | ||
| 762 | rbrace_column: u16, | ||
| 763 | |||
| 468 | state: Analysis, | 764 | state: Analysis, |
| 469 | 765 | ||
| 470 | pub const Analysis = enum { | 766 | pub const Analysis = enum { |
| ... | @@ -486,9 +782,7 @@ pub const Fn = struct { | ... | @@ -486,9 +782,7 @@ pub const Fn = struct { |
| 486 | ir.dumpFn(mod, func); | 782 | ir.dumpFn(mod, func); |
| 487 | } | 783 | } |
| 488 | 784 | ||
| 489 | pub fn deinit(func: *Fn, gpa: *Allocator) void { | 785 | pub fn deinit(func: *Fn, gpa: *Allocator) void {} |
| 490 | func.zir.deinit(gpa); | ||
| 491 | } | ||
| 492 | }; | 786 | }; |
| 493 | 787 | ||
| 494 | pub const Var = struct { | 788 | pub const Var = struct { |
| ... | @@ -504,8 +798,6 @@ pub const Var = struct { | ... | @@ -504,8 +798,6 @@ pub const Var = struct { |
| 504 | pub const Scope = struct { | 798 | pub const Scope = struct { |
| 505 | tag: Tag, | 799 | tag: Tag, |
| 506 | 800 | ||
| 507 | pub const NameHash = [16]u8; | ||
| 508 | |||
| 509 | pub fn cast(base: *Scope, comptime T: type) ?*T { | 801 | pub fn cast(base: *Scope, comptime T: type) ?*T { |
| 510 | if (base.tag != T.base_tag) | 802 | if (base.tag != T.base_tag) |
| 511 | return null; | 803 | return null; |
| ... | @@ -513,120 +805,38 @@ pub const Scope = struct { | ... | @@ -513,120 +805,38 @@ pub const Scope = struct { |
| 513 | return @fieldParentPtr(T, "base", base); | 805 | return @fieldParentPtr(T, "base", base); |
| 514 | } | 806 | } |
| 515 | 807 | ||
| 516 | /// Returns the arena Allocator associated with the Decl of the Scope. | ||
| 517 | pub fn arena(scope: *Scope) *Allocator { | ||
| 518 | switch (scope.tag) { | ||
| 519 | .block => return scope.cast(Block).?.sema.arena, | ||
| 520 | .gen_zir => return scope.cast(GenZir).?.astgen.arena, | ||
| 521 | .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena, | ||
| 522 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena, | ||
| 523 | .file => unreachable, | ||
| 524 | .container => unreachable, | ||
| 525 | .decl_ref => unreachable, | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | pub fn ownerDecl(scope: *Scope) ?*Decl { | 808 | pub fn ownerDecl(scope: *Scope) ?*Decl { |
| 530 | return switch (scope.tag) { | 809 | return switch (scope.tag) { |
| 531 | .block => scope.cast(Block).?.sema.owner_decl, | 810 | .block => scope.cast(Block).?.sema.owner_decl, |
| 532 | .gen_zir => scope.cast(GenZir).?.astgen.decl, | ||
| 533 | .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl, | ||
| 534 | .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl, | ||
| 535 | .file => null, | 811 | .file => null, |
| 536 | .container => null, | 812 | .namespace => null, |
| 537 | .decl_ref => scope.cast(DeclRef).?.decl, | ||
| 538 | }; | 813 | }; |
| 539 | } | 814 | } |
| 540 | 815 | ||
| 541 | pub fn srcDecl(scope: *Scope) ?*Decl { | 816 | pub fn srcDecl(scope: *Scope) ?*Decl { |
| 542 | return switch (scope.tag) { | 817 | return switch (scope.tag) { |
| 543 | .block => scope.cast(Block).?.src_decl, | 818 | .block => scope.cast(Block).?.src_decl, |
| 544 | .gen_zir => scope.cast(GenZir).?.astgen.decl, | ||
| 545 | .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl, | ||
| 546 | .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl, | ||
| 547 | .file => null, | 819 | .file => null, |
| 548 | .container => null, | 820 | .namespace => scope.cast(Namespace).?.getDecl(), |
| 549 | .decl_ref => scope.cast(DeclRef).?.decl, | ||
| 550 | }; | 821 | }; |
| 551 | } | 822 | } |
| 552 | 823 | ||
| 553 | /// Asserts the scope has a parent which is a Container and returns it. | 824 | /// Asserts the scope has a parent which is a Namespace and returns it. |
| 554 | pub fn namespace(scope: *Scope) *Container { | 825 | pub fn namespace(scope: *Scope) *Namespace { |
| 555 | switch (scope.tag) { | 826 | switch (scope.tag) { |
| 556 | .block => return scope.cast(Block).?.sema.owner_decl.container, | 827 | .block => return scope.cast(Block).?.sema.owner_decl.namespace, |
| 557 | .gen_zir => return scope.cast(GenZir).?.astgen.decl.container, | 828 | .file => return scope.cast(File).?.root_decl.?.namespace, |
| 558 | .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.container, | 829 | .namespace => return scope.cast(Namespace).?, |
| 559 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.container, | ||
| 560 | .file => return &scope.cast(File).?.root_container, | ||
| 561 | .container => return scope.cast(Container).?, | ||
| 562 | .decl_ref => return scope.cast(DeclRef).?.decl.container, | ||
| 563 | } | 830 | } |
| 564 | } | 831 | } |
| 565 | 832 | ||
| 566 | /// Must generate unique bytes with no collisions with other decls. | 833 | /// Asserts the scope has a parent which is a Namespace or File and |
| 567 | /// The point of hashing here is only to limit the number of bytes of | ||
| 568 | /// the unique identifier to a fixed size (16 bytes). | ||
| 569 | pub fn fullyQualifiedNameHash(scope: *Scope, name: []const u8) NameHash { | ||
| 570 | switch (scope.tag) { | ||
| 571 | .block => unreachable, | ||
| 572 | .gen_zir => unreachable, | ||
| 573 | .local_val => unreachable, | ||
| 574 | .local_ptr => unreachable, | ||
| 575 | .file => unreachable, | ||
| 576 | .container => return scope.cast(Container).?.fullyQualifiedNameHash(name), | ||
| 577 | .decl_ref => unreachable, | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | /// Asserts the scope is a child of a File and has an AST tree and returns the tree. | ||
| 582 | pub fn tree(scope: *Scope) *const ast.Tree { | ||
| 583 | switch (scope.tag) { | ||
| 584 | .file => return &scope.cast(File).?.tree, | ||
| 585 | .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree, | ||
| 586 | .gen_zir => return scope.cast(GenZir).?.tree(), | ||
| 587 | .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.container.file_scope.tree, | ||
| 588 | .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.container.file_scope.tree, | ||
| 589 | .container => return &scope.cast(Container).?.file_scope.tree, | ||
| 590 | .decl_ref => return &scope.cast(DeclRef).?.decl.container.file_scope.tree, | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 594 | /// Asserts the scope is a child of a `GenZir` and returns it. | ||
| 595 | pub fn getGenZir(scope: *Scope) *GenZir { | ||
| 596 | return switch (scope.tag) { | ||
| 597 | .block => unreachable, | ||
| 598 | .gen_zir => scope.cast(GenZir).?, | ||
| 599 | .local_val => return scope.cast(LocalVal).?.gen_zir, | ||
| 600 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir, | ||
| 601 | .file => unreachable, | ||
| 602 | .container => unreachable, | ||
| 603 | .decl_ref => unreachable, | ||
| 604 | }; | ||
| 605 | } | ||
| 606 | |||
| 607 | /// Asserts the scope has a parent which is a Container or File and | ||
| 608 | /// returns the sub_file_path field. | 834 | /// returns the sub_file_path field. |
| 609 | pub fn subFilePath(base: *Scope) []const u8 { | 835 | pub fn subFilePath(base: *Scope) []const u8 { |
| 610 | switch (base.tag) { | 836 | switch (base.tag) { |
| 611 | .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path, | 837 | .namespace => return @fieldParentPtr(Namespace, "base", base).file_scope.sub_file_path, |
| 612 | .file => return @fieldParentPtr(File, "base", base).sub_file_path, | 838 | .file => return @fieldParentPtr(File, "base", base).sub_file_path, |
| 613 | .block => unreachable, | 839 | .block => unreachable, |
| 614 | .gen_zir => unreachable, | ||
| 615 | .local_val => unreachable, | ||
| 616 | .local_ptr => unreachable, | ||
| 617 | .decl_ref => unreachable, | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 { | ||
| 622 | switch (base.tag) { | ||
| 623 | .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module), | ||
| 624 | .file => return @fieldParentPtr(File, "base", base).getSource(module), | ||
| 625 | .gen_zir => unreachable, | ||
| 626 | .local_val => unreachable, | ||
| 627 | .local_ptr => unreachable, | ||
| 628 | .block => unreachable, | ||
| 629 | .decl_ref => unreachable, | ||
| 630 | } | 840 | } |
| 631 | } | 841 | } |
| 632 | 842 | ||
| ... | @@ -635,70 +845,120 @@ pub const Scope = struct { | ... | @@ -635,70 +845,120 @@ pub const Scope = struct { |
| 635 | var cur = base; | 845 | var cur = base; |
| 636 | while (true) { | 846 | while (true) { |
| 637 | cur = switch (cur.tag) { | 847 | cur = switch (cur.tag) { |
| 638 | .container => return @fieldParentPtr(Container, "base", cur).file_scope, | 848 | .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope, |
| 639 | .file => return @fieldParentPtr(File, "base", cur), | 849 | .file => return @fieldParentPtr(File, "base", cur), |
| 640 | .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent, | 850 | .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope, |
| 641 | .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, | ||
| 642 | .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent, | ||
| 643 | .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope, | ||
| 644 | .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.container.file_scope, | ||
| 645 | }; | 851 | }; |
| 646 | } | 852 | } |
| 647 | } | 853 | } |
| 648 | 854 | ||
| 649 | fn name_hash_hash(x: NameHash) u32 { | ||
| 650 | return @truncate(u32, @bitCast(u128, x)); | ||
| 651 | } | ||
| 652 | |||
| 653 | fn name_hash_eql(a: NameHash, b: NameHash) bool { | ||
| 654 | return @bitCast(u128, a) == @bitCast(u128, b); | ||
| 655 | } | ||
| 656 | |||
| 657 | pub const Tag = enum { | 855 | pub const Tag = enum { |
| 658 | /// .zig source code. | 856 | /// .zig source code. |
| 659 | file, | 857 | file, |
| 660 | /// struct, enum or union, every .file contains one of these. | 858 | /// Namespace owned by structs, enums, unions, and opaques for decls. |
| 661 | container, | 859 | namespace, |
| 662 | block, | 860 | block, |
| 663 | gen_zir, | ||
| 664 | local_val, | ||
| 665 | local_ptr, | ||
| 666 | /// Used for simple error reporting. Only contains a reference to a | ||
| 667 | /// `Decl` for use with `srcDecl` and `ownerDecl`. | ||
| 668 | /// Has no parents or children. | ||
| 669 | decl_ref, | ||
| 670 | }; | 861 | }; |
| 671 | 862 | ||
| 672 | pub const Container = struct { | 863 | /// The container that structs, enums, unions, and opaques have. |
| 673 | pub const base_tag: Tag = .container; | 864 | pub const Namespace = struct { |
| 865 | pub const base_tag: Tag = .namespace; | ||
| 674 | base: Scope = Scope{ .tag = base_tag }, | 866 | base: Scope = Scope{ .tag = base_tag }, |
| 675 | 867 | ||
| 868 | parent: ?*Namespace, | ||
| 676 | file_scope: *Scope.File, | 869 | file_scope: *Scope.File, |
| 677 | parent_name_hash: NameHash, | 870 | /// Will be a struct, enum, union, or opaque. |
| 678 | |||
| 679 | /// Direct children of the file. | ||
| 680 | decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, | ||
| 681 | ty: Type, | 871 | ty: Type, |
| 872 | /// Direct children of the namespace. Used during an update to detect | ||
| 873 | /// which decls have been added/removed from source. | ||
| 874 | /// Declaration order is preserved via entry order. | ||
| 875 | /// Key memory is owned by `decl.name`. | ||
| 876 | /// TODO save memory with https://github.com/ziglang/zig/issues/8619. | ||
| 877 | /// Anonymous decls are not stored here; they are kept in `anon_decls` instead. | ||
| 878 | decls: std.StringArrayHashMapUnmanaged(*Decl) = .{}, | ||
| 879 | |||
| 880 | anon_decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, | ||
| 881 | |||
| 882 | pub fn deinit(ns: *Namespace, mod: *Module) void { | ||
| 883 | ns.destroyDecls(mod); | ||
| 884 | ns.* = undefined; | ||
| 885 | } | ||
| 886 | |||
| 887 | pub fn destroyDecls(ns: *Namespace, mod: *Module) void { | ||
| 888 | const gpa = mod.gpa; | ||
| 889 | |||
| 890 | log.debug("destroyDecls {*}", .{ns}); | ||
| 891 | |||
| 892 | var decls = ns.decls; | ||
| 893 | ns.decls = .{}; | ||
| 682 | 894 | ||
| 683 | pub fn deinit(cont: *Container, gpa: *Allocator) void { | 895 | var anon_decls = ns.anon_decls; |
| 684 | cont.decls.deinit(gpa); | 896 | ns.anon_decls = .{}; |
| 685 | // TODO either Container of File should have an arena for sub_file_path and ty | 897 | |
| 686 | gpa.destroy(cont.ty.castTag(.empty_struct).?); | 898 | for (decls.items()) |entry| { |
| 687 | gpa.free(cont.file_scope.sub_file_path); | 899 | entry.value.destroy(mod); |
| 688 | cont.* = undefined; | 900 | } |
| 901 | decls.deinit(gpa); | ||
| 902 | |||
| 903 | for (anon_decls.items()) |entry| { | ||
| 904 | entry.key.destroy(mod); | ||
| 905 | } | ||
| 906 | anon_decls.deinit(gpa); | ||
| 689 | } | 907 | } |
| 690 | 908 | ||
| 691 | pub fn removeDecl(cont: *Container, child: *Decl) void { | 909 | pub fn deleteAllDecls( |
| 692 | _ = cont.decls.swapRemove(child); | 910 | ns: *Namespace, |
| 911 | mod: *Module, | ||
| 912 | outdated_decls: ?*std.AutoArrayHashMap(*Decl, void), | ||
| 913 | ) !void { | ||
| 914 | const gpa = mod.gpa; | ||
| 915 | |||
| 916 | log.debug("deleteAllDecls {*}", .{ns}); | ||
| 917 | |||
| 918 | var decls = ns.decls; | ||
| 919 | ns.decls = .{}; | ||
| 920 | |||
| 921 | var anon_decls = ns.anon_decls; | ||
| 922 | ns.anon_decls = .{}; | ||
| 923 | |||
| 924 | // TODO rework this code to not panic on OOM. | ||
| 925 | // (might want to coordinate with the clearDecl function) | ||
| 926 | |||
| 927 | for (decls.items()) |entry| { | ||
| 928 | const child_decl = entry.value; | ||
| 929 | mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); | ||
| 930 | child_decl.destroy(mod); | ||
| 931 | } | ||
| 932 | decls.deinit(gpa); | ||
| 933 | |||
| 934 | for (anon_decls.items()) |entry| { | ||
| 935 | const child_decl = entry.key; | ||
| 936 | mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); | ||
| 937 | child_decl.destroy(mod); | ||
| 938 | } | ||
| 939 | anon_decls.deinit(gpa); | ||
| 693 | } | 940 | } |
| 694 | 941 | ||
| 695 | pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash { | 942 | // This renders e.g. "std.fs.Dir.OpenOptions" |
| 696 | return std.zig.hashName(cont.parent_name_hash, ".", name); | 943 | pub fn renderFullyQualifiedName( |
| 944 | ns: Namespace, | ||
| 945 | name: []const u8, | ||
| 946 | writer: anytype, | ||
| 947 | ) @TypeOf(writer).Error!void { | ||
| 948 | if (ns.parent) |parent| { | ||
| 949 | const decl = ns.getDecl(); | ||
| 950 | try parent.renderFullyQualifiedName(mem.spanZ(decl.name), writer); | ||
| 951 | } else { | ||
| 952 | try ns.file_scope.renderFullyQualifiedName(writer); | ||
| 953 | } | ||
| 954 | if (name.len != 0) { | ||
| 955 | try writer.writeAll("."); | ||
| 956 | try writer.writeAll(name); | ||
| 957 | } | ||
| 697 | } | 958 | } |
| 698 | 959 | ||
| 699 | pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void { | 960 | pub fn getDecl(ns: Namespace) *Decl { |
| 700 | // TODO this should render e.g. "std.fs.Dir.OpenOptions" | 961 | return ns.ty.getOwnerDecl(); |
| 701 | return writer.writeAll(name); | ||
| 702 | } | 962 | } |
| 703 | }; | 963 | }; |
| 704 | 964 | ||
| ... | @@ -707,85 +967,172 @@ pub const Scope = struct { | ... | @@ -707,85 +967,172 @@ pub const Scope = struct { |
| 707 | base: Scope = Scope{ .tag = base_tag }, | 967 | base: Scope = Scope{ .tag = base_tag }, |
| 708 | status: enum { | 968 | status: enum { |
| 709 | never_loaded, | 969 | never_loaded, |
| 710 | unloaded_success, | 970 | retryable_failure, |
| 711 | unloaded_parse_failure, | 971 | parse_failure, |
| 712 | loaded_success, | 972 | astgen_failure, |
| 973 | success_zir, | ||
| 713 | }, | 974 | }, |
| 714 | 975 | source_loaded: bool, | |
| 976 | tree_loaded: bool, | ||
| 977 | zir_loaded: bool, | ||
| 715 | /// Relative to the owning package's root_src_dir. | 978 | /// Relative to the owning package's root_src_dir. |
| 716 | /// Reference to external memory, not owned by File. | 979 | /// Memory is stored in gpa, owned by File. |
| 717 | sub_file_path: []const u8, | 980 | sub_file_path: []const u8, |
| 718 | source: union(enum) { | 981 | /// Whether this is populated depends on `source_loaded`. |
| 719 | unloaded: void, | 982 | source: [:0]const u8, |
| 720 | bytes: [:0]const u8, | 983 | /// Whether this is populated depends on `status`. |
| 721 | }, | 984 | stat_size: u64, |
| 722 | /// Whether this is populated or not depends on `status`. | 985 | /// Whether this is populated depends on `status`. |
| 986 | stat_inode: std.fs.File.INode, | ||
| 987 | /// Whether this is populated depends on `status`. | ||
| 988 | stat_mtime: i128, | ||
| 989 | /// Whether this is populated or not depends on `tree_loaded`. | ||
| 723 | tree: ast.Tree, | 990 | tree: ast.Tree, |
| 991 | /// Whether this is populated or not depends on `zir_loaded`. | ||
| 992 | zir: Zir, | ||
| 724 | /// Package that this file is a part of, managed externally. | 993 | /// Package that this file is a part of, managed externally. |
| 725 | pkg: *Package, | 994 | pkg: *Package, |
| 726 | 995 | /// The Decl of the struct that represents this File. | |
| 727 | root_container: Container, | 996 | root_decl: ?*Decl, |
| 997 | |||
| 998 | /// Used by change detection algorithm, after astgen, contains the | ||
| 999 | /// set of decls that existed in the previous ZIR but not in the new one. | ||
| 1000 | deleted_decls: std.ArrayListUnmanaged(*Decl) = .{}, | ||
| 1001 | /// Used by change detection algorithm, after astgen, contains the | ||
| 1002 | /// set of decls that existed both in the previous ZIR and in the new one, | ||
| 1003 | /// but their source code has been modified. | ||
| 1004 | outdated_decls: std.ArrayListUnmanaged(*Decl) = .{}, | ||
| 1005 | |||
| 1006 | /// The most recent successful ZIR for this file, with no errors. | ||
| 1007 | /// This is only populated when a previously successful ZIR | ||
| 1008 | /// newly introduces compile errors during an update. When ZIR is | ||
| 1009 | /// successful, this field is unloaded. | ||
| 1010 | prev_zir: ?*Zir = null, | ||
| 728 | 1011 | ||
| 729 | pub fn unload(file: *File, gpa: *Allocator) void { | 1012 | pub fn unload(file: *File, gpa: *Allocator) void { |
| 730 | switch (file.status) { | 1013 | file.unloadTree(gpa); |
| 731 | .unloaded_parse_failure, | 1014 | file.unloadSource(gpa); |
| 732 | .never_loaded, | 1015 | file.unloadZir(gpa); |
| 733 | .unloaded_success, | 1016 | } |
| 734 | => { | ||
| 735 | file.status = .unloaded_success; | ||
| 736 | }, | ||
| 737 | 1017 | ||
| 738 | .loaded_success => { | 1018 | pub fn unloadTree(file: *File, gpa: *Allocator) void { |
| 739 | file.tree.deinit(gpa); | 1019 | if (file.tree_loaded) { |
| 740 | file.status = .unloaded_success; | 1020 | file.tree_loaded = false; |
| 741 | }, | 1021 | file.tree.deinit(gpa); |
| 742 | } | 1022 | } |
| 743 | switch (file.source) { | 1023 | } |
| 744 | .bytes => |bytes| { | 1024 | |
| 745 | gpa.free(bytes); | 1025 | pub fn unloadSource(file: *File, gpa: *Allocator) void { |
| 746 | file.source = .{ .unloaded = {} }; | 1026 | if (file.source_loaded) { |
| 747 | }, | 1027 | file.source_loaded = false; |
| 748 | .unloaded => {}, | 1028 | gpa.free(file.source); |
| 749 | } | 1029 | } |
| 750 | } | 1030 | } |
| 751 | 1031 | ||
| 752 | pub fn deinit(file: *File, gpa: *Allocator) void { | 1032 | pub fn unloadZir(file: *File, gpa: *Allocator) void { |
| 753 | file.root_container.deinit(gpa); | 1033 | if (file.zir_loaded) { |
| 1034 | file.zir_loaded = false; | ||
| 1035 | file.zir.deinit(gpa); | ||
| 1036 | } | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | pub fn deinit(file: *File, mod: *Module) void { | ||
| 1040 | const gpa = mod.gpa; | ||
| 1041 | log.debug("deinit File {s}", .{file.sub_file_path}); | ||
| 1042 | file.deleted_decls.deinit(gpa); | ||
| 1043 | file.outdated_decls.deinit(gpa); | ||
| 1044 | if (file.root_decl) |root_decl| { | ||
| 1045 | root_decl.destroy(mod); | ||
| 1046 | } | ||
| 1047 | gpa.free(file.sub_file_path); | ||
| 754 | file.unload(gpa); | 1048 | file.unload(gpa); |
| 1049 | if (file.prev_zir) |prev_zir| { | ||
| 1050 | prev_zir.deinit(gpa); | ||
| 1051 | gpa.destroy(prev_zir); | ||
| 1052 | } | ||
| 755 | file.* = undefined; | 1053 | file.* = undefined; |
| 756 | } | 1054 | } |
| 757 | 1055 | ||
| 758 | pub fn destroy(file: *File, gpa: *Allocator) void { | 1056 | pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 { |
| 759 | file.deinit(gpa); | 1057 | if (file.source_loaded) return file.source; |
| 1058 | |||
| 1059 | const root_dir_path = file.pkg.root_src_directory.path orelse "."; | ||
| 1060 | log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{ | ||
| 1061 | root_dir_path, file.sub_file_path, | ||
| 1062 | }); | ||
| 1063 | |||
| 1064 | // Keep track of inode, file size, mtime, hash so we can detect which files | ||
| 1065 | // have been modified when an incremental update is requested. | ||
| 1066 | var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); | ||
| 1067 | defer f.close(); | ||
| 1068 | |||
| 1069 | const stat = try f.stat(); | ||
| 1070 | |||
| 1071 | if (stat.size > std.math.maxInt(u32)) | ||
| 1072 | return error.FileTooBig; | ||
| 1073 | |||
| 1074 | const source = try gpa.allocSentinel(u8, stat.size, 0); | ||
| 1075 | defer if (!file.source_loaded) gpa.free(source); | ||
| 1076 | const amt = try f.readAll(source); | ||
| 1077 | if (amt != stat.size) | ||
| 1078 | return error.UnexpectedEndOfFile; | ||
| 1079 | |||
| 1080 | // Here we do not modify stat fields because this function is the one | ||
| 1081 | // used for error reporting. We need to keep the stat fields stale so that | ||
| 1082 | // astGenFile can know to regenerate ZIR. | ||
| 1083 | |||
| 1084 | file.source = source; | ||
| 1085 | file.source_loaded = true; | ||
| 1086 | return source; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | pub fn getTree(file: *File, gpa: *Allocator) !*const ast.Tree { | ||
| 1090 | if (file.tree_loaded) return &file.tree; | ||
| 1091 | |||
| 1092 | const source = try file.getSource(gpa); | ||
| 1093 | file.tree = try std.zig.parse(gpa, source); | ||
| 1094 | file.tree_loaded = true; | ||
| 1095 | return &file.tree; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | pub fn destroy(file: *File, mod: *Module) void { | ||
| 1099 | const gpa = mod.gpa; | ||
| 1100 | file.deinit(mod); | ||
| 760 | gpa.destroy(file); | 1101 | gpa.destroy(file); |
| 761 | } | 1102 | } |
| 762 | 1103 | ||
| 1104 | pub fn renderFullyQualifiedName(file: File, writer: anytype) !void { | ||
| 1105 | // Convert all the slashes into dots and truncate the extension. | ||
| 1106 | const ext = std.fs.path.extension(file.sub_file_path); | ||
| 1107 | const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; | ||
| 1108 | for (noext) |byte| switch (byte) { | ||
| 1109 | '/', '\\' => try writer.writeByte('.'), | ||
| 1110 | else => try writer.writeByte(byte), | ||
| 1111 | }; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 { | ||
| 1115 | var buf = std.ArrayList(u8).init(gpa); | ||
| 1116 | defer buf.deinit(); | ||
| 1117 | try file.renderFullyQualifiedName(buf.writer()); | ||
| 1118 | return buf.toOwnedSliceSentinel(0); | ||
| 1119 | } | ||
| 1120 | |||
| 763 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { | 1121 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { |
| 764 | const loc = std.zig.findLineColumn(file.source.bytes, src); | 1122 | const loc = std.zig.findLineColumn(file.source.bytes, src); |
| 765 | std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); | 1123 | std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); |
| 766 | } | 1124 | } |
| 767 | 1125 | ||
| 768 | pub fn getSource(file: *File, module: *Module) ![:0]const u8 { | 1126 | pub fn okToReportErrors(file: File) bool { |
| 769 | switch (file.source) { | 1127 | return switch (file.status) { |
| 770 | .unloaded => { | 1128 | .parse_failure, .astgen_failure => false, |
| 771 | const source = try file.pkg.root_src_directory.handle.readFileAllocOptions( | 1129 | else => true, |
| 772 | module.gpa, | 1130 | }; |
| 773 | file.sub_file_path, | ||
| 774 | std.math.maxInt(u32), | ||
| 775 | null, | ||
| 776 | 1, | ||
| 777 | 0, | ||
| 778 | ); | ||
| 779 | file.source = .{ .bytes = source }; | ||
| 780 | return source; | ||
| 781 | }, | ||
| 782 | .bytes => |bytes| return bytes, | ||
| 783 | } | ||
| 784 | } | 1131 | } |
| 785 | }; | 1132 | }; |
| 786 | 1133 | ||
| 787 | /// This is the context needed to semantically analyze ZIR instructions and | 1134 | /// This is the context needed to semantically analyze ZIR instructions and |
| 788 | /// produce TZIR instructions. | 1135 | /// produce AIR instructions. |
| 789 | /// This is a temporary structure stored on the stack; references to it are valid only | 1136 | /// This is a temporary structure stored on the stack; references to it are valid only |
| 790 | /// during semantic analysis of the block. | 1137 | /// during semantic analysis of the block. |
| 791 | pub const Block = struct { | 1138 | pub const Block = struct { |
| ... | @@ -800,20 +1147,20 @@ pub const Scope = struct { | ... | @@ -800,20 +1147,20 @@ pub const Scope = struct { |
| 800 | /// for the one that will be the same for all Block instances. | 1147 | /// for the one that will be the same for all Block instances. |
| 801 | src_decl: *Decl, | 1148 | src_decl: *Decl, |
| 802 | instructions: ArrayListUnmanaged(*ir.Inst), | 1149 | instructions: ArrayListUnmanaged(*ir.Inst), |
| 803 | label: ?Label = null, | 1150 | label: ?*Label = null, |
| 804 | inlining: ?*Inlining, | 1151 | inlining: ?*Inlining, |
| 805 | is_comptime: bool, | 1152 | is_comptime: bool, |
| 806 | 1153 | ||
| 807 | /// This `Block` maps a block ZIR instruction to the corresponding | 1154 | /// This `Block` maps a block ZIR instruction to the corresponding |
| 808 | /// TZIR instruction for break instruction analysis. | 1155 | /// AIR instruction for break instruction analysis. |
| 809 | pub const Label = struct { | 1156 | pub const Label = struct { |
| 810 | zir_block: zir.Inst.Index, | 1157 | zir_block: Zir.Inst.Index, |
| 811 | merges: Merges, | 1158 | merges: Merges, |
| 812 | }; | 1159 | }; |
| 813 | 1160 | ||
| 814 | /// This `Block` indicates that an inline function call is happening | 1161 | /// This `Block` indicates that an inline function call is happening |
| 815 | /// and return instructions should be analyzed as a break instruction | 1162 | /// and return instructions should be analyzed as a break instruction |
| 816 | /// to this TZIR block instruction. | 1163 | /// to this AIR block instruction. |
| 817 | /// It is shared among all the blocks in an inline or comptime called | 1164 | /// It is shared among all the blocks in an inline or comptime called |
| 818 | /// function. | 1165 | /// function. |
| 819 | pub const Inlining = struct { | 1166 | pub const Inlining = struct { |
| ... | @@ -833,7 +1180,7 @@ pub const Scope = struct { | ... | @@ -833,7 +1180,7 @@ pub const Scope = struct { |
| 833 | 1180 | ||
| 834 | /// For debugging purposes. | 1181 | /// For debugging purposes. |
| 835 | pub fn dump(block: *Block, mod: Module) void { | 1182 | pub fn dump(block: *Block, mod: Module) void { |
| 836 | zir.dumpBlock(mod, block); | 1183 | Zir.dumpBlock(mod, block); |
| 837 | } | 1184 | } |
| 838 | 1185 | ||
| 839 | pub fn makeSubBlock(parent: *Block) Block { | 1186 | pub fn makeSubBlock(parent: *Block) Block { |
| ... | @@ -859,7 +1206,7 @@ pub const Scope = struct { | ... | @@ -859,7 +1206,7 @@ pub const Scope = struct { |
| 859 | } | 1206 | } |
| 860 | 1207 | ||
| 861 | pub fn getFileScope(block: *Block) *Scope.File { | 1208 | pub fn getFileScope(block: *Block) *Scope.File { |
| 862 | return block.src_decl.container.file_scope; | 1209 | return block.src_decl.namespace.file_scope; |
| 863 | } | 1210 | } |
| 864 | 1211 | ||
| 865 | pub fn addNoOp( | 1212 | pub fn addNoOp( |
| ... | @@ -1007,7 +1354,7 @@ pub const Scope = struct { | ... | @@ -1007,7 +1354,7 @@ pub const Scope = struct { |
| 1007 | return &inst.base; | 1354 | return &inst.base; |
| 1008 | } | 1355 | } |
| 1009 | 1356 | ||
| 1010 | pub fn addDbgStmt(block: *Scope.Block, src: LazySrcLoc, abs_byte_off: u32) !*ir.Inst { | 1357 | pub fn addDbgStmt(block: *Scope.Block, src: LazySrcLoc, line: u32, column: u32) !*ir.Inst { |
| 1011 | const inst = try block.sema.arena.create(ir.Inst.DbgStmt); | 1358 | const inst = try block.sema.arena.create(ir.Inst.DbgStmt); |
| 1012 | inst.* = .{ | 1359 | inst.* = .{ |
| 1013 | .base = .{ | 1360 | .base = .{ |
| ... | @@ -1015,7 +1362,8 @@ pub const Scope = struct { | ... | @@ -1015,7 +1362,8 @@ pub const Scope = struct { |
| 1015 | .ty = Type.initTag(.void), | 1362 | .ty = Type.initTag(.void), |
| 1016 | .src = src, | 1363 | .src = src, |
| 1017 | }, | 1364 | }, |
| 1018 | .byte_offset = abs_byte_off, | 1365 | .line = line, |
| 1366 | .column = column, | ||
| 1019 | }; | 1367 | }; |
| 1020 | try block.instructions.append(block.sema.gpa, &inst.base); | 1368 | try block.instructions.append(block.sema.gpa, &inst.base); |
| 1021 | return &inst.base; | 1369 | return &inst.base; |
| ... | @@ -1042,695 +1390,127 @@ pub const Scope = struct { | ... | @@ -1042,695 +1390,127 @@ pub const Scope = struct { |
| 1042 | return &inst.base; | 1390 | return &inst.base; |
| 1043 | } | 1391 | } |
| 1044 | }; | 1392 | }; |
| 1393 | }; | ||
| 1045 | 1394 | ||
| 1046 | /// This is a temporary structure; references to it are valid only | 1395 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. |
| 1047 | /// while constructing a `zir.Code`. | 1396 | /// Its memory is managed with the general purpose allocator so that they |
| 1048 | pub const GenZir = struct { | 1397 | /// can be created and destroyed in response to incremental updates. |
| 1049 | pub const base_tag: Tag = .gen_zir; | 1398 | /// In some cases, the Scope.File could have been inferred from where the ErrorMsg |
| 1050 | base: Scope = Scope{ .tag = base_tag }, | 1399 | /// is stored. For example, if it is stored in Module.failed_decls, then the Scope.File |
| 1051 | force_comptime: bool, | 1400 | /// would be determined by the Decl Scope. However, the data structure contains the field |
| 1052 | /// Parents can be: `GenZir`, `File` | 1401 | /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different |
| 1053 | parent: *Scope, | 1402 | /// file than the parent error message. It also simplifies processing of error messages. |
| 1054 | /// All `GenZir` scopes for the same ZIR share this. | 1403 | pub const ErrorMsg = struct { |
| 1055 | astgen: *AstGen, | 1404 | src_loc: SrcLoc, |
| 1056 | /// Keeps track of the list of instructions in this scope only. Indexes | 1405 | msg: []const u8, |
| 1057 | /// to instructions in `astgen`. | 1406 | notes: []ErrorMsg = &.{}, |
| 1058 | instructions: ArrayListUnmanaged(zir.Inst.Index) = .{}, | ||
| 1059 | label: ?Label = null, | ||
| 1060 | break_block: zir.Inst.Index = 0, | ||
| 1061 | continue_block: zir.Inst.Index = 0, | ||
| 1062 | /// Only valid when setBreakResultLoc is called. | ||
| 1063 | break_result_loc: AstGen.ResultLoc = undefined, | ||
| 1064 | /// When a block has a pointer result location, here it is. | ||
| 1065 | rl_ptr: zir.Inst.Ref = .none, | ||
| 1066 | /// When a block has a type result location, here it is. | ||
| 1067 | rl_ty_inst: zir.Inst.Ref = .none, | ||
| 1068 | /// Keeps track of how many branches of a block did not actually | ||
| 1069 | /// consume the result location. astgen uses this to figure out | ||
| 1070 | /// whether to rely on break instructions or writing to the result | ||
| 1071 | /// pointer for the result instruction. | ||
| 1072 | rvalue_rl_count: usize = 0, | ||
| 1073 | /// Keeps track of how many break instructions there are. When astgen is finished | ||
| 1074 | /// with a block, it can check this against rvalue_rl_count to find out whether | ||
| 1075 | /// the break instructions should be downgraded to break_void. | ||
| 1076 | break_count: usize = 0, | ||
| 1077 | /// Tracks `break :foo bar` instructions so they can possibly be elided later if | ||
| 1078 | /// the labeled block ends up not needing a result location pointer. | ||
| 1079 | labeled_breaks: ArrayListUnmanaged(zir.Inst.Index) = .{}, | ||
| 1080 | /// Tracks `store_to_block_ptr` instructions that correspond to break instructions | ||
| 1081 | /// so they can possibly be elided later if the labeled block ends up not needing | ||
| 1082 | /// a result location pointer. | ||
| 1083 | labeled_store_to_block_ptr_list: ArrayListUnmanaged(zir.Inst.Index) = .{}, | ||
| 1084 | 1407 | ||
| 1085 | pub const Label = struct { | 1408 | pub fn create( |
| 1086 | token: ast.TokenIndex, | 1409 | gpa: *Allocator, |
| 1087 | block_inst: zir.Inst.Index, | 1410 | src_loc: SrcLoc, |
| 1088 | used: bool = false, | 1411 | comptime format: []const u8, |
| 1089 | }; | 1412 | args: anytype, |
| 1413 | ) !*ErrorMsg { | ||
| 1414 | const err_msg = try gpa.create(ErrorMsg); | ||
| 1415 | errdefer gpa.destroy(err_msg); | ||
| 1416 | err_msg.* = try init(gpa, src_loc, format, args); | ||
| 1417 | return err_msg; | ||
| 1418 | } | ||
| 1090 | 1419 | ||
| 1091 | /// Only valid to call on the top of the `GenZir` stack. Completes the | 1420 | /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`, |
| 1092 | /// `AstGen` into a `zir.Code`. Leaves the `AstGen` in an | 1421 | /// as well as all notes. |
| 1093 | /// initialized, but empty, state. | 1422 | pub fn destroy(err_msg: *ErrorMsg, gpa: *Allocator) void { |
| 1094 | pub fn finish(gz: *GenZir) !zir.Code { | 1423 | err_msg.deinit(gpa); |
| 1095 | const gpa = gz.astgen.mod.gpa; | 1424 | gpa.destroy(err_msg); |
| 1096 | try gz.setBlockBody(0); | 1425 | } |
| 1097 | return zir.Code{ | ||
| 1098 | .instructions = gz.astgen.instructions.toOwnedSlice(), | ||
| 1099 | .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa), | ||
| 1100 | .extra = gz.astgen.extra.toOwnedSlice(gpa), | ||
| 1101 | }; | ||
| 1102 | } | ||
| 1103 | 1426 | ||
| 1104 | pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc { | 1427 | pub fn init( |
| 1105 | return gz.astgen.decl.tokSrcLoc(token_index); | 1428 | gpa: *Allocator, |
| 1106 | } | 1429 | src_loc: SrcLoc, |
| 1430 | comptime format: []const u8, | ||
| 1431 | args: anytype, | ||
| 1432 | ) !ErrorMsg { | ||
| 1433 | return ErrorMsg{ | ||
| 1434 | .src_loc = src_loc, | ||
| 1435 | .msg = try std.fmt.allocPrint(gpa, format, args), | ||
| 1436 | }; | ||
| 1437 | } | ||
| 1107 | 1438 | ||
| 1108 | pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc { | 1439 | pub fn deinit(err_msg: *ErrorMsg, gpa: *Allocator) void { |
| 1109 | return gz.astgen.decl.nodeSrcLoc(node_index); | 1440 | for (err_msg.notes) |*note| { |
| 1441 | note.deinit(gpa); | ||
| 1110 | } | 1442 | } |
| 1443 | gpa.free(err_msg.notes); | ||
| 1444 | gpa.free(err_msg.msg); | ||
| 1445 | err_msg.* = undefined; | ||
| 1446 | } | ||
| 1447 | }; | ||
| 1111 | 1448 | ||
| 1112 | pub fn tree(gz: *const GenZir) *const ast.Tree { | 1449 | /// Canonical reference to a position within a source file. |
| 1113 | return &gz.astgen.decl.container.file_scope.tree; | 1450 | pub const SrcLoc = struct { |
| 1114 | } | 1451 | file_scope: *Scope.File, |
| 1452 | /// Might be 0 depending on tag of `lazy`. | ||
| 1453 | parent_decl_node: ast.Node.Index, | ||
| 1454 | /// Relative to `parent_decl_node`. | ||
| 1455 | lazy: LazySrcLoc, | ||
| 1115 | 1456 | ||
| 1116 | pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { | 1457 | pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex { |
| 1117 | // Depending on whether the result location is a pointer or value, different | 1458 | const tree = src_loc.file_scope.tree; |
| 1118 | // ZIR needs to be generated. In the former case we rely on storing to the | 1459 | return tree.firstToken(src_loc.parent_decl_node); |
| 1119 | // pointer to communicate the result, and use breakvoid; in the latter case | 1460 | } |
| 1120 | // the block break instructions will have the result values. | ||
| 1121 | // One more complication: when the result location is a pointer, we detect | ||
| 1122 | // the scenario where the result location is not consumed. In this case | ||
| 1123 | // we emit ZIR for the block break instructions to have the result values, | ||
| 1124 | // and then rvalue() on that to pass the value to the result location. | ||
| 1125 | switch (parent_rl) { | ||
| 1126 | .ty => |ty_inst| { | ||
| 1127 | gz.rl_ty_inst = ty_inst; | ||
| 1128 | gz.break_result_loc = parent_rl; | ||
| 1129 | }, | ||
| 1130 | .none_or_ref => { | ||
| 1131 | gz.break_result_loc = .ref; | ||
| 1132 | }, | ||
| 1133 | .discard, .none, .ptr, .ref => { | ||
| 1134 | gz.break_result_loc = parent_rl; | ||
| 1135 | }, | ||
| 1136 | 1461 | ||
| 1137 | .inferred_ptr => |ptr| { | 1462 | pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex { |
| 1138 | gz.rl_ptr = ptr; | 1463 | return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); |
| 1139 | gz.break_result_loc = .{ .block_ptr = gz }; | 1464 | } |
| 1140 | }, | ||
| 1141 | 1465 | ||
| 1142 | .block_ptr => |parent_block_scope| { | 1466 | pub fn byteOffset(src_loc: SrcLoc, gpa: *Allocator) !u32 { |
| 1143 | gz.rl_ty_inst = parent_block_scope.rl_ty_inst; | ||
| 1144 | gz.rl_ptr = parent_block_scope.rl_ptr; | ||
| 1145 | gz.break_result_loc = .{ .block_ptr = gz }; | ||
| 1146 | }, | ||
| 1147 | } | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | pub fn setBoolBrBody(gz: GenZir, inst: zir.Inst.Index) !void { | ||
| 1151 | const gpa = gz.astgen.mod.gpa; | ||
| 1152 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1153 | @typeInfo(zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | ||
| 1154 | const zir_datas = gz.astgen.instructions.items(.data); | ||
| 1155 | zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( | ||
| 1156 | zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, | ||
| 1157 | ); | ||
| 1158 | gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | pub fn setBlockBody(gz: GenZir, inst: zir.Inst.Index) !void { | ||
| 1162 | const gpa = gz.astgen.mod.gpa; | ||
| 1163 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1164 | @typeInfo(zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | ||
| 1165 | const zir_datas = gz.astgen.instructions.items(.data); | ||
| 1166 | zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( | ||
| 1167 | zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, | ||
| 1168 | ); | ||
| 1169 | gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 { | ||
| 1173 | const astgen = gz.astgen; | ||
| 1174 | const gpa = astgen.mod.gpa; | ||
| 1175 | const string_bytes = &astgen.string_bytes; | ||
| 1176 | const str_index = @intCast(u32, string_bytes.items.len); | ||
| 1177 | try astgen.mod.appendIdentStr(&gz.base, ident_token, string_bytes); | ||
| 1178 | try string_bytes.append(gpa, 0); | ||
| 1179 | return str_index; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct { | ||
| 1183 | src_node: ast.Node.Index, | ||
| 1184 | param_types: []const zir.Inst.Ref, | ||
| 1185 | ret_ty: zir.Inst.Ref, | ||
| 1186 | cc: zir.Inst.Ref, | ||
| 1187 | }) !zir.Inst.Ref { | ||
| 1188 | assert(args.src_node != 0); | ||
| 1189 | assert(args.ret_ty != .none); | ||
| 1190 | assert(args.cc != .none); | ||
| 1191 | const gpa = gz.astgen.mod.gpa; | ||
| 1192 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1193 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1194 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1195 | @typeInfo(zir.Inst.FnTypeCc).Struct.fields.len + args.param_types.len); | ||
| 1196 | |||
| 1197 | const payload_index = gz.astgen.addExtraAssumeCapacity(zir.Inst.FnTypeCc{ | ||
| 1198 | .return_type = args.ret_ty, | ||
| 1199 | .cc = args.cc, | ||
| 1200 | .param_types_len = @intCast(u32, args.param_types.len), | ||
| 1201 | }); | ||
| 1202 | gz.astgen.appendRefsAssumeCapacity(args.param_types); | ||
| 1203 | |||
| 1204 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1205 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1206 | .tag = tag, | ||
| 1207 | .data = .{ .pl_node = .{ | ||
| 1208 | .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node), | ||
| 1209 | .payload_index = payload_index, | ||
| 1210 | } }, | ||
| 1211 | }); | ||
| 1212 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1213 | return gz.astgen.indexToRef(new_index); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | pub fn addFnType(gz: *GenZir, tag: zir.Inst.Tag, args: struct { | ||
| 1217 | src_node: ast.Node.Index, | ||
| 1218 | ret_ty: zir.Inst.Ref, | ||
| 1219 | param_types: []const zir.Inst.Ref, | ||
| 1220 | }) !zir.Inst.Ref { | ||
| 1221 | assert(args.src_node != 0); | ||
| 1222 | assert(args.ret_ty != .none); | ||
| 1223 | const gpa = gz.astgen.mod.gpa; | ||
| 1224 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1225 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1226 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1227 | @typeInfo(zir.Inst.FnType).Struct.fields.len + args.param_types.len); | ||
| 1228 | |||
| 1229 | const payload_index = gz.astgen.addExtraAssumeCapacity(zir.Inst.FnType{ | ||
| 1230 | .return_type = args.ret_ty, | ||
| 1231 | .param_types_len = @intCast(u32, args.param_types.len), | ||
| 1232 | }); | ||
| 1233 | gz.astgen.appendRefsAssumeCapacity(args.param_types); | ||
| 1234 | |||
| 1235 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1236 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1237 | .tag = tag, | ||
| 1238 | .data = .{ .pl_node = .{ | ||
| 1239 | .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node), | ||
| 1240 | .payload_index = payload_index, | ||
| 1241 | } }, | ||
| 1242 | }); | ||
| 1243 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1244 | return gz.astgen.indexToRef(new_index); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | pub fn addCall( | ||
| 1248 | gz: *GenZir, | ||
| 1249 | tag: zir.Inst.Tag, | ||
| 1250 | callee: zir.Inst.Ref, | ||
| 1251 | args: []const zir.Inst.Ref, | ||
| 1252 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 1253 | src_node: ast.Node.Index, | ||
| 1254 | ) !zir.Inst.Ref { | ||
| 1255 | assert(callee != .none); | ||
| 1256 | assert(src_node != 0); | ||
| 1257 | const gpa = gz.astgen.mod.gpa; | ||
| 1258 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1259 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1260 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | ||
| 1261 | @typeInfo(zir.Inst.Call).Struct.fields.len + args.len); | ||
| 1262 | |||
| 1263 | const payload_index = gz.astgen.addExtraAssumeCapacity(zir.Inst.Call{ | ||
| 1264 | .callee = callee, | ||
| 1265 | .args_len = @intCast(u32, args.len), | ||
| 1266 | }); | ||
| 1267 | gz.astgen.appendRefsAssumeCapacity(args); | ||
| 1268 | |||
| 1269 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1270 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1271 | .tag = tag, | ||
| 1272 | .data = .{ .pl_node = .{ | ||
| 1273 | .src_node = gz.astgen.decl.nodeIndexToRelative(src_node), | ||
| 1274 | .payload_index = payload_index, | ||
| 1275 | } }, | ||
| 1276 | }); | ||
| 1277 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1278 | return gz.astgen.indexToRef(new_index); | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | /// Note that this returns a `zir.Inst.Index` not a ref. | ||
| 1282 | /// Leaves the `payload_index` field undefined. | ||
| 1283 | pub fn addBoolBr( | ||
| 1284 | gz: *GenZir, | ||
| 1285 | tag: zir.Inst.Tag, | ||
| 1286 | lhs: zir.Inst.Ref, | ||
| 1287 | ) !zir.Inst.Index { | ||
| 1288 | assert(lhs != .none); | ||
| 1289 | const gpa = gz.astgen.mod.gpa; | ||
| 1290 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1291 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1292 | |||
| 1293 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1294 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1295 | .tag = tag, | ||
| 1296 | .data = .{ .bool_br = .{ | ||
| 1297 | .lhs = lhs, | ||
| 1298 | .payload_index = undefined, | ||
| 1299 | } }, | ||
| 1300 | }); | ||
| 1301 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1302 | return new_index; | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | pub fn addInt(gz: *GenZir, integer: u64) !zir.Inst.Ref { | ||
| 1306 | return gz.add(.{ | ||
| 1307 | .tag = .int, | ||
| 1308 | .data = .{ .int = integer }, | ||
| 1309 | }); | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !zir.Inst.Ref { | ||
| 1313 | return gz.add(.{ | ||
| 1314 | .tag = .float, | ||
| 1315 | .data = .{ .float = .{ | ||
| 1316 | .src_node = gz.astgen.decl.nodeIndexToRelative(src_node), | ||
| 1317 | .number = number, | ||
| 1318 | } }, | ||
| 1319 | }); | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | pub fn addUnNode( | ||
| 1323 | gz: *GenZir, | ||
| 1324 | tag: zir.Inst.Tag, | ||
| 1325 | operand: zir.Inst.Ref, | ||
| 1326 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 1327 | src_node: ast.Node.Index, | ||
| 1328 | ) !zir.Inst.Ref { | ||
| 1329 | assert(operand != .none); | ||
| 1330 | return gz.add(.{ | ||
| 1331 | .tag = tag, | ||
| 1332 | .data = .{ .un_node = .{ | ||
| 1333 | .operand = operand, | ||
| 1334 | .src_node = gz.astgen.decl.nodeIndexToRelative(src_node), | ||
| 1335 | } }, | ||
| 1336 | }); | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | pub fn addPlNode( | ||
| 1340 | gz: *GenZir, | ||
| 1341 | tag: zir.Inst.Tag, | ||
| 1342 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 1343 | src_node: ast.Node.Index, | ||
| 1344 | extra: anytype, | ||
| 1345 | ) !zir.Inst.Ref { | ||
| 1346 | const gpa = gz.astgen.mod.gpa; | ||
| 1347 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1348 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1349 | |||
| 1350 | const payload_index = try gz.astgen.addExtra(extra); | ||
| 1351 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1352 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1353 | .tag = tag, | ||
| 1354 | .data = .{ .pl_node = .{ | ||
| 1355 | .src_node = gz.astgen.decl.nodeIndexToRelative(src_node), | ||
| 1356 | .payload_index = payload_index, | ||
| 1357 | } }, | ||
| 1358 | }); | ||
| 1359 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1360 | return gz.astgen.indexToRef(new_index); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | pub fn addArrayTypeSentinel( | ||
| 1364 | gz: *GenZir, | ||
| 1365 | len: zir.Inst.Ref, | ||
| 1366 | sentinel: zir.Inst.Ref, | ||
| 1367 | elem_type: zir.Inst.Ref, | ||
| 1368 | ) !zir.Inst.Ref { | ||
| 1369 | const gpa = gz.astgen.mod.gpa; | ||
| 1370 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1371 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1372 | |||
| 1373 | const payload_index = try gz.astgen.addExtra(zir.Inst.ArrayTypeSentinel{ | ||
| 1374 | .sentinel = sentinel, | ||
| 1375 | .elem_type = elem_type, | ||
| 1376 | }); | ||
| 1377 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1378 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 1379 | .tag = .array_type_sentinel, | ||
| 1380 | .data = .{ .array_type_sentinel = .{ | ||
| 1381 | .len = len, | ||
| 1382 | .payload_index = payload_index, | ||
| 1383 | } }, | ||
| 1384 | }); | ||
| 1385 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1386 | return gz.astgen.indexToRef(new_index); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | pub fn addUnTok( | ||
| 1390 | gz: *GenZir, | ||
| 1391 | tag: zir.Inst.Tag, | ||
| 1392 | operand: zir.Inst.Ref, | ||
| 1393 | /// Absolute token index. This function does the conversion to Decl offset. | ||
| 1394 | abs_tok_index: ast.TokenIndex, | ||
| 1395 | ) !zir.Inst.Ref { | ||
| 1396 | assert(operand != .none); | ||
| 1397 | return gz.add(.{ | ||
| 1398 | .tag = tag, | ||
| 1399 | .data = .{ .un_tok = .{ | ||
| 1400 | .operand = operand, | ||
| 1401 | .src_tok = abs_tok_index - gz.astgen.decl.srcToken(), | ||
| 1402 | } }, | ||
| 1403 | }); | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | pub fn addStrTok( | ||
| 1407 | gz: *GenZir, | ||
| 1408 | tag: zir.Inst.Tag, | ||
| 1409 | str_index: u32, | ||
| 1410 | /// Absolute token index. This function does the conversion to Decl offset. | ||
| 1411 | abs_tok_index: ast.TokenIndex, | ||
| 1412 | ) !zir.Inst.Ref { | ||
| 1413 | return gz.add(.{ | ||
| 1414 | .tag = tag, | ||
| 1415 | .data = .{ .str_tok = .{ | ||
| 1416 | .start = str_index, | ||
| 1417 | .src_tok = abs_tok_index - gz.astgen.decl.srcToken(), | ||
| 1418 | } }, | ||
| 1419 | }); | ||
| 1420 | } | ||
| 1421 | |||
| 1422 | pub fn addBreak( | ||
| 1423 | gz: *GenZir, | ||
| 1424 | tag: zir.Inst.Tag, | ||
| 1425 | break_block: zir.Inst.Index, | ||
| 1426 | operand: zir.Inst.Ref, | ||
| 1427 | ) !zir.Inst.Index { | ||
| 1428 | return gz.addAsIndex(.{ | ||
| 1429 | .tag = tag, | ||
| 1430 | .data = .{ .@"break" = .{ | ||
| 1431 | .block_inst = break_block, | ||
| 1432 | .operand = operand, | ||
| 1433 | } }, | ||
| 1434 | }); | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | pub fn addBin( | ||
| 1438 | gz: *GenZir, | ||
| 1439 | tag: zir.Inst.Tag, | ||
| 1440 | lhs: zir.Inst.Ref, | ||
| 1441 | rhs: zir.Inst.Ref, | ||
| 1442 | ) !zir.Inst.Ref { | ||
| 1443 | assert(lhs != .none); | ||
| 1444 | assert(rhs != .none); | ||
| 1445 | return gz.add(.{ | ||
| 1446 | .tag = tag, | ||
| 1447 | .data = .{ .bin = .{ | ||
| 1448 | .lhs = lhs, | ||
| 1449 | .rhs = rhs, | ||
| 1450 | } }, | ||
| 1451 | }); | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | pub fn addDecl( | ||
| 1455 | gz: *GenZir, | ||
| 1456 | tag: zir.Inst.Tag, | ||
| 1457 | decl_index: u32, | ||
| 1458 | src_node: ast.Node.Index, | ||
| 1459 | ) !zir.Inst.Ref { | ||
| 1460 | return gz.add(.{ | ||
| 1461 | .tag = tag, | ||
| 1462 | .data = .{ .pl_node = .{ | ||
| 1463 | .src_node = gz.astgen.decl.nodeIndexToRelative(src_node), | ||
| 1464 | .payload_index = decl_index, | ||
| 1465 | } }, | ||
| 1466 | }); | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | pub fn addNode( | ||
| 1470 | gz: *GenZir, | ||
| 1471 | tag: zir.Inst.Tag, | ||
| 1472 | /// Absolute node index. This function does the conversion to offset from Decl. | ||
| 1473 | src_node: ast.Node.Index, | ||
| 1474 | ) !zir.Inst.Ref { | ||
| 1475 | return gz.add(.{ | ||
| 1476 | .tag = tag, | ||
| 1477 | .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(src_node) }, | ||
| 1478 | }); | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | /// Asserts that `str` is 8 or fewer bytes. | ||
| 1482 | pub fn addSmallStr( | ||
| 1483 | gz: *GenZir, | ||
| 1484 | tag: zir.Inst.Tag, | ||
| 1485 | str: []const u8, | ||
| 1486 | ) !zir.Inst.Ref { | ||
| 1487 | var buf: [9]u8 = undefined; | ||
| 1488 | mem.copy(u8, &buf, str); | ||
| 1489 | buf[str.len] = 0; | ||
| 1490 | |||
| 1491 | return gz.add(.{ | ||
| 1492 | .tag = tag, | ||
| 1493 | .data = .{ .small_str = .{ .bytes = buf[0..8].* } }, | ||
| 1494 | }); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | /// Note that this returns a `zir.Inst.Index` not a ref. | ||
| 1498 | /// Does *not* append the block instruction to the scope. | ||
| 1499 | /// Leaves the `payload_index` field undefined. | ||
| 1500 | pub fn addBlock(gz: *GenZir, tag: zir.Inst.Tag, node: ast.Node.Index) !zir.Inst.Index { | ||
| 1501 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1502 | const gpa = gz.astgen.mod.gpa; | ||
| 1503 | try gz.astgen.instructions.append(gpa, .{ | ||
| 1504 | .tag = tag, | ||
| 1505 | .data = .{ .pl_node = .{ | ||
| 1506 | .src_node = gz.astgen.decl.nodeIndexToRelative(node), | ||
| 1507 | .payload_index = undefined, | ||
| 1508 | } }, | ||
| 1509 | }); | ||
| 1510 | return new_index; | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | /// Note that this returns a `zir.Inst.Index` not a ref. | ||
| 1514 | /// Leaves the `payload_index` field undefined. | ||
| 1515 | pub fn addCondBr(gz: *GenZir, tag: zir.Inst.Tag, node: ast.Node.Index) !zir.Inst.Index { | ||
| 1516 | const gpa = gz.astgen.mod.gpa; | ||
| 1517 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1518 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1519 | try gz.astgen.instructions.append(gpa, .{ | ||
| 1520 | .tag = tag, | ||
| 1521 | .data = .{ .pl_node = .{ | ||
| 1522 | .src_node = gz.astgen.decl.nodeIndexToRelative(node), | ||
| 1523 | .payload_index = undefined, | ||
| 1524 | } }, | ||
| 1525 | }); | ||
| 1526 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1527 | return new_index; | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref { | ||
| 1531 | return gz.astgen.indexToRef(try gz.addAsIndex(inst)); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | pub fn addAsIndex(gz: *GenZir, inst: zir.Inst) !zir.Inst.Index { | ||
| 1535 | const gpa = gz.astgen.mod.gpa; | ||
| 1536 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | ||
| 1537 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | ||
| 1538 | |||
| 1539 | const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len); | ||
| 1540 | gz.astgen.instructions.appendAssumeCapacity(inst); | ||
| 1541 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 1542 | return new_index; | ||
| 1543 | } | ||
| 1544 | }; | ||
| 1545 | |||
| 1546 | /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. | ||
| 1547 | /// This structure lives as long as the AST generation of the Block | ||
| 1548 | /// node that contains the variable. | ||
| 1549 | pub const LocalVal = struct { | ||
| 1550 | pub const base_tag: Tag = .local_val; | ||
| 1551 | base: Scope = Scope{ .tag = base_tag }, | ||
| 1552 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`. | ||
| 1553 | parent: *Scope, | ||
| 1554 | gen_zir: *GenZir, | ||
| 1555 | name: []const u8, | ||
| 1556 | inst: zir.Inst.Ref, | ||
| 1557 | /// Source location of the corresponding variable declaration. | ||
| 1558 | src: LazySrcLoc, | ||
| 1559 | }; | ||
| 1560 | |||
| 1561 | /// This could be a `const` or `var` local. It has a pointer instead of a value. | ||
| 1562 | /// This structure lives as long as the AST generation of the Block | ||
| 1563 | /// node that contains the variable. | ||
| 1564 | pub const LocalPtr = struct { | ||
| 1565 | pub const base_tag: Tag = .local_ptr; | ||
| 1566 | base: Scope = Scope{ .tag = base_tag }, | ||
| 1567 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`. | ||
| 1568 | parent: *Scope, | ||
| 1569 | gen_zir: *GenZir, | ||
| 1570 | name: []const u8, | ||
| 1571 | ptr: zir.Inst.Ref, | ||
| 1572 | /// Source location of the corresponding variable declaration. | ||
| 1573 | src: LazySrcLoc, | ||
| 1574 | }; | ||
| 1575 | |||
| 1576 | pub const DeclRef = struct { | ||
| 1577 | pub const base_tag: Tag = .decl_ref; | ||
| 1578 | base: Scope = Scope{ .tag = base_tag }, | ||
| 1579 | decl: *Decl, | ||
| 1580 | }; | ||
| 1581 | }; | ||
| 1582 | |||
| 1583 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. | ||
| 1584 | /// Its memory is managed with the general purpose allocator so that they | ||
| 1585 | /// can be created and destroyed in response to incremental updates. | ||
| 1586 | /// In some cases, the Scope.File could have been inferred from where the ErrorMsg | ||
| 1587 | /// is stored. For example, if it is stored in Module.failed_decls, then the Scope.File | ||
| 1588 | /// would be determined by the Decl Scope. However, the data structure contains the field | ||
| 1589 | /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different | ||
| 1590 | /// file than the parent error message. It also simplifies processing of error messages. | ||
| 1591 | pub const ErrorMsg = struct { | ||
| 1592 | src_loc: SrcLoc, | ||
| 1593 | msg: []const u8, | ||
| 1594 | notes: []ErrorMsg = &.{}, | ||
| 1595 | |||
| 1596 | pub fn create( | ||
| 1597 | gpa: *Allocator, | ||
| 1598 | src_loc: SrcLoc, | ||
| 1599 | comptime format: []const u8, | ||
| 1600 | args: anytype, | ||
| 1601 | ) !*ErrorMsg { | ||
| 1602 | const err_msg = try gpa.create(ErrorMsg); | ||
| 1603 | errdefer gpa.destroy(err_msg); | ||
| 1604 | err_msg.* = try init(gpa, src_loc, format, args); | ||
| 1605 | return err_msg; | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`, | ||
| 1609 | /// as well as all notes. | ||
| 1610 | pub fn destroy(err_msg: *ErrorMsg, gpa: *Allocator) void { | ||
| 1611 | err_msg.deinit(gpa); | ||
| 1612 | gpa.destroy(err_msg); | ||
| 1613 | } | ||
| 1614 | |||
| 1615 | pub fn init( | ||
| 1616 | gpa: *Allocator, | ||
| 1617 | src_loc: SrcLoc, | ||
| 1618 | comptime format: []const u8, | ||
| 1619 | args: anytype, | ||
| 1620 | ) !ErrorMsg { | ||
| 1621 | return ErrorMsg{ | ||
| 1622 | .src_loc = src_loc, | ||
| 1623 | .msg = try std.fmt.allocPrint(gpa, format, args), | ||
| 1624 | }; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | pub fn deinit(err_msg: *ErrorMsg, gpa: *Allocator) void { | ||
| 1628 | for (err_msg.notes) |*note| { | ||
| 1629 | note.deinit(gpa); | ||
| 1630 | } | ||
| 1631 | gpa.free(err_msg.notes); | ||
| 1632 | gpa.free(err_msg.msg); | ||
| 1633 | err_msg.* = undefined; | ||
| 1634 | } | ||
| 1635 | }; | ||
| 1636 | |||
| 1637 | /// Canonical reference to a position within a source file. | ||
| 1638 | pub const SrcLoc = struct { | ||
| 1639 | /// The active field is determined by tag of `lazy`. | ||
| 1640 | container: union { | ||
| 1641 | /// The containing `Decl` according to the source code. | ||
| 1642 | decl: *Decl, | ||
| 1643 | file_scope: *Scope.File, | ||
| 1644 | }, | ||
| 1645 | /// Relative to `decl`. | ||
| 1646 | lazy: LazySrcLoc, | ||
| 1647 | |||
| 1648 | pub fn fileScope(src_loc: SrcLoc) *Scope.File { | ||
| 1649 | return switch (src_loc.lazy) { | ||
| 1650 | .unneeded => unreachable, | ||
| 1651 | |||
| 1652 | .byte_abs, | ||
| 1653 | .token_abs, | ||
| 1654 | .node_abs, | ||
| 1655 | => src_loc.container.file_scope, | ||
| 1656 | |||
| 1657 | .byte_offset, | ||
| 1658 | .token_offset, | ||
| 1659 | .node_offset, | ||
| 1660 | .node_offset_back2tok, | ||
| 1661 | .node_offset_var_decl_ty, | ||
| 1662 | .node_offset_for_cond, | ||
| 1663 | .node_offset_builtin_call_arg0, | ||
| 1664 | .node_offset_builtin_call_arg1, | ||
| 1665 | .node_offset_array_access_index, | ||
| 1666 | .node_offset_slice_sentinel, | ||
| 1667 | .node_offset_call_func, | ||
| 1668 | .node_offset_field_name, | ||
| 1669 | .node_offset_deref_ptr, | ||
| 1670 | .node_offset_asm_source, | ||
| 1671 | .node_offset_asm_ret_ty, | ||
| 1672 | .node_offset_if_cond, | ||
| 1673 | .node_offset_bin_op, | ||
| 1674 | .node_offset_bin_lhs, | ||
| 1675 | .node_offset_bin_rhs, | ||
| 1676 | .node_offset_switch_operand, | ||
| 1677 | .node_offset_switch_special_prong, | ||
| 1678 | .node_offset_switch_range, | ||
| 1679 | .node_offset_fn_type_cc, | ||
| 1680 | .node_offset_fn_type_ret_ty, | ||
| 1681 | => src_loc.container.decl.container.file_scope, | ||
| 1682 | }; | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | pub fn byteOffset(src_loc: SrcLoc) !u32 { | ||
| 1686 | switch (src_loc.lazy) { | 1467 | switch (src_loc.lazy) { |
| 1687 | .unneeded => unreachable, | 1468 | .unneeded => unreachable, |
| 1469 | .entire_file => return 0, | ||
| 1688 | 1470 | ||
| 1689 | .byte_abs => |byte_index| return byte_index, | 1471 | .byte_abs => |byte_index| return byte_index, |
| 1690 | 1472 | ||
| 1691 | .token_abs => |tok_index| { | 1473 | .token_abs => |tok_index| { |
| 1692 | const tree = src_loc.container.file_scope.base.tree(); | 1474 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1693 | const token_starts = tree.tokens.items(.start); | 1475 | const token_starts = tree.tokens.items(.start); |
| 1694 | return token_starts[tok_index]; | 1476 | return token_starts[tok_index]; |
| 1695 | }, | 1477 | }, |
| 1696 | .node_abs => |node| { | 1478 | .node_abs => |node| { |
| 1697 | const tree = src_loc.container.file_scope.base.tree(); | 1479 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1698 | const token_starts = tree.tokens.items(.start); | 1480 | const token_starts = tree.tokens.items(.start); |
| 1699 | const tok_index = tree.firstToken(node); | 1481 | const tok_index = tree.firstToken(node); |
| 1700 | return token_starts[tok_index]; | 1482 | return token_starts[tok_index]; |
| 1701 | }, | 1483 | }, |
| 1702 | .byte_offset => |byte_off| { | 1484 | .byte_offset => |byte_off| { |
| 1703 | const decl = src_loc.container.decl; | 1485 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1704 | return decl.srcByteOffset() + byte_off; | 1486 | const token_starts = tree.tokens.items(.start); |
| 1487 | return token_starts[src_loc.declSrcToken()] + byte_off; | ||
| 1705 | }, | 1488 | }, |
| 1706 | .token_offset => |tok_off| { | 1489 | .token_offset => |tok_off| { |
| 1707 | const decl = src_loc.container.decl; | 1490 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1708 | const tok_index = decl.srcToken() + tok_off; | 1491 | const tok_index = src_loc.declSrcToken() + tok_off; |
| 1709 | const tree = decl.container.file_scope.base.tree(); | ||
| 1710 | const token_starts = tree.tokens.items(.start); | 1492 | const token_starts = tree.tokens.items(.start); |
| 1711 | return token_starts[tok_index]; | 1493 | return token_starts[tok_index]; |
| 1712 | }, | 1494 | }, |
| 1713 | .node_offset, .node_offset_bin_op => |node_off| { | 1495 | .node_offset, .node_offset_bin_op => |node_off| { |
| 1714 | const decl = src_loc.container.decl; | 1496 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1715 | const node = decl.relativeToNodeIndex(node_off); | 1497 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1716 | const tree = decl.container.file_scope.base.tree(); | 1498 | assert(src_loc.file_scope.tree_loaded); |
| 1717 | const main_tokens = tree.nodes.items(.main_token); | 1499 | const main_tokens = tree.nodes.items(.main_token); |
| 1718 | const tok_index = main_tokens[node]; | 1500 | const tok_index = main_tokens[node]; |
| 1719 | const token_starts = tree.tokens.items(.start); | 1501 | const token_starts = tree.tokens.items(.start); |
| 1720 | return token_starts[tok_index]; | 1502 | return token_starts[tok_index]; |
| 1721 | }, | 1503 | }, |
| 1722 | .node_offset_back2tok => |node_off| { | 1504 | .node_offset_back2tok => |node_off| { |
| 1723 | const decl = src_loc.container.decl; | 1505 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1724 | const node = decl.relativeToNodeIndex(node_off); | 1506 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1725 | const tree = decl.container.file_scope.base.tree(); | ||
| 1726 | const tok_index = tree.firstToken(node) - 2; | 1507 | const tok_index = tree.firstToken(node) - 2; |
| 1727 | const token_starts = tree.tokens.items(.start); | 1508 | const token_starts = tree.tokens.items(.start); |
| 1728 | return token_starts[tok_index]; | 1509 | return token_starts[tok_index]; |
| 1729 | }, | 1510 | }, |
| 1730 | .node_offset_var_decl_ty => |node_off| { | 1511 | .node_offset_var_decl_ty => |node_off| { |
| 1731 | const decl = src_loc.container.decl; | 1512 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1732 | const node = decl.relativeToNodeIndex(node_off); | 1513 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1733 | const tree = decl.container.file_scope.base.tree(); | ||
| 1734 | const node_tags = tree.nodes.items(.tag); | 1514 | const node_tags = tree.nodes.items(.tag); |
| 1735 | const full = switch (node_tags[node]) { | 1515 | const full = switch (node_tags[node]) { |
| 1736 | .global_var_decl => tree.globalVarDecl(node), | 1516 | .global_var_decl => tree.globalVarDecl(node), |
| ... | @@ -1749,11 +1529,10 @@ pub const SrcLoc = struct { | ... | @@ -1749,11 +1529,10 @@ pub const SrcLoc = struct { |
| 1749 | return token_starts[tok_index]; | 1529 | return token_starts[tok_index]; |
| 1750 | }, | 1530 | }, |
| 1751 | .node_offset_builtin_call_arg0 => |node_off| { | 1531 | .node_offset_builtin_call_arg0 => |node_off| { |
| 1752 | const decl = src_loc.container.decl; | 1532 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1753 | const tree = decl.container.file_scope.base.tree(); | ||
| 1754 | const node_datas = tree.nodes.items(.data); | 1533 | const node_datas = tree.nodes.items(.data); |
| 1755 | const node_tags = tree.nodes.items(.tag); | 1534 | const node_tags = tree.nodes.items(.tag); |
| 1756 | const node = decl.relativeToNodeIndex(node_off); | 1535 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1757 | const param = switch (node_tags[node]) { | 1536 | const param = switch (node_tags[node]) { |
| 1758 | .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs, | 1537 | .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs, |
| 1759 | .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs], | 1538 | .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs], |
| ... | @@ -1765,11 +1544,10 @@ pub const SrcLoc = struct { | ... | @@ -1765,11 +1544,10 @@ pub const SrcLoc = struct { |
| 1765 | return token_starts[tok_index]; | 1544 | return token_starts[tok_index]; |
| 1766 | }, | 1545 | }, |
| 1767 | .node_offset_builtin_call_arg1 => |node_off| { | 1546 | .node_offset_builtin_call_arg1 => |node_off| { |
| 1768 | const decl = src_loc.container.decl; | 1547 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1769 | const tree = decl.container.file_scope.base.tree(); | ||
| 1770 | const node_datas = tree.nodes.items(.data); | 1548 | const node_datas = tree.nodes.items(.data); |
| 1771 | const node_tags = tree.nodes.items(.tag); | 1549 | const node_tags = tree.nodes.items(.tag); |
| 1772 | const node = decl.relativeToNodeIndex(node_off); | 1550 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1773 | const param = switch (node_tags[node]) { | 1551 | const param = switch (node_tags[node]) { |
| 1774 | .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs, | 1552 | .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs, |
| 1775 | .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1], | 1553 | .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1], |
| ... | @@ -1781,22 +1559,20 @@ pub const SrcLoc = struct { | ... | @@ -1781,22 +1559,20 @@ pub const SrcLoc = struct { |
| 1781 | return token_starts[tok_index]; | 1559 | return token_starts[tok_index]; |
| 1782 | }, | 1560 | }, |
| 1783 | .node_offset_array_access_index => |node_off| { | 1561 | .node_offset_array_access_index => |node_off| { |
| 1784 | const decl = src_loc.container.decl; | 1562 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1785 | const tree = decl.container.file_scope.base.tree(); | ||
| 1786 | const node_datas = tree.nodes.items(.data); | 1563 | const node_datas = tree.nodes.items(.data); |
| 1787 | const node_tags = tree.nodes.items(.tag); | 1564 | const node_tags = tree.nodes.items(.tag); |
| 1788 | const node = decl.relativeToNodeIndex(node_off); | 1565 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1789 | const main_tokens = tree.nodes.items(.main_token); | 1566 | const main_tokens = tree.nodes.items(.main_token); |
| 1790 | const tok_index = main_tokens[node_datas[node].rhs]; | 1567 | const tok_index = main_tokens[node_datas[node].rhs]; |
| 1791 | const token_starts = tree.tokens.items(.start); | 1568 | const token_starts = tree.tokens.items(.start); |
| 1792 | return token_starts[tok_index]; | 1569 | return token_starts[tok_index]; |
| 1793 | }, | 1570 | }, |
| 1794 | .node_offset_slice_sentinel => |node_off| { | 1571 | .node_offset_slice_sentinel => |node_off| { |
| 1795 | const decl = src_loc.container.decl; | 1572 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1796 | const tree = decl.container.file_scope.base.tree(); | ||
| 1797 | const node_datas = tree.nodes.items(.data); | 1573 | const node_datas = tree.nodes.items(.data); |
| 1798 | const node_tags = tree.nodes.items(.tag); | 1574 | const node_tags = tree.nodes.items(.tag); |
| 1799 | const node = decl.relativeToNodeIndex(node_off); | 1575 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1800 | const full = switch (node_tags[node]) { | 1576 | const full = switch (node_tags[node]) { |
| 1801 | .slice_open => tree.sliceOpen(node), | 1577 | .slice_open => tree.sliceOpen(node), |
| 1802 | .slice => tree.slice(node), | 1578 | .slice => tree.slice(node), |
| ... | @@ -1809,11 +1585,10 @@ pub const SrcLoc = struct { | ... | @@ -1809,11 +1585,10 @@ pub const SrcLoc = struct { |
| 1809 | return token_starts[tok_index]; | 1585 | return token_starts[tok_index]; |
| 1810 | }, | 1586 | }, |
| 1811 | .node_offset_call_func => |node_off| { | 1587 | .node_offset_call_func => |node_off| { |
| 1812 | const decl = src_loc.container.decl; | 1588 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1813 | const tree = decl.container.file_scope.base.tree(); | ||
| 1814 | const node_datas = tree.nodes.items(.data); | 1589 | const node_datas = tree.nodes.items(.data); |
| 1815 | const node_tags = tree.nodes.items(.tag); | 1590 | const node_tags = tree.nodes.items(.tag); |
| 1816 | const node = decl.relativeToNodeIndex(node_off); | 1591 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1817 | var params: [1]ast.Node.Index = undefined; | 1592 | var params: [1]ast.Node.Index = undefined; |
| 1818 | const full = switch (node_tags[node]) { | 1593 | const full = switch (node_tags[node]) { |
| 1819 | .call_one, | 1594 | .call_one, |
| ... | @@ -1836,11 +1611,10 @@ pub const SrcLoc = struct { | ... | @@ -1836,11 +1611,10 @@ pub const SrcLoc = struct { |
| 1836 | return token_starts[tok_index]; | 1611 | return token_starts[tok_index]; |
| 1837 | }, | 1612 | }, |
| 1838 | .node_offset_field_name => |node_off| { | 1613 | .node_offset_field_name => |node_off| { |
| 1839 | const decl = src_loc.container.decl; | 1614 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1840 | const tree = decl.container.file_scope.base.tree(); | ||
| 1841 | const node_datas = tree.nodes.items(.data); | 1615 | const node_datas = tree.nodes.items(.data); |
| 1842 | const node_tags = tree.nodes.items(.tag); | 1616 | const node_tags = tree.nodes.items(.tag); |
| 1843 | const node = decl.relativeToNodeIndex(node_off); | 1617 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1844 | const tok_index = switch (node_tags[node]) { | 1618 | const tok_index = switch (node_tags[node]) { |
| 1845 | .field_access => node_datas[node].rhs, | 1619 | .field_access => node_datas[node].rhs, |
| 1846 | else => tree.firstToken(node) - 2, | 1620 | else => tree.firstToken(node) - 2, |
| ... | @@ -1849,21 +1623,19 @@ pub const SrcLoc = struct { | ... | @@ -1849,21 +1623,19 @@ pub const SrcLoc = struct { |
| 1849 | return token_starts[tok_index]; | 1623 | return token_starts[tok_index]; |
| 1850 | }, | 1624 | }, |
| 1851 | .node_offset_deref_ptr => |node_off| { | 1625 | .node_offset_deref_ptr => |node_off| { |
| 1852 | const decl = src_loc.container.decl; | 1626 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1853 | const tree = decl.container.file_scope.base.tree(); | ||
| 1854 | const node_datas = tree.nodes.items(.data); | 1627 | const node_datas = tree.nodes.items(.data); |
| 1855 | const node_tags = tree.nodes.items(.tag); | 1628 | const node_tags = tree.nodes.items(.tag); |
| 1856 | const node = decl.relativeToNodeIndex(node_off); | 1629 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1857 | const tok_index = node_datas[node].lhs; | 1630 | const tok_index = node_datas[node].lhs; |
| 1858 | const token_starts = tree.tokens.items(.start); | 1631 | const token_starts = tree.tokens.items(.start); |
| 1859 | return token_starts[tok_index]; | 1632 | return token_starts[tok_index]; |
| 1860 | }, | 1633 | }, |
| 1861 | .node_offset_asm_source => |node_off| { | 1634 | .node_offset_asm_source => |node_off| { |
| 1862 | const decl = src_loc.container.decl; | 1635 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1863 | const tree = decl.container.file_scope.base.tree(); | ||
| 1864 | const node_datas = tree.nodes.items(.data); | 1636 | const node_datas = tree.nodes.items(.data); |
| 1865 | const node_tags = tree.nodes.items(.tag); | 1637 | const node_tags = tree.nodes.items(.tag); |
| 1866 | const node = decl.relativeToNodeIndex(node_off); | 1638 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1867 | const full = switch (node_tags[node]) { | 1639 | const full = switch (node_tags[node]) { |
| 1868 | .asm_simple => tree.asmSimple(node), | 1640 | .asm_simple => tree.asmSimple(node), |
| 1869 | .@"asm" => tree.asmFull(node), | 1641 | .@"asm" => tree.asmFull(node), |
| ... | @@ -1875,11 +1647,10 @@ pub const SrcLoc = struct { | ... | @@ -1875,11 +1647,10 @@ pub const SrcLoc = struct { |
| 1875 | return token_starts[tok_index]; | 1647 | return token_starts[tok_index]; |
| 1876 | }, | 1648 | }, |
| 1877 | .node_offset_asm_ret_ty => |node_off| { | 1649 | .node_offset_asm_ret_ty => |node_off| { |
| 1878 | const decl = src_loc.container.decl; | 1650 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1879 | const tree = decl.container.file_scope.base.tree(); | ||
| 1880 | const node_datas = tree.nodes.items(.data); | 1651 | const node_datas = tree.nodes.items(.data); |
| 1881 | const node_tags = tree.nodes.items(.tag); | 1652 | const node_tags = tree.nodes.items(.tag); |
| 1882 | const node = decl.relativeToNodeIndex(node_off); | 1653 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1883 | const full = switch (node_tags[node]) { | 1654 | const full = switch (node_tags[node]) { |
| 1884 | .asm_simple => tree.asmSimple(node), | 1655 | .asm_simple => tree.asmSimple(node), |
| 1885 | .@"asm" => tree.asmFull(node), | 1656 | .@"asm" => tree.asmFull(node), |
| ... | @@ -1892,9 +1663,8 @@ pub const SrcLoc = struct { | ... | @@ -1892,9 +1663,8 @@ pub const SrcLoc = struct { |
| 1892 | }, | 1663 | }, |
| 1893 | 1664 | ||
| 1894 | .node_offset_for_cond, .node_offset_if_cond => |node_off| { | 1665 | .node_offset_for_cond, .node_offset_if_cond => |node_off| { |
| 1895 | const decl = src_loc.container.decl; | 1666 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1896 | const node = decl.relativeToNodeIndex(node_off); | 1667 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1897 | const tree = decl.container.file_scope.base.tree(); | ||
| 1898 | const node_tags = tree.nodes.items(.tag); | 1668 | const node_tags = tree.nodes.items(.tag); |
| 1899 | const src_node = switch (node_tags[node]) { | 1669 | const src_node = switch (node_tags[node]) { |
| 1900 | .if_simple => tree.ifSimple(node).ast.cond_expr, | 1670 | .if_simple => tree.ifSimple(node).ast.cond_expr, |
| ... | @@ -1912,9 +1682,8 @@ pub const SrcLoc = struct { | ... | @@ -1912,9 +1682,8 @@ pub const SrcLoc = struct { |
| 1912 | return token_starts[tok_index]; | 1682 | return token_starts[tok_index]; |
| 1913 | }, | 1683 | }, |
| 1914 | .node_offset_bin_lhs => |node_off| { | 1684 | .node_offset_bin_lhs => |node_off| { |
| 1915 | const decl = src_loc.container.decl; | 1685 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1916 | const node = decl.relativeToNodeIndex(node_off); | 1686 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1917 | const tree = decl.container.file_scope.base.tree(); | ||
| 1918 | const node_datas = tree.nodes.items(.data); | 1687 | const node_datas = tree.nodes.items(.data); |
| 1919 | const src_node = node_datas[node].lhs; | 1688 | const src_node = node_datas[node].lhs; |
| 1920 | const main_tokens = tree.nodes.items(.main_token); | 1689 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -1923,9 +1692,8 @@ pub const SrcLoc = struct { | ... | @@ -1923,9 +1692,8 @@ pub const SrcLoc = struct { |
| 1923 | return token_starts[tok_index]; | 1692 | return token_starts[tok_index]; |
| 1924 | }, | 1693 | }, |
| 1925 | .node_offset_bin_rhs => |node_off| { | 1694 | .node_offset_bin_rhs => |node_off| { |
| 1926 | const decl = src_loc.container.decl; | 1695 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1927 | const node = decl.relativeToNodeIndex(node_off); | 1696 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1928 | const tree = decl.container.file_scope.base.tree(); | ||
| 1929 | const node_datas = tree.nodes.items(.data); | 1697 | const node_datas = tree.nodes.items(.data); |
| 1930 | const src_node = node_datas[node].rhs; | 1698 | const src_node = node_datas[node].rhs; |
| 1931 | const main_tokens = tree.nodes.items(.main_token); | 1699 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -1935,9 +1703,8 @@ pub const SrcLoc = struct { | ... | @@ -1935,9 +1703,8 @@ pub const SrcLoc = struct { |
| 1935 | }, | 1703 | }, |
| 1936 | 1704 | ||
| 1937 | .node_offset_switch_operand => |node_off| { | 1705 | .node_offset_switch_operand => |node_off| { |
| 1938 | const decl = src_loc.container.decl; | 1706 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1939 | const node = decl.relativeToNodeIndex(node_off); | 1707 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 1940 | const tree = decl.container.file_scope.base.tree(); | ||
| 1941 | const node_datas = tree.nodes.items(.data); | 1708 | const node_datas = tree.nodes.items(.data); |
| 1942 | const src_node = node_datas[node].lhs; | 1709 | const src_node = node_datas[node].lhs; |
| 1943 | const main_tokens = tree.nodes.items(.main_token); | 1710 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -1947,9 +1714,8 @@ pub const SrcLoc = struct { | ... | @@ -1947,9 +1714,8 @@ pub const SrcLoc = struct { |
| 1947 | }, | 1714 | }, |
| 1948 | 1715 | ||
| 1949 | .node_offset_switch_special_prong => |node_off| { | 1716 | .node_offset_switch_special_prong => |node_off| { |
| 1950 | const decl = src_loc.container.decl; | 1717 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1951 | const switch_node = decl.relativeToNodeIndex(node_off); | 1718 | const switch_node = src_loc.declRelativeToNodeIndex(node_off); |
| 1952 | const tree = decl.container.file_scope.base.tree(); | ||
| 1953 | const node_datas = tree.nodes.items(.data); | 1719 | const node_datas = tree.nodes.items(.data); |
| 1954 | const node_tags = tree.nodes.items(.tag); | 1720 | const node_tags = tree.nodes.items(.tag); |
| 1955 | const main_tokens = tree.nodes.items(.main_token); | 1721 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -1974,9 +1740,8 @@ pub const SrcLoc = struct { | ... | @@ -1974,9 +1740,8 @@ pub const SrcLoc = struct { |
| 1974 | }, | 1740 | }, |
| 1975 | 1741 | ||
| 1976 | .node_offset_switch_range => |node_off| { | 1742 | .node_offset_switch_range => |node_off| { |
| 1977 | const decl = src_loc.container.decl; | 1743 | const tree = try src_loc.file_scope.getTree(gpa); |
| 1978 | const switch_node = decl.relativeToNodeIndex(node_off); | 1744 | const switch_node = src_loc.declRelativeToNodeIndex(node_off); |
| 1979 | const tree = decl.container.file_scope.base.tree(); | ||
| 1980 | const node_datas = tree.nodes.items(.data); | 1745 | const node_datas = tree.nodes.items(.data); |
| 1981 | const node_tags = tree.nodes.items(.tag); | 1746 | const node_tags = tree.nodes.items(.tag); |
| 1982 | const main_tokens = tree.nodes.items(.main_token); | 1747 | const main_tokens = tree.nodes.items(.main_token); |
| ... | @@ -2005,11 +1770,10 @@ pub const SrcLoc = struct { | ... | @@ -2005,11 +1770,10 @@ pub const SrcLoc = struct { |
| 2005 | }, | 1770 | }, |
| 2006 | 1771 | ||
| 2007 | .node_offset_fn_type_cc => |node_off| { | 1772 | .node_offset_fn_type_cc => |node_off| { |
| 2008 | const decl = src_loc.container.decl; | 1773 | const tree = try src_loc.file_scope.getTree(gpa); |
| 2009 | const tree = decl.container.file_scope.base.tree(); | ||
| 2010 | const node_datas = tree.nodes.items(.data); | 1774 | const node_datas = tree.nodes.items(.data); |
| 2011 | const node_tags = tree.nodes.items(.tag); | 1775 | const node_tags = tree.nodes.items(.tag); |
| 2012 | const node = decl.relativeToNodeIndex(node_off); | 1776 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 2013 | var params: [1]ast.Node.Index = undefined; | 1777 | var params: [1]ast.Node.Index = undefined; |
| 2014 | const full = switch (node_tags[node]) { | 1778 | const full = switch (node_tags[node]) { |
| 2015 | .fn_proto_simple => tree.fnProtoSimple(&params, node), | 1779 | .fn_proto_simple => tree.fnProtoSimple(&params, node), |
| ... | @@ -2025,11 +1789,10 @@ pub const SrcLoc = struct { | ... | @@ -2025,11 +1789,10 @@ pub const SrcLoc = struct { |
| 2025 | }, | 1789 | }, |
| 2026 | 1790 | ||
| 2027 | .node_offset_fn_type_ret_ty => |node_off| { | 1791 | .node_offset_fn_type_ret_ty => |node_off| { |
| 2028 | const decl = src_loc.container.decl; | 1792 | const tree = try src_loc.file_scope.getTree(gpa); |
| 2029 | const tree = decl.container.file_scope.base.tree(); | ||
| 2030 | const node_datas = tree.nodes.items(.data); | 1793 | const node_datas = tree.nodes.items(.data); |
| 2031 | const node_tags = tree.nodes.items(.tag); | 1794 | const node_tags = tree.nodes.items(.tag); |
| 2032 | const node = decl.relativeToNodeIndex(node_off); | 1795 | const node = src_loc.declRelativeToNodeIndex(node_off); |
| 2033 | var params: [1]ast.Node.Index = undefined; | 1796 | var params: [1]ast.Node.Index = undefined; |
| 2034 | const full = switch (node_tags[node]) { | 1797 | const full = switch (node_tags[node]) { |
| 2035 | .fn_proto_simple => tree.fnProtoSimple(&params, node), | 1798 | .fn_proto_simple => tree.fnProtoSimple(&params, node), |
| ... | @@ -2043,6 +1806,46 @@ pub const SrcLoc = struct { | ... | @@ -2043,6 +1806,46 @@ pub const SrcLoc = struct { |
| 2043 | const token_starts = tree.tokens.items(.start); | 1806 | const token_starts = tree.tokens.items(.start); |
| 2044 | return token_starts[tok_index]; | 1807 | return token_starts[tok_index]; |
| 2045 | }, | 1808 | }, |
| 1809 | |||
| 1810 | .node_offset_anyframe_type => |node_off| { | ||
| 1811 | const tree = try src_loc.file_scope.getTree(gpa); | ||
| 1812 | const node_datas = tree.nodes.items(.data); | ||
| 1813 | const node_tags = tree.nodes.items(.tag); | ||
| 1814 | const parent_node = src_loc.declRelativeToNodeIndex(node_off); | ||
| 1815 | const node = node_datas[parent_node].rhs; | ||
| 1816 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1817 | const tok_index = main_tokens[node]; | ||
| 1818 | const token_starts = tree.tokens.items(.start); | ||
| 1819 | return token_starts[tok_index]; | ||
| 1820 | }, | ||
| 1821 | |||
| 1822 | .node_offset_lib_name => |node_off| { | ||
| 1823 | const tree = try src_loc.file_scope.getTree(gpa); | ||
| 1824 | const node_datas = tree.nodes.items(.data); | ||
| 1825 | const node_tags = tree.nodes.items(.tag); | ||
| 1826 | const parent_node = src_loc.declRelativeToNodeIndex(node_off); | ||
| 1827 | var params: [1]ast.Node.Index = undefined; | ||
| 1828 | const full = switch (node_tags[parent_node]) { | ||
| 1829 | .fn_proto_simple => tree.fnProtoSimple(&params, parent_node), | ||
| 1830 | .fn_proto_multi => tree.fnProtoMulti(parent_node), | ||
| 1831 | .fn_proto_one => tree.fnProtoOne(&params, parent_node), | ||
| 1832 | .fn_proto => tree.fnProto(parent_node), | ||
| 1833 | .fn_decl => blk: { | ||
| 1834 | const fn_proto = node_datas[parent_node].lhs; | ||
| 1835 | break :blk switch (node_tags[fn_proto]) { | ||
| 1836 | .fn_proto_simple => tree.fnProtoSimple(&params, fn_proto), | ||
| 1837 | .fn_proto_multi => tree.fnProtoMulti(fn_proto), | ||
| 1838 | .fn_proto_one => tree.fnProtoOne(&params, fn_proto), | ||
| 1839 | .fn_proto => tree.fnProto(fn_proto), | ||
| 1840 | else => unreachable, | ||
| 1841 | }; | ||
| 1842 | }, | ||
| 1843 | else => unreachable, | ||
| 1844 | }; | ||
| 1845 | const tok_index = full.lib_name.?; | ||
| 1846 | const token_starts = tree.tokens.items(.start); | ||
| 1847 | return token_starts[tok_index]; | ||
| 1848 | }, | ||
| 2046 | } | 1849 | } |
| 2047 | } | 1850 | } |
| 2048 | }; | 1851 | }; |
| ... | @@ -2062,6 +1865,9 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -2062,6 +1865,9 @@ pub const LazySrcLoc = union(enum) { |
| 2062 | /// look into using reverse-continue with a memory watchpoint to see where the | 1865 | /// look into using reverse-continue with a memory watchpoint to see where the |
| 2063 | /// value is being set to this tag. | 1866 | /// value is being set to this tag. |
| 2064 | unneeded, | 1867 | unneeded, |
| 1868 | /// Means the source location points to an entire file; not any particular | ||
| 1869 | /// location within the file. `file_scope` union field will be active. | ||
| 1870 | entire_file, | ||
| 2065 | /// The source location points to a byte offset within a source file, | 1871 | /// The source location points to a byte offset within a source file, |
| 2066 | /// offset from 0. The source file is determined contextually. | 1872 | /// offset from 0. The source file is determined contextually. |
| 2067 | /// Inside a `SrcLoc`, the `file_scope` union field will be active. | 1873 | /// Inside a `SrcLoc`, the `file_scope` union field will be active. |
| ... | @@ -2199,16 +2005,30 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -2199,16 +2005,30 @@ pub const LazySrcLoc = union(enum) { |
| 2199 | /// the return type node. | 2005 | /// the return type node. |
| 2200 | /// The Decl is determined contextually. | 2006 | /// The Decl is determined contextually. |
| 2201 | node_offset_fn_type_ret_ty: i32, | 2007 | node_offset_fn_type_ret_ty: i32, |
| 2008 | /// The source location points to the type expression of an `anyframe->T` | ||
| 2009 | /// expression, found by taking this AST node index offset from the containing | ||
| 2010 | /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate | ||
| 2011 | /// to the type expression. | ||
| 2012 | /// The Decl is determined contextually. | ||
| 2013 | node_offset_anyframe_type: i32, | ||
| 2014 | /// The source location points to the string literal of `extern "foo"`, found | ||
| 2015 | /// by taking this AST node index offset from the containing | ||
| 2016 | /// Decl AST node, which points to a function prototype or variable declaration | ||
| 2017 | /// expression AST node. Next, navigate to the string literal of the `extern "foo"`. | ||
| 2018 | /// The Decl is determined contextually. | ||
| 2019 | node_offset_lib_name: i32, | ||
| 2202 | 2020 | ||
| 2203 | /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope. | 2021 | /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope. |
| 2204 | pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc { | 2022 | pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc { |
| 2205 | return switch (lazy) { | 2023 | return switch (lazy) { |
| 2206 | .unneeded, | 2024 | .unneeded, |
| 2025 | .entire_file, | ||
| 2207 | .byte_abs, | 2026 | .byte_abs, |
| 2208 | .token_abs, | 2027 | .token_abs, |
| 2209 | .node_abs, | 2028 | .node_abs, |
| 2210 | => .{ | 2029 | => .{ |
| 2211 | .container = .{ .file_scope = scope.getFileScope() }, | 2030 | .file_scope = scope.getFileScope(), |
| 2031 | .parent_decl_node = 0, | ||
| 2212 | .lazy = lazy, | 2032 | .lazy = lazy, |
| 2213 | }, | 2033 | }, |
| 2214 | 2034 | ||
| ... | @@ -2236,8 +2056,11 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -2236,8 +2056,11 @@ pub const LazySrcLoc = union(enum) { |
| 2236 | .node_offset_switch_range, | 2056 | .node_offset_switch_range, |
| 2237 | .node_offset_fn_type_cc, | 2057 | .node_offset_fn_type_cc, |
| 2238 | .node_offset_fn_type_ret_ty, | 2058 | .node_offset_fn_type_ret_ty, |
| 2059 | .node_offset_anyframe_type, | ||
| 2060 | .node_offset_lib_name, | ||
| 2239 | => .{ | 2061 | => .{ |
| 2240 | .container = .{ .decl = scope.srcDecl().? }, | 2062 | .file_scope = scope.getFileScope(), |
| 2063 | .parent_decl_node = scope.srcDecl().?.src_node, | ||
| 2241 | .lazy = lazy, | 2064 | .lazy = lazy, |
| 2242 | }, | 2065 | }, |
| 2243 | }; | 2066 | }; |
| ... | @@ -2247,11 +2070,13 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -2247,11 +2070,13 @@ pub const LazySrcLoc = union(enum) { |
| 2247 | pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc { | 2070 | pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc { |
| 2248 | return switch (lazy) { | 2071 | return switch (lazy) { |
| 2249 | .unneeded, | 2072 | .unneeded, |
| 2073 | .entire_file, | ||
| 2250 | .byte_abs, | 2074 | .byte_abs, |
| 2251 | .token_abs, | 2075 | .token_abs, |
| 2252 | .node_abs, | 2076 | .node_abs, |
| 2253 | => .{ | 2077 | => .{ |
| 2254 | .container = .{ .file_scope = decl.getFileScope() }, | 2078 | .file_scope = decl.getFileScope(), |
| 2079 | .parent_decl_node = 0, | ||
| 2255 | .lazy = lazy, | 2080 | .lazy = lazy, |
| 2256 | }, | 2081 | }, |
| 2257 | 2082 | ||
| ... | @@ -2279,8 +2104,11 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -2279,8 +2104,11 @@ pub const LazySrcLoc = union(enum) { |
| 2279 | .node_offset_switch_range, | 2104 | .node_offset_switch_range, |
| 2280 | .node_offset_fn_type_cc, | 2105 | .node_offset_fn_type_cc, |
| 2281 | .node_offset_fn_type_ret_ty, | 2106 | .node_offset_fn_type_ret_ty, |
| 2107 | .node_offset_anyframe_type, | ||
| 2108 | .node_offset_lib_name, | ||
| 2282 | => .{ | 2109 | => .{ |
| 2283 | .container = .{ .decl = decl }, | 2110 | .file_scope = decl.getFileScope(), |
| 2111 | .parent_decl_node = decl.src_node, | ||
| 2284 | .lazy = lazy, | 2112 | .lazy = lazy, |
| 2285 | }, | 2113 | }, |
| 2286 | }; | 2114 | }; |
| ... | @@ -2292,6 +2120,14 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail }; | ... | @@ -2292,6 +2120,14 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 2292 | pub fn deinit(mod: *Module) void { | 2120 | pub fn deinit(mod: *Module) void { |
| 2293 | const gpa = mod.gpa; | 2121 | const gpa = mod.gpa; |
| 2294 | 2122 | ||
| 2123 | for (mod.import_table.items()) |entry| { | ||
| 2124 | gpa.free(entry.key); | ||
| 2125 | entry.value.destroy(mod); | ||
| 2126 | } | ||
| 2127 | mod.import_table.deinit(gpa); | ||
| 2128 | |||
| 2129 | mod.deletion_set.deinit(gpa); | ||
| 2130 | |||
| 2295 | // The callsite of `Compilation.create` owns the `root_pkg`, however | 2131 | // The callsite of `Compilation.create` owns the `root_pkg`, however |
| 2296 | // Module owns the builtin and std packages that it adds. | 2132 | // Module owns the builtin and std packages that it adds. |
| 2297 | if (mod.root_pkg.table.remove("builtin")) |entry| { | 2133 | if (mod.root_pkg.table.remove("builtin")) |entry| { |
| ... | @@ -2309,26 +2145,25 @@ pub fn deinit(mod: *Module) void { | ... | @@ -2309,26 +2145,25 @@ pub fn deinit(mod: *Module) void { |
| 2309 | mod.compile_log_text.deinit(gpa); | 2145 | mod.compile_log_text.deinit(gpa); |
| 2310 | 2146 | ||
| 2311 | mod.zig_cache_artifact_directory.handle.close(); | 2147 | mod.zig_cache_artifact_directory.handle.close(); |
| 2312 | 2148 | mod.local_zir_cache.handle.close(); | |
| 2313 | mod.deletion_set.deinit(gpa); | 2149 | mod.global_zir_cache.handle.close(); |
| 2314 | |||
| 2315 | for (mod.decl_table.items()) |entry| { | ||
| 2316 | entry.value.destroy(mod); | ||
| 2317 | } | ||
| 2318 | mod.decl_table.deinit(gpa); | ||
| 2319 | 2150 | ||
| 2320 | for (mod.failed_decls.items()) |entry| { | 2151 | for (mod.failed_decls.items()) |entry| { |
| 2321 | entry.value.destroy(gpa); | 2152 | entry.value.destroy(gpa); |
| 2322 | } | 2153 | } |
| 2323 | mod.failed_decls.deinit(gpa); | 2154 | mod.failed_decls.deinit(gpa); |
| 2324 | 2155 | ||
| 2325 | for (mod.emit_h_failed_decls.items()) |entry| { | 2156 | if (mod.emit_h) |emit_h| { |
| 2326 | entry.value.destroy(gpa); | 2157 | for (emit_h.failed_decls.items()) |entry| { |
| 2158 | entry.value.destroy(gpa); | ||
| 2159 | } | ||
| 2160 | emit_h.failed_decls.deinit(gpa); | ||
| 2161 | emit_h.decl_table.deinit(gpa); | ||
| 2162 | gpa.destroy(emit_h); | ||
| 2327 | } | 2163 | } |
| 2328 | mod.emit_h_failed_decls.deinit(gpa); | ||
| 2329 | 2164 | ||
| 2330 | for (mod.failed_files.items()) |entry| { | 2165 | for (mod.failed_files.items()) |entry| { |
| 2331 | entry.value.destroy(gpa); | 2166 | if (entry.value) |msg| msg.destroy(gpa); |
| 2332 | } | 2167 | } |
| 2333 | mod.failed_files.deinit(gpa); | 2168 | mod.failed_files.deinit(gpa); |
| 2334 | 2169 | ||
| ... | @@ -2350,9 +2185,6 @@ pub fn deinit(mod: *Module) void { | ... | @@ -2350,9 +2185,6 @@ pub fn deinit(mod: *Module) void { |
| 2350 | } | 2185 | } |
| 2351 | mod.export_owners.deinit(gpa); | 2186 | mod.export_owners.deinit(gpa); |
| 2352 | 2187 | ||
| 2353 | mod.symbol_exports.deinit(gpa); | ||
| 2354 | mod.root_scope.destroy(gpa); | ||
| 2355 | |||
| 2356 | var it = mod.global_error_set.iterator(); | 2188 | var it = mod.global_error_set.iterator(); |
| 2357 | while (it.next()) |entry| { | 2189 | while (it.next()) |entry| { |
| 2358 | gpa.free(entry.key); | 2190 | gpa.free(entry.key); |
| ... | @@ -2360,11 +2192,6 @@ pub fn deinit(mod: *Module) void { | ... | @@ -2360,11 +2192,6 @@ pub fn deinit(mod: *Module) void { |
| 2360 | mod.global_error_set.deinit(gpa); | 2192 | mod.global_error_set.deinit(gpa); |
| 2361 | 2193 | ||
| 2362 | mod.error_name_list.deinit(gpa); | 2194 | mod.error_name_list.deinit(gpa); |
| 2363 | |||
| 2364 | for (mod.import_table.items()) |entry| { | ||
| 2365 | entry.value.destroy(gpa); | ||
| 2366 | } | ||
| 2367 | mod.import_table.deinit(gpa); | ||
| 2368 | } | 2195 | } |
| 2369 | 2196 | ||
| 2370 | fn freeExportList(gpa: *Allocator, export_list: []*Export) void { | 2197 | fn freeExportList(gpa: *Allocator, export_list: []*Export) void { |
| ... | @@ -2375,1260 +2202,1242 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void { | ... | @@ -2375,1260 +2202,1242 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void { |
| 2375 | gpa.free(export_list); | 2202 | gpa.free(export_list); |
| 2376 | } | 2203 | } |
| 2377 | 2204 | ||
| 2378 | pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { | 2205 | const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; |
| 2206 | // TODO This is taking advantage of matching stage1 debug union layout. | ||
| 2207 | // We need a better language feature for initializing a union with | ||
| 2208 | // a runtime known tag. | ||
| 2209 | const Stage1DataLayout = extern struct { | ||
| 2210 | data: [8]u8 align(8), | ||
| 2211 | safety_tag: u8, | ||
| 2212 | }; | ||
| 2213 | comptime { | ||
| 2214 | if (data_has_safety_tag) { | ||
| 2215 | assert(@sizeOf(Stage1DataLayout) == @sizeOf(Zir.Inst.Data)); | ||
| 2216 | } | ||
| 2217 | } | ||
| 2218 | |||
| 2219 | pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void { | ||
| 2379 | const tracy = trace(@src()); | 2220 | const tracy = trace(@src()); |
| 2380 | defer tracy.end(); | 2221 | defer tracy.end(); |
| 2381 | 2222 | ||
| 2382 | const subsequent_analysis = switch (decl.analysis) { | 2223 | const comp = mod.comp; |
| 2383 | .in_progress => unreachable, | 2224 | const gpa = mod.gpa; |
| 2384 | 2225 | ||
| 2385 | .sema_failure, | 2226 | // In any case we need to examine the stat of the file to determine the course of action. |
| 2386 | .sema_failure_retryable, | 2227 | var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); |
| 2387 | .codegen_failure, | 2228 | defer source_file.close(); |
| 2388 | .dependency_failure, | ||
| 2389 | .codegen_failure_retryable, | ||
| 2390 | => return error.AnalysisFail, | ||
| 2391 | 2229 | ||
| 2392 | .complete => return, | 2230 | const stat = try source_file.stat(); |
| 2393 | 2231 | ||
| 2394 | .outdated => blk: { | 2232 | const want_local_cache = file.pkg == mod.root_pkg; |
| 2395 | log.debug("re-analyzing {s}", .{decl.name}); | 2233 | const digest = hash: { |
| 2234 | var path_hash: Cache.HashHelper = .{}; | ||
| 2235 | if (!want_local_cache) { | ||
| 2236 | path_hash.addOptionalBytes(file.pkg.root_src_directory.path); | ||
| 2237 | } | ||
| 2238 | path_hash.addBytes(file.sub_file_path); | ||
| 2239 | break :hash path_hash.final(); | ||
| 2240 | }; | ||
| 2241 | const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache; | ||
| 2242 | const zir_dir = cache_directory.handle; | ||
| 2243 | |||
| 2244 | var cache_file: ?std.fs.File = null; | ||
| 2245 | defer if (cache_file) |f| f.close(); | ||
| 2246 | |||
| 2247 | // Determine whether we need to reload the file from disk and redo parsing and AstGen. | ||
| 2248 | switch (file.status) { | ||
| 2249 | .never_loaded, .retryable_failure => cached: { | ||
| 2250 | // First, load the cached ZIR code, if any. | ||
| 2251 | log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{ | ||
| 2252 | file.sub_file_path, want_local_cache, &digest, | ||
| 2253 | }); | ||
| 2396 | 2254 | ||
| 2397 | // The exports this Decl performs will be re-discovered, so we remove them here | 2255 | // We ask for a lock in order to coordinate with other zig processes. |
| 2398 | // prior to re-analysis. | 2256 | // If another process is already working on this file, we will get the cached |
| 2399 | mod.deleteDeclExports(decl); | 2257 | // version. Likewise if we're working on AstGen and another process asks for |
| 2400 | // Dependencies will be re-discovered, so we remove them here prior to re-analysis. | 2258 | // the cached file, they'll get it. |
| 2401 | for (decl.dependencies.items()) |entry| { | 2259 | cache_file = zir_dir.openFile(&digest, .{ .lock = .Shared }) catch |err| switch (err) { |
| 2402 | const dep = entry.key; | 2260 | error.PathAlreadyExists => unreachable, // opening for reading |
| 2403 | dep.removeDependant(decl); | 2261 | error.NoSpaceLeft => unreachable, // opening for reading |
| 2404 | if (dep.dependants.items().len == 0 and !dep.deletion_flag) { | 2262 | error.NotDir => unreachable, // no dir components |
| 2405 | // We don't perform a deletion here, because this Decl or another one | 2263 | error.InvalidUtf8 => unreachable, // it's a hex encoded name |
| 2406 | // may end up referencing it before the update is complete. | 2264 | error.BadPathName => unreachable, // it's a hex encoded name |
| 2407 | dep.deletion_flag = true; | 2265 | error.NameTooLong => unreachable, // it's a fixed size name |
| 2408 | try mod.deletion_set.put(mod.gpa, dep, {}); | 2266 | error.PipeBusy => unreachable, // it's not a pipe |
| 2409 | } | 2267 | error.WouldBlock => unreachable, // not asking for non-blocking I/O |
| 2410 | } | 2268 | |
| 2411 | decl.dependencies.clearRetainingCapacity(); | 2269 | error.SymLinkLoop, |
| 2270 | error.FileNotFound, | ||
| 2271 | error.Unexpected, | ||
| 2272 | => break :cached, | ||
| 2273 | |||
| 2274 | else => |e| return e, // Retryable errors are handled at callsite. | ||
| 2275 | }; | ||
| 2412 | 2276 | ||
| 2413 | break :blk true; | 2277 | // First we read the header to determine the lengths of arrays. |
| 2414 | }, | 2278 | const header = cache_file.?.reader().readStruct(Zir.Header) catch |err| switch (err) { |
| 2279 | // This can happen if Zig bails out of this function between creating | ||
| 2280 | // the cached file and writing it. | ||
| 2281 | error.EndOfStream => break :cached, | ||
| 2282 | else => |e| return e, | ||
| 2283 | }; | ||
| 2284 | const unchanged_metadata = | ||
| 2285 | stat.size == header.stat_size and | ||
| 2286 | stat.mtime == header.stat_mtime and | ||
| 2287 | stat.inode == header.stat_inode; | ||
| 2288 | |||
| 2289 | if (!unchanged_metadata) { | ||
| 2290 | log.debug("AstGen cache stale: {s}", .{file.sub_file_path}); | ||
| 2291 | break :cached; | ||
| 2292 | } | ||
| 2293 | log.debug("AstGen cache hit: {s} instructions_len={d}", .{ | ||
| 2294 | file.sub_file_path, header.instructions_len, | ||
| 2295 | }); | ||
| 2415 | 2296 | ||
| 2416 | .unreferenced => false, | 2297 | var instructions: std.MultiArrayList(Zir.Inst) = .{}; |
| 2417 | }; | 2298 | defer instructions.deinit(gpa); |
| 2418 | 2299 | ||
| 2419 | const type_changed = mod.astgenAndSemaDecl(decl) catch |err| switch (err) { | 2300 | try instructions.setCapacity(gpa, header.instructions_len); |
| 2420 | error.OutOfMemory => return error.OutOfMemory, | 2301 | instructions.len = header.instructions_len; |
| 2421 | error.AnalysisFail => return error.AnalysisFail, | ||
| 2422 | else => { | ||
| 2423 | decl.analysis = .sema_failure_retryable; | ||
| 2424 | try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1); | ||
| 2425 | mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( | ||
| 2426 | mod.gpa, | ||
| 2427 | decl.srcLoc(), | ||
| 2428 | "unable to analyze: {s}", | ||
| 2429 | .{@errorName(err)}, | ||
| 2430 | )); | ||
| 2431 | return error.AnalysisFail; | ||
| 2432 | }, | ||
| 2433 | }; | ||
| 2434 | 2302 | ||
| 2435 | if (subsequent_analysis) { | 2303 | var zir: Zir = .{ |
| 2436 | // We may need to chase the dependants and re-analyze them. | 2304 | .instructions = instructions.toOwnedSlice(), |
| 2437 | // However, if the decl is a function, and the type is the same, we do not need to. | 2305 | .string_bytes = &.{}, |
| 2438 | if (type_changed or decl.typed_value.most_recent.typed_value.val.tag() != .function) { | 2306 | .extra = &.{}, |
| 2439 | for (decl.dependants.items()) |entry| { | 2307 | }; |
| 2440 | const dep = entry.key; | 2308 | var keep_zir = false; |
| 2441 | switch (dep.analysis) { | 2309 | defer if (!keep_zir) zir.deinit(gpa); |
| 2442 | .unreferenced => unreachable, | 2310 | |
| 2443 | .in_progress => unreachable, | 2311 | zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); |
| 2444 | .outdated => continue, // already queued for update | 2312 | zir.extra = try gpa.alloc(u32, header.extra_len); |
| 2445 | 2313 | ||
| 2446 | .dependency_failure, | 2314 | const safety_buffer = if (data_has_safety_tag) |
| 2447 | .sema_failure, | 2315 | try gpa.alloc([8]u8, header.instructions_len) |
| 2448 | .sema_failure_retryable, | 2316 | else |
| 2449 | .codegen_failure, | 2317 | undefined; |
| 2450 | .codegen_failure_retryable, | 2318 | defer if (data_has_safety_tag) gpa.free(safety_buffer); |
| 2451 | .complete, | 2319 | |
| 2452 | => if (dep.generation != mod.generation) { | 2320 | const data_ptr = if (data_has_safety_tag) |
| 2453 | try mod.markOutdatedDecl(dep); | 2321 | @ptrCast([*]u8, safety_buffer.ptr) |
| 2454 | }, | 2322 | else |
| 2323 | @ptrCast([*]u8, zir.instructions.items(.data).ptr); | ||
| 2324 | |||
| 2325 | var iovecs = [_]std.os.iovec{ | ||
| 2326 | .{ | ||
| 2327 | .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr), | ||
| 2328 | .iov_len = header.instructions_len, | ||
| 2329 | }, | ||
| 2330 | .{ | ||
| 2331 | .iov_base = data_ptr, | ||
| 2332 | .iov_len = header.instructions_len * 8, | ||
| 2333 | }, | ||
| 2334 | .{ | ||
| 2335 | .iov_base = zir.string_bytes.ptr, | ||
| 2336 | .iov_len = header.string_bytes_len, | ||
| 2337 | }, | ||
| 2338 | .{ | ||
| 2339 | .iov_base = @ptrCast([*]u8, zir.extra.ptr), | ||
| 2340 | .iov_len = header.extra_len * 4, | ||
| 2341 | }, | ||
| 2342 | }; | ||
| 2343 | const amt_read = try cache_file.?.readvAll(&iovecs); | ||
| 2344 | const amt_expected = zir.instructions.len * 9 + | ||
| 2345 | zir.string_bytes.len + | ||
| 2346 | zir.extra.len * 4; | ||
| 2347 | if (amt_read != amt_expected) { | ||
| 2348 | log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}); | ||
| 2349 | zir.deinit(gpa); | ||
| 2350 | break :cached; | ||
| 2351 | } | ||
| 2352 | if (data_has_safety_tag) { | ||
| 2353 | const tags = zir.instructions.items(.tag); | ||
| 2354 | for (zir.instructions.items(.data)) |*data, i| { | ||
| 2355 | const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; | ||
| 2356 | const as_struct = @ptrCast(*Stage1DataLayout, data); | ||
| 2357 | as_struct.* = .{ | ||
| 2358 | .safety_tag = @enumToInt(union_tag), | ||
| 2359 | .data = safety_buffer[i], | ||
| 2360 | }; | ||
| 2455 | } | 2361 | } |
| 2456 | } | 2362 | } |
| 2457 | } | ||
| 2458 | } | ||
| 2459 | } | ||
| 2460 | 2363 | ||
| 2461 | /// Returns `true` if the Decl type changed. | 2364 | keep_zir = true; |
| 2462 | /// Returns `true` if this is the first time analyzing the Decl. | 2365 | file.zir = zir; |
| 2463 | /// Returns `false` otherwise. | 2366 | file.zir_loaded = true; |
| 2464 | fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { | 2367 | file.stat_size = header.stat_size; |
| 2465 | const tracy = trace(@src()); | 2368 | file.stat_inode = header.stat_inode; |
| 2466 | defer tracy.end(); | 2369 | file.stat_mtime = header.stat_mtime; |
| 2467 | 2370 | file.status = .success_zir; | |
| 2468 | const tree = try mod.getAstTree(decl.container.file_scope); | 2371 | log.debug("AstGen cached success: {s}", .{file.sub_file_path}); |
| 2469 | const node_tags = tree.nodes.items(.tag); | 2372 | |
| 2470 | const node_datas = tree.nodes.items(.data); | 2373 | // TODO don't report compile errors until Sema @importFile |
| 2471 | const decl_node = decl.src_node; | 2374 | if (file.zir.hasCompileErrors()) { |
| 2472 | switch (node_tags[decl_node]) { | 2375 | { |
| 2473 | .fn_decl => { | 2376 | const lock = comp.mutex.acquire(); |
| 2474 | const fn_proto = node_datas[decl_node].lhs; | 2377 | defer lock.release(); |
| 2475 | const body = node_datas[decl_node].rhs; | 2378 | try mod.failed_files.putNoClobber(gpa, file, null); |
| 2476 | switch (node_tags[fn_proto]) { | 2379 | } |
| 2477 | .fn_proto_simple => { | 2380 | file.status = .astgen_failure; |
| 2478 | var params: [1]ast.Node.Index = undefined; | 2381 | return error.AnalysisFail; |
| 2479 | return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(&params, fn_proto)); | ||
| 2480 | }, | ||
| 2481 | .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)), | ||
| 2482 | .fn_proto_one => { | ||
| 2483 | var params: [1]ast.Node.Index = undefined; | ||
| 2484 | return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(&params, fn_proto)); | ||
| 2485 | }, | ||
| 2486 | .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)), | ||
| 2487 | else => unreachable, | ||
| 2488 | } | 2382 | } |
| 2383 | return; | ||
| 2489 | }, | 2384 | }, |
| 2490 | .fn_proto_simple => { | 2385 | .parse_failure, .astgen_failure, .success_zir => { |
| 2491 | var params: [1]ast.Node.Index = undefined; | 2386 | const unchanged_metadata = |
| 2492 | return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(&params, decl_node)); | 2387 | stat.size == file.stat_size and |
| 2388 | stat.mtime == file.stat_mtime and | ||
| 2389 | stat.inode == file.stat_inode; | ||
| 2390 | |||
| 2391 | if (unchanged_metadata) { | ||
| 2392 | log.debug("unmodified metadata of file: {s}", .{file.sub_file_path}); | ||
| 2393 | return; | ||
| 2394 | } | ||
| 2395 | |||
| 2396 | log.debug("metadata changed: {s}", .{file.sub_file_path}); | ||
| 2493 | }, | 2397 | }, |
| 2494 | .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)), | 2398 | } |
| 2495 | .fn_proto_one => { | 2399 | if (cache_file) |f| { |
| 2496 | var params: [1]ast.Node.Index = undefined; | 2400 | f.close(); |
| 2497 | return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(&params, decl_node)); | 2401 | cache_file = null; |
| 2402 | } | ||
| 2403 | cache_file = zir_dir.createFile(&digest, .{ .lock = .Exclusive }) catch |err| switch (err) { | ||
| 2404 | error.NotDir => unreachable, // no dir components | ||
| 2405 | error.InvalidUtf8 => unreachable, // it's a hex encoded name | ||
| 2406 | error.BadPathName => unreachable, // it's a hex encoded name | ||
| 2407 | error.NameTooLong => unreachable, // it's a fixed size name | ||
| 2408 | error.PipeBusy => unreachable, // it's not a pipe | ||
| 2409 | error.WouldBlock => unreachable, // not asking for non-blocking I/O | ||
| 2410 | error.FileNotFound => unreachable, // no dir components | ||
| 2411 | |||
| 2412 | else => |e| { | ||
| 2413 | const pkg_path = file.pkg.root_src_directory.path orelse "."; | ||
| 2414 | const cache_path = cache_directory.path orelse "."; | ||
| 2415 | log.warn("unable to save cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{ | ||
| 2416 | pkg_path, file.sub_file_path, cache_path, &digest, @errorName(e), | ||
| 2417 | }); | ||
| 2418 | return; | ||
| 2498 | }, | 2419 | }, |
| 2499 | .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)), | 2420 | }; |
| 2500 | |||
| 2501 | .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)), | ||
| 2502 | .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)), | ||
| 2503 | .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)), | ||
| 2504 | .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)), | ||
| 2505 | |||
| 2506 | .@"comptime" => { | ||
| 2507 | decl.analysis = .in_progress; | ||
| 2508 | |||
| 2509 | // A comptime decl does not store any value so we can just deinit this arena after analysis is done. | ||
| 2510 | var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa); | ||
| 2511 | defer analysis_arena.deinit(); | ||
| 2512 | |||
| 2513 | var code: zir.Code = blk: { | ||
| 2514 | var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator); | ||
| 2515 | defer astgen.deinit(); | ||
| 2516 | |||
| 2517 | var gen_scope: Scope.GenZir = .{ | ||
| 2518 | .force_comptime = true, | ||
| 2519 | .parent = &decl.container.base, | ||
| 2520 | .astgen = &astgen, | ||
| 2521 | }; | ||
| 2522 | defer gen_scope.instructions.deinit(mod.gpa); | ||
| 2523 | |||
| 2524 | const block_expr = node_datas[decl_node].lhs; | ||
| 2525 | _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr); | ||
| 2526 | _ = try gen_scope.addBreak(.break_inline, 0, .void_value); | ||
| 2527 | 2421 | ||
| 2528 | const code = try gen_scope.finish(); | 2422 | mod.lockAndClearFileCompileError(file); |
| 2529 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | 2423 | |
| 2530 | code.dump(mod.gpa, "comptime_block", &gen_scope.base, 0) catch {}; | 2424 | // If the previous ZIR does not have compile errors, keep it around |
| 2531 | } | 2425 | // in case parsing or new ZIR fails. In case of successful ZIR update |
| 2532 | break :blk code; | 2426 | // at the end of this function we will free it. |
| 2533 | }; | 2427 | // We keep the previous ZIR loaded so that we can use it |
| 2534 | defer code.deinit(mod.gpa); | 2428 | // for the update next time it does not have any compile errors. This avoids |
| 2535 | 2429 | // needlessly tossing out semantic analysis work when an error is | |
| 2536 | var sema: Sema = .{ | 2430 | // temporarily introduced. |
| 2537 | .mod = mod, | 2431 | if (file.zir_loaded and !file.zir.hasCompileErrors()) { |
| 2538 | .gpa = mod.gpa, | 2432 | assert(file.prev_zir == null); |
| 2539 | .arena = &analysis_arena.allocator, | 2433 | const prev_zir_ptr = try gpa.create(Zir); |
| 2540 | .code = code, | 2434 | file.prev_zir = prev_zir_ptr; |
| 2541 | .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len), | 2435 | prev_zir_ptr.* = file.zir; |
| 2542 | .owner_decl = decl, | 2436 | file.zir = undefined; |
| 2543 | .func = null, | 2437 | file.zir_loaded = false; |
| 2544 | .owner_func = null, | 2438 | } |
| 2545 | .param_inst_list = &.{}, | 2439 | file.unload(gpa); |
| 2546 | }; | ||
| 2547 | var block_scope: Scope.Block = .{ | ||
| 2548 | .parent = null, | ||
| 2549 | .sema = &sema, | ||
| 2550 | .src_decl = decl, | ||
| 2551 | .instructions = .{}, | ||
| 2552 | .inlining = null, | ||
| 2553 | .is_comptime = true, | ||
| 2554 | }; | ||
| 2555 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 2556 | 2440 | ||
| 2557 | _ = try sema.root(&block_scope); | 2441 | if (stat.size > std.math.maxInt(u32)) |
| 2442 | return error.FileTooBig; | ||
| 2558 | 2443 | ||
| 2559 | decl.analysis = .complete; | 2444 | const source = try gpa.allocSentinel(u8, stat.size, 0); |
| 2560 | decl.generation = mod.generation; | 2445 | defer if (!file.source_loaded) gpa.free(source); |
| 2561 | return true; | 2446 | const amt = try source_file.readAll(source); |
| 2562 | }, | 2447 | if (amt != stat.size) |
| 2563 | .@"usingnamespace" => @panic("TODO usingnamespace decl"), | 2448 | return error.UnexpectedEndOfFile; |
| 2564 | else => unreachable, | ||
| 2565 | } | ||
| 2566 | } | ||
| 2567 | 2449 | ||
| 2568 | fn astgenAndSemaFn( | 2450 | file.stat_size = stat.size; |
| 2569 | mod: *Module, | 2451 | file.stat_inode = stat.inode; |
| 2570 | decl: *Decl, | 2452 | file.stat_mtime = stat.mtime; |
| 2571 | tree: ast.Tree, | 2453 | file.source = source; |
| 2572 | body_node: ast.Node.Index, | 2454 | file.source_loaded = true; |
| 2573 | fn_proto: ast.full.FnProto, | ||
| 2574 | ) !bool { | ||
| 2575 | const tracy = trace(@src()); | ||
| 2576 | defer tracy.end(); | ||
| 2577 | 2455 | ||
| 2578 | decl.analysis = .in_progress; | 2456 | file.tree = try std.zig.parse(gpa, source); |
| 2457 | defer if (!file.tree_loaded) file.tree.deinit(gpa); | ||
| 2579 | 2458 | ||
| 2580 | const token_tags = tree.tokens.items(.tag); | 2459 | if (file.tree.errors.len != 0) { |
| 2460 | const parse_err = file.tree.errors[0]; | ||
| 2581 | 2461 | ||
| 2582 | // This arena allocator's memory is discarded at the end of this function. It is used | 2462 | var msg = std.ArrayList(u8).init(gpa); |
| 2583 | // to determine the type of the function, and hence the type of the decl, which is needed | 2463 | defer msg.deinit(); |
| 2584 | // to complete the Decl analysis. | ||
| 2585 | var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | ||
| 2586 | defer fn_type_scope_arena.deinit(); | ||
| 2587 | 2464 | ||
| 2588 | var fn_type_astgen = try AstGen.init(mod, decl, &fn_type_scope_arena.allocator); | 2465 | const token_starts = file.tree.tokens.items(.start); |
| 2589 | defer fn_type_astgen.deinit(); | ||
| 2590 | 2466 | ||
| 2591 | var fn_type_scope: Scope.GenZir = .{ | 2467 | try file.tree.renderError(parse_err, msg.writer()); |
| 2592 | .force_comptime = true, | 2468 | const err_msg = try gpa.create(ErrorMsg); |
| 2593 | .parent = &decl.container.base, | 2469 | err_msg.* = .{ |
| 2594 | .astgen = &fn_type_astgen, | 2470 | .src_loc = .{ |
| 2595 | }; | 2471 | .file_scope = file, |
| 2596 | defer fn_type_scope.instructions.deinit(mod.gpa); | 2472 | .parent_decl_node = 0, |
| 2597 | 2473 | .lazy = .{ .byte_abs = token_starts[parse_err.token] }, | |
| 2598 | decl.is_pub = fn_proto.visib_token != null; | 2474 | }, |
| 2599 | 2475 | .msg = msg.toOwnedSlice(), | |
| 2600 | // The AST params array does not contain anytype and ... parameters. | 2476 | }; |
| 2601 | // We must iterate to count how many param types to allocate. | ||
| 2602 | const param_count = blk: { | ||
| 2603 | var count: usize = 0; | ||
| 2604 | var it = fn_proto.iterate(tree); | ||
| 2605 | while (it.next()) |param| { | ||
| 2606 | if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break; | ||
| 2607 | count += 1; | ||
| 2608 | } | ||
| 2609 | break :blk count; | ||
| 2610 | }; | ||
| 2611 | const param_types = try fn_type_scope_arena.allocator.alloc(zir.Inst.Ref, param_count); | ||
| 2612 | 2477 | ||
| 2613 | var is_var_args = false; | 2478 | { |
| 2614 | { | 2479 | const lock = comp.mutex.acquire(); |
| 2615 | var param_type_i: usize = 0; | 2480 | defer lock.release(); |
| 2616 | var it = fn_proto.iterate(tree); | 2481 | try mod.failed_files.putNoClobber(gpa, file, err_msg); |
| 2617 | while (it.next()) |param| : (param_type_i += 1) { | ||
| 2618 | if (param.anytype_ellipsis3) |token| { | ||
| 2619 | switch (token_tags[token]) { | ||
| 2620 | .keyword_anytype => return mod.failTok( | ||
| 2621 | &fn_type_scope.base, | ||
| 2622 | token, | ||
| 2623 | "TODO implement anytype parameter", | ||
| 2624 | .{}, | ||
| 2625 | ), | ||
| 2626 | .ellipsis3 => { | ||
| 2627 | is_var_args = true; | ||
| 2628 | break; | ||
| 2629 | }, | ||
| 2630 | else => unreachable, | ||
| 2631 | } | ||
| 2632 | } | ||
| 2633 | const param_type_node = param.type_expr; | ||
| 2634 | assert(param_type_node != 0); | ||
| 2635 | param_types[param_type_i] = | ||
| 2636 | try AstGen.expr(&fn_type_scope, &fn_type_scope.base, .{ .ty = .type_type }, param_type_node); | ||
| 2637 | } | ||
| 2638 | assert(param_type_i == param_count); | ||
| 2639 | } | ||
| 2640 | if (fn_proto.lib_name) |lib_name_token| blk: { | ||
| 2641 | // TODO call std.zig.parseStringLiteral | ||
| 2642 | const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name_token), "\""); | ||
| 2643 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str}); | ||
| 2644 | const target = mod.comp.getTarget(); | ||
| 2645 | if (target_util.is_libc_lib_name(target, lib_name_str)) { | ||
| 2646 | if (!mod.comp.bin_file.options.link_libc) { | ||
| 2647 | return mod.failTok( | ||
| 2648 | &fn_type_scope.base, | ||
| 2649 | lib_name_token, | ||
| 2650 | "dependency on libc must be explicitly specified in the build command", | ||
| 2651 | .{}, | ||
| 2652 | ); | ||
| 2653 | } | ||
| 2654 | break :blk; | ||
| 2655 | } | ||
| 2656 | if (target_util.is_libcpp_lib_name(target, lib_name_str)) { | ||
| 2657 | if (!mod.comp.bin_file.options.link_libcpp) { | ||
| 2658 | return mod.failTok( | ||
| 2659 | &fn_type_scope.base, | ||
| 2660 | lib_name_token, | ||
| 2661 | "dependency on libc++ must be explicitly specified in the build command", | ||
| 2662 | .{}, | ||
| 2663 | ); | ||
| 2664 | } | ||
| 2665 | break :blk; | ||
| 2666 | } | ||
| 2667 | if (!target.isWasm() and !mod.comp.bin_file.options.pic) { | ||
| 2668 | return mod.failTok( | ||
| 2669 | &fn_type_scope.base, | ||
| 2670 | lib_name_token, | ||
| 2671 | "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", | ||
| 2672 | .{ lib_name_str, lib_name_str }, | ||
| 2673 | ); | ||
| 2674 | } | 2482 | } |
| 2675 | mod.comp.stage1AddLinkLib(lib_name_str) catch |err| { | 2483 | file.status = .parse_failure; |
| 2676 | return mod.failTok( | 2484 | return error.AnalysisFail; |
| 2677 | &fn_type_scope.base, | ||
| 2678 | lib_name_token, | ||
| 2679 | "unable to add link lib '{s}': {s}", | ||
| 2680 | .{ lib_name_str, @errorName(err) }, | ||
| 2681 | ); | ||
| 2682 | }; | ||
| 2683 | } | 2485 | } |
| 2684 | if (fn_proto.ast.align_expr != 0) { | 2486 | file.tree_loaded = true; |
| 2685 | return mod.failNode( | ||
| 2686 | &fn_type_scope.base, | ||
| 2687 | fn_proto.ast.align_expr, | ||
| 2688 | "TODO implement function align expression", | ||
| 2689 | .{}, | ||
| 2690 | ); | ||
| 2691 | } | ||
| 2692 | if (fn_proto.ast.section_expr != 0) { | ||
| 2693 | return mod.failNode( | ||
| 2694 | &fn_type_scope.base, | ||
| 2695 | fn_proto.ast.section_expr, | ||
| 2696 | "TODO implement function section expression", | ||
| 2697 | .{}, | ||
| 2698 | ); | ||
| 2699 | } | ||
| 2700 | |||
| 2701 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; | ||
| 2702 | if (token_tags[maybe_bang] == .bang) { | ||
| 2703 | return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{}); | ||
| 2704 | } | ||
| 2705 | const return_type_inst = try AstGen.expr( | ||
| 2706 | &fn_type_scope, | ||
| 2707 | &fn_type_scope.base, | ||
| 2708 | .{ .ty = .type_type }, | ||
| 2709 | fn_proto.ast.return_type, | ||
| 2710 | ); | ||
| 2711 | 2487 | ||
| 2712 | const is_extern = if (fn_proto.extern_export_token) |maybe_export_token| | 2488 | file.zir = try AstGen.generate(gpa, file.tree); |
| 2713 | token_tags[maybe_export_token] == .keyword_extern | 2489 | file.zir_loaded = true; |
| 2490 | file.status = .success_zir; | ||
| 2491 | log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); | ||
| 2492 | |||
| 2493 | const safety_buffer = if (data_has_safety_tag) | ||
| 2494 | try gpa.alloc([8]u8, file.zir.instructions.len) | ||
| 2714 | else | 2495 | else |
| 2715 | false; | 2496 | undefined; |
| 2716 | 2497 | defer if (data_has_safety_tag) gpa.free(safety_buffer); | |
| 2717 | const cc: zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) | 2498 | const data_ptr = if (data_has_safety_tag) |
| 2718 | // TODO instead of enum literal type, this needs to be the | 2499 | @ptrCast([*]const u8, safety_buffer.ptr) |
| 2719 | // std.builtin.CallingConvention enum. We need to implement importing other files | ||
| 2720 | // and enums in order to fix this. | ||
| 2721 | try AstGen.comptimeExpr( | ||
| 2722 | &fn_type_scope, | ||
| 2723 | &fn_type_scope.base, | ||
| 2724 | .{ .ty = .enum_literal_type }, | ||
| 2725 | fn_proto.ast.callconv_expr, | ||
| 2726 | ) | ||
| 2727 | else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269 | ||
| 2728 | try fn_type_scope.addSmallStr(.enum_literal_small, "C") | ||
| 2729 | else | 2500 | else |
| 2730 | .none; | 2501 | @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr); |
| 2731 | 2502 | if (data_has_safety_tag) { | |
| 2732 | const fn_type_inst: zir.Inst.Ref = if (cc != .none) fn_type: { | 2503 | // The `Data` union has a safety tag but in the file format we store it without. |
| 2733 | const tag: zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc; | 2504 | const tags = file.zir.instructions.items(.tag); |
| 2734 | break :fn_type try fn_type_scope.addFnTypeCc(tag, .{ | 2505 | for (file.zir.instructions.items(.data)) |*data, i| { |
| 2735 | .src_node = fn_proto.ast.proto_node, | 2506 | const as_struct = @ptrCast(*const Stage1DataLayout, data); |
| 2736 | .ret_ty = return_type_inst, | 2507 | safety_buffer[i] = as_struct.data; |
| 2737 | .param_types = param_types, | 2508 | } |
| 2738 | .cc = cc, | ||
| 2739 | }); | ||
| 2740 | } else fn_type: { | ||
| 2741 | const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type; | ||
| 2742 | break :fn_type try fn_type_scope.addFnType(tag, .{ | ||
| 2743 | .src_node = fn_proto.ast.proto_node, | ||
| 2744 | .ret_ty = return_type_inst, | ||
| 2745 | .param_types = param_types, | ||
| 2746 | }); | ||
| 2747 | }; | ||
| 2748 | _ = try fn_type_scope.addBreak(.break_inline, 0, fn_type_inst); | ||
| 2749 | |||
| 2750 | // We need the memory for the Type to go into the arena for the Decl | ||
| 2751 | var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); | ||
| 2752 | errdefer decl_arena.deinit(); | ||
| 2753 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 2754 | |||
| 2755 | var fn_type_code = try fn_type_scope.finish(); | ||
| 2756 | defer fn_type_code.deinit(mod.gpa); | ||
| 2757 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | ||
| 2758 | fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {}; | ||
| 2759 | } | 2509 | } |
| 2760 | 2510 | ||
| 2761 | var fn_type_sema: Sema = .{ | 2511 | const header: Zir.Header = .{ |
| 2762 | .mod = mod, | 2512 | .instructions_len = @intCast(u32, file.zir.instructions.len), |
| 2763 | .gpa = mod.gpa, | 2513 | .string_bytes_len = @intCast(u32, file.zir.string_bytes.len), |
| 2764 | .arena = &decl_arena.allocator, | 2514 | .extra_len = @intCast(u32, file.zir.extra.len), |
| 2765 | .code = fn_type_code, | 2515 | |
| 2766 | .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len), | 2516 | .stat_size = stat.size, |
| 2767 | .owner_decl = decl, | 2517 | .stat_inode = stat.inode, |
| 2768 | .func = null, | 2518 | .stat_mtime = stat.mtime, |
| 2769 | .owner_func = null, | ||
| 2770 | .param_inst_list = &.{}, | ||
| 2771 | }; | 2519 | }; |
| 2772 | var block_scope: Scope.Block = .{ | 2520 | var iovecs = [_]std.os.iovec_const{ |
| 2773 | .parent = null, | 2521 | .{ |
| 2774 | .sema = &fn_type_sema, | 2522 | .iov_base = @ptrCast([*]const u8, &header), |
| 2775 | .src_decl = decl, | 2523 | .iov_len = @sizeOf(Zir.Header), |
| 2776 | .instructions = .{}, | 2524 | }, |
| 2777 | .inlining = null, | 2525 | .{ |
| 2778 | .is_comptime = true, | 2526 | .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr), |
| 2527 | .iov_len = file.zir.instructions.len, | ||
| 2528 | }, | ||
| 2529 | .{ | ||
| 2530 | .iov_base = data_ptr, | ||
| 2531 | .iov_len = file.zir.instructions.len * 8, | ||
| 2532 | }, | ||
| 2533 | .{ | ||
| 2534 | .iov_base = file.zir.string_bytes.ptr, | ||
| 2535 | .iov_len = file.zir.string_bytes.len, | ||
| 2536 | }, | ||
| 2537 | .{ | ||
| 2538 | .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr), | ||
| 2539 | .iov_len = file.zir.extra.len * 4, | ||
| 2540 | }, | ||
| 2541 | }; | ||
| 2542 | cache_file.?.writevAll(&iovecs) catch |err| { | ||
| 2543 | const pkg_path = file.pkg.root_src_directory.path orelse "."; | ||
| 2544 | const cache_path = cache_directory.path orelse "."; | ||
| 2545 | log.warn("unable to write cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{ | ||
| 2546 | pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err), | ||
| 2547 | }); | ||
| 2779 | }; | 2548 | }; |
| 2780 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 2781 | |||
| 2782 | const fn_type = try fn_type_sema.rootAsType(&block_scope); | ||
| 2783 | if (body_node == 0) { | ||
| 2784 | if (!is_extern) { | ||
| 2785 | return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{}); | ||
| 2786 | } | ||
| 2787 | |||
| 2788 | // Extern function. | ||
| 2789 | var type_changed = true; | ||
| 2790 | if (decl.typedValueManaged()) |tvm| { | ||
| 2791 | type_changed = !tvm.typed_value.ty.eql(fn_type); | ||
| 2792 | |||
| 2793 | tvm.deinit(mod.gpa); | ||
| 2794 | } | ||
| 2795 | const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl); | ||
| 2796 | |||
| 2797 | decl_arena_state.* = decl_arena.state; | ||
| 2798 | decl.typed_value = .{ | ||
| 2799 | .most_recent = .{ | ||
| 2800 | .typed_value = .{ .ty = fn_type, .val = fn_val }, | ||
| 2801 | .arena = decl_arena_state, | ||
| 2802 | }, | ||
| 2803 | }; | ||
| 2804 | decl.analysis = .complete; | ||
| 2805 | decl.generation = mod.generation; | ||
| 2806 | |||
| 2807 | try mod.comp.bin_file.allocateDeclIndexes(decl); | ||
| 2808 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | ||
| 2809 | 2549 | ||
| 2810 | if (type_changed and mod.emit_h != null) { | 2550 | if (file.zir.hasCompileErrors()) { |
| 2811 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); | 2551 | { |
| 2552 | const lock = comp.mutex.acquire(); | ||
| 2553 | defer lock.release(); | ||
| 2554 | try mod.failed_files.putNoClobber(gpa, file, null); | ||
| 2812 | } | 2555 | } |
| 2813 | 2556 | file.status = .astgen_failure; | |
| 2814 | return type_changed; | 2557 | return error.AnalysisFail; |
| 2815 | } | 2558 | } |
| 2816 | 2559 | ||
| 2817 | if (fn_type.fnIsVarArgs()) { | 2560 | if (file.prev_zir) |prev_zir| { |
| 2818 | return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{}); | 2561 | // Iterate over all Namespace objects contained within this File, looking at the |
| 2562 | // previous and new ZIR together and update the references to point | ||
| 2563 | // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace | ||
| 2564 | // decl_table keys need to get updated to point to the new memory, even if the | ||
| 2565 | // underlying source code is unchanged. | ||
| 2566 | // We do not need to hold any locks at this time because all the Decl and Namespace | ||
| 2567 | // objects being touched are specific to this File, and the only other concurrent | ||
| 2568 | // tasks are touching other File objects. | ||
| 2569 | try updateZirRefs(gpa, file, prev_zir.*); | ||
| 2570 | // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, | ||
| 2571 | // and semantic analysis will deal with them properly. | ||
| 2572 | // No need to keep previous ZIR. | ||
| 2573 | prev_zir.deinit(gpa); | ||
| 2574 | gpa.destroy(prev_zir); | ||
| 2575 | file.prev_zir = null; | ||
| 2576 | } else if (file.root_decl) |root_decl| { | ||
| 2577 | // This is an update, but it is the first time the File has succeeded | ||
| 2578 | // ZIR. We must mark it outdated since we have already tried to | ||
| 2579 | // semantically analyze it. | ||
| 2580 | try file.outdated_decls.resize(gpa, 1); | ||
| 2581 | file.outdated_decls.items[0] = root_decl; | ||
| 2819 | } | 2582 | } |
| 2583 | } | ||
| 2820 | 2584 | ||
| 2821 | const new_func = try decl_arena.allocator.create(Fn); | 2585 | /// Patch ups: |
| 2822 | const fn_payload = try decl_arena.allocator.create(Value.Payload.Function); | 2586 | /// * Struct.zir_index |
| 2587 | /// * Decl.zir_index | ||
| 2588 | /// * Fn.zir_body_inst | ||
| 2589 | /// * Decl.zir_decl_index | ||
| 2590 | fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void { | ||
| 2591 | const new_zir = file.zir; | ||
| 2592 | |||
| 2593 | // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which | ||
| 2594 | // creates a namespace, gets mapped from old to new here. | ||
| 2595 | var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; | ||
| 2596 | defer inst_map.deinit(gpa); | ||
| 2597 | // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item. | ||
| 2598 | // e.g. the thing that Decl.zir_decl_index points to. | ||
| 2599 | var extra_map: std.AutoHashMapUnmanaged(u32, u32) = .{}; | ||
| 2600 | defer extra_map.deinit(gpa); | ||
| 2601 | |||
| 2602 | try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map); | ||
| 2603 | |||
| 2604 | // Walk the Decl graph, updating ZIR indexes, strings, and populating | ||
| 2605 | // the deleted and outdated lists. | ||
| 2606 | |||
| 2607 | var decl_stack: std.ArrayListUnmanaged(*Decl) = .{}; | ||
| 2608 | defer decl_stack.deinit(gpa); | ||
| 2609 | |||
| 2610 | const root_decl = file.root_decl.?; | ||
| 2611 | try decl_stack.append(gpa, root_decl); | ||
| 2612 | |||
| 2613 | file.deleted_decls.clearRetainingCapacity(); | ||
| 2614 | file.outdated_decls.clearRetainingCapacity(); | ||
| 2615 | |||
| 2616 | // The root decl is always outdated; otherwise we would not have had | ||
| 2617 | // to re-generate ZIR for the File. | ||
| 2618 | try file.outdated_decls.append(gpa, root_decl); | ||
| 2619 | |||
| 2620 | while (decl_stack.popOrNull()) |decl| { | ||
| 2621 | // Anonymous decls and the root decl have this set to 0. We still need | ||
| 2622 | // to walk them but we do not need to modify this value. | ||
| 2623 | // Anonymous decls should not be marked outdated. They will be re-generated | ||
| 2624 | // if their owner decl is marked outdated. | ||
| 2625 | if (decl.zir_decl_index != 0) { | ||
| 2626 | const old_zir_decl_index = decl.zir_decl_index; | ||
| 2627 | const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { | ||
| 2628 | log.debug("updateZirRefs {s}: delete {*} ({s})", .{ | ||
| 2629 | file.sub_file_path, decl, decl.name, | ||
| 2630 | }); | ||
| 2631 | try file.deleted_decls.append(gpa, decl); | ||
| 2632 | continue; | ||
| 2633 | }; | ||
| 2634 | const old_hash = decl.contentsHashZir(old_zir); | ||
| 2635 | decl.zir_decl_index = new_zir_decl_index; | ||
| 2636 | const new_hash = decl.contentsHashZir(new_zir); | ||
| 2637 | if (!std.zig.srcHashEql(old_hash, new_hash)) { | ||
| 2638 | log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ | ||
| 2639 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, | ||
| 2640 | }); | ||
| 2641 | try file.outdated_decls.append(gpa, decl); | ||
| 2642 | } else { | ||
| 2643 | log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ | ||
| 2644 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, | ||
| 2645 | }); | ||
| 2646 | } | ||
| 2647 | } | ||
| 2823 | 2648 | ||
| 2824 | const fn_zir: zir.Code = blk: { | 2649 | if (!decl.owns_tv) continue; |
| 2825 | // We put the ZIR inside the Decl arena. | ||
| 2826 | var astgen = try AstGen.init(mod, decl, &decl_arena.allocator); | ||
| 2827 | astgen.ref_start_index = @intCast(u32, zir.Inst.Ref.typed_value_map.len + param_count); | ||
| 2828 | defer astgen.deinit(); | ||
| 2829 | 2650 | ||
| 2830 | var gen_scope: Scope.GenZir = .{ | 2651 | if (decl.getStruct()) |struct_obj| { |
| 2831 | .force_comptime = false, | 2652 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { |
| 2832 | .parent = &decl.container.base, | 2653 | try file.deleted_decls.append(gpa, decl); |
| 2833 | .astgen = &astgen, | 2654 | continue; |
| 2834 | }; | ||
| 2835 | defer gen_scope.instructions.deinit(mod.gpa); | ||
| 2836 | |||
| 2837 | // Iterate over the parameters. We put the param names as the first N | ||
| 2838 | // items inside `extra` so that debug info later can refer to the parameter names | ||
| 2839 | // even while the respective source code is unloaded. | ||
| 2840 | try astgen.extra.ensureCapacity(mod.gpa, param_count); | ||
| 2841 | |||
| 2842 | var params_scope = &gen_scope.base; | ||
| 2843 | var i: usize = 0; | ||
| 2844 | var it = fn_proto.iterate(tree); | ||
| 2845 | while (it.next()) |param| : (i += 1) { | ||
| 2846 | const name_token = param.name_token.?; | ||
| 2847 | const param_name = try mod.identifierTokenString(&gen_scope.base, name_token); | ||
| 2848 | const sub_scope = try decl_arena.allocator.create(Scope.LocalVal); | ||
| 2849 | sub_scope.* = .{ | ||
| 2850 | .parent = params_scope, | ||
| 2851 | .gen_zir = &gen_scope, | ||
| 2852 | .name = param_name, | ||
| 2853 | // Implicit const list first, then implicit arg list. | ||
| 2854 | .inst = @intToEnum(zir.Inst.Ref, @intCast(u32, zir.Inst.Ref.typed_value_map.len + i)), | ||
| 2855 | .src = decl.tokSrcLoc(name_token), | ||
| 2856 | }; | 2655 | }; |
| 2857 | params_scope = &sub_scope.base; | ||
| 2858 | |||
| 2859 | // Additionally put the param name into `string_bytes` and reference it with | ||
| 2860 | // `extra` so that we have access to the data in codegen, for debug info. | ||
| 2861 | const str_index = @intCast(u32, astgen.string_bytes.items.len); | ||
| 2862 | astgen.extra.appendAssumeCapacity(str_index); | ||
| 2863 | const used_bytes = astgen.string_bytes.items.len; | ||
| 2864 | try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1); | ||
| 2865 | astgen.string_bytes.appendSliceAssumeCapacity(param_name); | ||
| 2866 | astgen.string_bytes.appendAssumeCapacity(0); | ||
| 2867 | } | 2656 | } |
| 2868 | 2657 | ||
| 2869 | _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node); | 2658 | if (decl.getUnion()) |union_obj| { |
| 2659 | union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { | ||
| 2660 | try file.deleted_decls.append(gpa, decl); | ||
| 2661 | continue; | ||
| 2662 | }; | ||
| 2663 | } | ||
| 2870 | 2664 | ||
| 2871 | if (gen_scope.instructions.items.len == 0 or | 2665 | if (decl.getFunction()) |func| { |
| 2872 | !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1] | 2666 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { |
| 2873 | .isNoReturn()) | 2667 | try file.deleted_decls.append(gpa, decl); |
| 2874 | { | 2668 | continue; |
| 2875 | // astgen uses result location semantics to coerce return operands. | 2669 | }; |
| 2876 | // Since we are adding the return instruction here, we must handle the coercion. | ||
| 2877 | // We do this by using the `ret_coerce` instruction. | ||
| 2878 | _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); | ||
| 2879 | } | 2670 | } |
| 2880 | 2671 | ||
| 2881 | const code = try gen_scope.finish(); | 2672 | if (decl.getInnerNamespace()) |namespace| { |
| 2882 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | 2673 | for (namespace.decls.items()) |entry| { |
| 2883 | code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {}; | 2674 | const sub_decl = entry.value; |
| 2675 | try decl_stack.append(gpa, sub_decl); | ||
| 2676 | } | ||
| 2677 | for (namespace.anon_decls.items()) |entry| { | ||
| 2678 | const sub_decl = entry.key; | ||
| 2679 | try decl_stack.append(gpa, sub_decl); | ||
| 2680 | } | ||
| 2884 | } | 2681 | } |
| 2682 | } | ||
| 2683 | } | ||
| 2885 | 2684 | ||
| 2886 | break :blk code; | 2685 | pub fn mapOldZirToNew( |
| 2686 | gpa: *Allocator, | ||
| 2687 | old_zir: Zir, | ||
| 2688 | new_zir: Zir, | ||
| 2689 | inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), | ||
| 2690 | extra_map: *std.AutoHashMapUnmanaged(u32, u32), | ||
| 2691 | ) Allocator.Error!void { | ||
| 2692 | // Contain ZIR indexes of declaration instructions. | ||
| 2693 | const MatchedZirDecl = struct { | ||
| 2694 | old_inst: Zir.Inst.Index, | ||
| 2695 | new_inst: Zir.Inst.Index, | ||
| 2887 | }; | 2696 | }; |
| 2697 | var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{}; | ||
| 2698 | defer match_stack.deinit(gpa); | ||
| 2888 | 2699 | ||
| 2889 | const is_inline = fn_type.fnCallingConvention() == .Inline; | 2700 | const old_main_struct_inst = old_zir.getMainStruct(); |
| 2890 | const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued; | 2701 | const new_main_struct_inst = new_zir.getMainStruct(); |
| 2891 | 2702 | ||
| 2892 | new_func.* = .{ | 2703 | try match_stack.append(gpa, .{ |
| 2893 | .state = anal_state, | 2704 | .old_inst = old_main_struct_inst, |
| 2894 | .zir = fn_zir, | 2705 | .new_inst = new_main_struct_inst, |
| 2895 | .body = undefined, | 2706 | }); |
| 2896 | .owner_decl = decl, | ||
| 2897 | }; | ||
| 2898 | fn_payload.* = .{ | ||
| 2899 | .base = .{ .tag = .function }, | ||
| 2900 | .data = new_func, | ||
| 2901 | }; | ||
| 2902 | 2707 | ||
| 2903 | var prev_type_has_bits = false; | 2708 | var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa); |
| 2904 | var prev_is_inline = false; | 2709 | defer old_decls.deinit(); |
| 2905 | var type_changed = true; | 2710 | var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa); |
| 2906 | 2711 | defer new_decls.deinit(); | |
| 2907 | if (decl.typedValueManaged()) |tvm| { | ||
| 2908 | prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits(); | ||
| 2909 | type_changed = !tvm.typed_value.ty.eql(fn_type); | ||
| 2910 | if (tvm.typed_value.val.castTag(.function)) |payload| { | ||
| 2911 | const prev_func = payload.data; | ||
| 2912 | prev_is_inline = prev_func.state == .inline_only; | ||
| 2913 | prev_func.deinit(mod.gpa); | ||
| 2914 | } | ||
| 2915 | 2712 | ||
| 2916 | tvm.deinit(mod.gpa); | 2713 | while (match_stack.popOrNull()) |match_item| { |
| 2917 | } | 2714 | try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); |
| 2918 | 2715 | ||
| 2919 | decl_arena_state.* = decl_arena.state; | 2716 | // Maps name to extra index of decl sub item. |
| 2920 | decl.typed_value = .{ | 2717 | var decl_map: std.StringHashMapUnmanaged(u32) = .{}; |
| 2921 | .most_recent = .{ | 2718 | defer decl_map.deinit(gpa); |
| 2922 | .typed_value = .{ | 2719 | |
| 2923 | .ty = fn_type, | 2720 | { |
| 2924 | .val = Value.initPayload(&fn_payload.base), | 2721 | var old_decl_it = old_zir.declIterator(match_item.old_inst); |
| 2925 | }, | 2722 | while (old_decl_it.next()) |old_decl| { |
| 2926 | .arena = decl_arena_state, | 2723 | try decl_map.put(gpa, old_decl.name, old_decl.sub_index); |
| 2927 | }, | 2724 | } |
| 2928 | }; | ||
| 2929 | decl.analysis = .complete; | ||
| 2930 | decl.generation = mod.generation; | ||
| 2931 | |||
| 2932 | if (!is_inline and fn_type.hasCodeGenBits()) { | ||
| 2933 | // We don't fully codegen the decl until later, but we do need to reserve a global | ||
| 2934 | // offset table index for it. This allows us to codegen decls out of dependency order, | ||
| 2935 | // increasing how many computations can be done in parallel. | ||
| 2936 | try mod.comp.bin_file.allocateDeclIndexes(decl); | ||
| 2937 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | ||
| 2938 | if (type_changed and mod.emit_h != null) { | ||
| 2939 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); | ||
| 2940 | } | 2725 | } |
| 2941 | } else if (!prev_is_inline and prev_type_has_bits) { | ||
| 2942 | mod.comp.bin_file.freeDecl(decl); | ||
| 2943 | } | ||
| 2944 | 2726 | ||
| 2945 | if (fn_proto.extern_export_token) |maybe_export_token| { | 2727 | var new_decl_it = new_zir.declIterator(match_item.new_inst); |
| 2946 | if (token_tags[maybe_export_token] == .keyword_export) { | 2728 | while (new_decl_it.next()) |new_decl| { |
| 2947 | if (is_inline) { | 2729 | const old_extra_index = decl_map.get(new_decl.name) orelse continue; |
| 2948 | return mod.failTok( | 2730 | const new_extra_index = new_decl.sub_index; |
| 2949 | &block_scope.base, | 2731 | try extra_map.put(gpa, old_extra_index, new_extra_index); |
| 2950 | maybe_export_token, | 2732 | |
| 2951 | "export of inline function", | 2733 | try old_zir.findDecls(&old_decls, old_extra_index); |
| 2952 | .{}, | 2734 | try new_zir.findDecls(&new_decls, new_extra_index); |
| 2953 | ); | 2735 | var i: usize = 0; |
| 2736 | while (true) : (i += 1) { | ||
| 2737 | if (i >= old_decls.items.len) break; | ||
| 2738 | if (i >= new_decls.items.len) break; | ||
| 2739 | try match_stack.append(gpa, .{ | ||
| 2740 | .old_inst = old_decls.items[i], | ||
| 2741 | .new_inst = new_decls.items[i], | ||
| 2742 | }); | ||
| 2954 | } | 2743 | } |
| 2955 | const export_src = decl.tokSrcLoc(maybe_export_token); | ||
| 2956 | const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString | ||
| 2957 | // The scope needs to have the decl in it. | ||
| 2958 | try mod.analyzeExport(&block_scope.base, export_src, name, decl); | ||
| 2959 | } | 2744 | } |
| 2960 | } | 2745 | } |
| 2961 | return type_changed or is_inline != prev_is_inline; | ||
| 2962 | } | 2746 | } |
| 2963 | 2747 | ||
| 2964 | fn astgenAndSemaVarDecl( | 2748 | pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { |
| 2965 | mod: *Module, | ||
| 2966 | decl: *Decl, | ||
| 2967 | tree: ast.Tree, | ||
| 2968 | var_decl: ast.full.VarDecl, | ||
| 2969 | ) !bool { | ||
| 2970 | const tracy = trace(@src()); | 2749 | const tracy = trace(@src()); |
| 2971 | defer tracy.end(); | 2750 | defer tracy.end(); |
| 2972 | 2751 | ||
| 2973 | decl.analysis = .in_progress; | 2752 | const subsequent_analysis = switch (decl.analysis) { |
| 2974 | decl.is_pub = var_decl.visib_token != null; | 2753 | .in_progress => unreachable, |
| 2975 | |||
| 2976 | const token_tags = tree.tokens.items(.tag); | ||
| 2977 | 2754 | ||
| 2978 | // We need the memory for the Type to go into the arena for the Decl | 2755 | .file_failure, |
| 2979 | var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2756 | .sema_failure, |
| 2980 | errdefer decl_arena.deinit(); | 2757 | .sema_failure_retryable, |
| 2981 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | 2758 | .codegen_failure, |
| 2759 | .dependency_failure, | ||
| 2760 | .codegen_failure_retryable, | ||
| 2761 | => return error.AnalysisFail, | ||
| 2982 | 2762 | ||
| 2983 | // Used for simple error reporting. | 2763 | .complete => return, |
| 2984 | var decl_scope: Scope.DeclRef = .{ .decl = decl }; | ||
| 2985 | 2764 | ||
| 2986 | const is_extern = blk: { | 2765 | .outdated => blk: { |
| 2987 | const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; | 2766 | log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); |
| 2988 | break :blk token_tags[maybe_extern_token] == .keyword_extern; | ||
| 2989 | }; | ||
| 2990 | 2767 | ||
| 2991 | if (var_decl.lib_name) |lib_name| { | 2768 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 2992 | assert(is_extern); | 2769 | // prior to re-analysis. |
| 2993 | return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{}); | 2770 | mod.deleteDeclExports(decl); |
| 2994 | } | 2771 | // Dependencies will be re-discovered, so we remove them here prior to re-analysis. |
| 2995 | const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; | 2772 | for (decl.dependencies.items()) |entry| { |
| 2996 | const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: { | 2773 | const dep = entry.key; |
| 2997 | if (!is_mutable) { | 2774 | dep.removeDependant(decl); |
| 2998 | return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{}); | 2775 | if (dep.dependants.count() == 0 and !dep.deletion_flag) { |
| 2999 | } | 2776 | log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ |
| 3000 | break :blk true; | 2777 | decl, decl.name, dep, dep.name, |
| 3001 | } else false; | 2778 | }); |
| 3002 | assert(var_decl.comptime_token == null); | 2779 | // We don't perform a deletion here, because this Decl or another one |
| 3003 | if (var_decl.ast.align_node != 0) { | 2780 | // may end up referencing it before the update is complete. |
| 3004 | return mod.failNode( | 2781 | dep.deletion_flag = true; |
| 3005 | &decl_scope.base, | 2782 | try mod.deletion_set.put(mod.gpa, dep, {}); |
| 3006 | var_decl.ast.align_node, | 2783 | } |
| 3007 | "TODO implement function align expression", | 2784 | } |
| 3008 | .{}, | 2785 | decl.dependencies.clearRetainingCapacity(); |
| 3009 | ); | ||
| 3010 | } | ||
| 3011 | if (var_decl.ast.section_node != 0) { | ||
| 3012 | return mod.failNode( | ||
| 3013 | &decl_scope.base, | ||
| 3014 | var_decl.ast.section_node, | ||
| 3015 | "TODO implement function section expression", | ||
| 3016 | .{}, | ||
| 3017 | ); | ||
| 3018 | } | ||
| 3019 | |||
| 3020 | const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: { | ||
| 3021 | if (is_extern) { | ||
| 3022 | return mod.failNode( | ||
| 3023 | &decl_scope.base, | ||
| 3024 | var_decl.ast.init_node, | ||
| 3025 | "extern variables have no initializers", | ||
| 3026 | .{}, | ||
| 3027 | ); | ||
| 3028 | } | ||
| 3029 | 2786 | ||
| 3030 | var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | 2787 | break :blk true; |
| 3031 | defer gen_scope_arena.deinit(); | 2788 | }, |
| 3032 | 2789 | ||
| 3033 | var astgen = try AstGen.init(mod, decl, &gen_scope_arena.allocator); | 2790 | .unreferenced => false, |
| 3034 | defer astgen.deinit(); | 2791 | }; |
| 3035 | 2792 | ||
| 3036 | var gen_scope: Scope.GenZir = .{ | 2793 | const type_changed = mod.semaDecl(decl) catch |err| switch (err) { |
| 3037 | .force_comptime = true, | 2794 | error.AnalysisFail => { |
| 3038 | .parent = &decl.container.base, | 2795 | if (decl.analysis == .in_progress) { |
| 3039 | .astgen = &astgen, | 2796 | // If this decl caused the compile error, the analysis field would |
| 3040 | }; | 2797 | // be changed to indicate it was this Decl's fault. Because this |
| 3041 | defer gen_scope.instructions.deinit(mod.gpa); | 2798 | // did not happen, we infer here that it was a dependency failure. |
| 2799 | decl.analysis = .dependency_failure; | ||
| 2800 | } | ||
| 2801 | return error.AnalysisFail; | ||
| 2802 | }, | ||
| 2803 | else => { | ||
| 2804 | decl.analysis = .sema_failure_retryable; | ||
| 2805 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); | ||
| 2806 | mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( | ||
| 2807 | mod.gpa, | ||
| 2808 | decl.srcLoc(), | ||
| 2809 | "unable to analyze: {s}", | ||
| 2810 | .{@errorName(err)}, | ||
| 2811 | )); | ||
| 2812 | return error.AnalysisFail; | ||
| 2813 | }, | ||
| 2814 | }; | ||
| 3042 | 2815 | ||
| 3043 | const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{ | 2816 | if (subsequent_analysis) { |
| 3044 | .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node), | 2817 | // We may need to chase the dependants and re-analyze them. |
| 3045 | } else .none; | 2818 | // However, if the decl is a function, and the type is the same, we do not need to. |
| 2819 | if (type_changed or decl.ty.zigTypeTag() != .Fn) { | ||
| 2820 | for (decl.dependants.items()) |entry| { | ||
| 2821 | const dep = entry.key; | ||
| 2822 | switch (dep.analysis) { | ||
| 2823 | .unreferenced => unreachable, | ||
| 2824 | .in_progress => continue, // already doing analysis, ok | ||
| 2825 | .outdated => continue, // already queued for update | ||
| 3046 | 2826 | ||
| 3047 | const init_inst = try AstGen.comptimeExpr( | 2827 | .file_failure, |
| 3048 | &gen_scope, | 2828 | .dependency_failure, |
| 3049 | &gen_scope.base, | 2829 | .sema_failure, |
| 3050 | init_result_loc, | 2830 | .sema_failure_retryable, |
| 3051 | var_decl.ast.init_node, | 2831 | .codegen_failure, |
| 3052 | ); | 2832 | .codegen_failure_retryable, |
| 3053 | _ = try gen_scope.addBreak(.break_inline, 0, init_inst); | 2833 | .complete, |
| 3054 | var code = try gen_scope.finish(); | 2834 | => if (dep.generation != mod.generation) { |
| 3055 | defer code.deinit(mod.gpa); | 2835 | try mod.markOutdatedDecl(dep); |
| 3056 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | 2836 | }, |
| 3057 | code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {}; | 2837 | } |
| 2838 | } | ||
| 3058 | } | 2839 | } |
| 2840 | } | ||
| 2841 | } | ||
| 3059 | 2842 | ||
| 3060 | var sema: Sema = .{ | 2843 | pub fn semaPkg(mod: *Module, pkg: *Package) !void { |
| 3061 | .mod = mod, | 2844 | const file = (try mod.importPkg(mod.root_pkg, pkg)).file; |
| 3062 | .gpa = mod.gpa, | 2845 | return mod.semaFile(file); |
| 3063 | .arena = &gen_scope_arena.allocator, | 2846 | } |
| 3064 | .code = code, | ||
| 3065 | .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), | ||
| 3066 | .owner_decl = decl, | ||
| 3067 | .func = null, | ||
| 3068 | .owner_func = null, | ||
| 3069 | .param_inst_list = &.{}, | ||
| 3070 | }; | ||
| 3071 | var block_scope: Scope.Block = .{ | ||
| 3072 | .parent = null, | ||
| 3073 | .sema = &sema, | ||
| 3074 | .src_decl = decl, | ||
| 3075 | .instructions = .{}, | ||
| 3076 | .inlining = null, | ||
| 3077 | .is_comptime = true, | ||
| 3078 | }; | ||
| 3079 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 3080 | 2847 | ||
| 3081 | const init_inst_zir_ref = try sema.rootAsRef(&block_scope); | 2848 | /// Regardless of the file status, will create a `Decl` so that we |
| 3082 | // The result location guarantees the type coercion. | 2849 | /// can track dependencies and re-analyze when the file becomes outdated. |
| 3083 | const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref); | 2850 | pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3084 | // The is_comptime in the Scope.Block guarantees the result is comptime-known. | 2851 | const tracy = trace(@src()); |
| 3085 | const val = analyzed_init_inst.value().?; | 2852 | defer tracy.end(); |
| 3086 | 2853 | ||
| 3087 | break :vi .{ | 2854 | if (file.root_decl != null) return; |
| 3088 | .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator), | ||
| 3089 | .val = try val.copy(&decl_arena.allocator), | ||
| 3090 | }; | ||
| 3091 | } else if (!is_extern) { | ||
| 3092 | return mod.failTok( | ||
| 3093 | &decl_scope.base, | ||
| 3094 | var_decl.ast.mut_token, | ||
| 3095 | "variables must be initialized", | ||
| 3096 | .{}, | ||
| 3097 | ); | ||
| 3098 | } else if (var_decl.ast.type_node != 0) vi: { | ||
| 3099 | var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); | ||
| 3100 | defer type_scope_arena.deinit(); | ||
| 3101 | |||
| 3102 | var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator); | ||
| 3103 | defer astgen.deinit(); | ||
| 3104 | |||
| 3105 | var type_scope: Scope.GenZir = .{ | ||
| 3106 | .force_comptime = true, | ||
| 3107 | .parent = &decl.container.base, | ||
| 3108 | .astgen = &astgen, | ||
| 3109 | }; | ||
| 3110 | defer type_scope.instructions.deinit(mod.gpa); | ||
| 3111 | 2855 | ||
| 3112 | const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node); | 2856 | const gpa = mod.gpa; |
| 3113 | _ = try type_scope.addBreak(.break_inline, 0, var_type); | 2857 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 2858 | errdefer new_decl_arena.deinit(); | ||
| 2859 | |||
| 2860 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); | ||
| 2861 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); | ||
| 2862 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); | ||
| 2863 | struct_obj.* = .{ | ||
| 2864 | .owner_decl = undefined, // set below | ||
| 2865 | .fields = .{}, | ||
| 2866 | .node_offset = 0, // it's the struct for the root file | ||
| 2867 | .zir_index = undefined, // set below | ||
| 2868 | .layout = .Auto, | ||
| 2869 | .status = .none, | ||
| 2870 | .namespace = .{ | ||
| 2871 | .parent = null, | ||
| 2872 | .ty = struct_ty, | ||
| 2873 | .file_scope = file, | ||
| 2874 | }, | ||
| 2875 | }; | ||
| 2876 | const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0); | ||
| 2877 | file.root_decl = new_decl; | ||
| 2878 | struct_obj.owner_decl = new_decl; | ||
| 2879 | new_decl.src_line = 0; | ||
| 2880 | new_decl.name = try file.fullyQualifiedNameZ(gpa); | ||
| 2881 | new_decl.is_pub = true; | ||
| 2882 | new_decl.is_exported = false; | ||
| 2883 | new_decl.has_align = false; | ||
| 2884 | new_decl.has_linksection = false; | ||
| 2885 | new_decl.ty = struct_ty; | ||
| 2886 | new_decl.val = struct_val; | ||
| 2887 | new_decl.has_tv = true; | ||
| 2888 | new_decl.owns_tv = true; | ||
| 2889 | new_decl.analysis = .in_progress; | ||
| 2890 | new_decl.generation = mod.generation; | ||
| 3114 | 2891 | ||
| 3115 | var code = try type_scope.finish(); | 2892 | if (file.status == .success_zir) { |
| 3116 | defer code.deinit(mod.gpa); | 2893 | assert(file.zir_loaded); |
| 3117 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { | 2894 | const main_struct_inst = file.zir.getMainStruct(); |
| 3118 | code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {}; | 2895 | struct_obj.zir_index = main_struct_inst; |
| 3119 | } | 2896 | |
| 2897 | var sema_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 2898 | defer sema_arena.deinit(); | ||
| 3120 | 2899 | ||
| 3121 | var sema: Sema = .{ | 2900 | var sema: Sema = .{ |
| 3122 | .mod = mod, | 2901 | .mod = mod, |
| 3123 | .gpa = mod.gpa, | 2902 | .gpa = gpa, |
| 3124 | .arena = &type_scope_arena.allocator, | 2903 | .arena = &sema_arena.allocator, |
| 3125 | .code = code, | 2904 | .code = file.zir, |
| 3126 | .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), | 2905 | .owner_decl = new_decl, |
| 3127 | .owner_decl = decl, | 2906 | .namespace = &struct_obj.namespace, |
| 3128 | .func = null, | 2907 | .func = null, |
| 3129 | .owner_func = null, | 2908 | .owner_func = null, |
| 3130 | .param_inst_list = &.{}, | 2909 | .param_inst_list = &.{}, |
| 3131 | }; | 2910 | }; |
| 2911 | defer sema.deinit(); | ||
| 3132 | var block_scope: Scope.Block = .{ | 2912 | var block_scope: Scope.Block = .{ |
| 3133 | .parent = null, | 2913 | .parent = null, |
| 3134 | .sema = &sema, | 2914 | .sema = &sema, |
| 3135 | .src_decl = decl, | 2915 | .src_decl = new_decl, |
| 3136 | .instructions = .{}, | 2916 | .instructions = .{}, |
| 3137 | .inlining = null, | 2917 | .inlining = null, |
| 3138 | .is_comptime = true, | 2918 | .is_comptime = true, |
| 3139 | }; | 2919 | }; |
| 3140 | defer block_scope.instructions.deinit(mod.gpa); | 2920 | defer block_scope.instructions.deinit(gpa); |
| 3141 | |||
| 3142 | const ty = try sema.rootAsType(&block_scope); | ||
| 3143 | 2921 | ||
| 3144 | break :vi .{ | 2922 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| { |
| 3145 | .ty = try ty.copy(&decl_arena.allocator), | 2923 | new_decl.analysis = .complete; |
| 3146 | .val = null, | 2924 | } else |err| switch (err) { |
| 3147 | }; | 2925 | error.OutOfMemory => return error.OutOfMemory, |
| 2926 | error.AnalysisFail => {}, | ||
| 2927 | } | ||
| 3148 | } else { | 2928 | } else { |
| 3149 | return mod.failTok( | 2929 | new_decl.analysis = .file_failure; |
| 3150 | &decl_scope.base, | ||
| 3151 | var_decl.ast.mut_token, | ||
| 3152 | "unable to infer variable type", | ||
| 3153 | .{}, | ||
| 3154 | ); | ||
| 3155 | }; | ||
| 3156 | |||
| 3157 | if (is_mutable and !var_info.ty.isValidVarType(is_extern)) { | ||
| 3158 | return mod.failTok( | ||
| 3159 | &decl_scope.base, | ||
| 3160 | var_decl.ast.mut_token, | ||
| 3161 | "variable of type '{}' must be const", | ||
| 3162 | .{var_info.ty}, | ||
| 3163 | ); | ||
| 3164 | } | 2930 | } |
| 3165 | 2931 | ||
| 3166 | var type_changed = true; | 2932 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 3167 | if (decl.typedValueManaged()) |tvm| { | 2933 | } |
| 3168 | type_changed = !tvm.typed_value.ty.eql(var_info.ty); | ||
| 3169 | 2934 | ||
| 3170 | tvm.deinit(mod.gpa); | 2935 | /// Returns `true` if the Decl type changed. |
| 3171 | } | 2936 | /// Returns `true` if this is the first time analyzing the Decl. |
| 2937 | /// Returns `false` otherwise. | ||
| 2938 | fn semaDecl(mod: *Module, decl: *Decl) !bool { | ||
| 2939 | const tracy = trace(@src()); | ||
| 2940 | defer tracy.end(); | ||
| 3172 | 2941 | ||
| 3173 | const new_variable = try decl_arena.allocator.create(Var); | 2942 | if (decl.namespace.file_scope.status != .success_zir) { |
| 3174 | new_variable.* = .{ | 2943 | return error.AnalysisFail; |
| 3175 | .owner_decl = decl, | ||
| 3176 | .init = var_info.val orelse undefined, | ||
| 3177 | .is_extern = is_extern, | ||
| 3178 | .is_mutable = is_mutable, | ||
| 3179 | .is_threadlocal = is_threadlocal, | ||
| 3180 | }; | ||
| 3181 | const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable); | ||
| 3182 | |||
| 3183 | decl_arena_state.* = decl_arena.state; | ||
| 3184 | decl.typed_value = .{ | ||
| 3185 | .most_recent = .{ | ||
| 3186 | .typed_value = .{ | ||
| 3187 | .ty = var_info.ty, | ||
| 3188 | .val = var_val, | ||
| 3189 | }, | ||
| 3190 | .arena = decl_arena_state, | ||
| 3191 | }, | ||
| 3192 | }; | ||
| 3193 | decl.analysis = .complete; | ||
| 3194 | decl.generation = mod.generation; | ||
| 3195 | |||
| 3196 | if (var_decl.extern_export_token) |maybe_export_token| { | ||
| 3197 | if (token_tags[maybe_export_token] == .keyword_export) { | ||
| 3198 | const export_src = decl.tokSrcLoc(maybe_export_token); | ||
| 3199 | const name_token = var_decl.ast.mut_token + 1; | ||
| 3200 | const name = tree.tokenSlice(name_token); // TODO identifierTokenString | ||
| 3201 | // The scope needs to have the decl in it. | ||
| 3202 | try mod.analyzeExport(&decl_scope.base, export_src, name, decl); | ||
| 3203 | } | ||
| 3204 | } | 2944 | } |
| 3205 | return type_changed; | ||
| 3206 | } | ||
| 3207 | 2945 | ||
| 3208 | /// Returns the depender's index of the dependee. | 2946 | const gpa = mod.gpa; |
| 3209 | pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 { | 2947 | const zir = decl.namespace.file_scope.zir; |
| 3210 | try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1); | 2948 | const zir_datas = zir.instructions.items(.data); |
| 3211 | try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1); | ||
| 3212 | 2949 | ||
| 3213 | if (dependee.deletion_flag) { | 2950 | decl.analysis = .in_progress; |
| 3214 | dependee.deletion_flag = false; | ||
| 3215 | mod.deletion_set.removeAssertDiscard(dependee); | ||
| 3216 | } | ||
| 3217 | 2951 | ||
| 3218 | dependee.dependants.putAssumeCapacity(depender, {}); | 2952 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 3219 | const gop = depender.dependencies.getOrPutAssumeCapacity(dependee); | 2953 | defer analysis_arena.deinit(); |
| 3220 | return @intCast(u32, gop.index); | ||
| 3221 | } | ||
| 3222 | 2954 | ||
| 3223 | pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree { | 2955 | var sema: Sema = .{ |
| 3224 | const tracy = trace(@src()); | 2956 | .mod = mod, |
| 3225 | defer tracy.end(); | 2957 | .gpa = gpa, |
| 2958 | .arena = &analysis_arena.allocator, | ||
| 2959 | .code = zir, | ||
| 2960 | .owner_decl = decl, | ||
| 2961 | .namespace = decl.namespace, | ||
| 2962 | .func = null, | ||
| 2963 | .owner_func = null, | ||
| 2964 | .param_inst_list = &.{}, | ||
| 2965 | }; | ||
| 2966 | defer sema.deinit(); | ||
| 2967 | |||
| 2968 | if (decl.isRoot()) { | ||
| 2969 | log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); | ||
| 2970 | const main_struct_inst = zir.getMainStruct(); | ||
| 2971 | const struct_obj = decl.getStruct().?; | ||
| 2972 | // This might not have gotten set in `semaFile` if the first time had | ||
| 2973 | // a ZIR failure, so we set it here in case. | ||
| 2974 | struct_obj.zir_index = main_struct_inst; | ||
| 2975 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj); | ||
| 2976 | decl.analysis = .complete; | ||
| 2977 | decl.generation = mod.generation; | ||
| 2978 | return false; | ||
| 2979 | } | ||
| 3226 | 2980 | ||
| 3227 | switch (root_scope.status) { | 2981 | var block_scope: Scope.Block = .{ |
| 3228 | .never_loaded, .unloaded_success => { | 2982 | .parent = null, |
| 3229 | try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1); | 2983 | .sema = &sema, |
| 2984 | .src_decl = decl, | ||
| 2985 | .instructions = .{}, | ||
| 2986 | .inlining = null, | ||
| 2987 | .is_comptime = true, | ||
| 2988 | }; | ||
| 2989 | defer block_scope.instructions.deinit(gpa); | ||
| 2990 | |||
| 2991 | const zir_block_index = decl.zirBlockIndex(); | ||
| 2992 | const inst_data = zir_datas[zir_block_index].pl_node; | ||
| 2993 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); | ||
| 2994 | const body = zir.extra[extra.end..][0..extra.data.body_len]; | ||
| 2995 | const break_index = try sema.analyzeBody(&block_scope, body); | ||
| 2996 | const result_ref = zir_datas[break_index].@"break".operand; | ||
| 2997 | const src: LazySrcLoc = .{ .node_offset = 0 }; | ||
| 2998 | const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref); | ||
| 2999 | const align_val = blk: { | ||
| 3000 | const align_ref = decl.zirAlignRef(); | ||
| 3001 | if (align_ref == .none) break :blk Value.initTag(.null_value); | ||
| 3002 | break :blk (try sema.resolveInstConst(&block_scope, src, align_ref)).val; | ||
| 3003 | }; | ||
| 3004 | const linksection_val = blk: { | ||
| 3005 | const linksection_ref = decl.zirLinksectionRef(); | ||
| 3006 | if (linksection_ref == .none) break :blk Value.initTag(.null_value); | ||
| 3007 | break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val; | ||
| 3008 | }; | ||
| 3230 | 3009 | ||
| 3231 | const source = try root_scope.getSource(mod); | 3010 | // We need the memory for the Type to go into the arena for the Decl |
| 3011 | var decl_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 3012 | errdefer decl_arena.deinit(); | ||
| 3013 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 3232 | 3014 | ||
| 3233 | var keep_tree = false; | 3015 | if (decl_tv.val.castTag(.function)) |fn_payload| { |
| 3234 | root_scope.tree = try std.zig.parse(mod.gpa, source); | 3016 | var prev_type_has_bits = false; |
| 3235 | defer if (!keep_tree) root_scope.tree.deinit(mod.gpa); | 3017 | var prev_is_inline = false; |
| 3018 | var type_changed = true; | ||
| 3236 | 3019 | ||
| 3237 | const tree = &root_scope.tree; | 3020 | if (decl.has_tv) { |
| 3021 | prev_type_has_bits = decl.ty.hasCodeGenBits(); | ||
| 3022 | type_changed = !decl.ty.eql(decl_tv.ty); | ||
| 3023 | if (decl.getFunction()) |prev_func| { | ||
| 3024 | prev_is_inline = prev_func.state == .inline_only; | ||
| 3025 | } | ||
| 3026 | decl.clearValues(gpa); | ||
| 3027 | } | ||
| 3238 | 3028 | ||
| 3239 | if (tree.errors.len != 0) { | 3029 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); |
| 3240 | const parse_err = tree.errors[0]; | 3030 | decl.val = try decl_tv.val.copy(&decl_arena.allocator); |
| 3031 | decl.align_val = try align_val.copy(&decl_arena.allocator); | ||
| 3032 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); | ||
| 3033 | decl.has_tv = true; | ||
| 3034 | decl.owns_tv = fn_payload.data.owner_decl == decl; | ||
| 3035 | decl_arena_state.* = decl_arena.state; | ||
| 3036 | decl.value_arena = decl_arena_state; | ||
| 3037 | decl.analysis = .complete; | ||
| 3038 | decl.generation = mod.generation; | ||
| 3241 | 3039 | ||
| 3242 | var msg = std.ArrayList(u8).init(mod.gpa); | 3040 | const is_inline = decl_tv.ty.fnCallingConvention() == .Inline; |
| 3243 | defer msg.deinit(); | 3041 | if (!is_inline and decl_tv.ty.hasCodeGenBits()) { |
| 3042 | // We don't fully codegen the decl until later, but we do need to reserve a global | ||
| 3043 | // offset table index for it. This allows us to codegen decls out of dependency order, | ||
| 3044 | // increasing how many computations can be done in parallel. | ||
| 3045 | try mod.comp.bin_file.allocateDeclIndexes(decl); | ||
| 3046 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | ||
| 3047 | if (type_changed and mod.emit_h != null) { | ||
| 3048 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); | ||
| 3049 | } | ||
| 3050 | } else if (!prev_is_inline and prev_type_has_bits) { | ||
| 3051 | mod.comp.bin_file.freeDecl(decl); | ||
| 3052 | } | ||
| 3244 | 3053 | ||
| 3245 | const token_starts = tree.tokens.items(.start); | 3054 | if (decl.is_exported) { |
| 3055 | const export_src = src; // TODO make this point at `export` token | ||
| 3056 | if (is_inline) { | ||
| 3057 | return mod.fail(&block_scope.base, export_src, "export of inline function", .{}); | ||
| 3058 | } | ||
| 3059 | // The scope needs to have the decl in it. | ||
| 3060 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); | ||
| 3061 | } | ||
| 3062 | return type_changed or is_inline != prev_is_inline; | ||
| 3063 | } else { | ||
| 3064 | var type_changed = true; | ||
| 3065 | if (decl.has_tv) { | ||
| 3066 | type_changed = !decl.ty.eql(decl_tv.ty); | ||
| 3067 | decl.clearValues(gpa); | ||
| 3068 | } | ||
| 3246 | 3069 | ||
| 3247 | try tree.renderError(parse_err, msg.writer()); | 3070 | decl.owns_tv = false; |
| 3248 | const err_msg = try mod.gpa.create(ErrorMsg); | 3071 | var queue_linker_work = false; |
| 3249 | err_msg.* = .{ | 3072 | if (decl_tv.val.castTag(.variable)) |payload| { |
| 3250 | .src_loc = .{ | 3073 | const variable = payload.data; |
| 3251 | .container = .{ .file_scope = root_scope }, | 3074 | if (variable.owner_decl == decl) { |
| 3252 | .lazy = .{ .byte_abs = token_starts[parse_err.token] }, | 3075 | decl.owns_tv = true; |
| 3253 | }, | 3076 | queue_linker_work = true; |
| 3254 | .msg = msg.toOwnedSlice(), | ||
| 3255 | }; | ||
| 3256 | 3077 | ||
| 3257 | mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg); | 3078 | const copied_init = try variable.init.copy(&decl_arena.allocator); |
| 3258 | root_scope.status = .unloaded_parse_failure; | 3079 | variable.init = copied_init; |
| 3259 | return error.AnalysisFail; | ||
| 3260 | } | 3080 | } |
| 3081 | } else if (decl_tv.val.castTag(.extern_fn)) |payload| { | ||
| 3082 | const owner_decl = payload.data; | ||
| 3083 | if (decl == owner_decl) { | ||
| 3084 | decl.owns_tv = true; | ||
| 3085 | queue_linker_work = true; | ||
| 3086 | } | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); | ||
| 3090 | decl.val = try decl_tv.val.copy(&decl_arena.allocator); | ||
| 3091 | decl.align_val = try align_val.copy(&decl_arena.allocator); | ||
| 3092 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); | ||
| 3093 | decl.has_tv = true; | ||
| 3094 | decl_arena_state.* = decl_arena.state; | ||
| 3095 | decl.value_arena = decl_arena_state; | ||
| 3096 | decl.analysis = .complete; | ||
| 3097 | decl.generation = mod.generation; | ||
| 3261 | 3098 | ||
| 3262 | root_scope.status = .loaded_success; | 3099 | if (queue_linker_work and decl.ty.hasCodeGenBits()) { |
| 3263 | keep_tree = true; | 3100 | try mod.comp.bin_file.allocateDeclIndexes(decl); |
| 3101 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | ||
| 3264 | 3102 | ||
| 3265 | return tree; | 3103 | if (type_changed and mod.emit_h != null) { |
| 3266 | }, | 3104 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); |
| 3105 | } | ||
| 3106 | } | ||
| 3267 | 3107 | ||
| 3268 | .unloaded_parse_failure => return error.AnalysisFail, | 3108 | if (decl.is_exported) { |
| 3109 | const export_src = src; // TODO point to the export token | ||
| 3110 | // The scope needs to have the decl in it. | ||
| 3111 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); | ||
| 3112 | } | ||
| 3269 | 3113 | ||
| 3270 | .loaded_success => return &root_scope.tree, | 3114 | return type_changed; |
| 3271 | } | 3115 | } |
| 3272 | } | 3116 | } |
| 3273 | 3117 | ||
| 3274 | pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | 3118 | /// Returns the depender's index of the dependee. |
| 3275 | const tracy = trace(@src()); | 3119 | pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void { |
| 3276 | defer tracy.end(); | 3120 | if (depender == dependee) return; |
| 3277 | 3121 | ||
| 3278 | // We may be analyzing it for the first time, or this may be | 3122 | log.debug("{*} ({s}) depends on {*} ({s})", .{ |
| 3279 | // an incremental update. This code handles both cases. | 3123 | depender, depender.name, dependee, dependee.name, |
| 3280 | const tree = try mod.getAstTree(container_scope.file_scope); | 3124 | }); |
| 3281 | const node_tags = tree.nodes.items(.tag); | ||
| 3282 | const node_datas = tree.nodes.items(.data); | ||
| 3283 | const decls = tree.rootDecls(); | ||
| 3284 | 3125 | ||
| 3285 | try mod.comp.work_queue.ensureUnusedCapacity(decls.len); | 3126 | try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); |
| 3286 | try container_scope.decls.ensureCapacity(mod.gpa, decls.len); | 3127 | try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1); |
| 3287 | 3128 | ||
| 3288 | // Keep track of the decls that we expect to see in this file so that | 3129 | if (dependee.deletion_flag) { |
| 3289 | // we know which ones have been deleted. | 3130 | dependee.deletion_flag = false; |
| 3290 | var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); | 3131 | mod.deletion_set.removeAssertDiscard(dependee); |
| 3291 | defer deleted_decls.deinit(); | ||
| 3292 | try deleted_decls.ensureCapacity(container_scope.decls.items().len); | ||
| 3293 | for (container_scope.decls.items()) |entry| { | ||
| 3294 | deleted_decls.putAssumeCapacityNoClobber(entry.key, {}); | ||
| 3295 | } | 3132 | } |
| 3296 | 3133 | ||
| 3297 | // Keep track of decls that are invalidated from the update. Ultimately, | 3134 | dependee.dependants.putAssumeCapacity(depender, {}); |
| 3298 | // the goal is to queue up `analyze_decl` tasks in the work queue for | 3135 | depender.dependencies.putAssumeCapacity(dependee, {}); |
| 3299 | // the outdated decls, but we cannot queue up the tasks until after | 3136 | } |
| 3300 | // we find out which ones have been deleted, otherwise there would be | ||
| 3301 | // deleted Decl pointers in the work queue. | ||
| 3302 | var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); | ||
| 3303 | defer outdated_decls.deinit(); | ||
| 3304 | 3137 | ||
| 3305 | for (decls) |decl_node| switch (node_tags[decl_node]) { | 3138 | pub const ImportFileResult = struct { |
| 3306 | .fn_decl => { | 3139 | file: *Scope.File, |
| 3307 | const fn_proto = node_datas[decl_node].lhs; | 3140 | is_new: bool, |
| 3308 | const body = node_datas[decl_node].rhs; | 3141 | }; |
| 3309 | switch (node_tags[fn_proto]) { | ||
| 3310 | .fn_proto_simple => { | ||
| 3311 | var params: [1]ast.Node.Index = undefined; | ||
| 3312 | try mod.semaContainerFn( | ||
| 3313 | container_scope, | ||
| 3314 | &deleted_decls, | ||
| 3315 | &outdated_decls, | ||
| 3316 | decl_node, | ||
| 3317 | tree.*, | ||
| 3318 | body, | ||
| 3319 | tree.fnProtoSimple(&params, fn_proto), | ||
| 3320 | ); | ||
| 3321 | }, | ||
| 3322 | .fn_proto_multi => try mod.semaContainerFn( | ||
| 3323 | container_scope, | ||
| 3324 | &deleted_decls, | ||
| 3325 | &outdated_decls, | ||
| 3326 | decl_node, | ||
| 3327 | tree.*, | ||
| 3328 | body, | ||
| 3329 | tree.fnProtoMulti(fn_proto), | ||
| 3330 | ), | ||
| 3331 | .fn_proto_one => { | ||
| 3332 | var params: [1]ast.Node.Index = undefined; | ||
| 3333 | try mod.semaContainerFn( | ||
| 3334 | container_scope, | ||
| 3335 | &deleted_decls, | ||
| 3336 | &outdated_decls, | ||
| 3337 | decl_node, | ||
| 3338 | tree.*, | ||
| 3339 | body, | ||
| 3340 | tree.fnProtoOne(&params, fn_proto), | ||
| 3341 | ); | ||
| 3342 | }, | ||
| 3343 | .fn_proto => try mod.semaContainerFn( | ||
| 3344 | container_scope, | ||
| 3345 | &deleted_decls, | ||
| 3346 | &outdated_decls, | ||
| 3347 | decl_node, | ||
| 3348 | tree.*, | ||
| 3349 | body, | ||
| 3350 | tree.fnProto(fn_proto), | ||
| 3351 | ), | ||
| 3352 | else => unreachable, | ||
| 3353 | } | ||
| 3354 | }, | ||
| 3355 | .fn_proto_simple => { | ||
| 3356 | var params: [1]ast.Node.Index = undefined; | ||
| 3357 | try mod.semaContainerFn( | ||
| 3358 | container_scope, | ||
| 3359 | &deleted_decls, | ||
| 3360 | &outdated_decls, | ||
| 3361 | decl_node, | ||
| 3362 | tree.*, | ||
| 3363 | 0, | ||
| 3364 | tree.fnProtoSimple(&params, decl_node), | ||
| 3365 | ); | ||
| 3366 | }, | ||
| 3367 | .fn_proto_multi => try mod.semaContainerFn( | ||
| 3368 | container_scope, | ||
| 3369 | &deleted_decls, | ||
| 3370 | &outdated_decls, | ||
| 3371 | decl_node, | ||
| 3372 | tree.*, | ||
| 3373 | 0, | ||
| 3374 | tree.fnProtoMulti(decl_node), | ||
| 3375 | ), | ||
| 3376 | .fn_proto_one => { | ||
| 3377 | var params: [1]ast.Node.Index = undefined; | ||
| 3378 | try mod.semaContainerFn( | ||
| 3379 | container_scope, | ||
| 3380 | &deleted_decls, | ||
| 3381 | &outdated_decls, | ||
| 3382 | decl_node, | ||
| 3383 | tree.*, | ||
| 3384 | 0, | ||
| 3385 | tree.fnProtoOne(&params, decl_node), | ||
| 3386 | ); | ||
| 3387 | }, | ||
| 3388 | .fn_proto => try mod.semaContainerFn( | ||
| 3389 | container_scope, | ||
| 3390 | &deleted_decls, | ||
| 3391 | &outdated_decls, | ||
| 3392 | decl_node, | ||
| 3393 | tree.*, | ||
| 3394 | 0, | ||
| 3395 | tree.fnProto(decl_node), | ||
| 3396 | ), | ||
| 3397 | 3142 | ||
| 3398 | .global_var_decl => try mod.semaContainerVar( | 3143 | pub fn importPkg(mod: *Module, cur_pkg: *Package, pkg: *Package) !ImportFileResult { |
| 3399 | container_scope, | 3144 | const gpa = mod.gpa; |
| 3400 | &deleted_decls, | ||
| 3401 | &outdated_decls, | ||
| 3402 | decl_node, | ||
| 3403 | tree.*, | ||
| 3404 | tree.globalVarDecl(decl_node), | ||
| 3405 | ), | ||
| 3406 | .local_var_decl => try mod.semaContainerVar( | ||
| 3407 | container_scope, | ||
| 3408 | &deleted_decls, | ||
| 3409 | &outdated_decls, | ||
| 3410 | decl_node, | ||
| 3411 | tree.*, | ||
| 3412 | tree.localVarDecl(decl_node), | ||
| 3413 | ), | ||
| 3414 | .simple_var_decl => try mod.semaContainerVar( | ||
| 3415 | container_scope, | ||
| 3416 | &deleted_decls, | ||
| 3417 | &outdated_decls, | ||
| 3418 | decl_node, | ||
| 3419 | tree.*, | ||
| 3420 | tree.simpleVarDecl(decl_node), | ||
| 3421 | ), | ||
| 3422 | .aligned_var_decl => try mod.semaContainerVar( | ||
| 3423 | container_scope, | ||
| 3424 | &deleted_decls, | ||
| 3425 | &outdated_decls, | ||
| 3426 | decl_node, | ||
| 3427 | tree.*, | ||
| 3428 | tree.alignedVarDecl(decl_node), | ||
| 3429 | ), | ||
| 3430 | 3145 | ||
| 3431 | .@"comptime" => { | 3146 | // The resolved path is used as the key in the import table, to detect if |
| 3432 | const name_index = mod.getNextAnonNameIndex(); | 3147 | // an import refers to the same as another, despite different relative paths |
| 3433 | const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index}); | 3148 | // or differently mapped package names. |
| 3434 | defer mod.gpa.free(name); | 3149 | const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ |
| 3150 | pkg.root_src_directory.path orelse ".", pkg.root_src_path, | ||
| 3151 | }); | ||
| 3152 | var keep_resolved_path = false; | ||
| 3153 | defer if (!keep_resolved_path) gpa.free(resolved_path); | ||
| 3435 | 3154 | ||
| 3436 | const name_hash = container_scope.fullyQualifiedNameHash(name); | 3155 | const gop = try mod.import_table.getOrPut(gpa, resolved_path); |
| 3437 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); | 3156 | if (gop.found_existing) return ImportFileResult{ |
| 3157 | .file = gop.entry.value, | ||
| 3158 | .is_new = false, | ||
| 3159 | }; | ||
| 3160 | keep_resolved_path = true; // It's now owned by import_table. | ||
| 3161 | |||
| 3162 | const sub_file_path = try gpa.dupe(u8, pkg.root_src_path); | ||
| 3163 | errdefer gpa.free(sub_file_path); | ||
| 3164 | |||
| 3165 | const new_file = try gpa.create(Scope.File); | ||
| 3166 | errdefer gpa.destroy(new_file); | ||
| 3167 | |||
| 3168 | gop.entry.value = new_file; | ||
| 3169 | new_file.* = .{ | ||
| 3170 | .sub_file_path = sub_file_path, | ||
| 3171 | .source = undefined, | ||
| 3172 | .source_loaded = false, | ||
| 3173 | .tree_loaded = false, | ||
| 3174 | .zir_loaded = false, | ||
| 3175 | .stat_size = undefined, | ||
| 3176 | .stat_inode = undefined, | ||
| 3177 | .stat_mtime = undefined, | ||
| 3178 | .tree = undefined, | ||
| 3179 | .zir = undefined, | ||
| 3180 | .status = .never_loaded, | ||
| 3181 | .pkg = pkg, | ||
| 3182 | .root_decl = null, | ||
| 3183 | }; | ||
| 3184 | return ImportFileResult{ | ||
| 3185 | .file = new_file, | ||
| 3186 | .is_new = true, | ||
| 3187 | }; | ||
| 3188 | } | ||
| 3438 | 3189 | ||
| 3439 | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); | 3190 | pub fn importFile( |
| 3440 | container_scope.decls.putAssumeCapacity(new_decl, {}); | 3191 | mod: *Module, |
| 3441 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | 3192 | cur_file: *Scope.File, |
| 3442 | }, | 3193 | import_string: []const u8, |
| 3194 | ) !ImportFileResult { | ||
| 3195 | if (cur_file.pkg.table.get(import_string)) |pkg| { | ||
| 3196 | return mod.importPkg(cur_file.pkg, pkg); | ||
| 3197 | } | ||
| 3198 | const gpa = mod.gpa; | ||
| 3443 | 3199 | ||
| 3444 | // Container fields are handled in AstGen. | 3200 | // The resolved path is used as the key in the import table, to detect if |
| 3445 | .container_field_init, | 3201 | // an import refers to the same as another, despite different relative paths |
| 3446 | .container_field_align, | 3202 | // or differently mapped package names. |
| 3447 | .container_field, | 3203 | const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse "."; |
| 3448 | => continue, | 3204 | const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ |
| 3205 | cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string, | ||
| 3206 | }); | ||
| 3207 | var keep_resolved_path = false; | ||
| 3208 | defer if (!keep_resolved_path) gpa.free(resolved_path); | ||
| 3449 | 3209 | ||
| 3450 | .test_decl => { | 3210 | const gop = try mod.import_table.getOrPut(gpa, resolved_path); |
| 3451 | if (mod.comp.bin_file.options.is_test) { | 3211 | if (gop.found_existing) return ImportFileResult{ |
| 3452 | log.err("TODO: analyze test decl", .{}); | 3212 | .file = gop.entry.value, |
| 3453 | } | 3213 | .is_new = false, |
| 3454 | }, | ||
| 3455 | .@"usingnamespace" => { | ||
| 3456 | log.err("TODO: analyze usingnamespace decl", .{}); | ||
| 3457 | }, | ||
| 3458 | else => unreachable, | ||
| 3459 | }; | 3214 | }; |
| 3460 | // Handle explicitly deleted decls from the source code. This is one of two | 3215 | keep_resolved_path = true; // It's now owned by import_table. |
| 3461 | // places that Decl deletions happen. The other is in `Compilation`, after | 3216 | |
| 3462 | // `performAllTheWork`, where we iterate over `Module.deletion_set` and | 3217 | const new_file = try gpa.create(Scope.File); |
| 3463 | // delete Decls which are no longer referenced. | 3218 | errdefer gpa.destroy(new_file); |
| 3464 | // If a Decl is explicitly deleted from source, and also no longer referenced, | 3219 | |
| 3465 | // it may be both in this `deleted_decls` set, as well as in the | 3220 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); |
| 3466 | // `Module.deletion_set`. To avoid deleting it twice, we remove it from the | 3221 | defer gpa.free(resolved_root_path); |
| 3467 | // deletion set at this time. | 3222 | |
| 3468 | for (deleted_decls.items()) |entry| { | 3223 | if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { |
| 3469 | const decl = entry.key; | 3224 | return error.ImportOutsidePkgPath; |
| 3470 | log.debug("'{s}' deleted from source", .{decl.name}); | ||
| 3471 | if (decl.deletion_flag) { | ||
| 3472 | log.debug("'{s}' redundantly in deletion set; removing", .{decl.name}); | ||
| 3473 | mod.deletion_set.removeAssertDiscard(decl); | ||
| 3474 | } | ||
| 3475 | try mod.deleteDecl(decl, &outdated_decls); | ||
| 3476 | } | ||
| 3477 | // Finally we can queue up re-analysis tasks after we have processed | ||
| 3478 | // the deleted decls. | ||
| 3479 | for (outdated_decls.items()) |entry| { | ||
| 3480 | try mod.markOutdatedDecl(entry.key); | ||
| 3481 | } | 3225 | } |
| 3226 | // +1 for the directory separator here. | ||
| 3227 | const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); | ||
| 3228 | errdefer gpa.free(sub_file_path); | ||
| 3229 | |||
| 3230 | log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{ | ||
| 3231 | resolved_root_path, resolved_path, sub_file_path, import_string, | ||
| 3232 | }); | ||
| 3233 | |||
| 3234 | gop.entry.value = new_file; | ||
| 3235 | new_file.* = .{ | ||
| 3236 | .sub_file_path = sub_file_path, | ||
| 3237 | .source = undefined, | ||
| 3238 | .source_loaded = false, | ||
| 3239 | .tree_loaded = false, | ||
| 3240 | .zir_loaded = false, | ||
| 3241 | .stat_size = undefined, | ||
| 3242 | .stat_inode = undefined, | ||
| 3243 | .stat_mtime = undefined, | ||
| 3244 | .tree = undefined, | ||
| 3245 | .zir = undefined, | ||
| 3246 | .status = .never_loaded, | ||
| 3247 | .pkg = cur_file.pkg, | ||
| 3248 | .root_decl = null, | ||
| 3249 | }; | ||
| 3250 | return ImportFileResult{ | ||
| 3251 | .file = new_file, | ||
| 3252 | .is_new = true, | ||
| 3253 | }; | ||
| 3482 | } | 3254 | } |
| 3483 | 3255 | ||
| 3484 | fn semaContainerFn( | 3256 | pub fn scanNamespace( |
| 3485 | mod: *Module, | 3257 | mod: *Module, |
| 3486 | container_scope: *Scope.Container, | 3258 | namespace: *Scope.Namespace, |
| 3487 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), | 3259 | extra_start: usize, |
| 3488 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), | 3260 | decls_len: u32, |
| 3489 | decl_node: ast.Node.Index, | 3261 | parent_decl: *Decl, |
| 3490 | tree: ast.Tree, | 3262 | ) InnerError!usize { |
| 3491 | body_node: ast.Node.Index, | ||
| 3492 | fn_proto: ast.full.FnProto, | ||
| 3493 | ) !void { | ||
| 3494 | const tracy = trace(@src()); | 3263 | const tracy = trace(@src()); |
| 3495 | defer tracy.end(); | 3264 | defer tracy.end(); |
| 3496 | 3265 | ||
| 3497 | // We will create a Decl for it regardless of analysis status. | 3266 | const gpa = mod.gpa; |
| 3498 | const name_token = fn_proto.name_token orelse { | 3267 | const zir = namespace.file_scope.zir; |
| 3499 | // This problem will go away with #1717. | 3268 | |
| 3500 | @panic("TODO missing function name"); | 3269 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); |
| 3270 | try namespace.decls.ensureCapacity(gpa, decls_len); | ||
| 3271 | |||
| 3272 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; | ||
| 3273 | var extra_index = extra_start + bit_bags_count; | ||
| 3274 | var bit_bag_index: usize = extra_start; | ||
| 3275 | var cur_bit_bag: u32 = undefined; | ||
| 3276 | var decl_i: u32 = 0; | ||
| 3277 | var scan_decl_iter: ScanDeclIter = .{ | ||
| 3278 | .module = mod, | ||
| 3279 | .namespace = namespace, | ||
| 3280 | .parent_decl = parent_decl, | ||
| 3501 | }; | 3281 | }; |
| 3502 | const name = tree.tokenSlice(name_token); // TODO use identifierTokenString | 3282 | while (decl_i < decls_len) : (decl_i += 1) { |
| 3503 | const name_hash = container_scope.fullyQualifiedNameHash(name); | 3283 | if (decl_i % 8 == 0) { |
| 3504 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); | 3284 | cur_bit_bag = zir.extra[bit_bag_index]; |
| 3505 | if (mod.decl_table.get(name_hash)) |decl| { | 3285 | bit_bag_index += 1; |
| 3506 | // Update the AST Node index of the decl, even if its contents are unchanged, it may | ||
| 3507 | // have been re-ordered. | ||
| 3508 | const prev_src_node = decl.src_node; | ||
| 3509 | decl.src_node = decl_node; | ||
| 3510 | if (deleted_decls.swapRemove(decl) == null) { | ||
| 3511 | decl.analysis = .sema_failure; | ||
| 3512 | const msg = try ErrorMsg.create(mod.gpa, .{ | ||
| 3513 | .container = .{ .file_scope = container_scope.file_scope }, | ||
| 3514 | .lazy = .{ .token_abs = name_token }, | ||
| 3515 | }, "redefinition of '{s}'", .{decl.name}); | ||
| 3516 | errdefer msg.destroy(mod.gpa); | ||
| 3517 | const other_src_loc: SrcLoc = .{ | ||
| 3518 | .container = .{ .file_scope = decl.container.file_scope }, | ||
| 3519 | .lazy = .{ .node_abs = prev_src_node }, | ||
| 3520 | }; | ||
| 3521 | try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{}); | ||
| 3522 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); | ||
| 3523 | } else { | ||
| 3524 | if (!srcHashEql(decl.contents_hash, contents_hash)) { | ||
| 3525 | try outdated_decls.put(decl, {}); | ||
| 3526 | decl.contents_hash = contents_hash; | ||
| 3527 | } else switch (mod.comp.bin_file.tag) { | ||
| 3528 | .coff => { | ||
| 3529 | // TODO Implement for COFF | ||
| 3530 | }, | ||
| 3531 | .elf => if (decl.fn_link.elf.len != 0) { | ||
| 3532 | // TODO Look into detecting when this would be unnecessary by storing enough state | ||
| 3533 | // in `Decl` to notice that the line number did not change. | ||
| 3534 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | ||
| 3535 | }, | ||
| 3536 | .macho => if (decl.fn_link.macho.len != 0) { | ||
| 3537 | // TODO Look into detecting when this would be unnecessary by storing enough state | ||
| 3538 | // in `Decl` to notice that the line number did not change. | ||
| 3539 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | ||
| 3540 | }, | ||
| 3541 | .c, .wasm, .spirv => {}, | ||
| 3542 | } | ||
| 3543 | } | ||
| 3544 | } else { | ||
| 3545 | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); | ||
| 3546 | container_scope.decls.putAssumeCapacity(new_decl, {}); | ||
| 3547 | if (fn_proto.extern_export_token) |maybe_export_token| { | ||
| 3548 | const token_tags = tree.tokens.items(.tag); | ||
| 3549 | if (token_tags[maybe_export_token] == .keyword_export) { | ||
| 3550 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | ||
| 3551 | } | ||
| 3552 | } | 3286 | } |
| 3553 | new_decl.is_pub = fn_proto.visib_token != null; | 3287 | const flags = @truncate(u4, cur_bit_bag); |
| 3288 | cur_bit_bag >>= 4; | ||
| 3289 | |||
| 3290 | const decl_sub_index = extra_index; | ||
| 3291 | extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1) | ||
| 3292 | extra_index += @truncate(u1, flags >> 2); | ||
| 3293 | extra_index += @truncate(u1, flags >> 3); | ||
| 3294 | |||
| 3295 | try scanDecl(&scan_decl_iter, decl_sub_index, flags); | ||
| 3554 | } | 3296 | } |
| 3297 | return extra_index; | ||
| 3555 | } | 3298 | } |
| 3556 | 3299 | ||
| 3557 | fn semaContainerVar( | 3300 | const ScanDeclIter = struct { |
| 3558 | mod: *Module, | 3301 | module: *Module, |
| 3559 | container_scope: *Scope.Container, | 3302 | namespace: *Scope.Namespace, |
| 3560 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), | 3303 | parent_decl: *Decl, |
| 3561 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), | 3304 | usingnamespace_index: usize = 0, |
| 3562 | decl_node: ast.Node.Index, | 3305 | comptime_index: usize = 0, |
| 3563 | tree: ast.Tree, | 3306 | unnamed_test_index: usize = 0, |
| 3564 | var_decl: ast.full.VarDecl, | 3307 | }; |
| 3565 | ) !void { | 3308 | |
| 3309 | fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!void { | ||
| 3566 | const tracy = trace(@src()); | 3310 | const tracy = trace(@src()); |
| 3567 | defer tracy.end(); | 3311 | defer tracy.end(); |
| 3568 | 3312 | ||
| 3569 | const name_token = var_decl.ast.mut_token + 1; | 3313 | const mod = iter.module; |
| 3570 | const name = tree.tokenSlice(name_token); // TODO identifierTokenString | 3314 | const namespace = iter.namespace; |
| 3571 | const name_hash = container_scope.fullyQualifiedNameHash(name); | 3315 | const gpa = mod.gpa; |
| 3572 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); | 3316 | const zir = namespace.file_scope.zir; |
| 3573 | if (mod.decl_table.get(name_hash)) |decl| { | 3317 | |
| 3574 | // Update the AST Node index of the decl, even if its contents are unchanged, it may | 3318 | // zig fmt: off |
| 3575 | // have been re-ordered. | 3319 | const is_pub = (flags & 0b0001) != 0; |
| 3576 | const prev_src_node = decl.src_node; | 3320 | const is_exported = (flags & 0b0010) != 0; |
| 3577 | decl.src_node = decl_node; | 3321 | const has_align = (flags & 0b0100) != 0; |
| 3578 | if (deleted_decls.swapRemove(decl) == null) { | 3322 | const has_linksection = (flags & 0b1000) != 0; |
| 3579 | decl.analysis = .sema_failure; | 3323 | // zig fmt: on |
| 3580 | const msg = try ErrorMsg.create(mod.gpa, .{ | 3324 | |
| 3581 | .container = .{ .file_scope = container_scope.file_scope }, | 3325 | const line = iter.parent_decl.relativeToLine(zir.extra[decl_sub_index + 4]); |
| 3582 | .lazy = .{ .token_abs = name_token }, | 3326 | const decl_name_index = zir.extra[decl_sub_index + 5]; |
| 3583 | }, "redefinition of '{s}'", .{decl.name}); | 3327 | const decl_index = zir.extra[decl_sub_index + 6]; |
| 3584 | errdefer msg.destroy(mod.gpa); | 3328 | const decl_block_inst_data = zir.instructions.items(.data)[decl_index].pl_node; |
| 3585 | const other_src_loc: SrcLoc = .{ | 3329 | const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node); |
| 3586 | .container = .{ .file_scope = decl.container.file_scope }, | 3330 | |
| 3587 | .lazy = .{ .node_abs = prev_src_node }, | 3331 | // Every Decl needs a name. |
| 3588 | }; | 3332 | var is_named_test = false; |
| 3589 | try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{}); | 3333 | const decl_name: [:0]const u8 = switch (decl_name_index) { |
| 3590 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); | 3334 | 0 => name: { |
| 3591 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { | 3335 | if (is_exported) { |
| 3592 | try outdated_decls.put(decl, {}); | 3336 | const i = iter.usingnamespace_index; |
| 3593 | decl.contents_hash = contents_hash; | 3337 | iter.usingnamespace_index += 1; |
| 3594 | } | 3338 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); |
| 3595 | } else { | 3339 | } else { |
| 3596 | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); | 3340 | const i = iter.comptime_index; |
| 3597 | container_scope.decls.putAssumeCapacity(new_decl, {}); | 3341 | iter.comptime_index += 1; |
| 3598 | if (var_decl.extern_export_token) |maybe_export_token| { | 3342 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); |
| 3599 | const token_tags = tree.tokens.items(.tag); | 3343 | } |
| 3600 | if (token_tags[maybe_export_token] == .keyword_export) { | 3344 | }, |
| 3601 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | 3345 | 1 => name: { |
| 3346 | const i = iter.unnamed_test_index; | ||
| 3347 | iter.unnamed_test_index += 1; | ||
| 3348 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); | ||
| 3349 | }, | ||
| 3350 | else => name: { | ||
| 3351 | const raw_name = zir.nullTerminatedString(decl_name_index); | ||
| 3352 | if (raw_name.len == 0) { | ||
| 3353 | is_named_test = true; | ||
| 3354 | const test_name = zir.nullTerminatedString(decl_name_index + 1); | ||
| 3355 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); | ||
| 3356 | } else { | ||
| 3357 | break :name try gpa.dupeZ(u8, raw_name); | ||
| 3602 | } | 3358 | } |
| 3359 | }, | ||
| 3360 | }; | ||
| 3361 | |||
| 3362 | // We create a Decl for it regardless of analysis status. | ||
| 3363 | const gop = try namespace.decls.getOrPut(gpa, decl_name); | ||
| 3364 | if (!gop.found_existing) { | ||
| 3365 | const new_decl = try mod.allocateNewDecl(namespace, decl_node); | ||
| 3366 | log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); | ||
| 3367 | new_decl.src_line = line; | ||
| 3368 | new_decl.name = decl_name; | ||
| 3369 | gop.entry.value = new_decl; | ||
| 3370 | // Exported decls, comptime decls, usingnamespace decls, and | ||
| 3371 | // test decls if in test mode, get analyzed. | ||
| 3372 | const want_analysis = is_exported or switch (decl_name_index) { | ||
| 3373 | 0 => true, // comptime decl | ||
| 3374 | 1 => mod.comp.bin_file.options.is_test, // test decl | ||
| 3375 | else => is_named_test and mod.comp.bin_file.options.is_test, | ||
| 3376 | }; | ||
| 3377 | if (want_analysis) { | ||
| 3378 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); | ||
| 3379 | } | ||
| 3380 | new_decl.is_pub = is_pub; | ||
| 3381 | new_decl.is_exported = is_exported; | ||
| 3382 | new_decl.has_align = has_align; | ||
| 3383 | new_decl.has_linksection = has_linksection; | ||
| 3384 | new_decl.zir_decl_index = @intCast(u32, decl_sub_index); | ||
| 3385 | return; | ||
| 3386 | } | ||
| 3387 | gpa.free(decl_name); | ||
| 3388 | const decl = gop.entry.value; | ||
| 3389 | log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); | ||
| 3390 | // Update the AST node of the decl; even if its contents are unchanged, it may | ||
| 3391 | // have been re-ordered. | ||
| 3392 | const prev_src_node = decl.src_node; | ||
| 3393 | decl.src_node = decl_node; | ||
| 3394 | decl.src_line = line; | ||
| 3395 | |||
| 3396 | decl.is_pub = is_pub; | ||
| 3397 | decl.is_exported = is_exported; | ||
| 3398 | decl.has_align = has_align; | ||
| 3399 | decl.has_linksection = has_linksection; | ||
| 3400 | decl.zir_decl_index = @intCast(u32, decl_sub_index); | ||
| 3401 | if (decl.getFunction()) |func| { | ||
| 3402 | switch (mod.comp.bin_file.tag) { | ||
| 3403 | .coff => { | ||
| 3404 | // TODO Implement for COFF | ||
| 3405 | }, | ||
| 3406 | .elf => if (decl.fn_link.elf.len != 0) { | ||
| 3407 | // TODO Look into detecting when this would be unnecessary by storing enough state | ||
| 3408 | // in `Decl` to notice that the line number did not change. | ||
| 3409 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | ||
| 3410 | }, | ||
| 3411 | .macho => if (decl.fn_link.macho.len != 0) { | ||
| 3412 | // TODO Look into detecting when this would be unnecessary by storing enough state | ||
| 3413 | // in `Decl` to notice that the line number did not change. | ||
| 3414 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | ||
| 3415 | }, | ||
| 3416 | .c, .wasm, .spirv => {}, | ||
| 3603 | } | 3417 | } |
| 3604 | new_decl.is_pub = var_decl.visib_token != null; | ||
| 3605 | } | 3418 | } |
| 3606 | } | 3419 | } |
| 3607 | 3420 | ||
| 3608 | pub fn deleteDecl( | 3421 | /// Make it as if the semantic analysis for this Decl never happened. |
| 3422 | pub fn clearDecl( | ||
| 3609 | mod: *Module, | 3423 | mod: *Module, |
| 3610 | decl: *Decl, | 3424 | decl: *Decl, |
| 3611 | outdated_decls: ?*std.AutoArrayHashMap(*Decl, void), | 3425 | outdated_decls: ?*std.AutoArrayHashMap(*Decl, void), |
| 3612 | ) !void { | 3426 | ) Allocator.Error!void { |
| 3613 | const tracy = trace(@src()); | 3427 | const tracy = trace(@src()); |
| 3614 | defer tracy.end(); | 3428 | defer tracy.end(); |
| 3615 | 3429 | ||
| 3616 | log.debug("deleting decl '{s}'", .{decl.name}); | 3430 | log.debug("clearing {*} ({s})", .{ decl, decl.name }); |
| 3431 | |||
| 3432 | const gpa = mod.gpa; | ||
| 3433 | try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); | ||
| 3617 | 3434 | ||
| 3618 | if (outdated_decls) |map| { | 3435 | if (outdated_decls) |map| { |
| 3619 | _ = map.swapRemove(decl); | 3436 | _ = map.swapRemove(decl); |
| 3620 | try map.ensureCapacity(map.count() + decl.dependants.count()); | 3437 | try map.ensureUnusedCapacity(decl.dependants.count()); |
| 3621 | } | 3438 | } |
| 3622 | try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() + | ||
| 3623 | decl.dependencies.count()); | ||
| 3624 | |||
| 3625 | // Remove from the namespace it resides in. In the case of an anonymous Decl it will | ||
| 3626 | // not be present in the set, and this does nothing. | ||
| 3627 | decl.container.removeDecl(decl); | ||
| 3628 | 3439 | ||
| 3629 | const name_hash = decl.fullyQualifiedNameHash(); | 3440 | // Remove itself from its dependencies. |
| 3630 | mod.decl_table.removeAssertDiscard(name_hash); | ||
| 3631 | // Remove itself from its dependencies, because we are about to destroy the decl pointer. | ||
| 3632 | for (decl.dependencies.items()) |entry| { | 3441 | for (decl.dependencies.items()) |entry| { |
| 3633 | const dep = entry.key; | 3442 | const dep = entry.key; |
| 3634 | dep.removeDependant(decl); | 3443 | dep.removeDependant(decl); |
| ... | @@ -3639,6 +3448,8 @@ pub fn deleteDecl( | ... | @@ -3639,6 +3448,8 @@ pub fn deleteDecl( |
| 3639 | mod.deletion_set.putAssumeCapacity(dep, {}); | 3448 | mod.deletion_set.putAssumeCapacity(dep, {}); |
| 3640 | } | 3449 | } |
| 3641 | } | 3450 | } |
| 3451 | decl.dependencies.clearRetainingCapacity(); | ||
| 3452 | |||
| 3642 | // Anything that depends on this deleted decl needs to be re-analyzed. | 3453 | // Anything that depends on this deleted decl needs to be re-analyzed. |
| 3643 | for (decl.dependants.items()) |entry| { | 3454 | for (decl.dependants.items()) |entry| { |
| 3644 | const dep = entry.key; | 3455 | const dep = entry.key; |
| ... | @@ -3654,17 +3465,55 @@ pub fn deleteDecl( | ... | @@ -3654,17 +3465,55 @@ pub fn deleteDecl( |
| 3654 | assert(mod.deletion_set.contains(dep)); | 3465 | assert(mod.deletion_set.contains(dep)); |
| 3655 | } | 3466 | } |
| 3656 | } | 3467 | } |
| 3468 | decl.dependants.clearRetainingCapacity(); | ||
| 3469 | |||
| 3657 | if (mod.failed_decls.swapRemove(decl)) |entry| { | 3470 | if (mod.failed_decls.swapRemove(decl)) |entry| { |
| 3658 | entry.value.destroy(mod.gpa); | 3471 | entry.value.destroy(gpa); |
| 3472 | } | ||
| 3473 | if (mod.emit_h) |emit_h| { | ||
| 3474 | if (emit_h.failed_decls.swapRemove(decl)) |entry| { | ||
| 3475 | entry.value.destroy(gpa); | ||
| 3476 | } | ||
| 3477 | emit_h.decl_table.removeAssertDiscard(decl); | ||
| 3478 | } | ||
| 3479 | _ = mod.compile_log_decls.swapRemove(decl); | ||
| 3480 | mod.deleteDeclExports(decl); | ||
| 3481 | |||
| 3482 | if (decl.has_tv) { | ||
| 3483 | if (decl.ty.hasCodeGenBits()) { | ||
| 3484 | mod.comp.bin_file.freeDecl(decl); | ||
| 3485 | |||
| 3486 | // TODO instead of a union, put this memory trailing Decl objects, | ||
| 3487 | // and allow it to be variably sized. | ||
| 3488 | decl.link = switch (mod.comp.bin_file.tag) { | ||
| 3489 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, | ||
| 3490 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, | ||
| 3491 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, | ||
| 3492 | .c => .{ .c = link.File.C.DeclBlock.empty }, | ||
| 3493 | .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, | ||
| 3494 | .spirv => .{ .spirv = {} }, | ||
| 3495 | }; | ||
| 3496 | decl.fn_link = switch (mod.comp.bin_file.tag) { | ||
| 3497 | .coff => .{ .coff = {} }, | ||
| 3498 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, | ||
| 3499 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, | ||
| 3500 | .c => .{ .c = link.File.C.FnBlock.empty }, | ||
| 3501 | .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, | ||
| 3502 | .spirv => .{ .spirv = .{} }, | ||
| 3503 | }; | ||
| 3504 | } | ||
| 3505 | if (decl.getInnerNamespace()) |namespace| { | ||
| 3506 | try namespace.deleteAllDecls(mod, outdated_decls); | ||
| 3507 | } | ||
| 3508 | decl.clearValues(gpa); | ||
| 3659 | } | 3509 | } |
| 3660 | if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| { | 3510 | |
| 3661 | entry.value.destroy(mod.gpa); | 3511 | if (decl.deletion_flag) { |
| 3512 | decl.deletion_flag = false; | ||
| 3513 | mod.deletion_set.swapRemoveAssertDiscard(decl); | ||
| 3662 | } | 3514 | } |
| 3663 | _ = mod.compile_log_decls.swapRemove(decl); | ||
| 3664 | mod.deleteDeclExports(decl); | ||
| 3665 | mod.comp.bin_file.freeDecl(decl); | ||
| 3666 | 3515 | ||
| 3667 | decl.destroy(mod); | 3516 | decl.analysis = .unreferenced; |
| 3668 | } | 3517 | } |
| 3669 | 3518 | ||
| 3670 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of | 3519 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of |
| ... | @@ -3700,7 +3549,6 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void { | ... | @@ -3700,7 +3549,6 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void { |
| 3700 | if (mod.failed_exports.swapRemove(exp)) |entry| { | 3549 | if (mod.failed_exports.swapRemove(exp)) |entry| { |
| 3701 | entry.value.destroy(mod.gpa); | 3550 | entry.value.destroy(mod.gpa); |
| 3702 | } | 3551 | } |
| 3703 | _ = mod.symbol_exports.swapRemove(exp.options.name); | ||
| 3704 | mod.gpa.free(exp.options.name); | 3552 | mod.gpa.free(exp.options.name); |
| 3705 | mod.gpa.destroy(exp); | 3553 | mod.gpa.destroy(exp); |
| 3706 | } | 3554 | } |
| ... | @@ -3712,16 +3560,15 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3712,16 +3560,15 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3712 | defer tracy.end(); | 3560 | defer tracy.end(); |
| 3713 | 3561 | ||
| 3714 | // Use the Decl's arena for function memory. | 3562 | // Use the Decl's arena for function memory. |
| 3715 | var arena = decl.typed_value.most_recent.arena.?.promote(mod.gpa); | 3563 | var arena = decl.value_arena.?.promote(mod.gpa); |
| 3716 | defer decl.typed_value.most_recent.arena.?.* = arena.state; | 3564 | defer decl.value_arena.?.* = arena.state; |
| 3717 | 3565 | ||
| 3718 | const fn_ty = decl.typed_value.most_recent.typed_value.ty; | 3566 | const fn_ty = decl.ty; |
| 3719 | const param_inst_list = try mod.gpa.alloc(*ir.Inst, fn_ty.fnParamLen()); | 3567 | const param_inst_list = try mod.gpa.alloc(*ir.Inst, fn_ty.fnParamLen()); |
| 3720 | defer mod.gpa.free(param_inst_list); | 3568 | defer mod.gpa.free(param_inst_list); |
| 3721 | 3569 | ||
| 3722 | for (param_inst_list) |*param_inst, param_index| { | 3570 | for (param_inst_list) |*param_inst, param_index| { |
| 3723 | const param_type = fn_ty.fnParamType(param_index); | 3571 | const param_type = fn_ty.fnParamType(param_index); |
| 3724 | const name = func.zir.nullTerminatedString(func.zir.extra[param_index]); | ||
| 3725 | const arg_inst = try arena.allocator.create(ir.Inst.Arg); | 3572 | const arg_inst = try arena.allocator.create(ir.Inst.Arg); |
| 3726 | arg_inst.* = .{ | 3573 | arg_inst.* = .{ |
| 3727 | .base = .{ | 3574 | .base = .{ |
| ... | @@ -3729,23 +3576,25 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3729,23 +3576,25 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3729 | .ty = param_type, | 3576 | .ty = param_type, |
| 3730 | .src = .unneeded, | 3577 | .src = .unneeded, |
| 3731 | }, | 3578 | }, |
| 3732 | .name = name, | 3579 | .name = undefined, // Set in the semantic analysis of the arg instruction. |
| 3733 | }; | 3580 | }; |
| 3734 | param_inst.* = &arg_inst.base; | 3581 | param_inst.* = &arg_inst.base; |
| 3735 | } | 3582 | } |
| 3736 | 3583 | ||
| 3584 | const zir = decl.namespace.file_scope.zir; | ||
| 3585 | |||
| 3737 | var sema: Sema = .{ | 3586 | var sema: Sema = .{ |
| 3738 | .mod = mod, | 3587 | .mod = mod, |
| 3739 | .gpa = mod.gpa, | 3588 | .gpa = mod.gpa, |
| 3740 | .arena = &arena.allocator, | 3589 | .arena = &arena.allocator, |
| 3741 | .code = func.zir, | 3590 | .code = zir, |
| 3742 | .inst_map = try mod.gpa.alloc(*ir.Inst, func.zir.instructions.len), | ||
| 3743 | .owner_decl = decl, | 3591 | .owner_decl = decl, |
| 3592 | .namespace = decl.namespace, | ||
| 3744 | .func = func, | 3593 | .func = func, |
| 3745 | .owner_func = func, | 3594 | .owner_func = func, |
| 3746 | .param_inst_list = param_inst_list, | 3595 | .param_inst_list = param_inst_list, |
| 3747 | }; | 3596 | }; |
| 3748 | defer mod.gpa.free(sema.inst_map); | 3597 | defer sema.deinit(); |
| 3749 | 3598 | ||
| 3750 | var inner_block: Scope.Block = .{ | 3599 | var inner_block: Scope.Block = .{ |
| 3751 | .parent = null, | 3600 | .parent = null, |
| ... | @@ -3757,13 +3606,13 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3757,13 +3606,13 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3757 | }; | 3606 | }; |
| 3758 | defer inner_block.instructions.deinit(mod.gpa); | 3607 | defer inner_block.instructions.deinit(mod.gpa); |
| 3759 | 3608 | ||
| 3760 | // TZIR currently requires the arg parameters to be the first N instructions | 3609 | // AIR currently requires the arg parameters to be the first N instructions |
| 3761 | try inner_block.instructions.appendSlice(mod.gpa, param_inst_list); | 3610 | try inner_block.instructions.appendSlice(mod.gpa, param_inst_list); |
| 3762 | 3611 | ||
| 3763 | func.state = .in_progress; | 3612 | func.state = .in_progress; |
| 3764 | log.debug("set {s} to in_progress", .{decl.name}); | 3613 | log.debug("set {s} to in_progress", .{decl.name}); |
| 3765 | 3614 | ||
| 3766 | _ = try sema.root(&inner_block); | 3615 | try sema.analyzeFnBody(&inner_block, func.zir_body_inst); |
| 3767 | 3616 | ||
| 3768 | const instructions = try arena.allocator.dupe(*ir.Inst, inner_block.instructions.items); | 3617 | const instructions = try arena.allocator.dupe(*ir.Inst, inner_block.instructions.items); |
| 3769 | func.state = .success; | 3618 | func.state = .success; |
| ... | @@ -3772,24 +3621,21 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3772,24 +3621,21 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3772 | } | 3621 | } |
| 3773 | 3622 | ||
| 3774 | fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { | 3623 | fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { |
| 3775 | log.debug("mark {s} outdated", .{decl.name}); | 3624 | log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); |
| 3776 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl }); | 3625 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl }); |
| 3777 | if (mod.failed_decls.swapRemove(decl)) |entry| { | 3626 | if (mod.failed_decls.swapRemove(decl)) |entry| { |
| 3778 | entry.value.destroy(mod.gpa); | 3627 | entry.value.destroy(mod.gpa); |
| 3779 | } | 3628 | } |
| 3780 | if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| { | 3629 | if (mod.emit_h) |emit_h| { |
| 3781 | entry.value.destroy(mod.gpa); | 3630 | if (emit_h.failed_decls.swapRemove(decl)) |entry| { |
| 3631 | entry.value.destroy(mod.gpa); | ||
| 3632 | } | ||
| 3782 | } | 3633 | } |
| 3783 | _ = mod.compile_log_decls.swapRemove(decl); | 3634 | _ = mod.compile_log_decls.swapRemove(decl); |
| 3784 | decl.analysis = .outdated; | 3635 | decl.analysis = .outdated; |
| 3785 | } | 3636 | } |
| 3786 | 3637 | ||
| 3787 | fn allocateNewDecl( | 3638 | fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl { |
| 3788 | mod: *Module, | ||
| 3789 | scope: *Scope, | ||
| 3790 | src_node: ast.Node.Index, | ||
| 3791 | contents_hash: std.zig.SrcHash, | ||
| 3792 | ) !*Decl { | ||
| 3793 | // If we have emit-h then we must allocate a bigger structure to store the emit-h state. | 3639 | // If we have emit-h then we must allocate a bigger structure to store the emit-h state. |
| 3794 | const new_decl: *Decl = if (mod.emit_h != null) blk: { | 3640 | const new_decl: *Decl = if (mod.emit_h != null) blk: { |
| 3795 | const parent_struct = try mod.gpa.create(DeclPlusEmitH); | 3641 | const parent_struct = try mod.gpa.create(DeclPlusEmitH); |
| ... | @@ -3802,12 +3648,18 @@ fn allocateNewDecl( | ... | @@ -3802,12 +3648,18 @@ fn allocateNewDecl( |
| 3802 | 3648 | ||
| 3803 | new_decl.* = .{ | 3649 | new_decl.* = .{ |
| 3804 | .name = "", | 3650 | .name = "", |
| 3805 | .container = scope.namespace(), | 3651 | .namespace = namespace, |
| 3806 | .src_node = src_node, | 3652 | .src_node = src_node, |
| 3807 | .typed_value = .{ .never_succeeded = {} }, | 3653 | .src_line = undefined, |
| 3654 | .has_tv = false, | ||
| 3655 | .owns_tv = false, | ||
| 3656 | .ty = undefined, | ||
| 3657 | .val = undefined, | ||
| 3658 | .align_val = undefined, | ||
| 3659 | .linksection_val = undefined, | ||
| 3808 | .analysis = .unreferenced, | 3660 | .analysis = .unreferenced, |
| 3809 | .deletion_flag = false, | 3661 | .deletion_flag = false, |
| 3810 | .contents_hash = contents_hash, | 3662 | .zir_decl_index = 0, |
| 3811 | .link = switch (mod.comp.bin_file.tag) { | 3663 | .link = switch (mod.comp.bin_file.tag) { |
| 3812 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, | 3664 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, |
| 3813 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, | 3665 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, |
| ... | @@ -3826,26 +3678,13 @@ fn allocateNewDecl( | ... | @@ -3826,26 +3678,13 @@ fn allocateNewDecl( |
| 3826 | }, | 3678 | }, |
| 3827 | .generation = 0, | 3679 | .generation = 0, |
| 3828 | .is_pub = false, | 3680 | .is_pub = false, |
| 3681 | .is_exported = false, | ||
| 3682 | .has_linksection = false, | ||
| 3683 | .has_align = false, | ||
| 3829 | }; | 3684 | }; |
| 3830 | return new_decl; | 3685 | return new_decl; |
| 3831 | } | 3686 | } |
| 3832 | 3687 | ||
| 3833 | fn createNewDecl( | ||
| 3834 | mod: *Module, | ||
| 3835 | scope: *Scope, | ||
| 3836 | decl_name: []const u8, | ||
| 3837 | src_node: ast.Node.Index, | ||
| 3838 | name_hash: Scope.NameHash, | ||
| 3839 | contents_hash: std.zig.SrcHash, | ||
| 3840 | ) !*Decl { | ||
| 3841 | try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1); | ||
| 3842 | const new_decl = try mod.allocateNewDecl(scope, src_node, contents_hash); | ||
| 3843 | errdefer mod.gpa.destroy(new_decl); | ||
| 3844 | new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name); | ||
| 3845 | mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl); | ||
| 3846 | return new_decl; | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | /// Get error value for error tag `name`. | 3688 | /// Get error value for error tag `name`. |
| 3850 | pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).Entry { | 3689 | pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).Entry { |
| 3851 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); | 3690 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); |
| ... | @@ -3868,10 +3707,9 @@ pub fn analyzeExport( | ... | @@ -3868,10 +3707,9 @@ pub fn analyzeExport( |
| 3868 | exported_decl: *Decl, | 3707 | exported_decl: *Decl, |
| 3869 | ) !void { | 3708 | ) !void { |
| 3870 | try mod.ensureDeclAnalyzed(exported_decl); | 3709 | try mod.ensureDeclAnalyzed(exported_decl); |
| 3871 | const typed_value = exported_decl.typed_value.most_recent.typed_value; | 3710 | switch (exported_decl.ty.zigTypeTag()) { |
| 3872 | switch (typed_value.ty.zigTypeTag()) { | ||
| 3873 | .Fn => {}, | 3711 | .Fn => {}, |
| 3874 | else => return mod.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}), | 3712 | else => return mod.fail(scope, src, "unable to export type '{}'", .{exported_decl.ty}), |
| 3875 | } | 3713 | } |
| 3876 | 3714 | ||
| 3877 | try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.items().len + 1); | 3715 | try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.items().len + 1); |
| ... | @@ -3885,6 +3723,10 @@ pub fn analyzeExport( | ... | @@ -3885,6 +3723,10 @@ pub fn analyzeExport( |
| 3885 | 3723 | ||
| 3886 | const owner_decl = scope.ownerDecl().?; | 3724 | const owner_decl = scope.ownerDecl().?; |
| 3887 | 3725 | ||
| 3726 | log.debug("exporting Decl '{s}' as symbol '{s}' from Decl '{s}'", .{ | ||
| 3727 | exported_decl.name, borrowed_symbol_name, owner_decl.name, | ||
| 3728 | }); | ||
| 3729 | |||
| 3888 | new_export.* = .{ | 3730 | new_export.* = .{ |
| 3889 | .options = .{ .name = symbol_name }, | 3731 | .options = .{ .name = symbol_name }, |
| 3890 | .src = src, | 3732 | .src = src, |
| ... | @@ -3918,39 +3760,6 @@ pub fn analyzeExport( | ... | @@ -3918,39 +3760,6 @@ pub fn analyzeExport( |
| 3918 | de_gop.entry.value = try mod.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1); | 3760 | de_gop.entry.value = try mod.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1); |
| 3919 | de_gop.entry.value[de_gop.entry.value.len - 1] = new_export; | 3761 | de_gop.entry.value[de_gop.entry.value.len - 1] = new_export; |
| 3920 | errdefer de_gop.entry.value = mod.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1); | 3762 | errdefer de_gop.entry.value = mod.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1); |
| 3921 | |||
| 3922 | if (mod.symbol_exports.get(symbol_name)) |other_export| { | ||
| 3923 | new_export.status = .failed_retryable; | ||
| 3924 | try mod.failed_exports.ensureCapacity(mod.gpa, mod.failed_exports.items().len + 1); | ||
| 3925 | const msg = try mod.errMsg( | ||
| 3926 | scope, | ||
| 3927 | src, | ||
| 3928 | "exported symbol collision: {s}", | ||
| 3929 | .{symbol_name}, | ||
| 3930 | ); | ||
| 3931 | errdefer msg.destroy(mod.gpa); | ||
| 3932 | try mod.errNote( | ||
| 3933 | &other_export.owner_decl.container.base, | ||
| 3934 | other_export.src, | ||
| 3935 | msg, | ||
| 3936 | "other symbol here", | ||
| 3937 | .{}, | ||
| 3938 | ); | ||
| 3939 | mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); | ||
| 3940 | new_export.status = .failed; | ||
| 3941 | return; | ||
| 3942 | } | ||
| 3943 | |||
| 3944 | try mod.symbol_exports.putNoClobber(mod.gpa, symbol_name, new_export); | ||
| 3945 | mod.comp.bin_file.updateDeclExports(mod, exported_decl, de_gop.entry.value) catch |err| switch (err) { | ||
| 3946 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3947 | else => { | ||
| 3948 | new_export.status = .failed_retryable; | ||
| 3949 | try mod.failed_exports.ensureCapacity(mod.gpa, mod.failed_exports.items().len + 1); | ||
| 3950 | const msg = try mod.errMsg(scope, src, "unable to export: {s}", .{@errorName(err)}); | ||
| 3951 | mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); | ||
| 3952 | }, | ||
| 3953 | }; | ||
| 3954 | } | 3763 | } |
| 3955 | pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst { | 3764 | pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst { |
| 3956 | const const_inst = try arena.create(ir.Inst.Constant); | 3765 | const const_inst = try arena.create(ir.Inst.Constant); |
| ... | @@ -4040,31 +3849,38 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b | ... | @@ -4040,31 +3849,38 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b |
| 4040 | } | 3849 | } |
| 4041 | } | 3850 | } |
| 4042 | 3851 | ||
| 4043 | pub fn createAnonymousDecl( | 3852 | pub fn deleteAnonDecl(mod: *Module, scope: *Scope, decl: *Decl) void { |
| 3853 | const scope_decl = scope.ownerDecl().?; | ||
| 3854 | scope_decl.namespace.anon_decls.swapRemoveAssertDiscard(decl); | ||
| 3855 | decl.destroy(mod); | ||
| 3856 | } | ||
| 3857 | |||
| 3858 | /// Takes ownership of `name` even if it returns an error. | ||
| 3859 | pub fn createAnonymousDeclNamed( | ||
| 4044 | mod: *Module, | 3860 | mod: *Module, |
| 4045 | scope: *Scope, | 3861 | scope: *Scope, |
| 4046 | decl_arena: *std.heap.ArenaAllocator, | ||
| 4047 | typed_value: TypedValue, | 3862 | typed_value: TypedValue, |
| 3863 | name: [:0]u8, | ||
| 4048 | ) !*Decl { | 3864 | ) !*Decl { |
| 4049 | const name_index = mod.getNextAnonNameIndex(); | 3865 | errdefer mod.gpa.free(name); |
| 3866 | |||
| 4050 | const scope_decl = scope.ownerDecl().?; | 3867 | const scope_decl = scope.ownerDecl().?; |
| 4051 | const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); | 3868 | const namespace = scope_decl.namespace; |
| 4052 | defer mod.gpa.free(name); | 3869 | try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4053 | const name_hash = scope.namespace().fullyQualifiedNameHash(name); | ||
| 4054 | const src_hash: std.zig.SrcHash = undefined; | ||
| 4055 | const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash); | ||
| 4056 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 4057 | 3870 | ||
| 4058 | decl_arena_state.* = decl_arena.state; | 3871 | const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node); |
| 4059 | new_decl.typed_value = .{ | 3872 | |
| 4060 | .most_recent = .{ | 3873 | new_decl.name = name; |
| 4061 | .typed_value = typed_value, | 3874 | new_decl.src_line = scope_decl.src_line; |
| 4062 | .arena = decl_arena_state, | 3875 | new_decl.ty = typed_value.ty; |
| 4063 | }, | 3876 | new_decl.val = typed_value.val; |
| 4064 | }; | 3877 | new_decl.has_tv = true; |
| 3878 | new_decl.owns_tv = true; | ||
| 4065 | new_decl.analysis = .complete; | 3879 | new_decl.analysis = .complete; |
| 4066 | new_decl.generation = mod.generation; | 3880 | new_decl.generation = mod.generation; |
| 4067 | 3881 | ||
| 3882 | namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {}); | ||
| 3883 | |||
| 4068 | // TODO: This generates the Decl into the machine code file if it is of a | 3884 | // TODO: This generates the Decl into the machine code file if it is of a |
| 4069 | // type that is non-zero size. We should be able to further improve the | 3885 | // type that is non-zero size. We should be able to further improve the |
| 4070 | // compiler to omit Decls which are only referenced at compile-time and not runtime. | 3886 | // compiler to omit Decls which are only referenced at compile-time and not runtime. |
| ... | @@ -4076,59 +3892,19 @@ pub fn createAnonymousDecl( | ... | @@ -4076,59 +3892,19 @@ pub fn createAnonymousDecl( |
| 4076 | return new_decl; | 3892 | return new_decl; |
| 4077 | } | 3893 | } |
| 4078 | 3894 | ||
| 4079 | pub fn createContainerDecl( | 3895 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { |
| 4080 | mod: *Module, | ||
| 4081 | scope: *Scope, | ||
| 4082 | base_token: std.zig.ast.TokenIndex, | ||
| 4083 | decl_arena: *std.heap.ArenaAllocator, | ||
| 4084 | typed_value: TypedValue, | ||
| 4085 | ) !*Decl { | ||
| 4086 | const scope_decl = scope.ownerDecl().?; | 3896 | const scope_decl = scope.ownerDecl().?; |
| 4087 | const name = try mod.getAnonTypeName(scope, base_token); | 3897 | const name_index = mod.getNextAnonNameIndex(); |
| 4088 | defer mod.gpa.free(name); | 3898 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ |
| 4089 | const name_hash = scope.namespace().fullyQualifiedNameHash(name); | 3899 | scope_decl.name, name_index, |
| 4090 | const src_hash: std.zig.SrcHash = undefined; | 3900 | }); |
| 4091 | const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash); | 3901 | return mod.createAnonymousDeclNamed(scope, typed_value, name); |
| 4092 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | ||
| 4093 | |||
| 4094 | decl_arena_state.* = decl_arena.state; | ||
| 4095 | new_decl.typed_value = .{ | ||
| 4096 | .most_recent = .{ | ||
| 4097 | .typed_value = typed_value, | ||
| 4098 | .arena = decl_arena_state, | ||
| 4099 | }, | ||
| 4100 | }; | ||
| 4101 | new_decl.analysis = .complete; | ||
| 4102 | new_decl.generation = mod.generation; | ||
| 4103 | |||
| 4104 | return new_decl; | ||
| 4105 | } | ||
| 4106 | |||
| 4107 | fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 { | ||
| 4108 | // TODO add namespaces, generic function signatrues | ||
| 4109 | const tree = scope.tree(); | ||
| 4110 | const token_tags = tree.tokens.items(.tag); | ||
| 4111 | const base_name = switch (token_tags[base_token]) { | ||
| 4112 | .keyword_struct => "struct", | ||
| 4113 | .keyword_enum => "enum", | ||
| 4114 | .keyword_union => "union", | ||
| 4115 | .keyword_opaque => "opaque", | ||
| 4116 | else => unreachable, | ||
| 4117 | }; | ||
| 4118 | const loc = tree.tokenLocation(0, base_token); | ||
| 4119 | return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column }); | ||
| 4120 | } | 3902 | } |
| 4121 | 3903 | ||
| 4122 | fn getNextAnonNameIndex(mod: *Module) usize { | 3904 | pub fn getNextAnonNameIndex(mod: *Module) usize { |
| 4123 | return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic); | 3905 | return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic); |
| 4124 | } | 3906 | } |
| 4125 | 3907 | ||
| 4126 | pub fn lookupDeclName(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl { | ||
| 4127 | const namespace = scope.namespace(); | ||
| 4128 | const name_hash = namespace.fullyQualifiedNameHash(ident_name); | ||
| 4129 | return mod.decl_table.get(name_hash); | ||
| 4130 | } | ||
| 4131 | |||
| 4132 | pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type { | 3908 | pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type { |
| 4133 | const int_payload = try arena.create(Type.Payload.Bits); | 3909 | const int_payload = try arena.create(Type.Payload.Bits); |
| 4134 | int_payload.* = .{ | 3910 | int_payload.* = .{ |
| ... | @@ -4194,20 +3970,6 @@ pub fn fail( | ... | @@ -4194,20 +3970,6 @@ pub fn fail( |
| 4194 | return mod.failWithOwnedErrorMsg(scope, err_msg); | 3970 | return mod.failWithOwnedErrorMsg(scope, err_msg); |
| 4195 | } | 3971 | } |
| 4196 | 3972 | ||
| 4197 | /// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc` | ||
| 4198 | /// for pointing at it relatively by subtracting from the containing `Decl`. | ||
| 4199 | pub fn failOff( | ||
| 4200 | mod: *Module, | ||
| 4201 | scope: *Scope, | ||
| 4202 | byte_offset: u32, | ||
| 4203 | comptime format: []const u8, | ||
| 4204 | args: anytype, | ||
| 4205 | ) InnerError { | ||
| 4206 | const decl_byte_offset = scope.srcDecl().?.srcByteOffset(); | ||
| 4207 | const src: LazySrcLoc = .{ .byte_offset = byte_offset - decl_byte_offset }; | ||
| 4208 | return mod.fail(scope, src, format, args); | ||
| 4209 | } | ||
| 4210 | |||
| 4211 | /// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc` | 3973 | /// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc` |
| 4212 | /// for pointing at it relatively by subtracting from the containing `Decl`. | 3974 | /// for pointing at it relatively by subtracting from the containing `Decl`. |
| 4213 | pub fn failTok( | 3975 | pub fn failTok( |
| ... | @@ -4236,6 +3998,7 @@ pub fn failNode( | ... | @@ -4236,6 +3998,7 @@ pub fn failNode( |
| 4236 | 3998 | ||
| 4237 | pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError { | 3999 | pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError { |
| 4238 | @setCold(true); | 4000 | @setCold(true); |
| 4001 | |||
| 4239 | { | 4002 | { |
| 4240 | errdefer err_msg.destroy(mod.gpa); | 4003 | errdefer err_msg.destroy(mod.gpa); |
| 4241 | try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1); | 4004 | try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1); |
| ... | @@ -4252,40 +4015,12 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In | ... | @@ -4252,40 +4015,12 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In |
| 4252 | } | 4015 | } |
| 4253 | mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg); | 4016 | mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg); |
| 4254 | }, | 4017 | }, |
| 4255 | .gen_zir => { | ||
| 4256 | const gen_zir = scope.cast(Scope.GenZir).?; | ||
| 4257 | gen_zir.astgen.decl.analysis = .sema_failure; | ||
| 4258 | gen_zir.astgen.decl.generation = mod.generation; | ||
| 4259 | mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg); | ||
| 4260 | }, | ||
| 4261 | .local_val => { | ||
| 4262 | const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir; | ||
| 4263 | gen_zir.astgen.decl.analysis = .sema_failure; | ||
| 4264 | gen_zir.astgen.decl.generation = mod.generation; | ||
| 4265 | mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg); | ||
| 4266 | }, | ||
| 4267 | .local_ptr => { | ||
| 4268 | const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir; | ||
| 4269 | gen_zir.astgen.decl.analysis = .sema_failure; | ||
| 4270 | gen_zir.astgen.decl.generation = mod.generation; | ||
| 4271 | mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg); | ||
| 4272 | }, | ||
| 4273 | .file => unreachable, | 4018 | .file => unreachable, |
| 4274 | .container => unreachable, | 4019 | .namespace => unreachable, |
| 4275 | .decl_ref => { | ||
| 4276 | const decl_ref = scope.cast(Scope.DeclRef).?; | ||
| 4277 | decl_ref.decl.analysis = .sema_failure; | ||
| 4278 | decl_ref.decl.generation = mod.generation; | ||
| 4279 | mod.failed_decls.putAssumeCapacityNoClobber(decl_ref.decl, err_msg); | ||
| 4280 | }, | ||
| 4281 | } | 4020 | } |
| 4282 | return error.AnalysisFail; | 4021 | return error.AnalysisFail; |
| 4283 | } | 4022 | } |
| 4284 | 4023 | ||
| 4285 | fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool { | ||
| 4286 | return @bitCast(u128, a) == @bitCast(u128, b); | ||
| 4287 | } | ||
| 4288 | |||
| 4289 | pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value { | 4024 | pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value { |
| 4290 | // TODO is this a performance issue? maybe we should try the operation without | 4025 | // TODO is this a performance issue? maybe we should try the operation without |
| 4291 | // resorting to BigInt first. | 4026 | // resorting to BigInt first. |
| ... | @@ -4330,6 +4065,37 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value { | ... | @@ -4330,6 +4065,37 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value { |
| 4330 | } | 4065 | } |
| 4331 | } | 4066 | } |
| 4332 | 4067 | ||
| 4068 | pub fn intDiv(allocator: *Allocator, lhs: Value, rhs: Value) !Value { | ||
| 4069 | // TODO is this a performance issue? maybe we should try the operation without | ||
| 4070 | // resorting to BigInt first. | ||
| 4071 | var lhs_space: Value.BigIntSpace = undefined; | ||
| 4072 | var rhs_space: Value.BigIntSpace = undefined; | ||
| 4073 | const lhs_bigint = lhs.toBigInt(&lhs_space); | ||
| 4074 | const rhs_bigint = rhs.toBigInt(&rhs_space); | ||
| 4075 | const limbs_q = try allocator.alloc( | ||
| 4076 | std.math.big.Limb, | ||
| 4077 | lhs_bigint.limbs.len + rhs_bigint.limbs.len + 1, | ||
| 4078 | ); | ||
| 4079 | const limbs_r = try allocator.alloc( | ||
| 4080 | std.math.big.Limb, | ||
| 4081 | lhs_bigint.limbs.len, | ||
| 4082 | ); | ||
| 4083 | const limbs_buffer = try allocator.alloc( | ||
| 4084 | std.math.big.Limb, | ||
| 4085 | std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), | ||
| 4086 | ); | ||
| 4087 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | ||
| 4088 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | ||
| 4089 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer, null); | ||
| 4090 | const result_limbs = result_q.limbs[0..result_q.len]; | ||
| 4091 | |||
| 4092 | if (result_q.positive) { | ||
| 4093 | return Value.Tag.int_big_positive.create(allocator, result_limbs); | ||
| 4094 | } else { | ||
| 4095 | return Value.Tag.int_big_negative.create(allocator, result_limbs); | ||
| 4096 | } | ||
| 4097 | } | ||
| 4098 | |||
| 4333 | pub fn intMul(allocator: *Allocator, lhs: Value, rhs: Value) !Value { | 4099 | pub fn intMul(allocator: *Allocator, lhs: Value, rhs: Value) !Value { |
| 4334 | // TODO is this a performance issue? maybe we should try the operation without | 4100 | // TODO is this a performance issue? maybe we should try the operation without |
| 4335 | // resorting to BigInt first. | 4101 | // resorting to BigInt first. |
| ... | @@ -4423,6 +4189,39 @@ pub fn floatSub( | ... | @@ -4423,6 +4189,39 @@ pub fn floatSub( |
| 4423 | } | 4189 | } |
| 4424 | } | 4190 | } |
| 4425 | 4191 | ||
| 4192 | pub fn floatDiv( | ||
| 4193 | arena: *Allocator, | ||
| 4194 | float_type: Type, | ||
| 4195 | src: LazySrcLoc, | ||
| 4196 | lhs: Value, | ||
| 4197 | rhs: Value, | ||
| 4198 | ) !Value { | ||
| 4199 | switch (float_type.tag()) { | ||
| 4200 | .f16 => { | ||
| 4201 | @panic("TODO add __trunctfhf2 to compiler-rt"); | ||
| 4202 | //const lhs_val = lhs.toFloat(f16); | ||
| 4203 | //const rhs_val = rhs.toFloat(f16); | ||
| 4204 | //return Value.Tag.float_16.create(arena, lhs_val / rhs_val); | ||
| 4205 | }, | ||
| 4206 | .f32 => { | ||
| 4207 | const lhs_val = lhs.toFloat(f32); | ||
| 4208 | const rhs_val = rhs.toFloat(f32); | ||
| 4209 | return Value.Tag.float_32.create(arena, lhs_val / rhs_val); | ||
| 4210 | }, | ||
| 4211 | .f64 => { | ||
| 4212 | const lhs_val = lhs.toFloat(f64); | ||
| 4213 | const rhs_val = rhs.toFloat(f64); | ||
| 4214 | return Value.Tag.float_64.create(arena, lhs_val / rhs_val); | ||
| 4215 | }, | ||
| 4216 | .f128, .comptime_float, .c_longdouble => { | ||
| 4217 | const lhs_val = lhs.toFloat(f128); | ||
| 4218 | const rhs_val = rhs.toFloat(f128); | ||
| 4219 | return Value.Tag.float_128.create(arena, lhs_val / rhs_val); | ||
| 4220 | }, | ||
| 4221 | else => unreachable, | ||
| 4222 | } | ||
| 4223 | } | ||
| 4224 | |||
| 4426 | pub fn floatMul( | 4225 | pub fn floatMul( |
| 4427 | arena: *Allocator, | 4226 | arena: *Allocator, |
| 4428 | float_type: Type, | 4227 | float_type: Type, |
| ... | @@ -4615,138 +4414,512 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode { | ... | @@ -4615,138 +4414,512 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode { |
| 4615 | return mod.comp.bin_file.options.optimize_mode; | 4414 | return mod.comp.bin_file.options.optimize_mode; |
| 4616 | } | 4415 | } |
| 4617 | 4416 | ||
| 4618 | /// Given an identifier token, obtain the string for it. | 4417 | fn lockAndClearFileCompileError(mod: *Module, file: *Scope.File) void { |
| 4619 | /// If the token uses @"" syntax, parses as a string, reports errors if applicable, | 4418 | switch (file.status) { |
| 4620 | /// and allocates the result within `scope.arena()`. | 4419 | .success_zir, .retryable_failure => {}, |
| 4621 | /// Otherwise, returns a reference to the source code bytes directly. | 4420 | .never_loaded, .parse_failure, .astgen_failure => { |
| 4622 | /// See also `appendIdentStr` and `parseStrLit`. | 4421 | const lock = mod.comp.mutex.acquire(); |
| 4623 | pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 { | 4422 | defer lock.release(); |
| 4624 | const tree = scope.tree(); | 4423 | if (mod.failed_files.swapRemove(file)) |entry| { |
| 4625 | const token_tags = tree.tokens.items(.tag); | 4424 | if (entry.value) |msg| msg.destroy(mod.gpa); // Delete previous error message. |
| 4626 | assert(token_tags[token] == .identifier); | 4425 | } |
| 4627 | const ident_name = tree.tokenSlice(token); | 4426 | }, |
| 4628 | if (!mem.startsWith(u8, ident_name, "@")) { | 4427 | } |
| 4629 | return ident_name; | ||
| 4630 | } | ||
| 4631 | var buf: ArrayListUnmanaged(u8) = .{}; | ||
| 4632 | defer buf.deinit(mod.gpa); | ||
| 4633 | try parseStrLit(mod, scope, token, &buf, ident_name, 1); | ||
| 4634 | const duped = try scope.arena().dupe(u8, buf.items); | ||
| 4635 | return duped; | ||
| 4636 | } | 4428 | } |
| 4637 | 4429 | ||
| 4638 | /// `scope` is only used for error reporting. | 4430 | pub const SwitchProngSrc = union(enum) { |
| 4639 | /// The string is stored in `arena` regardless of whether it uses @"" syntax. | 4431 | scalar: u32, |
| 4640 | pub fn identifierTokenStringTreeArena( | 4432 | multi: Multi, |
| 4641 | mod: *Module, | 4433 | range: Multi, |
| 4642 | scope: *Scope, | 4434 | |
| 4643 | token: ast.TokenIndex, | 4435 | pub const Multi = struct { |
| 4644 | tree: *const ast.Tree, | 4436 | prong: u32, |
| 4645 | arena: *Allocator, | 4437 | item: u32, |
| 4646 | ) InnerError![]u8 { | 4438 | }; |
| 4647 | const token_tags = tree.tokens.items(.tag); | 4439 | |
| 4648 | assert(token_tags[token] == .identifier); | 4440 | pub const RangeExpand = enum { none, first, last }; |
| 4649 | const ident_name = tree.tokenSlice(token); | 4441 | |
| 4650 | if (!mem.startsWith(u8, ident_name, "@")) { | 4442 | /// This function is intended to be called only when it is certain that we need |
| 4651 | return arena.dupe(u8, ident_name); | 4443 | /// the LazySrcLoc in order to emit a compile error. |
| 4652 | } | 4444 | pub fn resolve( |
| 4653 | var buf: ArrayListUnmanaged(u8) = .{}; | 4445 | prong_src: SwitchProngSrc, |
| 4654 | defer buf.deinit(mod.gpa); | 4446 | gpa: *Allocator, |
| 4655 | try parseStrLit(mod, scope, token, &buf, ident_name, 1); | 4447 | decl: *Decl, |
| 4656 | return arena.dupe(u8, buf.items); | 4448 | switch_node_offset: i32, |
| 4449 | range_expand: RangeExpand, | ||
| 4450 | ) LazySrcLoc { | ||
| 4451 | @setCold(true); | ||
| 4452 | const tree = decl.namespace.file_scope.getTree(gpa) catch |err| { | ||
| 4453 | // In this case we emit a warning + a less precise source location. | ||
| 4454 | log.warn("unable to load {s}: {s}", .{ | ||
| 4455 | decl.namespace.file_scope.sub_file_path, @errorName(err), | ||
| 4456 | }); | ||
| 4457 | return LazySrcLoc{ .node_offset = 0 }; | ||
| 4458 | }; | ||
| 4459 | const switch_node = decl.relativeToNodeIndex(switch_node_offset); | ||
| 4460 | const main_tokens = tree.nodes.items(.main_token); | ||
| 4461 | const node_datas = tree.nodes.items(.data); | ||
| 4462 | const node_tags = tree.nodes.items(.tag); | ||
| 4463 | const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); | ||
| 4464 | const case_nodes = tree.extra_data[extra.start..extra.end]; | ||
| 4465 | |||
| 4466 | var multi_i: u32 = 0; | ||
| 4467 | var scalar_i: u32 = 0; | ||
| 4468 | for (case_nodes) |case_node| { | ||
| 4469 | const case = switch (node_tags[case_node]) { | ||
| 4470 | .switch_case_one => tree.switchCaseOne(case_node), | ||
| 4471 | .switch_case => tree.switchCase(case_node), | ||
| 4472 | else => unreachable, | ||
| 4473 | }; | ||
| 4474 | if (case.ast.values.len == 0) | ||
| 4475 | continue; | ||
| 4476 | if (case.ast.values.len == 1 and | ||
| 4477 | node_tags[case.ast.values[0]] == .identifier and | ||
| 4478 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) | ||
| 4479 | { | ||
| 4480 | continue; | ||
| 4481 | } | ||
| 4482 | const is_multi = case.ast.values.len != 1 or | ||
| 4483 | node_tags[case.ast.values[0]] == .switch_range; | ||
| 4484 | |||
| 4485 | switch (prong_src) { | ||
| 4486 | .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc{ | ||
| 4487 | .node_offset = decl.nodeIndexToRelative(case.ast.values[0]), | ||
| 4488 | }, | ||
| 4489 | .multi => |s| if (is_multi and s.prong == multi_i) { | ||
| 4490 | var item_i: u32 = 0; | ||
| 4491 | for (case.ast.values) |item_node| { | ||
| 4492 | if (node_tags[item_node] == .switch_range) continue; | ||
| 4493 | |||
| 4494 | if (item_i == s.item) return LazySrcLoc{ | ||
| 4495 | .node_offset = decl.nodeIndexToRelative(item_node), | ||
| 4496 | }; | ||
| 4497 | item_i += 1; | ||
| 4498 | } else unreachable; | ||
| 4499 | }, | ||
| 4500 | .range => |s| if (is_multi and s.prong == multi_i) { | ||
| 4501 | var range_i: u32 = 0; | ||
| 4502 | for (case.ast.values) |range| { | ||
| 4503 | if (node_tags[range] != .switch_range) continue; | ||
| 4504 | |||
| 4505 | if (range_i == s.item) switch (range_expand) { | ||
| 4506 | .none => return LazySrcLoc{ | ||
| 4507 | .node_offset = decl.nodeIndexToRelative(range), | ||
| 4508 | }, | ||
| 4509 | .first => return LazySrcLoc{ | ||
| 4510 | .node_offset = decl.nodeIndexToRelative(node_datas[range].lhs), | ||
| 4511 | }, | ||
| 4512 | .last => return LazySrcLoc{ | ||
| 4513 | .node_offset = decl.nodeIndexToRelative(node_datas[range].rhs), | ||
| 4514 | }, | ||
| 4515 | }; | ||
| 4516 | range_i += 1; | ||
| 4517 | } else unreachable; | ||
| 4518 | }, | ||
| 4519 | } | ||
| 4520 | if (is_multi) { | ||
| 4521 | multi_i += 1; | ||
| 4522 | } else { | ||
| 4523 | scalar_i += 1; | ||
| 4524 | } | ||
| 4525 | } else unreachable; | ||
| 4526 | } | ||
| 4527 | }; | ||
| 4528 | |||
| 4529 | pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) InnerError!void { | ||
| 4530 | const tracy = trace(@src()); | ||
| 4531 | defer tracy.end(); | ||
| 4532 | |||
| 4533 | const gpa = mod.gpa; | ||
| 4534 | const zir = struct_obj.owner_decl.namespace.file_scope.zir; | ||
| 4535 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | ||
| 4536 | assert(extended.opcode == .struct_decl); | ||
| 4537 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | ||
| 4538 | var extra_index: usize = extended.operand; | ||
| 4539 | |||
| 4540 | const src: LazySrcLoc = .{ .node_offset = struct_obj.node_offset }; | ||
| 4541 | extra_index += @boolToInt(small.has_src_node); | ||
| 4542 | |||
| 4543 | const body_len = if (small.has_body_len) blk: { | ||
| 4544 | const body_len = zir.extra[extra_index]; | ||
| 4545 | extra_index += 1; | ||
| 4546 | break :blk body_len; | ||
| 4547 | } else 0; | ||
| 4548 | |||
| 4549 | const fields_len = if (small.has_fields_len) blk: { | ||
| 4550 | const fields_len = zir.extra[extra_index]; | ||
| 4551 | extra_index += 1; | ||
| 4552 | break :blk fields_len; | ||
| 4553 | } else 0; | ||
| 4554 | |||
| 4555 | const decls_len = if (small.has_decls_len) decls_len: { | ||
| 4556 | const decls_len = zir.extra[extra_index]; | ||
| 4557 | extra_index += 1; | ||
| 4558 | break :decls_len decls_len; | ||
| 4559 | } else 0; | ||
| 4560 | |||
| 4561 | // Skip over decls. | ||
| 4562 | var decls_it = zir.declIteratorInner(extra_index, decls_len); | ||
| 4563 | while (decls_it.next()) |_| {} | ||
| 4564 | extra_index = decls_it.extra_index; | ||
| 4565 | |||
| 4566 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 4567 | if (fields_len == 0) { | ||
| 4568 | assert(body.len == 0); | ||
| 4569 | return; | ||
| 4570 | } | ||
| 4571 | extra_index += body.len; | ||
| 4572 | |||
| 4573 | var decl_arena = struct_obj.owner_decl.value_arena.?.promote(gpa); | ||
| 4574 | defer struct_obj.owner_decl.value_arena.?.* = decl_arena.state; | ||
| 4575 | |||
| 4576 | try struct_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len); | ||
| 4577 | |||
| 4578 | // We create a block for the field type instructions because they | ||
| 4579 | // may need to reference Decls from inside the struct namespace. | ||
| 4580 | // Within the field type, default value, and alignment expressions, the "owner decl" | ||
| 4581 | // should be the struct itself. Thus we need a new Sema. | ||
| 4582 | var sema: Sema = .{ | ||
| 4583 | .mod = mod, | ||
| 4584 | .gpa = gpa, | ||
| 4585 | .arena = &decl_arena.allocator, | ||
| 4586 | .code = zir, | ||
| 4587 | .owner_decl = struct_obj.owner_decl, | ||
| 4588 | .namespace = &struct_obj.namespace, | ||
| 4589 | .owner_func = null, | ||
| 4590 | .func = null, | ||
| 4591 | .param_inst_list = &.{}, | ||
| 4592 | }; | ||
| 4593 | defer sema.deinit(); | ||
| 4594 | |||
| 4595 | var block: Scope.Block = .{ | ||
| 4596 | .parent = null, | ||
| 4597 | .sema = &sema, | ||
| 4598 | .src_decl = struct_obj.owner_decl, | ||
| 4599 | .instructions = .{}, | ||
| 4600 | .inlining = null, | ||
| 4601 | .is_comptime = true, | ||
| 4602 | }; | ||
| 4603 | defer assert(block.instructions.items.len == 0); // should all be comptime instructions | ||
| 4604 | |||
| 4605 | if (body.len != 0) { | ||
| 4606 | _ = try sema.analyzeBody(&block, body); | ||
| 4607 | } | ||
| 4608 | |||
| 4609 | const bits_per_field = 4; | ||
| 4610 | const fields_per_u32 = 32 / bits_per_field; | ||
| 4611 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | ||
| 4612 | var bit_bag_index: usize = extra_index; | ||
| 4613 | extra_index += bit_bags_count; | ||
| 4614 | var cur_bit_bag: u32 = undefined; | ||
| 4615 | var field_i: u32 = 0; | ||
| 4616 | while (field_i < fields_len) : (field_i += 1) { | ||
| 4617 | if (field_i % fields_per_u32 == 0) { | ||
| 4618 | cur_bit_bag = zir.extra[bit_bag_index]; | ||
| 4619 | bit_bag_index += 1; | ||
| 4620 | } | ||
| 4621 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 4622 | cur_bit_bag >>= 1; | ||
| 4623 | const has_default = @truncate(u1, cur_bit_bag) != 0; | ||
| 4624 | cur_bit_bag >>= 1; | ||
| 4625 | const is_comptime = @truncate(u1, cur_bit_bag) != 0; | ||
| 4626 | cur_bit_bag >>= 1; | ||
| 4627 | const unused = @truncate(u1, cur_bit_bag) != 0; | ||
| 4628 | cur_bit_bag >>= 1; | ||
| 4629 | |||
| 4630 | _ = unused; | ||
| 4631 | |||
| 4632 | const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); | ||
| 4633 | extra_index += 1; | ||
| 4634 | const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4635 | extra_index += 1; | ||
| 4636 | |||
| 4637 | // This string needs to outlive the ZIR code. | ||
| 4638 | const field_name = try decl_arena.allocator.dupe(u8, field_name_zir); | ||
| 4639 | if (field_type_ref == .none) { | ||
| 4640 | return mod.fail(&block.base, src, "TODO: implement anytype struct field", .{}); | ||
| 4641 | } | ||
| 4642 | const field_ty: Type = if (field_type_ref == .none) | ||
| 4643 | Type.initTag(.noreturn) | ||
| 4644 | else | ||
| 4645 | // TODO: if we need to report an error here, use a source location | ||
| 4646 | // that points to this type expression rather than the struct. | ||
| 4647 | // But only resolve the source location if we need to emit a compile error. | ||
| 4648 | try sema.resolveType(&block, src, field_type_ref); | ||
| 4649 | |||
| 4650 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | ||
| 4651 | assert(!gop.found_existing); | ||
| 4652 | gop.entry.value = .{ | ||
| 4653 | .ty = field_ty, | ||
| 4654 | .abi_align = Value.initTag(.abi_align_default), | ||
| 4655 | .default_val = Value.initTag(.unreachable_value), | ||
| 4656 | .is_comptime = is_comptime, | ||
| 4657 | .offset = undefined, | ||
| 4658 | }; | ||
| 4659 | |||
| 4660 | if (has_align) { | ||
| 4661 | const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4662 | extra_index += 1; | ||
| 4663 | // TODO: if we need to report an error here, use a source location | ||
| 4664 | // that points to this alignment expression rather than the struct. | ||
| 4665 | // But only resolve the source location if we need to emit a compile error. | ||
| 4666 | gop.entry.value.abi_align = (try sema.resolveInstConst(&block, src, align_ref)).val; | ||
| 4667 | } | ||
| 4668 | if (has_default) { | ||
| 4669 | const default_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4670 | extra_index += 1; | ||
| 4671 | // TODO: if we need to report an error here, use a source location | ||
| 4672 | // that points to this default value expression rather than the struct. | ||
| 4673 | // But only resolve the source location if we need to emit a compile error. | ||
| 4674 | gop.entry.value.default_val = (try sema.resolveInstConst(&block, src, default_ref)).val; | ||
| 4675 | } | ||
| 4676 | } | ||
| 4657 | } | 4677 | } |
| 4658 | 4678 | ||
| 4659 | /// Given an identifier token, obtain the string for it (possibly parsing as a string | 4679 | pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void { |
| 4660 | /// literal if it is @"" syntax), and append the string to `buf`. | 4680 | const tracy = trace(@src()); |
| 4661 | /// See also `identifierTokenString` and `parseStrLit`. | 4681 | defer tracy.end(); |
| 4662 | pub fn appendIdentStr( | 4682 | |
| 4663 | mod: *Module, | 4683 | const gpa = mod.gpa; |
| 4664 | scope: *Scope, | 4684 | const zir = union_obj.owner_decl.namespace.file_scope.zir; |
| 4665 | token: ast.TokenIndex, | 4685 | const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; |
| 4666 | buf: *ArrayListUnmanaged(u8), | 4686 | assert(extended.opcode == .union_decl); |
| 4667 | ) InnerError!void { | 4687 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| 4668 | const tree = scope.tree(); | 4688 | var extra_index: usize = extended.operand; |
| 4669 | const token_tags = tree.tokens.items(.tag); | 4689 | |
| 4670 | assert(token_tags[token] == .identifier); | 4690 | const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset }; |
| 4671 | const ident_name = tree.tokenSlice(token); | 4691 | extra_index += @boolToInt(small.has_src_node); |
| 4672 | if (!mem.startsWith(u8, ident_name, "@")) { | 4692 | |
| 4673 | return buf.appendSlice(mod.gpa, ident_name); | 4693 | const tag_type_ref = if (small.has_tag_type) blk: { |
| 4674 | } else { | 4694 | const tag_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 4675 | return mod.parseStrLit(scope, token, buf, ident_name, 1); | 4695 | extra_index += 1; |
| 4696 | break :blk tag_type_ref; | ||
| 4697 | } else .none; | ||
| 4698 | |||
| 4699 | const body_len = if (small.has_body_len) blk: { | ||
| 4700 | const body_len = zir.extra[extra_index]; | ||
| 4701 | extra_index += 1; | ||
| 4702 | break :blk body_len; | ||
| 4703 | } else 0; | ||
| 4704 | |||
| 4705 | const fields_len = if (small.has_fields_len) blk: { | ||
| 4706 | const fields_len = zir.extra[extra_index]; | ||
| 4707 | extra_index += 1; | ||
| 4708 | break :blk fields_len; | ||
| 4709 | } else 0; | ||
| 4710 | |||
| 4711 | const decls_len = if (small.has_decls_len) decls_len: { | ||
| 4712 | const decls_len = zir.extra[extra_index]; | ||
| 4713 | extra_index += 1; | ||
| 4714 | break :decls_len decls_len; | ||
| 4715 | } else 0; | ||
| 4716 | |||
| 4717 | // Skip over decls. | ||
| 4718 | var decls_it = zir.declIteratorInner(extra_index, decls_len); | ||
| 4719 | while (decls_it.next()) |_| {} | ||
| 4720 | extra_index = decls_it.extra_index; | ||
| 4721 | |||
| 4722 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 4723 | if (fields_len == 0) { | ||
| 4724 | assert(body.len == 0); | ||
| 4725 | return; | ||
| 4726 | } | ||
| 4727 | extra_index += body.len; | ||
| 4728 | |||
| 4729 | var decl_arena = union_obj.owner_decl.value_arena.?.promote(gpa); | ||
| 4730 | defer union_obj.owner_decl.value_arena.?.* = decl_arena.state; | ||
| 4731 | |||
| 4732 | try union_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len); | ||
| 4733 | |||
| 4734 | // We create a block for the field type instructions because they | ||
| 4735 | // may need to reference Decls from inside the struct namespace. | ||
| 4736 | // Within the field type, default value, and alignment expressions, the "owner decl" | ||
| 4737 | // should be the struct itself. Thus we need a new Sema. | ||
| 4738 | var sema: Sema = .{ | ||
| 4739 | .mod = mod, | ||
| 4740 | .gpa = gpa, | ||
| 4741 | .arena = &decl_arena.allocator, | ||
| 4742 | .code = zir, | ||
| 4743 | .owner_decl = union_obj.owner_decl, | ||
| 4744 | .namespace = &union_obj.namespace, | ||
| 4745 | .owner_func = null, | ||
| 4746 | .func = null, | ||
| 4747 | .param_inst_list = &.{}, | ||
| 4748 | }; | ||
| 4749 | defer sema.deinit(); | ||
| 4750 | |||
| 4751 | var block: Scope.Block = .{ | ||
| 4752 | .parent = null, | ||
| 4753 | .sema = &sema, | ||
| 4754 | .src_decl = union_obj.owner_decl, | ||
| 4755 | .instructions = .{}, | ||
| 4756 | .inlining = null, | ||
| 4757 | .is_comptime = true, | ||
| 4758 | }; | ||
| 4759 | defer assert(block.instructions.items.len == 0); // should all be comptime instructions | ||
| 4760 | |||
| 4761 | if (body.len != 0) { | ||
| 4762 | _ = try sema.analyzeBody(&block, body); | ||
| 4763 | } | ||
| 4764 | |||
| 4765 | const bits_per_field = 4; | ||
| 4766 | const fields_per_u32 = 32 / bits_per_field; | ||
| 4767 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | ||
| 4768 | var bit_bag_index: usize = extra_index; | ||
| 4769 | extra_index += bit_bags_count; | ||
| 4770 | var cur_bit_bag: u32 = undefined; | ||
| 4771 | var field_i: u32 = 0; | ||
| 4772 | while (field_i < fields_len) : (field_i += 1) { | ||
| 4773 | if (field_i % fields_per_u32 == 0) { | ||
| 4774 | cur_bit_bag = zir.extra[bit_bag_index]; | ||
| 4775 | bit_bag_index += 1; | ||
| 4776 | } | ||
| 4777 | const has_type = @truncate(u1, cur_bit_bag) != 0; | ||
| 4778 | cur_bit_bag >>= 1; | ||
| 4779 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 4780 | cur_bit_bag >>= 1; | ||
| 4781 | const has_tag = @truncate(u1, cur_bit_bag) != 0; | ||
| 4782 | cur_bit_bag >>= 1; | ||
| 4783 | const unused = @truncate(u1, cur_bit_bag) != 0; | ||
| 4784 | cur_bit_bag >>= 1; | ||
| 4785 | |||
| 4786 | const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); | ||
| 4787 | extra_index += 1; | ||
| 4788 | |||
| 4789 | const field_type_ref: Zir.Inst.Ref = if (has_type) blk: { | ||
| 4790 | const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4791 | extra_index += 1; | ||
| 4792 | break :blk field_type_ref; | ||
| 4793 | } else .none; | ||
| 4794 | |||
| 4795 | const align_ref: Zir.Inst.Ref = if (has_align) blk: { | ||
| 4796 | const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4797 | extra_index += 1; | ||
| 4798 | break :blk align_ref; | ||
| 4799 | } else .none; | ||
| 4800 | |||
| 4801 | const tag_ref: Zir.Inst.Ref = if (has_tag) blk: { | ||
| 4802 | const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 4803 | extra_index += 1; | ||
| 4804 | break :blk tag_ref; | ||
| 4805 | } else .none; | ||
| 4806 | |||
| 4807 | // This string needs to outlive the ZIR code. | ||
| 4808 | const field_name = try decl_arena.allocator.dupe(u8, field_name_zir); | ||
| 4809 | const field_ty: Type = if (field_type_ref == .none) | ||
| 4810 | Type.initTag(.void) | ||
| 4811 | else | ||
| 4812 | // TODO: if we need to report an error here, use a source location | ||
| 4813 | // that points to this type expression rather than the union. | ||
| 4814 | // But only resolve the source location if we need to emit a compile error. | ||
| 4815 | try sema.resolveType(&block, src, field_type_ref); | ||
| 4816 | |||
| 4817 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); | ||
| 4818 | assert(!gop.found_existing); | ||
| 4819 | gop.entry.value = .{ | ||
| 4820 | .ty = field_ty, | ||
| 4821 | .abi_align = Value.initTag(.abi_align_default), | ||
| 4822 | }; | ||
| 4823 | |||
| 4824 | if (align_ref != .none) { | ||
| 4825 | // TODO: if we need to report an error here, use a source location | ||
| 4826 | // that points to this alignment expression rather than the struct. | ||
| 4827 | // But only resolve the source location if we need to emit a compile error. | ||
| 4828 | gop.entry.value.abi_align = (try sema.resolveInstConst(&block, src, align_ref)).val; | ||
| 4829 | } | ||
| 4676 | } | 4830 | } |
| 4831 | |||
| 4832 | // TODO resolve the union tag_type_ref | ||
| 4677 | } | 4833 | } |
| 4678 | 4834 | ||
| 4679 | /// Appends the result to `buf`. | 4835 | /// Called from `performAllTheWork`, after all AstGen workers have finished, |
| 4680 | pub fn parseStrLit( | 4836 | /// and before the main semantic analysis loop begins. |
| 4681 | mod: *Module, | 4837 | pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| 4682 | scope: *Scope, | 4838 | // Ultimately, the goal is to queue up `analyze_decl` tasks in the work queue |
| 4683 | token: ast.TokenIndex, | 4839 | // for the outdated decls, but we cannot queue up the tasks until after |
| 4684 | buf: *ArrayListUnmanaged(u8), | 4840 | // we find out which ones have been deleted, otherwise there would be |
| 4685 | bytes: []const u8, | 4841 | // deleted Decl pointers in the work queue. |
| 4686 | offset: u32, | 4842 | var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); |
| 4687 | ) InnerError!void { | 4843 | defer outdated_decls.deinit(); |
| 4688 | const tree = scope.tree(); | 4844 | for (mod.import_table.items()) |import_table_entry| { |
| 4689 | const token_starts = tree.tokens.items(.start); | 4845 | const file = import_table_entry.value; |
| 4690 | const raw_string = bytes[offset..]; | 4846 | |
| 4691 | var buf_managed = buf.toManaged(mod.gpa); | 4847 | try outdated_decls.ensureUnusedCapacity(file.outdated_decls.items.len); |
| 4692 | const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); | 4848 | for (file.outdated_decls.items) |decl| { |
| 4693 | buf.* = buf_managed.toUnmanaged(); | 4849 | outdated_decls.putAssumeCapacity(decl, {}); |
| 4694 | switch (try result) { | 4850 | } |
| 4695 | .success => return, | 4851 | file.outdated_decls.clearRetainingCapacity(); |
| 4696 | .invalid_character => |bad_index| { | 4852 | |
| 4697 | return mod.failOff( | 4853 | // Handle explicitly deleted decls from the source code. This is one of two |
| 4698 | scope, | 4854 | // places that Decl deletions happen. The other is in `Compilation`, after |
| 4699 | token_starts[token] + offset + @intCast(u32, bad_index), | 4855 | // `performAllTheWork`, where we iterate over `Module.deletion_set` and |
| 4700 | "invalid string literal character: '{c}'", | 4856 | // delete Decls which are no longer referenced. |
| 4701 | .{raw_string[bad_index]}, | 4857 | // If a Decl is explicitly deleted from source, and also no longer referenced, |
| 4702 | ); | 4858 | // it may be both in this `deleted_decls` set, as well as in the |
| 4703 | }, | 4859 | // `Module.deletion_set`. To avoid deleting it twice, we remove it from the |
| 4704 | .expected_hex_digits => |bad_index| { | 4860 | // deletion set at this time. |
| 4705 | return mod.failOff( | 4861 | for (file.deleted_decls.items) |decl| { |
| 4706 | scope, | 4862 | log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); |
| 4707 | token_starts[token] + offset + @intCast(u32, bad_index), | 4863 | |
| 4708 | "expected hex digits after '\\x'", | 4864 | // Remove from the namespace it resides in, preserving declaration order. |
| 4709 | .{}, | 4865 | assert(decl.zir_decl_index != 0); |
| 4710 | ); | 4866 | _ = decl.namespace.decls.orderedRemove(mem.spanZ(decl.name)); |
| 4711 | }, | 4867 | |
| 4712 | .invalid_hex_escape => |bad_index| { | 4868 | try mod.clearDecl(decl, &outdated_decls); |
| 4713 | return mod.failOff( | 4869 | decl.destroy(mod); |
| 4714 | scope, | 4870 | } |
| 4715 | token_starts[token] + offset + @intCast(u32, bad_index), | 4871 | file.deleted_decls.clearRetainingCapacity(); |
| 4716 | "invalid hex digit: '{c}'", | 4872 | } |
| 4717 | .{raw_string[bad_index]}, | 4873 | // Finally we can queue up re-analysis tasks after we have processed |
| 4718 | ); | 4874 | // the deleted decls. |
| 4719 | }, | 4875 | for (outdated_decls.items()) |entry| { |
| 4720 | .invalid_unicode_escape => |bad_index| { | 4876 | try mod.markOutdatedDecl(entry.key); |
| 4721 | return mod.failOff( | ||
| 4722 | scope, | ||
| 4723 | token_starts[token] + offset + @intCast(u32, bad_index), | ||
| 4724 | "invalid unicode digit: '{c}'", | ||
| 4725 | .{raw_string[bad_index]}, | ||
| 4726 | ); | ||
| 4727 | }, | ||
| 4728 | .missing_matching_rbrace => |bad_index| { | ||
| 4729 | return mod.failOff( | ||
| 4730 | scope, | ||
| 4731 | token_starts[token] + offset + @intCast(u32, bad_index), | ||
| 4732 | "missing matching '}}' character", | ||
| 4733 | .{}, | ||
| 4734 | ); | ||
| 4735 | }, | ||
| 4736 | .expected_unicode_digits => |bad_index| { | ||
| 4737 | return mod.failOff( | ||
| 4738 | scope, | ||
| 4739 | token_starts[token] + offset + @intCast(u32, bad_index), | ||
| 4740 | "expected unicode digits after '\\u'", | ||
| 4741 | .{}, | ||
| 4742 | ); | ||
| 4743 | }, | ||
| 4744 | } | 4877 | } |
| 4745 | } | 4878 | } |
| 4746 | 4879 | ||
| 4747 | pub fn unloadFile(mod: *Module, file_scope: *Scope.File) void { | 4880 | /// Called from `Compilation.update`, after everything is done, just before |
| 4748 | if (file_scope.status == .unloaded_parse_failure) { | 4881 | /// reporting compile errors. In this function we emit exported symbol collision |
| 4749 | mod.failed_files.swapRemove(file_scope).?.value.destroy(mod.gpa); | 4882 | /// errors and communicate exported symbols to the linker backend. |
| 4883 | pub fn processExports(mod: *Module) !void { | ||
| 4884 | const gpa = mod.gpa; | ||
| 4885 | // Map symbol names to `Export` for name collision detection. | ||
| 4886 | var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}; | ||
| 4887 | defer symbol_exports.deinit(gpa); | ||
| 4888 | |||
| 4889 | for (mod.decl_exports.items()) |entry| { | ||
| 4890 | const exported_decl = entry.key; | ||
| 4891 | const exports = entry.value; | ||
| 4892 | for (exports) |new_export| { | ||
| 4893 | const gop = try symbol_exports.getOrPut(gpa, new_export.options.name); | ||
| 4894 | if (gop.found_existing) { | ||
| 4895 | new_export.status = .failed_retryable; | ||
| 4896 | try mod.failed_exports.ensureUnusedCapacity(gpa, 1); | ||
| 4897 | const src_loc = new_export.getSrcLoc(); | ||
| 4898 | const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ | ||
| 4899 | new_export.options.name, | ||
| 4900 | }); | ||
| 4901 | errdefer msg.destroy(gpa); | ||
| 4902 | const other_export = gop.entry.value; | ||
| 4903 | const other_src_loc = other_export.getSrcLoc(); | ||
| 4904 | try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{}); | ||
| 4905 | mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); | ||
| 4906 | new_export.status = .failed; | ||
| 4907 | } else { | ||
| 4908 | gop.entry.value = new_export; | ||
| 4909 | } | ||
| 4910 | } | ||
| 4911 | mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) { | ||
| 4912 | error.OutOfMemory => return error.OutOfMemory, | ||
| 4913 | else => { | ||
| 4914 | const new_export = exports[0]; | ||
| 4915 | new_export.status = .failed_retryable; | ||
| 4916 | try mod.failed_exports.ensureUnusedCapacity(gpa, 1); | ||
| 4917 | const src_loc = new_export.getSrcLoc(); | ||
| 4918 | const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{ | ||
| 4919 | @errorName(err), | ||
| 4920 | }); | ||
| 4921 | mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); | ||
| 4922 | }, | ||
| 4923 | }; | ||
| 4750 | } | 4924 | } |
| 4751 | file_scope.unload(mod.gpa); | ||
| 4752 | } | 4925 | } |
src/Package.zig-11| ... | @@ -11,22 +11,15 @@ const Module = @import("Module.zig"); | ... | @@ -11,22 +11,15 @@ const Module = @import("Module.zig"); |
| 11 | 11 | ||
| 12 | pub const Table = std.StringHashMapUnmanaged(*Package); | 12 | pub const Table = std.StringHashMapUnmanaged(*Package); |
| 13 | 13 | ||
| 14 | pub const root_namespace_hash: Module.Scope.NameHash = .{ | ||
| 15 | 0, 0, 6, 6, 6, 0, 0, 0, | ||
| 16 | 6, 9, 0, 0, 0, 4, 2, 0, | ||
| 17 | }; | ||
| 18 | |||
| 19 | root_src_directory: Compilation.Directory, | 14 | root_src_directory: Compilation.Directory, |
| 20 | /// Relative to `root_src_directory`. May contain path separators. | 15 | /// Relative to `root_src_directory`. May contain path separators. |
| 21 | root_src_path: []const u8, | 16 | root_src_path: []const u8, |
| 22 | table: Table = .{}, | 17 | table: Table = .{}, |
| 23 | parent: ?*Package = null, | 18 | parent: ?*Package = null, |
| 24 | namespace_hash: Module.Scope.NameHash, | ||
| 25 | /// Whether to free `root_src_directory` on `destroy`. | 19 | /// Whether to free `root_src_directory` on `destroy`. |
| 26 | root_src_directory_owned: bool = false, | 20 | root_src_directory_owned: bool = false, |
| 27 | 21 | ||
| 28 | /// Allocate a Package. No references to the slices passed are kept. | 22 | /// Allocate a Package. No references to the slices passed are kept. |
| 29 | /// Don't forget to set `namespace_hash` later. | ||
| 30 | pub fn create( | 23 | pub fn create( |
| 31 | gpa: *Allocator, | 24 | gpa: *Allocator, |
| 32 | /// Null indicates the current working directory | 25 | /// Null indicates the current working directory |
| ... | @@ -50,7 +43,6 @@ pub fn create( | ... | @@ -50,7 +43,6 @@ pub fn create( |
| 50 | }, | 43 | }, |
| 51 | .root_src_path = owned_src_path, | 44 | .root_src_path = owned_src_path, |
| 52 | .root_src_directory_owned = true, | 45 | .root_src_directory_owned = true, |
| 53 | .namespace_hash = undefined, | ||
| 54 | }; | 46 | }; |
| 55 | 47 | ||
| 56 | return ptr; | 48 | return ptr; |
| ... | @@ -82,14 +74,12 @@ pub fn createWithDir( | ... | @@ -82,14 +74,12 @@ pub fn createWithDir( |
| 82 | }, | 74 | }, |
| 83 | .root_src_directory_owned = true, | 75 | .root_src_directory_owned = true, |
| 84 | .root_src_path = owned_src_path, | 76 | .root_src_path = owned_src_path, |
| 85 | .namespace_hash = undefined, | ||
| 86 | }; | 77 | }; |
| 87 | } else { | 78 | } else { |
| 88 | ptr.* = .{ | 79 | ptr.* = .{ |
| 89 | .root_src_directory = directory, | 80 | .root_src_directory = directory, |
| 90 | .root_src_directory_owned = false, | 81 | .root_src_directory_owned = false, |
| 91 | .root_src_path = owned_src_path, | 82 | .root_src_path = owned_src_path, |
| 92 | .namespace_hash = undefined, | ||
| 93 | }; | 83 | }; |
| 94 | } | 84 | } |
| 95 | return ptr; | 85 | return ptr; |
| ... | @@ -129,6 +119,5 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) | ... | @@ -129,6 +119,5 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) |
| 129 | pub fn addAndAdopt(parent: *Package, gpa: *Allocator, name: []const u8, child: *Package) !void { | 119 | pub fn addAndAdopt(parent: *Package, gpa: *Allocator, name: []const u8, child: *Package) !void { |
| 130 | assert(child.parent == null); // make up your mind, who is the parent?? | 120 | assert(child.parent == null); // make up your mind, who is the parent?? |
| 131 | child.parent = parent; | 121 | child.parent = parent; |
| 132 | child.namespace_hash = std.zig.hashName(parent.namespace_hash, ":", name); | ||
| 133 | return parent.add(gpa, name, child); | 122 | return parent.add(gpa, name, child); |
| 134 | } | 123 | } |
src/RangeSet.zig+1-1| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | const Order = std.math.Order; | 2 | const Order = std.math.Order; |
| 3 | const Value = @import("value.zig").Value; | 3 | const Value = @import("value.zig").Value; |
| 4 | const RangeSet = @This(); | 4 | const RangeSet = @This(); |
| 5 | const SwitchProngSrc = @import("AstGen.zig").SwitchProngSrc; | 5 | const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; |
| 6 | 6 | ||
| 7 | ranges: std.ArrayList(Range), | 7 | ranges: std.ArrayList(Range), |
| 8 | 8 |
src/Sema.zig+2857-975| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | //! Semantic analysis of ZIR instructions. | 1 | //! Semantic analysis of ZIR instructions. |
| 2 | //! Shared to every Block. Stored on the stack. | 2 | //! Shared to every Block. Stored on the stack. |
| 3 | //! State used for compiling a `zir.Code` into TZIR. | 3 | //! State used for compiling a `Zir` into AIR. |
| 4 | //! Transforms untyped ZIR instructions into semantically-analyzed TZIR instructions. | 4 | //! Transforms untyped ZIR instructions into semantically-analyzed AIR instructions. |
| 5 | //! Does type checking, comptime control flow, and safety-check generation. | 5 | //! Does type checking, comptime control flow, and safety-check generation. |
| 6 | //! This is the the heart of the Zig compiler. | 6 | //! This is the the heart of the Zig compiler. |
| 7 | 7 | ||
| ... | @@ -10,13 +10,15 @@ mod: *Module, | ... | @@ -10,13 +10,15 @@ mod: *Module, |
| 10 | gpa: *Allocator, | 10 | gpa: *Allocator, |
| 11 | /// Points to the arena allocator of the Decl. | 11 | /// Points to the arena allocator of the Decl. |
| 12 | arena: *Allocator, | 12 | arena: *Allocator, |
| 13 | code: zir.Code, | 13 | code: Zir, |
| 14 | /// Maps ZIR to TZIR. | 14 | /// Maps ZIR to AIR. |
| 15 | inst_map: []*Inst, | 15 | inst_map: InstMap = .{}, |
| 16 | /// When analyzing an inline function call, owner_decl is the Decl of the caller | 16 | /// When analyzing an inline function call, owner_decl is the Decl of the caller |
| 17 | /// and `src_decl` of `Scope.Block` is the `Decl` of the callee. | 17 | /// and `src_decl` of `Scope.Block` is the `Decl` of the callee. |
| 18 | /// This `Decl` owns the arena memory of this `Sema`. | 18 | /// This `Decl` owns the arena memory of this `Sema`. |
| 19 | owner_decl: *Decl, | 19 | owner_decl: *Decl, |
| 20 | /// How to look up decl names. | ||
| 21 | namespace: *Scope.Namespace, | ||
| 20 | /// For an inline or comptime function call, this will be the root parent function | 22 | /// For an inline or comptime function call, this will be the root parent function |
| 21 | /// which contains the callsite. Corresponds to `owner_decl`. | 23 | /// which contains the callsite. Corresponds to `owner_decl`. |
| 22 | owner_func: ?*Module.Fn, | 24 | owner_func: ?*Module.Fn, |
| ... | @@ -24,9 +26,9 @@ owner_func: ?*Module.Fn, | ... | @@ -24,9 +26,9 @@ owner_func: ?*Module.Fn, |
| 24 | /// This starts out the same as `owner_func` and then diverges in the case of | 26 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 25 | /// an inline or comptime function call. | 27 | /// an inline or comptime function call. |
| 26 | func: ?*Module.Fn, | 28 | func: ?*Module.Fn, |
| 27 | /// For now, TZIR requires arg instructions to be the first N instructions in the | 29 | /// For now, AIR requires arg instructions to be the first N instructions in the |
| 28 | /// TZIR code. We store references here for the purpose of `resolveInst`. | 30 | /// AIR code. We store references here for the purpose of `resolveInst`. |
| 29 | /// This can get reworked with TZIR memory layout changes, into simply: | 31 | /// This can get reworked with AIR memory layout changes, into simply: |
| 30 | /// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function, | 32 | /// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function, |
| 31 | /// > otherwise it is the number of parameters of the function. | 33 | /// > otherwise it is the number of parameters of the function. |
| 32 | /// > param_count: u32 | 34 | /// > param_count: u32 |
| ... | @@ -38,6 +40,7 @@ branch_count: u32 = 0, | ... | @@ -38,6 +40,7 @@ branch_count: u32 = 0, |
| 38 | /// access to the source location set by the previous instruction which did | 40 | /// access to the source location set by the previous instruction which did |
| 39 | /// contain a mapped source location. | 41 | /// contain a mapped source location. |
| 40 | src: LazySrcLoc = .{ .token_offset = 0 }, | 42 | src: LazySrcLoc = .{ .token_offset = 0 }, |
| 43 | next_arg_index: usize = 0, | ||
| 41 | 44 | ||
| 42 | const std = @import("std"); | 45 | const std = @import("std"); |
| 43 | const mem = std.mem; | 46 | const mem = std.mem; |
| ... | @@ -50,7 +53,7 @@ const Value = @import("value.zig").Value; | ... | @@ -50,7 +53,7 @@ const Value = @import("value.zig").Value; |
| 50 | const Type = @import("type.zig").Type; | 53 | const Type = @import("type.zig").Type; |
| 51 | const TypedValue = @import("TypedValue.zig"); | 54 | const TypedValue = @import("TypedValue.zig"); |
| 52 | const ir = @import("ir.zig"); | 55 | const ir = @import("ir.zig"); |
| 53 | const zir = @import("zir.zig"); | 56 | const Zir = @import("Zir.zig"); |
| 54 | const Module = @import("Module.zig"); | 57 | const Module = @import("Module.zig"); |
| 55 | const Inst = ir.Inst; | 58 | const Inst = ir.Inst; |
| 56 | const Body = ir.Body; | 59 | const Body = ir.Body; |
| ... | @@ -60,34 +63,52 @@ const InnerError = Module.InnerError; | ... | @@ -60,34 +63,52 @@ const InnerError = Module.InnerError; |
| 60 | const Decl = Module.Decl; | 63 | const Decl = Module.Decl; |
| 61 | const LazySrcLoc = Module.LazySrcLoc; | 64 | const LazySrcLoc = Module.LazySrcLoc; |
| 62 | const RangeSet = @import("RangeSet.zig"); | 65 | const RangeSet = @import("RangeSet.zig"); |
| 63 | const AstGen = @import("AstGen.zig"); | 66 | const target_util = @import("target.zig"); |
| 64 | 67 | ||
| 65 | pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index { | 68 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, *ir.Inst); |
| 66 | const inst_data = sema.code.instructions.items(.data)[0].pl_node; | ||
| 67 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | ||
| 68 | const root_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 69 | return sema.analyzeBody(root_block, root_body); | ||
| 70 | } | ||
| 71 | 69 | ||
| 72 | pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref { | 70 | pub fn deinit(sema: *Sema) void { |
| 73 | const break_inst = try sema.root(root_block); | 71 | sema.inst_map.deinit(sema.gpa); |
| 74 | return sema.code.instructions.items(.data)[break_inst].@"break".operand; | 72 | sema.* = undefined; |
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | /// Assumes that `root_block` ends with `break_inline`. | 75 | pub fn analyzeFnBody( |
| 78 | pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type { | 76 | sema: *Sema, |
| 79 | assert(root_block.is_comptime); | 77 | block: *Scope.Block, |
| 80 | const zir_inst_ref = try sema.rootAsRef(root_block); | 78 | fn_body_inst: Zir.Inst.Index, |
| 81 | // Source location is unneeded because resolveConstValue must have already | 79 | ) InnerError!void { |
| 82 | // been successfully called when coercing the value to a type, from the | 80 | const tags = sema.code.instructions.items(.tag); |
| 83 | // result location. | 81 | const datas = sema.code.instructions.items(.data); |
| 84 | return sema.resolveType(root_block, .unneeded, zir_inst_ref); | 82 | const body: []const Zir.Inst.Index = switch (tags[fn_body_inst]) { |
| 83 | .func, .func_inferred => blk: { | ||
| 84 | const inst_data = datas[fn_body_inst].pl_node; | ||
| 85 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); | ||
| 86 | const param_types_len = extra.data.param_types_len; | ||
| 87 | const body = sema.code.extra[extra.end + param_types_len ..][0..extra.data.body_len]; | ||
| 88 | break :blk body; | ||
| 89 | }, | ||
| 90 | .extended => blk: { | ||
| 91 | const extended = datas[fn_body_inst].extended; | ||
| 92 | assert(extended.opcode == .func); | ||
| 93 | const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand); | ||
| 94 | const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); | ||
| 95 | var extra_index: usize = extra.end; | ||
| 96 | extra_index += @boolToInt(small.has_lib_name); | ||
| 97 | extra_index += @boolToInt(small.has_cc); | ||
| 98 | extra_index += @boolToInt(small.has_align); | ||
| 99 | extra_index += extra.data.param_types_len; | ||
| 100 | const body = sema.code.extra[extra_index..][0..extra.data.body_len]; | ||
| 101 | break :blk body; | ||
| 102 | }, | ||
| 103 | else => unreachable, | ||
| 104 | }; | ||
| 105 | _ = try sema.analyzeBody(block, body); | ||
| 85 | } | 106 | } |
| 86 | 107 | ||
| 87 | /// Returns only the result from the body that is specified. | 108 | /// Returns only the result from the body that is specified. |
| 88 | /// Only appropriate to call when it is determined at comptime that this body | 109 | /// Only appropriate to call when it is determined at comptime that this body |
| 89 | /// has no peers. | 110 | /// has no peers. |
| 90 | fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) InnerError!*Inst { | 111 | fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const Zir.Inst.Index) InnerError!*Inst { |
| 91 | const break_inst = try sema.analyzeBody(block, body); | 112 | const break_inst = try sema.analyzeBody(block, body); |
| 92 | const operand_ref = sema.code.instructions.items(.data)[break_inst].@"break".operand; | 113 | const operand_ref = sema.code.instructions.items(.data)[break_inst].@"break".operand; |
| 93 | return sema.resolveInst(operand_ref); | 114 | return sema.resolveInst(operand_ref); |
| ... | @@ -97,25 +118,25 @@ fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) I | ... | @@ -97,25 +118,25 @@ fn resolveBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) I |
| 97 | /// return type of `analyzeBody` so that we can tail call them. | 118 | /// return type of `analyzeBody` so that we can tail call them. |
| 98 | /// Only appropriate to return when the instruction is known to be NoReturn | 119 | /// Only appropriate to return when the instruction is known to be NoReturn |
| 99 | /// solely based on the ZIR tag. | 120 | /// solely based on the ZIR tag. |
| 100 | const always_noreturn: InnerError!zir.Inst.Index = @as(zir.Inst.Index, undefined); | 121 | const always_noreturn: InnerError!Zir.Inst.Index = @as(Zir.Inst.Index, undefined); |
| 101 | 122 | ||
| 102 | /// This function is the main loop of `Sema` and it can be used in two different ways: | 123 | /// This function is the main loop of `Sema` and it can be used in two different ways: |
| 103 | /// * The traditional way where there are N breaks out of the block and peer type | 124 | /// * The traditional way where there are N breaks out of the block and peer type |
| 104 | /// resolution is done on the break operands. In this case, the `zir.Inst.Index` | 125 | /// resolution is done on the break operands. In this case, the `Zir.Inst.Index` |
| 105 | /// part of the return value will be `undefined`, and callsites should ignore it, | 126 | /// part of the return value will be `undefined`, and callsites should ignore it, |
| 106 | /// finding the block result value via the block scope. | 127 | /// finding the block result value via the block scope. |
| 107 | /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline` | 128 | /// * The "flat" way. There is only 1 break out of the block, and it is with a `break_inline` |
| 108 | /// instruction. In this case, the `zir.Inst.Index` part of the return value will be | 129 | /// instruction. In this case, the `Zir.Inst.Index` part of the return value will be |
| 109 | /// the break instruction. This communicates both which block the break applies to, as | 130 | /// the break instruction. This communicates both which block the break applies to, as |
| 110 | /// well as the operand. No block scope needs to be created for this strategy. | 131 | /// well as the operand. No block scope needs to be created for this strategy. |
| 111 | pub fn analyzeBody( | 132 | pub fn analyzeBody( |
| 112 | sema: *Sema, | 133 | sema: *Sema, |
| 113 | block: *Scope.Block, | 134 | block: *Scope.Block, |
| 114 | body: []const zir.Inst.Index, | 135 | body: []const Zir.Inst.Index, |
| 115 | ) InnerError!zir.Inst.Index { | 136 | ) InnerError!Zir.Inst.Index { |
| 116 | // No tracy calls here, to avoid interfering with the tail call mechanism. | 137 | // No tracy calls here, to avoid interfering with the tail call mechanism. |
| 117 | 138 | ||
| 118 | const map = block.sema.inst_map; | 139 | const map = &block.sema.inst_map; |
| 119 | const tags = block.sema.code.instructions.items(.tag); | 140 | const tags = block.sema.code.instructions.items(.tag); |
| 120 | const datas = block.sema.code.instructions.items(.data); | 141 | const datas = block.sema.code.instructions.items(.data); |
| 121 | 142 | ||
| ... | @@ -128,166 +149,243 @@ pub fn analyzeBody( | ... | @@ -128,166 +149,243 @@ pub fn analyzeBody( |
| 128 | var i: usize = 0; | 149 | var i: usize = 0; |
| 129 | while (true) : (i += 1) { | 150 | while (true) : (i += 1) { |
| 130 | const inst = body[i]; | 151 | const inst = body[i]; |
| 131 | map[inst] = switch (tags[inst]) { | 152 | const air_inst = switch (tags[inst]) { |
| 132 | .elided => continue, | 153 | // zig fmt: off |
| 133 | 154 | .arg => try sema.zirArg(block, inst), | |
| 134 | .add => try sema.zirArithmetic(block, inst), | 155 | .alloc => try sema.zirAlloc(block, inst), |
| 135 | .addwrap => try sema.zirArithmetic(block, inst), | 156 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), |
| 136 | .alloc => try sema.zirAlloc(block, inst), | 157 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), |
| 137 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), | 158 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst), |
| 138 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), | 159 | .alloc_mut => try sema.zirAllocMut(block, inst), |
| 139 | .alloc_mut => try sema.zirAllocMut(block, inst), | 160 | .alloc_comptime => try sema.zirAllocComptime(block, inst), |
| 140 | .array_cat => try sema.zirArrayCat(block, inst), | 161 | .anyframe_type => try sema.zirAnyframeType(block, inst), |
| 141 | .array_mul => try sema.zirArrayMul(block, inst), | 162 | .array_cat => try sema.zirArrayCat(block, inst), |
| 142 | .array_type => try sema.zirArrayType(block, inst), | 163 | .array_mul => try sema.zirArrayMul(block, inst), |
| 143 | .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), | 164 | .array_type => try sema.zirArrayType(block, inst), |
| 144 | .as => try sema.zirAs(block, inst), | 165 | .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), |
| 145 | .as_node => try sema.zirAsNode(block, inst), | 166 | .vector_type => try sema.zirVectorType(block, inst), |
| 146 | .@"asm" => try sema.zirAsm(block, inst, false), | 167 | .as => try sema.zirAs(block, inst), |
| 147 | .asm_volatile => try sema.zirAsm(block, inst, true), | 168 | .as_node => try sema.zirAsNode(block, inst), |
| 148 | .bit_and => try sema.zirBitwise(block, inst, .bit_and), | 169 | .bit_and => try sema.zirBitwise(block, inst, .bit_and), |
| 149 | .bit_not => try sema.zirBitNot(block, inst), | 170 | .bit_not => try sema.zirBitNot(block, inst), |
| 150 | .bit_or => try sema.zirBitwise(block, inst, .bit_or), | 171 | .bit_or => try sema.zirBitwise(block, inst, .bit_or), |
| 151 | .bitcast => try sema.zirBitcast(block, inst), | 172 | .bitcast => try sema.zirBitcast(block, inst), |
| 152 | .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), | 173 | .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), |
| 153 | .block => try sema.zirBlock(block, inst), | 174 | .block => try sema.zirBlock(block, inst), |
| 154 | .bool_not => try sema.zirBoolNot(block, inst), | 175 | .suspend_block => try sema.zirSuspendBlock(block, inst), |
| 155 | .bool_and => try sema.zirBoolOp(block, inst, false), | 176 | .bool_not => try sema.zirBoolNot(block, inst), |
| 156 | .bool_or => try sema.zirBoolOp(block, inst, true), | 177 | .bool_and => try sema.zirBoolOp(block, inst, false), |
| 157 | .bool_br_and => try sema.zirBoolBr(block, inst, false), | 178 | .bool_or => try sema.zirBoolOp(block, inst, true), |
| 158 | .bool_br_or => try sema.zirBoolBr(block, inst, true), | 179 | .bool_br_and => try sema.zirBoolBr(block, inst, false), |
| 159 | .call => try sema.zirCall(block, inst, .auto, false), | 180 | .bool_br_or => try sema.zirBoolBr(block, inst, true), |
| 160 | .call_chkused => try sema.zirCall(block, inst, .auto, true), | 181 | .c_import => try sema.zirCImport(block, inst), |
| 161 | .call_compile_time => try sema.zirCall(block, inst, .compile_time, false), | 182 | .call => try sema.zirCall(block, inst, .auto, false), |
| 162 | .call_none => try sema.zirCallNone(block, inst, false), | 183 | .call_chkused => try sema.zirCall(block, inst, .auto, true), |
| 163 | .call_none_chkused => try sema.zirCallNone(block, inst, true), | 184 | .call_compile_time => try sema.zirCall(block, inst, .compile_time, false), |
| 164 | .cmp_eq => try sema.zirCmp(block, inst, .eq), | 185 | .call_nosuspend => try sema.zirCall(block, inst, .no_async, false), |
| 165 | .cmp_gt => try sema.zirCmp(block, inst, .gt), | 186 | .call_async => try sema.zirCall(block, inst, .async_kw, false), |
| 166 | .cmp_gte => try sema.zirCmp(block, inst, .gte), | 187 | .cmp_eq => try sema.zirCmp(block, inst, .eq), |
| 167 | .cmp_lt => try sema.zirCmp(block, inst, .lt), | 188 | .cmp_gt => try sema.zirCmp(block, inst, .gt), |
| 168 | .cmp_lte => try sema.zirCmp(block, inst, .lte), | 189 | .cmp_gte => try sema.zirCmp(block, inst, .gte), |
| 169 | .cmp_neq => try sema.zirCmp(block, inst, .neq), | 190 | .cmp_lt => try sema.zirCmp(block, inst, .lt), |
| 170 | .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), | 191 | .cmp_lte => try sema.zirCmp(block, inst, .lte), |
| 171 | .decl_ref => try sema.zirDeclRef(block, inst), | 192 | .cmp_neq => try sema.zirCmp(block, inst, .neq), |
| 172 | .decl_val => try sema.zirDeclVal(block, inst), | 193 | .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), |
| 173 | .load => try sema.zirLoad(block, inst), | 194 | .decl_ref => try sema.zirDeclRef(block, inst), |
| 174 | .div => try sema.zirArithmetic(block, inst), | 195 | .decl_val => try sema.zirDeclVal(block, inst), |
| 175 | .elem_ptr => try sema.zirElemPtr(block, inst), | 196 | .load => try sema.zirLoad(block, inst), |
| 176 | .elem_ptr_node => try sema.zirElemPtrNode(block, inst), | 197 | .elem_ptr => try sema.zirElemPtr(block, inst), |
| 177 | .elem_val => try sema.zirElemVal(block, inst), | 198 | .elem_ptr_node => try sema.zirElemPtrNode(block, inst), |
| 178 | .elem_val_node => try sema.zirElemValNode(block, inst), | 199 | .elem_val => try sema.zirElemVal(block, inst), |
| 179 | .enum_literal => try sema.zirEnumLiteral(block, inst), | 200 | .elem_val_node => try sema.zirElemValNode(block, inst), |
| 180 | .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst), | 201 | .elem_type => try sema.zirElemType(block, inst), |
| 181 | .enum_to_int => try sema.zirEnumToInt(block, inst), | 202 | .enum_literal => try sema.zirEnumLiteral(block, inst), |
| 182 | .int_to_enum => try sema.zirIntToEnum(block, inst), | 203 | .enum_to_int => try sema.zirEnumToInt(block, inst), |
| 183 | .err_union_code => try sema.zirErrUnionCode(block, inst), | 204 | .int_to_enum => try sema.zirIntToEnum(block, inst), |
| 184 | .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), | 205 | .err_union_code => try sema.zirErrUnionCode(block, inst), |
| 185 | .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), | 206 | .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), |
| 186 | .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), | 207 | .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), |
| 187 | .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), | 208 | .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), |
| 209 | .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), | ||
| 188 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), | 210 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), |
| 189 | .error_union_type => try sema.zirErrorUnionType(block, inst), | 211 | .error_union_type => try sema.zirErrorUnionType(block, inst), |
| 190 | .error_value => try sema.zirErrorValue(block, inst), | 212 | .error_value => try sema.zirErrorValue(block, inst), |
| 191 | .error_to_int => try sema.zirErrorToInt(block, inst), | 213 | .error_to_int => try sema.zirErrorToInt(block, inst), |
| 192 | .int_to_error => try sema.zirIntToError(block, inst), | 214 | .int_to_error => try sema.zirIntToError(block, inst), |
| 193 | .field_ptr => try sema.zirFieldPtr(block, inst), | 215 | .field_ptr => try sema.zirFieldPtr(block, inst), |
| 194 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), | 216 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 195 | .field_val => try sema.zirFieldVal(block, inst), | 217 | .field_val => try sema.zirFieldVal(block, inst), |
| 196 | .field_val_named => try sema.zirFieldValNamed(block, inst), | 218 | .field_val_named => try sema.zirFieldValNamed(block, inst), |
| 197 | .floatcast => try sema.zirFloatcast(block, inst), | 219 | .func => try sema.zirFunc(block, inst, false), |
| 198 | .fn_type => try sema.zirFnType(block, inst, false), | 220 | .func_inferred => try sema.zirFunc(block, inst, true), |
| 199 | .fn_type_cc => try sema.zirFnTypeCc(block, inst, false), | 221 | .import => try sema.zirImport(block, inst), |
| 200 | .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true), | 222 | .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), |
| 201 | .fn_type_var_args => try sema.zirFnType(block, inst, true), | 223 | .int => try sema.zirInt(block, inst), |
| 202 | .has_decl => try sema.zirHasDecl(block, inst), | 224 | .int_big => try sema.zirIntBig(block, inst), |
| 203 | .import => try sema.zirImport(block, inst), | 225 | .float => try sema.zirFloat(block, inst), |
| 204 | .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), | 226 | .float128 => try sema.zirFloat128(block, inst), |
| 205 | .int => try sema.zirInt(block, inst), | 227 | .int_type => try sema.zirIntType(block, inst), |
| 206 | .float => try sema.zirFloat(block, inst), | 228 | .is_err => try sema.zirIsErr(block, inst), |
| 207 | .float128 => try sema.zirFloat128(block, inst), | 229 | .is_err_ptr => try sema.zirIsErrPtr(block, inst), |
| 208 | .int_type => try sema.zirIntType(block, inst), | 230 | .is_non_null => try sema.zirIsNull(block, inst, true), |
| 209 | .intcast => try sema.zirIntcast(block, inst), | 231 | .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), |
| 210 | .is_err => try sema.zirIsErr(block, inst), | 232 | .is_null => try sema.zirIsNull(block, inst, false), |
| 211 | .is_err_ptr => try sema.zirIsErrPtr(block, inst), | 233 | .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), |
| 212 | .is_non_null => try sema.zirIsNull(block, inst, true), | 234 | .loop => try sema.zirLoop(block, inst), |
| 213 | .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), | 235 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), |
| 214 | .is_null => try sema.zirIsNull(block, inst, false), | 236 | .negate => try sema.zirNegate(block, inst, .sub), |
| 215 | .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), | 237 | .negate_wrap => try sema.zirNegate(block, inst, .subwrap), |
| 216 | .loop => try sema.zirLoop(block, inst), | 238 | .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), |
| 217 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), | 239 | .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), |
| 240 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), | ||
| 241 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), | ||
| 242 | .optional_type => try sema.zirOptionalType(block, inst), | ||
| 243 | .param_type => try sema.zirParamType(block, inst), | ||
| 244 | .ptr_type => try sema.zirPtrType(block, inst), | ||
| 245 | .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), | ||
| 246 | .ref => try sema.zirRef(block, inst), | ||
| 247 | .shl => try sema.zirShl(block, inst), | ||
| 248 | .shr => try sema.zirShr(block, inst), | ||
| 249 | .slice_end => try sema.zirSliceEnd(block, inst), | ||
| 250 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | ||
| 251 | .slice_start => try sema.zirSliceStart(block, inst), | ||
| 252 | .str => try sema.zirStr(block, inst), | ||
| 253 | .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), | ||
| 254 | .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), | ||
| 255 | .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), | ||
| 256 | .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), | ||
| 257 | .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), | ||
| 258 | .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), | ||
| 259 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), | ||
| 260 | .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), | ||
| 261 | .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), | ||
| 262 | .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), | ||
| 263 | .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), | ||
| 264 | .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), | ||
| 265 | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), | ||
| 266 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | ||
| 267 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | ||
| 268 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), | ||
| 269 | .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), | ||
| 270 | .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), | ||
| 271 | .type_info => try sema.zirTypeInfo(block, inst), | ||
| 272 | .size_of => try sema.zirSizeOf(block, inst), | ||
| 273 | .bit_size_of => try sema.zirBitSizeOf(block, inst), | ||
| 274 | .typeof => try sema.zirTypeof(block, inst), | ||
| 275 | .typeof_elem => try sema.zirTypeofElem(block, inst), | ||
| 276 | .log2_int_type => try sema.zirLog2IntType(block, inst), | ||
| 277 | .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), | ||
| 278 | .xor => try sema.zirBitwise(block, inst, .xor), | ||
| 279 | .struct_init_empty => try sema.zirStructInitEmpty(block, inst), | ||
| 280 | .struct_init => try sema.zirStructInit(block, inst, false), | ||
| 281 | .struct_init_ref => try sema.zirStructInit(block, inst, true), | ||
| 282 | .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), | ||
| 283 | .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), | ||
| 284 | .array_init => try sema.zirArrayInit(block, inst, false), | ||
| 285 | .array_init_ref => try sema.zirArrayInit(block, inst, true), | ||
| 286 | .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), | ||
| 287 | .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), | ||
| 288 | .union_init_ptr => try sema.zirUnionInitPtr(block, inst), | ||
| 289 | .field_type => try sema.zirFieldType(block, inst), | ||
| 290 | .field_type_ref => try sema.zirFieldTypeRef(block, inst), | ||
| 291 | .ptr_to_int => try sema.zirPtrToInt(block, inst), | ||
| 292 | .align_of => try sema.zirAlignOf(block, inst), | ||
| 293 | .bool_to_int => try sema.zirBoolToInt(block, inst), | ||
| 294 | .embed_file => try sema.zirEmbedFile(block, inst), | ||
| 295 | .error_name => try sema.zirErrorName(block, inst), | ||
| 296 | .tag_name => try sema.zirTagName(block, inst), | ||
| 297 | .reify => try sema.zirReify(block, inst), | ||
| 298 | .type_name => try sema.zirTypeName(block, inst), | ||
| 299 | .frame_type => try sema.zirFrameType(block, inst), | ||
| 300 | .frame_size => try sema.zirFrameSize(block, inst), | ||
| 301 | .float_to_int => try sema.zirFloatToInt(block, inst), | ||
| 302 | .int_to_float => try sema.zirIntToFloat(block, inst), | ||
| 303 | .int_to_ptr => try sema.zirIntToPtr(block, inst), | ||
| 304 | .float_cast => try sema.zirFloatCast(block, inst), | ||
| 305 | .int_cast => try sema.zirIntCast(block, inst), | ||
| 306 | .err_set_cast => try sema.zirErrSetCast(block, inst), | ||
| 307 | .ptr_cast => try sema.zirPtrCast(block, inst), | ||
| 308 | .truncate => try sema.zirTruncate(block, inst), | ||
| 309 | .align_cast => try sema.zirAlignCast(block, inst), | ||
| 310 | .has_decl => try sema.zirHasDecl(block, inst), | ||
| 311 | .has_field => try sema.zirHasField(block, inst), | ||
| 312 | .clz => try sema.zirClz(block, inst), | ||
| 313 | .ctz => try sema.zirCtz(block, inst), | ||
| 314 | .pop_count => try sema.zirPopCount(block, inst), | ||
| 315 | .byte_swap => try sema.zirByteSwap(block, inst), | ||
| 316 | .bit_reverse => try sema.zirBitReverse(block, inst), | ||
| 317 | .div_exact => try sema.zirDivExact(block, inst), | ||
| 318 | .div_floor => try sema.zirDivFloor(block, inst), | ||
| 319 | .div_trunc => try sema.zirDivTrunc(block, inst), | ||
| 320 | .mod => try sema.zirMod(block, inst), | ||
| 321 | .rem => try sema.zirRem(block, inst), | ||
| 322 | .shl_exact => try sema.zirShlExact(block, inst), | ||
| 323 | .shr_exact => try sema.zirShrExact(block, inst), | ||
| 324 | .bit_offset_of => try sema.zirBitOffsetOf(block, inst), | ||
| 325 | .byte_offset_of => try sema.zirByteOffsetOf(block, inst), | ||
| 326 | .cmpxchg_strong => try sema.zirCmpxchg(block, inst), | ||
| 327 | .cmpxchg_weak => try sema.zirCmpxchg(block, inst), | ||
| 328 | .splat => try sema.zirSplat(block, inst), | ||
| 329 | .reduce => try sema.zirReduce(block, inst), | ||
| 330 | .shuffle => try sema.zirShuffle(block, inst), | ||
| 331 | .atomic_load => try sema.zirAtomicLoad(block, inst), | ||
| 332 | .atomic_rmw => try sema.zirAtomicRmw(block, inst), | ||
| 333 | .atomic_store => try sema.zirAtomicStore(block, inst), | ||
| 334 | .mul_add => try sema.zirMulAdd(block, inst), | ||
| 335 | .builtin_call => try sema.zirBuiltinCall(block, inst), | ||
| 336 | .field_ptr_type => try sema.zirFieldPtrType(block, inst), | ||
| 337 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), | ||
| 338 | .memcpy => try sema.zirMemcpy(block, inst), | ||
| 339 | .memset => try sema.zirMemset(block, inst), | ||
| 340 | .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), | ||
| 341 | .@"resume" => try sema.zirResume(block, inst), | ||
| 342 | .@"await" => try sema.zirAwait(block, inst, false), | ||
| 343 | .await_nosuspend => try sema.zirAwait(block, inst, true), | ||
| 344 | .extended => try sema.zirExtended(block, inst), | ||
| 345 | |||
| 346 | .sqrt => try sema.zirUnaryMath(block, inst), | ||
| 347 | .sin => try sema.zirUnaryMath(block, inst), | ||
| 348 | .cos => try sema.zirUnaryMath(block, inst), | ||
| 349 | .exp => try sema.zirUnaryMath(block, inst), | ||
| 350 | .exp2 => try sema.zirUnaryMath(block, inst), | ||
| 351 | .log => try sema.zirUnaryMath(block, inst), | ||
| 352 | .log2 => try sema.zirUnaryMath(block, inst), | ||
| 353 | .log10 => try sema.zirUnaryMath(block, inst), | ||
| 354 | .fabs => try sema.zirUnaryMath(block, inst), | ||
| 355 | .floor => try sema.zirUnaryMath(block, inst), | ||
| 356 | .ceil => try sema.zirUnaryMath(block, inst), | ||
| 357 | .trunc => try sema.zirUnaryMath(block, inst), | ||
| 358 | .round => try sema.zirUnaryMath(block, inst), | ||
| 359 | |||
| 360 | .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent), | ||
| 361 | .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon), | ||
| 362 | .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func), | ||
| 363 | .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), | ||
| 364 | .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), | ||
| 365 | .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), | ||
| 366 | |||
| 367 | .add => try sema.zirArithmetic(block, inst), | ||
| 368 | .addwrap => try sema.zirArithmetic(block, inst), | ||
| 369 | .div => try sema.zirArithmetic(block, inst), | ||
| 218 | .mod_rem => try sema.zirArithmetic(block, inst), | 370 | .mod_rem => try sema.zirArithmetic(block, inst), |
| 219 | .mul => try sema.zirArithmetic(block, inst), | 371 | .mul => try sema.zirArithmetic(block, inst), |
| 220 | .mulwrap => try sema.zirArithmetic(block, inst), | 372 | .mulwrap => try sema.zirArithmetic(block, inst), |
| 221 | .negate => try sema.zirNegate(block, inst, .sub), | 373 | .sub => try sema.zirArithmetic(block, inst), |
| 222 | .negate_wrap => try sema.zirNegate(block, inst, .subwrap), | ||
| 223 | .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), | ||
| 224 | .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), | ||
| 225 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), | ||
| 226 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), | ||
| 227 | .optional_type => try sema.zirOptionalType(block, inst), | ||
| 228 | .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst), | ||
| 229 | .param_type => try sema.zirParamType(block, inst), | ||
| 230 | .ptr_type => try sema.zirPtrType(block, inst), | ||
| 231 | .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), | ||
| 232 | .ptrtoint => try sema.zirPtrtoint(block, inst), | ||
| 233 | .ref => try sema.zirRef(block, inst), | ||
| 234 | .ret_ptr => try sema.zirRetPtr(block, inst), | ||
| 235 | .ret_type => try sema.zirRetType(block, inst), | ||
| 236 | .shl => try sema.zirShl(block, inst), | ||
| 237 | .shr => try sema.zirShr(block, inst), | ||
| 238 | .slice_end => try sema.zirSliceEnd(block, inst), | ||
| 239 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | ||
| 240 | .slice_start => try sema.zirSliceStart(block, inst), | ||
| 241 | .str => try sema.zirStr(block, inst), | ||
| 242 | .sub => try sema.zirArithmetic(block, inst), | ||
| 243 | .subwrap => try sema.zirArithmetic(block, inst), | 374 | .subwrap => try sema.zirArithmetic(block, inst), |
| 244 | .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), | ||
| 245 | .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), | ||
| 246 | .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), | ||
| 247 | .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), | ||
| 248 | .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), | ||
| 249 | .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), | ||
| 250 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), | ||
| 251 | .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), | ||
| 252 | .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), | ||
| 253 | .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), | ||
| 254 | .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), | ||
| 255 | .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), | ||
| 256 | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), | ||
| 257 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | ||
| 258 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | ||
| 259 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), | ||
| 260 | .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), | ||
| 261 | .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), | ||
| 262 | .type_info => try sema.zirTypeInfo(block, inst), | ||
| 263 | .typeof => try sema.zirTypeof(block, inst), | ||
| 264 | .typeof_elem => try sema.zirTypeofElem(block, inst), | ||
| 265 | .typeof_peer => try sema.zirTypeofPeer(block, inst), | ||
| 266 | .xor => try sema.zirBitwise(block, inst, .xor), | ||
| 267 | .struct_init_empty => try sema.zirStructInitEmpty(block, inst), | ||
| 268 | .struct_init => try sema.zirStructInit(block, inst), | ||
| 269 | .field_type => try sema.zirFieldType(block, inst), | ||
| 270 | |||
| 271 | .struct_decl => try sema.zirStructDecl(block, inst, .Auto), | ||
| 272 | .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed), | ||
| 273 | .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern), | ||
| 274 | .enum_decl => try sema.zirEnumDecl(block, inst, false), | ||
| 275 | .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true), | ||
| 276 | .union_decl => try sema.zirUnionDecl(block, inst), | ||
| 277 | .opaque_decl => try sema.zirOpaqueDecl(block, inst), | ||
| 278 | 375 | ||
| 279 | // Instructions that we know to *always* be noreturn based solely on their tag. | 376 | // Instructions that we know to *always* be noreturn based solely on their tag. |
| 280 | // These functions match the return type of analyzeBody so that we can | 377 | // These functions match the return type of analyzeBody so that we can |
| 281 | // tail call them here. | 378 | // tail call them here. |
| 282 | .condbr => return sema.zirCondbr(block, inst), | 379 | .break_inline => return inst, |
| 283 | .@"break" => return sema.zirBreak(block, inst), | 380 | .condbr => return sema.zirCondbr(block, inst), |
| 284 | .break_inline => return inst, | 381 | .@"break" => return sema.zirBreak(block, inst), |
| 285 | .compile_error => return sema.zirCompileError(block, inst), | 382 | .compile_error => return sema.zirCompileError(block, inst), |
| 286 | .ret_coerce => return sema.zirRetTok(block, inst, true), | 383 | .ret_coerce => return sema.zirRetTok(block, inst, true), |
| 287 | .ret_node => return sema.zirRetNode(block, inst), | 384 | .ret_node => return sema.zirRetNode(block, inst), |
| 288 | .ret_tok => return sema.zirRetTok(block, inst, false), | ||
| 289 | .@"unreachable" => return sema.zirUnreachable(block, inst), | 385 | .@"unreachable" => return sema.zirUnreachable(block, inst), |
| 290 | .repeat => return sema.zirRepeat(block, inst), | 386 | .repeat => return sema.zirRepeat(block, inst), |
| 387 | .panic => return sema.zirPanic(block, inst), | ||
| 388 | // zig fmt: on | ||
| 291 | 389 | ||
| 292 | // Instructions that we know can *never* be noreturn based solely on | 390 | // Instructions that we know can *never* be noreturn based solely on |
| 293 | // their tag. We avoid needlessly checking if they are noreturn and | 391 | // their tag. We avoid needlessly checking if they are noreturn and |
| ... | @@ -298,8 +396,12 @@ pub fn analyzeBody( | ... | @@ -298,8 +396,12 @@ pub fn analyzeBody( |
| 298 | try sema.zirBreakpoint(block, inst); | 396 | try sema.zirBreakpoint(block, inst); |
| 299 | continue; | 397 | continue; |
| 300 | }, | 398 | }, |
| 301 | .dbg_stmt_node => { | 399 | .fence => { |
| 302 | try sema.zirDbgStmtNode(block, inst); | 400 | try sema.zirFence(block, inst); |
| 401 | continue; | ||
| 402 | }, | ||
| 403 | .dbg_stmt => { | ||
| 404 | try sema.zirDbgStmt(block, inst); | ||
| 303 | continue; | 405 | continue; |
| 304 | }, | 406 | }, |
| 305 | .ensure_err_payload_void => { | 407 | .ensure_err_payload_void => { |
| ... | @@ -314,10 +416,6 @@ pub fn analyzeBody( | ... | @@ -314,10 +416,6 @@ pub fn analyzeBody( |
| 314 | try sema.zirEnsureResultUsed(block, inst); | 416 | try sema.zirEnsureResultUsed(block, inst); |
| 315 | continue; | 417 | continue; |
| 316 | }, | 418 | }, |
| 317 | .compile_log => { | ||
| 318 | try sema.zirCompileLog(block, inst); | ||
| 319 | continue; | ||
| 320 | }, | ||
| 321 | .set_eval_branch_quota => { | 419 | .set_eval_branch_quota => { |
| 322 | try sema.zirSetEvalBranchQuota(block, inst); | 420 | try sema.zirSetEvalBranchQuota(block, inst); |
| 323 | continue; | 421 | continue; |
| ... | @@ -346,10 +444,30 @@ pub fn analyzeBody( | ... | @@ -346,10 +444,30 @@ pub fn analyzeBody( |
| 346 | try sema.zirValidateStructInitPtr(block, inst); | 444 | try sema.zirValidateStructInitPtr(block, inst); |
| 347 | continue; | 445 | continue; |
| 348 | }, | 446 | }, |
| 447 | .validate_array_init_ptr => { | ||
| 448 | try sema.zirValidateArrayInitPtr(block, inst); | ||
| 449 | continue; | ||
| 450 | }, | ||
| 349 | .@"export" => { | 451 | .@"export" => { |
| 350 | try sema.zirExport(block, inst); | 452 | try sema.zirExport(block, inst); |
| 351 | continue; | 453 | continue; |
| 352 | }, | 454 | }, |
| 455 | .set_align_stack => { | ||
| 456 | try sema.zirSetAlignStack(block, inst); | ||
| 457 | continue; | ||
| 458 | }, | ||
| 459 | .set_cold => { | ||
| 460 | try sema.zirSetAlignStack(block, inst); | ||
| 461 | continue; | ||
| 462 | }, | ||
| 463 | .set_float_mode => { | ||
| 464 | try sema.zirSetFloatMode(block, inst); | ||
| 465 | continue; | ||
| 466 | }, | ||
| 467 | .set_runtime_safety => { | ||
| 468 | try sema.zirSetRuntimeSafety(block, inst); | ||
| 469 | continue; | ||
| 470 | }, | ||
| 353 | 471 | ||
| 354 | // Special case instructions to handle comptime control flow. | 472 | // Special case instructions to handle comptime control flow. |
| 355 | .repeat_inline => { | 473 | .repeat_inline => { |
| ... | @@ -362,7 +480,7 @@ pub fn analyzeBody( | ... | @@ -362,7 +480,7 @@ pub fn analyzeBody( |
| 362 | .block_inline => blk: { | 480 | .block_inline => blk: { |
| 363 | // Directly analyze the block body without introducing a new block. | 481 | // Directly analyze the block body without introducing a new block. |
| 364 | const inst_data = datas[inst].pl_node; | 482 | const inst_data = datas[inst].pl_node; |
| 365 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 483 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 366 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 484 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 367 | const break_inst = try sema.analyzeBody(block, inline_body); | 485 | const break_inst = try sema.analyzeBody(block, inline_body); |
| 368 | const break_data = datas[break_inst].@"break"; | 486 | const break_data = datas[break_inst].@"break"; |
| ... | @@ -375,7 +493,7 @@ pub fn analyzeBody( | ... | @@ -375,7 +493,7 @@ pub fn analyzeBody( |
| 375 | .condbr_inline => blk: { | 493 | .condbr_inline => blk: { |
| 376 | const inst_data = datas[inst].pl_node; | 494 | const inst_data = datas[inst].pl_node; |
| 377 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; | 495 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; |
| 378 | const extra = sema.code.extraData(zir.Inst.CondBr, inst_data.payload_index); | 496 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); |
| 379 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; | 497 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; |
| 380 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 498 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 381 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); | 499 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); |
| ... | @@ -389,53 +507,87 @@ pub fn analyzeBody( | ... | @@ -389,53 +507,87 @@ pub fn analyzeBody( |
| 389 | } | 507 | } |
| 390 | }, | 508 | }, |
| 391 | }; | 509 | }; |
| 392 | if (map[inst].ty.isNoReturn()) | 510 | if (air_inst.ty.isNoReturn()) |
| 393 | return always_noreturn; | 511 | return always_noreturn; |
| 512 | try map.putNoClobber(sema.gpa, inst, air_inst); | ||
| 394 | } | 513 | } |
| 395 | } | 514 | } |
| 396 | 515 | ||
| 397 | /// TODO when we rework TZIR memory layout, this function will no longer have a possible error. | 516 | fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 398 | pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst { | 517 | const extended = sema.code.instructions.items(.data)[inst].extended; |
| 518 | switch (extended.opcode) { | ||
| 519 | // zig fmt: off | ||
| 520 | .func => return sema.zirFuncExtended( block, extended, inst), | ||
| 521 | .variable => return sema.zirVarExtended( block, extended), | ||
| 522 | .struct_decl => return sema.zirStructDecl( block, extended, inst), | ||
| 523 | .enum_decl => return sema.zirEnumDecl( block, extended), | ||
| 524 | .union_decl => return sema.zirUnionDecl( block, extended, inst), | ||
| 525 | .ret_ptr => return sema.zirRetPtr( block, extended), | ||
| 526 | .ret_type => return sema.zirRetType( block, extended), | ||
| 527 | .this => return sema.zirThis( block, extended), | ||
| 528 | .ret_addr => return sema.zirRetAddr( block, extended), | ||
| 529 | .builtin_src => return sema.zirBuiltinSrc( block, extended), | ||
| 530 | .error_return_trace => return sema.zirErrorReturnTrace( block, extended), | ||
| 531 | .frame => return sema.zirFrame( block, extended), | ||
| 532 | .frame_address => return sema.zirFrameAddress( block, extended), | ||
| 533 | .alloc => return sema.zirAllocExtended( block, extended), | ||
| 534 | .builtin_extern => return sema.zirBuiltinExtern( block, extended), | ||
| 535 | .@"asm" => return sema.zirAsm( block, extended), | ||
| 536 | .typeof_peer => return sema.zirTypeofPeer( block, extended), | ||
| 537 | .compile_log => return sema.zirCompileLog( block, extended), | ||
| 538 | .add_with_overflow => return sema.zirOverflowArithmetic(block, extended), | ||
| 539 | .sub_with_overflow => return sema.zirOverflowArithmetic(block, extended), | ||
| 540 | .mul_with_overflow => return sema.zirOverflowArithmetic(block, extended), | ||
| 541 | .shl_with_overflow => return sema.zirOverflowArithmetic(block, extended), | ||
| 542 | .c_undef => return sema.zirCUndef( block, extended), | ||
| 543 | .c_include => return sema.zirCInclude( block, extended), | ||
| 544 | .c_define => return sema.zirCDefine( block, extended), | ||
| 545 | .wasm_memory_size => return sema.zirWasmMemorySize( block, extended), | ||
| 546 | .wasm_memory_grow => return sema.zirWasmMemoryGrow( block, extended), | ||
| 547 | // zig fmt: on | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | /// TODO when we rework AIR memory layout, this function will no longer have a possible error. | ||
| 552 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.Inst { | ||
| 399 | var i: usize = @enumToInt(zir_ref); | 553 | var i: usize = @enumToInt(zir_ref); |
| 400 | 554 | ||
| 401 | // First section of indexes correspond to a set number of constant values. | 555 | // First section of indexes correspond to a set number of constant values. |
| 402 | if (i < zir.Inst.Ref.typed_value_map.len) { | 556 | if (i < Zir.Inst.Ref.typed_value_map.len) { |
| 403 | // TODO when we rework TZIR memory layout, this function can be as simple as: | 557 | // TODO when we rework AIR memory layout, this function can be as simple as: |
| 404 | // if (zir_ref < zir.const_inst_list.len + sema.param_count) | 558 | // if (zir_ref < Zir.const_inst_list.len + sema.param_count) |
| 405 | // return zir_ref; | 559 | // return zir_ref; |
| 406 | // Until then we allocate memory for a new, mutable `ir.Inst` to match what | 560 | // Until then we allocate memory for a new, mutable `ir.Inst` to match what |
| 407 | // TZIR expects. | 561 | // AIR expects. |
| 408 | return sema.mod.constInst(sema.arena, .unneeded, zir.Inst.Ref.typed_value_map[i]); | 562 | return sema.mod.constInst(sema.arena, .unneeded, Zir.Inst.Ref.typed_value_map[i]); |
| 409 | } | ||
| 410 | i -= zir.Inst.Ref.typed_value_map.len; | ||
| 411 | |||
| 412 | // Next section of indexes correspond to function parameters, if any. | ||
| 413 | if (i < sema.param_inst_list.len) { | ||
| 414 | return sema.param_inst_list[i]; | ||
| 415 | } | 563 | } |
| 416 | i -= sema.param_inst_list.len; | 564 | i -= Zir.Inst.Ref.typed_value_map.len; |
| 417 | 565 | ||
| 418 | // Finally, the last section of indexes refers to the map of ZIR=>TZIR. | 566 | // Finally, the last section of indexes refers to the map of ZIR=>AIR. |
| 419 | return sema.inst_map[i]; | 567 | return sema.inst_map.get(@intCast(u32, i)).?; |
| 420 | } | 568 | } |
| 421 | 569 | ||
| 422 | fn resolveConstString( | 570 | fn resolveConstString( |
| 423 | sema: *Sema, | 571 | sema: *Sema, |
| 424 | block: *Scope.Block, | 572 | block: *Scope.Block, |
| 425 | src: LazySrcLoc, | 573 | src: LazySrcLoc, |
| 426 | zir_ref: zir.Inst.Ref, | 574 | zir_ref: Zir.Inst.Ref, |
| 427 | ) ![]u8 { | 575 | ) ![]u8 { |
| 428 | const tzir_inst = try sema.resolveInst(zir_ref); | 576 | const air_inst = try sema.resolveInst(zir_ref); |
| 429 | const wanted_type = Type.initTag(.const_slice_u8); | 577 | const wanted_type = Type.initTag(.const_slice_u8); |
| 430 | const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst, src); | 578 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 431 | const val = try sema.resolveConstValue(block, src, coerced_inst); | 579 | const val = try sema.resolveConstValue(block, src, coerced_inst); |
| 432 | return val.toAllocatedBytes(sema.arena); | 580 | return val.toAllocatedBytes(sema.arena); |
| 433 | } | 581 | } |
| 434 | 582 | ||
| 435 | fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type { | 583 | pub fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { |
| 436 | const tzir_inst = try sema.resolveInst(zir_ref); | 584 | const air_inst = try sema.resolveInst(zir_ref); |
| 585 | return sema.resolveAirAsType(block, src, air_inst); | ||
| 586 | } | ||
| 587 | |||
| 588 | fn resolveAirAsType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, air_inst: *ir.Inst) !Type { | ||
| 437 | const wanted_type = Type.initTag(.@"type"); | 589 | const wanted_type = Type.initTag(.@"type"); |
| 438 | const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst, src); | 590 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 439 | const val = try sema.resolveConstValue(block, src, coerced_inst); | 591 | const val = try sema.resolveConstValue(block, src, coerced_inst); |
| 440 | return val.toType(sema.arena); | 592 | return val.toType(sema.arena); |
| 441 | } | 593 | } |
| ... | @@ -446,7 +598,7 @@ fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *i | ... | @@ -446,7 +598,7 @@ fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *i |
| 446 | } | 598 | } |
| 447 | 599 | ||
| 448 | fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value { | 600 | fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value { |
| 449 | if (base.value()) |val| { | 601 | if (try sema.resolvePossiblyUndefinedValue(block, src, base)) |val| { |
| 450 | if (val.isUndef()) { | 602 | if (val.isUndef()) { |
| 451 | return sema.failWithUseOfUndef(block, src); | 603 | return sema.failWithUseOfUndef(block, src); |
| 452 | } | 604 | } |
| ... | @@ -455,6 +607,19 @@ fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: | ... | @@ -455,6 +607,19 @@ fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: |
| 455 | return null; | 607 | return null; |
| 456 | } | 608 | } |
| 457 | 609 | ||
| 610 | fn resolvePossiblyUndefinedValue( | ||
| 611 | sema: *Sema, | ||
| 612 | block: *Scope.Block, | ||
| 613 | src: LazySrcLoc, | ||
| 614 | base: *ir.Inst, | ||
| 615 | ) !?Value { | ||
| 616 | if (try sema.typeHasOnePossibleValue(block, src, base.ty)) |opv| { | ||
| 617 | return opv; | ||
| 618 | } | ||
| 619 | const inst = base.castTag(.constant) orelse return null; | ||
| 620 | return inst.val; | ||
| 621 | } | ||
| 622 | |||
| 458 | fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError { | 623 | fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError { |
| 459 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); | 624 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); |
| 460 | } | 625 | } |
| ... | @@ -470,12 +635,12 @@ fn resolveAlreadyCoercedInt( | ... | @@ -470,12 +635,12 @@ fn resolveAlreadyCoercedInt( |
| 470 | sema: *Sema, | 635 | sema: *Sema, |
| 471 | block: *Scope.Block, | 636 | block: *Scope.Block, |
| 472 | src: LazySrcLoc, | 637 | src: LazySrcLoc, |
| 473 | zir_ref: zir.Inst.Ref, | 638 | zir_ref: Zir.Inst.Ref, |
| 474 | comptime Int: type, | 639 | comptime Int: type, |
| 475 | ) !Int { | 640 | ) !Int { |
| 476 | comptime assert(@typeInfo(Int).Int.bits <= 64); | 641 | comptime assert(@typeInfo(Int).Int.bits <= 64); |
| 477 | const tzir_inst = try sema.resolveInst(zir_ref); | 642 | const air_inst = try sema.resolveInst(zir_ref); |
| 478 | const val = try sema.resolveConstValue(block, src, tzir_inst); | 643 | const val = try sema.resolveConstValue(block, src, air_inst); |
| 479 | switch (@typeInfo(Int).Int.signedness) { | 644 | switch (@typeInfo(Int).Int.signedness) { |
| 480 | .signed => return @intCast(Int, val.toSignedInt()), | 645 | .signed => return @intCast(Int, val.toSignedInt()), |
| 481 | .unsigned => return @intCast(Int, val.toUnsignedInt()), | 646 | .unsigned => return @intCast(Int, val.toUnsignedInt()), |
| ... | @@ -486,189 +651,470 @@ fn resolveInt( | ... | @@ -486,189 +651,470 @@ fn resolveInt( |
| 486 | sema: *Sema, | 651 | sema: *Sema, |
| 487 | block: *Scope.Block, | 652 | block: *Scope.Block, |
| 488 | src: LazySrcLoc, | 653 | src: LazySrcLoc, |
| 489 | zir_ref: zir.Inst.Ref, | 654 | zir_ref: Zir.Inst.Ref, |
| 490 | dest_type: Type, | 655 | dest_type: Type, |
| 491 | ) !u64 { | 656 | ) !u64 { |
| 492 | const tzir_inst = try sema.resolveInst(zir_ref); | 657 | const air_inst = try sema.resolveInst(zir_ref); |
| 493 | const coerced = try sema.coerce(block, dest_type, tzir_inst, src); | 658 | const coerced = try sema.coerce(block, dest_type, air_inst, src); |
| 494 | const val = try sema.resolveConstValue(block, src, coerced); | 659 | const val = try sema.resolveConstValue(block, src, coerced); |
| 495 | 660 | ||
| 496 | return val.toUnsignedInt(); | 661 | return val.toUnsignedInt(); |
| 497 | } | 662 | } |
| 498 | 663 | ||
| 499 | fn resolveInstConst( | 664 | pub fn resolveInstConst( |
| 500 | sema: *Sema, | 665 | sema: *Sema, |
| 501 | block: *Scope.Block, | 666 | block: *Scope.Block, |
| 502 | src: LazySrcLoc, | 667 | src: LazySrcLoc, |
| 503 | zir_ref: zir.Inst.Ref, | 668 | zir_ref: Zir.Inst.Ref, |
| 504 | ) InnerError!TypedValue { | 669 | ) InnerError!TypedValue { |
| 505 | const tzir_inst = try sema.resolveInst(zir_ref); | 670 | const air_inst = try sema.resolveInst(zir_ref); |
| 506 | const val = try sema.resolveConstValue(block, src, tzir_inst); | 671 | const val = try sema.resolveConstValue(block, src, air_inst); |
| 507 | return TypedValue{ | 672 | return TypedValue{ |
| 508 | .ty = tzir_inst.ty, | 673 | .ty = air_inst.ty, |
| 509 | .val = val, | 674 | .val = val, |
| 510 | }; | 675 | }; |
| 511 | } | 676 | } |
| 512 | 677 | ||
| 513 | fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 678 | fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 514 | const tracy = trace(@src()); | 679 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 515 | defer tracy.end(); | 680 | const src = inst_data.src(); |
| 516 | return sema.mod.fail(&block.base, sema.src, "TODO implement zir_sema.zirBitcastResultPtr", .{}); | 681 | return sema.mod.fail(&block.base, src, "TODO implement zir_sema.zirBitcastResultPtr", .{}); |
| 517 | } | 682 | } |
| 518 | 683 | ||
| 519 | fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 684 | fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 520 | const tracy = trace(@src()); | 685 | const tracy = trace(@src()); |
| 521 | defer tracy.end(); | 686 | defer tracy.end(); |
| 522 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{}); | 687 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{}); |
| 523 | } | 688 | } |
| 524 | 689 | ||
| 690 | pub fn analyzeStructDecl( | ||
| 691 | sema: *Sema, | ||
| 692 | new_decl: *Decl, | ||
| 693 | inst: Zir.Inst.Index, | ||
| 694 | struct_obj: *Module.Struct, | ||
| 695 | ) InnerError!void { | ||
| 696 | const extended = sema.code.instructions.items(.data)[inst].extended; | ||
| 697 | assert(extended.opcode == .struct_decl); | ||
| 698 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | ||
| 699 | |||
| 700 | var extra_index: usize = extended.operand; | ||
| 701 | extra_index += @boolToInt(small.has_src_node); | ||
| 702 | extra_index += @boolToInt(small.has_body_len); | ||
| 703 | extra_index += @boolToInt(small.has_fields_len); | ||
| 704 | const decls_len = if (small.has_decls_len) blk: { | ||
| 705 | const decls_len = sema.code.extra[extra_index]; | ||
| 706 | extra_index += 1; | ||
| 707 | break :blk decls_len; | ||
| 708 | } else 0; | ||
| 709 | |||
| 710 | _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl); | ||
| 711 | } | ||
| 712 | |||
| 525 | fn zirStructDecl( | 713 | fn zirStructDecl( |
| 526 | sema: *Sema, | 714 | sema: *Sema, |
| 527 | block: *Scope.Block, | 715 | block: *Scope.Block, |
| 528 | inst: zir.Inst.Index, | 716 | extended: Zir.Inst.Extended.InstData, |
| 529 | layout: std.builtin.TypeInfo.ContainerLayout, | 717 | inst: Zir.Inst.Index, |
| 530 | ) InnerError!*Inst { | 718 | ) InnerError!*Inst { |
| 531 | const tracy = trace(@src()); | 719 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| 532 | defer tracy.end(); | 720 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 533 | 721 | const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); | |
| 534 | const gpa = sema.gpa; | 722 | break :blk .{ .node_offset = node_offset }; |
| 535 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 723 | } else sema.src; |
| 536 | const src = inst_data.src(); | ||
| 537 | const extra = sema.code.extraData(zir.Inst.StructDecl, inst_data.payload_index); | ||
| 538 | const fields_len = extra.data.fields_len; | ||
| 539 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; | ||
| 540 | 724 | ||
| 541 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 725 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 542 | errdefer new_decl_arena.deinit(); | 726 | errdefer new_decl_arena.deinit(); |
| 543 | 727 | ||
| 544 | var fields_map: std.StringArrayHashMapUnmanaged(Module.Struct.Field) = .{}; | ||
| 545 | try fields_map.ensureCapacity(&new_decl_arena.allocator, fields_len); | ||
| 546 | |||
| 547 | { | ||
| 548 | var field_index: usize = extra.end + bit_bags_count; | ||
| 549 | var bit_bag_index: usize = extra.end; | ||
| 550 | var cur_bit_bag: u32 = undefined; | ||
| 551 | var field_i: u32 = 0; | ||
| 552 | while (field_i < fields_len) : (field_i += 1) { | ||
| 553 | if (field_i % 16 == 0) { | ||
| 554 | cur_bit_bag = sema.code.extra[bit_bag_index]; | ||
| 555 | bit_bag_index += 1; | ||
| 556 | } | ||
| 557 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 558 | cur_bit_bag >>= 1; | ||
| 559 | const has_default = @truncate(u1, cur_bit_bag) != 0; | ||
| 560 | cur_bit_bag >>= 1; | ||
| 561 | |||
| 562 | const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[field_index]); | ||
| 563 | field_index += 1; | ||
| 564 | const field_type_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | ||
| 565 | field_index += 1; | ||
| 566 | |||
| 567 | // This string needs to outlive the ZIR code. | ||
| 568 | const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir); | ||
| 569 | // TODO: if we need to report an error here, use a source location | ||
| 570 | // that points to this type expression rather than the struct. | ||
| 571 | // But only resolve the source location if we need to emit a compile error. | ||
| 572 | const field_ty = try sema.resolveType(block, src, field_type_ref); | ||
| 573 | |||
| 574 | const gop = fields_map.getOrPutAssumeCapacity(field_name); | ||
| 575 | assert(!gop.found_existing); | ||
| 576 | gop.entry.value = .{ | ||
| 577 | .ty = field_ty, | ||
| 578 | .abi_align = Value.initTag(.abi_align_default), | ||
| 579 | .default_val = Value.initTag(.unreachable_value), | ||
| 580 | }; | ||
| 581 | |||
| 582 | if (has_align) { | ||
| 583 | const align_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | ||
| 584 | field_index += 1; | ||
| 585 | // TODO: if we need to report an error here, use a source location | ||
| 586 | // that points to this alignment expression rather than the struct. | ||
| 587 | // But only resolve the source location if we need to emit a compile error. | ||
| 588 | gop.entry.value.abi_align = (try sema.resolveInstConst(block, src, align_ref)).val; | ||
| 589 | } | ||
| 590 | if (has_default) { | ||
| 591 | const default_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | ||
| 592 | field_index += 1; | ||
| 593 | // TODO: if we need to report an error here, use a source location | ||
| 594 | // that points to this default value expression rather than the struct. | ||
| 595 | // But only resolve the source location if we need to emit a compile error. | ||
| 596 | gop.entry.value.default_val = (try sema.resolveInstConst(block, src, default_ref)).val; | ||
| 597 | } | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); | 728 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); |
| 602 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); | 729 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); |
| 603 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); | 730 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); |
| 604 | const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{ | 731 | const type_name = try sema.createTypeName(block, small.name_strategy); |
| 732 | const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ | ||
| 605 | .ty = Type.initTag(.type), | 733 | .ty = Type.initTag(.type), |
| 606 | .val = struct_val, | 734 | .val = struct_val, |
| 607 | }); | 735 | }, type_name); |
| 736 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | ||
| 608 | struct_obj.* = .{ | 737 | struct_obj.* = .{ |
| 609 | .owner_decl = sema.owner_decl, | 738 | .owner_decl = new_decl, |
| 610 | .fields = fields_map, | 739 | .fields = .{}, |
| 611 | .node_offset = inst_data.src_node, | 740 | .node_offset = src.node_offset, |
| 612 | .container = .{ | 741 | .zir_index = inst, |
| 742 | .layout = small.layout, | ||
| 743 | .status = .none, | ||
| 744 | .namespace = .{ | ||
| 745 | .parent = sema.owner_decl.namespace, | ||
| 613 | .ty = struct_ty, | 746 | .ty = struct_ty, |
| 614 | .file_scope = block.getFileScope(), | 747 | .file_scope = block.getFileScope(), |
| 615 | .parent_name_hash = new_decl.fullyQualifiedNameHash(), | ||
| 616 | }, | 748 | }, |
| 617 | }; | 749 | }; |
| 750 | std.log.scoped(.module).debug("create struct {*} owned by {*} ({s})", .{ | ||
| 751 | &struct_obj.namespace, new_decl, new_decl.name, | ||
| 752 | }); | ||
| 753 | try sema.analyzeStructDecl(new_decl, inst, struct_obj); | ||
| 754 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 618 | return sema.analyzeDeclVal(block, src, new_decl); | 755 | return sema.analyzeDeclVal(block, src, new_decl); |
| 619 | } | 756 | } |
| 620 | 757 | ||
| 758 | fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 { | ||
| 759 | switch (name_strategy) { | ||
| 760 | .anon => { | ||
| 761 | // It would be neat to have "struct:line:column" but this name has | ||
| 762 | // to survive incremental updates, where it may have been shifted down | ||
| 763 | // or up to a different line, but unchanged, and thus not unnecessarily | ||
| 764 | // semantically analyzed. | ||
| 765 | const name_index = sema.mod.getNextAnonNameIndex(); | ||
| 766 | return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ | ||
| 767 | sema.owner_decl.name, name_index, | ||
| 768 | }); | ||
| 769 | }, | ||
| 770 | .parent => return sema.gpa.dupeZ(u8, mem.spanZ(sema.owner_decl.name)), | ||
| 771 | .func => { | ||
| 772 | const name_index = sema.mod.getNextAnonNameIndex(); | ||
| 773 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ | ||
| 774 | sema.owner_decl.name, name_index, | ||
| 775 | }); | ||
| 776 | log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{ | ||
| 777 | name, | ||
| 778 | }); | ||
| 779 | return name; | ||
| 780 | }, | ||
| 781 | } | ||
| 782 | } | ||
| 783 | |||
| 621 | fn zirEnumDecl( | 784 | fn zirEnumDecl( |
| 622 | sema: *Sema, | 785 | sema: *Sema, |
| 623 | block: *Scope.Block, | 786 | block: *Scope.Block, |
| 624 | inst: zir.Inst.Index, | 787 | extended: Zir.Inst.Extended.InstData, |
| 625 | nonexhaustive: bool, | ||
| 626 | ) InnerError!*Inst { | 788 | ) InnerError!*Inst { |
| 627 | const tracy = trace(@src()); | 789 | const tracy = trace(@src()); |
| 628 | defer tracy.end(); | 790 | defer tracy.end(); |
| 629 | 791 | ||
| 630 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 792 | const mod = sema.mod; |
| 631 | const src = inst_data.src(); | 793 | const gpa = sema.gpa; |
| 632 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 794 | const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small); |
| 795 | var extra_index: usize = extended.operand; | ||
| 796 | |||
| 797 | const src: LazySrcLoc = if (small.has_src_node) blk: { | ||
| 798 | const node_offset = @bitCast(i32, sema.code.extra[extra_index]); | ||
| 799 | extra_index += 1; | ||
| 800 | break :blk .{ .node_offset = node_offset }; | ||
| 801 | } else sema.src; | ||
| 802 | |||
| 803 | const tag_type_ref = if (small.has_tag_type) blk: { | ||
| 804 | const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 805 | extra_index += 1; | ||
| 806 | break :blk tag_type_ref; | ||
| 807 | } else .none; | ||
| 808 | |||
| 809 | const body_len = if (small.has_body_len) blk: { | ||
| 810 | const body_len = sema.code.extra[extra_index]; | ||
| 811 | extra_index += 1; | ||
| 812 | break :blk body_len; | ||
| 813 | } else 0; | ||
| 814 | |||
| 815 | const fields_len = if (small.has_fields_len) blk: { | ||
| 816 | const fields_len = sema.code.extra[extra_index]; | ||
| 817 | extra_index += 1; | ||
| 818 | break :blk fields_len; | ||
| 819 | } else 0; | ||
| 820 | |||
| 821 | const decls_len = if (small.has_decls_len) blk: { | ||
| 822 | const decls_len = sema.code.extra[extra_index]; | ||
| 823 | extra_index += 1; | ||
| 824 | break :blk decls_len; | ||
| 825 | } else 0; | ||
| 826 | |||
| 827 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 828 | errdefer new_decl_arena.deinit(); | ||
| 829 | |||
| 830 | const tag_ty = blk: { | ||
| 831 | if (tag_type_ref != .none) { | ||
| 832 | // TODO better source location | ||
| 833 | // TODO (needs AstGen fix too) move this eval to the block so it gets allocated | ||
| 834 | // in the new decl arena. | ||
| 835 | break :blk try sema.resolveType(block, src, tag_type_ref); | ||
| 836 | } | ||
| 837 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 838 | break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits); | ||
| 839 | }; | ||
| 840 | |||
| 841 | const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull); | ||
| 842 | const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull); | ||
| 843 | enum_ty_payload.* = .{ | ||
| 844 | .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full }, | ||
| 845 | .data = enum_obj, | ||
| 846 | }; | ||
| 847 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | ||
| 848 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); | ||
| 849 | const type_name = try sema.createTypeName(block, small.name_strategy); | ||
| 850 | const new_decl = try mod.createAnonymousDeclNamed(&block.base, .{ | ||
| 851 | .ty = Type.initTag(.type), | ||
| 852 | .val = enum_val, | ||
| 853 | }, type_name); | ||
| 854 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | ||
| 855 | |||
| 856 | enum_obj.* = .{ | ||
| 857 | .owner_decl = new_decl, | ||
| 858 | .tag_ty = tag_ty, | ||
| 859 | .fields = .{}, | ||
| 860 | .values = .{}, | ||
| 861 | .node_offset = src.node_offset, | ||
| 862 | .namespace = .{ | ||
| 863 | .parent = sema.owner_decl.namespace, | ||
| 864 | .ty = enum_ty, | ||
| 865 | .file_scope = block.getFileScope(), | ||
| 866 | }, | ||
| 867 | }; | ||
| 868 | std.log.scoped(.module).debug("create enum {*} owned by {*} ({s})", .{ | ||
| 869 | &enum_obj.namespace, new_decl, new_decl.name, | ||
| 870 | }); | ||
| 871 | |||
| 872 | extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); | ||
| 873 | |||
| 874 | const body = sema.code.extra[extra_index..][0..body_len]; | ||
| 875 | if (fields_len == 0) { | ||
| 876 | assert(body.len == 0); | ||
| 877 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 878 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 879 | } | ||
| 880 | extra_index += body.len; | ||
| 881 | |||
| 882 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 883 | const body_end = extra_index; | ||
| 884 | extra_index += bit_bags_count; | ||
| 885 | |||
| 886 | try enum_obj.fields.ensureCapacity(&new_decl_arena.allocator, fields_len); | ||
| 887 | const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { | ||
| 888 | if (bag != 0) break true; | ||
| 889 | } else false; | ||
| 890 | if (any_values) { | ||
| 891 | try enum_obj.values.ensureCapacity(&new_decl_arena.allocator, fields_len); | ||
| 892 | } | ||
| 893 | |||
| 894 | { | ||
| 895 | // We create a block for the field type instructions because they | ||
| 896 | // may need to reference Decls from inside the enum namespace. | ||
| 897 | // Within the field type, default value, and alignment expressions, the "owner decl" | ||
| 898 | // should be the enum itself. Thus we need a new Sema. | ||
| 899 | var enum_sema: Sema = .{ | ||
| 900 | .mod = mod, | ||
| 901 | .gpa = gpa, | ||
| 902 | .arena = &new_decl_arena.allocator, | ||
| 903 | .code = sema.code, | ||
| 904 | .inst_map = sema.inst_map, | ||
| 905 | .owner_decl = new_decl, | ||
| 906 | .namespace = &enum_obj.namespace, | ||
| 907 | .owner_func = null, | ||
| 908 | .func = null, | ||
| 909 | .param_inst_list = &.{}, | ||
| 910 | .branch_quota = sema.branch_quota, | ||
| 911 | .branch_count = sema.branch_count, | ||
| 912 | }; | ||
| 913 | |||
| 914 | var enum_block: Scope.Block = .{ | ||
| 915 | .parent = null, | ||
| 916 | .sema = &enum_sema, | ||
| 917 | .src_decl = new_decl, | ||
| 918 | .instructions = .{}, | ||
| 919 | .inlining = null, | ||
| 920 | .is_comptime = true, | ||
| 921 | }; | ||
| 922 | defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions | ||
| 923 | |||
| 924 | if (body.len != 0) { | ||
| 925 | _ = try enum_sema.analyzeBody(&enum_block, body); | ||
| 926 | } | ||
| 633 | 927 | ||
| 634 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirEnumDecl", .{}); | 928 | sema.branch_count = enum_sema.branch_count; |
| 929 | sema.branch_quota = enum_sema.branch_quota; | ||
| 930 | } | ||
| 931 | var bit_bag_index: usize = body_end; | ||
| 932 | var cur_bit_bag: u32 = undefined; | ||
| 933 | var field_i: u32 = 0; | ||
| 934 | while (field_i < fields_len) : (field_i += 1) { | ||
| 935 | if (field_i % 32 == 0) { | ||
| 936 | cur_bit_bag = sema.code.extra[bit_bag_index]; | ||
| 937 | bit_bag_index += 1; | ||
| 938 | } | ||
| 939 | const has_tag_value = @truncate(u1, cur_bit_bag) != 0; | ||
| 940 | cur_bit_bag >>= 1; | ||
| 941 | |||
| 942 | const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); | ||
| 943 | extra_index += 1; | ||
| 944 | |||
| 945 | // This string needs to outlive the ZIR code. | ||
| 946 | const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir); | ||
| 947 | |||
| 948 | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); | ||
| 949 | if (gop.found_existing) { | ||
| 950 | const tree = try sema.getAstTree(block); | ||
| 951 | const field_src = enumFieldSrcLoc(block.src_decl, tree.*, src.node_offset, field_i); | ||
| 952 | const other_tag_src = enumFieldSrcLoc(block.src_decl, tree.*, src.node_offset, gop.index); | ||
| 953 | const msg = msg: { | ||
| 954 | const msg = try mod.errMsg(&block.base, field_src, "duplicate enum tag", .{}); | ||
| 955 | errdefer msg.destroy(gpa); | ||
| 956 | try mod.errNote(&block.base, other_tag_src, msg, "other tag here", .{}); | ||
| 957 | break :msg msg; | ||
| 958 | }; | ||
| 959 | return mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 960 | } | ||
| 961 | |||
| 962 | if (has_tag_value) { | ||
| 963 | const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 964 | extra_index += 1; | ||
| 965 | // TODO: if we need to report an error here, use a source location | ||
| 966 | // that points to this default value expression rather than the struct. | ||
| 967 | // But only resolve the source location if we need to emit a compile error. | ||
| 968 | const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val; | ||
| 969 | enum_obj.values.putAssumeCapacityNoClobber(tag_val, {}); | ||
| 970 | } else if (any_values) { | ||
| 971 | const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i); | ||
| 972 | enum_obj.values.putAssumeCapacityNoClobber(tag_val, {}); | ||
| 973 | } | ||
| 974 | } | ||
| 975 | |||
| 976 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 977 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 978 | } | ||
| 979 | |||
| 980 | fn zirUnionDecl( | ||
| 981 | sema: *Sema, | ||
| 982 | block: *Scope.Block, | ||
| 983 | extended: Zir.Inst.Extended.InstData, | ||
| 984 | inst: Zir.Inst.Index, | ||
| 985 | ) InnerError!*Inst { | ||
| 986 | const tracy = trace(@src()); | ||
| 987 | defer tracy.end(); | ||
| 988 | |||
| 989 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); | ||
| 990 | var extra_index: usize = extended.operand; | ||
| 991 | |||
| 992 | const src: LazySrcLoc = if (small.has_src_node) blk: { | ||
| 993 | const node_offset = @bitCast(i32, sema.code.extra[extra_index]); | ||
| 994 | extra_index += 1; | ||
| 995 | break :blk .{ .node_offset = node_offset }; | ||
| 996 | } else sema.src; | ||
| 997 | |||
| 998 | extra_index += @boolToInt(small.has_tag_type); | ||
| 999 | extra_index += @boolToInt(small.has_body_len); | ||
| 1000 | extra_index += @boolToInt(small.has_fields_len); | ||
| 1001 | |||
| 1002 | const decls_len = if (small.has_decls_len) blk: { | ||
| 1003 | const decls_len = sema.code.extra[extra_index]; | ||
| 1004 | extra_index += 1; | ||
| 1005 | break :blk decls_len; | ||
| 1006 | } else 0; | ||
| 1007 | |||
| 1008 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | ||
| 1009 | errdefer new_decl_arena.deinit(); | ||
| 1010 | |||
| 1011 | const union_obj = try new_decl_arena.allocator.create(Module.Union); | ||
| 1012 | const union_ty = try Type.Tag.@"union".create(&new_decl_arena.allocator, union_obj); | ||
| 1013 | const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty); | ||
| 1014 | const type_name = try sema.createTypeName(block, small.name_strategy); | ||
| 1015 | const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ | ||
| 1016 | .ty = Type.initTag(.type), | ||
| 1017 | .val = union_val, | ||
| 1018 | }, type_name); | ||
| 1019 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | ||
| 1020 | union_obj.* = .{ | ||
| 1021 | .owner_decl = new_decl, | ||
| 1022 | .tag_ty = Type.initTag(.@"null"), | ||
| 1023 | .fields = .{}, | ||
| 1024 | .node_offset = src.node_offset, | ||
| 1025 | .zir_index = inst, | ||
| 1026 | .layout = small.layout, | ||
| 1027 | .status = .none, | ||
| 1028 | .namespace = .{ | ||
| 1029 | .parent = sema.owner_decl.namespace, | ||
| 1030 | .ty = union_ty, | ||
| 1031 | .file_scope = block.getFileScope(), | ||
| 1032 | }, | ||
| 1033 | }; | ||
| 1034 | std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{ | ||
| 1035 | &union_obj.namespace, new_decl, new_decl.name, | ||
| 1036 | }); | ||
| 1037 | |||
| 1038 | _ = try sema.mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl); | ||
| 1039 | |||
| 1040 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 1041 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 635 | } | 1042 | } |
| 636 | 1043 | ||
| 637 | fn zirUnionDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1044 | fn zirOpaqueDecl( |
| 1045 | sema: *Sema, | ||
| 1046 | block: *Scope.Block, | ||
| 1047 | inst: Zir.Inst.Index, | ||
| 1048 | name_strategy: Zir.Inst.NameStrategy, | ||
| 1049 | ) InnerError!*Inst { | ||
| 638 | const tracy = trace(@src()); | 1050 | const tracy = trace(@src()); |
| 639 | defer tracy.end(); | 1051 | defer tracy.end(); |
| 640 | 1052 | ||
| 641 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1053 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 642 | const src = inst_data.src(); | 1054 | const src = inst_data.src(); |
| 643 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 1055 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 644 | 1056 | ||
| 645 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirUnionDecl", .{}); | 1057 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{}); |
| 646 | } | 1058 | } |
| 647 | 1059 | ||
| 648 | fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1060 | fn zirErrorSetDecl( |
| 1061 | sema: *Sema, | ||
| 1062 | block: *Scope.Block, | ||
| 1063 | inst: Zir.Inst.Index, | ||
| 1064 | name_strategy: Zir.Inst.NameStrategy, | ||
| 1065 | ) InnerError!*Inst { | ||
| 649 | const tracy = trace(@src()); | 1066 | const tracy = trace(@src()); |
| 650 | defer tracy.end(); | 1067 | defer tracy.end(); |
| 651 | 1068 | ||
| 1069 | const gpa = sema.gpa; | ||
| 652 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1070 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 653 | const src = inst_data.src(); | 1071 | const src = inst_data.src(); |
| 654 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 1072 | const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); |
| 1073 | const fields = sema.code.extra[extra.end..][0..extra.data.fields_len]; | ||
| 655 | 1074 | ||
| 656 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{}); | 1075 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 1076 | errdefer new_decl_arena.deinit(); | ||
| 1077 | |||
| 1078 | const error_set = try new_decl_arena.allocator.create(Module.ErrorSet); | ||
| 1079 | const error_set_ty = try Type.Tag.error_set.create(&new_decl_arena.allocator, error_set); | ||
| 1080 | const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty); | ||
| 1081 | const type_name = try sema.createTypeName(block, name_strategy); | ||
| 1082 | const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ | ||
| 1083 | .ty = Type.initTag(.type), | ||
| 1084 | .val = error_set_val, | ||
| 1085 | }, type_name); | ||
| 1086 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | ||
| 1087 | const names = try new_decl_arena.allocator.alloc([]const u8, fields.len); | ||
| 1088 | for (fields) |str_index, i| { | ||
| 1089 | names[i] = try new_decl_arena.allocator.dupe(u8, sema.code.nullTerminatedString(str_index)); | ||
| 1090 | } | ||
| 1091 | error_set.* = .{ | ||
| 1092 | .owner_decl = new_decl, | ||
| 1093 | .node_offset = inst_data.src_node, | ||
| 1094 | .names_ptr = names.ptr, | ||
| 1095 | .names_len = @intCast(u32, names.len), | ||
| 1096 | }; | ||
| 1097 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 1098 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 657 | } | 1099 | } |
| 658 | 1100 | ||
| 659 | fn zirRetPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1101 | fn zirRetPtr( |
| 1102 | sema: *Sema, | ||
| 1103 | block: *Scope.Block, | ||
| 1104 | extended: Zir.Inst.Extended.InstData, | ||
| 1105 | ) InnerError!*Inst { | ||
| 660 | const tracy = trace(@src()); | 1106 | const tracy = trace(@src()); |
| 661 | defer tracy.end(); | 1107 | defer tracy.end(); |
| 662 | 1108 | ||
| 663 | const src: LazySrcLoc = .unneeded; | 1109 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 664 | try sema.requireFunctionBlock(block, src); | 1110 | try sema.requireFunctionBlock(block, src); |
| 665 | const fn_ty = sema.func.?.owner_decl.typed_value.most_recent.typed_value.ty; | 1111 | const fn_ty = sema.func.?.owner_decl.ty; |
| 666 | const ret_type = fn_ty.fnReturnType(); | 1112 | const ret_type = fn_ty.fnReturnType(); |
| 667 | const ptr_type = try sema.mod.simplePtrType(sema.arena, ret_type, true, .One); | 1113 | const ptr_type = try sema.mod.simplePtrType(sema.arena, ret_type, true, .One); |
| 668 | return block.addNoOp(src, ptr_type, .alloc); | 1114 | return block.addNoOp(src, ptr_type, .alloc); |
| 669 | } | 1115 | } |
| 670 | 1116 | ||
| 671 | fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1117 | fn zirRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 672 | const tracy = trace(@src()); | 1118 | const tracy = trace(@src()); |
| 673 | defer tracy.end(); | 1119 | defer tracy.end(); |
| 674 | 1120 | ||
| ... | @@ -677,18 +1123,22 @@ fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In | ... | @@ -677,18 +1123,22 @@ fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In |
| 677 | return sema.analyzeRef(block, inst_data.src(), operand); | 1123 | return sema.analyzeRef(block, inst_data.src(), operand); |
| 678 | } | 1124 | } |
| 679 | 1125 | ||
| 680 | fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1126 | fn zirRetType( |
| 1127 | sema: *Sema, | ||
| 1128 | block: *Scope.Block, | ||
| 1129 | extended: Zir.Inst.Extended.InstData, | ||
| 1130 | ) InnerError!*Inst { | ||
| 681 | const tracy = trace(@src()); | 1131 | const tracy = trace(@src()); |
| 682 | defer tracy.end(); | 1132 | defer tracy.end(); |
| 683 | 1133 | ||
| 684 | const src: LazySrcLoc = .unneeded; | 1134 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 685 | try sema.requireFunctionBlock(block, src); | 1135 | try sema.requireFunctionBlock(block, src); |
| 686 | const fn_ty = sema.func.?.owner_decl.typed_value.most_recent.typed_value.ty; | 1136 | const fn_ty = sema.func.?.owner_decl.ty; |
| 687 | const ret_type = fn_ty.fnReturnType(); | 1137 | const ret_type = fn_ty.fnReturnType(); |
| 688 | return sema.mod.constType(sema.arena, src, ret_type); | 1138 | return sema.mod.constType(sema.arena, src, ret_type); |
| 689 | } | 1139 | } |
| 690 | 1140 | ||
| 691 | fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1141 | fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 692 | const tracy = trace(@src()); | 1142 | const tracy = trace(@src()); |
| 693 | defer tracy.end(); | 1143 | defer tracy.end(); |
| 694 | 1144 | ||
| ... | @@ -711,7 +1161,7 @@ fn ensureResultUsed( | ... | @@ -711,7 +1161,7 @@ fn ensureResultUsed( |
| 711 | } | 1161 | } |
| 712 | } | 1162 | } |
| 713 | 1163 | ||
| 714 | fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1164 | fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 715 | const tracy = trace(@src()); | 1165 | const tracy = trace(@src()); |
| 716 | defer tracy.end(); | 1166 | defer tracy.end(); |
| 717 | 1167 | ||
| ... | @@ -724,7 +1174,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde | ... | @@ -724,7 +1174,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde |
| 724 | } | 1174 | } |
| 725 | } | 1175 | } |
| 726 | 1176 | ||
| 727 | fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1177 | fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 728 | const tracy = trace(@src()); | 1178 | const tracy = trace(@src()); |
| 729 | defer tracy.end(); | 1179 | defer tracy.end(); |
| 730 | 1180 | ||
| ... | @@ -758,7 +1208,48 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In | ... | @@ -758,7 +1208,48 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In |
| 758 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); | 1208 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); |
| 759 | } | 1209 | } |
| 760 | 1210 | ||
| 761 | fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1211 | fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1212 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | ||
| 1213 | const src = inst_data.src(); | ||
| 1214 | const arg_name = inst_data.get(sema.code); | ||
| 1215 | const arg_index = sema.next_arg_index; | ||
| 1216 | sema.next_arg_index += 1; | ||
| 1217 | |||
| 1218 | // TODO check if arg_name shadows a Decl | ||
| 1219 | |||
| 1220 | if (block.inlining) |inlining| { | ||
| 1221 | return sema.param_inst_list[arg_index]; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | // Need to set the name of the Air.Arg instruction. | ||
| 1225 | const air_arg = sema.param_inst_list[arg_index].castTag(.arg).?; | ||
| 1226 | air_arg.name = arg_name; | ||
| 1227 | return &air_arg.base; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | fn zirAllocExtended( | ||
| 1231 | sema: *Sema, | ||
| 1232 | block: *Scope.Block, | ||
| 1233 | extended: Zir.Inst.Extended.InstData, | ||
| 1234 | ) InnerError!*Inst { | ||
| 1235 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); | ||
| 1236 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; | ||
| 1237 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocExtended", .{}); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1241 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1242 | const src = inst_data.src(); | ||
| 1243 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocComptime", .{}); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1247 | const src_node = sema.code.instructions.items(.data)[inst].node; | ||
| 1248 | const src: LazySrcLoc = .{ .node_offset = src_node }; | ||
| 1249 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocInferredComptime", .{}); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 762 | const tracy = trace(@src()); | 1253 | const tracy = trace(@src()); |
| 763 | defer tracy.end(); | 1254 | defer tracy.end(); |
| 764 | 1255 | ||
| ... | @@ -771,7 +1262,7 @@ fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* | ... | @@ -771,7 +1262,7 @@ fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* |
| 771 | return block.addNoOp(var_decl_src, ptr_type, .alloc); | 1262 | return block.addNoOp(var_decl_src, ptr_type, .alloc); |
| 772 | } | 1263 | } |
| 773 | 1264 | ||
| 774 | fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1265 | fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 775 | const tracy = trace(@src()); | 1266 | const tracy = trace(@src()); |
| 776 | defer tracy.end(); | 1267 | defer tracy.end(); |
| 777 | 1268 | ||
| ... | @@ -788,7 +1279,7 @@ fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -788,7 +1279,7 @@ fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 788 | fn zirAllocInferred( | 1279 | fn zirAllocInferred( |
| 789 | sema: *Sema, | 1280 | sema: *Sema, |
| 790 | block: *Scope.Block, | 1281 | block: *Scope.Block, |
| 791 | inst: zir.Inst.Index, | 1282 | inst: Zir.Inst.Index, |
| 792 | inferred_alloc_ty: Type, | 1283 | inferred_alloc_ty: Type, |
| 793 | ) InnerError!*Inst { | 1284 | ) InnerError!*Inst { |
| 794 | const tracy = trace(@src()); | 1285 | const tracy = trace(@src()); |
| ... | @@ -814,7 +1305,7 @@ fn zirAllocInferred( | ... | @@ -814,7 +1305,7 @@ fn zirAllocInferred( |
| 814 | return result; | 1305 | return result; |
| 815 | } | 1306 | } |
| 816 | 1307 | ||
| 817 | fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1308 | fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 818 | const tracy = trace(@src()); | 1309 | const tracy = trace(@src()); |
| 819 | defer tracy.end(); | 1310 | defer tracy.end(); |
| 820 | 1311 | ||
| ... | @@ -840,7 +1331,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde | ... | @@ -840,7 +1331,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde |
| 840 | ptr.tag = .alloc; | 1331 | ptr.tag = .alloc; |
| 841 | } | 1332 | } |
| 842 | 1333 | ||
| 843 | fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1334 | fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 844 | const tracy = trace(@src()); | 1335 | const tracy = trace(@src()); |
| 845 | defer tracy.end(); | 1336 | defer tracy.end(); |
| 846 | 1337 | ||
| ... | @@ -848,26 +1339,25 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind | ... | @@ -848,26 +1339,25 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind |
| 848 | const mod = sema.mod; | 1339 | const mod = sema.mod; |
| 849 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; | 1340 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; |
| 850 | const struct_init_src = validate_inst.src(); | 1341 | const struct_init_src = validate_inst.src(); |
| 851 | const validate_extra = sema.code.extraData(zir.Inst.Block, validate_inst.payload_index); | 1342 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); |
| 852 | const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; | 1343 | const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; |
| 853 | 1344 | ||
| 854 | const struct_obj: *Module.Struct = s: { | 1345 | const struct_obj: *Module.Struct = s: { |
| 855 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; | 1346 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 856 | const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data; | 1347 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 857 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); | 1348 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); |
| 858 | break :s object_ptr.ty.elemType().castTag(.@"struct").?.data; | 1349 | break :s object_ptr.ty.elemType().castTag(.@"struct").?.data; |
| 859 | }; | 1350 | }; |
| 860 | 1351 | ||
| 861 | // Maps field index to field_ptr index of where it was already initialized. | 1352 | // Maps field index to field_ptr index of where it was already initialized. |
| 862 | const found_fields = try gpa.alloc(zir.Inst.Index, struct_obj.fields.entries.items.len); | 1353 | const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len); |
| 863 | defer gpa.free(found_fields); | 1354 | defer gpa.free(found_fields); |
| 864 | 1355 | mem.set(Zir.Inst.Index, found_fields, 0); | |
| 865 | mem.set(zir.Inst.Index, found_fields, 0); | ||
| 866 | 1356 | ||
| 867 | for (instrs) |field_ptr| { | 1357 | for (instrs) |field_ptr| { |
| 868 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; | 1358 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 869 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node }; | 1359 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node }; |
| 870 | const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data; | 1360 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 871 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | 1361 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); |
| 872 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 1362 | const field_index = struct_obj.fields.getIndex(field_name) orelse |
| 873 | return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name); | 1363 | return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name); |
| ... | @@ -888,11 +1378,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind | ... | @@ -888,11 +1378,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind |
| 888 | 1378 | ||
| 889 | var root_msg: ?*Module.ErrorMsg = null; | 1379 | var root_msg: ?*Module.ErrorMsg = null; |
| 890 | 1380 | ||
| 1381 | // TODO handle default struct field values | ||
| 891 | for (found_fields) |field_ptr, i| { | 1382 | for (found_fields) |field_ptr, i| { |
| 892 | if (field_ptr != 0) continue; | 1383 | if (field_ptr != 0) continue; |
| 893 | 1384 | ||
| 894 | const field_name = struct_obj.fields.entries.items[i].key; | 1385 | const field_name = struct_obj.fields.entries.items[i].key; |
| 895 | const template = "mising struct field: {s}"; | 1386 | const template = "missing struct field: {s}"; |
| 896 | const args = .{field_name}; | 1387 | const args = .{field_name}; |
| 897 | if (root_msg) |msg| { | 1388 | if (root_msg) |msg| { |
| 898 | try mod.errNote(&block.base, struct_init_src, msg, template, args); | 1389 | try mod.errNote(&block.base, struct_init_src, msg, template, args); |
| ... | @@ -913,6 +1404,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind | ... | @@ -913,6 +1404,12 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind |
| 913 | } | 1404 | } |
| 914 | } | 1405 | } |
| 915 | 1406 | ||
| 1407 | fn zirValidateArrayInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { | ||
| 1408 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 1409 | const src = inst_data.src(); | ||
| 1410 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirValidateArrayInitPtr", .{}); | ||
| 1411 | } | ||
| 1412 | |||
| 916 | fn failWithBadFieldAccess( | 1413 | fn failWithBadFieldAccess( |
| 917 | sema: *Sema, | 1414 | sema: *Sema, |
| 918 | block: *Scope.Block, | 1415 | block: *Scope.Block, |
| ... | @@ -940,11 +1437,43 @@ fn failWithBadFieldAccess( | ... | @@ -940,11 +1437,43 @@ fn failWithBadFieldAccess( |
| 940 | return mod.failWithOwnedErrorMsg(&block.base, msg); | 1437 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 941 | } | 1438 | } |
| 942 | 1439 | ||
| 943 | fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1440 | fn failWithBadUnionFieldAccess( |
| 1441 | sema: *Sema, | ||
| 1442 | block: *Scope.Block, | ||
| 1443 | union_obj: *Module.Union, | ||
| 1444 | field_src: LazySrcLoc, | ||
| 1445 | field_name: []const u8, | ||
| 1446 | ) InnerError { | ||
| 1447 | const mod = sema.mod; | ||
| 1448 | const gpa = sema.gpa; | ||
| 1449 | |||
| 1450 | const fqn = try union_obj.getFullyQualifiedName(gpa); | ||
| 1451 | defer gpa.free(fqn); | ||
| 1452 | |||
| 1453 | const msg = msg: { | ||
| 1454 | const msg = try mod.errMsg( | ||
| 1455 | &block.base, | ||
| 1456 | field_src, | ||
| 1457 | "no field named '{s}' in union '{s}'", | ||
| 1458 | .{ field_name, fqn }, | ||
| 1459 | ); | ||
| 1460 | errdefer msg.destroy(gpa); | ||
| 1461 | try mod.errNoteNonLazy(union_obj.srcLoc(), msg, "union declared here", .{}); | ||
| 1462 | break :msg msg; | ||
| 1463 | }; | ||
| 1464 | return mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { | ||
| 944 | const tracy = trace(@src()); | 1468 | const tracy = trace(@src()); |
| 945 | defer tracy.end(); | 1469 | defer tracy.end(); |
| 946 | 1470 | ||
| 947 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; | 1471 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; |
| 1472 | if (bin_inst.lhs == .none) { | ||
| 1473 | // This is an elided instruction, but AstGen was not smart enough | ||
| 1474 | // to omit it. | ||
| 1475 | return; | ||
| 1476 | } | ||
| 948 | const ptr = try sema.resolveInst(bin_inst.lhs); | 1477 | const ptr = try sema.resolveInst(bin_inst.lhs); |
| 949 | const value = try sema.resolveInst(bin_inst.rhs); | 1478 | const value = try sema.resolveInst(bin_inst.rhs); |
| 950 | const ptr_ty = try sema.mod.simplePtrType(sema.arena, value.ty, true, .One); | 1479 | const ptr_ty = try sema.mod.simplePtrType(sema.arena, value.ty, true, .One); |
| ... | @@ -956,7 +1485,7 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In | ... | @@ -956,7 +1485,7 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In |
| 956 | return sema.storePtr(block, src, bitcasted_ptr, value); | 1485 | return sema.storePtr(block, src, bitcasted_ptr, value); |
| 957 | } | 1486 | } |
| 958 | 1487 | ||
| 959 | fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1488 | fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 960 | const tracy = trace(@src()); | 1489 | const tracy = trace(@src()); |
| 961 | defer tracy.end(); | 1490 | defer tracy.end(); |
| 962 | 1491 | ||
| ... | @@ -975,16 +1504,15 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) | ... | @@ -975,16 +1504,15 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) |
| 975 | return sema.storePtr(block, src, bitcasted_ptr, value); | 1504 | return sema.storePtr(block, src, bitcasted_ptr, value); |
| 976 | } | 1505 | } |
| 977 | 1506 | ||
| 978 | fn zirSetEvalBranchQuota(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1507 | fn zirSetEvalBranchQuota(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 979 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 1508 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 980 | const src = inst_data.src(); | 1509 | const src = inst_data.src(); |
| 981 | try sema.requireFunctionBlock(block, src); | ||
| 982 | const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32); | 1510 | const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32); |
| 983 | if (sema.branch_quota < quota) | 1511 | if (sema.branch_quota < quota) |
| 984 | sema.branch_quota = quota; | 1512 | sema.branch_quota = quota; |
| 985 | } | 1513 | } |
| 986 | 1514 | ||
| 987 | fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1515 | fn zirStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 988 | const tracy = trace(@src()); | 1516 | const tracy = trace(@src()); |
| 989 | defer tracy.end(); | 1517 | defer tracy.end(); |
| 990 | 1518 | ||
| ... | @@ -994,19 +1522,19 @@ fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!v | ... | @@ -994,19 +1522,19 @@ fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!v |
| 994 | return sema.storePtr(block, sema.src, ptr, value); | 1522 | return sema.storePtr(block, sema.src, ptr, value); |
| 995 | } | 1523 | } |
| 996 | 1524 | ||
| 997 | fn zirStoreNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1525 | fn zirStoreNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 998 | const tracy = trace(@src()); | 1526 | const tracy = trace(@src()); |
| 999 | defer tracy.end(); | 1527 | defer tracy.end(); |
| 1000 | 1528 | ||
| 1001 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1529 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1002 | const src = inst_data.src(); | 1530 | const src = inst_data.src(); |
| 1003 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 1531 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 1004 | const ptr = try sema.resolveInst(extra.lhs); | 1532 | const ptr = try sema.resolveInst(extra.lhs); |
| 1005 | const value = try sema.resolveInst(extra.rhs); | 1533 | const value = try sema.resolveInst(extra.rhs); |
| 1006 | return sema.storePtr(block, src, ptr, value); | 1534 | return sema.storePtr(block, src, ptr, value); |
| 1007 | } | 1535 | } |
| 1008 | 1536 | ||
| 1009 | fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1537 | fn zirParamType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1010 | const tracy = trace(@src()); | 1538 | const tracy = trace(@src()); |
| 1011 | defer tracy.end(); | 1539 | defer tracy.end(); |
| 1012 | 1540 | ||
| ... | @@ -1042,7 +1570,7 @@ fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -1042,7 +1570,7 @@ fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 1042 | return sema.mod.constType(sema.arena, src, param_type); | 1570 | return sema.mod.constType(sema.arena, src, param_type); |
| 1043 | } | 1571 | } |
| 1044 | 1572 | ||
| 1045 | fn zirStr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1573 | fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1046 | const tracy = trace(@src()); | 1574 | const tracy = trace(@src()); |
| 1047 | defer tracy.end(); | 1575 | defer tracy.end(); |
| 1048 | 1576 | ||
| ... | @@ -1061,14 +1589,16 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In | ... | @@ -1061,14 +1589,16 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In |
| 1061 | const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len); | 1589 | const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len); |
| 1062 | const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes); | 1590 | const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes); |
| 1063 | 1591 | ||
| 1064 | const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{ | 1592 | const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{ |
| 1065 | .ty = decl_ty, | 1593 | .ty = decl_ty, |
| 1066 | .val = decl_val, | 1594 | .val = decl_val, |
| 1067 | }); | 1595 | }); |
| 1596 | errdefer sema.mod.deleteAnonDecl(&block.base, new_decl); | ||
| 1597 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 1068 | return sema.analyzeDeclRef(block, .unneeded, new_decl); | 1598 | return sema.analyzeDeclRef(block, .unneeded, new_decl); |
| 1069 | } | 1599 | } |
| 1070 | 1600 | ||
| 1071 | fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1601 | fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1072 | const tracy = trace(@src()); | 1602 | const tracy = trace(@src()); |
| 1073 | defer tracy.end(); | 1603 | defer tracy.end(); |
| 1074 | 1604 | ||
| ... | @@ -1076,11 +1606,28 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In | ... | @@ -1076,11 +1606,28 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In |
| 1076 | return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int); | 1606 | return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int); |
| 1077 | } | 1607 | } |
| 1078 | 1608 | ||
| 1079 | fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1609 | fn zirIntBig(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1080 | const arena = sema.arena; | 1610 | const tracy = trace(@src()); |
| 1081 | const inst_data = sema.code.instructions.items(.data)[inst].float; | 1611 | defer tracy.end(); |
| 1082 | const src = inst_data.src(); | 1612 | |
| 1083 | const number = inst_data.number; | 1613 | const arena = sema.arena; |
| 1614 | const int = sema.code.instructions.items(.data)[inst].str; | ||
| 1615 | const byte_count = int.len * @sizeOf(std.math.big.Limb); | ||
| 1616 | const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count]; | ||
| 1617 | const limbs = try arena.alloc(std.math.big.Limb, int.len); | ||
| 1618 | mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); | ||
| 1619 | |||
| 1620 | return sema.mod.constInst(arena, .unneeded, .{ | ||
| 1621 | .ty = Type.initTag(.comptime_int), | ||
| 1622 | .val = try Value.Tag.int_big_positive.create(arena, limbs), | ||
| 1623 | }); | ||
| 1624 | } | ||
| 1625 | |||
| 1626 | fn zirFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1627 | const arena = sema.arena; | ||
| 1628 | const inst_data = sema.code.instructions.items(.data)[inst].float; | ||
| 1629 | const src = inst_data.src(); | ||
| 1630 | const number = inst_data.number; | ||
| 1084 | 1631 | ||
| 1085 | return sema.mod.constInst(arena, src, .{ | 1632 | return sema.mod.constInst(arena, src, .{ |
| 1086 | .ty = Type.initTag(.comptime_float), | 1633 | .ty = Type.initTag(.comptime_float), |
| ... | @@ -1088,10 +1635,10 @@ fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* | ... | @@ -1088,10 +1635,10 @@ fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* |
| 1088 | }); | 1635 | }); |
| 1089 | } | 1636 | } |
| 1090 | 1637 | ||
| 1091 | fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1638 | fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1092 | const arena = sema.arena; | 1639 | const arena = sema.arena; |
| 1093 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1640 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1094 | const extra = sema.code.extraData(zir.Inst.Float128, inst_data.payload_index).data; | 1641 | const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; |
| 1095 | const src = inst_data.src(); | 1642 | const src = inst_data.src(); |
| 1096 | const number = extra.get(); | 1643 | const number = extra.get(); |
| 1097 | 1644 | ||
| ... | @@ -1101,7 +1648,7 @@ fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -1101,7 +1648,7 @@ fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 1101 | }); | 1648 | }); |
| 1102 | } | 1649 | } |
| 1103 | 1650 | ||
| 1104 | fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { | 1651 | fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { |
| 1105 | const tracy = trace(@src()); | 1652 | const tracy = trace(@src()); |
| 1106 | defer tracy.end(); | 1653 | defer tracy.end(); |
| 1107 | 1654 | ||
| ... | @@ -1112,20 +1659,25 @@ fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner | ... | @@ -1112,20 +1659,25 @@ fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner |
| 1112 | return sema.mod.fail(&block.base, src, "{s}", .{msg}); | 1659 | return sema.mod.fail(&block.base, src, "{s}", .{msg}); |
| 1113 | } | 1660 | } |
| 1114 | 1661 | ||
| 1115 | fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1662 | fn zirCompileLog( |
| 1663 | sema: *Sema, | ||
| 1664 | block: *Scope.Block, | ||
| 1665 | extended: Zir.Inst.Extended.InstData, | ||
| 1666 | ) InnerError!*Inst { | ||
| 1116 | var managed = sema.mod.compile_log_text.toManaged(sema.gpa); | 1667 | var managed = sema.mod.compile_log_text.toManaged(sema.gpa); |
| 1117 | defer sema.mod.compile_log_text = managed.moveToUnmanaged(); | 1668 | defer sema.mod.compile_log_text = managed.moveToUnmanaged(); |
| 1118 | const writer = managed.writer(); | 1669 | const writer = managed.writer(); |
| 1119 | 1670 | ||
| 1120 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1671 | const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); |
| 1121 | const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index); | 1672 | const src_node = extra.data.src_node; |
| 1122 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | 1673 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 1674 | const args = sema.code.refSlice(extra.end, extended.small); | ||
| 1123 | 1675 | ||
| 1124 | for (args) |arg_ref, i| { | 1676 | for (args) |arg_ref, i| { |
| 1125 | if (i != 0) try writer.print(", ", .{}); | 1677 | if (i != 0) try writer.print(", ", .{}); |
| 1126 | 1678 | ||
| 1127 | const arg = try sema.resolveInst(arg_ref); | 1679 | const arg = try sema.resolveInst(arg_ref); |
| 1128 | if (arg.value()) |val| { | 1680 | if (try sema.resolvePossiblyUndefinedValue(block, src, arg)) |val| { |
| 1129 | try writer.print("@as({}, {})", .{ arg.ty, val }); | 1681 | try writer.print("@as({}, {})", .{ arg.ty, val }); |
| 1130 | } else { | 1682 | } else { |
| 1131 | try writer.print("@as({}, [runtime value])", .{arg.ty}); | 1683 | try writer.print("@as({}, [runtime value])", .{arg.ty}); |
| ... | @@ -1135,11 +1687,15 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1135,11 +1687,15 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1135 | 1687 | ||
| 1136 | const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, sema.owner_decl); | 1688 | const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, sema.owner_decl); |
| 1137 | if (!gop.found_existing) { | 1689 | if (!gop.found_existing) { |
| 1138 | gop.entry.value = inst_data.src().toSrcLoc(&block.base); | 1690 | gop.entry.value = src_node; |
| 1139 | } | 1691 | } |
| 1692 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 1693 | .ty = Type.initTag(.void), | ||
| 1694 | .val = Value.initTag(.void_value), | ||
| 1695 | }); | ||
| 1140 | } | 1696 | } |
| 1141 | 1697 | ||
| 1142 | fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { | 1698 | fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { |
| 1143 | const tracy = trace(@src()); | 1699 | const tracy = trace(@src()); |
| 1144 | defer tracy.end(); | 1700 | defer tracy.end(); |
| 1145 | 1701 | ||
| ... | @@ -1149,16 +1705,23 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError! | ... | @@ -1149,16 +1705,23 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError! |
| 1149 | return always_noreturn; | 1705 | return always_noreturn; |
| 1150 | } | 1706 | } |
| 1151 | 1707 | ||
| 1152 | fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1708 | fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { |
| 1709 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1710 | const src: LazySrcLoc = inst_data.src(); | ||
| 1711 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{}); | ||
| 1712 | //return always_noreturn; | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1153 | const tracy = trace(@src()); | 1716 | const tracy = trace(@src()); |
| 1154 | defer tracy.end(); | 1717 | defer tracy.end(); |
| 1155 | 1718 | ||
| 1156 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1719 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1157 | const src = inst_data.src(); | 1720 | const src = inst_data.src(); |
| 1158 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 1721 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 1159 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 1722 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 1160 | 1723 | ||
| 1161 | // TZIR expects a block outside the loop block too. | 1724 | // AIR expects a block outside the loop block too. |
| 1162 | const block_inst = try sema.arena.create(Inst.Block); | 1725 | const block_inst = try sema.arena.create(Inst.Block); |
| 1163 | block_inst.* = .{ | 1726 | block_inst.* = .{ |
| 1164 | .base = .{ | 1727 | .base = .{ |
| ... | @@ -1169,8 +1732,7 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1169,8 +1732,7 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1169 | .body = undefined, | 1732 | .body = undefined, |
| 1170 | }; | 1733 | }; |
| 1171 | 1734 | ||
| 1172 | var child_block = parent_block.makeSubBlock(); | 1735 | var label: Scope.Block.Label = .{ |
| 1173 | child_block.label = Scope.Block.Label{ | ||
| 1174 | .zir_block = inst, | 1736 | .zir_block = inst, |
| 1175 | .merges = .{ | 1737 | .merges = .{ |
| 1176 | .results = .{}, | 1738 | .results = .{}, |
| ... | @@ -1178,6 +1740,8 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1178,6 +1740,8 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1178 | .block_inst = block_inst, | 1740 | .block_inst = block_inst, |
| 1179 | }, | 1741 | }, |
| 1180 | }; | 1742 | }; |
| 1743 | var child_block = parent_block.makeSubBlock(); | ||
| 1744 | child_block.label = &label; | ||
| 1181 | const merges = &child_block.label.?.merges; | 1745 | const merges = &child_block.label.?.merges; |
| 1182 | 1746 | ||
| 1183 | defer child_block.instructions.deinit(sema.gpa); | 1747 | defer child_block.instructions.deinit(sema.gpa); |
| ... | @@ -1210,13 +1774,29 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1210,13 +1774,29 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1210 | return sema.analyzeBlockBody(parent_block, src, &child_block, merges); | 1774 | return sema.analyzeBlockBody(parent_block, src, &child_block, merges); |
| 1211 | } | 1775 | } |
| 1212 | 1776 | ||
| 1213 | fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 1777 | fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1778 | const tracy = trace(@src()); | ||
| 1779 | defer tracy.end(); | ||
| 1780 | |||
| 1781 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 1782 | const src = inst_data.src(); | ||
| 1783 | |||
| 1784 | return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{}); | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1788 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 1789 | const src = inst_data.src(); | ||
| 1790 | return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirSuspendBlock", .{}); | ||
| 1791 | } | ||
| 1792 | |||
| 1793 | fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1214 | const tracy = trace(@src()); | 1794 | const tracy = trace(@src()); |
| 1215 | defer tracy.end(); | 1795 | defer tracy.end(); |
| 1216 | 1796 | ||
| 1217 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1797 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1218 | const src = inst_data.src(); | 1798 | const src = inst_data.src(); |
| 1219 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 1799 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 1220 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 1800 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 1221 | 1801 | ||
| 1222 | // Reserve space for a Block instruction so that generated Break instructions can | 1802 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | @@ -1232,20 +1812,21 @@ fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inner | ... | @@ -1232,20 +1812,21 @@ fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inner |
| 1232 | .body = undefined, | 1812 | .body = undefined, |
| 1233 | }; | 1813 | }; |
| 1234 | 1814 | ||
| 1815 | var label: Scope.Block.Label = .{ | ||
| 1816 | .zir_block = inst, | ||
| 1817 | .merges = .{ | ||
| 1818 | .results = .{}, | ||
| 1819 | .br_list = .{}, | ||
| 1820 | .block_inst = block_inst, | ||
| 1821 | }, | ||
| 1822 | }; | ||
| 1823 | |||
| 1235 | var child_block: Scope.Block = .{ | 1824 | var child_block: Scope.Block = .{ |
| 1236 | .parent = parent_block, | 1825 | .parent = parent_block, |
| 1237 | .sema = sema, | 1826 | .sema = sema, |
| 1238 | .src_decl = parent_block.src_decl, | 1827 | .src_decl = parent_block.src_decl, |
| 1239 | .instructions = .{}, | 1828 | .instructions = .{}, |
| 1240 | // TODO @as here is working around a stage1 miscompilation bug :( | 1829 | .label = &label, |
| 1241 | .label = @as(?Scope.Block.Label, Scope.Block.Label{ | ||
| 1242 | .zir_block = inst, | ||
| 1243 | .merges = .{ | ||
| 1244 | .results = .{}, | ||
| 1245 | .br_list = .{}, | ||
| 1246 | .block_inst = block_inst, | ||
| 1247 | }, | ||
| 1248 | }), | ||
| 1249 | .inlining = parent_block.inlining, | 1830 | .inlining = parent_block.inlining, |
| 1250 | .is_comptime = parent_block.is_comptime, | 1831 | .is_comptime = parent_block.is_comptime, |
| 1251 | }; | 1832 | }; |
| ... | @@ -1260,6 +1841,18 @@ fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inner | ... | @@ -1260,6 +1841,18 @@ fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inner |
| 1260 | return sema.analyzeBlockBody(parent_block, src, &child_block, merges); | 1841 | return sema.analyzeBlockBody(parent_block, src, &child_block, merges); |
| 1261 | } | 1842 | } |
| 1262 | 1843 | ||
| 1844 | fn resolveBlockBody( | ||
| 1845 | sema: *Sema, | ||
| 1846 | parent_block: *Scope.Block, | ||
| 1847 | src: LazySrcLoc, | ||
| 1848 | child_block: *Scope.Block, | ||
| 1849 | body: []const Zir.Inst.Index, | ||
| 1850 | merges: *Scope.Block.Merges, | ||
| 1851 | ) InnerError!*Inst { | ||
| 1852 | _ = try sema.analyzeBody(child_block, body); | ||
| 1853 | return sema.analyzeBlockBody(parent_block, src, child_block, merges); | ||
| 1854 | } | ||
| 1855 | |||
| 1263 | fn analyzeBlockBody( | 1856 | fn analyzeBlockBody( |
| 1264 | sema: *Sema, | 1857 | sema: *Sema, |
| 1265 | parent_block: *Scope.Block, | 1858 | parent_block: *Scope.Block, |
| ... | @@ -1342,29 +1935,64 @@ fn analyzeBlockBody( | ... | @@ -1342,29 +1935,64 @@ fn analyzeBlockBody( |
| 1342 | return &merges.block_inst.base; | 1935 | return &merges.block_inst.base; |
| 1343 | } | 1936 | } |
| 1344 | 1937 | ||
| 1345 | fn zirExport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1938 | fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 1346 | const tracy = trace(@src()); | 1939 | const tracy = trace(@src()); |
| 1347 | defer tracy.end(); | 1940 | defer tracy.end(); |
| 1348 | 1941 | ||
| 1349 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 1942 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1350 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 1943 | const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; |
| 1351 | const src = inst_data.src(); | 1944 | const src = inst_data.src(); |
| 1352 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 1945 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 1353 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 1946 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 1947 | const decl_name = sema.code.nullTerminatedString(extra.decl_name); | ||
| 1948 | const decl = try sema.lookupIdentifier(block, lhs_src, decl_name); | ||
| 1949 | const options = try sema.resolveInstConst(block, rhs_src, extra.options); | ||
| 1950 | const struct_obj = options.ty.castTag(.@"struct").?.data; | ||
| 1951 | const fields = options.val.castTag(.@"struct").?.data[0..struct_obj.fields.count()]; | ||
| 1952 | const name_index = struct_obj.fields.getIndex("name").?; | ||
| 1953 | const linkage_index = struct_obj.fields.getIndex("linkage").?; | ||
| 1954 | const section_index = struct_obj.fields.getIndex("section").?; | ||
| 1955 | const export_name = try fields[name_index].toAllocatedBytes(sema.arena); | ||
| 1956 | const linkage = fields[linkage_index].toEnum( | ||
| 1957 | struct_obj.fields.items()[linkage_index].value.ty, | ||
| 1958 | std.builtin.GlobalLinkage, | ||
| 1959 | ); | ||
| 1960 | |||
| 1961 | if (linkage != .Strong) { | ||
| 1962 | return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{}); | ||
| 1963 | } | ||
| 1964 | if (!fields[section_index].isNull()) { | ||
| 1965 | return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{}); | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | try sema.mod.analyzeExport(&block.base, src, export_name, decl); | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { | ||
| 1972 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1973 | const src: LazySrcLoc = inst_data.src(); | ||
| 1974 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetAlignStack", .{}); | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { | ||
| 1978 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 1979 | const src: LazySrcLoc = inst_data.src(); | ||
| 1980 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{}); | ||
| 1981 | } | ||
| 1354 | 1982 | ||
| 1355 | // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref` | 1983 | fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 1356 | // instruction, which could reference any decl, which is then supposed to get | 1984 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1357 | // exported, regardless of whether or not it is a function. | 1985 | const src: LazySrcLoc = inst_data.src(); |
| 1358 | const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs); | 1986 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetFloatMode", .{}); |
| 1359 | // TODO (see corresponding TODO in AstGen) this is supposed to be | 1987 | } |
| 1360 | // `std.builtin.ExportOptions`, not a string. | ||
| 1361 | const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs); | ||
| 1362 | 1988 | ||
| 1363 | const actual_fn = target_fn.val.castTag(.function).?.data; | 1989 | fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 1364 | try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl); | 1990 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1991 | const src: LazySrcLoc = inst_data.src(); | ||
| 1992 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetRuntimeSafety", .{}); | ||
| 1365 | } | 1993 | } |
| 1366 | 1994 | ||
| 1367 | fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 1995 | fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 1368 | const tracy = trace(@src()); | 1996 | const tracy = trace(@src()); |
| 1369 | defer tracy.end(); | 1997 | defer tracy.end(); |
| 1370 | 1998 | ||
| ... | @@ -1374,7 +2002,13 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1374,7 +2002,13 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1374 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); | 2002 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); |
| 1375 | } | 2003 | } |
| 1376 | 2004 | ||
| 1377 | fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { | 2005 | fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 2006 | const src_node = sema.code.instructions.items(.data)[inst].node; | ||
| 2007 | const src: LazySrcLoc = .{ .node_offset = src_node }; | ||
| 2008 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{}); | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { | ||
| 1378 | const tracy = trace(@src()); | 2012 | const tracy = trace(@src()); |
| 1379 | defer tracy.end(); | 2013 | defer tracy.end(); |
| 1380 | 2014 | ||
| ... | @@ -1385,7 +2019,7 @@ fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1385,7 +2019,7 @@ fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1385 | 2019 | ||
| 1386 | var block = start_block; | 2020 | var block = start_block; |
| 1387 | while (true) { | 2021 | while (true) { |
| 1388 | if (block.label) |*label| { | 2022 | if (block.label) |label| { |
| 1389 | if (label.zir_block == zir_block) { | 2023 | if (label.zir_block == zir_block) { |
| 1390 | // Here we add a br instruction, but we over-allocate a little bit | 2024 | // Here we add a br instruction, but we over-allocate a little bit |
| 1391 | // (if necessary) to make it possible to convert the instruction into | 2025 | // (if necessary) to make it possible to convert the instruction into |
| ... | @@ -1414,7 +2048,7 @@ fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1414,7 +2048,7 @@ fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1414 | } | 2048 | } |
| 1415 | } | 2049 | } |
| 1416 | 2050 | ||
| 1417 | fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 2051 | fn zirDbgStmt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 1418 | const tracy = trace(@src()); | 2052 | const tracy = trace(@src()); |
| 1419 | defer tracy.end(); | 2053 | defer tracy.end(); |
| 1420 | 2054 | ||
| ... | @@ -1424,47 +2058,70 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1424,47 +2058,70 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1424 | // instructions. | 2058 | // instructions. |
| 1425 | if (block.is_comptime) return; | 2059 | if (block.is_comptime) return; |
| 1426 | 2060 | ||
| 1427 | const src_node = sema.code.instructions.items(.data)[inst].node; | 2061 | const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt; |
| 1428 | const src: LazySrcLoc = .{ .node_offset = src_node }; | 2062 | _ = try block.addDbgStmt(.unneeded, inst_data.line, inst_data.column); |
| 1429 | |||
| 1430 | const src_loc = src.toSrcLoc(&block.base); | ||
| 1431 | const abs_byte_off = try src_loc.byteOffset(); | ||
| 1432 | _ = try block.addDbgStmt(src, abs_byte_off); | ||
| 1433 | } | 2063 | } |
| 1434 | 2064 | ||
| 1435 | fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2065 | fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1436 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2066 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 1437 | const src = inst_data.src(); | 2067 | const src = inst_data.src(); |
| 1438 | const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key; | 2068 | const decl_name = inst_data.get(sema.code); |
| 2069 | const decl = try sema.lookupIdentifier(block, src, decl_name); | ||
| 1439 | return sema.analyzeDeclRef(block, src, decl); | 2070 | return sema.analyzeDeclRef(block, src, decl); |
| 1440 | } | 2071 | } |
| 1441 | 2072 | ||
| 1442 | fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2073 | fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1443 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2074 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 1444 | const src = inst_data.src(); | 2075 | const src = inst_data.src(); |
| 1445 | const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key; | 2076 | const decl_name = inst_data.get(sema.code); |
| 2077 | const decl = try sema.lookupIdentifier(block, src, decl_name); | ||
| 1446 | return sema.analyzeDeclVal(block, src, decl); | 2078 | return sema.analyzeDeclVal(block, src, decl); |
| 1447 | } | 2079 | } |
| 1448 | 2080 | ||
| 1449 | fn zirCallNone( | 2081 | fn lookupIdentifier(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, name: []const u8) !*Decl { |
| 1450 | sema: *Sema, | 2082 | // TODO emit a compile error if more than one decl would be matched. |
| 1451 | block: *Scope.Block, | 2083 | var namespace = sema.namespace; |
| 1452 | inst: zir.Inst.Index, | 2084 | while (true) { |
| 1453 | ensure_result_used: bool, | 2085 | if (try sema.lookupInNamespace(namespace, name)) |decl| { |
| 1454 | ) InnerError!*Inst { | 2086 | return decl; |
| 1455 | const tracy = trace(@src()); | 2087 | } |
| 1456 | defer tracy.end(); | 2088 | namespace = namespace.parent orelse break; |
| 2089 | } | ||
| 2090 | return sema.mod.fail(&block.base, src, "use of undeclared identifier '{s}'", .{name}); | ||
| 2091 | } | ||
| 1457 | 2092 | ||
| 1458 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 2093 | /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but |
| 1459 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; | 2094 | /// only for ones in the specified namespace. |
| 2095 | fn lookupInNamespace( | ||
| 2096 | sema: *Sema, | ||
| 2097 | namespace: *Scope.Namespace, | ||
| 2098 | ident_name: []const u8, | ||
| 2099 | ) InnerError!?*Decl { | ||
| 2100 | const namespace_decl = namespace.getDecl(); | ||
| 2101 | if (namespace_decl.analysis == .file_failure) { | ||
| 2102 | try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl); | ||
| 2103 | return error.AnalysisFail; | ||
| 2104 | } | ||
| 1460 | 2105 | ||
| 1461 | return sema.analyzeCall(block, inst_data.operand, func_src, inst_data.src(), .auto, ensure_result_used, &.{}); | 2106 | // TODO implement usingnamespace |
| 2107 | if (namespace.decls.get(ident_name)) |decl| { | ||
| 2108 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); | ||
| 2109 | return decl; | ||
| 2110 | } | ||
| 2111 | log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ | ||
| 2112 | sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, | ||
| 2113 | }); | ||
| 2114 | // TODO This dependency is too strong. Really, it should only be a dependency | ||
| 2115 | // on the non-existence of `ident_name` in the namespace. We can lessen the number of | ||
| 2116 | // outdated declarations by making this dependency more sophisticated. | ||
| 2117 | try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl); | ||
| 2118 | return null; | ||
| 1462 | } | 2119 | } |
| 1463 | 2120 | ||
| 1464 | fn zirCall( | 2121 | fn zirCall( |
| 1465 | sema: *Sema, | 2122 | sema: *Sema, |
| 1466 | block: *Scope.Block, | 2123 | block: *Scope.Block, |
| 1467 | inst: zir.Inst.Index, | 2124 | inst: Zir.Inst.Index, |
| 1468 | modifier: std.builtin.CallOptions.Modifier, | 2125 | modifier: std.builtin.CallOptions.Modifier, |
| 1469 | ensure_result_used: bool, | 2126 | ensure_result_used: bool, |
| 1470 | ) InnerError!*Inst { | 2127 | ) InnerError!*Inst { |
| ... | @@ -1474,7 +2131,7 @@ fn zirCall( | ... | @@ -1474,7 +2131,7 @@ fn zirCall( |
| 1474 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2131 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1475 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; | 2132 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 1476 | const call_src = inst_data.src(); | 2133 | const call_src = inst_data.src(); |
| 1477 | const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index); | 2134 | const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index); |
| 1478 | const args = sema.code.refSlice(extra.end, extra.data.args_len); | 2135 | const args = sema.code.refSlice(extra.end, extra.data.args_len); |
| 1479 | 2136 | ||
| 1480 | return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args); | 2137 | return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args); |
| ... | @@ -1483,12 +2140,12 @@ fn zirCall( | ... | @@ -1483,12 +2140,12 @@ fn zirCall( |
| 1483 | fn analyzeCall( | 2140 | fn analyzeCall( |
| 1484 | sema: *Sema, | 2141 | sema: *Sema, |
| 1485 | block: *Scope.Block, | 2142 | block: *Scope.Block, |
| 1486 | zir_func: zir.Inst.Ref, | 2143 | zir_func: Zir.Inst.Ref, |
| 1487 | func_src: LazySrcLoc, | 2144 | func_src: LazySrcLoc, |
| 1488 | call_src: LazySrcLoc, | 2145 | call_src: LazySrcLoc, |
| 1489 | modifier: std.builtin.CallOptions.Modifier, | 2146 | modifier: std.builtin.CallOptions.Modifier, |
| 1490 | ensure_result_used: bool, | 2147 | ensure_result_used: bool, |
| 1491 | zir_args: []const zir.Inst.Ref, | 2148 | zir_args: []const Zir.Inst.Ref, |
| 1492 | ) InnerError!*ir.Inst { | 2149 | ) InnerError!*ir.Inst { |
| 1493 | const func = try sema.resolveInst(zir_func); | 2150 | const func = try sema.resolveInst(zir_func); |
| 1494 | 2151 | ||
| ... | @@ -1527,11 +2184,20 @@ fn analyzeCall( | ... | @@ -1527,11 +2184,20 @@ fn analyzeCall( |
| 1527 | ); | 2184 | ); |
| 1528 | } | 2185 | } |
| 1529 | 2186 | ||
| 1530 | if (modifier == .compile_time) { | 2187 | switch (modifier) { |
| 1531 | return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{}); | 2188 | .auto, |
| 1532 | } | 2189 | .always_inline, |
| 1533 | if (modifier != .auto) { | 2190 | .compile_time, |
| 1534 | return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{modifier}); | 2191 | => {}, |
| 2192 | |||
| 2193 | .async_kw, | ||
| 2194 | .never_tail, | ||
| 2195 | .never_inline, | ||
| 2196 | .no_async, | ||
| 2197 | .always_tail, | ||
| 2198 | => return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{ | ||
| 2199 | modifier, | ||
| 2200 | }), | ||
| 1535 | } | 2201 | } |
| 1536 | 2202 | ||
| 1537 | // TODO handle function calls of generic functions | 2203 | // TODO handle function calls of generic functions |
| ... | @@ -1579,24 +2245,38 @@ fn analyzeCall( | ... | @@ -1579,24 +2245,38 @@ fn analyzeCall( |
| 1579 | .block_inst = block_inst, | 2245 | .block_inst = block_inst, |
| 1580 | }, | 2246 | }, |
| 1581 | }; | 2247 | }; |
| 1582 | var inline_sema: Sema = .{ | 2248 | // In order to save a bit of stack space, directly modify Sema rather |
| 1583 | .mod = sema.mod, | 2249 | // than create a child one. |
| 1584 | .gpa = sema.mod.gpa, | 2250 | const parent_zir = sema.code; |
| 1585 | .arena = sema.arena, | 2251 | sema.code = module_fn.owner_decl.namespace.file_scope.zir; |
| 1586 | .code = module_fn.zir, | 2252 | defer sema.code = parent_zir; |
| 1587 | .inst_map = try sema.gpa.alloc(*ir.Inst, module_fn.zir.instructions.len), | 2253 | |
| 1588 | .owner_decl = sema.owner_decl, | 2254 | const parent_inst_map = sema.inst_map; |
| 1589 | .owner_func = sema.owner_func, | 2255 | sema.inst_map = .{}; |
| 1590 | .func = module_fn, | 2256 | defer { |
| 1591 | .param_inst_list = casted_args, | 2257 | sema.inst_map.deinit(sema.gpa); |
| 1592 | .branch_quota = sema.branch_quota, | 2258 | sema.inst_map = parent_inst_map; |
| 1593 | .branch_count = sema.branch_count, | 2259 | } |
| 1594 | }; | 2260 | |
| 1595 | defer sema.gpa.free(inline_sema.inst_map); | 2261 | const parent_namespace = sema.namespace; |
| 2262 | sema.namespace = module_fn.owner_decl.namespace; | ||
| 2263 | defer sema.namespace = parent_namespace; | ||
| 2264 | |||
| 2265 | const parent_func = sema.func; | ||
| 2266 | sema.func = module_fn; | ||
| 2267 | defer sema.func = parent_func; | ||
| 2268 | |||
| 2269 | const parent_param_inst_list = sema.param_inst_list; | ||
| 2270 | sema.param_inst_list = casted_args; | ||
| 2271 | defer sema.param_inst_list = parent_param_inst_list; | ||
| 2272 | |||
| 2273 | const parent_next_arg_index = sema.next_arg_index; | ||
| 2274 | sema.next_arg_index = 0; | ||
| 2275 | defer sema.next_arg_index = parent_next_arg_index; | ||
| 1596 | 2276 | ||
| 1597 | var child_block: Scope.Block = .{ | 2277 | var child_block: Scope.Block = .{ |
| 1598 | .parent = null, | 2278 | .parent = null, |
| 1599 | .sema = &inline_sema, | 2279 | .sema = sema, |
| 1600 | .src_decl = module_fn.owner_decl, | 2280 | .src_decl = module_fn.owner_decl, |
| 1601 | .instructions = .{}, | 2281 | .instructions = .{}, |
| 1602 | .label = null, | 2282 | .label = null, |
| ... | @@ -1610,16 +2290,13 @@ fn analyzeCall( | ... | @@ -1610,16 +2290,13 @@ fn analyzeCall( |
| 1610 | defer merges.results.deinit(sema.gpa); | 2290 | defer merges.results.deinit(sema.gpa); |
| 1611 | defer merges.br_list.deinit(sema.gpa); | 2291 | defer merges.br_list.deinit(sema.gpa); |
| 1612 | 2292 | ||
| 1613 | try inline_sema.emitBackwardBranch(&child_block, call_src); | 2293 | try sema.emitBackwardBranch(&child_block, call_src); |
| 1614 | 2294 | ||
| 1615 | // This will have return instructions analyzed as break instructions to | 2295 | // This will have return instructions analyzed as break instructions to |
| 1616 | // the block_inst above. | 2296 | // the block_inst above. |
| 1617 | _ = try inline_sema.root(&child_block); | 2297 | try sema.analyzeFnBody(&child_block, module_fn.zir_body_inst); |
| 1618 | |||
| 1619 | const result = try inline_sema.analyzeBlockBody(block, call_src, &child_block, merges); | ||
| 1620 | 2298 | ||
| 1621 | sema.branch_quota = inline_sema.branch_quota; | 2299 | const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 1622 | sema.branch_count = inline_sema.branch_count; | ||
| 1623 | 2300 | ||
| 1624 | break :res result; | 2301 | break :res result; |
| 1625 | } else res: { | 2302 | } else res: { |
| ... | @@ -1633,7 +2310,7 @@ fn analyzeCall( | ... | @@ -1633,7 +2310,7 @@ fn analyzeCall( |
| 1633 | return result; | 2310 | return result; |
| 1634 | } | 2311 | } |
| 1635 | 2312 | ||
| 1636 | fn zirIntType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2313 | fn zirIntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1637 | const tracy = trace(@src()); | 2314 | const tracy = trace(@src()); |
| 1638 | defer tracy.end(); | 2315 | defer tracy.end(); |
| 1639 | 2316 | ||
| ... | @@ -1644,7 +2321,7 @@ fn zirIntType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -1644,7 +2321,7 @@ fn zirIntType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 1644 | return sema.mod.constType(sema.arena, src, ty); | 2321 | return sema.mod.constType(sema.arena, src, ty); |
| 1645 | } | 2322 | } |
| 1646 | 2323 | ||
| 1647 | fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2324 | fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1648 | const tracy = trace(@src()); | 2325 | const tracy = trace(@src()); |
| 1649 | defer tracy.end(); | 2326 | defer tracy.end(); |
| 1650 | 2327 | ||
| ... | @@ -1656,19 +2333,30 @@ fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner | ... | @@ -1656,19 +2333,30 @@ fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner |
| 1656 | return sema.mod.constType(sema.arena, src, opt_type); | 2333 | return sema.mod.constType(sema.arena, src, opt_type); |
| 1657 | } | 2334 | } |
| 1658 | 2335 | ||
| 1659 | fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2336 | fn zirElemType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1660 | const tracy = trace(@src()); | ||
| 1661 | defer tracy.end(); | ||
| 1662 | |||
| 1663 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 2337 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1664 | const ptr = try sema.resolveInst(inst_data.operand); | 2338 | const src = inst_data.src(); |
| 1665 | const elem_ty = ptr.ty.elemType(); | 2339 | const array_type = try sema.resolveType(block, src, inst_data.operand); |
| 1666 | const opt_ty = try sema.mod.optionalType(sema.arena, elem_ty); | 2340 | const elem_type = array_type.elemType(); |
| 2341 | return sema.mod.constType(sema.arena, src, elem_type); | ||
| 2342 | } | ||
| 1667 | 2343 | ||
| 1668 | return sema.mod.constType(sema.arena, inst_data.src(), opt_ty); | 2344 | fn zirVectorType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2345 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 2346 | const src = inst_data.src(); | ||
| 2347 | const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | ||
| 2348 | const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | ||
| 2349 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | ||
| 2350 | const len = try sema.resolveAlreadyCoercedInt(block, len_src, extra.lhs, u32); | ||
| 2351 | const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); | ||
| 2352 | const vector_type = try Type.Tag.vector.create(sema.arena, .{ | ||
| 2353 | .len = len, | ||
| 2354 | .elem_type = elem_type, | ||
| 2355 | }); | ||
| 2356 | return sema.mod.constType(sema.arena, src, vector_type); | ||
| 1669 | } | 2357 | } |
| 1670 | 2358 | ||
| 1671 | fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2359 | fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1672 | const tracy = trace(@src()); | 2360 | const tracy = trace(@src()); |
| 1673 | defer tracy.end(); | 2361 | defer tracy.end(); |
| 1674 | 2362 | ||
| ... | @@ -1681,14 +2369,14 @@ fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -1681,14 +2369,14 @@ fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 1681 | return sema.mod.constType(sema.arena, .unneeded, array_ty); | 2369 | return sema.mod.constType(sema.arena, .unneeded, array_ty); |
| 1682 | } | 2370 | } |
| 1683 | 2371 | ||
| 1684 | fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2372 | fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1685 | const tracy = trace(@src()); | 2373 | const tracy = trace(@src()); |
| 1686 | defer tracy.end(); | 2374 | defer tracy.end(); |
| 1687 | 2375 | ||
| 1688 | // TODO these should be lazily evaluated | 2376 | // TODO these should be lazily evaluated |
| 1689 | const inst_data = sema.code.instructions.items(.data)[inst].array_type_sentinel; | 2377 | const inst_data = sema.code.instructions.items(.data)[inst].array_type_sentinel; |
| 1690 | const len = try sema.resolveInstConst(block, .unneeded, inst_data.len); | 2378 | const len = try sema.resolveInstConst(block, .unneeded, inst_data.len); |
| 1691 | const extra = sema.code.extraData(zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; | 2379 | const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; |
| 1692 | const sentinel = try sema.resolveInstConst(block, .unneeded, extra.sentinel); | 2380 | const sentinel = try sema.resolveInstConst(block, .unneeded, extra.sentinel); |
| 1693 | const elem_type = try sema.resolveType(block, .unneeded, extra.elem_type); | 2381 | const elem_type = try sema.resolveType(block, .unneeded, extra.elem_type); |
| 1694 | const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), sentinel.val, elem_type); | 2382 | const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), sentinel.val, elem_type); |
| ... | @@ -1696,12 +2384,25 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) | ... | @@ -1696,12 +2384,25 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) |
| 1696 | return sema.mod.constType(sema.arena, .unneeded, array_ty); | 2384 | return sema.mod.constType(sema.arena, .unneeded, array_ty); |
| 1697 | } | 2385 | } |
| 1698 | 2386 | ||
| 1699 | fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2387 | fn zirAnyframeType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2388 | const tracy = trace(@src()); | ||
| 2389 | defer tracy.end(); | ||
| 2390 | |||
| 2391 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 2392 | const src = inst_data.src(); | ||
| 2393 | const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; | ||
| 2394 | const return_type = try sema.resolveType(block, operand_src, inst_data.operand); | ||
| 2395 | const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type); | ||
| 2396 | |||
| 2397 | return sema.mod.constType(sema.arena, src, anyframe_type); | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 1700 | const tracy = trace(@src()); | 2401 | const tracy = trace(@src()); |
| 1701 | defer tracy.end(); | 2402 | defer tracy.end(); |
| 1702 | 2403 | ||
| 1703 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2404 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1704 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 2405 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 1705 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 2406 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 1706 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 2407 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 1707 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 2408 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| ... | @@ -1717,7 +2418,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inn | ... | @@ -1717,7 +2418,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inn |
| 1717 | return sema.mod.constType(sema.arena, src, err_union_ty); | 2418 | return sema.mod.constType(sema.arena, src, err_union_ty); |
| 1718 | } | 2419 | } |
| 1719 | 2420 | ||
| 1720 | fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2421 | fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1721 | const tracy = trace(@src()); | 2422 | const tracy = trace(@src()); |
| 1722 | defer tracy.end(); | 2423 | defer tracy.end(); |
| 1723 | 2424 | ||
| ... | @@ -1735,7 +2436,7 @@ fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1735,7 +2436,7 @@ fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1735 | }); | 2436 | }); |
| 1736 | } | 2437 | } |
| 1737 | 2438 | ||
| 1738 | fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2439 | fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1739 | const tracy = trace(@src()); | 2440 | const tracy = trace(@src()); |
| 1740 | defer tracy.end(); | 2441 | defer tracy.end(); |
| 1741 | 2442 | ||
| ... | @@ -1744,24 +2445,28 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1744,24 +2445,28 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1744 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 2445 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 1745 | const op = try sema.resolveInst(inst_data.operand); | 2446 | const op = try sema.resolveInst(inst_data.operand); |
| 1746 | const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src); | 2447 | const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src); |
| 2448 | const result_ty = Type.initTag(.u16); | ||
| 1747 | 2449 | ||
| 1748 | if (op_coerced.value()) |val| { | 2450 | if (try sema.resolvePossiblyUndefinedValue(block, src, op_coerced)) |val| { |
| 2451 | if (val.isUndef()) { | ||
| 2452 | return sema.mod.constUndef(sema.arena, src, result_ty); | ||
| 2453 | } | ||
| 1749 | const payload = try sema.arena.create(Value.Payload.U64); | 2454 | const payload = try sema.arena.create(Value.Payload.U64); |
| 1750 | payload.* = .{ | 2455 | payload.* = .{ |
| 1751 | .base = .{ .tag = .int_u64 }, | 2456 | .base = .{ .tag = .int_u64 }, |
| 1752 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, | 2457 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, |
| 1753 | }; | 2458 | }; |
| 1754 | return sema.mod.constInst(sema.arena, src, .{ | 2459 | return sema.mod.constInst(sema.arena, src, .{ |
| 1755 | .ty = Type.initTag(.u16), | 2460 | .ty = result_ty, |
| 1756 | .val = Value.initPayload(&payload.base), | 2461 | .val = Value.initPayload(&payload.base), |
| 1757 | }); | 2462 | }); |
| 1758 | } | 2463 | } |
| 1759 | 2464 | ||
| 1760 | try sema.requireRuntimeBlock(block, src); | 2465 | try sema.requireRuntimeBlock(block, src); |
| 1761 | return block.addUnOp(src, Type.initTag(.u16), .error_to_int, op_coerced); | 2466 | return block.addUnOp(src, result_ty, .error_to_int, op_coerced); |
| 1762 | } | 2467 | } |
| 1763 | 2468 | ||
| 1764 | fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2469 | fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1765 | const tracy = trace(@src()); | 2470 | const tracy = trace(@src()); |
| 1766 | defer tracy.end(); | 2471 | defer tracy.end(); |
| 1767 | 2472 | ||
| ... | @@ -1794,12 +2499,12 @@ fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -1794,12 +2499,12 @@ fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 1794 | return block.addUnOp(src, Type.initTag(.anyerror), .int_to_error, op); | 2499 | return block.addUnOp(src, Type.initTag(.anyerror), .int_to_error, op); |
| 1795 | } | 2500 | } |
| 1796 | 2501 | ||
| 1797 | fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2502 | fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1798 | const tracy = trace(@src()); | 2503 | const tracy = trace(@src()); |
| 1799 | defer tracy.end(); | 2504 | defer tracy.end(); |
| 1800 | 2505 | ||
| 1801 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2506 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1802 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 2507 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 1803 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 2508 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 1804 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 2509 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 1805 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 2510 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| ... | @@ -1873,7 +2578,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inn | ... | @@ -1873,7 +2578,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inn |
| 1873 | }); | 2578 | }); |
| 1874 | } | 2579 | } |
| 1875 | 2580 | ||
| 1876 | fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2581 | fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1877 | const tracy = trace(@src()); | 2582 | const tracy = trace(@src()); |
| 1878 | defer tracy.end(); | 2583 | defer tracy.end(); |
| 1879 | 2584 | ||
| ... | @@ -1886,20 +2591,7 @@ fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -1886,20 +2591,7 @@ fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1886 | }); | 2591 | }); |
| 1887 | } | 2592 | } |
| 1888 | 2593 | ||
| 1889 | fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2594 | fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1890 | const tracy = trace(@src()); | ||
| 1891 | defer tracy.end(); | ||
| 1892 | |||
| 1893 | const name = sema.code.instructions.items(.data)[inst].small_str.get(); | ||
| 1894 | const src: LazySrcLoc = .unneeded; | ||
| 1895 | const duped_name = try sema.arena.dupe(u8, name); | ||
| 1896 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 1897 | .ty = Type.initTag(.enum_literal), | ||
| 1898 | .val = try Value.Tag.enum_literal.create(sema.arena, duped_name), | ||
| 1899 | }); | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | ||
| 1903 | const mod = sema.mod; | 2595 | const mod = sema.mod; |
| 1904 | const arena = sema.arena; | 2596 | const arena = sema.arena; |
| 1905 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 2597 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| ... | @@ -1930,7 +2622,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -1930,7 +2622,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 1930 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 2622 | var int_tag_type_buffer: Type.Payload.Bits = undefined; |
| 1931 | const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena); | 2623 | const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena); |
| 1932 | 2624 | ||
| 1933 | if (enum_tag.ty.onePossibleValue()) |opv| { | 2625 | if (try sema.typeHasOnePossibleValue(block, src, enum_tag.ty)) |opv| { |
| 1934 | return mod.constInst(arena, src, .{ | 2626 | return mod.constInst(arena, src, .{ |
| 1935 | .ty = int_tag_ty, | 2627 | .ty = int_tag_ty, |
| 1936 | .val = opv, | 2628 | .val = opv, |
| ... | @@ -1981,12 +2673,12 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -1981,12 +2673,12 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 1981 | return block.addUnOp(src, int_tag_ty, .bitcast, enum_tag); | 2673 | return block.addUnOp(src, int_tag_ty, .bitcast, enum_tag); |
| 1982 | } | 2674 | } |
| 1983 | 2675 | ||
| 1984 | fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2676 | fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 1985 | const mod = sema.mod; | 2677 | const mod = sema.mod; |
| 1986 | const target = mod.getTarget(); | 2678 | const target = mod.getTarget(); |
| 1987 | const arena = sema.arena; | 2679 | const arena = sema.arena; |
| 1988 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2680 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1989 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 2681 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 1990 | const src = inst_data.src(); | 2682 | const src = inst_data.src(); |
| 1991 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 2683 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 1992 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 2684 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| ... | @@ -2040,7 +2732,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -2040,7 +2732,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 2040 | fn zirOptionalPayloadPtr( | 2732 | fn zirOptionalPayloadPtr( |
| 2041 | sema: *Sema, | 2733 | sema: *Sema, |
| 2042 | block: *Scope.Block, | 2734 | block: *Scope.Block, |
| 2043 | inst: zir.Inst.Index, | 2735 | inst: Zir.Inst.Index, |
| 2044 | safety_check: bool, | 2736 | safety_check: bool, |
| 2045 | ) InnerError!*Inst { | 2737 | ) InnerError!*Inst { |
| 2046 | const tracy = trace(@src()); | 2738 | const tracy = trace(@src()); |
| ... | @@ -2083,7 +2775,7 @@ fn zirOptionalPayloadPtr( | ... | @@ -2083,7 +2775,7 @@ fn zirOptionalPayloadPtr( |
| 2083 | fn zirOptionalPayload( | 2775 | fn zirOptionalPayload( |
| 2084 | sema: *Sema, | 2776 | sema: *Sema, |
| 2085 | block: *Scope.Block, | 2777 | block: *Scope.Block, |
| 2086 | inst: zir.Inst.Index, | 2778 | inst: Zir.Inst.Index, |
| 2087 | safety_check: bool, | 2779 | safety_check: bool, |
| 2088 | ) InnerError!*Inst { | 2780 | ) InnerError!*Inst { |
| 2089 | const tracy = trace(@src()); | 2781 | const tracy = trace(@src()); |
| ... | @@ -2121,7 +2813,7 @@ fn zirOptionalPayload( | ... | @@ -2121,7 +2813,7 @@ fn zirOptionalPayload( |
| 2121 | fn zirErrUnionPayload( | 2813 | fn zirErrUnionPayload( |
| 2122 | sema: *Sema, | 2814 | sema: *Sema, |
| 2123 | block: *Scope.Block, | 2815 | block: *Scope.Block, |
| 2124 | inst: zir.Inst.Index, | 2816 | inst: Zir.Inst.Index, |
| 2125 | safety_check: bool, | 2817 | safety_check: bool, |
| 2126 | ) InnerError!*Inst { | 2818 | ) InnerError!*Inst { |
| 2127 | const tracy = trace(@src()); | 2819 | const tracy = trace(@src()); |
| ... | @@ -2155,7 +2847,7 @@ fn zirErrUnionPayload( | ... | @@ -2155,7 +2847,7 @@ fn zirErrUnionPayload( |
| 2155 | fn zirErrUnionPayloadPtr( | 2847 | fn zirErrUnionPayloadPtr( |
| 2156 | sema: *Sema, | 2848 | sema: *Sema, |
| 2157 | block: *Scope.Block, | 2849 | block: *Scope.Block, |
| 2158 | inst: zir.Inst.Index, | 2850 | inst: Zir.Inst.Index, |
| 2159 | safety_check: bool, | 2851 | safety_check: bool, |
| 2160 | ) InnerError!*Inst { | 2852 | ) InnerError!*Inst { |
| 2161 | const tracy = trace(@src()); | 2853 | const tracy = trace(@src()); |
| ... | @@ -2196,7 +2888,7 @@ fn zirErrUnionPayloadPtr( | ... | @@ -2196,7 +2888,7 @@ fn zirErrUnionPayloadPtr( |
| 2196 | } | 2888 | } |
| 2197 | 2889 | ||
| 2198 | /// Value in, value out | 2890 | /// Value in, value out |
| 2199 | fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2891 | fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2200 | const tracy = trace(@src()); | 2892 | const tracy = trace(@src()); |
| 2201 | defer tracy.end(); | 2893 | defer tracy.end(); |
| 2202 | 2894 | ||
| ... | @@ -2220,7 +2912,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner | ... | @@ -2220,7 +2912,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner |
| 2220 | } | 2912 | } |
| 2221 | 2913 | ||
| 2222 | /// Pointer in, value out | 2914 | /// Pointer in, value out |
| 2223 | fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 2915 | fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2224 | const tracy = trace(@src()); | 2916 | const tracy = trace(@src()); |
| 2225 | defer tracy.end(); | 2917 | defer tracy.end(); |
| 2226 | 2918 | ||
| ... | @@ -2246,7 +2938,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In | ... | @@ -2246,7 +2938,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In |
| 2246 | return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand); | 2938 | return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand); |
| 2247 | } | 2939 | } |
| 2248 | 2940 | ||
| 2249 | fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void { | 2941 | fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { |
| 2250 | const tracy = trace(@src()); | 2942 | const tracy = trace(@src()); |
| 2251 | defer tracy.end(); | 2943 | defer tracy.end(); |
| 2252 | 2944 | ||
| ... | @@ -2260,102 +2952,190 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde | ... | @@ -2260,102 +2952,190 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde |
| 2260 | } | 2952 | } |
| 2261 | } | 2953 | } |
| 2262 | 2954 | ||
| 2263 | fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst { | 2955 | fn zirFunc( |
| 2956 | sema: *Sema, | ||
| 2957 | block: *Scope.Block, | ||
| 2958 | inst: Zir.Inst.Index, | ||
| 2959 | inferred_error_set: bool, | ||
| 2960 | ) InnerError!*Inst { | ||
| 2264 | const tracy = trace(@src()); | 2961 | const tracy = trace(@src()); |
| 2265 | defer tracy.end(); | 2962 | defer tracy.end(); |
| 2266 | 2963 | ||
| 2267 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2964 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2268 | const src = inst_data.src(); | 2965 | const src = inst_data.src(); |
| 2269 | const extra = sema.code.extraData(zir.Inst.FnType, inst_data.payload_index); | 2966 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); |
| 2270 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); | 2967 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); |
| 2271 | 2968 | ||
| 2272 | return sema.fnTypeCommon( | 2969 | var body_inst: Zir.Inst.Index = 0; |
| 2273 | block, | 2970 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; |
| 2274 | inst_data.src_node, | 2971 | if (extra.data.body_len != 0) { |
| 2275 | param_types, | 2972 | body_inst = inst; |
| 2276 | extra.data.return_type, | 2973 | const extra_index = extra.end + extra.data.param_types_len + extra.data.body_len; |
| 2277 | .Unspecified, | 2974 | src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; |
| 2278 | var_args, | 2975 | } |
| 2279 | ); | ||
| 2280 | } | ||
| 2281 | |||
| 2282 | fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst { | ||
| 2283 | const tracy = trace(@src()); | ||
| 2284 | defer tracy.end(); | ||
| 2285 | 2976 | ||
| 2286 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2977 | const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported) |
| 2287 | const src = inst_data.src(); | 2978 | .C |
| 2288 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node }; | 2979 | else |
| 2289 | const extra = sema.code.extraData(zir.Inst.FnTypeCc, inst_data.payload_index); | 2980 | .Unspecified; |
| 2290 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); | ||
| 2291 | 2981 | ||
| 2292 | const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc); | 2982 | return sema.funcCommon( |
| 2293 | // TODO once we're capable of importing and analyzing decls from | ||
| 2294 | // std.builtin, this needs to change | ||
| 2295 | const cc_str = cc_tv.val.castTag(.enum_literal).?.data; | ||
| 2296 | const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse | ||
| 2297 | return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str}); | ||
| 2298 | return sema.fnTypeCommon( | ||
| 2299 | block, | 2983 | block, |
| 2300 | inst_data.src_node, | 2984 | inst_data.src_node, |
| 2301 | param_types, | 2985 | param_types, |
| 2986 | body_inst, | ||
| 2302 | extra.data.return_type, | 2987 | extra.data.return_type, |
| 2303 | cc, | 2988 | cc, |
| 2304 | var_args, | 2989 | Value.initTag(.null_value), |
| 2990 | false, | ||
| 2991 | inferred_error_set, | ||
| 2992 | false, | ||
| 2993 | src_locs, | ||
| 2994 | null, | ||
| 2305 | ); | 2995 | ); |
| 2306 | } | 2996 | } |
| 2307 | 2997 | ||
| 2308 | fn fnTypeCommon( | 2998 | fn funcCommon( |
| 2309 | sema: *Sema, | 2999 | sema: *Sema, |
| 2310 | block: *Scope.Block, | 3000 | block: *Scope.Block, |
| 2311 | src_node_offset: i32, | 3001 | src_node_offset: i32, |
| 2312 | zir_param_types: []const zir.Inst.Ref, | 3002 | zir_param_types: []const Zir.Inst.Ref, |
| 2313 | zir_return_type: zir.Inst.Ref, | 3003 | body_inst: Zir.Inst.Index, |
| 3004 | zir_return_type: Zir.Inst.Ref, | ||
| 2314 | cc: std.builtin.CallingConvention, | 3005 | cc: std.builtin.CallingConvention, |
| 3006 | align_val: Value, | ||
| 2315 | var_args: bool, | 3007 | var_args: bool, |
| 3008 | inferred_error_set: bool, | ||
| 3009 | is_extern: bool, | ||
| 3010 | src_locs: Zir.Inst.Func.SrcLocs, | ||
| 3011 | opt_lib_name: ?[]const u8, | ||
| 2316 | ) InnerError!*Inst { | 3012 | ) InnerError!*Inst { |
| 2317 | const src: LazySrcLoc = .{ .node_offset = src_node_offset }; | 3013 | const src: LazySrcLoc = .{ .node_offset = src_node_offset }; |
| 2318 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; | 3014 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| 2319 | const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type); | 3015 | const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type); |
| 2320 | 3016 | ||
| 2321 | // Hot path for some common function types. | 3017 | const mod = sema.mod; |
| 2322 | if (zir_param_types.len == 0 and !var_args) { | 3018 | |
| 2323 | if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { | 3019 | const fn_ty: Type = fn_ty: { |
| 2324 | return sema.mod.constType(sema.arena, src, Type.initTag(.fn_noreturn_no_args)); | 3020 | // Hot path for some common function types. |
| 3021 | if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) { | ||
| 3022 | if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { | ||
| 3023 | break :fn_ty Type.initTag(.fn_noreturn_no_args); | ||
| 3024 | } | ||
| 3025 | |||
| 3026 | if (return_type.zigTypeTag() == .Void and cc == .Unspecified) { | ||
| 3027 | break :fn_ty Type.initTag(.fn_void_no_args); | ||
| 3028 | } | ||
| 3029 | |||
| 3030 | if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) { | ||
| 3031 | break :fn_ty Type.initTag(.fn_naked_noreturn_no_args); | ||
| 3032 | } | ||
| 3033 | |||
| 3034 | if (return_type.zigTypeTag() == .Void and cc == .C) { | ||
| 3035 | break :fn_ty Type.initTag(.fn_ccc_void_no_args); | ||
| 3036 | } | ||
| 2325 | } | 3037 | } |
| 2326 | 3038 | ||
| 2327 | if (return_type.zigTypeTag() == .Void and cc == .Unspecified) { | 3039 | const param_types = try sema.arena.alloc(Type, zir_param_types.len); |
| 2328 | return sema.mod.constType(sema.arena, src, Type.initTag(.fn_void_no_args)); | 3040 | for (zir_param_types) |param_type, i| { |
| 3041 | // TODO make a compile error from `resolveType` report the source location | ||
| 3042 | // of the specific parameter. Will need to take a similar strategy as | ||
| 3043 | // `resolveSwitchItemVal` to avoid resolving the source location unless | ||
| 3044 | // we actually need to report an error. | ||
| 3045 | param_types[i] = try sema.resolveType(block, src, param_type); | ||
| 2329 | } | 3046 | } |
| 2330 | 3047 | ||
| 2331 | if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) { | 3048 | if (align_val.tag() != .null_value) { |
| 2332 | return sema.mod.constType(sema.arena, src, Type.initTag(.fn_naked_noreturn_no_args)); | 3049 | return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{}); |
| 2333 | } | 3050 | } |
| 2334 | 3051 | ||
| 2335 | if (return_type.zigTypeTag() == .Void and cc == .C) { | 3052 | break :fn_ty try Type.Tag.function.create(sema.arena, .{ |
| 2336 | return sema.mod.constType(sema.arena, src, Type.initTag(.fn_ccc_void_no_args)); | 3053 | .param_types = param_types, |
| 3054 | .return_type = return_type, | ||
| 3055 | .cc = cc, | ||
| 3056 | .is_var_args = var_args, | ||
| 3057 | }); | ||
| 3058 | }; | ||
| 3059 | |||
| 3060 | if (opt_lib_name) |lib_name| blk: { | ||
| 3061 | const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset }; | ||
| 3062 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); | ||
| 3063 | mod.comp.stage1AddLinkLib(lib_name) catch |err| { | ||
| 3064 | return mod.fail(&block.base, lib_name_src, "unable to add link lib '{s}': {s}", .{ | ||
| 3065 | lib_name, @errorName(err), | ||
| 3066 | }); | ||
| 3067 | }; | ||
| 3068 | const target = mod.getTarget(); | ||
| 3069 | if (target_util.is_libc_lib_name(target, lib_name)) { | ||
| 3070 | if (!mod.comp.bin_file.options.link_libc) { | ||
| 3071 | return mod.fail( | ||
| 3072 | &block.base, | ||
| 3073 | lib_name_src, | ||
| 3074 | "dependency on libc must be explicitly specified in the build command", | ||
| 3075 | .{}, | ||
| 3076 | ); | ||
| 3077 | } | ||
| 3078 | break :blk; | ||
| 3079 | } | ||
| 3080 | if (target_util.is_libcpp_lib_name(target, lib_name)) { | ||
| 3081 | if (!mod.comp.bin_file.options.link_libcpp) { | ||
| 3082 | return mod.fail( | ||
| 3083 | &block.base, | ||
| 3084 | lib_name_src, | ||
| 3085 | "dependency on libc++ must be explicitly specified in the build command", | ||
| 3086 | .{}, | ||
| 3087 | ); | ||
| 3088 | } | ||
| 3089 | break :blk; | ||
| 3090 | } | ||
| 3091 | if (!target.isWasm() and !mod.comp.bin_file.options.pic) { | ||
| 3092 | return mod.fail( | ||
| 3093 | &block.base, | ||
| 3094 | lib_name_src, | ||
| 3095 | "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", | ||
| 3096 | .{ lib_name, lib_name }, | ||
| 3097 | ); | ||
| 2337 | } | 3098 | } |
| 2338 | } | 3099 | } |
| 2339 | 3100 | ||
| 2340 | const param_types = try sema.arena.alloc(Type, zir_param_types.len); | 3101 | if (is_extern) { |
| 2341 | for (zir_param_types) |param_type, i| { | 3102 | return sema.mod.constInst(sema.arena, src, .{ |
| 2342 | // TODO make a compile error from `resolveType` report the source location | 3103 | .ty = fn_ty, |
| 2343 | // of the specific parameter. Will need to take a similar strategy as | 3104 | .val = try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl), |
| 2344 | // `resolveSwitchItemVal` to avoid resolving the source location unless | 3105 | }); |
| 2345 | // we actually need to report an error. | 3106 | } |
| 2346 | param_types[i] = try sema.resolveType(block, src, param_type); | 3107 | |
| 3108 | if (body_inst == 0) { | ||
| 3109 | return mod.constType(sema.arena, src, fn_ty); | ||
| 2347 | } | 3110 | } |
| 2348 | 3111 | ||
| 2349 | const fn_ty = try Type.Tag.function.create(sema.arena, .{ | 3112 | const is_inline = fn_ty.fnCallingConvention() == .Inline; |
| 2350 | .param_types = param_types, | 3113 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued; |
| 2351 | .return_type = return_type, | 3114 | |
| 2352 | .cc = cc, | 3115 | const fn_payload = try sema.arena.create(Value.Payload.Function); |
| 2353 | .is_var_args = var_args, | 3116 | const new_func = try sema.gpa.create(Module.Fn); |
| 3117 | new_func.* = .{ | ||
| 3118 | .state = anal_state, | ||
| 3119 | .zir_body_inst = body_inst, | ||
| 3120 | .owner_decl = sema.owner_decl, | ||
| 3121 | .body = undefined, | ||
| 3122 | .lbrace_line = src_locs.lbrace_line, | ||
| 3123 | .rbrace_line = src_locs.rbrace_line, | ||
| 3124 | .lbrace_column = @truncate(u16, src_locs.columns), | ||
| 3125 | .rbrace_column = @truncate(u16, src_locs.columns >> 16), | ||
| 3126 | }; | ||
| 3127 | fn_payload.* = .{ | ||
| 3128 | .base = .{ .tag = .function }, | ||
| 3129 | .data = new_func, | ||
| 3130 | }; | ||
| 3131 | const result = try sema.mod.constInst(sema.arena, src, .{ | ||
| 3132 | .ty = fn_ty, | ||
| 3133 | .val = Value.initPayload(&fn_payload.base), | ||
| 2354 | }); | 3134 | }); |
| 2355 | return sema.mod.constType(sema.arena, src, fn_ty); | 3135 | return result; |
| 2356 | } | 3136 | } |
| 2357 | 3137 | ||
| 2358 | fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3138 | fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2359 | const tracy = trace(@src()); | 3139 | const tracy = trace(@src()); |
| 2360 | defer tracy.end(); | 3140 | defer tracy.end(); |
| 2361 | 3141 | ||
| ... | @@ -2363,13 +3143,13 @@ fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Ins | ... | @@ -2363,13 +3143,13 @@ fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Ins |
| 2363 | return sema.analyzeAs(block, .unneeded, bin_inst.lhs, bin_inst.rhs); | 3143 | return sema.analyzeAs(block, .unneeded, bin_inst.lhs, bin_inst.rhs); |
| 2364 | } | 3144 | } |
| 2365 | 3145 | ||
| 2366 | fn zirAsNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3146 | fn zirAsNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2367 | const tracy = trace(@src()); | 3147 | const tracy = trace(@src()); |
| 2368 | defer tracy.end(); | 3148 | defer tracy.end(); |
| 2369 | 3149 | ||
| 2370 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3150 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2371 | const src = inst_data.src(); | 3151 | const src = inst_data.src(); |
| 2372 | const extra = sema.code.extraData(zir.Inst.As, inst_data.payload_index).data; | 3152 | const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; |
| 2373 | return sema.analyzeAs(block, src, extra.dest_type, extra.operand); | 3153 | return sema.analyzeAs(block, src, extra.dest_type, extra.operand); |
| 2374 | } | 3154 | } |
| 2375 | 3155 | ||
| ... | @@ -2377,15 +3157,15 @@ fn analyzeAs( | ... | @@ -2377,15 +3157,15 @@ fn analyzeAs( |
| 2377 | sema: *Sema, | 3157 | sema: *Sema, |
| 2378 | block: *Scope.Block, | 3158 | block: *Scope.Block, |
| 2379 | src: LazySrcLoc, | 3159 | src: LazySrcLoc, |
| 2380 | zir_dest_type: zir.Inst.Ref, | 3160 | zir_dest_type: Zir.Inst.Ref, |
| 2381 | zir_operand: zir.Inst.Ref, | 3161 | zir_operand: Zir.Inst.Ref, |
| 2382 | ) InnerError!*Inst { | 3162 | ) InnerError!*Inst { |
| 2383 | const dest_type = try sema.resolveType(block, src, zir_dest_type); | 3163 | const dest_type = try sema.resolveType(block, src, zir_dest_type); |
| 2384 | const operand = try sema.resolveInst(zir_operand); | 3164 | const operand = try sema.resolveInst(zir_operand); |
| 2385 | return sema.coerce(block, dest_type, operand, src); | 3165 | return sema.coerce(block, dest_type, operand, src); |
| 2386 | } | 3166 | } |
| 2387 | 3167 | ||
| 2388 | fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3168 | fn zirPtrToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2389 | const tracy = trace(@src()); | 3169 | const tracy = trace(@src()); |
| 2390 | defer tracy.end(); | 3170 | defer tracy.end(); |
| 2391 | 3171 | ||
| ... | @@ -2402,14 +3182,14 @@ fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -2402,14 +3182,14 @@ fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 2402 | return block.addUnOp(src, ty, .ptrtoint, ptr); | 3182 | return block.addUnOp(src, ty, .ptrtoint, ptr); |
| 2403 | } | 3183 | } |
| 2404 | 3184 | ||
| 2405 | fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3185 | fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2406 | const tracy = trace(@src()); | 3186 | const tracy = trace(@src()); |
| 2407 | defer tracy.end(); | 3187 | defer tracy.end(); |
| 2408 | 3188 | ||
| 2409 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3189 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2410 | const src = inst_data.src(); | 3190 | const src = inst_data.src(); |
| 2411 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 3191 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 2412 | const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data; | 3192 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 2413 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 3193 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 2414 | const object = try sema.resolveInst(extra.lhs); | 3194 | const object = try sema.resolveInst(extra.lhs); |
| 2415 | const object_ptr = if (object.ty.zigTypeTag() == .Pointer) | 3195 | const object_ptr = if (object.ty.zigTypeTag() == .Pointer) |
| ... | @@ -2420,27 +3200,27 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -2420,27 +3200,27 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 2420 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); | 3200 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); |
| 2421 | } | 3201 | } |
| 2422 | 3202 | ||
| 2423 | fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3203 | fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2424 | const tracy = trace(@src()); | 3204 | const tracy = trace(@src()); |
| 2425 | defer tracy.end(); | 3205 | defer tracy.end(); |
| 2426 | 3206 | ||
| 2427 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3207 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2428 | const src = inst_data.src(); | 3208 | const src = inst_data.src(); |
| 2429 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 3209 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 2430 | const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data; | 3210 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 2431 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 3211 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 2432 | const object_ptr = try sema.resolveInst(extra.lhs); | 3212 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 2433 | return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src); | 3213 | return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src); |
| 2434 | } | 3214 | } |
| 2435 | 3215 | ||
| 2436 | fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3216 | fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2437 | const tracy = trace(@src()); | 3217 | const tracy = trace(@src()); |
| 2438 | defer tracy.end(); | 3218 | defer tracy.end(); |
| 2439 | 3219 | ||
| 2440 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3220 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2441 | const src = inst_data.src(); | 3221 | const src = inst_data.src(); |
| 2442 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 3222 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 2443 | const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data; | 3223 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 2444 | const object = try sema.resolveInst(extra.lhs); | 3224 | const object = try sema.resolveInst(extra.lhs); |
| 2445 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name); | 3225 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name); |
| 2446 | const object_ptr = try sema.analyzeRef(block, src, object); | 3226 | const object_ptr = try sema.analyzeRef(block, src, object); |
| ... | @@ -2448,20 +3228,20 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne | ... | @@ -2448,20 +3228,20 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne |
| 2448 | return sema.analyzeLoad(block, src, result_ptr, src); | 3228 | return sema.analyzeLoad(block, src, result_ptr, src); |
| 2449 | } | 3229 | } |
| 2450 | 3230 | ||
| 2451 | fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3231 | fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2452 | const tracy = trace(@src()); | 3232 | const tracy = trace(@src()); |
| 2453 | defer tracy.end(); | 3233 | defer tracy.end(); |
| 2454 | 3234 | ||
| 2455 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3235 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2456 | const src = inst_data.src(); | 3236 | const src = inst_data.src(); |
| 2457 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 3237 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 2458 | const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data; | 3238 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 2459 | const object_ptr = try sema.resolveInst(extra.lhs); | 3239 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 2460 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name); | 3240 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name); |
| 2461 | return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src); | 3241 | return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src); |
| 2462 | } | 3242 | } |
| 2463 | 3243 | ||
| 2464 | fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3244 | fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2465 | const tracy = trace(@src()); | 3245 | const tracy = trace(@src()); |
| 2466 | defer tracy.end(); | 3246 | defer tracy.end(); |
| 2467 | 3247 | ||
| ... | @@ -2469,7 +3249,7 @@ fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -2469,7 +3249,7 @@ fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 2469 | const src = inst_data.src(); | 3249 | const src = inst_data.src(); |
| 2470 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 3250 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 2471 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 3251 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 2472 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 3252 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2473 | 3253 | ||
| 2474 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); | 3254 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 2475 | const operand = try sema.resolveInst(extra.rhs); | 3255 | const operand = try sema.resolveInst(extra.rhs); |
| ... | @@ -2504,7 +3284,7 @@ fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -2504,7 +3284,7 @@ fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 2504 | return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten int", .{}); | 3284 | return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten int", .{}); |
| 2505 | } | 3285 | } |
| 2506 | 3286 | ||
| 2507 | fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3287 | fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2508 | const tracy = trace(@src()); | 3288 | const tracy = trace(@src()); |
| 2509 | defer tracy.end(); | 3289 | defer tracy.end(); |
| 2510 | 3290 | ||
| ... | @@ -2512,14 +3292,14 @@ fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -2512,14 +3292,14 @@ fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 2512 | const src = inst_data.src(); | 3292 | const src = inst_data.src(); |
| 2513 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 3293 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 2514 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 3294 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 2515 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 3295 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2516 | 3296 | ||
| 2517 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); | 3297 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 2518 | const operand = try sema.resolveInst(extra.rhs); | 3298 | const operand = try sema.resolveInst(extra.rhs); |
| 2519 | return sema.bitcast(block, dest_type, operand); | 3299 | return sema.bitcast(block, dest_type, operand); |
| 2520 | } | 3300 | } |
| 2521 | 3301 | ||
| 2522 | fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3302 | fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2523 | const tracy = trace(@src()); | 3303 | const tracy = trace(@src()); |
| 2524 | defer tracy.end(); | 3304 | defer tracy.end(); |
| 2525 | 3305 | ||
| ... | @@ -2527,7 +3307,7 @@ fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -2527,7 +3307,7 @@ fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 2527 | const src = inst_data.src(); | 3307 | const src = inst_data.src(); |
| 2528 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 3308 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 2529 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 3309 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 2530 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 3310 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2531 | 3311 | ||
| 2532 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); | 3312 | const dest_type = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 2533 | const operand = try sema.resolveInst(extra.rhs); | 3313 | const operand = try sema.resolveInst(extra.rhs); |
| ... | @@ -2562,7 +3342,7 @@ fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr | ... | @@ -2562,7 +3342,7 @@ fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr |
| 2562 | return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten float", .{}); | 3342 | return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten float", .{}); |
| 2563 | } | 3343 | } |
| 2564 | 3344 | ||
| 2565 | fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3345 | fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2566 | const tracy = trace(@src()); | 3346 | const tracy = trace(@src()); |
| 2567 | defer tracy.end(); | 3347 | defer tracy.end(); |
| 2568 | 3348 | ||
| ... | @@ -2577,14 +3357,14 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -2577,14 +3357,14 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 2577 | return sema.analyzeLoad(block, sema.src, result_ptr, sema.src); | 3357 | return sema.analyzeLoad(block, sema.src, result_ptr, sema.src); |
| 2578 | } | 3358 | } |
| 2579 | 3359 | ||
| 2580 | fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3360 | fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2581 | const tracy = trace(@src()); | 3361 | const tracy = trace(@src()); |
| 2582 | defer tracy.end(); | 3362 | defer tracy.end(); |
| 2583 | 3363 | ||
| 2584 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3364 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2585 | const src = inst_data.src(); | 3365 | const src = inst_data.src(); |
| 2586 | const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; | 3366 | const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; |
| 2587 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 3367 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2588 | const array = try sema.resolveInst(extra.lhs); | 3368 | const array = try sema.resolveInst(extra.lhs); |
| 2589 | const array_ptr = if (array.ty.zigTypeTag() == .Pointer) | 3369 | const array_ptr = if (array.ty.zigTypeTag() == .Pointer) |
| 2590 | array | 3370 | array |
| ... | @@ -2595,7 +3375,7 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -2595,7 +3375,7 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 2595 | return sema.analyzeLoad(block, src, result_ptr, src); | 3375 | return sema.analyzeLoad(block, src, result_ptr, src); |
| 2596 | } | 3376 | } |
| 2597 | 3377 | ||
| 2598 | fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3378 | fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2599 | const tracy = trace(@src()); | 3379 | const tracy = trace(@src()); |
| 2600 | defer tracy.end(); | 3380 | defer tracy.end(); |
| 2601 | 3381 | ||
| ... | @@ -2605,39 +3385,39 @@ fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -2605,39 +3385,39 @@ fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 2605 | return sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src); | 3385 | return sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src); |
| 2606 | } | 3386 | } |
| 2607 | 3387 | ||
| 2608 | fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3388 | fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2609 | const tracy = trace(@src()); | 3389 | const tracy = trace(@src()); |
| 2610 | defer tracy.end(); | 3390 | defer tracy.end(); |
| 2611 | 3391 | ||
| 2612 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3392 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2613 | const src = inst_data.src(); | 3393 | const src = inst_data.src(); |
| 2614 | const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; | 3394 | const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node }; |
| 2615 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 3395 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2616 | const array_ptr = try sema.resolveInst(extra.lhs); | 3396 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 2617 | const elem_index = try sema.resolveInst(extra.rhs); | 3397 | const elem_index = try sema.resolveInst(extra.rhs); |
| 2618 | return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src); | 3398 | return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src); |
| 2619 | } | 3399 | } |
| 2620 | 3400 | ||
| 2621 | fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3401 | fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2622 | const tracy = trace(@src()); | 3402 | const tracy = trace(@src()); |
| 2623 | defer tracy.end(); | 3403 | defer tracy.end(); |
| 2624 | 3404 | ||
| 2625 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3405 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2626 | const src = inst_data.src(); | 3406 | const src = inst_data.src(); |
| 2627 | const extra = sema.code.extraData(zir.Inst.SliceStart, inst_data.payload_index).data; | 3407 | const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data; |
| 2628 | const array_ptr = try sema.resolveInst(extra.lhs); | 3408 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 2629 | const start = try sema.resolveInst(extra.start); | 3409 | const start = try sema.resolveInst(extra.start); |
| 2630 | 3410 | ||
| 2631 | return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded); | 3411 | return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded); |
| 2632 | } | 3412 | } |
| 2633 | 3413 | ||
| 2634 | fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3414 | fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2635 | const tracy = trace(@src()); | 3415 | const tracy = trace(@src()); |
| 2636 | defer tracy.end(); | 3416 | defer tracy.end(); |
| 2637 | 3417 | ||
| 2638 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3418 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2639 | const src = inst_data.src(); | 3419 | const src = inst_data.src(); |
| 2640 | const extra = sema.code.extraData(zir.Inst.SliceEnd, inst_data.payload_index).data; | 3420 | const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data; |
| 2641 | const array_ptr = try sema.resolveInst(extra.lhs); | 3421 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 2642 | const start = try sema.resolveInst(extra.start); | 3422 | const start = try sema.resolveInst(extra.start); |
| 2643 | const end = try sema.resolveInst(extra.end); | 3423 | const end = try sema.resolveInst(extra.end); |
| ... | @@ -2645,14 +3425,14 @@ fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -2645,14 +3425,14 @@ fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 2645 | return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded); | 3425 | return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded); |
| 2646 | } | 3426 | } |
| 2647 | 3427 | ||
| 2648 | fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 3428 | fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 2649 | const tracy = trace(@src()); | 3429 | const tracy = trace(@src()); |
| 2650 | defer tracy.end(); | 3430 | defer tracy.end(); |
| 2651 | 3431 | ||
| 2652 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3432 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2653 | const src = inst_data.src(); | 3433 | const src = inst_data.src(); |
| 2654 | const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node }; | 3434 | const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node }; |
| 2655 | const extra = sema.code.extraData(zir.Inst.SliceSentinel, inst_data.payload_index).data; | 3435 | const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data; |
| 2656 | const array_ptr = try sema.resolveInst(extra.lhs); | 3436 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 2657 | const start = try sema.resolveInst(extra.start); | 3437 | const start = try sema.resolveInst(extra.start); |
| 2658 | const end = try sema.resolveInst(extra.end); | 3438 | const end = try sema.resolveInst(extra.end); |
| ... | @@ -2664,7 +3444,7 @@ fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne | ... | @@ -2664,7 +3444,7 @@ fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne |
| 2664 | fn zirSwitchCapture( | 3444 | fn zirSwitchCapture( |
| 2665 | sema: *Sema, | 3445 | sema: *Sema, |
| 2666 | block: *Scope.Block, | 3446 | block: *Scope.Block, |
| 2667 | inst: zir.Inst.Index, | 3447 | inst: Zir.Inst.Index, |
| 2668 | is_multi: bool, | 3448 | is_multi: bool, |
| 2669 | is_ref: bool, | 3449 | is_ref: bool, |
| 2670 | ) InnerError!*Inst { | 3450 | ) InnerError!*Inst { |
| ... | @@ -2682,7 +3462,7 @@ fn zirSwitchCapture( | ... | @@ -2682,7 +3462,7 @@ fn zirSwitchCapture( |
| 2682 | fn zirSwitchCaptureElse( | 3462 | fn zirSwitchCaptureElse( |
| 2683 | sema: *Sema, | 3463 | sema: *Sema, |
| 2684 | block: *Scope.Block, | 3464 | block: *Scope.Block, |
| 2685 | inst: zir.Inst.Index, | 3465 | inst: Zir.Inst.Index, |
| 2686 | is_ref: bool, | 3466 | is_ref: bool, |
| 2687 | ) InnerError!*Inst { | 3467 | ) InnerError!*Inst { |
| 2688 | const tracy = trace(@src()); | 3468 | const tracy = trace(@src()); |
| ... | @@ -2699,9 +3479,9 @@ fn zirSwitchCaptureElse( | ... | @@ -2699,9 +3479,9 @@ fn zirSwitchCaptureElse( |
| 2699 | fn zirSwitchBlock( | 3479 | fn zirSwitchBlock( |
| 2700 | sema: *Sema, | 3480 | sema: *Sema, |
| 2701 | block: *Scope.Block, | 3481 | block: *Scope.Block, |
| 2702 | inst: zir.Inst.Index, | 3482 | inst: Zir.Inst.Index, |
| 2703 | is_ref: bool, | 3483 | is_ref: bool, |
| 2704 | special_prong: zir.SpecialProng, | 3484 | special_prong: Zir.SpecialProng, |
| 2705 | ) InnerError!*Inst { | 3485 | ) InnerError!*Inst { |
| 2706 | const tracy = trace(@src()); | 3486 | const tracy = trace(@src()); |
| 2707 | defer tracy.end(); | 3487 | defer tracy.end(); |
| ... | @@ -2709,7 +3489,7 @@ fn zirSwitchBlock( | ... | @@ -2709,7 +3489,7 @@ fn zirSwitchBlock( |
| 2709 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3489 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2710 | const src = inst_data.src(); | 3490 | const src = inst_data.src(); |
| 2711 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; | 3491 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; |
| 2712 | const extra = sema.code.extraData(zir.Inst.SwitchBlock, inst_data.payload_index); | 3492 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 2713 | 3493 | ||
| 2714 | const operand_ptr = try sema.resolveInst(extra.data.operand); | 3494 | const operand_ptr = try sema.resolveInst(extra.data.operand); |
| 2715 | const operand = if (is_ref) | 3495 | const operand = if (is_ref) |
| ... | @@ -2732,9 +3512,9 @@ fn zirSwitchBlock( | ... | @@ -2732,9 +3512,9 @@ fn zirSwitchBlock( |
| 2732 | fn zirSwitchBlockMulti( | 3512 | fn zirSwitchBlockMulti( |
| 2733 | sema: *Sema, | 3513 | sema: *Sema, |
| 2734 | block: *Scope.Block, | 3514 | block: *Scope.Block, |
| 2735 | inst: zir.Inst.Index, | 3515 | inst: Zir.Inst.Index, |
| 2736 | is_ref: bool, | 3516 | is_ref: bool, |
| 2737 | special_prong: zir.SpecialProng, | 3517 | special_prong: Zir.SpecialProng, |
| 2738 | ) InnerError!*Inst { | 3518 | ) InnerError!*Inst { |
| 2739 | const tracy = trace(@src()); | 3519 | const tracy = trace(@src()); |
| 2740 | defer tracy.end(); | 3520 | defer tracy.end(); |
| ... | @@ -2742,7 +3522,7 @@ fn zirSwitchBlockMulti( | ... | @@ -2742,7 +3522,7 @@ fn zirSwitchBlockMulti( |
| 2742 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3522 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2743 | const src = inst_data.src(); | 3523 | const src = inst_data.src(); |
| 2744 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; | 3524 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; |
| 2745 | const extra = sema.code.extraData(zir.Inst.SwitchBlockMulti, inst_data.payload_index); | 3525 | const extra = sema.code.extraData(Zir.Inst.SwitchBlockMulti, inst_data.payload_index); |
| 2746 | 3526 | ||
| 2747 | const operand_ptr = try sema.resolveInst(extra.data.operand); | 3527 | const operand_ptr = try sema.resolveInst(extra.data.operand); |
| 2748 | const operand = if (is_ref) | 3528 | const operand = if (is_ref) |
| ... | @@ -2767,16 +3547,16 @@ fn analyzeSwitch( | ... | @@ -2767,16 +3547,16 @@ fn analyzeSwitch( |
| 2767 | block: *Scope.Block, | 3547 | block: *Scope.Block, |
| 2768 | operand: *Inst, | 3548 | operand: *Inst, |
| 2769 | extra_end: usize, | 3549 | extra_end: usize, |
| 2770 | special_prong: zir.SpecialProng, | 3550 | special_prong: Zir.SpecialProng, |
| 2771 | scalar_cases_len: usize, | 3551 | scalar_cases_len: usize, |
| 2772 | multi_cases_len: usize, | 3552 | multi_cases_len: usize, |
| 2773 | switch_inst: zir.Inst.Index, | 3553 | switch_inst: Zir.Inst.Index, |
| 2774 | src_node_offset: i32, | 3554 | src_node_offset: i32, |
| 2775 | ) InnerError!*Inst { | 3555 | ) InnerError!*Inst { |
| 2776 | const gpa = sema.gpa; | 3556 | const gpa = sema.gpa; |
| 2777 | const mod = sema.mod; | 3557 | const mod = sema.mod; |
| 2778 | 3558 | ||
| 2779 | const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) { | 3559 | const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) { |
| 2780 | .none => .{ .body = &.{}, .end = extra_end }, | 3560 | .none => .{ .body = &.{}, .end = extra_end }, |
| 2781 | .under, .@"else" => blk: { | 3561 | .under, .@"else" => blk: { |
| 2782 | const body_len = sema.code.extra[extra_end]; | 3562 | const body_len = sema.code.extra[extra_end]; |
| ... | @@ -2817,16 +3597,16 @@ fn analyzeSwitch( | ... | @@ -2817,16 +3597,16 @@ fn analyzeSwitch( |
| 2817 | // Validate for duplicate items, missing else prong, and invalid range. | 3597 | // Validate for duplicate items, missing else prong, and invalid range. |
| 2818 | switch (operand.ty.zigTypeTag()) { | 3598 | switch (operand.ty.zigTypeTag()) { |
| 2819 | .Enum => { | 3599 | .Enum => { |
| 2820 | var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount()); | 3600 | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand.ty.enumFieldCount()); |
| 2821 | defer gpa.free(seen_fields); | 3601 | defer gpa.free(seen_fields); |
| 2822 | 3602 | ||
| 2823 | mem.set(?AstGen.SwitchProngSrc, seen_fields, null); | 3603 | mem.set(?Module.SwitchProngSrc, seen_fields, null); |
| 2824 | 3604 | ||
| 2825 | var extra_index: usize = special.end; | 3605 | var extra_index: usize = special.end; |
| 2826 | { | 3606 | { |
| 2827 | var scalar_i: u32 = 0; | 3607 | var scalar_i: u32 = 0; |
| 2828 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 3608 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 2829 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3609 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2830 | extra_index += 1; | 3610 | extra_index += 1; |
| 2831 | const body_len = sema.code.extra[extra_index]; | 3611 | const body_len = sema.code.extra[extra_index]; |
| 2832 | extra_index += 1; | 3612 | extra_index += 1; |
| ... | @@ -2936,7 +3716,7 @@ fn analyzeSwitch( | ... | @@ -2936,7 +3716,7 @@ fn analyzeSwitch( |
| 2936 | { | 3716 | { |
| 2937 | var scalar_i: u32 = 0; | 3717 | var scalar_i: u32 = 0; |
| 2938 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 3718 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 2939 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3719 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2940 | extra_index += 1; | 3720 | extra_index += 1; |
| 2941 | const body_len = sema.code.extra[extra_index]; | 3721 | const body_len = sema.code.extra[extra_index]; |
| 2942 | extra_index += 1; | 3722 | extra_index += 1; |
| ... | @@ -2976,9 +3756,9 @@ fn analyzeSwitch( | ... | @@ -2976,9 +3756,9 @@ fn analyzeSwitch( |
| 2976 | 3756 | ||
| 2977 | var range_i: u32 = 0; | 3757 | var range_i: u32 = 0; |
| 2978 | while (range_i < ranges_len) : (range_i += 1) { | 3758 | while (range_i < ranges_len) : (range_i += 1) { |
| 2979 | const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3759 | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2980 | extra_index += 1; | 3760 | extra_index += 1; |
| 2981 | const item_last = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3761 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2982 | extra_index += 1; | 3762 | extra_index += 1; |
| 2983 | 3763 | ||
| 2984 | try sema.validateSwitchRange( | 3764 | try sema.validateSwitchRange( |
| ... | @@ -3032,7 +3812,7 @@ fn analyzeSwitch( | ... | @@ -3032,7 +3812,7 @@ fn analyzeSwitch( |
| 3032 | { | 3812 | { |
| 3033 | var scalar_i: u32 = 0; | 3813 | var scalar_i: u32 = 0; |
| 3034 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 3814 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 3035 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3815 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3036 | extra_index += 1; | 3816 | extra_index += 1; |
| 3037 | const body_len = sema.code.extra[extra_index]; | 3817 | const body_len = sema.code.extra[extra_index]; |
| 3038 | extra_index += 1; | 3818 | extra_index += 1; |
| ... | @@ -3115,7 +3895,7 @@ fn analyzeSwitch( | ... | @@ -3115,7 +3895,7 @@ fn analyzeSwitch( |
| 3115 | { | 3895 | { |
| 3116 | var scalar_i: u32 = 0; | 3896 | var scalar_i: u32 = 0; |
| 3117 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 3897 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 3118 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3898 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3119 | extra_index += 1; | 3899 | extra_index += 1; |
| 3120 | const body_len = sema.code.extra[extra_index]; | 3900 | const body_len = sema.code.extra[extra_index]; |
| 3121 | extra_index += 1; | 3901 | extra_index += 1; |
| ... | @@ -3177,12 +3957,45 @@ fn analyzeSwitch( | ... | @@ -3177,12 +3957,45 @@ fn analyzeSwitch( |
| 3177 | }), | 3957 | }), |
| 3178 | } | 3958 | } |
| 3179 | 3959 | ||
| 3180 | if (try sema.resolveDefinedValue(block, src, operand)) |operand_val| { | 3960 | const block_inst = try sema.arena.create(Inst.Block); |
| 3961 | block_inst.* = .{ | ||
| 3962 | .base = .{ | ||
| 3963 | .tag = Inst.Block.base_tag, | ||
| 3964 | .ty = undefined, // Set after analysis. | ||
| 3965 | .src = src, | ||
| 3966 | }, | ||
| 3967 | .body = undefined, | ||
| 3968 | }; | ||
| 3969 | |||
| 3970 | var label: Scope.Block.Label = .{ | ||
| 3971 | .zir_block = switch_inst, | ||
| 3972 | .merges = .{ | ||
| 3973 | .results = .{}, | ||
| 3974 | .br_list = .{}, | ||
| 3975 | .block_inst = block_inst, | ||
| 3976 | }, | ||
| 3977 | }; | ||
| 3978 | |||
| 3979 | var child_block: Scope.Block = .{ | ||
| 3980 | .parent = block, | ||
| 3981 | .sema = sema, | ||
| 3982 | .src_decl = block.src_decl, | ||
| 3983 | .instructions = .{}, | ||
| 3984 | .label = &label, | ||
| 3985 | .inlining = block.inlining, | ||
| 3986 | .is_comptime = block.is_comptime, | ||
| 3987 | }; | ||
| 3988 | const merges = &child_block.label.?.merges; | ||
| 3989 | defer child_block.instructions.deinit(gpa); | ||
| 3990 | defer merges.results.deinit(gpa); | ||
| 3991 | defer merges.br_list.deinit(gpa); | ||
| 3992 | |||
| 3993 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { | ||
| 3181 | var extra_index: usize = special.end; | 3994 | var extra_index: usize = special.end; |
| 3182 | { | 3995 | { |
| 3183 | var scalar_i: usize = 0; | 3996 | var scalar_i: usize = 0; |
| 3184 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 3997 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 3185 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 3998 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3186 | extra_index += 1; | 3999 | extra_index += 1; |
| 3187 | const body_len = sema.code.extra[extra_index]; | 4000 | const body_len = sema.code.extra[extra_index]; |
| 3188 | extra_index += 1; | 4001 | extra_index += 1; |
| ... | @@ -3191,9 +4004,9 @@ fn analyzeSwitch( | ... | @@ -3191,9 +4004,9 @@ fn analyzeSwitch( |
| 3191 | 4004 | ||
| 3192 | // Validation above ensured these will succeed. | 4005 | // Validation above ensured these will succeed. |
| 3193 | const item = sema.resolveInst(item_ref) catch unreachable; | 4006 | const item = sema.resolveInst(item_ref) catch unreachable; |
| 3194 | const item_val = sema.resolveConstValue(block, .unneeded, item) catch unreachable; | 4007 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable; |
| 3195 | if (operand_val.eql(item_val)) { | 4008 | if (operand_val.eql(item_val)) { |
| 3196 | return sema.resolveBody(block, body); | 4009 | return sema.resolveBlockBody(block, src, &child_block, body, merges); |
| 3197 | } | 4010 | } |
| 3198 | } | 4011 | } |
| 3199 | } | 4012 | } |
| ... | @@ -3213,76 +4026,44 @@ fn analyzeSwitch( | ... | @@ -3213,76 +4026,44 @@ fn analyzeSwitch( |
| 3213 | for (items) |item_ref| { | 4026 | for (items) |item_ref| { |
| 3214 | // Validation above ensured these will succeed. | 4027 | // Validation above ensured these will succeed. |
| 3215 | const item = sema.resolveInst(item_ref) catch unreachable; | 4028 | const item = sema.resolveInst(item_ref) catch unreachable; |
| 3216 | const item_val = sema.resolveConstValue(block, item.src, item) catch unreachable; | 4029 | const item_val = sema.resolveConstValue(&child_block, item.src, item) catch unreachable; |
| 3217 | if (operand_val.eql(item_val)) { | 4030 | if (operand_val.eql(item_val)) { |
| 3218 | return sema.resolveBody(block, body); | 4031 | return sema.resolveBlockBody(block, src, &child_block, body, merges); |
| 3219 | } | 4032 | } |
| 3220 | } | 4033 | } |
| 3221 | 4034 | ||
| 3222 | var range_i: usize = 0; | 4035 | var range_i: usize = 0; |
| 3223 | while (range_i < ranges_len) : (range_i += 1) { | 4036 | while (range_i < ranges_len) : (range_i += 1) { |
| 3224 | const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 4037 | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3225 | extra_index += 1; | 4038 | extra_index += 1; |
| 3226 | const item_last = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 4039 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3227 | extra_index += 1; | 4040 | extra_index += 1; |
| 3228 | 4041 | ||
| 3229 | // Validation above ensured these will succeed. | 4042 | // Validation above ensured these will succeed. |
| 3230 | const first_tv = sema.resolveInstConst(block, .unneeded, item_first) catch unreachable; | 4043 | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable; |
| 3231 | const last_tv = sema.resolveInstConst(block, .unneeded, item_last) catch unreachable; | 4044 | const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable; |
| 3232 | if (Value.compare(operand_val, .gte, first_tv.val) and | 4045 | if (Value.compare(operand_val, .gte, first_tv.val) and |
| 3233 | Value.compare(operand_val, .lte, last_tv.val)) | 4046 | Value.compare(operand_val, .lte, last_tv.val)) |
| 3234 | { | 4047 | { |
| 3235 | return sema.resolveBody(block, body); | 4048 | return sema.resolveBlockBody(block, src, &child_block, body, merges); |
| 3236 | } | 4049 | } |
| 3237 | } | 4050 | } |
| 3238 | 4051 | ||
| 3239 | extra_index += body_len; | 4052 | extra_index += body_len; |
| 3240 | } | 4053 | } |
| 3241 | } | 4054 | } |
| 3242 | return sema.resolveBody(block, special.body); | 4055 | return sema.resolveBlockBody(block, src, &child_block, special.body, merges); |
| 3243 | } | 4056 | } |
| 3244 | 4057 | ||
| 3245 | if (scalar_cases_len + multi_cases_len == 0) { | 4058 | if (scalar_cases_len + multi_cases_len == 0) { |
| 3246 | return sema.resolveBody(block, special.body); | 4059 | return sema.resolveBlockBody(block, src, &child_block, special.body, merges); |
| 3247 | } | 4060 | } |
| 3248 | 4061 | ||
| 3249 | try sema.requireRuntimeBlock(block, src); | 4062 | try sema.requireRuntimeBlock(block, src); |
| 3250 | 4063 | ||
| 3251 | const block_inst = try sema.arena.create(Inst.Block); | 4064 | // TODO when reworking AIR memory layout make multi cases get generated as cases, |
| 3252 | block_inst.* = .{ | 4065 | // not as part of the "else" block. |
| 3253 | .base = .{ | 4066 | const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len); |
| 3254 | .tag = Inst.Block.base_tag, | ||
| 3255 | .ty = undefined, // Set after analysis. | ||
| 3256 | .src = src, | ||
| 3257 | }, | ||
| 3258 | .body = undefined, | ||
| 3259 | }; | ||
| 3260 | |||
| 3261 | var child_block: Scope.Block = .{ | ||
| 3262 | .parent = block, | ||
| 3263 | .sema = sema, | ||
| 3264 | .src_decl = block.src_decl, | ||
| 3265 | .instructions = .{}, | ||
| 3266 | // TODO @as here is working around a stage1 miscompilation bug :( | ||
| 3267 | .label = @as(?Scope.Block.Label, Scope.Block.Label{ | ||
| 3268 | .zir_block = switch_inst, | ||
| 3269 | .merges = .{ | ||
| 3270 | .results = .{}, | ||
| 3271 | .br_list = .{}, | ||
| 3272 | .block_inst = block_inst, | ||
| 3273 | }, | ||
| 3274 | }), | ||
| 3275 | .inlining = block.inlining, | ||
| 3276 | .is_comptime = block.is_comptime, | ||
| 3277 | }; | ||
| 3278 | const merges = &child_block.label.?.merges; | ||
| 3279 | defer child_block.instructions.deinit(gpa); | ||
| 3280 | defer merges.results.deinit(gpa); | ||
| 3281 | defer merges.br_list.deinit(gpa); | ||
| 3282 | |||
| 3283 | // TODO when reworking TZIR memory layout make multi cases get generated as cases, | ||
| 3284 | // not as part of the "else" block. | ||
| 3285 | const cases = try sema.arena.alloc(Inst.SwitchBr.Case, scalar_cases_len); | ||
| 3286 | 4067 | ||
| 3287 | var case_block = child_block.makeSubBlock(); | 4068 | var case_block = child_block.makeSubBlock(); |
| 3288 | defer case_block.instructions.deinit(gpa); | 4069 | defer case_block.instructions.deinit(gpa); |
| ... | @@ -3291,7 +4072,7 @@ fn analyzeSwitch( | ... | @@ -3291,7 +4072,7 @@ fn analyzeSwitch( |
| 3291 | 4072 | ||
| 3292 | var scalar_i: usize = 0; | 4073 | var scalar_i: usize = 0; |
| 3293 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 4074 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 3294 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 4075 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3295 | extra_index += 1; | 4076 | extra_index += 1; |
| 3296 | const body_len = sema.code.extra[extra_index]; | 4077 | const body_len = sema.code.extra[extra_index]; |
| 3297 | extra_index += 1; | 4078 | extra_index += 1; |
| ... | @@ -3344,9 +4125,9 @@ fn analyzeSwitch( | ... | @@ -3344,9 +4125,9 @@ fn analyzeSwitch( |
| 3344 | 4125 | ||
| 3345 | var range_i: usize = 0; | 4126 | var range_i: usize = 0; |
| 3346 | while (range_i < ranges_len) : (range_i += 1) { | 4127 | while (range_i < ranges_len) : (range_i += 1) { |
| 3347 | const first_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 4128 | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3348 | extra_index += 1; | 4129 | extra_index += 1; |
| 3349 | const last_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 4130 | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 3350 | extra_index += 1; | 4131 | extra_index += 1; |
| 3351 | 4132 | ||
| 3352 | const item_first = try sema.resolveInst(first_ref); | 4133 | const item_first = try sema.resolveInst(first_ref); |
| ... | @@ -3443,10 +4224,10 @@ fn analyzeSwitch( | ... | @@ -3443,10 +4224,10 @@ fn analyzeSwitch( |
| 3443 | fn resolveSwitchItemVal( | 4224 | fn resolveSwitchItemVal( |
| 3444 | sema: *Sema, | 4225 | sema: *Sema, |
| 3445 | block: *Scope.Block, | 4226 | block: *Scope.Block, |
| 3446 | item_ref: zir.Inst.Ref, | 4227 | item_ref: Zir.Inst.Ref, |
| 3447 | switch_node_offset: i32, | 4228 | switch_node_offset: i32, |
| 3448 | switch_prong_src: AstGen.SwitchProngSrc, | 4229 | switch_prong_src: Module.SwitchProngSrc, |
| 3449 | range_expand: AstGen.SwitchProngSrc.RangeExpand, | 4230 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 3450 | ) InnerError!TypedValue { | 4231 | ) InnerError!TypedValue { |
| 3451 | const item = try sema.resolveInst(item_ref); | 4232 | const item = try sema.resolveInst(item_ref); |
| 3452 | // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc | 4233 | // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc |
| ... | @@ -3454,12 +4235,12 @@ fn resolveSwitchItemVal( | ... | @@ -3454,12 +4235,12 @@ fn resolveSwitchItemVal( |
| 3454 | // a compile error do we resolve the full source locations. | 4235 | // a compile error do we resolve the full source locations. |
| 3455 | if (item.value()) |val| { | 4236 | if (item.value()) |val| { |
| 3456 | if (val.isUndef()) { | 4237 | if (val.isUndef()) { |
| 3457 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); | 4238 | const src = switch_prong_src.resolve(sema.gpa, block.src_decl, switch_node_offset, range_expand); |
| 3458 | return sema.failWithUseOfUndef(block, src); | 4239 | return sema.failWithUseOfUndef(block, src); |
| 3459 | } | 4240 | } |
| 3460 | return TypedValue{ .ty = item.ty, .val = val }; | 4241 | return TypedValue{ .ty = item.ty, .val = val }; |
| 3461 | } | 4242 | } |
| 3462 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); | 4243 | const src = switch_prong_src.resolve(sema.gpa, block.src_decl, switch_node_offset, range_expand); |
| 3463 | return sema.failWithNeededComptime(block, src); | 4244 | return sema.failWithNeededComptime(block, src); |
| 3464 | } | 4245 | } |
| 3465 | 4246 | ||
| ... | @@ -3467,10 +4248,10 @@ fn validateSwitchRange( | ... | @@ -3467,10 +4248,10 @@ fn validateSwitchRange( |
| 3467 | sema: *Sema, | 4248 | sema: *Sema, |
| 3468 | block: *Scope.Block, | 4249 | block: *Scope.Block, |
| 3469 | range_set: *RangeSet, | 4250 | range_set: *RangeSet, |
| 3470 | first_ref: zir.Inst.Ref, | 4251 | first_ref: Zir.Inst.Ref, |
| 3471 | last_ref: zir.Inst.Ref, | 4252 | last_ref: Zir.Inst.Ref, |
| 3472 | src_node_offset: i32, | 4253 | src_node_offset: i32, |
| 3473 | switch_prong_src: AstGen.SwitchProngSrc, | 4254 | switch_prong_src: Module.SwitchProngSrc, |
| 3474 | ) InnerError!void { | 4255 | ) InnerError!void { |
| 3475 | const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; | 4256 | const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; |
| 3476 | const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; | 4257 | const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; |
| ... | @@ -3482,9 +4263,9 @@ fn validateSwitchItem( | ... | @@ -3482,9 +4263,9 @@ fn validateSwitchItem( |
| 3482 | sema: *Sema, | 4263 | sema: *Sema, |
| 3483 | block: *Scope.Block, | 4264 | block: *Scope.Block, |
| 3484 | range_set: *RangeSet, | 4265 | range_set: *RangeSet, |
| 3485 | item_ref: zir.Inst.Ref, | 4266 | item_ref: Zir.Inst.Ref, |
| 3486 | src_node_offset: i32, | 4267 | src_node_offset: i32, |
| 3487 | switch_prong_src: AstGen.SwitchProngSrc, | 4268 | switch_prong_src: Module.SwitchProngSrc, |
| 3488 | ) InnerError!void { | 4269 | ) InnerError!void { |
| 3489 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 4270 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3490 | const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src); | 4271 | const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src); |
| ... | @@ -3494,16 +4275,16 @@ fn validateSwitchItem( | ... | @@ -3494,16 +4275,16 @@ fn validateSwitchItem( |
| 3494 | fn validateSwitchItemEnum( | 4275 | fn validateSwitchItemEnum( |
| 3495 | sema: *Sema, | 4276 | sema: *Sema, |
| 3496 | block: *Scope.Block, | 4277 | block: *Scope.Block, |
| 3497 | seen_fields: []?AstGen.SwitchProngSrc, | 4278 | seen_fields: []?Module.SwitchProngSrc, |
| 3498 | item_ref: zir.Inst.Ref, | 4279 | item_ref: Zir.Inst.Ref, |
| 3499 | src_node_offset: i32, | 4280 | src_node_offset: i32, |
| 3500 | switch_prong_src: AstGen.SwitchProngSrc, | 4281 | switch_prong_src: Module.SwitchProngSrc, |
| 3501 | ) InnerError!void { | 4282 | ) InnerError!void { |
| 3502 | const mod = sema.mod; | 4283 | const mod = sema.mod; |
| 3503 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 4284 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 3504 | const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse { | 4285 | const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse { |
| 3505 | const msg = msg: { | 4286 | const msg = msg: { |
| 3506 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); | 4287 | const src = switch_prong_src.resolve(sema.gpa, block.src_decl, src_node_offset, .none); |
| 3507 | const msg = try mod.errMsg( | 4288 | const msg = try mod.errMsg( |
| 3508 | &block.base, | 4289 | &block.base, |
| 3509 | src, | 4290 | src, |
| ... | @@ -3529,14 +4310,15 @@ fn validateSwitchItemEnum( | ... | @@ -3529,14 +4310,15 @@ fn validateSwitchItemEnum( |
| 3529 | fn validateSwitchDupe( | 4310 | fn validateSwitchDupe( |
| 3530 | sema: *Sema, | 4311 | sema: *Sema, |
| 3531 | block: *Scope.Block, | 4312 | block: *Scope.Block, |
| 3532 | maybe_prev_src: ?AstGen.SwitchProngSrc, | 4313 | maybe_prev_src: ?Module.SwitchProngSrc, |
| 3533 | switch_prong_src: AstGen.SwitchProngSrc, | 4314 | switch_prong_src: Module.SwitchProngSrc, |
| 3534 | src_node_offset: i32, | 4315 | src_node_offset: i32, |
| 3535 | ) InnerError!void { | 4316 | ) InnerError!void { |
| 3536 | const prev_prong_src = maybe_prev_src orelse return; | 4317 | const prev_prong_src = maybe_prev_src orelse return; |
| 3537 | const mod = sema.mod; | 4318 | const mod = sema.mod; |
| 3538 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); | 4319 | const gpa = sema.gpa; |
| 3539 | const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none); | 4320 | const src = switch_prong_src.resolve(gpa, block.src_decl, src_node_offset, .none); |
| 4321 | const prev_src = prev_prong_src.resolve(gpa, block.src_decl, src_node_offset, .none); | ||
| 3540 | const msg = msg: { | 4322 | const msg = msg: { |
| 3541 | const msg = try mod.errMsg( | 4323 | const msg = try mod.errMsg( |
| 3542 | &block.base, | 4324 | &block.base, |
| ... | @@ -3562,9 +4344,9 @@ fn validateSwitchItemBool( | ... | @@ -3562,9 +4344,9 @@ fn validateSwitchItemBool( |
| 3562 | block: *Scope.Block, | 4344 | block: *Scope.Block, |
| 3563 | true_count: *u8, | 4345 | true_count: *u8, |
| 3564 | false_count: *u8, | 4346 | false_count: *u8, |
| 3565 | item_ref: zir.Inst.Ref, | 4347 | item_ref: Zir.Inst.Ref, |
| 3566 | src_node_offset: i32, | 4348 | src_node_offset: i32, |
| 3567 | switch_prong_src: AstGen.SwitchProngSrc, | 4349 | switch_prong_src: Module.SwitchProngSrc, |
| 3568 | ) InnerError!void { | 4350 | ) InnerError!void { |
| 3569 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 4351 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3570 | if (item_val.toBool()) { | 4352 | if (item_val.toBool()) { |
| ... | @@ -3573,20 +4355,20 @@ fn validateSwitchItemBool( | ... | @@ -3573,20 +4355,20 @@ fn validateSwitchItemBool( |
| 3573 | false_count.* += 1; | 4355 | false_count.* += 1; |
| 3574 | } | 4356 | } |
| 3575 | if (true_count.* + false_count.* > 2) { | 4357 | if (true_count.* + false_count.* > 2) { |
| 3576 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); | 4358 | const src = switch_prong_src.resolve(sema.gpa, block.src_decl, src_node_offset, .none); |
| 3577 | return sema.mod.fail(&block.base, src, "duplicate switch value", .{}); | 4359 | return sema.mod.fail(&block.base, src, "duplicate switch value", .{}); |
| 3578 | } | 4360 | } |
| 3579 | } | 4361 | } |
| 3580 | 4362 | ||
| 3581 | const ValueSrcMap = std.HashMap(Value, AstGen.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); | 4363 | const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); |
| 3582 | 4364 | ||
| 3583 | fn validateSwitchItemSparse( | 4365 | fn validateSwitchItemSparse( |
| 3584 | sema: *Sema, | 4366 | sema: *Sema, |
| 3585 | block: *Scope.Block, | 4367 | block: *Scope.Block, |
| 3586 | seen_values: *ValueSrcMap, | 4368 | seen_values: *ValueSrcMap, |
| 3587 | item_ref: zir.Inst.Ref, | 4369 | item_ref: Zir.Inst.Ref, |
| 3588 | src_node_offset: i32, | 4370 | src_node_offset: i32, |
| 3589 | switch_prong_src: AstGen.SwitchProngSrc, | 4371 | switch_prong_src: Module.SwitchProngSrc, |
| 3590 | ) InnerError!void { | 4372 | ) InnerError!void { |
| 3591 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 4373 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3592 | const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; | 4374 | const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; |
| ... | @@ -3626,12 +4408,17 @@ fn validateSwitchNoRange( | ... | @@ -3626,12 +4408,17 @@ fn validateSwitchNoRange( |
| 3626 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | 4408 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 3627 | } | 4409 | } |
| 3628 | 4410 | ||
| 3629 | fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4411 | fn zirHasField(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3630 | const tracy = trace(@src()); | 4412 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3631 | defer tracy.end(); | 4413 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 4414 | const src = inst_data.src(); | ||
| 4415 | |||
| 4416 | return sema.mod.fail(&block.base, src, "TODO implement zirHasField", .{}); | ||
| 4417 | } | ||
| 3632 | 4418 | ||
| 4419 | fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 3633 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4420 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3634 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 4421 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 3635 | const src = inst_data.src(); | 4422 | const src = inst_data.src(); |
| 3636 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 4423 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 3637 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 4424 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| ... | @@ -3640,51 +4427,52 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -3640,51 +4427,52 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 3640 | const mod = sema.mod; | 4427 | const mod = sema.mod; |
| 3641 | const arena = sema.arena; | 4428 | const arena = sema.arena; |
| 3642 | 4429 | ||
| 3643 | const container_scope = container_type.getContainerScope() orelse return mod.fail( | 4430 | const namespace = container_type.getNamespace() orelse return mod.fail( |
| 3644 | &block.base, | 4431 | &block.base, |
| 3645 | lhs_src, | 4432 | lhs_src, |
| 3646 | "expected struct, enum, union, or opaque, found '{}'", | 4433 | "expected struct, enum, union, or opaque, found '{}'", |
| 3647 | .{container_type}, | 4434 | .{container_type}, |
| 3648 | ); | 4435 | ); |
| 3649 | if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| { | 4436 | if (try sema.lookupInNamespace(namespace, decl_name)) |decl| { |
| 3650 | // TODO if !decl.is_pub and inDifferentFiles() return false | 4437 | if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) { |
| 3651 | return mod.constBool(arena, src, true); | 4438 | return mod.constBool(arena, src, true); |
| 3652 | } else { | 4439 | } |
| 3653 | return mod.constBool(arena, src, false); | ||
| 3654 | } | 4440 | } |
| 4441 | return mod.constBool(arena, src, false); | ||
| 3655 | } | 4442 | } |
| 3656 | 4443 | ||
| 3657 | fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4444 | fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3658 | const tracy = trace(@src()); | 4445 | const tracy = trace(@src()); |
| 3659 | defer tracy.end(); | 4446 | defer tracy.end(); |
| 3660 | 4447 | ||
| 3661 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4448 | const mod = sema.mod; |
| 4449 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | ||
| 3662 | const src = inst_data.src(); | 4450 | const src = inst_data.src(); |
| 3663 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 4451 | const operand = inst_data.get(sema.code); |
| 3664 | const operand = try sema.resolveConstString(block, operand_src, inst_data.operand); | ||
| 3665 | 4452 | ||
| 3666 | const file_scope = sema.analyzeImport(block, src, operand) catch |err| switch (err) { | 4453 | const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) { |
| 3667 | error.ImportOutsidePkgPath => { | 4454 | error.ImportOutsidePkgPath => { |
| 3668 | return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand}); | 4455 | return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand}); |
| 3669 | }, | ||
| 3670 | error.FileNotFound => { | ||
| 3671 | return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand}); | ||
| 3672 | }, | 4456 | }, |
| 3673 | else => { | 4457 | else => { |
| 3674 | // TODO: make sure this gets retried and not cached | 4458 | // TODO: these errors are file system errors; make sure an update() will |
| 3675 | return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); | 4459 | // retry this and not cache the file system error, which may be transient. |
| 4460 | return mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); | ||
| 3676 | }, | 4461 | }, |
| 3677 | }; | 4462 | }; |
| 3678 | return sema.mod.constType(sema.arena, src, file_scope.root_container.ty); | 4463 | try mod.semaFile(result.file); |
| 4464 | const file_root_decl = result.file.root_decl.?; | ||
| 4465 | try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl); | ||
| 4466 | return mod.constType(sema.arena, src, file_root_decl.ty); | ||
| 3679 | } | 4467 | } |
| 3680 | 4468 | ||
| 3681 | fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4469 | fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3682 | const tracy = trace(@src()); | 4470 | const tracy = trace(@src()); |
| 3683 | defer tracy.end(); | 4471 | defer tracy.end(); |
| 3684 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{}); | 4472 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{}); |
| 3685 | } | 4473 | } |
| 3686 | 4474 | ||
| 3687 | fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4475 | fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3688 | const tracy = trace(@src()); | 4476 | const tracy = trace(@src()); |
| 3689 | defer tracy.end(); | 4477 | defer tracy.end(); |
| 3690 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{}); | 4478 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{}); |
| ... | @@ -3693,7 +4481,7 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In | ... | @@ -3693,7 +4481,7 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In |
| 3693 | fn zirBitwise( | 4481 | fn zirBitwise( |
| 3694 | sema: *Sema, | 4482 | sema: *Sema, |
| 3695 | block: *Scope.Block, | 4483 | block: *Scope.Block, |
| 3696 | inst: zir.Inst.Index, | 4484 | inst: Zir.Inst.Index, |
| 3697 | ir_tag: ir.Inst.Tag, | 4485 | ir_tag: ir.Inst.Tag, |
| 3698 | ) InnerError!*Inst { | 4486 | ) InnerError!*Inst { |
| 3699 | const tracy = trace(@src()); | 4487 | const tracy = trace(@src()); |
| ... | @@ -3703,7 +4491,7 @@ fn zirBitwise( | ... | @@ -3703,7 +4491,7 @@ fn zirBitwise( |
| 3703 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 4491 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 3704 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 4492 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 3705 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 4493 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 3706 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 4494 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 3707 | const lhs = try sema.resolveInst(extra.lhs); | 4495 | const lhs = try sema.resolveInst(extra.lhs); |
| 3708 | const rhs = try sema.resolveInst(extra.rhs); | 4496 | const rhs = try sema.resolveInst(extra.rhs); |
| 3709 | 4497 | ||
| ... | @@ -3743,10 +4531,7 @@ fn zirBitwise( | ... | @@ -3743,10 +4531,7 @@ fn zirBitwise( |
| 3743 | if (casted_lhs.value()) |lhs_val| { | 4531 | if (casted_lhs.value()) |lhs_val| { |
| 3744 | if (casted_rhs.value()) |rhs_val| { | 4532 | if (casted_rhs.value()) |rhs_val| { |
| 3745 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 4533 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 3746 | return sema.mod.constInst(sema.arena, src, .{ | 4534 | return sema.mod.constUndef(sema.arena, src, resolved_type); |
| 3747 | .ty = resolved_type, | ||
| 3748 | .val = Value.initTag(.undef), | ||
| 3749 | }); | ||
| 3750 | } | 4535 | } |
| 3751 | return sema.mod.fail(&block.base, src, "TODO implement comptime bitwise operations", .{}); | 4536 | return sema.mod.fail(&block.base, src, "TODO implement comptime bitwise operations", .{}); |
| 3752 | } | 4537 | } |
| ... | @@ -3756,19 +4541,19 @@ fn zirBitwise( | ... | @@ -3756,19 +4541,19 @@ fn zirBitwise( |
| 3756 | return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs); | 4541 | return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs); |
| 3757 | } | 4542 | } |
| 3758 | 4543 | ||
| 3759 | fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4544 | fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3760 | const tracy = trace(@src()); | 4545 | const tracy = trace(@src()); |
| 3761 | defer tracy.end(); | 4546 | defer tracy.end(); |
| 3762 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirBitNot", .{}); | 4547 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirBitNot", .{}); |
| 3763 | } | 4548 | } |
| 3764 | 4549 | ||
| 3765 | fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4550 | fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3766 | const tracy = trace(@src()); | 4551 | const tracy = trace(@src()); |
| 3767 | defer tracy.end(); | 4552 | defer tracy.end(); |
| 3768 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayCat", .{}); | 4553 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayCat", .{}); |
| 3769 | } | 4554 | } |
| 3770 | 4555 | ||
| 3771 | fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4556 | fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3772 | const tracy = trace(@src()); | 4557 | const tracy = trace(@src()); |
| 3773 | defer tracy.end(); | 4558 | defer tracy.end(); |
| 3774 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayMul", .{}); | 4559 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirArrayMul", .{}); |
| ... | @@ -3777,8 +4562,8 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -3777,8 +4562,8 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 3777 | fn zirNegate( | 4562 | fn zirNegate( |
| 3778 | sema: *Sema, | 4563 | sema: *Sema, |
| 3779 | block: *Scope.Block, | 4564 | block: *Scope.Block, |
| 3780 | inst: zir.Inst.Index, | 4565 | inst: Zir.Inst.Index, |
| 3781 | tag_override: zir.Inst.Tag, | 4566 | tag_override: Zir.Inst.Tag, |
| 3782 | ) InnerError!*Inst { | 4567 | ) InnerError!*Inst { |
| 3783 | const tracy = trace(@src()); | 4568 | const tracy = trace(@src()); |
| 3784 | defer tracy.end(); | 4569 | defer tracy.end(); |
| ... | @@ -3793,7 +4578,7 @@ fn zirNegate( | ... | @@ -3793,7 +4578,7 @@ fn zirNegate( |
| 3793 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src); | 4578 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src); |
| 3794 | } | 4579 | } |
| 3795 | 4580 | ||
| 3796 | fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4581 | fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3797 | const tracy = trace(@src()); | 4582 | const tracy = trace(@src()); |
| 3798 | defer tracy.end(); | 4583 | defer tracy.end(); |
| 3799 | 4584 | ||
| ... | @@ -3802,17 +4587,31 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -3802,17 +4587,31 @@ fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 3802 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 4587 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 3803 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 4588 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 3804 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 4589 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 3805 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 4590 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 3806 | const lhs = try sema.resolveInst(extra.lhs); | 4591 | const lhs = try sema.resolveInst(extra.lhs); |
| 3807 | const rhs = try sema.resolveInst(extra.rhs); | 4592 | const rhs = try sema.resolveInst(extra.rhs); |
| 3808 | 4593 | ||
| 3809 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src); | 4594 | return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src); |
| 3810 | } | 4595 | } |
| 3811 | 4596 | ||
| 4597 | fn zirOverflowArithmetic( | ||
| 4598 | sema: *Sema, | ||
| 4599 | block: *Scope.Block, | ||
| 4600 | extended: Zir.Inst.Extended.InstData, | ||
| 4601 | ) InnerError!*Inst { | ||
| 4602 | const tracy = trace(@src()); | ||
| 4603 | defer tracy.end(); | ||
| 4604 | |||
| 4605 | const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; | ||
| 4606 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 4607 | |||
| 4608 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirOverflowArithmetic", .{}); | ||
| 4609 | } | ||
| 4610 | |||
| 3812 | fn analyzeArithmetic( | 4611 | fn analyzeArithmetic( |
| 3813 | sema: *Sema, | 4612 | sema: *Sema, |
| 3814 | block: *Scope.Block, | 4613 | block: *Scope.Block, |
| 3815 | zir_tag: zir.Inst.Tag, | 4614 | zir_tag: Zir.Inst.Tag, |
| 3816 | lhs: *Inst, | 4615 | lhs: *Inst, |
| 3817 | rhs: *Inst, | 4616 | rhs: *Inst, |
| 3818 | src: LazySrcLoc, | 4617 | src: LazySrcLoc, |
| ... | @@ -3856,10 +4655,7 @@ fn analyzeArithmetic( | ... | @@ -3856,10 +4655,7 @@ fn analyzeArithmetic( |
| 3856 | if (casted_lhs.value()) |lhs_val| { | 4655 | if (casted_lhs.value()) |lhs_val| { |
| 3857 | if (casted_rhs.value()) |rhs_val| { | 4656 | if (casted_rhs.value()) |rhs_val| { |
| 3858 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 4657 | if (lhs_val.isUndef() or rhs_val.isUndef()) { |
| 3859 | return sema.mod.constInst(sema.arena, src, .{ | 4658 | return sema.mod.constUndef(sema.arena, src, resolved_type); |
| 3860 | .ty = resolved_type, | ||
| 3861 | .val = Value.initTag(.undef), | ||
| 3862 | }); | ||
| 3863 | } | 4659 | } |
| 3864 | // incase rhs is 0, simply return lhs without doing any calculations | 4660 | // incase rhs is 0, simply return lhs without doing any calculations |
| 3865 | // TODO Once division is implemented we should throw an error when dividing by 0. | 4661 | // TODO Once division is implemented we should throw an error when dividing by 0. |
| ... | @@ -3890,6 +4686,13 @@ fn analyzeArithmetic( | ... | @@ -3890,6 +4686,13 @@ fn analyzeArithmetic( |
| 3890 | try Module.floatSub(sema.arena, scalar_type, src, lhs_val, rhs_val); | 4686 | try Module.floatSub(sema.arena, scalar_type, src, lhs_val, rhs_val); |
| 3891 | break :blk val; | 4687 | break :blk val; |
| 3892 | }, | 4688 | }, |
| 4689 | .div => blk: { | ||
| 4690 | const val = if (is_int) | ||
| 4691 | try Module.intDiv(sema.arena, lhs_val, rhs_val) | ||
| 4692 | else | ||
| 4693 | try Module.floatDiv(sema.arena, scalar_type, src, lhs_val, rhs_val); | ||
| 4694 | break :blk val; | ||
| 4695 | }, | ||
| 3893 | .mul => blk: { | 4696 | .mul => blk: { |
| 3894 | const val = if (is_int) | 4697 | const val = if (is_int) |
| 3895 | try Module.intMul(sema.arena, lhs_val, rhs_val) | 4698 | try Module.intMul(sema.arena, lhs_val, rhs_val) |
| ... | @@ -3924,7 +4727,7 @@ fn analyzeArithmetic( | ... | @@ -3924,7 +4727,7 @@ fn analyzeArithmetic( |
| 3924 | return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs); | 4727 | return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs); |
| 3925 | } | 4728 | } |
| 3926 | 4729 | ||
| 3927 | fn zirLoad(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4730 | fn zirLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 3928 | const tracy = trace(@src()); | 4731 | const tracy = trace(@src()); |
| 3929 | defer tracy.end(); | 4732 | defer tracy.end(); |
| 3930 | 4733 | ||
| ... | @@ -3938,72 +4741,90 @@ fn zirLoad(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*I | ... | @@ -3938,72 +4741,90 @@ fn zirLoad(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*I |
| 3938 | fn zirAsm( | 4741 | fn zirAsm( |
| 3939 | sema: *Sema, | 4742 | sema: *Sema, |
| 3940 | block: *Scope.Block, | 4743 | block: *Scope.Block, |
| 3941 | inst: zir.Inst.Index, | 4744 | extended: Zir.Inst.Extended.InstData, |
| 3942 | is_volatile: bool, | ||
| 3943 | ) InnerError!*Inst { | 4745 | ) InnerError!*Inst { |
| 3944 | const tracy = trace(@src()); | 4746 | const tracy = trace(@src()); |
| 3945 | defer tracy.end(); | 4747 | defer tracy.end(); |
| 3946 | 4748 | ||
| 3947 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4749 | const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand); |
| 3948 | const src = inst_data.src(); | 4750 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; |
| 3949 | const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node }; | 4751 | const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = extra.data.src_node }; |
| 3950 | const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node }; | 4752 | const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = extra.data.src_node }; |
| 3951 | const extra = sema.code.extraData(zir.Inst.Asm, inst_data.payload_index); | ||
| 3952 | const return_type = try sema.resolveType(block, ret_ty_src, extra.data.return_type); | ||
| 3953 | const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source); | 4753 | const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source); |
| 4754 | const outputs_len = @truncate(u5, extended.small); | ||
| 4755 | const inputs_len = @truncate(u5, extended.small >> 5); | ||
| 4756 | const clobbers_len = @truncate(u5, extended.small >> 10); | ||
| 4757 | const is_volatile = @truncate(u1, extended.small >> 15) != 0; | ||
| 4758 | |||
| 4759 | if (outputs_len > 1) { | ||
| 4760 | return sema.mod.fail(&block.base, src, "TODO implement Sema for asm with more than 1 output", .{}); | ||
| 4761 | } | ||
| 3954 | 4762 | ||
| 3955 | var extra_i = extra.end; | 4763 | var extra_i = extra.end; |
| 3956 | const Output = struct { name: []const u8, inst: *Inst }; | 4764 | var output_type_bits = extra.data.output_type_bits; |
| 3957 | const output: ?Output = if (extra.data.output != .none) blk: { | 4765 | |
| 3958 | const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]); | 4766 | const Output = struct { constraint: []const u8, ty: Type }; |
| 3959 | extra_i += 1; | 4767 | const output: ?Output = if (outputs_len == 0) null else blk: { |
| 4768 | const output = sema.code.extraData(Zir.Inst.Asm.Output, extra_i); | ||
| 4769 | extra_i = output.end; | ||
| 4770 | |||
| 4771 | const is_type = @truncate(u1, output_type_bits) != 0; | ||
| 4772 | output_type_bits >>= 1; | ||
| 4773 | |||
| 4774 | if (!is_type) { | ||
| 4775 | return sema.mod.fail(&block.base, src, "TODO implement Sema for asm with non `->` output", .{}); | ||
| 4776 | } | ||
| 4777 | |||
| 4778 | const constraint = sema.code.nullTerminatedString(output.data.constraint); | ||
| 3960 | break :blk Output{ | 4779 | break :blk Output{ |
| 3961 | .name = name, | 4780 | .constraint = constraint, |
| 3962 | .inst = try sema.resolveInst(extra.data.output), | 4781 | .ty = try sema.resolveType(block, ret_ty_src, output.data.operand), |
| 3963 | }; | 4782 | }; |
| 3964 | } else null; | 4783 | }; |
| 3965 | 4784 | ||
| 3966 | const args = try sema.arena.alloc(*Inst, extra.data.args_len); | 4785 | const args = try sema.arena.alloc(*Inst, inputs_len); |
| 3967 | const inputs = try sema.arena.alloc([]const u8, extra.data.args_len); | 4786 | const inputs = try sema.arena.alloc([]const u8, inputs_len); |
| 3968 | const clobbers = try sema.arena.alloc([]const u8, extra.data.clobbers_len); | ||
| 3969 | 4787 | ||
| 3970 | for (args) |*arg| { | 4788 | for (args) |*arg, arg_i| { |
| 3971 | arg.* = try sema.resolveInst(@intToEnum(zir.Inst.Ref, sema.code.extra[extra_i])); | 4789 | const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); |
| 3972 | extra_i += 1; | 4790 | extra_i = input.end; |
| 3973 | } | 4791 | |
| 3974 | for (inputs) |*name| { | 4792 | const name = sema.code.nullTerminatedString(input.data.name); |
| 3975 | name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]); | 4793 | _ = name; // TODO: use the name |
| 3976 | extra_i += 1; | 4794 | |
| 4795 | arg.* = try sema.resolveInst(input.data.operand); | ||
| 4796 | inputs[arg_i] = sema.code.nullTerminatedString(input.data.constraint); | ||
| 3977 | } | 4797 | } |
| 4798 | |||
| 4799 | const clobbers = try sema.arena.alloc([]const u8, clobbers_len); | ||
| 3978 | for (clobbers) |*name| { | 4800 | for (clobbers) |*name| { |
| 3979 | name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]); | 4801 | name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]); |
| 3980 | extra_i += 1; | 4802 | extra_i += 1; |
| 3981 | } | 4803 | } |
| 3982 | 4804 | ||
| 3983 | try sema.requireRuntimeBlock(block, src); | 4805 | try sema.requireRuntimeBlock(block, src); |
| 3984 | const asm_tzir = try sema.arena.create(Inst.Assembly); | 4806 | const asm_air = try sema.arena.create(Inst.Assembly); |
| 3985 | asm_tzir.* = .{ | 4807 | asm_air.* = .{ |
| 3986 | .base = .{ | 4808 | .base = .{ |
| 3987 | .tag = .assembly, | 4809 | .tag = .assembly, |
| 3988 | .ty = return_type, | 4810 | .ty = if (output) |o| o.ty else Type.initTag(.void), |
| 3989 | .src = src, | 4811 | .src = src, |
| 3990 | }, | 4812 | }, |
| 3991 | .asm_source = asm_source, | 4813 | .asm_source = asm_source, |
| 3992 | .is_volatile = is_volatile, | 4814 | .is_volatile = is_volatile, |
| 3993 | .output = if (output) |o| o.inst else null, | 4815 | .output_constraint = if (output) |o| o.constraint else null, |
| 3994 | .output_name = if (output) |o| o.name else null, | ||
| 3995 | .inputs = inputs, | 4816 | .inputs = inputs, |
| 3996 | .clobbers = clobbers, | 4817 | .clobbers = clobbers, |
| 3997 | .args = args, | 4818 | .args = args, |
| 3998 | }; | 4819 | }; |
| 3999 | try block.instructions.append(sema.gpa, &asm_tzir.base); | 4820 | try block.instructions.append(sema.gpa, &asm_air.base); |
| 4000 | return &asm_tzir.base; | 4821 | return &asm_air.base; |
| 4001 | } | 4822 | } |
| 4002 | 4823 | ||
| 4003 | fn zirCmp( | 4824 | fn zirCmp( |
| 4004 | sema: *Sema, | 4825 | sema: *Sema, |
| 4005 | block: *Scope.Block, | 4826 | block: *Scope.Block, |
| 4006 | inst: zir.Inst.Index, | 4827 | inst: Zir.Inst.Index, |
| 4007 | op: std.math.CompareOperator, | 4828 | op: std.math.CompareOperator, |
| 4008 | ) InnerError!*Inst { | 4829 | ) InnerError!*Inst { |
| 4009 | const tracy = trace(@src()); | 4830 | const tracy = trace(@src()); |
| ... | @@ -4012,7 +4833,7 @@ fn zirCmp( | ... | @@ -4012,7 +4833,7 @@ fn zirCmp( |
| 4012 | const mod = sema.mod; | 4833 | const mod = sema.mod; |
| 4013 | 4834 | ||
| 4014 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4835 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 4015 | const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data; | 4836 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 4016 | const src: LazySrcLoc = inst_data.src(); | 4837 | const src: LazySrcLoc = inst_data.src(); |
| 4017 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 4838 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 4018 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 4839 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| ... | @@ -4079,8 +4900,18 @@ fn zirCmp( | ... | @@ -4079,8 +4900,18 @@ fn zirCmp( |
| 4079 | 4900 | ||
| 4080 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 4901 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 4081 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 4902 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 4082 | try sema.requireRuntimeBlock(block, src); // TODO try to do it at comptime | 4903 | |
| 4083 | const bool_type = Type.initTag(.bool); // TODO handle vectors | 4904 | if (casted_lhs.value()) |lhs_val| { |
| 4905 | if (casted_rhs.value()) |rhs_val| { | ||
| 4906 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | ||
| 4907 | return sema.mod.constUndef(sema.arena, src, resolved_type); | ||
| 4908 | } | ||
| 4909 | const result = lhs_val.compare(op, rhs_val); | ||
| 4910 | return sema.mod.constBool(sema.arena, src, result); | ||
| 4911 | } | ||
| 4912 | } | ||
| 4913 | |||
| 4914 | try sema.requireRuntimeBlock(block, src); | ||
| 4084 | const tag: Inst.Tag = switch (op) { | 4915 | const tag: Inst.Tag = switch (op) { |
| 4085 | .lt => .cmp_lt, | 4916 | .lt => .cmp_lt, |
| 4086 | .lte => .cmp_lte, | 4917 | .lte => .cmp_lte, |
| ... | @@ -4089,23 +4920,109 @@ fn zirCmp( | ... | @@ -4089,23 +4920,109 @@ fn zirCmp( |
| 4089 | .gt => .cmp_gt, | 4920 | .gt => .cmp_gt, |
| 4090 | .neq => .cmp_neq, | 4921 | .neq => .cmp_neq, |
| 4091 | }; | 4922 | }; |
| 4923 | const bool_type = Type.initTag(.bool); // TODO handle vectors | ||
| 4092 | return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs); | 4924 | return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs); |
| 4093 | } | 4925 | } |
| 4094 | 4926 | ||
| 4095 | fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4927 | fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4096 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4928 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4097 | const src = inst_data.src(); | 4929 | const src = inst_data.src(); |
| 4098 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeInfo", .{}); | 4930 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 4931 | const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); | ||
| 4932 | const target = sema.mod.getTarget(); | ||
| 4933 | const abi_size = operand_ty.abiSize(target); | ||
| 4934 | return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), abi_size); | ||
| 4099 | } | 4935 | } |
| 4100 | 4936 | ||
| 4101 | fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 4937 | fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4102 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4938 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4103 | const src = inst_data.src(); | 4939 | const src = inst_data.src(); |
| 4940 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | ||
| 4941 | const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); | ||
| 4942 | const target = sema.mod.getTarget(); | ||
| 4943 | const bit_size = operand_ty.bitSize(target); | ||
| 4944 | return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size); | ||
| 4945 | } | ||
| 4946 | |||
| 4947 | fn zirThis( | ||
| 4948 | sema: *Sema, | ||
| 4949 | block: *Scope.Block, | ||
| 4950 | extended: Zir.Inst.Extended.InstData, | ||
| 4951 | ) InnerError!*Inst { | ||
| 4952 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 4953 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{}); | ||
| 4954 | } | ||
| 4955 | |||
| 4956 | fn zirRetAddr( | ||
| 4957 | sema: *Sema, | ||
| 4958 | block: *Scope.Block, | ||
| 4959 | extended: Zir.Inst.Extended.InstData, | ||
| 4960 | ) InnerError!*Inst { | ||
| 4961 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 4962 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{}); | ||
| 4963 | } | ||
| 4964 | |||
| 4965 | fn zirBuiltinSrc( | ||
| 4966 | sema: *Sema, | ||
| 4967 | block: *Scope.Block, | ||
| 4968 | extended: Zir.Inst.Extended.InstData, | ||
| 4969 | ) InnerError!*Inst { | ||
| 4970 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 4971 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinSrc", .{}); | ||
| 4972 | } | ||
| 4973 | |||
| 4974 | fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 4975 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 4976 | const src = inst_data.src(); | ||
| 4977 | const ty = try sema.resolveType(block, src, inst_data.operand); | ||
| 4978 | const type_info_ty = try sema.getBuiltinType(block, src, "TypeInfo"); | ||
| 4979 | const target = sema.mod.getTarget(); | ||
| 4980 | |||
| 4981 | switch (ty.zigTypeTag()) { | ||
| 4982 | .Fn => { | ||
| 4983 | const field_values = try sema.arena.alloc(Value, 6); | ||
| 4984 | // calling_convention: CallingConvention, | ||
| 4985 | field_values[0] = try Value.Tag.enum_field_index.create( | ||
| 4986 | sema.arena, | ||
| 4987 | @enumToInt(ty.fnCallingConvention()), | ||
| 4988 | ); | ||
| 4989 | // alignment: comptime_int, | ||
| 4990 | field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)); | ||
| 4991 | // is_generic: bool, | ||
| 4992 | field_values[2] = Value.initTag(.bool_false); // TODO | ||
| 4993 | // is_var_args: bool, | ||
| 4994 | field_values[3] = Value.initTag(.bool_false); // TODO | ||
| 4995 | // return_type: ?type, | ||
| 4996 | field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); | ||
| 4997 | // args: []const FnArg, | ||
| 4998 | field_values[5] = Value.initTag(.null_value); // TODO | ||
| 4999 | |||
| 5000 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 5001 | .ty = type_info_ty, | ||
| 5002 | .val = try Value.Tag.@"union".create(sema.arena, .{ | ||
| 5003 | .tag = try Value.Tag.enum_field_index.create( | ||
| 5004 | sema.arena, | ||
| 5005 | @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn), | ||
| 5006 | ), | ||
| 5007 | .val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr), | ||
| 5008 | }), | ||
| 5009 | }); | ||
| 5010 | }, | ||
| 5011 | else => |t| return sema.mod.fail(&block.base, src, "TODO: implement zirTypeInfo for {s}", .{ | ||
| 5012 | @tagName(t), | ||
| 5013 | }), | ||
| 5014 | } | ||
| 5015 | } | ||
| 5016 | |||
| 5017 | fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5018 | const zir_datas = sema.code.instructions.items(.data); | ||
| 5019 | const inst_data = zir_datas[inst].un_node; | ||
| 5020 | const src = inst_data.src(); | ||
| 4104 | const operand = try sema.resolveInst(inst_data.operand); | 5021 | const operand = try sema.resolveInst(inst_data.operand); |
| 4105 | return sema.mod.constType(sema.arena, src, operand.ty); | 5022 | return sema.mod.constType(sema.arena, src, operand.ty); |
| 4106 | } | 5023 | } |
| 4107 | 5024 | ||
| 4108 | fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5025 | fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4109 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 5026 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4110 | const src = inst_data.src(); | 5027 | const src = inst_data.src(); |
| 4111 | const operand_ptr = try sema.resolveInst(inst_data.operand); | 5028 | const operand_ptr = try sema.resolveInst(inst_data.operand); |
| ... | @@ -4113,16 +5030,31 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -4113,16 +5030,31 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 4113 | return sema.mod.constType(sema.arena, src, elem_ty); | 5030 | return sema.mod.constType(sema.arena, src, elem_ty); |
| 4114 | } | 5031 | } |
| 4115 | 5032 | ||
| 4116 | fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5033 | fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 5034 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5035 | const src = inst_data.src(); | ||
| 5036 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{}); | ||
| 5037 | } | ||
| 5038 | |||
| 5039 | fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5040 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5041 | const src = inst_data.src(); | ||
| 5042 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{}); | ||
| 5043 | } | ||
| 5044 | |||
| 5045 | fn zirTypeofPeer( | ||
| 5046 | sema: *Sema, | ||
| 5047 | block: *Scope.Block, | ||
| 5048 | extended: Zir.Inst.Extended.InstData, | ||
| 5049 | ) InnerError!*Inst { | ||
| 4117 | const tracy = trace(@src()); | 5050 | const tracy = trace(@src()); |
| 4118 | defer tracy.end(); | 5051 | defer tracy.end(); |
| 4119 | 5052 | ||
| 4120 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5053 | const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); |
| 4121 | const src = inst_data.src(); | 5054 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; |
| 4122 | const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index); | 5055 | const args = sema.code.refSlice(extra.end, extended.small); |
| 4123 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | ||
| 4124 | 5056 | ||
| 4125 | const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len); | 5057 | const inst_list = try sema.gpa.alloc(*ir.Inst, args.len); |
| 4126 | defer sema.gpa.free(inst_list); | 5058 | defer sema.gpa.free(inst_list); |
| 4127 | 5059 | ||
| 4128 | for (args) |arg_ref, i| { | 5060 | for (args) |arg_ref, i| { |
| ... | @@ -4133,7 +5065,7 @@ fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr | ... | @@ -4133,7 +5065,7 @@ fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 4133 | return sema.mod.constType(sema.arena, src, result_type); | 5065 | return sema.mod.constType(sema.arena, src, result_type); |
| 4134 | } | 5066 | } |
| 4135 | 5067 | ||
| 4136 | fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5068 | fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4137 | const tracy = trace(@src()); | 5069 | const tracy = trace(@src()); |
| 4138 | defer tracy.end(); | 5070 | defer tracy.end(); |
| 4139 | 5071 | ||
| ... | @@ -4153,7 +5085,7 @@ fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError | ... | @@ -4153,7 +5085,7 @@ fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 4153 | fn zirBoolOp( | 5085 | fn zirBoolOp( |
| 4154 | sema: *Sema, | 5086 | sema: *Sema, |
| 4155 | block: *Scope.Block, | 5087 | block: *Scope.Block, |
| 4156 | inst: zir.Inst.Index, | 5088 | inst: Zir.Inst.Index, |
| 4157 | comptime is_bool_or: bool, | 5089 | comptime is_bool_or: bool, |
| 4158 | ) InnerError!*Inst { | 5090 | ) InnerError!*Inst { |
| 4159 | const tracy = trace(@src()); | 5091 | const tracy = trace(@src()); |
| ... | @@ -4184,7 +5116,7 @@ fn zirBoolOp( | ... | @@ -4184,7 +5116,7 @@ fn zirBoolOp( |
| 4184 | fn zirBoolBr( | 5116 | fn zirBoolBr( |
| 4185 | sema: *Sema, | 5117 | sema: *Sema, |
| 4186 | parent_block: *Scope.Block, | 5118 | parent_block: *Scope.Block, |
| 4187 | inst: zir.Inst.Index, | 5119 | inst: Zir.Inst.Index, |
| 4188 | is_bool_or: bool, | 5120 | is_bool_or: bool, |
| 4189 | ) InnerError!*Inst { | 5121 | ) InnerError!*Inst { |
| 4190 | const tracy = trace(@src()); | 5122 | const tracy = trace(@src()); |
| ... | @@ -4194,7 +5126,7 @@ fn zirBoolBr( | ... | @@ -4194,7 +5126,7 @@ fn zirBoolBr( |
| 4194 | const inst_data = datas[inst].bool_br; | 5126 | const inst_data = datas[inst].bool_br; |
| 4195 | const src: LazySrcLoc = .unneeded; | 5127 | const src: LazySrcLoc = .unneeded; |
| 4196 | const lhs = try sema.resolveInst(inst_data.lhs); | 5128 | const lhs = try sema.resolveInst(inst_data.lhs); |
| 4197 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 5129 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 4198 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 5130 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 4199 | 5131 | ||
| 4200 | if (try sema.resolveDefinedValue(parent_block, src, lhs)) |lhs_val| { | 5132 | if (try sema.resolveDefinedValue(parent_block, src, lhs)) |lhs_val| { |
| ... | @@ -4238,9 +5170,9 @@ fn zirBoolBr( | ... | @@ -4238,9 +5170,9 @@ fn zirBoolBr( |
| 4238 | const rhs_result = try sema.resolveBody(rhs_block, body); | 5170 | const rhs_result = try sema.resolveBody(rhs_block, body); |
| 4239 | _ = try rhs_block.addBr(src, block_inst, rhs_result); | 5171 | _ = try rhs_block.addBr(src, block_inst, rhs_result); |
| 4240 | 5172 | ||
| 4241 | const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) }; | 5173 | const air_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) }; |
| 4242 | const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, else_block.instructions.items) }; | 5174 | const air_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, else_block.instructions.items) }; |
| 4243 | _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body); | 5175 | _ = try child_block.addCondBr(src, lhs, air_then_body, air_else_body); |
| 4244 | 5176 | ||
| 4245 | block_inst.body = .{ | 5177 | block_inst.body = .{ |
| 4246 | .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items), | 5178 | .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items), |
| ... | @@ -4252,7 +5184,7 @@ fn zirBoolBr( | ... | @@ -4252,7 +5184,7 @@ fn zirBoolBr( |
| 4252 | fn zirIsNull( | 5184 | fn zirIsNull( |
| 4253 | sema: *Sema, | 5185 | sema: *Sema, |
| 4254 | block: *Scope.Block, | 5186 | block: *Scope.Block, |
| 4255 | inst: zir.Inst.Index, | 5187 | inst: Zir.Inst.Index, |
| 4256 | invert_logic: bool, | 5188 | invert_logic: bool, |
| 4257 | ) InnerError!*Inst { | 5189 | ) InnerError!*Inst { |
| 4258 | const tracy = trace(@src()); | 5190 | const tracy = trace(@src()); |
| ... | @@ -4267,7 +5199,7 @@ fn zirIsNull( | ... | @@ -4267,7 +5199,7 @@ fn zirIsNull( |
| 4267 | fn zirIsNullPtr( | 5199 | fn zirIsNullPtr( |
| 4268 | sema: *Sema, | 5200 | sema: *Sema, |
| 4269 | block: *Scope.Block, | 5201 | block: *Scope.Block, |
| 4270 | inst: zir.Inst.Index, | 5202 | inst: Zir.Inst.Index, |
| 4271 | invert_logic: bool, | 5203 | invert_logic: bool, |
| 4272 | ) InnerError!*Inst { | 5204 | ) InnerError!*Inst { |
| 4273 | const tracy = trace(@src()); | 5205 | const tracy = trace(@src()); |
| ... | @@ -4280,7 +5212,7 @@ fn zirIsNullPtr( | ... | @@ -4280,7 +5212,7 @@ fn zirIsNullPtr( |
| 4280 | return sema.analyzeIsNull(block, src, loaded, invert_logic); | 5212 | return sema.analyzeIsNull(block, src, loaded, invert_logic); |
| 4281 | } | 5213 | } |
| 4282 | 5214 | ||
| 4283 | fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5215 | fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4284 | const tracy = trace(@src()); | 5216 | const tracy = trace(@src()); |
| 4285 | defer tracy.end(); | 5217 | defer tracy.end(); |
| 4286 | 5218 | ||
| ... | @@ -4289,7 +5221,7 @@ fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* | ... | @@ -4289,7 +5221,7 @@ fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!* |
| 4289 | return sema.analyzeIsErr(block, inst_data.src(), operand); | 5221 | return sema.analyzeIsErr(block, inst_data.src(), operand); |
| 4290 | } | 5222 | } |
| 4291 | 5223 | ||
| 4292 | fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5224 | fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { |
| 4293 | const tracy = trace(@src()); | 5225 | const tracy = trace(@src()); |
| 4294 | defer tracy.end(); | 5226 | defer tracy.end(); |
| 4295 | 5227 | ||
| ... | @@ -4303,15 +5235,15 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro | ... | @@ -4303,15 +5235,15 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro |
| 4303 | fn zirCondbr( | 5235 | fn zirCondbr( |
| 4304 | sema: *Sema, | 5236 | sema: *Sema, |
| 4305 | parent_block: *Scope.Block, | 5237 | parent_block: *Scope.Block, |
| 4306 | inst: zir.Inst.Index, | 5238 | inst: Zir.Inst.Index, |
| 4307 | ) InnerError!zir.Inst.Index { | 5239 | ) InnerError!Zir.Inst.Index { |
| 4308 | const tracy = trace(@src()); | 5240 | const tracy = trace(@src()); |
| 4309 | defer tracy.end(); | 5241 | defer tracy.end(); |
| 4310 | 5242 | ||
| 4311 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5243 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 4312 | const src = inst_data.src(); | 5244 | const src = inst_data.src(); |
| 4313 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; | 5245 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; |
| 4314 | const extra = sema.code.extraData(zir.Inst.CondBr, inst_data.payload_index); | 5246 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); |
| 4315 | 5247 | ||
| 4316 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; | 5248 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; |
| 4317 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 5249 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| ... | @@ -4329,22 +5261,22 @@ fn zirCondbr( | ... | @@ -4329,22 +5261,22 @@ fn zirCondbr( |
| 4329 | defer sub_block.instructions.deinit(sema.gpa); | 5261 | defer sub_block.instructions.deinit(sema.gpa); |
| 4330 | 5262 | ||
| 4331 | _ = try sema.analyzeBody(&sub_block, then_body); | 5263 | _ = try sema.analyzeBody(&sub_block, then_body); |
| 4332 | const tzir_then_body: ir.Body = .{ | 5264 | const air_then_body: ir.Body = .{ |
| 4333 | .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items), | 5265 | .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items), |
| 4334 | }; | 5266 | }; |
| 4335 | 5267 | ||
| 4336 | sub_block.instructions.shrinkRetainingCapacity(0); | 5268 | sub_block.instructions.shrinkRetainingCapacity(0); |
| 4337 | 5269 | ||
| 4338 | _ = try sema.analyzeBody(&sub_block, else_body); | 5270 | _ = try sema.analyzeBody(&sub_block, else_body); |
| 4339 | const tzir_else_body: ir.Body = .{ | 5271 | const air_else_body: ir.Body = .{ |
| 4340 | .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items), | 5272 | .instructions = try sema.arena.dupe(*Inst, sub_block.instructions.items), |
| 4341 | }; | 5273 | }; |
| 4342 | 5274 | ||
| 4343 | _ = try parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body); | 5275 | _ = try parent_block.addCondBr(src, cond, air_then_body, air_else_body); |
| 4344 | return always_noreturn; | 5276 | return always_noreturn; |
| 4345 | } | 5277 | } |
| 4346 | 5278 | ||
| 4347 | fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { | 5279 | fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { |
| 4348 | const tracy = trace(@src()); | 5280 | const tracy = trace(@src()); |
| 4349 | defer tracy.end(); | 5281 | defer tracy.end(); |
| 4350 | 5282 | ||
| ... | @@ -4364,9 +5296,9 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE | ... | @@ -4364,9 +5296,9 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 4364 | fn zirRetTok( | 5296 | fn zirRetTok( |
| 4365 | sema: *Sema, | 5297 | sema: *Sema, |
| 4366 | block: *Scope.Block, | 5298 | block: *Scope.Block, |
| 4367 | inst: zir.Inst.Index, | 5299 | inst: Zir.Inst.Index, |
| 4368 | need_coercion: bool, | 5300 | need_coercion: bool, |
| 4369 | ) InnerError!zir.Inst.Index { | 5301 | ) InnerError!Zir.Inst.Index { |
| 4370 | const tracy = trace(@src()); | 5302 | const tracy = trace(@src()); |
| 4371 | defer tracy.end(); | 5303 | defer tracy.end(); |
| 4372 | 5304 | ||
| ... | @@ -4377,7 +5309,7 @@ fn zirRetTok( | ... | @@ -4377,7 +5309,7 @@ fn zirRetTok( |
| 4377 | return sema.analyzeRet(block, operand, src, need_coercion); | 5309 | return sema.analyzeRet(block, operand, src, need_coercion); |
| 4378 | } | 5310 | } |
| 4379 | 5311 | ||
| 4380 | fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index { | 5312 | fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { |
| 4381 | const tracy = trace(@src()); | 5313 | const tracy = trace(@src()); |
| 4382 | defer tracy.end(); | 5314 | defer tracy.end(); |
| 4383 | 5315 | ||
| ... | @@ -4394,7 +5326,7 @@ fn analyzeRet( | ... | @@ -4394,7 +5326,7 @@ fn analyzeRet( |
| 4394 | operand: *Inst, | 5326 | operand: *Inst, |
| 4395 | src: LazySrcLoc, | 5327 | src: LazySrcLoc, |
| 4396 | need_coercion: bool, | 5328 | need_coercion: bool, |
| 4397 | ) InnerError!zir.Inst.Index { | 5329 | ) InnerError!Zir.Inst.Index { |
| 4398 | if (block.inlining) |inlining| { | 5330 | if (block.inlining) |inlining| { |
| 4399 | // We are inlining a function call; rewrite the `ret` as a `break`. | 5331 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 4400 | try inlining.merges.results.append(sema.gpa, operand); | 5332 | try inlining.merges.results.append(sema.gpa, operand); |
| ... | @@ -4404,7 +5336,7 @@ fn analyzeRet( | ... | @@ -4404,7 +5336,7 @@ fn analyzeRet( |
| 4404 | 5336 | ||
| 4405 | if (need_coercion) { | 5337 | if (need_coercion) { |
| 4406 | if (sema.func) |func| { | 5338 | if (sema.func) |func| { |
| 4407 | const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty; | 5339 | const fn_ty = func.owner_decl.ty; |
| 4408 | const fn_ret_ty = fn_ty.fnReturnType(); | 5340 | const fn_ret_ty = fn_ty.fnReturnType(); |
| 4409 | const casted_operand = try sema.coerce(block, fn_ret_ty, operand, src); | 5341 | const casted_operand = try sema.coerce(block, fn_ret_ty, operand, src); |
| 4410 | if (fn_ret_ty.zigTypeTag() == .Void) | 5342 | if (fn_ret_ty.zigTypeTag() == .Void) |
| ... | @@ -4418,113 +5350,762 @@ fn analyzeRet( | ... | @@ -4418,113 +5350,762 @@ fn analyzeRet( |
| 4418 | return always_noreturn; | 5350 | return always_noreturn; |
| 4419 | } | 5351 | } |
| 4420 | 5352 | ||
| 4421 | fn floatOpAllowed(tag: zir.Inst.Tag) bool { | 5353 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { |
| 4422 | // extend this swich as additional operators are implemented | 5354 | // extend this swich as additional operators are implemented |
| 4423 | return switch (tag) { | 5355 | return switch (tag) { |
| 4424 | .add, .sub => true, | 5356 | .add, .sub => true, |
| 4425 | else => false, | 5357 | else => false, |
| 4426 | }; | 5358 | }; |
| 4427 | } | 5359 | } |
| 5360 | |||
| 5361 | fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5362 | const tracy = trace(@src()); | ||
| 5363 | defer tracy.end(); | ||
| 5364 | |||
| 5365 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple; | ||
| 5366 | const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type); | ||
| 5367 | const ty = try sema.mod.ptrType( | ||
| 5368 | sema.arena, | ||
| 5369 | elem_type, | ||
| 5370 | null, | ||
| 5371 | 0, | ||
| 5372 | 0, | ||
| 5373 | 0, | ||
| 5374 | inst_data.is_mutable, | ||
| 5375 | inst_data.is_allowzero, | ||
| 5376 | inst_data.is_volatile, | ||
| 5377 | inst_data.size, | ||
| 5378 | ); | ||
| 5379 | return sema.mod.constType(sema.arena, .unneeded, ty); | ||
| 5380 | } | ||
| 5381 | |||
| 5382 | fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5383 | const tracy = trace(@src()); | ||
| 5384 | defer tracy.end(); | ||
| 5385 | |||
| 5386 | const src: LazySrcLoc = .unneeded; | ||
| 5387 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; | ||
| 5388 | const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); | ||
| 5389 | |||
| 5390 | var extra_i = extra.end; | ||
| 5391 | |||
| 5392 | const sentinel = if (inst_data.flags.has_sentinel) blk: { | ||
| 5393 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 5394 | extra_i += 1; | ||
| 5395 | break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val; | ||
| 5396 | } else null; | ||
| 5397 | |||
| 5398 | const abi_align = if (inst_data.flags.has_align) blk: { | ||
| 5399 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 5400 | extra_i += 1; | ||
| 5401 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32); | ||
| 5402 | } else 0; | ||
| 5403 | |||
| 5404 | const bit_start = if (inst_data.flags.has_bit_range) blk: { | ||
| 5405 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 5406 | extra_i += 1; | ||
| 5407 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16); | ||
| 5408 | } else 0; | ||
| 5409 | |||
| 5410 | const bit_end = if (inst_data.flags.has_bit_range) blk: { | ||
| 5411 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 5412 | extra_i += 1; | ||
| 5413 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16); | ||
| 5414 | } else 0; | ||
| 5415 | |||
| 5416 | if (bit_end != 0 and bit_start >= bit_end * 8) | ||
| 5417 | return sema.mod.fail(&block.base, src, "bit offset starts after end of host integer", .{}); | ||
| 5418 | |||
| 5419 | const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type); | ||
| 5420 | |||
| 5421 | const ty = try sema.mod.ptrType( | ||
| 5422 | sema.arena, | ||
| 5423 | elem_type, | ||
| 5424 | sentinel, | ||
| 5425 | abi_align, | ||
| 5426 | bit_start, | ||
| 5427 | bit_end, | ||
| 5428 | inst_data.flags.is_mutable, | ||
| 5429 | inst_data.flags.is_allowzero, | ||
| 5430 | inst_data.flags.is_volatile, | ||
| 5431 | inst_data.size, | ||
| 5432 | ); | ||
| 5433 | return sema.mod.constType(sema.arena, src, ty); | ||
| 5434 | } | ||
| 5435 | |||
| 5436 | fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5437 | const tracy = trace(@src()); | ||
| 5438 | defer tracy.end(); | ||
| 5439 | |||
| 5440 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5441 | const src = inst_data.src(); | ||
| 5442 | const struct_type = try sema.resolveType(block, src, inst_data.operand); | ||
| 5443 | |||
| 5444 | return sema.mod.constInst(sema.arena, src, .{ | ||
| 5445 | .ty = struct_type, | ||
| 5446 | .val = Value.initTag(.empty_struct_value), | ||
| 5447 | }); | ||
| 5448 | } | ||
| 5449 | |||
| 5450 | fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5451 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5452 | const src = inst_data.src(); | ||
| 5453 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnionInitPtr", .{}); | ||
| 5454 | } | ||
| 5455 | |||
| 5456 | fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst { | ||
| 5457 | const mod = sema.mod; | ||
| 5458 | const gpa = sema.gpa; | ||
| 5459 | const zir_datas = sema.code.instructions.items(.data); | ||
| 5460 | const inst_data = zir_datas[inst].pl_node; | ||
| 5461 | const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); | ||
| 5462 | const src = inst_data.src(); | ||
| 5463 | |||
| 5464 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; | ||
| 5465 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; | ||
| 5466 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; | ||
| 5467 | const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type); | ||
| 5468 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type); | ||
| 5469 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 5470 | |||
| 5471 | // Maps field index to field_type index of where it was already initialized. | ||
| 5472 | // For making sure all fields are accounted for and no fields are duplicated. | ||
| 5473 | const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.entries.items.len); | ||
| 5474 | defer gpa.free(found_fields); | ||
| 5475 | mem.set(Zir.Inst.Index, found_fields, 0); | ||
| 5476 | |||
| 5477 | // The init values to use for the struct instance. | ||
| 5478 | const field_inits = try gpa.alloc(*ir.Inst, struct_obj.fields.entries.items.len); | ||
| 5479 | defer gpa.free(field_inits); | ||
| 5480 | |||
| 5481 | var field_i: u32 = 0; | ||
| 5482 | var extra_index = extra.end; | ||
| 5483 | |||
| 5484 | while (field_i < extra.data.fields_len) : (field_i += 1) { | ||
| 5485 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); | ||
| 5486 | extra_index = item.end; | ||
| 5487 | |||
| 5488 | const field_type_data = zir_datas[item.data.field_type].pl_node; | ||
| 5489 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node }; | ||
| 5490 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; | ||
| 5491 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); | ||
| 5492 | const field_index = struct_obj.fields.getIndex(field_name) orelse | ||
| 5493 | return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name); | ||
| 5494 | if (found_fields[field_index] != 0) { | ||
| 5495 | const other_field_type = found_fields[field_index]; | ||
| 5496 | const other_field_type_data = zir_datas[other_field_type].pl_node; | ||
| 5497 | const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node }; | ||
| 5498 | const msg = msg: { | ||
| 5499 | const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{}); | ||
| 5500 | errdefer msg.destroy(gpa); | ||
| 5501 | try mod.errNote(&block.base, other_field_src, msg, "other field here", .{}); | ||
| 5502 | break :msg msg; | ||
| 5503 | }; | ||
| 5504 | return mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 5505 | } | ||
| 5506 | found_fields[field_index] = item.data.field_type; | ||
| 5507 | field_inits[field_index] = try sema.resolveInst(item.data.init); | ||
| 5508 | } | ||
| 5509 | |||
| 5510 | var root_msg: ?*Module.ErrorMsg = null; | ||
| 5511 | |||
| 5512 | for (found_fields) |field_type_inst, i| { | ||
| 5513 | if (field_type_inst != 0) continue; | ||
| 5514 | |||
| 5515 | // Check if the field has a default init. | ||
| 5516 | const field = struct_obj.fields.entries.items[i].value; | ||
| 5517 | if (field.default_val.tag() == .unreachable_value) { | ||
| 5518 | const field_name = struct_obj.fields.entries.items[i].key; | ||
| 5519 | const template = "missing struct field: {s}"; | ||
| 5520 | const args = .{field_name}; | ||
| 5521 | if (root_msg) |msg| { | ||
| 5522 | try mod.errNote(&block.base, src, msg, template, args); | ||
| 5523 | } else { | ||
| 5524 | root_msg = try mod.errMsg(&block.base, src, template, args); | ||
| 5525 | } | ||
| 5526 | } else { | ||
| 5527 | field_inits[i] = try mod.constInst(sema.arena, src, .{ | ||
| 5528 | .ty = field.ty, | ||
| 5529 | .val = field.default_val, | ||
| 5530 | }); | ||
| 5531 | } | ||
| 5532 | } | ||
| 5533 | if (root_msg) |msg| { | ||
| 5534 | const fqn = try struct_obj.getFullyQualifiedName(gpa); | ||
| 5535 | defer gpa.free(fqn); | ||
| 5536 | try mod.errNoteNonLazy( | ||
| 5537 | struct_obj.srcLoc(), | ||
| 5538 | msg, | ||
| 5539 | "struct '{s}' declared here", | ||
| 5540 | .{fqn}, | ||
| 5541 | ); | ||
| 5542 | return mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 5543 | } | ||
| 5544 | |||
| 5545 | const is_comptime = for (field_inits) |field_init| { | ||
| 5546 | if (field_init.value() == null) { | ||
| 5547 | break false; | ||
| 5548 | } | ||
| 5549 | } else true; | ||
| 5550 | |||
| 5551 | if (is_comptime) { | ||
| 5552 | const values = try sema.arena.alloc(Value, field_inits.len); | ||
| 5553 | for (field_inits) |field_init, i| { | ||
| 5554 | values[i] = field_init.value().?; | ||
| 5555 | } | ||
| 5556 | return mod.constInst(sema.arena, src, .{ | ||
| 5557 | .ty = struct_ty, | ||
| 5558 | .val = try Value.Tag.@"struct".create(sema.arena, values.ptr), | ||
| 5559 | }); | ||
| 5560 | } | ||
| 5561 | |||
| 5562 | return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{}); | ||
| 5563 | } | ||
| 5564 | |||
| 5565 | fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst { | ||
| 5566 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5567 | const src = inst_data.src(); | ||
| 5568 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInitAnon", .{}); | ||
| 5569 | } | ||
| 5570 | |||
| 5571 | fn zirArrayInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst { | ||
| 5572 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5573 | const src = inst_data.src(); | ||
| 5574 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirArrayInit", .{}); | ||
| 5575 | } | ||
| 5576 | |||
| 5577 | fn zirArrayInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) InnerError!*Inst { | ||
| 5578 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5579 | const src = inst_data.src(); | ||
| 5580 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirArrayInitAnon", .{}); | ||
| 5581 | } | ||
| 5582 | |||
| 5583 | fn zirFieldTypeRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5584 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5585 | const src = inst_data.src(); | ||
| 5586 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldTypeRef", .{}); | ||
| 5587 | } | ||
| 5588 | |||
| 5589 | fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5590 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5591 | const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; | ||
| 5592 | const src = inst_data.src(); | ||
| 5593 | const field_name = sema.code.nullTerminatedString(extra.name_start); | ||
| 5594 | const unresolved_struct_type = try sema.resolveType(block, src, extra.container_type); | ||
| 5595 | if (unresolved_struct_type.zigTypeTag() != .Struct) { | ||
| 5596 | return sema.mod.fail(&block.base, src, "expected struct; found '{}'", .{ | ||
| 5597 | unresolved_struct_type, | ||
| 5598 | }); | ||
| 5599 | } | ||
| 5600 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type); | ||
| 5601 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 5602 | const field = struct_obj.fields.get(field_name) orelse | ||
| 5603 | return sema.failWithBadFieldAccess(block, struct_obj, src, field_name); | ||
| 5604 | return sema.mod.constType(sema.arena, src, field.ty); | ||
| 5605 | } | ||
| 5606 | |||
| 5607 | fn zirErrorReturnTrace( | ||
| 5608 | sema: *Sema, | ||
| 5609 | block: *Scope.Block, | ||
| 5610 | extended: Zir.Inst.Extended.InstData, | ||
| 5611 | ) InnerError!*Inst { | ||
| 5612 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 5613 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorReturnTrace", .{}); | ||
| 5614 | } | ||
| 5615 | |||
| 5616 | fn zirFrame( | ||
| 5617 | sema: *Sema, | ||
| 5618 | block: *Scope.Block, | ||
| 5619 | extended: Zir.Inst.Extended.InstData, | ||
| 5620 | ) InnerError!*Inst { | ||
| 5621 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 5622 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrame", .{}); | ||
| 5623 | } | ||
| 5624 | |||
| 5625 | fn zirFrameAddress( | ||
| 5626 | sema: *Sema, | ||
| 5627 | block: *Scope.Block, | ||
| 5628 | extended: Zir.Inst.Extended.InstData, | ||
| 5629 | ) InnerError!*Inst { | ||
| 5630 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 5631 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameAddress", .{}); | ||
| 5632 | } | ||
| 5633 | |||
| 5634 | fn zirAlignOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5635 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5636 | const src = inst_data.src(); | ||
| 5637 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignOf", .{}); | ||
| 5638 | } | ||
| 5639 | |||
| 5640 | fn zirBoolToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5641 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5642 | const src = inst_data.src(); | ||
| 5643 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirBoolToInt", .{}); | ||
| 5644 | } | ||
| 5645 | |||
| 5646 | fn zirEmbedFile(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5647 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5648 | const src = inst_data.src(); | ||
| 5649 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirEmbedFile", .{}); | ||
| 5650 | } | ||
| 5651 | |||
| 5652 | fn zirErrorName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5653 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5654 | const src = inst_data.src(); | ||
| 5655 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorName", .{}); | ||
| 5656 | } | ||
| 5657 | |||
| 5658 | fn zirUnaryMath(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5659 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5660 | const src = inst_data.src(); | ||
| 5661 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnaryMath", .{}); | ||
| 5662 | } | ||
| 5663 | |||
| 5664 | fn zirTagName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5665 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5666 | const src = inst_data.src(); | ||
| 5667 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirTagName", .{}); | ||
| 5668 | } | ||
| 5669 | |||
| 5670 | fn zirReify(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5671 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5672 | const src = inst_data.src(); | ||
| 5673 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify", .{}); | ||
| 5674 | } | ||
| 5675 | |||
| 5676 | fn zirTypeName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5677 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5678 | const src = inst_data.src(); | ||
| 5679 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirTypeName", .{}); | ||
| 5680 | } | ||
| 5681 | |||
| 5682 | fn zirFrameType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5683 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5684 | const src = inst_data.src(); | ||
| 5685 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameType", .{}); | ||
| 5686 | } | ||
| 5687 | |||
| 5688 | fn zirFrameSize(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5689 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5690 | const src = inst_data.src(); | ||
| 5691 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameSize", .{}); | ||
| 5692 | } | ||
| 5693 | |||
| 5694 | fn zirFloatToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5695 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5696 | const src = inst_data.src(); | ||
| 5697 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFloatToInt", .{}); | ||
| 5698 | } | ||
| 5699 | |||
| 5700 | fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5701 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5702 | const src = inst_data.src(); | ||
| 5703 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToFloat", .{}); | ||
| 5704 | } | ||
| 5705 | |||
| 5706 | fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5707 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5708 | const src = inst_data.src(); | ||
| 5709 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{}); | ||
| 5710 | } | ||
| 5711 | |||
| 5712 | fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5713 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5714 | const src = inst_data.src(); | ||
| 5715 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrSetCast", .{}); | ||
| 5716 | } | ||
| 5717 | |||
| 5718 | fn zirPtrCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5719 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5720 | const src = inst_data.src(); | ||
| 5721 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirPtrCast", .{}); | ||
| 5722 | } | ||
| 5723 | |||
| 5724 | fn zirTruncate(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5725 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5726 | const src = inst_data.src(); | ||
| 5727 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirTruncate", .{}); | ||
| 5728 | } | ||
| 5729 | |||
| 5730 | fn zirAlignCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5731 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5732 | const src = inst_data.src(); | ||
| 5733 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignCast", .{}); | ||
| 5734 | } | ||
| 5735 | |||
| 5736 | fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5737 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5738 | const src = inst_data.src(); | ||
| 5739 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirClz", .{}); | ||
| 5740 | } | ||
| 5741 | |||
| 5742 | fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5743 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5744 | const src = inst_data.src(); | ||
| 5745 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirCtz", .{}); | ||
| 5746 | } | ||
| 5747 | |||
| 5748 | fn zirPopCount(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5749 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5750 | const src = inst_data.src(); | ||
| 5751 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirPopCount", .{}); | ||
| 5752 | } | ||
| 5753 | |||
| 5754 | fn zirByteSwap(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5755 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5756 | const src = inst_data.src(); | ||
| 5757 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteSwap", .{}); | ||
| 5758 | } | ||
| 5759 | |||
| 5760 | fn zirBitReverse(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5761 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5762 | const src = inst_data.src(); | ||
| 5763 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitReverse", .{}); | ||
| 5764 | } | ||
| 5765 | |||
| 5766 | fn zirDivExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5767 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5768 | const src = inst_data.src(); | ||
| 5769 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivExact", .{}); | ||
| 5770 | } | ||
| 5771 | |||
| 5772 | fn zirDivFloor(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5773 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5774 | const src = inst_data.src(); | ||
| 5775 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivFloor", .{}); | ||
| 5776 | } | ||
| 5777 | |||
| 5778 | fn zirDivTrunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5779 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5780 | const src = inst_data.src(); | ||
| 5781 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivTrunc", .{}); | ||
| 5782 | } | ||
| 5783 | |||
| 5784 | fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5785 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5786 | const src = inst_data.src(); | ||
| 5787 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMod", .{}); | ||
| 5788 | } | ||
| 5789 | |||
| 5790 | fn zirRem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5791 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5792 | const src = inst_data.src(); | ||
| 5793 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirRem", .{}); | ||
| 5794 | } | ||
| 5795 | |||
| 5796 | fn zirShlExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5797 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5798 | const src = inst_data.src(); | ||
| 5799 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirShlExact", .{}); | ||
| 5800 | } | ||
| 5801 | |||
| 5802 | fn zirShrExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5803 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5804 | const src = inst_data.src(); | ||
| 5805 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirShrExact", .{}); | ||
| 5806 | } | ||
| 5807 | |||
| 5808 | fn zirBitOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5809 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5810 | const src = inst_data.src(); | ||
| 5811 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitOffsetOf", .{}); | ||
| 5812 | } | ||
| 5813 | |||
| 5814 | fn zirByteOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5815 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5816 | const src = inst_data.src(); | ||
| 5817 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteOffsetOf", .{}); | ||
| 5818 | } | ||
| 5819 | |||
| 5820 | fn zirCmpxchg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5821 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5822 | const src = inst_data.src(); | ||
| 5823 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirCmpxchg", .{}); | ||
| 5824 | } | ||
| 5825 | |||
| 5826 | fn zirSplat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5827 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5828 | const src = inst_data.src(); | ||
| 5829 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirSplat", .{}); | ||
| 5830 | } | ||
| 5831 | |||
| 5832 | fn zirReduce(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5833 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5834 | const src = inst_data.src(); | ||
| 5835 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirReduce", .{}); | ||
| 5836 | } | ||
| 5837 | |||
| 5838 | fn zirShuffle(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5839 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5840 | const src = inst_data.src(); | ||
| 5841 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirShuffle", .{}); | ||
| 5842 | } | ||
| 5843 | |||
| 5844 | fn zirAtomicLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5845 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5846 | const src = inst_data.src(); | ||
| 5847 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicLoad", .{}); | ||
| 5848 | } | ||
| 5849 | |||
| 5850 | fn zirAtomicRmw(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5851 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5852 | const src = inst_data.src(); | ||
| 5853 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicRmw", .{}); | ||
| 5854 | } | ||
| 5855 | |||
| 5856 | fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5857 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5858 | const src = inst_data.src(); | ||
| 5859 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicStore", .{}); | ||
| 5860 | } | ||
| 5861 | |||
| 5862 | fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5863 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5864 | const src = inst_data.src(); | ||
| 5865 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMulAdd", .{}); | ||
| 5866 | } | ||
| 5867 | |||
| 5868 | fn zirBuiltinCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5869 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5870 | const src = inst_data.src(); | ||
| 5871 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinCall", .{}); | ||
| 5872 | } | ||
| 5873 | |||
| 5874 | fn zirFieldPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5875 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5876 | const src = inst_data.src(); | ||
| 5877 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldPtrType", .{}); | ||
| 5878 | } | ||
| 5879 | |||
| 5880 | fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5881 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5882 | const src = inst_data.src(); | ||
| 5883 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{}); | ||
| 5884 | } | ||
| 5885 | |||
| 5886 | fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5887 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5888 | const src = inst_data.src(); | ||
| 5889 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemcpy", .{}); | ||
| 5890 | } | ||
| 5891 | |||
| 5892 | fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5893 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5894 | const src = inst_data.src(); | ||
| 5895 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{}); | ||
| 5896 | } | ||
| 5897 | |||
| 5898 | fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5899 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5900 | const src = inst_data.src(); | ||
| 5901 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinAsyncCall", .{}); | ||
| 5902 | } | ||
| 5903 | |||
| 5904 | fn zirResume(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { | ||
| 5905 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5906 | const src = inst_data.src(); | ||
| 5907 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirResume", .{}); | ||
| 5908 | } | ||
| 5909 | |||
| 5910 | fn zirAwait( | ||
| 5911 | sema: *Sema, | ||
| 5912 | block: *Scope.Block, | ||
| 5913 | inst: Zir.Inst.Index, | ||
| 5914 | is_nosuspend: bool, | ||
| 5915 | ) InnerError!*Inst { | ||
| 5916 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | ||
| 5917 | const src = inst_data.src(); | ||
| 5918 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirAwait", .{}); | ||
| 5919 | } | ||
| 5920 | |||
| 5921 | fn zirVarExtended( | ||
| 5922 | sema: *Sema, | ||
| 5923 | block: *Scope.Block, | ||
| 5924 | extended: Zir.Inst.Extended.InstData, | ||
| 5925 | ) InnerError!*Inst { | ||
| 5926 | const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); | ||
| 5927 | const src = sema.src; | ||
| 5928 | const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align | ||
| 5929 | const ty_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at type | ||
| 5930 | const mut_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at mut token | ||
| 5931 | const init_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at init expr | ||
| 5932 | const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small); | ||
| 5933 | const var_ty = try sema.resolveType(block, ty_src, extra.data.var_type); | ||
| 5934 | |||
| 5935 | var extra_index: usize = extra.end; | ||
| 5936 | |||
| 5937 | const lib_name: ?[]const u8 = if (small.has_lib_name) blk: { | ||
| 5938 | const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); | ||
| 5939 | extra_index += 1; | ||
| 5940 | break :blk lib_name; | ||
| 5941 | } else null; | ||
| 5942 | |||
| 5943 | // ZIR supports encoding this information but it is not used; the information | ||
| 5944 | // is encoded via the Decl entry. | ||
| 5945 | assert(!small.has_align); | ||
| 5946 | //const align_val: Value = if (small.has_align) blk: { | ||
| 5947 | // const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 5948 | // extra_index += 1; | ||
| 5949 | // const align_tv = try sema.resolveInstConst(block, align_src, align_ref); | ||
| 5950 | // break :blk align_tv.val; | ||
| 5951 | //} else Value.initTag(.null_value); | ||
| 5952 | |||
| 5953 | const init_val: Value = if (small.has_init) blk: { | ||
| 5954 | const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 5955 | extra_index += 1; | ||
| 5956 | const init_tv = try sema.resolveInstConst(block, init_src, init_ref); | ||
| 5957 | break :blk init_tv.val; | ||
| 5958 | } else Value.initTag(.unreachable_value); | ||
| 4428 | 5959 | ||
| 4429 | fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5960 | if (!var_ty.isValidVarType(small.is_extern)) { |
| 4430 | const tracy = trace(@src()); | 5961 | return sema.mod.fail(&block.base, mut_src, "variable of type '{}' must be const", .{ |
| 4431 | defer tracy.end(); | 5962 | var_ty, |
| 5963 | }); | ||
| 5964 | } | ||
| 4432 | 5965 | ||
| 4433 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple; | 5966 | if (lib_name != null) { |
| 4434 | const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type); | 5967 | // Look at the sema code for functions which has this logic, it just needs to |
| 4435 | const ty = try sema.mod.ptrType( | 5968 | // be extracted and shared by both var and func |
| 4436 | sema.arena, | 5969 | return sema.mod.fail(&block.base, src, "TODO: handle var with lib_name in Sema", .{}); |
| 4437 | elem_type, | 5970 | } |
| 4438 | null, | 5971 | |
| 4439 | 0, | 5972 | const new_var = try sema.gpa.create(Module.Var); |
| 4440 | 0, | 5973 | new_var.* = .{ |
| 4441 | 0, | 5974 | .owner_decl = sema.owner_decl, |
| 4442 | inst_data.is_mutable, | 5975 | .init = init_val, |
| 4443 | inst_data.is_allowzero, | 5976 | .is_extern = small.is_extern, |
| 4444 | inst_data.is_volatile, | 5977 | .is_mutable = true, // TODO get rid of this unused field |
| 4445 | inst_data.size, | 5978 | .is_threadlocal = small.is_threadlocal, |
| 4446 | ); | 5979 | }; |
| 4447 | return sema.mod.constType(sema.arena, .unneeded, ty); | 5980 | const result = try sema.mod.constInst(sema.arena, src, .{ |
| 5981 | .ty = var_ty, | ||
| 5982 | .val = try Value.Tag.variable.create(sema.arena, new_var), | ||
| 5983 | }); | ||
| 5984 | return result; | ||
| 4448 | } | 5985 | } |
| 4449 | 5986 | ||
| 4450 | fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 5987 | fn zirFuncExtended( |
| 5988 | sema: *Sema, | ||
| 5989 | block: *Scope.Block, | ||
| 5990 | extended: Zir.Inst.Extended.InstData, | ||
| 5991 | inst: Zir.Inst.Index, | ||
| 5992 | ) InnerError!*Inst { | ||
| 4451 | const tracy = trace(@src()); | 5993 | const tracy = trace(@src()); |
| 4452 | defer tracy.end(); | 5994 | defer tracy.end(); |
| 4453 | 5995 | ||
| 4454 | const src: LazySrcLoc = .unneeded; | 5996 | const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand); |
| 4455 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; | 5997 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; |
| 4456 | const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index); | 5998 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node }; |
| 5999 | const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align | ||
| 6000 | const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); | ||
| 4457 | 6001 | ||
| 4458 | var extra_i = extra.end; | 6002 | var extra_index: usize = extra.end; |
| 4459 | 6003 | ||
| 4460 | const sentinel = if (inst_data.flags.has_sentinel) blk: { | 6004 | const lib_name: ?[]const u8 = if (small.has_lib_name) blk: { |
| 4461 | const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]); | 6005 | const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); |
| 4462 | extra_i += 1; | 6006 | extra_index += 1; |
| 4463 | break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val; | 6007 | break :blk lib_name; |
| 4464 | } else null; | 6008 | } else null; |
| 4465 | 6009 | ||
| 4466 | const abi_align = if (inst_data.flags.has_align) blk: { | 6010 | const cc: std.builtin.CallingConvention = if (small.has_cc) blk: { |
| 4467 | const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]); | 6011 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 4468 | extra_i += 1; | 6012 | extra_index += 1; |
| 4469 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32); | 6013 | const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref); |
| 4470 | } else 0; | 6014 | break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention); |
| 4471 | 6015 | } else .Unspecified; | |
| 4472 | const bit_start = if (inst_data.flags.has_bit_range) blk: { | ||
| 4473 | const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 4474 | extra_i += 1; | ||
| 4475 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16); | ||
| 4476 | } else 0; | ||
| 4477 | |||
| 4478 | const bit_end = if (inst_data.flags.has_bit_range) blk: { | ||
| 4479 | const ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_i]); | ||
| 4480 | extra_i += 1; | ||
| 4481 | break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16); | ||
| 4482 | } else 0; | ||
| 4483 | |||
| 4484 | if (bit_end != 0 and bit_start >= bit_end * 8) | ||
| 4485 | return sema.mod.fail(&block.base, src, "bit offset starts after end of host integer", .{}); | ||
| 4486 | 6016 | ||
| 4487 | const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type); | 6017 | const align_val: Value = if (small.has_align) blk: { |
| 6018 | const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 6019 | extra_index += 1; | ||
| 6020 | const align_tv = try sema.resolveInstConst(block, align_src, align_ref); | ||
| 6021 | break :blk align_tv.val; | ||
| 6022 | } else Value.initTag(.null_value); | ||
| 6023 | |||
| 6024 | const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len); | ||
| 6025 | extra_index += param_types.len; | ||
| 6026 | |||
| 6027 | var body_inst: Zir.Inst.Index = 0; | ||
| 6028 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; | ||
| 6029 | if (extra.data.body_len != 0) { | ||
| 6030 | body_inst = inst; | ||
| 6031 | extra_index += extra.data.body_len; | ||
| 6032 | src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; | ||
| 6033 | } | ||
| 4488 | 6034 | ||
| 4489 | const ty = try sema.mod.ptrType( | 6035 | return sema.funcCommon( |
| 4490 | sema.arena, | 6036 | block, |
| 4491 | elem_type, | 6037 | extra.data.src_node, |
| 4492 | sentinel, | 6038 | param_types, |
| 4493 | abi_align, | 6039 | body_inst, |
| 4494 | bit_start, | 6040 | extra.data.return_type, |
| 4495 | bit_end, | 6041 | cc, |
| 4496 | inst_data.flags.is_mutable, | 6042 | align_val, |
| 4497 | inst_data.flags.is_allowzero, | 6043 | small.is_var_args, |
| 4498 | inst_data.flags.is_volatile, | 6044 | small.is_inferred_error, |
| 4499 | inst_data.size, | 6045 | small.is_extern, |
| 6046 | src_locs, | ||
| 6047 | lib_name, | ||
| 4500 | ); | 6048 | ); |
| 4501 | return sema.mod.constType(sema.arena, src, ty); | ||
| 4502 | } | 6049 | } |
| 4503 | 6050 | ||
| 4504 | fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 6051 | fn zirCUndef( |
| 4505 | const tracy = trace(@src()); | 6052 | sema: *Sema, |
| 4506 | defer tracy.end(); | 6053 | block: *Scope.Block, |
| 6054 | extended: Zir.Inst.Extended.InstData, | ||
| 6055 | ) InnerError!*Inst { | ||
| 6056 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | ||
| 6057 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6058 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{}); | ||
| 6059 | } | ||
| 4507 | 6060 | ||
| 4508 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 6061 | fn zirCInclude( |
| 4509 | const src = inst_data.src(); | 6062 | sema: *Sema, |
| 4510 | const struct_type = try sema.resolveType(block, src, inst_data.operand); | 6063 | block: *Scope.Block, |
| 6064 | extended: Zir.Inst.Extended.InstData, | ||
| 6065 | ) InnerError!*Inst { | ||
| 6066 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | ||
| 6067 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6068 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{}); | ||
| 6069 | } | ||
| 4511 | 6070 | ||
| 4512 | return sema.mod.constInst(sema.arena, src, .{ | 6071 | fn zirCDefine( |
| 4513 | .ty = struct_type, | 6072 | sema: *Sema, |
| 4514 | .val = Value.initTag(.empty_struct_value), | 6073 | block: *Scope.Block, |
| 4515 | }); | 6074 | extended: Zir.Inst.Extended.InstData, |
| 6075 | ) InnerError!*Inst { | ||
| 6076 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | ||
| 6077 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6078 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{}); | ||
| 4516 | } | 6079 | } |
| 4517 | 6080 | ||
| 4518 | fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 6081 | fn zirWasmMemorySize( |
| 4519 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6082 | sema: *Sema, |
| 4520 | const src = inst_data.src(); | 6083 | block: *Scope.Block, |
| 4521 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{}); | 6084 | extended: Zir.Inst.Extended.InstData, |
| 6085 | ) InnerError!*Inst { | ||
| 6086 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | ||
| 6087 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6088 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemorySize", .{}); | ||
| 4522 | } | 6089 | } |
| 4523 | 6090 | ||
| 4524 | fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 6091 | fn zirWasmMemoryGrow( |
| 4525 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6092 | sema: *Sema, |
| 4526 | const src = inst_data.src(); | 6093 | block: *Scope.Block, |
| 4527 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{}); | 6094 | extended: Zir.Inst.Extended.InstData, |
| 6095 | ) InnerError!*Inst { | ||
| 6096 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | ||
| 6097 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6098 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemoryGrow", .{}); | ||
| 6099 | } | ||
| 6100 | |||
| 6101 | fn zirBuiltinExtern( | ||
| 6102 | sema: *Sema, | ||
| 6103 | block: *Scope.Block, | ||
| 6104 | extended: Zir.Inst.Extended.InstData, | ||
| 6105 | ) InnerError!*Inst { | ||
| 6106 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | ||
| 6107 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 6108 | return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinExtern", .{}); | ||
| 4528 | } | 6109 | } |
| 4529 | 6110 | ||
| 4530 | fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { | 6111 | fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { |
| ... | @@ -4535,7 +6116,7 @@ fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void | ... | @@ -4535,7 +6116,7 @@ fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void |
| 4535 | 6116 | ||
| 4536 | fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { | 6117 | fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { |
| 4537 | if (block.is_comptime) { | 6118 | if (block.is_comptime) { |
| 4538 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); | 6119 | return sema.failWithNeededComptime(block, src); |
| 4539 | } | 6120 | } |
| 4540 | try sema.requireFunctionBlock(block, src); | 6121 | try sema.requireFunctionBlock(block, src); |
| 4541 | } | 6122 | } |
| ... | @@ -4611,7 +6192,7 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: | ... | @@ -4611,7 +6192,7 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: |
| 4611 | try parent_block.instructions.append(sema.gpa, &block_inst.base); | 6192 | try parent_block.instructions.append(sema.gpa, &block_inst.base); |
| 4612 | } | 6193 | } |
| 4613 | 6194 | ||
| 4614 | fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !zir.Inst.Index { | 6195 | fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !Zir.Inst.Index { |
| 4615 | // TODO Once we have a panic function to call, call it here instead of breakpoint. | 6196 | // TODO Once we have a panic function to call, call it here instead of breakpoint. |
| 4616 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); | 6197 | _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); |
| 4617 | _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach); | 6198 | _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach); |
| ... | @@ -4719,21 +6300,9 @@ fn namedFieldPtr( | ... | @@ -4719,21 +6300,9 @@ fn namedFieldPtr( |
| 4719 | }); | 6300 | }); |
| 4720 | }, | 6301 | }, |
| 4721 | .Struct, .Opaque, .Union => { | 6302 | .Struct, .Opaque, .Union => { |
| 4722 | if (child_type.getContainerScope()) |container_scope| { | 6303 | if (child_type.getNamespace()) |namespace| { |
| 4723 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { | 6304 | if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| { |
| 4724 | if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope)) | 6305 | return inst; |
| 4725 | return mod.fail(&block.base, src, "'{s}' is private", .{field_name}); | ||
| 4726 | return sema.analyzeDeclRef(block, src, decl); | ||
| 4727 | } | ||
| 4728 | |||
| 4729 | // TODO this will give false positives for structs inside the root file | ||
| 4730 | if (container_scope.file_scope == mod.root_scope) { | ||
| 4731 | return mod.fail( | ||
| 4732 | &block.base, | ||
| 4733 | src, | ||
| 4734 | "root source file has no member named '{s}'", | ||
| 4735 | .{field_name}, | ||
| 4736 | ); | ||
| 4737 | } | 6306 | } |
| 4738 | } | 6307 | } |
| 4739 | // TODO add note: declared here | 6308 | // TODO add note: declared here |
| ... | @@ -4748,11 +6317,9 @@ fn namedFieldPtr( | ... | @@ -4748,11 +6317,9 @@ fn namedFieldPtr( |
| 4748 | }); | 6317 | }); |
| 4749 | }, | 6318 | }, |
| 4750 | .Enum => { | 6319 | .Enum => { |
| 4751 | if (child_type.getContainerScope()) |container_scope| { | 6320 | if (child_type.getNamespace()) |namespace| { |
| 4752 | if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| { | 6321 | if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| { |
| 4753 | if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope)) | 6322 | return inst; |
| 4754 | return mod.fail(&block.base, src, "'{s}' is private", .{field_name}); | ||
| 4755 | return sema.analyzeDeclRef(block, src, decl); | ||
| 4756 | } | 6323 | } |
| 4757 | } | 6324 | } |
| 4758 | const field_index = child_type.enumFieldIndex(field_name) orelse { | 6325 | const field_index = child_type.enumFieldIndex(field_name) orelse { |
| ... | @@ -4785,11 +6352,38 @@ fn namedFieldPtr( | ... | @@ -4785,11 +6352,38 @@ fn namedFieldPtr( |
| 4785 | } | 6352 | } |
| 4786 | }, | 6353 | }, |
| 4787 | .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty), | 6354 | .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty), |
| 6355 | .Union => return sema.analyzeUnionFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty), | ||
| 4788 | else => {}, | 6356 | else => {}, |
| 4789 | } | 6357 | } |
| 4790 | return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty}); | 6358 | return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty}); |
| 4791 | } | 6359 | } |
| 4792 | 6360 | ||
| 6361 | fn analyzeNamespaceLookup( | ||
| 6362 | sema: *Sema, | ||
| 6363 | block: *Scope.Block, | ||
| 6364 | src: LazySrcLoc, | ||
| 6365 | namespace: *Scope.Namespace, | ||
| 6366 | decl_name: []const u8, | ||
| 6367 | ) InnerError!?*Inst { | ||
| 6368 | const mod = sema.mod; | ||
| 6369 | const gpa = sema.gpa; | ||
| 6370 | if (try sema.lookupInNamespace(namespace, decl_name)) |decl| { | ||
| 6371 | if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) { | ||
| 6372 | const msg = msg: { | ||
| 6373 | const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{ | ||
| 6374 | decl_name, | ||
| 6375 | }); | ||
| 6376 | errdefer msg.destroy(gpa); | ||
| 6377 | try mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{}); | ||
| 6378 | break :msg msg; | ||
| 6379 | }; | ||
| 6380 | return mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 6381 | } | ||
| 6382 | return try sema.analyzeDeclRef(block, src, decl); | ||
| 6383 | } | ||
| 6384 | return null; | ||
| 6385 | } | ||
| 6386 | |||
| 4793 | fn analyzeStructFieldPtr( | 6387 | fn analyzeStructFieldPtr( |
| 4794 | sema: *Sema, | 6388 | sema: *Sema, |
| 4795 | block: *Scope.Block, | 6389 | block: *Scope.Block, |
| ... | @@ -4797,23 +6391,71 @@ fn analyzeStructFieldPtr( | ... | @@ -4797,23 +6391,71 @@ fn analyzeStructFieldPtr( |
| 4797 | struct_ptr: *Inst, | 6391 | struct_ptr: *Inst, |
| 4798 | field_name: []const u8, | 6392 | field_name: []const u8, |
| 4799 | field_name_src: LazySrcLoc, | 6393 | field_name_src: LazySrcLoc, |
| 4800 | elem_ty: Type, | 6394 | unresolved_struct_ty: Type, |
| 4801 | ) InnerError!*Inst { | 6395 | ) InnerError!*Inst { |
| 4802 | const mod = sema.mod; | 6396 | const mod = sema.mod; |
| 4803 | const arena = sema.arena; | 6397 | const arena = sema.arena; |
| 4804 | assert(elem_ty.zigTypeTag() == .Struct); | 6398 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); |
| 4805 | 6399 | ||
| 4806 | const struct_obj = elem_ty.castTag(.@"struct").?.data; | 6400 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); |
| 6401 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 4807 | 6402 | ||
| 4808 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 6403 | const field_index = struct_obj.fields.getIndex(field_name) orelse |
| 4809 | return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); | 6404 | return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); |
| 4810 | const field = struct_obj.fields.entries.items[field_index].value; | 6405 | const field = struct_obj.fields.entries.items[field_index].value; |
| 4811 | const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One); | 6406 | const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One); |
| 4812 | // TODO comptime field access | 6407 | |
| 6408 | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { | ||
| 6409 | return mod.constInst(arena, src, .{ | ||
| 6410 | .ty = ptr_field_ty, | ||
| 6411 | .val = try Value.Tag.field_ptr.create(arena, .{ | ||
| 6412 | .container_ptr = struct_ptr_val, | ||
| 6413 | .field_index = field_index, | ||
| 6414 | }), | ||
| 6415 | }); | ||
| 6416 | } | ||
| 6417 | |||
| 4813 | try sema.requireRuntimeBlock(block, src); | 6418 | try sema.requireRuntimeBlock(block, src); |
| 4814 | return block.addStructFieldPtr(src, ptr_field_ty, struct_ptr, @intCast(u32, field_index)); | 6419 | return block.addStructFieldPtr(src, ptr_field_ty, struct_ptr, @intCast(u32, field_index)); |
| 4815 | } | 6420 | } |
| 4816 | 6421 | ||
| 6422 | fn analyzeUnionFieldPtr( | ||
| 6423 | sema: *Sema, | ||
| 6424 | block: *Scope.Block, | ||
| 6425 | src: LazySrcLoc, | ||
| 6426 | union_ptr: *Inst, | ||
| 6427 | field_name: []const u8, | ||
| 6428 | field_name_src: LazySrcLoc, | ||
| 6429 | unresolved_union_ty: Type, | ||
| 6430 | ) InnerError!*Inst { | ||
| 6431 | const mod = sema.mod; | ||
| 6432 | const arena = sema.arena; | ||
| 6433 | assert(unresolved_union_ty.zigTypeTag() == .Union); | ||
| 6434 | |||
| 6435 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); | ||
| 6436 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | ||
| 6437 | |||
| 6438 | const field_index = union_obj.fields.getIndex(field_name) orelse | ||
| 6439 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); | ||
| 6440 | |||
| 6441 | const field = union_obj.fields.entries.items[field_index].value; | ||
| 6442 | const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One); | ||
| 6443 | |||
| 6444 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| { | ||
| 6445 | // TODO detect inactive union field and emit compile error | ||
| 6446 | return mod.constInst(arena, src, .{ | ||
| 6447 | .ty = ptr_field_ty, | ||
| 6448 | .val = try Value.Tag.field_ptr.create(arena, .{ | ||
| 6449 | .container_ptr = union_ptr_val, | ||
| 6450 | .field_index = field_index, | ||
| 6451 | }), | ||
| 6452 | }); | ||
| 6453 | } | ||
| 6454 | |||
| 6455 | try sema.requireRuntimeBlock(block, src); | ||
| 6456 | return mod.fail(&block.base, src, "TODO implement runtime union field access", .{}); | ||
| 6457 | } | ||
| 6458 | |||
| 4817 | fn elemPtr( | 6459 | fn elemPtr( |
| 4818 | sema: *Sema, | 6460 | sema: *Sema, |
| 4819 | block: *Scope.Block, | 6461 | block: *Scope.Block, |
| ... | @@ -5003,17 +6645,18 @@ fn coerce( | ... | @@ -5003,17 +6645,18 @@ fn coerce( |
| 5003 | if (inst.ty.zigTypeTag() == .EnumLiteral) { | 6645 | if (inst.ty.zigTypeTag() == .EnumLiteral) { |
| 5004 | const val = try sema.resolveConstValue(block, inst_src, inst); | 6646 | const val = try sema.resolveConstValue(block, inst_src, inst); |
| 5005 | const bytes = val.castTag(.enum_literal).?.data; | 6647 | const bytes = val.castTag(.enum_literal).?.data; |
| 5006 | const field_index = dest_type.enumFieldIndex(bytes) orelse { | 6648 | const resolved_dest_type = try sema.resolveTypeFields(block, inst_src, dest_type); |
| 6649 | const field_index = resolved_dest_type.enumFieldIndex(bytes) orelse { | ||
| 5007 | const msg = msg: { | 6650 | const msg = msg: { |
| 5008 | const msg = try mod.errMsg( | 6651 | const msg = try mod.errMsg( |
| 5009 | &block.base, | 6652 | &block.base, |
| 5010 | inst_src, | 6653 | inst_src, |
| 5011 | "enum '{}' has no field named '{s}'", | 6654 | "enum '{}' has no field named '{s}'", |
| 5012 | .{ dest_type, bytes }, | 6655 | .{ resolved_dest_type, bytes }, |
| 5013 | ); | 6656 | ); |
| 5014 | errdefer msg.destroy(sema.gpa); | 6657 | errdefer msg.destroy(sema.gpa); |
| 5015 | try mod.errNoteNonLazy( | 6658 | try mod.errNoteNonLazy( |
| 5016 | dest_type.declSrcLoc(), | 6659 | resolved_dest_type.declSrcLoc(), |
| 5017 | msg, | 6660 | msg, |
| 5018 | "enum declared here", | 6661 | "enum declared here", |
| 5019 | .{}, | 6662 | .{}, |
| ... | @@ -5023,7 +6666,7 @@ fn coerce( | ... | @@ -5023,7 +6666,7 @@ fn coerce( |
| 5023 | return mod.failWithOwnedErrorMsg(&block.base, msg); | 6666 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 5024 | }; | 6667 | }; |
| 5025 | return mod.constInst(arena, inst_src, .{ | 6668 | return mod.constInst(arena, inst_src, .{ |
| 5026 | .ty = dest_type, | 6669 | .ty = resolved_dest_type, |
| 5027 | .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)), | 6670 | .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)), |
| 5028 | }); | 6671 | }); |
| 5029 | } | 6672 | } |
| ... | @@ -5107,7 +6750,7 @@ fn storePtr( | ... | @@ -5107,7 +6750,7 @@ fn storePtr( |
| 5107 | 6750 | ||
| 5108 | const elem_ty = ptr.ty.elemType(); | 6751 | const elem_ty = ptr.ty.elemType(); |
| 5109 | const value = try sema.coerce(block, elem_ty, uncasted_value, src); | 6752 | const value = try sema.coerce(block, elem_ty, uncasted_value, src); |
| 5110 | if (elem_ty.onePossibleValue() != null) | 6753 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) |
| 5111 | return; | 6754 | return; |
| 5112 | 6755 | ||
| 5113 | // TODO handle comptime pointer writes | 6756 | // TODO handle comptime pointer writes |
| ... | @@ -5149,7 +6792,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl | ... | @@ -5149,7 +6792,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl |
| 5149 | } | 6792 | } |
| 5150 | 6793 | ||
| 5151 | fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst { | 6794 | fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst { |
| 5152 | _ = try sema.mod.declareDeclDependency(sema.owner_decl, decl); | 6795 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 5153 | sema.mod.ensureDeclAnalyzed(decl) catch |err| { | 6796 | sema.mod.ensureDeclAnalyzed(decl) catch |err| { |
| 5154 | if (sema.func) |func| { | 6797 | if (sema.func) |func| { |
| 5155 | func.state = .dependency_failure; | 6798 | func.state = .dependency_failure; |
| ... | @@ -5202,7 +6845,7 @@ fn analyzeRef( | ... | @@ -5202,7 +6845,7 @@ fn analyzeRef( |
| 5202 | ) InnerError!*Inst { | 6845 | ) InnerError!*Inst { |
| 5203 | const ptr_type = try sema.mod.simplePtrType(sema.arena, operand.ty, false, .One); | 6846 | const ptr_type = try sema.mod.simplePtrType(sema.arena, operand.ty, false, .One); |
| 5204 | 6847 | ||
| 5205 | if (operand.value()) |val| { | 6848 | if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |val| { |
| 5206 | return sema.mod.constInst(sema.arena, src, .{ | 6849 | return sema.mod.constInst(sema.arena, src, .{ |
| 5207 | .ty = ptr_type, | 6850 | .ty = ptr_type, |
| 5208 | .val = try Value.Tag.ref_val.create(sema.arena, val), | 6851 | .val = try Value.Tag.ref_val.create(sema.arena, val), |
| ... | @@ -5224,10 +6867,10 @@ fn analyzeLoad( | ... | @@ -5224,10 +6867,10 @@ fn analyzeLoad( |
| 5224 | .Pointer => ptr.ty.elemType(), | 6867 | .Pointer => ptr.ty.elemType(), |
| 5225 | else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}), | 6868 | else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}), |
| 5226 | }; | 6869 | }; |
| 5227 | if (ptr.value()) |val| { | 6870 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 5228 | return sema.mod.constInst(sema.arena, src, .{ | 6871 | return sema.mod.constInst(sema.arena, src, .{ |
| 5229 | .ty = elem_ty, | 6872 | .ty = elem_ty, |
| 5230 | .val = try val.pointerDeref(sema.arena), | 6873 | .val = try ptr_val.pointerDeref(sema.arena), |
| 5231 | }); | 6874 | }); |
| 5232 | } | 6875 | } |
| 5233 | 6876 | ||
| ... | @@ -5242,14 +6885,18 @@ fn analyzeIsNull( | ... | @@ -5242,14 +6885,18 @@ fn analyzeIsNull( |
| 5242 | operand: *Inst, | 6885 | operand: *Inst, |
| 5243 | invert_logic: bool, | 6886 | invert_logic: bool, |
| 5244 | ) InnerError!*Inst { | 6887 | ) InnerError!*Inst { |
| 5245 | if (operand.value()) |opt_val| { | 6888 | const result_ty = Type.initTag(.bool); |
| 6889 | if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |opt_val| { | ||
| 6890 | if (opt_val.isUndef()) { | ||
| 6891 | return sema.mod.constUndef(sema.arena, src, result_ty); | ||
| 6892 | } | ||
| 5246 | const is_null = opt_val.isNull(); | 6893 | const is_null = opt_val.isNull(); |
| 5247 | const bool_value = if (invert_logic) !is_null else is_null; | 6894 | const bool_value = if (invert_logic) !is_null else is_null; |
| 5248 | return sema.mod.constBool(sema.arena, src, bool_value); | 6895 | return sema.mod.constBool(sema.arena, src, bool_value); |
| 5249 | } | 6896 | } |
| 5250 | try sema.requireRuntimeBlock(block, src); | 6897 | try sema.requireRuntimeBlock(block, src); |
| 5251 | const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null; | 6898 | const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null; |
| 5252 | return block.addUnOp(src, Type.initTag(.bool), inst_tag, operand); | 6899 | return block.addUnOp(src, result_ty, inst_tag, operand); |
| 5253 | } | 6900 | } |
| 5254 | 6901 | ||
| 5255 | fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst { | 6902 | fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst { |
| ... | @@ -5257,11 +6904,15 @@ fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Ins | ... | @@ -5257,11 +6904,15 @@ fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Ins |
| 5257 | if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false); | 6904 | if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false); |
| 5258 | if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true); | 6905 | if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true); |
| 5259 | assert(ot == .ErrorUnion); | 6906 | assert(ot == .ErrorUnion); |
| 5260 | if (operand.value()) |err_union| { | 6907 | const result_ty = Type.initTag(.bool); |
| 6908 | if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| { | ||
| 6909 | if (err_union.isUndef()) { | ||
| 6910 | return sema.mod.constUndef(sema.arena, src, result_ty); | ||
| 6911 | } | ||
| 5261 | return sema.mod.constBool(sema.arena, src, err_union.getError() != null); | 6912 | return sema.mod.constBool(sema.arena, src, err_union.getError() != null); |
| 5262 | } | 6913 | } |
| 5263 | try sema.requireRuntimeBlock(block, src); | 6914 | try sema.requireRuntimeBlock(block, src); |
| 5264 | return block.addUnOp(src, Type.initTag(.bool), .is_err, operand); | 6915 | return block.addUnOp(src, result_ty, .is_err, operand); |
| 5265 | } | 6916 | } |
| 5266 | 6917 | ||
| 5267 | fn analyzeSlice( | 6918 | fn analyzeSlice( |
| ... | @@ -5338,65 +6989,6 @@ fn analyzeSlice( | ... | @@ -5338,65 +6989,6 @@ fn analyzeSlice( |
| 5338 | return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{}); | 6989 | return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{}); |
| 5339 | } | 6990 | } |
| 5340 | 6991 | ||
| 5341 | fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_string: []const u8) !*Scope.File { | ||
| 5342 | const cur_pkg = block.getFileScope().pkg; | ||
| 5343 | const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse "."; | ||
| 5344 | const found_pkg = cur_pkg.table.get(target_string); | ||
| 5345 | |||
| 5346 | const resolved_path = if (found_pkg) |pkg| | ||
| 5347 | try std.fs.path.resolve(sema.gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path }) | ||
| 5348 | else | ||
| 5349 | try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string }); | ||
| 5350 | errdefer sema.gpa.free(resolved_path); | ||
| 5351 | |||
| 5352 | if (sema.mod.import_table.get(resolved_path)) |cached_import| { | ||
| 5353 | sema.gpa.free(resolved_path); | ||
| 5354 | return cached_import; | ||
| 5355 | } | ||
| 5356 | |||
| 5357 | if (found_pkg == null) { | ||
| 5358 | const resolved_root_path = try std.fs.path.resolve(sema.gpa, &[_][]const u8{cur_pkg_dir_path}); | ||
| 5359 | defer sema.gpa.free(resolved_root_path); | ||
| 5360 | |||
| 5361 | if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { | ||
| 5362 | return error.ImportOutsidePkgPath; | ||
| 5363 | } | ||
| 5364 | } | ||
| 5365 | |||
| 5366 | // TODO Scope.Container arena for ty and sub_file_path | ||
| 5367 | const file_scope = try sema.gpa.create(Scope.File); | ||
| 5368 | errdefer sema.gpa.destroy(file_scope); | ||
| 5369 | const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container); | ||
| 5370 | errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?); | ||
| 5371 | |||
| 5372 | const container_name_hash: Scope.NameHash = if (found_pkg) |pkg| | ||
| 5373 | pkg.namespace_hash | ||
| 5374 | else | ||
| 5375 | std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path); | ||
| 5376 | |||
| 5377 | file_scope.* = .{ | ||
| 5378 | .sub_file_path = resolved_path, | ||
| 5379 | .source = .{ .unloaded = {} }, | ||
| 5380 | .tree = undefined, | ||
| 5381 | .status = .never_loaded, | ||
| 5382 | .pkg = found_pkg orelse cur_pkg, | ||
| 5383 | .root_container = .{ | ||
| 5384 | .file_scope = file_scope, | ||
| 5385 | .decls = .{}, | ||
| 5386 | .ty = struct_ty, | ||
| 5387 | .parent_name_hash = container_name_hash, | ||
| 5388 | }, | ||
| 5389 | }; | ||
| 5390 | sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) { | ||
| 5391 | error.AnalysisFail => { | ||
| 5392 | assert(sema.mod.comp.totalErrorCount() != 0); | ||
| 5393 | }, | ||
| 5394 | else => |e| return e, | ||
| 5395 | }; | ||
| 5396 | try sema.mod.import_table.put(sema.gpa, file_scope.sub_file_path, file_scope); | ||
| 5397 | return file_scope; | ||
| 5398 | } | ||
| 5399 | |||
| 5400 | /// Asserts that lhs and rhs types are both numeric. | 6992 | /// Asserts that lhs and rhs types are both numeric. |
| 5401 | fn cmpNumeric( | 6993 | fn cmpNumeric( |
| 5402 | sema: *Sema, | 6994 | sema: *Sema, |
| ... | @@ -5696,9 +7288,299 @@ fn resolvePeerTypes(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, instructi | ... | @@ -5696,9 +7288,299 @@ fn resolvePeerTypes(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, instructi |
| 5696 | continue; | 7288 | continue; |
| 5697 | } | 7289 | } |
| 5698 | 7290 | ||
| 7291 | if (chosen.ty.zigTypeTag() == .Enum and candidate.ty.zigTypeTag() == .EnumLiteral) { | ||
| 7292 | continue; | ||
| 7293 | } | ||
| 7294 | if (chosen.ty.zigTypeTag() == .EnumLiteral and candidate.ty.zigTypeTag() == .Enum) { | ||
| 7295 | chosen = candidate; | ||
| 7296 | continue; | ||
| 7297 | } | ||
| 7298 | |||
| 5699 | // TODO error notes pointing out each type | 7299 | // TODO error notes pointing out each type |
| 5700 | return sema.mod.fail(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen.ty, candidate.ty }); | 7300 | return sema.mod.fail(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen.ty, candidate.ty }); |
| 5701 | } | 7301 | } |
| 5702 | 7302 | ||
| 5703 | return chosen.ty; | 7303 | return chosen.ty; |
| 5704 | } | 7304 | } |
| 7305 | |||
| 7306 | fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) InnerError!Type { | ||
| 7307 | switch (ty.tag()) { | ||
| 7308 | .@"struct" => { | ||
| 7309 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 7310 | switch (struct_obj.status) { | ||
| 7311 | .none => {}, | ||
| 7312 | .field_types_wip => { | ||
| 7313 | return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ | ||
| 7314 | ty, | ||
| 7315 | }); | ||
| 7316 | }, | ||
| 7317 | .have_field_types, .have_layout, .layout_wip => return ty, | ||
| 7318 | } | ||
| 7319 | struct_obj.status = .field_types_wip; | ||
| 7320 | try sema.mod.analyzeStructFields(struct_obj); | ||
| 7321 | struct_obj.status = .have_field_types; | ||
| 7322 | return ty; | ||
| 7323 | }, | ||
| 7324 | .extern_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExternOptions"), | ||
| 7325 | .export_options => return sema.resolveBuiltinTypeFields(block, src, ty, "ExportOptions"), | ||
| 7326 | .atomic_ordering => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicOrdering"), | ||
| 7327 | .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, ty, "AtomicRmwOp"), | ||
| 7328 | .calling_convention => return sema.resolveBuiltinTypeFields(block, src, ty, "CallingConvention"), | ||
| 7329 | .float_mode => return sema.resolveBuiltinTypeFields(block, src, ty, "FloatMode"), | ||
| 7330 | .reduce_op => return sema.resolveBuiltinTypeFields(block, src, ty, "ReduceOp"), | ||
| 7331 | .call_options => return sema.resolveBuiltinTypeFields(block, src, ty, "CallOptions"), | ||
| 7332 | |||
| 7333 | .@"union", .union_tagged => { | ||
| 7334 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 7335 | switch (union_obj.status) { | ||
| 7336 | .none => {}, | ||
| 7337 | .field_types_wip => { | ||
| 7338 | return sema.mod.fail(&block.base, src, "union {} depends on itself", .{ | ||
| 7339 | ty, | ||
| 7340 | }); | ||
| 7341 | }, | ||
| 7342 | .have_field_types, .have_layout, .layout_wip => return ty, | ||
| 7343 | } | ||
| 7344 | union_obj.status = .field_types_wip; | ||
| 7345 | try sema.mod.analyzeUnionFields(union_obj); | ||
| 7346 | union_obj.status = .have_field_types; | ||
| 7347 | return ty; | ||
| 7348 | }, | ||
| 7349 | else => return ty, | ||
| 7350 | } | ||
| 7351 | } | ||
| 7352 | |||
| 7353 | fn resolveBuiltinTypeFields( | ||
| 7354 | sema: *Sema, | ||
| 7355 | block: *Scope.Block, | ||
| 7356 | src: LazySrcLoc, | ||
| 7357 | ty: Type, | ||
| 7358 | name: []const u8, | ||
| 7359 | ) InnerError!Type { | ||
| 7360 | const resolved_ty = try sema.getBuiltinType(block, src, name); | ||
| 7361 | return sema.resolveTypeFields(block, src, resolved_ty); | ||
| 7362 | } | ||
| 7363 | |||
| 7364 | fn getBuiltinType( | ||
| 7365 | sema: *Sema, | ||
| 7366 | block: *Scope.Block, | ||
| 7367 | src: LazySrcLoc, | ||
| 7368 | name: []const u8, | ||
| 7369 | ) InnerError!Type { | ||
| 7370 | const mod = sema.mod; | ||
| 7371 | const std_pkg = mod.root_pkg.table.get("std").?; | ||
| 7372 | const std_file = (mod.importPkg(mod.root_pkg, std_pkg) catch unreachable).file; | ||
| 7373 | const opt_builtin_inst = try sema.analyzeNamespaceLookup( | ||
| 7374 | block, | ||
| 7375 | src, | ||
| 7376 | std_file.root_decl.?.namespace, | ||
| 7377 | "builtin", | ||
| 7378 | ); | ||
| 7379 | const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst.?, src); | ||
| 7380 | const builtin_ty = try sema.resolveAirAsType(block, src, builtin_inst); | ||
| 7381 | const opt_ty_inst = try sema.analyzeNamespaceLookup( | ||
| 7382 | block, | ||
| 7383 | src, | ||
| 7384 | builtin_ty.getNamespace().?, | ||
| 7385 | name, | ||
| 7386 | ); | ||
| 7387 | const ty_inst = try sema.analyzeLoad(block, src, opt_ty_inst.?, src); | ||
| 7388 | return sema.resolveAirAsType(block, src, ty_inst); | ||
| 7389 | } | ||
| 7390 | |||
| 7391 | /// There is another implementation of this in `Type.onePossibleValue`. This one | ||
| 7392 | /// in `Sema` is for calling during semantic analysis, and peforms field resolution | ||
| 7393 | /// to get the answer. The one in `Type` is for calling during codegen and asserts | ||
| 7394 | /// that the types are already resolved. | ||
| 7395 | fn typeHasOnePossibleValue( | ||
| 7396 | sema: *Sema, | ||
| 7397 | block: *Scope.Block, | ||
| 7398 | src: LazySrcLoc, | ||
| 7399 | starting_type: Type, | ||
| 7400 | ) InnerError!?Value { | ||
| 7401 | var ty = starting_type; | ||
| 7402 | while (true) switch (ty.tag()) { | ||
| 7403 | .f16, | ||
| 7404 | .f32, | ||
| 7405 | .f64, | ||
| 7406 | .f128, | ||
| 7407 | .c_longdouble, | ||
| 7408 | .comptime_int, | ||
| 7409 | .comptime_float, | ||
| 7410 | .u8, | ||
| 7411 | .i8, | ||
| 7412 | .u16, | ||
| 7413 | .i16, | ||
| 7414 | .u32, | ||
| 7415 | .i32, | ||
| 7416 | .u64, | ||
| 7417 | .i64, | ||
| 7418 | .u128, | ||
| 7419 | .i128, | ||
| 7420 | .usize, | ||
| 7421 | .isize, | ||
| 7422 | .c_short, | ||
| 7423 | .c_ushort, | ||
| 7424 | .c_int, | ||
| 7425 | .c_uint, | ||
| 7426 | .c_long, | ||
| 7427 | .c_ulong, | ||
| 7428 | .c_longlong, | ||
| 7429 | .c_ulonglong, | ||
| 7430 | .bool, | ||
| 7431 | .type, | ||
| 7432 | .anyerror, | ||
| 7433 | .fn_noreturn_no_args, | ||
| 7434 | .fn_void_no_args, | ||
| 7435 | .fn_naked_noreturn_no_args, | ||
| 7436 | .fn_ccc_void_no_args, | ||
| 7437 | .function, | ||
| 7438 | .single_const_pointer_to_comptime_int, | ||
| 7439 | .array_sentinel, | ||
| 7440 | .array_u8_sentinel_0, | ||
| 7441 | .const_slice_u8, | ||
| 7442 | .const_slice, | ||
| 7443 | .mut_slice, | ||
| 7444 | .c_void, | ||
| 7445 | .optional, | ||
| 7446 | .optional_single_mut_pointer, | ||
| 7447 | .optional_single_const_pointer, | ||
| 7448 | .enum_literal, | ||
| 7449 | .anyerror_void_error_union, | ||
| 7450 | .error_union, | ||
| 7451 | .error_set, | ||
| 7452 | .error_set_single, | ||
| 7453 | .@"opaque", | ||
| 7454 | .var_args_param, | ||
| 7455 | .manyptr_u8, | ||
| 7456 | .manyptr_const_u8, | ||
| 7457 | .atomic_ordering, | ||
| 7458 | .atomic_rmw_op, | ||
| 7459 | .calling_convention, | ||
| 7460 | .float_mode, | ||
| 7461 | .reduce_op, | ||
| 7462 | .call_options, | ||
| 7463 | .export_options, | ||
| 7464 | .extern_options, | ||
| 7465 | .@"anyframe", | ||
| 7466 | .anyframe_T, | ||
| 7467 | .many_const_pointer, | ||
| 7468 | .many_mut_pointer, | ||
| 7469 | .c_const_pointer, | ||
| 7470 | .c_mut_pointer, | ||
| 7471 | .single_const_pointer, | ||
| 7472 | .single_mut_pointer, | ||
| 7473 | .pointer, | ||
| 7474 | => return null, | ||
| 7475 | |||
| 7476 | .@"struct" => { | ||
| 7477 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | ||
| 7478 | const s = resolved_ty.castTag(.@"struct").?.data; | ||
| 7479 | for (s.fields.entries.items) |entry| { | ||
| 7480 | const field_ty = entry.value.ty; | ||
| 7481 | if ((try sema.typeHasOnePossibleValue(block, src, field_ty)) == null) { | ||
| 7482 | return null; | ||
| 7483 | } | ||
| 7484 | } | ||
| 7485 | return Value.initTag(.empty_struct_value); | ||
| 7486 | }, | ||
| 7487 | .enum_full => { | ||
| 7488 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | ||
| 7489 | const enum_full = resolved_ty.castTag(.enum_full).?.data; | ||
| 7490 | if (enum_full.fields.count() == 1) { | ||
| 7491 | return enum_full.values.entries.items[0].key; | ||
| 7492 | } else { | ||
| 7493 | return null; | ||
| 7494 | } | ||
| 7495 | }, | ||
| 7496 | .enum_simple => { | ||
| 7497 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | ||
| 7498 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; | ||
| 7499 | if (enum_simple.fields.count() == 1) { | ||
| 7500 | return Value.initTag(.zero); | ||
| 7501 | } else { | ||
| 7502 | return null; | ||
| 7503 | } | ||
| 7504 | }, | ||
| 7505 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, | ||
| 7506 | .@"union" => { | ||
| 7507 | return null; // TODO | ||
| 7508 | }, | ||
| 7509 | .union_tagged => { | ||
| 7510 | return null; // TODO | ||
| 7511 | }, | ||
| 7512 | |||
| 7513 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | ||
| 7514 | .void => return Value.initTag(.void_value), | ||
| 7515 | .noreturn => return Value.initTag(.unreachable_value), | ||
| 7516 | .@"null" => return Value.initTag(.null_value), | ||
| 7517 | .@"undefined" => return Value.initTag(.undef), | ||
| 7518 | |||
| 7519 | .int_unsigned, .int_signed => { | ||
| 7520 | if (ty.cast(Type.Payload.Bits).?.data == 0) { | ||
| 7521 | return Value.initTag(.zero); | ||
| 7522 | } else { | ||
| 7523 | return null; | ||
| 7524 | } | ||
| 7525 | }, | ||
| 7526 | .vector, .array, .array_u8 => { | ||
| 7527 | if (ty.arrayLen() == 0) | ||
| 7528 | return Value.initTag(.empty_array); | ||
| 7529 | ty = ty.elemType(); | ||
| 7530 | continue; | ||
| 7531 | }, | ||
| 7532 | |||
| 7533 | .inferred_alloc_const => unreachable, | ||
| 7534 | .inferred_alloc_mut => unreachable, | ||
| 7535 | }; | ||
| 7536 | } | ||
| 7537 | |||
| 7538 | fn getAstTree(sema: *Sema, block: *Scope.Block) InnerError!*const std.zig.ast.Tree { | ||
| 7539 | return block.src_decl.namespace.file_scope.getTree(sema.gpa) catch |err| { | ||
| 7540 | log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); | ||
| 7541 | return error.AnalysisFail; | ||
| 7542 | }; | ||
| 7543 | } | ||
| 7544 | |||
| 7545 | fn enumFieldSrcLoc( | ||
| 7546 | decl: *Decl, | ||
| 7547 | tree: std.zig.ast.Tree, | ||
| 7548 | node_offset: i32, | ||
| 7549 | field_index: usize, | ||
| 7550 | ) LazySrcLoc { | ||
| 7551 | @setCold(true); | ||
| 7552 | const enum_node = decl.relativeToNodeIndex(node_offset); | ||
| 7553 | const node_tags = tree.nodes.items(.tag); | ||
| 7554 | var buffer: [2]std.zig.ast.Node.Index = undefined; | ||
| 7555 | const container_decl = switch (node_tags[enum_node]) { | ||
| 7556 | .container_decl, | ||
| 7557 | .container_decl_trailing, | ||
| 7558 | => tree.containerDecl(enum_node), | ||
| 7559 | |||
| 7560 | .container_decl_two, | ||
| 7561 | .container_decl_two_trailing, | ||
| 7562 | => tree.containerDeclTwo(&buffer, enum_node), | ||
| 7563 | |||
| 7564 | .container_decl_arg, | ||
| 7565 | .container_decl_arg_trailing, | ||
| 7566 | => tree.containerDeclArg(enum_node), | ||
| 7567 | |||
| 7568 | else => unreachable, | ||
| 7569 | }; | ||
| 7570 | var it_index: usize = 0; | ||
| 7571 | for (container_decl.ast.members) |member_node| { | ||
| 7572 | switch (node_tags[member_node]) { | ||
| 7573 | .container_field_init, | ||
| 7574 | .container_field_align, | ||
| 7575 | .container_field, | ||
| 7576 | => { | ||
| 7577 | if (it_index == field_index) { | ||
| 7578 | return .{ .node_offset = decl.nodeIndexToRelative(member_node) }; | ||
| 7579 | } | ||
| 7580 | it_index += 1; | ||
| 7581 | }, | ||
| 7582 | |||
| 7583 | else => continue, | ||
| 7584 | } | ||
| 7585 | } else unreachable; | ||
| 7586 | } |
src/Zir.zig created+4810| ... | @@ -0,0 +1,4810 @@ | ||
| 1 | //! Zig Intermediate Representation. Astgen.zig converts AST nodes to these | ||
| 2 | //! untyped IR instructions. Next, Sema.zig processes these into TZIR. | ||
| 3 | //! The minimum amount of information needed to represent a list of ZIR instructions. | ||
| 4 | //! Once this structure is completed, it can be used to generate TZIR, followed by | ||
| 5 | //! machine code, without any memory access into the AST tree token list, node list, | ||
| 6 | //! or source bytes. Exceptions include: | ||
| 7 | //! * Compile errors, which may need to reach into these data structures to | ||
| 8 | //! create a useful report. | ||
| 9 | //! * In the future, possibly inline assembly, which needs to get parsed and | ||
| 10 | //! handled by the codegen backend, and errors reported there. However for now, | ||
| 11 | //! inline assembly is not an exception. | ||
| 12 | |||
| 13 | const std = @import("std"); | ||
| 14 | const mem = std.mem; | ||
| 15 | const Allocator = std.mem.Allocator; | ||
| 16 | const assert = std.debug.assert; | ||
| 17 | const BigIntConst = std.math.big.int.Const; | ||
| 18 | const BigIntMutable = std.math.big.int.Mutable; | ||
| 19 | const ast = std.zig.ast; | ||
| 20 | |||
| 21 | const Zir = @This(); | ||
| 22 | const Type = @import("type.zig").Type; | ||
| 23 | const Value = @import("value.zig").Value; | ||
| 24 | const TypedValue = @import("TypedValue.zig"); | ||
| 25 | const ir = @import("ir.zig"); | ||
| 26 | const Module = @import("Module.zig"); | ||
| 27 | const LazySrcLoc = Module.LazySrcLoc; | ||
| 28 | |||
| 29 | instructions: std.MultiArrayList(Inst).Slice, | ||
| 30 | /// In order to store references to strings in fewer bytes, we copy all | ||
| 31 | /// string bytes into here. String bytes can be null. It is up to whomever | ||
| 32 | /// is referencing the data here whether they want to store both index and length, | ||
| 33 | /// thus allowing null bytes, or store only index, and use null-termination. The | ||
| 34 | /// `string_bytes` array is agnostic to either usage. | ||
| 35 | /// Indexes 0 and 1 are reserved for special cases. | ||
| 36 | string_bytes: []u8, | ||
| 37 | /// The meaning of this data is determined by `Inst.Tag` value. | ||
| 38 | /// The first few indexes are reserved. See `ExtraIndex` for the values. | ||
| 39 | extra: []u32, | ||
| 40 | |||
| 41 | /// The data stored at byte offset 0 when ZIR is stored in a file. | ||
| 42 | pub const Header = extern struct { | ||
| 43 | instructions_len: u32, | ||
| 44 | string_bytes_len: u32, | ||
| 45 | extra_len: u32, | ||
| 46 | |||
| 47 | stat_inode: std.fs.File.INode, | ||
| 48 | stat_size: u64, | ||
| 49 | stat_mtime: i128, | ||
| 50 | }; | ||
| 51 | |||
| 52 | pub const ExtraIndex = enum(u32) { | ||
| 53 | /// Ref. The main struct decl for this file. | ||
| 54 | main_struct, | ||
| 55 | /// If this is 0, no compile errors. Otherwise there is a `CompileErrors` | ||
| 56 | /// payload at this index. | ||
| 57 | compile_errors, | ||
| 58 | /// If this is 0, this file contains no imports. Otherwise there is a `Imports` | ||
| 59 | /// payload at this index. | ||
| 60 | imports, | ||
| 61 | |||
| 62 | _, | ||
| 63 | }; | ||
| 64 | |||
| 65 | pub fn getMainStruct(zir: Zir) Zir.Inst.Index { | ||
| 66 | return zir.extra[@enumToInt(ExtraIndex.main_struct)] - | ||
| 67 | @intCast(u32, Inst.Ref.typed_value_map.len); | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Returns the requested data, as well as the new index which is at the start of the | ||
| 71 | /// trailers for the object. | ||
| 72 | pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } { | ||
| 73 | const fields = std.meta.fields(T); | ||
| 74 | var i: usize = index; | ||
| 75 | var result: T = undefined; | ||
| 76 | inline for (fields) |field| { | ||
| 77 | @field(result, field.name) = switch (field.field_type) { | ||
| 78 | u32 => code.extra[i], | ||
| 79 | Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]), | ||
| 80 | i32 => @bitCast(i32, code.extra[i]), | ||
| 81 | else => @compileError("bad field type"), | ||
| 82 | }; | ||
| 83 | i += 1; | ||
| 84 | } | ||
| 85 | return .{ | ||
| 86 | .data = result, | ||
| 87 | .end = i, | ||
| 88 | }; | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Given an index into `string_bytes` returns the null-terminated string found there. | ||
| 92 | pub fn nullTerminatedString(code: Zir, index: usize) [:0]const u8 { | ||
| 93 | var end: usize = index; | ||
| 94 | while (code.string_bytes[end] != 0) { | ||
| 95 | end += 1; | ||
| 96 | } | ||
| 97 | return code.string_bytes[index..end :0]; | ||
| 98 | } | ||
| 99 | |||
| 100 | pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref { | ||
| 101 | const raw_slice = code.extra[start..][0..len]; | ||
| 102 | return @bitCast([]Inst.Ref, raw_slice); | ||
| 103 | } | ||
| 104 | |||
| 105 | pub fn hasCompileErrors(code: Zir) bool { | ||
| 106 | return code.extra[@enumToInt(ExtraIndex.compile_errors)] != 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | pub fn deinit(code: *Zir, gpa: *Allocator) void { | ||
| 110 | code.instructions.deinit(gpa); | ||
| 111 | gpa.free(code.string_bytes); | ||
| 112 | gpa.free(code.extra); | ||
| 113 | code.* = undefined; | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Write human-readable, debug formatted ZIR code to a file. | ||
| 117 | pub fn renderAsTextToFile( | ||
| 118 | gpa: *Allocator, | ||
| 119 | scope_file: *Module.Scope.File, | ||
| 120 | fs_file: std.fs.File, | ||
| 121 | ) !void { | ||
| 122 | var arena = std.heap.ArenaAllocator.init(gpa); | ||
| 123 | defer arena.deinit(); | ||
| 124 | |||
| 125 | var writer: Writer = .{ | ||
| 126 | .gpa = gpa, | ||
| 127 | .arena = &arena.allocator, | ||
| 128 | .file = scope_file, | ||
| 129 | .code = scope_file.zir, | ||
| 130 | .indent = 0, | ||
| 131 | .parent_decl_node = 0, | ||
| 132 | }; | ||
| 133 | |||
| 134 | const main_struct_inst = scope_file.zir.getMainStruct(); | ||
| 135 | try fs_file.writer().print("%{d} ", .{main_struct_inst}); | ||
| 136 | try writer.writeInstToStream(fs_file.writer(), main_struct_inst); | ||
| 137 | try fs_file.writeAll("\n"); | ||
| 138 | const imports_index = scope_file.zir.extra[@enumToInt(ExtraIndex.imports)]; | ||
| 139 | if (imports_index != 0) { | ||
| 140 | try fs_file.writeAll("Imports:\n"); | ||
| 141 | const imports_len = scope_file.zir.extra[imports_index]; | ||
| 142 | for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| { | ||
| 143 | const import_path = scope_file.zir.nullTerminatedString(str_index); | ||
| 144 | try fs_file.writer().print(" {s}\n", .{import_path}); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | /// These are untyped instructions generated from an Abstract Syntax Tree. | ||
| 150 | /// The data here is immutable because it is possible to have multiple | ||
| 151 | /// analyses on the same ZIR happening at the same time. | ||
| 152 | pub const Inst = struct { | ||
| 153 | tag: Tag, | ||
| 154 | data: Data, | ||
| 155 | |||
| 156 | /// These names are used directly as the instruction names in the text format. | ||
| 157 | /// See `data_field_map` for a list of which `Data` fields are used by each `Tag`. | ||
| 158 | pub const Tag = enum(u8) { | ||
| 159 | /// Arithmetic addition, asserts no integer overflow. | ||
| 160 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 161 | add, | ||
| 162 | /// Twos complement wrapping integer addition. | ||
| 163 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 164 | addwrap, | ||
| 165 | /// Declares a parameter of the current function. Used for debug info and | ||
| 166 | /// for checking shadowing against declarations in the current namespace. | ||
| 167 | /// Uses the `str_tok` field. Token is the parameter name, string is the | ||
| 168 | /// parameter name. | ||
| 169 | arg, | ||
| 170 | /// Array concatenation. `a ++ b` | ||
| 171 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 172 | array_cat, | ||
| 173 | /// Array multiplication `a ** b` | ||
| 174 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 175 | array_mul, | ||
| 176 | /// `[N]T` syntax. No source location provided. | ||
| 177 | /// Uses the `bin` union field. lhs is length, rhs is element type. | ||
| 178 | array_type, | ||
| 179 | /// `[N:S]T` syntax. No source location provided. | ||
| 180 | /// Uses the `array_type_sentinel` field. | ||
| 181 | array_type_sentinel, | ||
| 182 | /// `@Vector` builtin. | ||
| 183 | /// Uses the `pl_node` union field with `Bin` payload. | ||
| 184 | /// lhs is length, rhs is element type. | ||
| 185 | vector_type, | ||
| 186 | /// Given an array type, returns the element type. | ||
| 187 | /// Uses the `un_node` union field. | ||
| 188 | elem_type, | ||
| 189 | /// Given a pointer to an indexable object, returns the len property. This is | ||
| 190 | /// used by for loops. This instruction also emits a for-loop specific compile | ||
| 191 | /// error if the indexable object is not indexable. | ||
| 192 | /// Uses the `un_node` field. The AST node is the for loop node. | ||
| 193 | indexable_ptr_len, | ||
| 194 | /// Create a `anyframe->T` type. | ||
| 195 | /// Uses the `un_node` field. | ||
| 196 | anyframe_type, | ||
| 197 | /// Type coercion. No source location attached. | ||
| 198 | /// Uses the `bin` field. | ||
| 199 | as, | ||
| 200 | /// Type coercion to the function's return type. | ||
| 201 | /// Uses the `pl_node` field. Payload is `As`. AST node could be many things. | ||
| 202 | as_node, | ||
| 203 | /// Bitwise AND. `&` | ||
| 204 | bit_and, | ||
| 205 | /// Bitcast a value to a different type. | ||
| 206 | /// Uses the pl_node field with payload `Bin`. | ||
| 207 | bitcast, | ||
| 208 | /// A typed result location pointer is bitcasted to a new result location pointer. | ||
| 209 | /// The new result location pointer has an inferred type. | ||
| 210 | /// Uses the pl_node field with payload `Bin`. | ||
| 211 | bitcast_result_ptr, | ||
| 212 | /// Bitwise NOT. `~` | ||
| 213 | /// Uses `un_node`. | ||
| 214 | bit_not, | ||
| 215 | /// Bitwise OR. `|` | ||
| 216 | bit_or, | ||
| 217 | /// A labeled block of code, which can return a value. | ||
| 218 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 219 | block, | ||
| 220 | /// A list of instructions which are analyzed in the parent context, without | ||
| 221 | /// generating a runtime block. Must terminate with an "inline" variant of | ||
| 222 | /// a noreturn instruction. | ||
| 223 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 224 | block_inline, | ||
| 225 | /// Implements `suspend {...}`. | ||
| 226 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 227 | suspend_block, | ||
| 228 | /// Boolean AND. See also `bit_and`. | ||
| 229 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 230 | bool_and, | ||
| 231 | /// Boolean NOT. See also `bit_not`. | ||
| 232 | /// Uses the `un_node` field. | ||
| 233 | bool_not, | ||
| 234 | /// Boolean OR. See also `bit_or`. | ||
| 235 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 236 | bool_or, | ||
| 237 | /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand | ||
| 238 | /// is a block, which is evaluated if `lhs` is `true`. | ||
| 239 | /// Uses the `bool_br` union field. | ||
| 240 | bool_br_and, | ||
| 241 | /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand | ||
| 242 | /// is a block, which is evaluated if `lhs` is `false`. | ||
| 243 | /// Uses the `bool_br` union field. | ||
| 244 | bool_br_or, | ||
| 245 | /// Return a value from a block. | ||
| 246 | /// Uses the `break` union field. | ||
| 247 | /// Uses the source information from previous instruction. | ||
| 248 | @"break", | ||
| 249 | /// Return a value from a block. This instruction is used as the terminator | ||
| 250 | /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`. | ||
| 251 | /// This instruction may also be used when it is known that there is only one | ||
| 252 | /// break instruction in a block, and the target block is the parent. | ||
| 253 | /// Uses the `break` union field. | ||
| 254 | break_inline, | ||
| 255 | /// Uses the `node` union field. | ||
| 256 | breakpoint, | ||
| 257 | /// Function call with modifier `.auto`. | ||
| 258 | /// Uses `pl_node`. AST node is the function call. Payload is `Call`. | ||
| 259 | call, | ||
| 260 | /// Same as `call` but it also does `ensure_result_used` on the return value. | ||
| 261 | call_chkused, | ||
| 262 | /// Same as `call` but with modifier `.compile_time`. | ||
| 263 | call_compile_time, | ||
| 264 | /// Same as `call` but with modifier `.no_suspend`. | ||
| 265 | call_nosuspend, | ||
| 266 | /// Same as `call` but with modifier `.async_kw`. | ||
| 267 | call_async, | ||
| 268 | /// `<` | ||
| 269 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 270 | cmp_lt, | ||
| 271 | /// `<=` | ||
| 272 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 273 | cmp_lte, | ||
| 274 | /// `==` | ||
| 275 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 276 | cmp_eq, | ||
| 277 | /// `>=` | ||
| 278 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 279 | cmp_gte, | ||
| 280 | /// `>` | ||
| 281 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 282 | cmp_gt, | ||
| 283 | /// `!=` | ||
| 284 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 285 | cmp_neq, | ||
| 286 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- | ||
| 287 | /// as type coercion from the new element type to the old element type. | ||
| 288 | /// Uses the `bin` union field. | ||
| 289 | /// LHS is destination element type, RHS is result pointer. | ||
| 290 | coerce_result_ptr, | ||
| 291 | /// Conditional branch. Splits control flow based on a boolean condition value. | ||
| 292 | /// Uses the `pl_node` union field. AST node is an if, while, for, etc. | ||
| 293 | /// Payload is `CondBr`. | ||
| 294 | condbr, | ||
| 295 | /// Same as `condbr`, except the condition is coerced to a comptime value, and | ||
| 296 | /// only the taken branch is analyzed. The then block and else block must | ||
| 297 | /// terminate with an "inline" variant of a noreturn instruction. | ||
| 298 | condbr_inline, | ||
| 299 | /// An opaque type definition. Provides an AST node only. | ||
| 300 | /// Uses the `pl_node` union field. Payload is `OpaqueDecl`. | ||
| 301 | opaque_decl, | ||
| 302 | opaque_decl_anon, | ||
| 303 | opaque_decl_func, | ||
| 304 | /// An error set type definition. Contains a list of field names. | ||
| 305 | /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`. | ||
| 306 | error_set_decl, | ||
| 307 | error_set_decl_anon, | ||
| 308 | error_set_decl_func, | ||
| 309 | /// Declares the beginning of a statement. Used for debug info. | ||
| 310 | /// Uses the `dbg_stmt` union field. The line and column are offset | ||
| 311 | /// from the parent declaration. | ||
| 312 | dbg_stmt, | ||
| 313 | /// Uses a name to identify a Decl and takes a pointer to it. | ||
| 314 | /// Uses the `str_tok` union field. | ||
| 315 | decl_ref, | ||
| 316 | /// Uses a name to identify a Decl and uses it as a value. | ||
| 317 | /// Uses the `str_tok` union field. | ||
| 318 | decl_val, | ||
| 319 | /// Load the value from a pointer. Assumes `x.*` syntax. | ||
| 320 | /// Uses `un_node` field. AST node is the `x.*` syntax. | ||
| 321 | load, | ||
| 322 | /// Arithmetic division. Asserts no integer overflow. | ||
| 323 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 324 | div, | ||
| 325 | /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at | ||
| 326 | /// the provided index. Uses the `bin` union field. Source location is implied | ||
| 327 | /// to be the same as the previous instruction. | ||
| 328 | elem_ptr, | ||
| 329 | /// Same as `elem_ptr` except also stores a source location node. | ||
| 330 | /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. | ||
| 331 | elem_ptr_node, | ||
| 332 | /// Given an array, slice, or pointer, returns the element at the provided index. | ||
| 333 | /// Uses the `bin` union field. Source location is implied to be the same | ||
| 334 | /// as the previous instruction. | ||
| 335 | elem_val, | ||
| 336 | /// Same as `elem_val` except also stores a source location node. | ||
| 337 | /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. | ||
| 338 | elem_val_node, | ||
| 339 | /// Emits a compile error if the operand is not `void`. | ||
| 340 | /// Uses the `un_node` field. | ||
| 341 | ensure_result_used, | ||
| 342 | /// Emits a compile error if an error is ignored. | ||
| 343 | /// Uses the `un_node` field. | ||
| 344 | ensure_result_non_error, | ||
| 345 | /// Create a `E!T` type. | ||
| 346 | /// Uses the `pl_node` field with `Bin` payload. | ||
| 347 | error_union_type, | ||
| 348 | /// `error.Foo` syntax. Uses the `str_tok` field of the Data union. | ||
| 349 | error_value, | ||
| 350 | /// Implements the `@export` builtin function. | ||
| 351 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 352 | @"export", | ||
| 353 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | ||
| 354 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. | ||
| 355 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. | ||
| 356 | field_ptr, | ||
| 357 | /// Given a struct or object that contains virtual fields, returns the named field. | ||
| 358 | /// The field name is stored in string_bytes. Used by a.b syntax. | ||
| 359 | /// This instruction also accepts a pointer. | ||
| 360 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. | ||
| 361 | field_val, | ||
| 362 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | ||
| 363 | /// to the named field. The field name is a comptime instruction. Used by @field. | ||
| 364 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. | ||
| 365 | field_ptr_named, | ||
| 366 | /// Given a struct or object that contains virtual fields, returns the named field. | ||
| 367 | /// The field name is a comptime instruction. Used by @field. | ||
| 368 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. | ||
| 369 | field_val_named, | ||
| 370 | /// Returns a function type, or a function instance, depending on whether | ||
| 371 | /// the body_len is 0. Calling convention is auto. | ||
| 372 | /// Uses the `pl_node` union field. `payload_index` points to a `Func`. | ||
| 373 | func, | ||
| 374 | /// Same as `func` but has an inferred error set. | ||
| 375 | func_inferred, | ||
| 376 | /// Implements the `@import` builtin. | ||
| 377 | /// Uses the `str_tok` field. | ||
| 378 | import, | ||
| 379 | /// Integer literal that fits in a u64. Uses the `int` union field. | ||
| 380 | int, | ||
| 381 | /// Arbitrary sized integer literal. Uses the `str` union field. | ||
| 382 | int_big, | ||
| 383 | /// A float literal that fits in a f32. Uses the float union value. | ||
| 384 | float, | ||
| 385 | /// A float literal that fits in a f128. Uses the `pl_node` union value. | ||
| 386 | /// Payload is `Float128`. | ||
| 387 | float128, | ||
| 388 | /// Make an integer type out of signedness and bit count. | ||
| 389 | /// Payload is `int_type` | ||
| 390 | int_type, | ||
| 391 | /// Return a boolean false if an optional is null. `x != null` | ||
| 392 | /// Uses the `un_node` field. | ||
| 393 | is_non_null, | ||
| 394 | /// Return a boolean true if an optional is null. `x == null` | ||
| 395 | /// Uses the `un_node` field. | ||
| 396 | is_null, | ||
| 397 | /// Return a boolean false if an optional is null. `x.* != null` | ||
| 398 | /// Uses the `un_node` field. | ||
| 399 | is_non_null_ptr, | ||
| 400 | /// Return a boolean true if an optional is null. `x.* == null` | ||
| 401 | /// Uses the `un_node` field. | ||
| 402 | is_null_ptr, | ||
| 403 | /// Return a boolean true if value is an error | ||
| 404 | /// Uses the `un_node` field. | ||
| 405 | is_err, | ||
| 406 | /// Return a boolean true if dereferenced pointer is an error | ||
| 407 | /// Uses the `un_node` field. | ||
| 408 | is_err_ptr, | ||
| 409 | /// A labeled block of code that loops forever. At the end of the body will have either | ||
| 410 | /// a `repeat` instruction or a `repeat_inline` instruction. | ||
| 411 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. | ||
| 412 | /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema | ||
| 413 | /// needs to emit more than 1 TZIR block for this instruction. | ||
| 414 | /// The payload is `Block`. | ||
| 415 | loop, | ||
| 416 | /// Sends runtime control flow back to the beginning of the current block. | ||
| 417 | /// Uses the `node` field. | ||
| 418 | repeat, | ||
| 419 | /// Sends comptime control flow back to the beginning of the current block. | ||
| 420 | /// Uses the `node` field. | ||
| 421 | repeat_inline, | ||
| 422 | /// Merge two error sets into one, `E1 || E2`. | ||
| 423 | /// Uses the `pl_node` field with payload `Bin`. | ||
| 424 | merge_error_sets, | ||
| 425 | /// Ambiguously remainder division or modulus. If the computation would possibly have | ||
| 426 | /// a different value depending on whether the operation is remainder division or modulus, | ||
| 427 | /// a compile error is emitted. Otherwise the computation is performed. | ||
| 428 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 429 | mod_rem, | ||
| 430 | /// Arithmetic multiplication. Asserts no integer overflow. | ||
| 431 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 432 | mul, | ||
| 433 | /// Twos complement wrapping integer multiplication. | ||
| 434 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 435 | mulwrap, | ||
| 436 | /// Given a reference to a function and a parameter index, returns the | ||
| 437 | /// type of the parameter. The only usage of this instruction is for the | ||
| 438 | /// result location of parameters of function calls. In the case of a function's | ||
| 439 | /// parameter type being `anytype`, it is the type coercion's job to detect this | ||
| 440 | /// scenario and skip the coercion, so that semantic analysis of this instruction | ||
| 441 | /// is not in a position where it must create an invalid type. | ||
| 442 | /// Uses the `param_type` union field. | ||
| 443 | param_type, | ||
| 444 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, | ||
| 445 | /// stores it in a memory location, and returns a const pointer to it. If the value | ||
| 446 | /// is `comptime`, the memory location is global static constant data. Otherwise, | ||
| 447 | /// the memory location is in the stack frame, local to the scope containing the | ||
| 448 | /// instruction. | ||
| 449 | /// Uses the `un_tok` union field. | ||
| 450 | ref, | ||
| 451 | /// Sends control flow back to the function's callee. | ||
| 452 | /// Includes an operand as the return value. | ||
| 453 | /// Includes an AST node source location. | ||
| 454 | /// Uses the `un_node` union field. | ||
| 455 | ret_node, | ||
| 456 | /// Sends control flow back to the function's callee. | ||
| 457 | /// Includes an operand as the return value. | ||
| 458 | /// Includes a token source location. | ||
| 459 | /// Uses the `un_tok` union field. | ||
| 460 | /// The operand needs to get coerced to the function's return type. | ||
| 461 | ret_coerce, | ||
| 462 | /// Create a pointer type that does not have a sentinel, alignment, or bit range specified. | ||
| 463 | /// Uses the `ptr_type_simple` union field. | ||
| 464 | ptr_type_simple, | ||
| 465 | /// Create a pointer type which can have a sentinel, alignment, and/or bit range. | ||
| 466 | /// Uses the `ptr_type` union field. | ||
| 467 | ptr_type, | ||
| 468 | /// Slice operation `lhs[rhs..]`. No sentinel and no end offset. | ||
| 469 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`. | ||
| 470 | slice_start, | ||
| 471 | /// Slice operation `array_ptr[start..end]`. No sentinel. | ||
| 472 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`. | ||
| 473 | slice_end, | ||
| 474 | /// Slice operation `array_ptr[start..end:sentinel]`. | ||
| 475 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`. | ||
| 476 | slice_sentinel, | ||
| 477 | /// Write a value to a pointer. For loading, see `load`. | ||
| 478 | /// Source location is assumed to be same as previous instruction. | ||
| 479 | /// Uses the `bin` union field. | ||
| 480 | store, | ||
| 481 | /// Same as `store` except provides a source location. | ||
| 482 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 483 | store_node, | ||
| 484 | /// Same as `store` but the type of the value being stored will be used to infer | ||
| 485 | /// the block type. The LHS is the pointer to store to. | ||
| 486 | /// Uses the `bin` union field. | ||
| 487 | /// If the pointer is none, it means this instruction has been elided in | ||
| 488 | /// AstGen, but AstGen was unable to actually omit it from the ZIR code. | ||
| 489 | store_to_block_ptr, | ||
| 490 | /// Same as `store` but the type of the value being stored will be used to infer | ||
| 491 | /// the pointer type. | ||
| 492 | /// Uses the `bin` union field - Astgen.zig depends on the ability to change | ||
| 493 | /// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr` | ||
| 494 | /// without changing the data. | ||
| 495 | store_to_inferred_ptr, | ||
| 496 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. | ||
| 497 | /// Uses the `str` union field. | ||
| 498 | str, | ||
| 499 | /// Arithmetic subtraction. Asserts no integer overflow. | ||
| 500 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 501 | sub, | ||
| 502 | /// Twos complement wrapping integer subtraction. | ||
| 503 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 504 | subwrap, | ||
| 505 | /// Arithmetic negation. Asserts no integer overflow. | ||
| 506 | /// Same as sub with a lhs of 0, split into a separate instruction to save memory. | ||
| 507 | /// Uses `un_node`. | ||
| 508 | negate, | ||
| 509 | /// Twos complement wrapping integer negation. | ||
| 510 | /// Same as subwrap with a lhs of 0, split into a separate instruction to save memory. | ||
| 511 | /// Uses `un_node`. | ||
| 512 | negate_wrap, | ||
| 513 | /// Returns the type of a value. | ||
| 514 | /// Uses the `un_node` field. | ||
| 515 | typeof, | ||
| 516 | /// Given a value which is a pointer, returns the element type. | ||
| 517 | /// Uses the `un_node` field. | ||
| 518 | typeof_elem, | ||
| 519 | /// Given a value, look at the type of it, which must be an integer type. | ||
| 520 | /// Returns the integer type for the RHS of a shift operation. | ||
| 521 | /// Uses the `un_node` field. | ||
| 522 | typeof_log2_int_type, | ||
| 523 | /// Given an integer type, returns the integer type for the RHS of a shift operation. | ||
| 524 | /// Uses the `un_node` field. | ||
| 525 | log2_int_type, | ||
| 526 | /// Asserts control-flow will not reach this instruction (`unreachable`). | ||
| 527 | /// Uses the `unreachable` union field. | ||
| 528 | @"unreachable", | ||
| 529 | /// Bitwise XOR. `^` | ||
| 530 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 531 | xor, | ||
| 532 | /// Create an optional type '?T' | ||
| 533 | /// Uses the `un_node` field. | ||
| 534 | optional_type, | ||
| 535 | /// ?T => T with safety. | ||
| 536 | /// Given an optional value, returns the payload value, with a safety check that | ||
| 537 | /// the value is non-null. Used for `orelse`, `if` and `while`. | ||
| 538 | /// Uses the `un_node` field. | ||
| 539 | optional_payload_safe, | ||
| 540 | /// ?T => T without safety. | ||
| 541 | /// Given an optional value, returns the payload value. No safety checks. | ||
| 542 | /// Uses the `un_node` field. | ||
| 543 | optional_payload_unsafe, | ||
| 544 | /// *?T => *T with safety. | ||
| 545 | /// Given a pointer to an optional value, returns a pointer to the payload value, | ||
| 546 | /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`. | ||
| 547 | /// Uses the `un_node` field. | ||
| 548 | optional_payload_safe_ptr, | ||
| 549 | /// *?T => *T without safety. | ||
| 550 | /// Given a pointer to an optional value, returns a pointer to the payload value. | ||
| 551 | /// No safety checks. | ||
| 552 | /// Uses the `un_node` field. | ||
| 553 | optional_payload_unsafe_ptr, | ||
| 554 | /// E!T => T with safety. | ||
| 555 | /// Given an error union value, returns the payload value, with a safety check | ||
| 556 | /// that the value is not an error. Used for catch, if, and while. | ||
| 557 | /// Uses the `un_node` field. | ||
| 558 | err_union_payload_safe, | ||
| 559 | /// E!T => T without safety. | ||
| 560 | /// Given an error union value, returns the payload value. No safety checks. | ||
| 561 | /// Uses the `un_node` field. | ||
| 562 | err_union_payload_unsafe, | ||
| 563 | /// *E!T => *T with safety. | ||
| 564 | /// Given a pointer to an error union value, returns a pointer to the payload value, | ||
| 565 | /// with a safety check that the value is not an error. Used for catch, if, and while. | ||
| 566 | /// Uses the `un_node` field. | ||
| 567 | err_union_payload_safe_ptr, | ||
| 568 | /// *E!T => *T without safety. | ||
| 569 | /// Given a pointer to a error union value, returns a pointer to the payload value. | ||
| 570 | /// No safety checks. | ||
| 571 | /// Uses the `un_node` field. | ||
| 572 | err_union_payload_unsafe_ptr, | ||
| 573 | /// E!T => E without safety. | ||
| 574 | /// Given an error union value, returns the error code. No safety checks. | ||
| 575 | /// Uses the `un_node` field. | ||
| 576 | err_union_code, | ||
| 577 | /// *E!T => E without safety. | ||
| 578 | /// Given a pointer to an error union value, returns the error code. No safety checks. | ||
| 579 | /// Uses the `un_node` field. | ||
| 580 | err_union_code_ptr, | ||
| 581 | /// Takes a *E!T and raises a compiler error if T != void | ||
| 582 | /// Uses the `un_tok` field. | ||
| 583 | ensure_err_payload_void, | ||
| 584 | /// An enum literal. Uses the `str_tok` union field. | ||
| 585 | enum_literal, | ||
| 586 | /// A switch expression. Uses the `pl_node` union field. | ||
| 587 | /// AST node is the switch, payload is `SwitchBlock`. | ||
| 588 | /// All prongs of target handled. | ||
| 589 | switch_block, | ||
| 590 | /// Same as switch_block, except one or more prongs have multiple items. | ||
| 591 | /// Payload is `SwitchBlockMulti` | ||
| 592 | switch_block_multi, | ||
| 593 | /// Same as switch_block, except has an else prong. | ||
| 594 | switch_block_else, | ||
| 595 | /// Same as switch_block_else, except one or more prongs have multiple items. | ||
| 596 | /// Payload is `SwitchBlockMulti` | ||
| 597 | switch_block_else_multi, | ||
| 598 | /// Same as switch_block, except has an underscore prong. | ||
| 599 | switch_block_under, | ||
| 600 | /// Same as switch_block, except one or more prongs have multiple items. | ||
| 601 | /// Payload is `SwitchBlockMulti` | ||
| 602 | switch_block_under_multi, | ||
| 603 | /// Same as `switch_block` but the target is a pointer to the value being switched on. | ||
| 604 | switch_block_ref, | ||
| 605 | /// Same as `switch_block_multi` but the target is a pointer to the value being switched on. | ||
| 606 | /// Payload is `SwitchBlockMulti` | ||
| 607 | switch_block_ref_multi, | ||
| 608 | /// Same as `switch_block_else` but the target is a pointer to the value being switched on. | ||
| 609 | switch_block_ref_else, | ||
| 610 | /// Same as `switch_block_else_multi` but the target is a pointer to the | ||
| 611 | /// value being switched on. | ||
| 612 | /// Payload is `SwitchBlockMulti` | ||
| 613 | switch_block_ref_else_multi, | ||
| 614 | /// Same as `switch_block_under` but the target is a pointer to the value | ||
| 615 | /// being switched on. | ||
| 616 | switch_block_ref_under, | ||
| 617 | /// Same as `switch_block_under_multi` but the target is a pointer to | ||
| 618 | /// the value being switched on. | ||
| 619 | /// Payload is `SwitchBlockMulti` | ||
| 620 | switch_block_ref_under_multi, | ||
| 621 | /// Produces the capture value for a switch prong. | ||
| 622 | /// Uses the `switch_capture` field. | ||
| 623 | switch_capture, | ||
| 624 | /// Produces the capture value for a switch prong. | ||
| 625 | /// Result is a pointer to the value. | ||
| 626 | /// Uses the `switch_capture` field. | ||
| 627 | switch_capture_ref, | ||
| 628 | /// Produces the capture value for a switch prong. | ||
| 629 | /// The prong is one of the multi cases. | ||
| 630 | /// Uses the `switch_capture` field. | ||
| 631 | switch_capture_multi, | ||
| 632 | /// Produces the capture value for a switch prong. | ||
| 633 | /// The prong is one of the multi cases. | ||
| 634 | /// Result is a pointer to the value. | ||
| 635 | /// Uses the `switch_capture` field. | ||
| 636 | switch_capture_multi_ref, | ||
| 637 | /// Produces the capture value for the else/'_' switch prong. | ||
| 638 | /// Uses the `switch_capture` field. | ||
| 639 | switch_capture_else, | ||
| 640 | /// Produces the capture value for the else/'_' switch prong. | ||
| 641 | /// Result is a pointer to the value. | ||
| 642 | /// Uses the `switch_capture` field. | ||
| 643 | switch_capture_else_ref, | ||
| 644 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct | ||
| 645 | /// initialization expression, and emits compile errors for duplicate fields | ||
| 646 | /// as well as missing fields, if applicable. | ||
| 647 | /// This instruction asserts that there is at least one field_ptr instruction, | ||
| 648 | /// because it must use one of them to find out the struct type. | ||
| 649 | /// Uses the `pl_node` field. Payload is `Block`. | ||
| 650 | validate_struct_init_ptr, | ||
| 651 | /// Given a set of `elem_ptr_node` instructions, assumes they are all part of an | ||
| 652 | /// array initialization expression, and emits a compile error if the number of | ||
| 653 | /// elements does not match the array type. | ||
| 654 | /// This instruction asserts that there is at least one elem_ptr_node instruction, | ||
| 655 | /// because it must use one of them to find out the array type. | ||
| 656 | /// Uses the `pl_node` field. Payload is `Block`. | ||
| 657 | validate_array_init_ptr, | ||
| 658 | /// A struct literal with a specified type, with no fields. | ||
| 659 | /// Uses the `un_node` field. | ||
| 660 | struct_init_empty, | ||
| 661 | /// Given a struct, union, or enum, and a field name as a string index, | ||
| 662 | /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`. | ||
| 663 | field_type, | ||
| 664 | /// Given a struct, union, or enum, and a field name as a Ref, | ||
| 665 | /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`. | ||
| 666 | field_type_ref, | ||
| 667 | /// Finalizes a typed struct initialization, performs validation, and returns the | ||
| 668 | /// struct value. | ||
| 669 | /// Uses the `pl_node` field. Payload is `StructInit`. | ||
| 670 | struct_init, | ||
| 671 | /// Struct initialization syntax, make the result a pointer. | ||
| 672 | /// Uses the `pl_node` field. Payload is `StructInit`. | ||
| 673 | struct_init_ref, | ||
| 674 | /// Struct initialization without a type. | ||
| 675 | /// Uses the `pl_node` field. Payload is `StructInitAnon`. | ||
| 676 | struct_init_anon, | ||
| 677 | /// Anonymous struct initialization syntax, make the result a pointer. | ||
| 678 | /// Uses the `pl_node` field. Payload is `StructInitAnon`. | ||
| 679 | struct_init_anon_ref, | ||
| 680 | /// Array initialization syntax. | ||
| 681 | /// Uses the `pl_node` field. Payload is `MultiOp`. | ||
| 682 | array_init, | ||
| 683 | /// Anonymous array initialization syntax. | ||
| 684 | /// Uses the `pl_node` field. Payload is `MultiOp`. | ||
| 685 | array_init_anon, | ||
| 686 | /// Array initialization syntax, make the result a pointer. | ||
| 687 | /// Uses the `pl_node` field. Payload is `MultiOp`. | ||
| 688 | array_init_ref, | ||
| 689 | /// Anonymous array initialization syntax, make the result a pointer. | ||
| 690 | /// Uses the `pl_node` field. Payload is `MultiOp`. | ||
| 691 | array_init_anon_ref, | ||
| 692 | /// Given a pointer to a union and a comptime known field name, activates that field | ||
| 693 | /// and returns a pointer to it. | ||
| 694 | /// Uses the `pl_node` field. Payload is `UnionInitPtr`. | ||
| 695 | union_init_ptr, | ||
| 696 | /// Implements the `@typeInfo` builtin. Uses `un_node`. | ||
| 697 | type_info, | ||
| 698 | /// Implements the `@sizeOf` builtin. Uses `un_node`. | ||
| 699 | size_of, | ||
| 700 | /// Implements the `@bitSizeOf` builtin. Uses `un_node`. | ||
| 701 | bit_size_of, | ||
| 702 | /// Implements the `@fence` builtin. Uses `node`. | ||
| 703 | fence, | ||
| 704 | |||
| 705 | /// Implement builtin `@ptrToInt`. Uses `un_node`. | ||
| 706 | /// Convert a pointer to a `usize` integer. | ||
| 707 | ptr_to_int, | ||
| 708 | /// Implement builtin `@errToInt`. Uses `un_node`. | ||
| 709 | error_to_int, | ||
| 710 | /// Implement builtin `@intToError`. Uses `un_node`. | ||
| 711 | int_to_error, | ||
| 712 | /// Emit an error message and fail compilation. | ||
| 713 | /// Uses the `un_node` field. | ||
| 714 | compile_error, | ||
| 715 | /// Changes the maximum number of backwards branches that compile-time | ||
| 716 | /// code execution can use before giving up and making a compile error. | ||
| 717 | /// Uses the `un_node` union field. | ||
| 718 | set_eval_branch_quota, | ||
| 719 | /// Converts an enum value into an integer. Resulting type will be the tag type | ||
| 720 | /// of the enum. Uses `un_node`. | ||
| 721 | enum_to_int, | ||
| 722 | /// Implement builtin `@alignOf`. Uses `un_node`. | ||
| 723 | align_of, | ||
| 724 | /// Implement builtin `@boolToInt`. Uses `un_node`. | ||
| 725 | bool_to_int, | ||
| 726 | /// Implement builtin `@embedFile`. Uses `un_node`. | ||
| 727 | embed_file, | ||
| 728 | /// Implement builtin `@errorName`. Uses `un_node`. | ||
| 729 | error_name, | ||
| 730 | /// Implement builtin `@panic`. Uses `un_node`. | ||
| 731 | panic, | ||
| 732 | /// Implement builtin `@setAlignStack`. Uses `un_node`. | ||
| 733 | set_align_stack, | ||
| 734 | /// Implement builtin `@setCold`. Uses `un_node`. | ||
| 735 | set_cold, | ||
| 736 | /// Implement builtin `@setFloatMode`. Uses `un_node`. | ||
| 737 | set_float_mode, | ||
| 738 | /// Implement builtin `@setRuntimeSafety`. Uses `un_node`. | ||
| 739 | set_runtime_safety, | ||
| 740 | /// Implement builtin `@sqrt`. Uses `un_node`. | ||
| 741 | sqrt, | ||
| 742 | /// Implement builtin `@sin`. Uses `un_node`. | ||
| 743 | sin, | ||
| 744 | /// Implement builtin `@cos`. Uses `un_node`. | ||
| 745 | cos, | ||
| 746 | /// Implement builtin `@exp`. Uses `un_node`. | ||
| 747 | exp, | ||
| 748 | /// Implement builtin `@exp2`. Uses `un_node`. | ||
| 749 | exp2, | ||
| 750 | /// Implement builtin `@log`. Uses `un_node`. | ||
| 751 | log, | ||
| 752 | /// Implement builtin `@log2`. Uses `un_node`. | ||
| 753 | log2, | ||
| 754 | /// Implement builtin `@log10`. Uses `un_node`. | ||
| 755 | log10, | ||
| 756 | /// Implement builtin `@fabs`. Uses `un_node`. | ||
| 757 | fabs, | ||
| 758 | /// Implement builtin `@floor`. Uses `un_node`. | ||
| 759 | floor, | ||
| 760 | /// Implement builtin `@ceil`. Uses `un_node`. | ||
| 761 | ceil, | ||
| 762 | /// Implement builtin `@trunc`. Uses `un_node`. | ||
| 763 | trunc, | ||
| 764 | /// Implement builtin `@round`. Uses `un_node`. | ||
| 765 | round, | ||
| 766 | /// Implement builtin `@tagName`. Uses `un_node`. | ||
| 767 | tag_name, | ||
| 768 | /// Implement builtin `@Type`. Uses `un_node`. | ||
| 769 | reify, | ||
| 770 | /// Implement builtin `@typeName`. Uses `un_node`. | ||
| 771 | type_name, | ||
| 772 | /// Implement builtin `@Frame`. Uses `un_node`. | ||
| 773 | frame_type, | ||
| 774 | /// Implement builtin `@frameSize`. Uses `un_node`. | ||
| 775 | frame_size, | ||
| 776 | |||
| 777 | /// Implements the `@floatToInt` builtin. | ||
| 778 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 779 | float_to_int, | ||
| 780 | /// Implements the `@intToFloat` builtin. | ||
| 781 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 782 | int_to_float, | ||
| 783 | /// Implements the `@intToPtr` builtin. | ||
| 784 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 785 | int_to_ptr, | ||
| 786 | /// Converts an integer into an enum value. | ||
| 787 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 788 | int_to_enum, | ||
| 789 | /// Convert a larger float type to any other float type, possibly causing | ||
| 790 | /// a loss of precision. | ||
| 791 | /// Uses the `pl_node` field. AST is the `@floatCast` syntax. | ||
| 792 | /// Payload is `Bin` with lhs as the dest type, rhs the operand. | ||
| 793 | float_cast, | ||
| 794 | /// Implements the `@intCast` builtin. | ||
| 795 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 796 | /// Convert an integer value to another integer type, asserting that the destination type | ||
| 797 | /// can hold the same mathematical value. | ||
| 798 | int_cast, | ||
| 799 | /// Implements the `@errSetCast` builtin. | ||
| 800 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 801 | err_set_cast, | ||
| 802 | /// Implements the `@ptrCast` builtin. | ||
| 803 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 804 | ptr_cast, | ||
| 805 | /// Implements the `@truncate` builtin. | ||
| 806 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. | ||
| 807 | truncate, | ||
| 808 | /// Implements the `@alignCast` builtin. | ||
| 809 | /// Uses `pl_node` with payload `Bin`. `lhs` is dest alignment, `rhs` is operand. | ||
| 810 | align_cast, | ||
| 811 | |||
| 812 | /// Implements the `@hasDecl` builtin. | ||
| 813 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 814 | has_decl, | ||
| 815 | /// Implements the `@hasField` builtin. | ||
| 816 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 817 | has_field, | ||
| 818 | |||
| 819 | /// Implements the `@clz` builtin. Uses the `un_node` union field. | ||
| 820 | clz, | ||
| 821 | /// Implements the `@ctz` builtin. Uses the `un_node` union field. | ||
| 822 | ctz, | ||
| 823 | /// Implements the `@popCount` builtin. Uses the `un_node` union field. | ||
| 824 | pop_count, | ||
| 825 | /// Implements the `@byteSwap` builtin. Uses the `un_node` union field. | ||
| 826 | byte_swap, | ||
| 827 | /// Implements the `@bitReverse` builtin. Uses the `un_node` union field. | ||
| 828 | bit_reverse, | ||
| 829 | |||
| 830 | /// Implements the `@divExact` builtin. | ||
| 831 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 832 | div_exact, | ||
| 833 | /// Implements the `@divFloor` builtin. | ||
| 834 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 835 | div_floor, | ||
| 836 | /// Implements the `@divTrunc` builtin. | ||
| 837 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 838 | div_trunc, | ||
| 839 | /// Implements the `@mod` builtin. | ||
| 840 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 841 | mod, | ||
| 842 | /// Implements the `@rem` builtin. | ||
| 843 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 844 | rem, | ||
| 845 | |||
| 846 | /// Integer shift-left. Zeroes are shifted in from the right hand side. | ||
| 847 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 848 | shl, | ||
| 849 | /// Implements the `@shlExact` builtin. | ||
| 850 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 851 | shl_exact, | ||
| 852 | /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. | ||
| 853 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 854 | shr, | ||
| 855 | /// Implements the `@shrExact` builtin. | ||
| 856 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 857 | shr_exact, | ||
| 858 | |||
| 859 | /// Implements the `@bitOffsetOf` builtin. | ||
| 860 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 861 | bit_offset_of, | ||
| 862 | /// Implements the `@byteOffsetOf` builtin. | ||
| 863 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 864 | byte_offset_of, | ||
| 865 | /// Implements the `@cmpxchgStrong` builtin. | ||
| 866 | /// Uses the `pl_node` union field with payload `Cmpxchg`. | ||
| 867 | cmpxchg_strong, | ||
| 868 | /// Implements the `@cmpxchgWeak` builtin. | ||
| 869 | /// Uses the `pl_node` union field with payload `Cmpxchg`. | ||
| 870 | cmpxchg_weak, | ||
| 871 | /// Implements the `@splat` builtin. | ||
| 872 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 873 | splat, | ||
| 874 | /// Implements the `@reduce` builtin. | ||
| 875 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 876 | reduce, | ||
| 877 | /// Implements the `@shuffle` builtin. | ||
| 878 | /// Uses the `pl_node` union field with payload `Shuffle`. | ||
| 879 | shuffle, | ||
| 880 | /// Implements the `@atomicLoad` builtin. | ||
| 881 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 882 | atomic_load, | ||
| 883 | /// Implements the `@atomicRmw` builtin. | ||
| 884 | /// Uses the `pl_node` union field with payload `AtomicRmw`. | ||
| 885 | atomic_rmw, | ||
| 886 | /// Implements the `@atomicStore` builtin. | ||
| 887 | /// Uses the `pl_node` union field with payload `AtomicStore`. | ||
| 888 | atomic_store, | ||
| 889 | /// Implements the `@mulAdd` builtin. | ||
| 890 | /// Uses the `pl_node` union field with payload `MulAdd`. | ||
| 891 | mul_add, | ||
| 892 | /// Implements the `@call` builtin. | ||
| 893 | /// Uses the `pl_node` union field with payload `BuiltinCall`. | ||
| 894 | builtin_call, | ||
| 895 | /// Given a type and a field name, returns a pointer to the field type. | ||
| 896 | /// Assumed to be part of a `@fieldParentPtr` builtin call. | ||
| 897 | /// Uses the `bin` union field. LHS is type, RHS is field name. | ||
| 898 | field_ptr_type, | ||
| 899 | /// Implements the `@fieldParentPtr` builtin. | ||
| 900 | /// Uses the `pl_node` union field with payload `FieldParentPtr`. | ||
| 901 | field_parent_ptr, | ||
| 902 | /// Implements the `@memcpy` builtin. | ||
| 903 | /// Uses the `pl_node` union field with payload `Memcpy`. | ||
| 904 | memcpy, | ||
| 905 | /// Implements the `@memset` builtin. | ||
| 906 | /// Uses the `pl_node` union field with payload `Memset`. | ||
| 907 | memset, | ||
| 908 | /// Implements the `@asyncCall` builtin. | ||
| 909 | /// Uses the `pl_node` union field with payload `AsyncCall`. | ||
| 910 | builtin_async_call, | ||
| 911 | /// Implements the `@cImport` builtin. | ||
| 912 | /// Uses the `pl_node` union field with payload `Block`. | ||
| 913 | c_import, | ||
| 914 | |||
| 915 | /// Allocates stack local memory. | ||
| 916 | /// Uses the `un_node` union field. The operand is the type of the allocated object. | ||
| 917 | /// The node source location points to a var decl node. | ||
| 918 | alloc, | ||
| 919 | /// Same as `alloc` except mutable. | ||
| 920 | alloc_mut, | ||
| 921 | /// Allocates comptime-mutable memory. | ||
| 922 | /// Uses the `un_node` union field. The operand is the type of the allocated object. | ||
| 923 | /// The node source location points to a var decl node. | ||
| 924 | alloc_comptime, | ||
| 925 | /// Same as `alloc` except the type is inferred. | ||
| 926 | /// Uses the `node` union field. | ||
| 927 | alloc_inferred, | ||
| 928 | /// Same as `alloc_inferred` except mutable. | ||
| 929 | alloc_inferred_mut, | ||
| 930 | /// Same as `alloc_comptime` except the type is inferred. | ||
| 931 | alloc_inferred_comptime, | ||
| 932 | /// Each `store_to_inferred_ptr` puts the type of the stored value into a set, | ||
| 933 | /// and then `resolve_inferred_alloc` triggers peer type resolution on the set. | ||
| 934 | /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which | ||
| 935 | /// is the allocation that needs to have its type inferred. | ||
| 936 | /// Uses the `un_node` field. The AST node is the var decl. | ||
| 937 | resolve_inferred_alloc, | ||
| 938 | |||
| 939 | /// Implements `resume` syntax. Uses `un_node` field. | ||
| 940 | @"resume", | ||
| 941 | @"await", | ||
| 942 | await_nosuspend, | ||
| 943 | |||
| 944 | /// The ZIR instruction tag is one of the `Extended` ones. | ||
| 945 | /// Uses the `extended` union field. | ||
| 946 | extended, | ||
| 947 | |||
| 948 | /// Returns whether the instruction is one of the control flow "noreturn" types. | ||
| 949 | /// Function calls do not count. | ||
| 950 | pub fn isNoReturn(tag: Tag) bool { | ||
| 951 | return switch (tag) { | ||
| 952 | .arg, | ||
| 953 | .add, | ||
| 954 | .addwrap, | ||
| 955 | .alloc, | ||
| 956 | .alloc_mut, | ||
| 957 | .alloc_comptime, | ||
| 958 | .alloc_inferred, | ||
| 959 | .alloc_inferred_mut, | ||
| 960 | .alloc_inferred_comptime, | ||
| 961 | .array_cat, | ||
| 962 | .array_mul, | ||
| 963 | .array_type, | ||
| 964 | .array_type_sentinel, | ||
| 965 | .vector_type, | ||
| 966 | .elem_type, | ||
| 967 | .indexable_ptr_len, | ||
| 968 | .anyframe_type, | ||
| 969 | .as, | ||
| 970 | .as_node, | ||
| 971 | .bit_and, | ||
| 972 | .bitcast, | ||
| 973 | .bitcast_result_ptr, | ||
| 974 | .bit_or, | ||
| 975 | .block, | ||
| 976 | .block_inline, | ||
| 977 | .suspend_block, | ||
| 978 | .loop, | ||
| 979 | .bool_br_and, | ||
| 980 | .bool_br_or, | ||
| 981 | .bool_not, | ||
| 982 | .bool_and, | ||
| 983 | .bool_or, | ||
| 984 | .breakpoint, | ||
| 985 | .fence, | ||
| 986 | .call, | ||
| 987 | .call_chkused, | ||
| 988 | .call_compile_time, | ||
| 989 | .call_nosuspend, | ||
| 990 | .call_async, | ||
| 991 | .cmp_lt, | ||
| 992 | .cmp_lte, | ||
| 993 | .cmp_eq, | ||
| 994 | .cmp_gte, | ||
| 995 | .cmp_gt, | ||
| 996 | .cmp_neq, | ||
| 997 | .coerce_result_ptr, | ||
| 998 | .opaque_decl, | ||
| 999 | .opaque_decl_anon, | ||
| 1000 | .opaque_decl_func, | ||
| 1001 | .error_set_decl, | ||
| 1002 | .error_set_decl_anon, | ||
| 1003 | .error_set_decl_func, | ||
| 1004 | .dbg_stmt, | ||
| 1005 | .decl_ref, | ||
| 1006 | .decl_val, | ||
| 1007 | .load, | ||
| 1008 | .div, | ||
| 1009 | .elem_ptr, | ||
| 1010 | .elem_val, | ||
| 1011 | .elem_ptr_node, | ||
| 1012 | .elem_val_node, | ||
| 1013 | .ensure_result_used, | ||
| 1014 | .ensure_result_non_error, | ||
| 1015 | .@"export", | ||
| 1016 | .field_ptr, | ||
| 1017 | .field_val, | ||
| 1018 | .field_ptr_named, | ||
| 1019 | .field_val_named, | ||
| 1020 | .func, | ||
| 1021 | .func_inferred, | ||
| 1022 | .has_decl, | ||
| 1023 | .int, | ||
| 1024 | .int_big, | ||
| 1025 | .float, | ||
| 1026 | .float128, | ||
| 1027 | .int_type, | ||
| 1028 | .is_non_null, | ||
| 1029 | .is_null, | ||
| 1030 | .is_non_null_ptr, | ||
| 1031 | .is_null_ptr, | ||
| 1032 | .is_err, | ||
| 1033 | .is_err_ptr, | ||
| 1034 | .mod_rem, | ||
| 1035 | .mul, | ||
| 1036 | .mulwrap, | ||
| 1037 | .param_type, | ||
| 1038 | .ref, | ||
| 1039 | .shl, | ||
| 1040 | .shr, | ||
| 1041 | .store, | ||
| 1042 | .store_node, | ||
| 1043 | .store_to_block_ptr, | ||
| 1044 | .store_to_inferred_ptr, | ||
| 1045 | .str, | ||
| 1046 | .sub, | ||
| 1047 | .subwrap, | ||
| 1048 | .negate, | ||
| 1049 | .negate_wrap, | ||
| 1050 | .typeof, | ||
| 1051 | .typeof_elem, | ||
| 1052 | .xor, | ||
| 1053 | .optional_type, | ||
| 1054 | .optional_payload_safe, | ||
| 1055 | .optional_payload_unsafe, | ||
| 1056 | .optional_payload_safe_ptr, | ||
| 1057 | .optional_payload_unsafe_ptr, | ||
| 1058 | .err_union_payload_safe, | ||
| 1059 | .err_union_payload_unsafe, | ||
| 1060 | .err_union_payload_safe_ptr, | ||
| 1061 | .err_union_payload_unsafe_ptr, | ||
| 1062 | .err_union_code, | ||
| 1063 | .err_union_code_ptr, | ||
| 1064 | .error_to_int, | ||
| 1065 | .int_to_error, | ||
| 1066 | .ptr_type, | ||
| 1067 | .ptr_type_simple, | ||
| 1068 | .ensure_err_payload_void, | ||
| 1069 | .enum_literal, | ||
| 1070 | .merge_error_sets, | ||
| 1071 | .error_union_type, | ||
| 1072 | .bit_not, | ||
| 1073 | .error_value, | ||
| 1074 | .slice_start, | ||
| 1075 | .slice_end, | ||
| 1076 | .slice_sentinel, | ||
| 1077 | .import, | ||
| 1078 | .typeof_log2_int_type, | ||
| 1079 | .log2_int_type, | ||
| 1080 | .resolve_inferred_alloc, | ||
| 1081 | .set_eval_branch_quota, | ||
| 1082 | .switch_capture, | ||
| 1083 | .switch_capture_ref, | ||
| 1084 | .switch_capture_multi, | ||
| 1085 | .switch_capture_multi_ref, | ||
| 1086 | .switch_capture_else, | ||
| 1087 | .switch_capture_else_ref, | ||
| 1088 | .switch_block, | ||
| 1089 | .switch_block_multi, | ||
| 1090 | .switch_block_else, | ||
| 1091 | .switch_block_else_multi, | ||
| 1092 | .switch_block_under, | ||
| 1093 | .switch_block_under_multi, | ||
| 1094 | .switch_block_ref, | ||
| 1095 | .switch_block_ref_multi, | ||
| 1096 | .switch_block_ref_else, | ||
| 1097 | .switch_block_ref_else_multi, | ||
| 1098 | .switch_block_ref_under, | ||
| 1099 | .switch_block_ref_under_multi, | ||
| 1100 | .validate_struct_init_ptr, | ||
| 1101 | .validate_array_init_ptr, | ||
| 1102 | .struct_init_empty, | ||
| 1103 | .struct_init, | ||
| 1104 | .struct_init_ref, | ||
| 1105 | .struct_init_anon, | ||
| 1106 | .struct_init_anon_ref, | ||
| 1107 | .array_init, | ||
| 1108 | .array_init_anon, | ||
| 1109 | .array_init_ref, | ||
| 1110 | .array_init_anon_ref, | ||
| 1111 | .union_init_ptr, | ||
| 1112 | .field_type, | ||
| 1113 | .field_type_ref, | ||
| 1114 | .int_to_enum, | ||
| 1115 | .enum_to_int, | ||
| 1116 | .type_info, | ||
| 1117 | .size_of, | ||
| 1118 | .bit_size_of, | ||
| 1119 | .ptr_to_int, | ||
| 1120 | .align_of, | ||
| 1121 | .bool_to_int, | ||
| 1122 | .embed_file, | ||
| 1123 | .error_name, | ||
| 1124 | .set_align_stack, | ||
| 1125 | .set_cold, | ||
| 1126 | .set_float_mode, | ||
| 1127 | .set_runtime_safety, | ||
| 1128 | .sqrt, | ||
| 1129 | .sin, | ||
| 1130 | .cos, | ||
| 1131 | .exp, | ||
| 1132 | .exp2, | ||
| 1133 | .log, | ||
| 1134 | .log2, | ||
| 1135 | .log10, | ||
| 1136 | .fabs, | ||
| 1137 | .floor, | ||
| 1138 | .ceil, | ||
| 1139 | .trunc, | ||
| 1140 | .round, | ||
| 1141 | .tag_name, | ||
| 1142 | .reify, | ||
| 1143 | .type_name, | ||
| 1144 | .frame_type, | ||
| 1145 | .frame_size, | ||
| 1146 | .float_to_int, | ||
| 1147 | .int_to_float, | ||
| 1148 | .int_to_ptr, | ||
| 1149 | .float_cast, | ||
| 1150 | .int_cast, | ||
| 1151 | .err_set_cast, | ||
| 1152 | .ptr_cast, | ||
| 1153 | .truncate, | ||
| 1154 | .align_cast, | ||
| 1155 | .has_field, | ||
| 1156 | .clz, | ||
| 1157 | .ctz, | ||
| 1158 | .pop_count, | ||
| 1159 | .byte_swap, | ||
| 1160 | .bit_reverse, | ||
| 1161 | .div_exact, | ||
| 1162 | .div_floor, | ||
| 1163 | .div_trunc, | ||
| 1164 | .mod, | ||
| 1165 | .rem, | ||
| 1166 | .shl_exact, | ||
| 1167 | .shr_exact, | ||
| 1168 | .bit_offset_of, | ||
| 1169 | .byte_offset_of, | ||
| 1170 | .cmpxchg_strong, | ||
| 1171 | .cmpxchg_weak, | ||
| 1172 | .splat, | ||
| 1173 | .reduce, | ||
| 1174 | .shuffle, | ||
| 1175 | .atomic_load, | ||
| 1176 | .atomic_rmw, | ||
| 1177 | .atomic_store, | ||
| 1178 | .mul_add, | ||
| 1179 | .builtin_call, | ||
| 1180 | .field_ptr_type, | ||
| 1181 | .field_parent_ptr, | ||
| 1182 | .memcpy, | ||
| 1183 | .memset, | ||
| 1184 | .builtin_async_call, | ||
| 1185 | .c_import, | ||
| 1186 | .@"resume", | ||
| 1187 | .@"await", | ||
| 1188 | .await_nosuspend, | ||
| 1189 | .extended, | ||
| 1190 | => false, | ||
| 1191 | |||
| 1192 | .@"break", | ||
| 1193 | .break_inline, | ||
| 1194 | .condbr, | ||
| 1195 | .condbr_inline, | ||
| 1196 | .compile_error, | ||
| 1197 | .ret_node, | ||
| 1198 | .ret_coerce, | ||
| 1199 | .@"unreachable", | ||
| 1200 | .repeat, | ||
| 1201 | .repeat_inline, | ||
| 1202 | .panic, | ||
| 1203 | => true, | ||
| 1204 | }; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | /// Used by debug safety-checking code. | ||
| 1208 | pub const data_tags = list: { | ||
| 1209 | @setEvalBranchQuota(2000); | ||
| 1210 | break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{ | ||
| 1211 | .add = .pl_node, | ||
| 1212 | .addwrap = .pl_node, | ||
| 1213 | .arg = .str_tok, | ||
| 1214 | .array_cat = .pl_node, | ||
| 1215 | .array_mul = .pl_node, | ||
| 1216 | .array_type = .bin, | ||
| 1217 | .array_type_sentinel = .array_type_sentinel, | ||
| 1218 | .vector_type = .pl_node, | ||
| 1219 | .elem_type = .un_node, | ||
| 1220 | .indexable_ptr_len = .un_node, | ||
| 1221 | .anyframe_type = .un_node, | ||
| 1222 | .as = .bin, | ||
| 1223 | .as_node = .pl_node, | ||
| 1224 | .bit_and = .pl_node, | ||
| 1225 | .bitcast = .pl_node, | ||
| 1226 | .bitcast_result_ptr = .pl_node, | ||
| 1227 | .bit_not = .un_node, | ||
| 1228 | .bit_or = .pl_node, | ||
| 1229 | .block = .pl_node, | ||
| 1230 | .block_inline = .pl_node, | ||
| 1231 | .suspend_block = .pl_node, | ||
| 1232 | .bool_and = .pl_node, | ||
| 1233 | .bool_not = .un_node, | ||
| 1234 | .bool_or = .pl_node, | ||
| 1235 | .bool_br_and = .bool_br, | ||
| 1236 | .bool_br_or = .bool_br, | ||
| 1237 | .@"break" = .@"break", | ||
| 1238 | .break_inline = .@"break", | ||
| 1239 | .breakpoint = .node, | ||
| 1240 | .call = .pl_node, | ||
| 1241 | .call_chkused = .pl_node, | ||
| 1242 | .call_compile_time = .pl_node, | ||
| 1243 | .call_nosuspend = .pl_node, | ||
| 1244 | .call_async = .pl_node, | ||
| 1245 | .cmp_lt = .pl_node, | ||
| 1246 | .cmp_lte = .pl_node, | ||
| 1247 | .cmp_eq = .pl_node, | ||
| 1248 | .cmp_gte = .pl_node, | ||
| 1249 | .cmp_gt = .pl_node, | ||
| 1250 | .cmp_neq = .pl_node, | ||
| 1251 | .coerce_result_ptr = .bin, | ||
| 1252 | .condbr = .pl_node, | ||
| 1253 | .condbr_inline = .pl_node, | ||
| 1254 | .opaque_decl = .pl_node, | ||
| 1255 | .opaque_decl_anon = .pl_node, | ||
| 1256 | .opaque_decl_func = .pl_node, | ||
| 1257 | .error_set_decl = .pl_node, | ||
| 1258 | .error_set_decl_anon = .pl_node, | ||
| 1259 | .error_set_decl_func = .pl_node, | ||
| 1260 | .dbg_stmt = .dbg_stmt, | ||
| 1261 | .decl_ref = .str_tok, | ||
| 1262 | .decl_val = .str_tok, | ||
| 1263 | .load = .un_node, | ||
| 1264 | .div = .pl_node, | ||
| 1265 | .elem_ptr = .bin, | ||
| 1266 | .elem_ptr_node = .pl_node, | ||
| 1267 | .elem_val = .bin, | ||
| 1268 | .elem_val_node = .pl_node, | ||
| 1269 | .ensure_result_used = .un_node, | ||
| 1270 | .ensure_result_non_error = .un_node, | ||
| 1271 | .error_union_type = .pl_node, | ||
| 1272 | .error_value = .str_tok, | ||
| 1273 | .@"export" = .pl_node, | ||
| 1274 | .field_ptr = .pl_node, | ||
| 1275 | .field_val = .pl_node, | ||
| 1276 | .field_ptr_named = .pl_node, | ||
| 1277 | .field_val_named = .pl_node, | ||
| 1278 | .func = .pl_node, | ||
| 1279 | .func_inferred = .pl_node, | ||
| 1280 | .import = .str_tok, | ||
| 1281 | .int = .int, | ||
| 1282 | .int_big = .str, | ||
| 1283 | .float = .float, | ||
| 1284 | .float128 = .pl_node, | ||
| 1285 | .int_type = .int_type, | ||
| 1286 | .is_non_null = .un_node, | ||
| 1287 | .is_null = .un_node, | ||
| 1288 | .is_non_null_ptr = .un_node, | ||
| 1289 | .is_null_ptr = .un_node, | ||
| 1290 | .is_err = .un_node, | ||
| 1291 | .is_err_ptr = .un_node, | ||
| 1292 | .loop = .pl_node, | ||
| 1293 | .repeat = .node, | ||
| 1294 | .repeat_inline = .node, | ||
| 1295 | .merge_error_sets = .pl_node, | ||
| 1296 | .mod_rem = .pl_node, | ||
| 1297 | .mul = .pl_node, | ||
| 1298 | .mulwrap = .pl_node, | ||
| 1299 | .param_type = .param_type, | ||
| 1300 | .ref = .un_tok, | ||
| 1301 | .ret_node = .un_node, | ||
| 1302 | .ret_coerce = .un_tok, | ||
| 1303 | .ptr_type_simple = .ptr_type_simple, | ||
| 1304 | .ptr_type = .ptr_type, | ||
| 1305 | .slice_start = .pl_node, | ||
| 1306 | .slice_end = .pl_node, | ||
| 1307 | .slice_sentinel = .pl_node, | ||
| 1308 | .store = .bin, | ||
| 1309 | .store_node = .pl_node, | ||
| 1310 | .store_to_block_ptr = .bin, | ||
| 1311 | .store_to_inferred_ptr = .bin, | ||
| 1312 | .str = .str, | ||
| 1313 | .sub = .pl_node, | ||
| 1314 | .subwrap = .pl_node, | ||
| 1315 | .negate = .un_node, | ||
| 1316 | .negate_wrap = .un_node, | ||
| 1317 | .typeof = .un_node, | ||
| 1318 | .typeof_elem = .un_node, | ||
| 1319 | .typeof_log2_int_type = .un_node, | ||
| 1320 | .log2_int_type = .un_node, | ||
| 1321 | .@"unreachable" = .@"unreachable", | ||
| 1322 | .xor = .pl_node, | ||
| 1323 | .optional_type = .un_node, | ||
| 1324 | .optional_payload_safe = .un_node, | ||
| 1325 | .optional_payload_unsafe = .un_node, | ||
| 1326 | .optional_payload_safe_ptr = .un_node, | ||
| 1327 | .optional_payload_unsafe_ptr = .un_node, | ||
| 1328 | .err_union_payload_safe = .un_node, | ||
| 1329 | .err_union_payload_unsafe = .un_node, | ||
| 1330 | .err_union_payload_safe_ptr = .un_node, | ||
| 1331 | .err_union_payload_unsafe_ptr = .un_node, | ||
| 1332 | .err_union_code = .un_node, | ||
| 1333 | .err_union_code_ptr = .un_node, | ||
| 1334 | .ensure_err_payload_void = .un_tok, | ||
| 1335 | .enum_literal = .str_tok, | ||
| 1336 | .switch_block = .pl_node, | ||
| 1337 | .switch_block_multi = .pl_node, | ||
| 1338 | .switch_block_else = .pl_node, | ||
| 1339 | .switch_block_else_multi = .pl_node, | ||
| 1340 | .switch_block_under = .pl_node, | ||
| 1341 | .switch_block_under_multi = .pl_node, | ||
| 1342 | .switch_block_ref = .pl_node, | ||
| 1343 | .switch_block_ref_multi = .pl_node, | ||
| 1344 | .switch_block_ref_else = .pl_node, | ||
| 1345 | .switch_block_ref_else_multi = .pl_node, | ||
| 1346 | .switch_block_ref_under = .pl_node, | ||
| 1347 | .switch_block_ref_under_multi = .pl_node, | ||
| 1348 | .switch_capture = .switch_capture, | ||
| 1349 | .switch_capture_ref = .switch_capture, | ||
| 1350 | .switch_capture_multi = .switch_capture, | ||
| 1351 | .switch_capture_multi_ref = .switch_capture, | ||
| 1352 | .switch_capture_else = .switch_capture, | ||
| 1353 | .switch_capture_else_ref = .switch_capture, | ||
| 1354 | .validate_struct_init_ptr = .pl_node, | ||
| 1355 | .validate_array_init_ptr = .pl_node, | ||
| 1356 | .struct_init_empty = .un_node, | ||
| 1357 | .field_type = .pl_node, | ||
| 1358 | .field_type_ref = .pl_node, | ||
| 1359 | .struct_init = .pl_node, | ||
| 1360 | .struct_init_ref = .pl_node, | ||
| 1361 | .struct_init_anon = .pl_node, | ||
| 1362 | .struct_init_anon_ref = .pl_node, | ||
| 1363 | .array_init = .pl_node, | ||
| 1364 | .array_init_anon = .pl_node, | ||
| 1365 | .array_init_ref = .pl_node, | ||
| 1366 | .array_init_anon_ref = .pl_node, | ||
| 1367 | .union_init_ptr = .pl_node, | ||
| 1368 | .type_info = .un_node, | ||
| 1369 | .size_of = .un_node, | ||
| 1370 | .bit_size_of = .un_node, | ||
| 1371 | .fence = .node, | ||
| 1372 | |||
| 1373 | .ptr_to_int = .un_node, | ||
| 1374 | .error_to_int = .un_node, | ||
| 1375 | .int_to_error = .un_node, | ||
| 1376 | .compile_error = .un_node, | ||
| 1377 | .set_eval_branch_quota = .un_node, | ||
| 1378 | .enum_to_int = .un_node, | ||
| 1379 | .align_of = .un_node, | ||
| 1380 | .bool_to_int = .un_node, | ||
| 1381 | .embed_file = .un_node, | ||
| 1382 | .error_name = .un_node, | ||
| 1383 | .panic = .un_node, | ||
| 1384 | .set_align_stack = .un_node, | ||
| 1385 | .set_cold = .un_node, | ||
| 1386 | .set_float_mode = .un_node, | ||
| 1387 | .set_runtime_safety = .un_node, | ||
| 1388 | .sqrt = .un_node, | ||
| 1389 | .sin = .un_node, | ||
| 1390 | .cos = .un_node, | ||
| 1391 | .exp = .un_node, | ||
| 1392 | .exp2 = .un_node, | ||
| 1393 | .log = .un_node, | ||
| 1394 | .log2 = .un_node, | ||
| 1395 | .log10 = .un_node, | ||
| 1396 | .fabs = .un_node, | ||
| 1397 | .floor = .un_node, | ||
| 1398 | .ceil = .un_node, | ||
| 1399 | .trunc = .un_node, | ||
| 1400 | .round = .un_node, | ||
| 1401 | .tag_name = .un_node, | ||
| 1402 | .reify = .un_node, | ||
| 1403 | .type_name = .un_node, | ||
| 1404 | .frame_type = .un_node, | ||
| 1405 | .frame_size = .un_node, | ||
| 1406 | |||
| 1407 | .float_to_int = .pl_node, | ||
| 1408 | .int_to_float = .pl_node, | ||
| 1409 | .int_to_ptr = .pl_node, | ||
| 1410 | .int_to_enum = .pl_node, | ||
| 1411 | .float_cast = .pl_node, | ||
| 1412 | .int_cast = .pl_node, | ||
| 1413 | .err_set_cast = .pl_node, | ||
| 1414 | .ptr_cast = .pl_node, | ||
| 1415 | .truncate = .pl_node, | ||
| 1416 | .align_cast = .pl_node, | ||
| 1417 | |||
| 1418 | .has_decl = .pl_node, | ||
| 1419 | .has_field = .pl_node, | ||
| 1420 | |||
| 1421 | .clz = .un_node, | ||
| 1422 | .ctz = .un_node, | ||
| 1423 | .pop_count = .un_node, | ||
| 1424 | .byte_swap = .un_node, | ||
| 1425 | .bit_reverse = .un_node, | ||
| 1426 | |||
| 1427 | .div_exact = .pl_node, | ||
| 1428 | .div_floor = .pl_node, | ||
| 1429 | .div_trunc = .pl_node, | ||
| 1430 | .mod = .pl_node, | ||
| 1431 | .rem = .pl_node, | ||
| 1432 | |||
| 1433 | .shl = .pl_node, | ||
| 1434 | .shl_exact = .pl_node, | ||
| 1435 | .shr = .pl_node, | ||
| 1436 | .shr_exact = .pl_node, | ||
| 1437 | |||
| 1438 | .bit_offset_of = .pl_node, | ||
| 1439 | .byte_offset_of = .pl_node, | ||
| 1440 | .cmpxchg_strong = .pl_node, | ||
| 1441 | .cmpxchg_weak = .pl_node, | ||
| 1442 | .splat = .pl_node, | ||
| 1443 | .reduce = .pl_node, | ||
| 1444 | .shuffle = .pl_node, | ||
| 1445 | .atomic_load = .pl_node, | ||
| 1446 | .atomic_rmw = .pl_node, | ||
| 1447 | .atomic_store = .pl_node, | ||
| 1448 | .mul_add = .pl_node, | ||
| 1449 | .builtin_call = .pl_node, | ||
| 1450 | .field_ptr_type = .bin, | ||
| 1451 | .field_parent_ptr = .pl_node, | ||
| 1452 | .memcpy = .pl_node, | ||
| 1453 | .memset = .pl_node, | ||
| 1454 | .builtin_async_call = .pl_node, | ||
| 1455 | .c_import = .pl_node, | ||
| 1456 | |||
| 1457 | .alloc = .un_node, | ||
| 1458 | .alloc_mut = .un_node, | ||
| 1459 | .alloc_comptime = .un_node, | ||
| 1460 | .alloc_inferred = .node, | ||
| 1461 | .alloc_inferred_mut = .node, | ||
| 1462 | .alloc_inferred_comptime = .node, | ||
| 1463 | .resolve_inferred_alloc = .un_node, | ||
| 1464 | |||
| 1465 | .@"resume" = .un_node, | ||
| 1466 | .@"await" = .un_node, | ||
| 1467 | .await_nosuspend = .un_node, | ||
| 1468 | |||
| 1469 | .extended = .extended, | ||
| 1470 | }); | ||
| 1471 | }; | ||
| 1472 | }; | ||
| 1473 | |||
| 1474 | /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum. | ||
| 1475 | /// `noreturn` instructions may not go here; they must be part of the main `Tag` enum. | ||
| 1476 | pub const Extended = enum(u16) { | ||
| 1477 | /// Represents a function declaration or function prototype, depending on | ||
| 1478 | /// whether body_len is 0. | ||
| 1479 | /// `operand` is payload index to `ExtendedFunc`. | ||
| 1480 | /// `small` is `ExtendedFunc.Small`. | ||
| 1481 | func, | ||
| 1482 | /// Declares a global variable. | ||
| 1483 | /// `operand` is payload index to `ExtendedVar`. | ||
| 1484 | /// `small` is `ExtendedVar.Small`. | ||
| 1485 | variable, | ||
| 1486 | /// A struct type definition. Contains references to ZIR instructions for | ||
| 1487 | /// the field types, defaults, and alignments. | ||
| 1488 | /// `operand` is payload index to `StructDecl`. | ||
| 1489 | /// `small` is `StructDecl.Small`. | ||
| 1490 | struct_decl, | ||
| 1491 | /// An enum type definition. Contains references to ZIR instructions for | ||
| 1492 | /// the field value expressions and optional type tag expression. | ||
| 1493 | /// `operand` is payload index to `EnumDecl`. | ||
| 1494 | /// `small` is `EnumDecl.Small`. | ||
| 1495 | enum_decl, | ||
| 1496 | /// A union type definition. Contains references to ZIR instructions for | ||
| 1497 | /// the field types and optional type tag expression. | ||
| 1498 | /// `operand` is payload index to `UnionDecl`. | ||
| 1499 | /// `small` is `UnionDecl.Small`. | ||
| 1500 | union_decl, | ||
| 1501 | /// Obtains a pointer to the return value. | ||
| 1502 | /// `operand` is `src_node: i32`. | ||
| 1503 | ret_ptr, | ||
| 1504 | /// Obtains the return type of the in-scope function. | ||
| 1505 | /// `operand` is `src_node: i32`. | ||
| 1506 | ret_type, | ||
| 1507 | /// Implements the `@This` builtin. | ||
| 1508 | /// `operand` is `src_node: i32`. | ||
| 1509 | this, | ||
| 1510 | /// Implements the `@returnAddress` builtin. | ||
| 1511 | /// `operand` is `src_node: i32`. | ||
| 1512 | ret_addr, | ||
| 1513 | /// Implements the `@src` builtin. | ||
| 1514 | /// `operand` is `src_node: i32`. | ||
| 1515 | builtin_src, | ||
| 1516 | /// Implements the `@errorReturnTrace` builtin. | ||
| 1517 | /// `operand` is `src_node: i32`. | ||
| 1518 | error_return_trace, | ||
| 1519 | /// Implements the `@frame` builtin. | ||
| 1520 | /// `operand` is `src_node: i32`. | ||
| 1521 | frame, | ||
| 1522 | /// Implements the `@frameAddress` builtin. | ||
| 1523 | /// `operand` is `src_node: i32`. | ||
| 1524 | frame_address, | ||
| 1525 | /// Same as `alloc` from `Tag` but may contain an alignment instruction. | ||
| 1526 | /// `operand` is payload index to `AllocExtended`. | ||
| 1527 | /// `small`: | ||
| 1528 | /// * 0b000X - has type | ||
| 1529 | /// * 0b00X0 - has alignment | ||
| 1530 | /// * 0b0X00 - 1=const, 0=var | ||
| 1531 | /// * 0bX000 - is comptime | ||
| 1532 | alloc, | ||
| 1533 | /// The `@extern` builtin. | ||
| 1534 | /// `operand` is payload index to `BinNode`. | ||
| 1535 | builtin_extern, | ||
| 1536 | /// Inline assembly. | ||
| 1537 | /// `small`: | ||
| 1538 | /// * 0b00000000_000XXXXX - `outputs_len`. | ||
| 1539 | /// * 0b000000XX_XXX00000 - `inputs_len`. | ||
| 1540 | /// * 0b0XXXXX00_00000000 - `clobbers_len`. | ||
| 1541 | /// * 0bX0000000_00000000 - is volatile | ||
| 1542 | /// `operand` is payload index to `Asm`. | ||
| 1543 | @"asm", | ||
| 1544 | /// Log compile time variables and emit an error message. | ||
| 1545 | /// `operand` is payload index to `NodeMultiOp`. | ||
| 1546 | /// `small` is `operands_len`. | ||
| 1547 | /// The AST node is the compile log builtin call. | ||
| 1548 | compile_log, | ||
| 1549 | /// The builtin `@TypeOf` which returns the type after Peer Type Resolution | ||
| 1550 | /// of one or more params. | ||
| 1551 | /// `operand` is payload index to `NodeMultiOp`. | ||
| 1552 | /// `small` is `operands_len`. | ||
| 1553 | /// The AST node is the builtin call. | ||
| 1554 | typeof_peer, | ||
| 1555 | /// Implements the `@addWithOverflow` builtin. | ||
| 1556 | /// `operand` is payload index to `OverflowArithmetic`. | ||
| 1557 | /// `small` is unused. | ||
| 1558 | add_with_overflow, | ||
| 1559 | /// Implements the `@subWithOverflow` builtin. | ||
| 1560 | /// `operand` is payload index to `OverflowArithmetic`. | ||
| 1561 | /// `small` is unused. | ||
| 1562 | sub_with_overflow, | ||
| 1563 | /// Implements the `@mulWithOverflow` builtin. | ||
| 1564 | /// `operand` is payload index to `OverflowArithmetic`. | ||
| 1565 | /// `small` is unused. | ||
| 1566 | mul_with_overflow, | ||
| 1567 | /// Implements the `@shlWithOverflow` builtin. | ||
| 1568 | /// `operand` is payload index to `OverflowArithmetic`. | ||
| 1569 | /// `small` is unused. | ||
| 1570 | shl_with_overflow, | ||
| 1571 | /// `operand` is payload index to `UnNode`. | ||
| 1572 | c_undef, | ||
| 1573 | /// `operand` is payload index to `UnNode`. | ||
| 1574 | c_include, | ||
| 1575 | /// `operand` is payload index to `BinNode`. | ||
| 1576 | c_define, | ||
| 1577 | /// `operand` is payload index to `UnNode`. | ||
| 1578 | wasm_memory_size, | ||
| 1579 | /// `operand` is payload index to `BinNode`. | ||
| 1580 | wasm_memory_grow, | ||
| 1581 | |||
| 1582 | pub const InstData = struct { | ||
| 1583 | opcode: Extended, | ||
| 1584 | small: u16, | ||
| 1585 | operand: u32, | ||
| 1586 | }; | ||
| 1587 | }; | ||
| 1588 | |||
| 1589 | /// The position of a ZIR instruction within the `Zir` instructions array. | ||
| 1590 | pub const Index = u32; | ||
| 1591 | |||
| 1592 | /// A reference to a TypedValue or ZIR instruction. | ||
| 1593 | /// | ||
| 1594 | /// If the Ref has a tag in this enum, it refers to a TypedValue which may be | ||
| 1595 | /// retrieved with Ref.toTypedValue(). | ||
| 1596 | /// | ||
| 1597 | /// If the value of a Ref does not have a tag, it refers to a ZIR instruction. | ||
| 1598 | /// | ||
| 1599 | /// The first values after the the last tag refer to ZIR instructions which may | ||
| 1600 | /// be derived by subtracting `typed_value_map.len`. | ||
| 1601 | /// | ||
| 1602 | /// When adding a tag to this enum, consider adding a corresponding entry to | ||
| 1603 | /// `simple_types` in astgen. | ||
| 1604 | /// | ||
| 1605 | /// The tag type is specified so that it is safe to bitcast between `[]u32` | ||
| 1606 | /// and `[]Ref`. | ||
| 1607 | pub const Ref = enum(u32) { | ||
| 1608 | /// This Ref does not correspond to any ZIR instruction or constant | ||
| 1609 | /// value and may instead be used as a sentinel to indicate null. | ||
| 1610 | none, | ||
| 1611 | |||
| 1612 | u8_type, | ||
| 1613 | i8_type, | ||
| 1614 | u16_type, | ||
| 1615 | i16_type, | ||
| 1616 | u32_type, | ||
| 1617 | i32_type, | ||
| 1618 | u64_type, | ||
| 1619 | i64_type, | ||
| 1620 | u128_type, | ||
| 1621 | i128_type, | ||
| 1622 | usize_type, | ||
| 1623 | isize_type, | ||
| 1624 | c_short_type, | ||
| 1625 | c_ushort_type, | ||
| 1626 | c_int_type, | ||
| 1627 | c_uint_type, | ||
| 1628 | c_long_type, | ||
| 1629 | c_ulong_type, | ||
| 1630 | c_longlong_type, | ||
| 1631 | c_ulonglong_type, | ||
| 1632 | c_longdouble_type, | ||
| 1633 | f16_type, | ||
| 1634 | f32_type, | ||
| 1635 | f64_type, | ||
| 1636 | f128_type, | ||
| 1637 | c_void_type, | ||
| 1638 | bool_type, | ||
| 1639 | void_type, | ||
| 1640 | type_type, | ||
| 1641 | anyerror_type, | ||
| 1642 | comptime_int_type, | ||
| 1643 | comptime_float_type, | ||
| 1644 | noreturn_type, | ||
| 1645 | anyframe_type, | ||
| 1646 | null_type, | ||
| 1647 | undefined_type, | ||
| 1648 | enum_literal_type, | ||
| 1649 | atomic_ordering_type, | ||
| 1650 | atomic_rmw_op_type, | ||
| 1651 | calling_convention_type, | ||
| 1652 | float_mode_type, | ||
| 1653 | reduce_op_type, | ||
| 1654 | call_options_type, | ||
| 1655 | export_options_type, | ||
| 1656 | extern_options_type, | ||
| 1657 | manyptr_u8_type, | ||
| 1658 | manyptr_const_u8_type, | ||
| 1659 | fn_noreturn_no_args_type, | ||
| 1660 | fn_void_no_args_type, | ||
| 1661 | fn_naked_noreturn_no_args_type, | ||
| 1662 | fn_ccc_void_no_args_type, | ||
| 1663 | single_const_pointer_to_comptime_int_type, | ||
| 1664 | const_slice_u8_type, | ||
| 1665 | |||
| 1666 | /// `undefined` (untyped) | ||
| 1667 | undef, | ||
| 1668 | /// `0` (comptime_int) | ||
| 1669 | zero, | ||
| 1670 | /// `1` (comptime_int) | ||
| 1671 | one, | ||
| 1672 | /// `{}` | ||
| 1673 | void_value, | ||
| 1674 | /// `unreachable` (noreturn type) | ||
| 1675 | unreachable_value, | ||
| 1676 | /// `null` (untyped) | ||
| 1677 | null_value, | ||
| 1678 | /// `true` | ||
| 1679 | bool_true, | ||
| 1680 | /// `false` | ||
| 1681 | bool_false, | ||
| 1682 | /// `.{}` (untyped) | ||
| 1683 | empty_struct, | ||
| 1684 | /// `0` (usize) | ||
| 1685 | zero_usize, | ||
| 1686 | /// `1` (usize) | ||
| 1687 | one_usize, | ||
| 1688 | /// `std.builtin.CallingConvention.C` | ||
| 1689 | calling_convention_c, | ||
| 1690 | |||
| 1691 | _, | ||
| 1692 | |||
| 1693 | pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{ | ||
| 1694 | .none = undefined, | ||
| 1695 | |||
| 1696 | .u8_type = .{ | ||
| 1697 | .ty = Type.initTag(.type), | ||
| 1698 | .val = Value.initTag(.u8_type), | ||
| 1699 | }, | ||
| 1700 | .i8_type = .{ | ||
| 1701 | .ty = Type.initTag(.type), | ||
| 1702 | .val = Value.initTag(.i8_type), | ||
| 1703 | }, | ||
| 1704 | .u16_type = .{ | ||
| 1705 | .ty = Type.initTag(.type), | ||
| 1706 | .val = Value.initTag(.u16_type), | ||
| 1707 | }, | ||
| 1708 | .i16_type = .{ | ||
| 1709 | .ty = Type.initTag(.type), | ||
| 1710 | .val = Value.initTag(.i16_type), | ||
| 1711 | }, | ||
| 1712 | .u32_type = .{ | ||
| 1713 | .ty = Type.initTag(.type), | ||
| 1714 | .val = Value.initTag(.u32_type), | ||
| 1715 | }, | ||
| 1716 | .i32_type = .{ | ||
| 1717 | .ty = Type.initTag(.type), | ||
| 1718 | .val = Value.initTag(.i32_type), | ||
| 1719 | }, | ||
| 1720 | .u64_type = .{ | ||
| 1721 | .ty = Type.initTag(.type), | ||
| 1722 | .val = Value.initTag(.u64_type), | ||
| 1723 | }, | ||
| 1724 | .i64_type = .{ | ||
| 1725 | .ty = Type.initTag(.type), | ||
| 1726 | .val = Value.initTag(.i64_type), | ||
| 1727 | }, | ||
| 1728 | .u128_type = .{ | ||
| 1729 | .ty = Type.initTag(.type), | ||
| 1730 | .val = Value.initTag(.u128_type), | ||
| 1731 | }, | ||
| 1732 | .i128_type = .{ | ||
| 1733 | .ty = Type.initTag(.type), | ||
| 1734 | .val = Value.initTag(.i128_type), | ||
| 1735 | }, | ||
| 1736 | .usize_type = .{ | ||
| 1737 | .ty = Type.initTag(.type), | ||
| 1738 | .val = Value.initTag(.usize_type), | ||
| 1739 | }, | ||
| 1740 | .isize_type = .{ | ||
| 1741 | .ty = Type.initTag(.type), | ||
| 1742 | .val = Value.initTag(.isize_type), | ||
| 1743 | }, | ||
| 1744 | .c_short_type = .{ | ||
| 1745 | .ty = Type.initTag(.type), | ||
| 1746 | .val = Value.initTag(.c_short_type), | ||
| 1747 | }, | ||
| 1748 | .c_ushort_type = .{ | ||
| 1749 | .ty = Type.initTag(.type), | ||
| 1750 | .val = Value.initTag(.c_ushort_type), | ||
| 1751 | }, | ||
| 1752 | .c_int_type = .{ | ||
| 1753 | .ty = Type.initTag(.type), | ||
| 1754 | .val = Value.initTag(.c_int_type), | ||
| 1755 | }, | ||
| 1756 | .c_uint_type = .{ | ||
| 1757 | .ty = Type.initTag(.type), | ||
| 1758 | .val = Value.initTag(.c_uint_type), | ||
| 1759 | }, | ||
| 1760 | .c_long_type = .{ | ||
| 1761 | .ty = Type.initTag(.type), | ||
| 1762 | .val = Value.initTag(.c_long_type), | ||
| 1763 | }, | ||
| 1764 | .c_ulong_type = .{ | ||
| 1765 | .ty = Type.initTag(.type), | ||
| 1766 | .val = Value.initTag(.c_ulong_type), | ||
| 1767 | }, | ||
| 1768 | .c_longlong_type = .{ | ||
| 1769 | .ty = Type.initTag(.type), | ||
| 1770 | .val = Value.initTag(.c_longlong_type), | ||
| 1771 | }, | ||
| 1772 | .c_ulonglong_type = .{ | ||
| 1773 | .ty = Type.initTag(.type), | ||
| 1774 | .val = Value.initTag(.c_ulonglong_type), | ||
| 1775 | }, | ||
| 1776 | .c_longdouble_type = .{ | ||
| 1777 | .ty = Type.initTag(.type), | ||
| 1778 | .val = Value.initTag(.c_longdouble_type), | ||
| 1779 | }, | ||
| 1780 | .f16_type = .{ | ||
| 1781 | .ty = Type.initTag(.type), | ||
| 1782 | .val = Value.initTag(.f16_type), | ||
| 1783 | }, | ||
| 1784 | .f32_type = .{ | ||
| 1785 | .ty = Type.initTag(.type), | ||
| 1786 | .val = Value.initTag(.f32_type), | ||
| 1787 | }, | ||
| 1788 | .f64_type = .{ | ||
| 1789 | .ty = Type.initTag(.type), | ||
| 1790 | .val = Value.initTag(.f64_type), | ||
| 1791 | }, | ||
| 1792 | .f128_type = .{ | ||
| 1793 | .ty = Type.initTag(.type), | ||
| 1794 | .val = Value.initTag(.f128_type), | ||
| 1795 | }, | ||
| 1796 | .c_void_type = .{ | ||
| 1797 | .ty = Type.initTag(.type), | ||
| 1798 | .val = Value.initTag(.c_void_type), | ||
| 1799 | }, | ||
| 1800 | .bool_type = .{ | ||
| 1801 | .ty = Type.initTag(.type), | ||
| 1802 | .val = Value.initTag(.bool_type), | ||
| 1803 | }, | ||
| 1804 | .void_type = .{ | ||
| 1805 | .ty = Type.initTag(.type), | ||
| 1806 | .val = Value.initTag(.void_type), | ||
| 1807 | }, | ||
| 1808 | .type_type = .{ | ||
| 1809 | .ty = Type.initTag(.type), | ||
| 1810 | .val = Value.initTag(.type_type), | ||
| 1811 | }, | ||
| 1812 | .anyerror_type = .{ | ||
| 1813 | .ty = Type.initTag(.type), | ||
| 1814 | .val = Value.initTag(.anyerror_type), | ||
| 1815 | }, | ||
| 1816 | .comptime_int_type = .{ | ||
| 1817 | .ty = Type.initTag(.type), | ||
| 1818 | .val = Value.initTag(.comptime_int_type), | ||
| 1819 | }, | ||
| 1820 | .comptime_float_type = .{ | ||
| 1821 | .ty = Type.initTag(.type), | ||
| 1822 | .val = Value.initTag(.comptime_float_type), | ||
| 1823 | }, | ||
| 1824 | .noreturn_type = .{ | ||
| 1825 | .ty = Type.initTag(.type), | ||
| 1826 | .val = Value.initTag(.noreturn_type), | ||
| 1827 | }, | ||
| 1828 | .anyframe_type = .{ | ||
| 1829 | .ty = Type.initTag(.type), | ||
| 1830 | .val = Value.initTag(.anyframe_type), | ||
| 1831 | }, | ||
| 1832 | .null_type = .{ | ||
| 1833 | .ty = Type.initTag(.type), | ||
| 1834 | .val = Value.initTag(.null_type), | ||
| 1835 | }, | ||
| 1836 | .undefined_type = .{ | ||
| 1837 | .ty = Type.initTag(.type), | ||
| 1838 | .val = Value.initTag(.undefined_type), | ||
| 1839 | }, | ||
| 1840 | .fn_noreturn_no_args_type = .{ | ||
| 1841 | .ty = Type.initTag(.type), | ||
| 1842 | .val = Value.initTag(.fn_noreturn_no_args_type), | ||
| 1843 | }, | ||
| 1844 | .fn_void_no_args_type = .{ | ||
| 1845 | .ty = Type.initTag(.type), | ||
| 1846 | .val = Value.initTag(.fn_void_no_args_type), | ||
| 1847 | }, | ||
| 1848 | .fn_naked_noreturn_no_args_type = .{ | ||
| 1849 | .ty = Type.initTag(.type), | ||
| 1850 | .val = Value.initTag(.fn_naked_noreturn_no_args_type), | ||
| 1851 | }, | ||
| 1852 | .fn_ccc_void_no_args_type = .{ | ||
| 1853 | .ty = Type.initTag(.type), | ||
| 1854 | .val = Value.initTag(.fn_ccc_void_no_args_type), | ||
| 1855 | }, | ||
| 1856 | .single_const_pointer_to_comptime_int_type = .{ | ||
| 1857 | .ty = Type.initTag(.type), | ||
| 1858 | .val = Value.initTag(.single_const_pointer_to_comptime_int_type), | ||
| 1859 | }, | ||
| 1860 | .const_slice_u8_type = .{ | ||
| 1861 | .ty = Type.initTag(.type), | ||
| 1862 | .val = Value.initTag(.const_slice_u8_type), | ||
| 1863 | }, | ||
| 1864 | .enum_literal_type = .{ | ||
| 1865 | .ty = Type.initTag(.type), | ||
| 1866 | .val = Value.initTag(.enum_literal_type), | ||
| 1867 | }, | ||
| 1868 | .manyptr_u8_type = .{ | ||
| 1869 | .ty = Type.initTag(.type), | ||
| 1870 | .val = Value.initTag(.manyptr_u8_type), | ||
| 1871 | }, | ||
| 1872 | .manyptr_const_u8_type = .{ | ||
| 1873 | .ty = Type.initTag(.type), | ||
| 1874 | .val = Value.initTag(.manyptr_const_u8_type), | ||
| 1875 | }, | ||
| 1876 | .atomic_ordering_type = .{ | ||
| 1877 | .ty = Type.initTag(.type), | ||
| 1878 | .val = Value.initTag(.atomic_ordering_type), | ||
| 1879 | }, | ||
| 1880 | .atomic_rmw_op_type = .{ | ||
| 1881 | .ty = Type.initTag(.type), | ||
| 1882 | .val = Value.initTag(.atomic_rmw_op_type), | ||
| 1883 | }, | ||
| 1884 | .calling_convention_type = .{ | ||
| 1885 | .ty = Type.initTag(.type), | ||
| 1886 | .val = Value.initTag(.calling_convention_type), | ||
| 1887 | }, | ||
| 1888 | .float_mode_type = .{ | ||
| 1889 | .ty = Type.initTag(.type), | ||
| 1890 | .val = Value.initTag(.float_mode_type), | ||
| 1891 | }, | ||
| 1892 | .reduce_op_type = .{ | ||
| 1893 | .ty = Type.initTag(.type), | ||
| 1894 | .val = Value.initTag(.reduce_op_type), | ||
| 1895 | }, | ||
| 1896 | .call_options_type = .{ | ||
| 1897 | .ty = Type.initTag(.type), | ||
| 1898 | .val = Value.initTag(.call_options_type), | ||
| 1899 | }, | ||
| 1900 | .export_options_type = .{ | ||
| 1901 | .ty = Type.initTag(.type), | ||
| 1902 | .val = Value.initTag(.export_options_type), | ||
| 1903 | }, | ||
| 1904 | .extern_options_type = .{ | ||
| 1905 | .ty = Type.initTag(.type), | ||
| 1906 | .val = Value.initTag(.extern_options_type), | ||
| 1907 | }, | ||
| 1908 | |||
| 1909 | .undef = .{ | ||
| 1910 | .ty = Type.initTag(.@"undefined"), | ||
| 1911 | .val = Value.initTag(.undef), | ||
| 1912 | }, | ||
| 1913 | .zero = .{ | ||
| 1914 | .ty = Type.initTag(.comptime_int), | ||
| 1915 | .val = Value.initTag(.zero), | ||
| 1916 | }, | ||
| 1917 | .zero_usize = .{ | ||
| 1918 | .ty = Type.initTag(.usize), | ||
| 1919 | .val = Value.initTag(.zero), | ||
| 1920 | }, | ||
| 1921 | .one = .{ | ||
| 1922 | .ty = Type.initTag(.comptime_int), | ||
| 1923 | .val = Value.initTag(.one), | ||
| 1924 | }, | ||
| 1925 | .one_usize = .{ | ||
| 1926 | .ty = Type.initTag(.usize), | ||
| 1927 | .val = Value.initTag(.one), | ||
| 1928 | }, | ||
| 1929 | .void_value = .{ | ||
| 1930 | .ty = Type.initTag(.void), | ||
| 1931 | .val = Value.initTag(.void_value), | ||
| 1932 | }, | ||
| 1933 | .unreachable_value = .{ | ||
| 1934 | .ty = Type.initTag(.noreturn), | ||
| 1935 | .val = Value.initTag(.unreachable_value), | ||
| 1936 | }, | ||
| 1937 | .null_value = .{ | ||
| 1938 | .ty = Type.initTag(.@"null"), | ||
| 1939 | .val = Value.initTag(.null_value), | ||
| 1940 | }, | ||
| 1941 | .bool_true = .{ | ||
| 1942 | .ty = Type.initTag(.bool), | ||
| 1943 | .val = Value.initTag(.bool_true), | ||
| 1944 | }, | ||
| 1945 | .bool_false = .{ | ||
| 1946 | .ty = Type.initTag(.bool), | ||
| 1947 | .val = Value.initTag(.bool_false), | ||
| 1948 | }, | ||
| 1949 | .empty_struct = .{ | ||
| 1950 | .ty = Type.initTag(.empty_struct_literal), | ||
| 1951 | .val = Value.initTag(.empty_struct_value), | ||
| 1952 | }, | ||
| 1953 | .calling_convention_c = .{ | ||
| 1954 | .ty = Type.initTag(.calling_convention), | ||
| 1955 | .val = .{ .ptr_otherwise = &calling_convention_c_payload.base }, | ||
| 1956 | }, | ||
| 1957 | }); | ||
| 1958 | }; | ||
| 1959 | |||
| 1960 | /// We would like this to be const but `Value` wants a mutable pointer for | ||
| 1961 | /// its payload field. Nothing should mutate this though. | ||
| 1962 | var calling_convention_c_payload: Value.Payload.U32 = .{ | ||
| 1963 | .base = .{ .tag = .enum_field_index }, | ||
| 1964 | .data = @enumToInt(std.builtin.CallingConvention.C), | ||
| 1965 | }; | ||
| 1966 | |||
| 1967 | /// All instructions have an 8-byte payload, which is contained within | ||
| 1968 | /// this union. `Tag` determines which union field is active, as well as | ||
| 1969 | /// how to interpret the data within. | ||
| 1970 | pub const Data = union { | ||
| 1971 | /// Used for `Tag.extended`. The extended opcode determines the meaning | ||
| 1972 | /// of the `small` and `operand` fields. | ||
| 1973 | extended: Extended.InstData, | ||
| 1974 | /// Used for unary operators, with an AST node source location. | ||
| 1975 | un_node: struct { | ||
| 1976 | /// Offset from Decl AST node index. | ||
| 1977 | src_node: i32, | ||
| 1978 | /// The meaning of this operand depends on the corresponding `Tag`. | ||
| 1979 | operand: Ref, | ||
| 1980 | |||
| 1981 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1982 | return .{ .node_offset = self.src_node }; | ||
| 1983 | } | ||
| 1984 | }, | ||
| 1985 | /// Used for unary operators, with a token source location. | ||
| 1986 | un_tok: struct { | ||
| 1987 | /// Offset from Decl AST token index. | ||
| 1988 | src_tok: ast.TokenIndex, | ||
| 1989 | /// The meaning of this operand depends on the corresponding `Tag`. | ||
| 1990 | operand: Ref, | ||
| 1991 | |||
| 1992 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1993 | return .{ .token_offset = self.src_tok }; | ||
| 1994 | } | ||
| 1995 | }, | ||
| 1996 | pl_node: struct { | ||
| 1997 | /// Offset from Decl AST node index. | ||
| 1998 | /// `Tag` determines which kind of AST node this points to. | ||
| 1999 | src_node: i32, | ||
| 2000 | /// index into extra. | ||
| 2001 | /// `Tag` determines what lives there. | ||
| 2002 | payload_index: u32, | ||
| 2003 | |||
| 2004 | pub fn src(self: @This()) LazySrcLoc { | ||
| 2005 | return .{ .node_offset = self.src_node }; | ||
| 2006 | } | ||
| 2007 | }, | ||
| 2008 | bin: Bin, | ||
| 2009 | /// For strings which may contain null bytes. | ||
| 2010 | str: struct { | ||
| 2011 | /// Offset into `string_bytes`. | ||
| 2012 | start: u32, | ||
| 2013 | /// Number of bytes in the string. | ||
| 2014 | len: u32, | ||
| 2015 | |||
| 2016 | pub fn get(self: @This(), code: Zir) []const u8 { | ||
| 2017 | return code.string_bytes[self.start..][0..self.len]; | ||
| 2018 | } | ||
| 2019 | }, | ||
| 2020 | str_tok: struct { | ||
| 2021 | /// Offset into `string_bytes`. Null-terminated. | ||
| 2022 | start: u32, | ||
| 2023 | /// Offset from Decl AST token index. | ||
| 2024 | src_tok: u32, | ||
| 2025 | |||
| 2026 | pub fn get(self: @This(), code: Zir) [:0]const u8 { | ||
| 2027 | return code.nullTerminatedString(self.start); | ||
| 2028 | } | ||
| 2029 | |||
| 2030 | pub fn src(self: @This()) LazySrcLoc { | ||
| 2031 | return .{ .token_offset = self.src_tok }; | ||
| 2032 | } | ||
| 2033 | }, | ||
| 2034 | /// Offset from Decl AST token index. | ||
| 2035 | tok: ast.TokenIndex, | ||
| 2036 | /// Offset from Decl AST node index. | ||
| 2037 | node: i32, | ||
| 2038 | int: u64, | ||
| 2039 | float: struct { | ||
| 2040 | /// Offset from Decl AST node index. | ||
| 2041 | /// `Tag` determines which kind of AST node this points to. | ||
| 2042 | src_node: i32, | ||
| 2043 | number: f32, | ||
| 2044 | |||
| 2045 | pub fn src(self: @This()) LazySrcLoc { | ||
| 2046 | return .{ .node_offset = self.src_node }; | ||
| 2047 | } | ||
| 2048 | }, | ||
| 2049 | array_type_sentinel: struct { | ||
| 2050 | len: Ref, | ||
| 2051 | /// index into extra, points to an `ArrayTypeSentinel` | ||
| 2052 | payload_index: u32, | ||
| 2053 | }, | ||
| 2054 | ptr_type_simple: struct { | ||
| 2055 | is_allowzero: bool, | ||
| 2056 | is_mutable: bool, | ||
| 2057 | is_volatile: bool, | ||
| 2058 | size: std.builtin.TypeInfo.Pointer.Size, | ||
| 2059 | elem_type: Ref, | ||
| 2060 | }, | ||
| 2061 | ptr_type: struct { | ||
| 2062 | flags: packed struct { | ||
| 2063 | is_allowzero: bool, | ||
| 2064 | is_mutable: bool, | ||
| 2065 | is_volatile: bool, | ||
| 2066 | has_sentinel: bool, | ||
| 2067 | has_align: bool, | ||
| 2068 | has_bit_range: bool, | ||
| 2069 | _: u2 = undefined, | ||
| 2070 | }, | ||
| 2071 | size: std.builtin.TypeInfo.Pointer.Size, | ||
| 2072 | /// Index into extra. See `PtrType`. | ||
| 2073 | payload_index: u32, | ||
| 2074 | }, | ||
| 2075 | int_type: struct { | ||
| 2076 | /// Offset from Decl AST node index. | ||
| 2077 | /// `Tag` determines which kind of AST node this points to. | ||
| 2078 | src_node: i32, | ||
| 2079 | signedness: std.builtin.Signedness, | ||
| 2080 | bit_count: u16, | ||
| 2081 | |||
| 2082 | pub fn src(self: @This()) LazySrcLoc { | ||
| 2083 | return .{ .node_offset = self.src_node }; | ||
| 2084 | } | ||
| 2085 | }, | ||
| 2086 | bool_br: struct { | ||
| 2087 | lhs: Ref, | ||
| 2088 | /// Points to a `Block`. | ||
| 2089 | payload_index: u32, | ||
| 2090 | }, | ||
| 2091 | param_type: struct { | ||
| 2092 | callee: Ref, | ||
| 2093 | param_index: u32, | ||
| 2094 | }, | ||
| 2095 | @"unreachable": struct { | ||
| 2096 | /// Offset from Decl AST node index. | ||
| 2097 | /// `Tag` determines which kind of AST node this points to. | ||
| 2098 | src_node: i32, | ||
| 2099 | /// `false`: Not safety checked - the compiler will assume the | ||
| 2100 | /// correctness of this instruction. | ||
| 2101 | /// `true`: In safety-checked modes, this will generate a call | ||
| 2102 | /// to the panic function unless it can be proven unreachable by the compiler. | ||
| 2103 | safety: bool, | ||
| 2104 | |||
| 2105 | pub fn src(self: @This()) LazySrcLoc { | ||
| 2106 | return .{ .node_offset = self.src_node }; | ||
| 2107 | } | ||
| 2108 | }, | ||
| 2109 | @"break": struct { | ||
| 2110 | block_inst: Index, | ||
| 2111 | operand: Ref, | ||
| 2112 | }, | ||
| 2113 | switch_capture: struct { | ||
| 2114 | switch_inst: Index, | ||
| 2115 | prong_index: u32, | ||
| 2116 | }, | ||
| 2117 | dbg_stmt: struct { | ||
| 2118 | line: u32, | ||
| 2119 | column: u32, | ||
| 2120 | }, | ||
| 2121 | |||
| 2122 | // Make sure we don't accidentally add a field to make this union | ||
| 2123 | // bigger than expected. Note that in Debug builds, Zig is allowed | ||
| 2124 | // to insert a secret field for safety checks. | ||
| 2125 | comptime { | ||
| 2126 | if (std.builtin.mode != .Debug) { | ||
| 2127 | assert(@sizeOf(Data) == 8); | ||
| 2128 | } | ||
| 2129 | } | ||
| 2130 | |||
| 2131 | /// TODO this has to be kept in sync with `Data` which we want to be an untagged | ||
| 2132 | /// union. There is some kind of language awkwardness here and it has to do with | ||
| 2133 | /// deserializing an untagged union (in this case `Data`) from a file, and trying | ||
| 2134 | /// to preserve the hidden safety field. | ||
| 2135 | pub const FieldEnum = enum { | ||
| 2136 | extended, | ||
| 2137 | un_node, | ||
| 2138 | un_tok, | ||
| 2139 | pl_node, | ||
| 2140 | bin, | ||
| 2141 | str, | ||
| 2142 | str_tok, | ||
| 2143 | tok, | ||
| 2144 | node, | ||
| 2145 | int, | ||
| 2146 | float, | ||
| 2147 | array_type_sentinel, | ||
| 2148 | ptr_type_simple, | ||
| 2149 | ptr_type, | ||
| 2150 | int_type, | ||
| 2151 | bool_br, | ||
| 2152 | param_type, | ||
| 2153 | @"unreachable", | ||
| 2154 | @"break", | ||
| 2155 | switch_capture, | ||
| 2156 | dbg_stmt, | ||
| 2157 | }; | ||
| 2158 | }; | ||
| 2159 | |||
| 2160 | /// Trailing: | ||
| 2161 | /// 0. Output for every outputs_len | ||
| 2162 | /// 1. Input for every inputs_len | ||
| 2163 | /// 2. clobber: u32 // index into string_bytes (null terminated) for every clobbers_len. | ||
| 2164 | pub const Asm = struct { | ||
| 2165 | src_node: i32, | ||
| 2166 | asm_source: Ref, | ||
| 2167 | /// 1 bit for each outputs_len: whether it uses `-> T` or not. | ||
| 2168 | /// 0b0 - operand is a pointer to where to store the output. | ||
| 2169 | /// 0b1 - operand is a type; asm expression has the output as the result. | ||
| 2170 | /// 0b0X is the first output, 0bX0 is the second, etc. | ||
| 2171 | output_type_bits: u32, | ||
| 2172 | |||
| 2173 | pub const Output = struct { | ||
| 2174 | /// index into string_bytes (null terminated) | ||
| 2175 | name: u32, | ||
| 2176 | /// index into string_bytes (null terminated) | ||
| 2177 | constraint: u32, | ||
| 2178 | /// How to interpret this is determined by `output_type_bits`. | ||
| 2179 | operand: Ref, | ||
| 2180 | }; | ||
| 2181 | |||
| 2182 | pub const Input = struct { | ||
| 2183 | /// index into string_bytes (null terminated) | ||
| 2184 | name: u32, | ||
| 2185 | /// index into string_bytes (null terminated) | ||
| 2186 | constraint: u32, | ||
| 2187 | operand: Ref, | ||
| 2188 | }; | ||
| 2189 | }; | ||
| 2190 | |||
| 2191 | /// Trailing: | ||
| 2192 | /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set | ||
| 2193 | /// 1. cc: Ref, // if has_cc is set | ||
| 2194 | /// 2. align: Ref, // if has_align is set | ||
| 2195 | /// 3. param_type: Ref // for each param_types_len | ||
| 2196 | /// 4. body: Index // for each body_len | ||
| 2197 | /// 5. src_locs: Func.SrcLocs // if body_len != 0 | ||
| 2198 | pub const ExtendedFunc = struct { | ||
| 2199 | src_node: i32, | ||
| 2200 | return_type: Ref, | ||
| 2201 | param_types_len: u32, | ||
| 2202 | body_len: u32, | ||
| 2203 | |||
| 2204 | pub const Small = packed struct { | ||
| 2205 | is_var_args: bool, | ||
| 2206 | is_inferred_error: bool, | ||
| 2207 | has_lib_name: bool, | ||
| 2208 | has_cc: bool, | ||
| 2209 | has_align: bool, | ||
| 2210 | is_test: bool, | ||
| 2211 | is_extern: bool, | ||
| 2212 | _: u9 = undefined, | ||
| 2213 | }; | ||
| 2214 | }; | ||
| 2215 | |||
| 2216 | /// Trailing: | ||
| 2217 | /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set | ||
| 2218 | /// 1. align: Ref, // if has_align is set | ||
| 2219 | /// 2. init: Ref // if has_init is set | ||
| 2220 | /// The source node is obtained from the containing `block_inline`. | ||
| 2221 | pub const ExtendedVar = struct { | ||
| 2222 | var_type: Ref, | ||
| 2223 | |||
| 2224 | pub const Small = packed struct { | ||
| 2225 | has_lib_name: bool, | ||
| 2226 | has_align: bool, | ||
| 2227 | has_init: bool, | ||
| 2228 | is_extern: bool, | ||
| 2229 | is_threadlocal: bool, | ||
| 2230 | _: u11 = undefined, | ||
| 2231 | }; | ||
| 2232 | }; | ||
| 2233 | |||
| 2234 | /// Trailing: | ||
| 2235 | /// 0. param_type: Ref // for each param_types_len | ||
| 2236 | /// - `none` indicates that the param type is `anytype`. | ||
| 2237 | /// 1. body: Index // for each body_len | ||
| 2238 | /// 2. src_locs: SrcLocs // if body_len != 0 | ||
| 2239 | pub const Func = struct { | ||
| 2240 | return_type: Ref, | ||
| 2241 | param_types_len: u32, | ||
| 2242 | body_len: u32, | ||
| 2243 | |||
| 2244 | pub const SrcLocs = struct { | ||
| 2245 | /// Absolute line index in the source file. | ||
| 2246 | lbrace_line: u32, | ||
| 2247 | /// Absolute line index in the source file. | ||
| 2248 | rbrace_line: u32, | ||
| 2249 | /// lbrace_column is least significant bits u16 | ||
| 2250 | /// rbrace_column is most significant bits u16 | ||
| 2251 | columns: u32, | ||
| 2252 | }; | ||
| 2253 | }; | ||
| 2254 | |||
| 2255 | /// This data is stored inside extra, with trailing operands according to `operands_len`. | ||
| 2256 | /// Each operand is a `Ref`. | ||
| 2257 | pub const MultiOp = struct { | ||
| 2258 | operands_len: u32, | ||
| 2259 | }; | ||
| 2260 | |||
| 2261 | /// Trailing: operand: Ref, // for each `operands_len` (stored in `small`). | ||
| 2262 | pub const NodeMultiOp = struct { | ||
| 2263 | src_node: i32, | ||
| 2264 | }; | ||
| 2265 | |||
| 2266 | /// This data is stored inside extra, with trailing operands according to `body_len`. | ||
| 2267 | /// Each operand is an `Index`. | ||
| 2268 | pub const Block = struct { | ||
| 2269 | body_len: u32, | ||
| 2270 | }; | ||
| 2271 | |||
| 2272 | /// Stored inside extra, with trailing arguments according to `args_len`. | ||
| 2273 | /// Each argument is a `Ref`. | ||
| 2274 | pub const Call = struct { | ||
| 2275 | callee: Ref, | ||
| 2276 | args_len: u32, | ||
| 2277 | }; | ||
| 2278 | |||
| 2279 | pub const BuiltinCall = struct { | ||
| 2280 | options: Ref, | ||
| 2281 | callee: Ref, | ||
| 2282 | args: Ref, | ||
| 2283 | }; | ||
| 2284 | |||
| 2285 | /// This data is stored inside extra, with two sets of trailing `Ref`: | ||
| 2286 | /// * 0. the then body, according to `then_body_len`. | ||
| 2287 | /// * 1. the else body, according to `else_body_len`. | ||
| 2288 | pub const CondBr = struct { | ||
| 2289 | condition: Ref, | ||
| 2290 | then_body_len: u32, | ||
| 2291 | else_body_len: u32, | ||
| 2292 | }; | ||
| 2293 | |||
| 2294 | /// Stored in extra. Depending on the flags in Data, there will be up to 4 | ||
| 2295 | /// trailing Ref fields: | ||
| 2296 | /// 0. sentinel: Ref // if `has_sentinel` flag is set | ||
| 2297 | /// 1. align: Ref // if `has_align` flag is set | ||
| 2298 | /// 2. bit_start: Ref // if `has_bit_range` flag is set | ||
| 2299 | /// 3. bit_end: Ref // if `has_bit_range` flag is set | ||
| 2300 | pub const PtrType = struct { | ||
| 2301 | elem_type: Ref, | ||
| 2302 | }; | ||
| 2303 | |||
| 2304 | pub const ArrayTypeSentinel = struct { | ||
| 2305 | sentinel: Ref, | ||
| 2306 | elem_type: Ref, | ||
| 2307 | }; | ||
| 2308 | |||
| 2309 | pub const SliceStart = struct { | ||
| 2310 | lhs: Ref, | ||
| 2311 | start: Ref, | ||
| 2312 | }; | ||
| 2313 | |||
| 2314 | pub const SliceEnd = struct { | ||
| 2315 | lhs: Ref, | ||
| 2316 | start: Ref, | ||
| 2317 | end: Ref, | ||
| 2318 | }; | ||
| 2319 | |||
| 2320 | pub const SliceSentinel = struct { | ||
| 2321 | lhs: Ref, | ||
| 2322 | start: Ref, | ||
| 2323 | end: Ref, | ||
| 2324 | sentinel: Ref, | ||
| 2325 | }; | ||
| 2326 | |||
| 2327 | /// The meaning of these operands depends on the corresponding `Tag`. | ||
| 2328 | pub const Bin = struct { | ||
| 2329 | lhs: Ref, | ||
| 2330 | rhs: Ref, | ||
| 2331 | }; | ||
| 2332 | |||
| 2333 | pub const BinNode = struct { | ||
| 2334 | node: i32, | ||
| 2335 | lhs: Ref, | ||
| 2336 | rhs: Ref, | ||
| 2337 | }; | ||
| 2338 | |||
| 2339 | pub const UnNode = struct { | ||
| 2340 | node: i32, | ||
| 2341 | operand: Ref, | ||
| 2342 | }; | ||
| 2343 | |||
| 2344 | /// This form is supported when there are no ranges, and exactly 1 item per block. | ||
| 2345 | /// Depending on zir tag and len fields, extra fields trail | ||
| 2346 | /// this one in the extra array. | ||
| 2347 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 2348 | /// body_len: u32, | ||
| 2349 | /// body member Index for every body_len | ||
| 2350 | /// } | ||
| 2351 | /// 1. cases: { | ||
| 2352 | /// item: Ref, | ||
| 2353 | /// body_len: u32, | ||
| 2354 | /// body member Index for every body_len | ||
| 2355 | /// } for every cases_len | ||
| 2356 | pub const SwitchBlock = struct { | ||
| 2357 | operand: Ref, | ||
| 2358 | cases_len: u32, | ||
| 2359 | }; | ||
| 2360 | |||
| 2361 | /// This form is required when there exists a block which has more than one item, | ||
| 2362 | /// or a range. | ||
| 2363 | /// Depending on zir tag and len fields, extra fields trail | ||
| 2364 | /// this one in the extra array. | ||
| 2365 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 2366 | /// body_len: u32, | ||
| 2367 | /// body member Index for every body_len | ||
| 2368 | /// } | ||
| 2369 | /// 1. scalar_cases: { // for every scalar_cases_len | ||
| 2370 | /// item: Ref, | ||
| 2371 | /// body_len: u32, | ||
| 2372 | /// body member Index for every body_len | ||
| 2373 | /// } | ||
| 2374 | /// 2. multi_cases: { // for every multi_cases_len | ||
| 2375 | /// items_len: u32, | ||
| 2376 | /// ranges_len: u32, | ||
| 2377 | /// body_len: u32, | ||
| 2378 | /// item: Ref // for every items_len | ||
| 2379 | /// ranges: { // for every ranges_len | ||
| 2380 | /// item_first: Ref, | ||
| 2381 | /// item_last: Ref, | ||
| 2382 | /// } | ||
| 2383 | /// body member Index for every body_len | ||
| 2384 | /// } | ||
| 2385 | pub const SwitchBlockMulti = struct { | ||
| 2386 | operand: Ref, | ||
| 2387 | scalar_cases_len: u32, | ||
| 2388 | multi_cases_len: u32, | ||
| 2389 | }; | ||
| 2390 | |||
| 2391 | pub const Field = struct { | ||
| 2392 | lhs: Ref, | ||
| 2393 | /// Offset into `string_bytes`. | ||
| 2394 | field_name_start: u32, | ||
| 2395 | }; | ||
| 2396 | |||
| 2397 | pub const FieldNamed = struct { | ||
| 2398 | lhs: Ref, | ||
| 2399 | field_name: Ref, | ||
| 2400 | }; | ||
| 2401 | |||
| 2402 | pub const As = struct { | ||
| 2403 | dest_type: Ref, | ||
| 2404 | operand: Ref, | ||
| 2405 | }; | ||
| 2406 | |||
| 2407 | /// Trailing: | ||
| 2408 | /// 0. src_node: i32, // if has_src_node | ||
| 2409 | /// 1. body_len: u32, // if has_body_len | ||
| 2410 | /// 2. fields_len: u32, // if has_fields_len | ||
| 2411 | /// 3. decls_len: u32, // if has_decls_len | ||
| 2412 | /// 4. decl_bits: u32 // for every 8 decls | ||
| 2413 | /// - sets of 4 bits: | ||
| 2414 | /// 0b000X: whether corresponding decl is pub | ||
| 2415 | /// 0b00X0: whether corresponding decl is exported | ||
| 2416 | /// 0b0X00: whether corresponding decl has an align expression | ||
| 2417 | /// 0bX000: whether corresponding decl has a linksection expression | ||
| 2418 | /// 5. decl: { // for every decls_len | ||
| 2419 | /// src_hash: [4]u32, // hash of source bytes | ||
| 2420 | /// line: u32, // line number of decl, relative to parent | ||
| 2421 | /// name: u32, // null terminated string index | ||
| 2422 | /// - 0 means comptime or usingnamespace decl. | ||
| 2423 | /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace | ||
| 2424 | /// - 1 means test decl with no name. | ||
| 2425 | /// - if there is a 0 byte at the position `name` indexes, it indicates | ||
| 2426 | /// this is a test decl, and the name starts at `name+1`. | ||
| 2427 | /// value: Index, | ||
| 2428 | /// align: Ref, // if corresponding bit is set | ||
| 2429 | /// link_section: Ref, // if corresponding bit is set | ||
| 2430 | /// } | ||
| 2431 | /// 6. inst: Index // for every body_len | ||
| 2432 | /// 7. flags: u32 // for every 8 fields | ||
| 2433 | /// - sets of 4 bits: | ||
| 2434 | /// 0b000X: whether corresponding field has an align expression | ||
| 2435 | /// 0b00X0: whether corresponding field has a default expression | ||
| 2436 | /// 0b0X00: whether corresponding field is comptime | ||
| 2437 | /// 0bX000: unused | ||
| 2438 | /// 8. fields: { // for every fields_len | ||
| 2439 | /// field_name: u32, | ||
| 2440 | /// field_type: Ref, | ||
| 2441 | /// - if none, means `anytype`. | ||
| 2442 | /// align: Ref, // if corresponding bit is set | ||
| 2443 | /// default_value: Ref, // if corresponding bit is set | ||
| 2444 | /// } | ||
| 2445 | pub const StructDecl = struct { | ||
| 2446 | pub const Small = packed struct { | ||
| 2447 | has_src_node: bool, | ||
| 2448 | has_body_len: bool, | ||
| 2449 | has_fields_len: bool, | ||
| 2450 | has_decls_len: bool, | ||
| 2451 | name_strategy: NameStrategy, | ||
| 2452 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 2453 | _: u8 = undefined, | ||
| 2454 | }; | ||
| 2455 | }; | ||
| 2456 | |||
| 2457 | pub const NameStrategy = enum(u2) { | ||
| 2458 | /// Use the same name as the parent declaration name. | ||
| 2459 | /// e.g. `const Foo = struct {...};`. | ||
| 2460 | parent, | ||
| 2461 | /// Use the name of the currently executing comptime function call, | ||
| 2462 | /// with the current parameters. e.g. `ArrayList(i32)`. | ||
| 2463 | func, | ||
| 2464 | /// Create an anonymous name for this declaration. | ||
| 2465 | /// Like this: "ParentDeclName_struct_69" | ||
| 2466 | anon, | ||
| 2467 | }; | ||
| 2468 | |||
| 2469 | /// Trailing: | ||
| 2470 | /// 0. src_node: i32, // if has_src_node | ||
| 2471 | /// 1. tag_type: Ref, // if has_tag_type | ||
| 2472 | /// 2. body_len: u32, // if has_body_len | ||
| 2473 | /// 3. fields_len: u32, // if has_fields_len | ||
| 2474 | /// 4. decls_len: u32, // if has_decls_len | ||
| 2475 | /// 5. decl_bits: u32 // for every 8 decls | ||
| 2476 | /// - sets of 4 bits: | ||
| 2477 | /// 0b000X: whether corresponding decl is pub | ||
| 2478 | /// 0b00X0: whether corresponding decl is exported | ||
| 2479 | /// 0b0X00: whether corresponding decl has an align expression | ||
| 2480 | /// 0bX000: whether corresponding decl has a linksection expression | ||
| 2481 | /// 6. decl: { // for every decls_len | ||
| 2482 | /// src_hash: [4]u32, // hash of source bytes | ||
| 2483 | /// line: u32, // line number of decl, relative to parent | ||
| 2484 | /// name: u32, // null terminated string index | ||
| 2485 | /// - 0 means comptime or usingnamespace decl. | ||
| 2486 | /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace | ||
| 2487 | /// - 1 means test decl with no name. | ||
| 2488 | /// - if there is a 0 byte at the position `name` indexes, it indicates | ||
| 2489 | /// this is a test decl, and the name starts at `name+1`. | ||
| 2490 | /// value: Index, | ||
| 2491 | /// align: Ref, // if corresponding bit is set | ||
| 2492 | /// link_section: Ref, // if corresponding bit is set | ||
| 2493 | /// } | ||
| 2494 | /// 7. inst: Index // for every body_len | ||
| 2495 | /// 8. has_bits: u32 // for every 32 fields | ||
| 2496 | /// - the bit is whether corresponding field has an value expression | ||
| 2497 | /// 9. fields: { // for every fields_len | ||
| 2498 | /// field_name: u32, | ||
| 2499 | /// value: Ref, // if corresponding bit is set | ||
| 2500 | /// } | ||
| 2501 | pub const EnumDecl = struct { | ||
| 2502 | pub const Small = packed struct { | ||
| 2503 | has_src_node: bool, | ||
| 2504 | has_tag_type: bool, | ||
| 2505 | has_body_len: bool, | ||
| 2506 | has_fields_len: bool, | ||
| 2507 | has_decls_len: bool, | ||
| 2508 | name_strategy: NameStrategy, | ||
| 2509 | nonexhaustive: bool, | ||
| 2510 | _: u8 = undefined, | ||
| 2511 | }; | ||
| 2512 | }; | ||
| 2513 | |||
| 2514 | /// Trailing: | ||
| 2515 | /// 0. src_node: i32, // if has_src_node | ||
| 2516 | /// 1. tag_type: Ref, // if has_tag_type | ||
| 2517 | /// 2. body_len: u32, // if has_body_len | ||
| 2518 | /// 3. fields_len: u32, // if has_fields_len | ||
| 2519 | /// 4. decls_len: u32, // if has_decls_len | ||
| 2520 | /// 5. decl_bits: u32 // for every 8 decls | ||
| 2521 | /// - sets of 4 bits: | ||
| 2522 | /// 0b000X: whether corresponding decl is pub | ||
| 2523 | /// 0b00X0: whether corresponding decl is exported | ||
| 2524 | /// 0b0X00: whether corresponding decl has an align expression | ||
| 2525 | /// 0bX000: whether corresponding decl has a linksection expression | ||
| 2526 | /// 6. decl: { // for every decls_len | ||
| 2527 | /// src_hash: [4]u32, // hash of source bytes | ||
| 2528 | /// line: u32, // line number of decl, relative to parent | ||
| 2529 | /// name: u32, // null terminated string index | ||
| 2530 | /// - 0 means comptime or usingnamespace decl. | ||
| 2531 | /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace | ||
| 2532 | /// - 1 means test decl with no name. | ||
| 2533 | /// - if there is a 0 byte at the position `name` indexes, it indicates | ||
| 2534 | /// this is a test decl, and the name starts at `name+1`. | ||
| 2535 | /// value: Index, | ||
| 2536 | /// align: Ref, // if corresponding bit is set | ||
| 2537 | /// link_section: Ref, // if corresponding bit is set | ||
| 2538 | /// } | ||
| 2539 | /// 7. inst: Index // for every body_len | ||
| 2540 | /// 8. has_bits: u32 // for every 8 fields | ||
| 2541 | /// - sets of 4 bits: | ||
| 2542 | /// 0b000X: whether corresponding field has a type expression | ||
| 2543 | /// 0b00X0: whether corresponding field has a align expression | ||
| 2544 | /// 0b0X00: whether corresponding field has a tag value expression | ||
| 2545 | /// 0bX000: unused | ||
| 2546 | /// 9. fields: { // for every fields_len | ||
| 2547 | /// field_name: u32, // null terminated string index | ||
| 2548 | /// field_type: Ref, // if corresponding bit is set | ||
| 2549 | /// align: Ref, // if corresponding bit is set | ||
| 2550 | /// tag_value: Ref, // if corresponding bit is set | ||
| 2551 | /// } | ||
| 2552 | pub const UnionDecl = struct { | ||
| 2553 | pub const Small = packed struct { | ||
| 2554 | has_src_node: bool, | ||
| 2555 | has_tag_type: bool, | ||
| 2556 | has_body_len: bool, | ||
| 2557 | has_fields_len: bool, | ||
| 2558 | has_decls_len: bool, | ||
| 2559 | name_strategy: NameStrategy, | ||
| 2560 | layout: std.builtin.TypeInfo.ContainerLayout, | ||
| 2561 | /// false: union(tag_type) | ||
| 2562 | /// true: union(enum(tag_type)) | ||
| 2563 | auto_enum_tag: bool, | ||
| 2564 | _: u6 = undefined, | ||
| 2565 | }; | ||
| 2566 | }; | ||
| 2567 | |||
| 2568 | /// Trailing: | ||
| 2569 | /// 0. decl_bits: u32 // for every 8 decls | ||
| 2570 | /// - sets of 4 bits: | ||
| 2571 | /// 0b000X: whether corresponding decl is pub | ||
| 2572 | /// 0b00X0: whether corresponding decl is exported | ||
| 2573 | /// 0b0X00: whether corresponding decl has an align expression | ||
| 2574 | /// 0bX000: whether corresponding decl has a linksection expression | ||
| 2575 | /// 1. decl: { // for every decls_len | ||
| 2576 | /// src_hash: [4]u32, // hash of source bytes | ||
| 2577 | /// line: u32, // line number of decl, relative to parent | ||
| 2578 | /// name: u32, // null terminated string index | ||
| 2579 | /// - 0 means comptime or usingnamespace decl. | ||
| 2580 | /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace | ||
| 2581 | /// - 1 means test decl with no name. | ||
| 2582 | /// - if there is a 0 byte at the position `name` indexes, it indicates | ||
| 2583 | /// this is a test decl, and the name starts at `name+1`. | ||
| 2584 | /// value: Index, | ||
| 2585 | /// align: Ref, // if corresponding bit is set | ||
| 2586 | /// link_section: Ref, // if corresponding bit is set | ||
| 2587 | /// } | ||
| 2588 | pub const OpaqueDecl = struct { | ||
| 2589 | decls_len: u32, | ||
| 2590 | }; | ||
| 2591 | |||
| 2592 | /// Trailing: field_name: u32 // for every field: null terminated string index | ||
| 2593 | pub const ErrorSetDecl = struct { | ||
| 2594 | fields_len: u32, | ||
| 2595 | }; | ||
| 2596 | |||
| 2597 | /// A f128 value, broken up into 4 u32 parts. | ||
| 2598 | pub const Float128 = struct { | ||
| 2599 | piece0: u32, | ||
| 2600 | piece1: u32, | ||
| 2601 | piece2: u32, | ||
| 2602 | piece3: u32, | ||
| 2603 | |||
| 2604 | pub fn get(self: Float128) f128 { | ||
| 2605 | const int_bits = @as(u128, self.piece0) | | ||
| 2606 | (@as(u128, self.piece1) << 32) | | ||
| 2607 | (@as(u128, self.piece2) << 64) | | ||
| 2608 | (@as(u128, self.piece3) << 96); | ||
| 2609 | return @bitCast(f128, int_bits); | ||
| 2610 | } | ||
| 2611 | }; | ||
| 2612 | |||
| 2613 | /// Trailing is an item per field. | ||
| 2614 | pub const StructInit = struct { | ||
| 2615 | fields_len: u32, | ||
| 2616 | |||
| 2617 | pub const Item = struct { | ||
| 2618 | /// The `field_type` ZIR instruction for this field init. | ||
| 2619 | field_type: Index, | ||
| 2620 | /// The field init expression to be used as the field value. | ||
| 2621 | init: Ref, | ||
| 2622 | }; | ||
| 2623 | }; | ||
| 2624 | |||
| 2625 | /// Trailing is an item per field. | ||
| 2626 | pub const StructInitAnon = struct { | ||
| 2627 | fields_len: u32, | ||
| 2628 | |||
| 2629 | pub const Item = struct { | ||
| 2630 | /// Null-terminated string table index. | ||
| 2631 | field_name: u32, | ||
| 2632 | /// The field init expression to be used as the field value. | ||
| 2633 | init: Ref, | ||
| 2634 | }; | ||
| 2635 | }; | ||
| 2636 | |||
| 2637 | pub const FieldType = struct { | ||
| 2638 | container_type: Ref, | ||
| 2639 | /// Offset into `string_bytes`, null terminated. | ||
| 2640 | name_start: u32, | ||
| 2641 | }; | ||
| 2642 | |||
| 2643 | pub const FieldTypeRef = struct { | ||
| 2644 | container_type: Ref, | ||
| 2645 | field_name: Ref, | ||
| 2646 | }; | ||
| 2647 | |||
| 2648 | pub const OverflowArithmetic = struct { | ||
| 2649 | node: i32, | ||
| 2650 | lhs: Ref, | ||
| 2651 | rhs: Ref, | ||
| 2652 | ptr: Ref, | ||
| 2653 | }; | ||
| 2654 | |||
| 2655 | pub const Cmpxchg = struct { | ||
| 2656 | ptr: Ref, | ||
| 2657 | expected_value: Ref, | ||
| 2658 | new_value: Ref, | ||
| 2659 | success_order: Ref, | ||
| 2660 | fail_order: Ref, | ||
| 2661 | }; | ||
| 2662 | |||
| 2663 | pub const AtomicRmw = struct { | ||
| 2664 | ptr: Ref, | ||
| 2665 | operation: Ref, | ||
| 2666 | operand: Ref, | ||
| 2667 | ordering: Ref, | ||
| 2668 | }; | ||
| 2669 | |||
| 2670 | pub const UnionInitPtr = struct { | ||
| 2671 | result_ptr: Ref, | ||
| 2672 | union_type: Ref, | ||
| 2673 | field_name: Ref, | ||
| 2674 | }; | ||
| 2675 | |||
| 2676 | pub const AtomicStore = struct { | ||
| 2677 | ptr: Ref, | ||
| 2678 | operand: Ref, | ||
| 2679 | ordering: Ref, | ||
| 2680 | }; | ||
| 2681 | |||
| 2682 | pub const MulAdd = struct { | ||
| 2683 | mulend1: Ref, | ||
| 2684 | mulend2: Ref, | ||
| 2685 | addend: Ref, | ||
| 2686 | }; | ||
| 2687 | |||
| 2688 | pub const FieldParentPtr = struct { | ||
| 2689 | parent_type: Ref, | ||
| 2690 | field_name: Ref, | ||
| 2691 | field_ptr: Ref, | ||
| 2692 | }; | ||
| 2693 | |||
| 2694 | pub const Memcpy = struct { | ||
| 2695 | dest: Ref, | ||
| 2696 | source: Ref, | ||
| 2697 | byte_count: Ref, | ||
| 2698 | }; | ||
| 2699 | |||
| 2700 | pub const Memset = struct { | ||
| 2701 | dest: Ref, | ||
| 2702 | byte: Ref, | ||
| 2703 | byte_count: Ref, | ||
| 2704 | }; | ||
| 2705 | |||
| 2706 | pub const Shuffle = struct { | ||
| 2707 | elem_type: Ref, | ||
| 2708 | a: Ref, | ||
| 2709 | b: Ref, | ||
| 2710 | mask: Ref, | ||
| 2711 | }; | ||
| 2712 | |||
| 2713 | pub const AsyncCall = struct { | ||
| 2714 | frame_buffer: Ref, | ||
| 2715 | result_ptr: Ref, | ||
| 2716 | fn_ptr: Ref, | ||
| 2717 | args: Ref, | ||
| 2718 | }; | ||
| 2719 | |||
| 2720 | /// Trailing: | ||
| 2721 | /// 0. type_inst: Ref, // if small 0b000X is set | ||
| 2722 | /// 1. align_inst: Ref, // if small 0b00X0 is set | ||
| 2723 | pub const AllocExtended = struct { | ||
| 2724 | src_node: i32, | ||
| 2725 | }; | ||
| 2726 | |||
| 2727 | pub const Export = struct { | ||
| 2728 | /// Null-terminated string index. | ||
| 2729 | decl_name: u32, | ||
| 2730 | options: Ref, | ||
| 2731 | }; | ||
| 2732 | |||
| 2733 | /// Trailing: `CompileErrors.Item` for each `items_len`. | ||
| 2734 | pub const CompileErrors = struct { | ||
| 2735 | items_len: u32, | ||
| 2736 | |||
| 2737 | /// Trailing: `note_payload_index: u32` for each `notes_len`. | ||
| 2738 | /// It's a payload index of another `Item`. | ||
| 2739 | pub const Item = struct { | ||
| 2740 | /// null terminated string index | ||
| 2741 | msg: u32, | ||
| 2742 | node: ast.Node.Index, | ||
| 2743 | /// If node is 0 then this will be populated. | ||
| 2744 | token: ast.TokenIndex, | ||
| 2745 | /// Can be used in combination with `token`. | ||
| 2746 | byte_offset: u32, | ||
| 2747 | /// 0 or a payload index of a `Block`, each is a payload | ||
| 2748 | /// index of another `Item`. | ||
| 2749 | notes: u32, | ||
| 2750 | }; | ||
| 2751 | }; | ||
| 2752 | |||
| 2753 | /// Trailing: for each `imports_len` there is a string table index. | ||
| 2754 | pub const Imports = struct { | ||
| 2755 | imports_len: u32, | ||
| 2756 | }; | ||
| 2757 | }; | ||
| 2758 | |||
| 2759 | pub const SpecialProng = enum { none, @"else", under }; | ||
| 2760 | |||
| 2761 | const Writer = struct { | ||
| 2762 | gpa: *Allocator, | ||
| 2763 | arena: *Allocator, | ||
| 2764 | file: *Module.Scope.File, | ||
| 2765 | code: Zir, | ||
| 2766 | indent: u32, | ||
| 2767 | parent_decl_node: u32, | ||
| 2768 | |||
| 2769 | fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index { | ||
| 2770 | return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); | ||
| 2771 | } | ||
| 2772 | |||
| 2773 | fn writeInstToStream( | ||
| 2774 | self: *Writer, | ||
| 2775 | stream: anytype, | ||
| 2776 | inst: Inst.Index, | ||
| 2777 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 2778 | const tags = self.code.instructions.items(.tag); | ||
| 2779 | const tag = tags[inst]; | ||
| 2780 | try stream.print("= {s}(", .{@tagName(tags[inst])}); | ||
| 2781 | switch (tag) { | ||
| 2782 | .array_type, | ||
| 2783 | .as, | ||
| 2784 | .coerce_result_ptr, | ||
| 2785 | .elem_ptr, | ||
| 2786 | .elem_val, | ||
| 2787 | .store, | ||
| 2788 | .store_to_block_ptr, | ||
| 2789 | .store_to_inferred_ptr, | ||
| 2790 | .field_ptr_type, | ||
| 2791 | => try self.writeBin(stream, inst), | ||
| 2792 | |||
| 2793 | .alloc, | ||
| 2794 | .alloc_mut, | ||
| 2795 | .alloc_comptime, | ||
| 2796 | .indexable_ptr_len, | ||
| 2797 | .anyframe_type, | ||
| 2798 | .bit_not, | ||
| 2799 | .bool_not, | ||
| 2800 | .negate, | ||
| 2801 | .negate_wrap, | ||
| 2802 | .load, | ||
| 2803 | .ensure_result_used, | ||
| 2804 | .ensure_result_non_error, | ||
| 2805 | .ret_node, | ||
| 2806 | .resolve_inferred_alloc, | ||
| 2807 | .optional_type, | ||
| 2808 | .optional_payload_safe, | ||
| 2809 | .optional_payload_unsafe, | ||
| 2810 | .optional_payload_safe_ptr, | ||
| 2811 | .optional_payload_unsafe_ptr, | ||
| 2812 | .err_union_payload_safe, | ||
| 2813 | .err_union_payload_unsafe, | ||
| 2814 | .err_union_payload_safe_ptr, | ||
| 2815 | .err_union_payload_unsafe_ptr, | ||
| 2816 | .err_union_code, | ||
| 2817 | .err_union_code_ptr, | ||
| 2818 | .is_non_null, | ||
| 2819 | .is_null, | ||
| 2820 | .is_non_null_ptr, | ||
| 2821 | .is_null_ptr, | ||
| 2822 | .is_err, | ||
| 2823 | .is_err_ptr, | ||
| 2824 | .typeof, | ||
| 2825 | .typeof_elem, | ||
| 2826 | .struct_init_empty, | ||
| 2827 | .type_info, | ||
| 2828 | .size_of, | ||
| 2829 | .bit_size_of, | ||
| 2830 | .typeof_log2_int_type, | ||
| 2831 | .log2_int_type, | ||
| 2832 | .ptr_to_int, | ||
| 2833 | .error_to_int, | ||
| 2834 | .int_to_error, | ||
| 2835 | .compile_error, | ||
| 2836 | .set_eval_branch_quota, | ||
| 2837 | .enum_to_int, | ||
| 2838 | .align_of, | ||
| 2839 | .bool_to_int, | ||
| 2840 | .embed_file, | ||
| 2841 | .error_name, | ||
| 2842 | .panic, | ||
| 2843 | .set_align_stack, | ||
| 2844 | .set_cold, | ||
| 2845 | .set_float_mode, | ||
| 2846 | .set_runtime_safety, | ||
| 2847 | .sqrt, | ||
| 2848 | .sin, | ||
| 2849 | .cos, | ||
| 2850 | .exp, | ||
| 2851 | .exp2, | ||
| 2852 | .log, | ||
| 2853 | .log2, | ||
| 2854 | .log10, | ||
| 2855 | .fabs, | ||
| 2856 | .floor, | ||
| 2857 | .ceil, | ||
| 2858 | .trunc, | ||
| 2859 | .round, | ||
| 2860 | .tag_name, | ||
| 2861 | .reify, | ||
| 2862 | .type_name, | ||
| 2863 | .frame_type, | ||
| 2864 | .frame_size, | ||
| 2865 | .clz, | ||
| 2866 | .ctz, | ||
| 2867 | .pop_count, | ||
| 2868 | .byte_swap, | ||
| 2869 | .bit_reverse, | ||
| 2870 | .elem_type, | ||
| 2871 | .@"resume", | ||
| 2872 | .@"await", | ||
| 2873 | .await_nosuspend, | ||
| 2874 | => try self.writeUnNode(stream, inst), | ||
| 2875 | |||
| 2876 | .ref, | ||
| 2877 | .ret_coerce, | ||
| 2878 | .ensure_err_payload_void, | ||
| 2879 | => try self.writeUnTok(stream, inst), | ||
| 2880 | |||
| 2881 | .bool_br_and, | ||
| 2882 | .bool_br_or, | ||
| 2883 | => try self.writeBoolBr(stream, inst), | ||
| 2884 | |||
| 2885 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), | ||
| 2886 | .param_type => try self.writeParamType(stream, inst), | ||
| 2887 | .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), | ||
| 2888 | .ptr_type => try self.writePtrType(stream, inst), | ||
| 2889 | .int => try self.writeInt(stream, inst), | ||
| 2890 | .int_big => try self.writeIntBig(stream, inst), | ||
| 2891 | .float => try self.writeFloat(stream, inst), | ||
| 2892 | .float128 => try self.writeFloat128(stream, inst), | ||
| 2893 | .str => try self.writeStr(stream, inst), | ||
| 2894 | .int_type => try self.writeIntType(stream, inst), | ||
| 2895 | |||
| 2896 | .@"break", | ||
| 2897 | .break_inline, | ||
| 2898 | => try self.writeBreak(stream, inst), | ||
| 2899 | |||
| 2900 | .elem_ptr_node, | ||
| 2901 | .elem_val_node, | ||
| 2902 | .field_ptr_named, | ||
| 2903 | .field_val_named, | ||
| 2904 | .slice_start, | ||
| 2905 | .slice_end, | ||
| 2906 | .slice_sentinel, | ||
| 2907 | .array_init, | ||
| 2908 | .array_init_anon, | ||
| 2909 | .array_init_ref, | ||
| 2910 | .array_init_anon_ref, | ||
| 2911 | .union_init_ptr, | ||
| 2912 | .cmpxchg_strong, | ||
| 2913 | .cmpxchg_weak, | ||
| 2914 | .shuffle, | ||
| 2915 | .atomic_rmw, | ||
| 2916 | .atomic_store, | ||
| 2917 | .mul_add, | ||
| 2918 | .builtin_call, | ||
| 2919 | .field_parent_ptr, | ||
| 2920 | .memcpy, | ||
| 2921 | .memset, | ||
| 2922 | .builtin_async_call, | ||
| 2923 | => try self.writePlNode(stream, inst), | ||
| 2924 | |||
| 2925 | .struct_init, | ||
| 2926 | .struct_init_ref, | ||
| 2927 | => try self.writeStructInit(stream, inst), | ||
| 2928 | |||
| 2929 | .struct_init_anon, | ||
| 2930 | .struct_init_anon_ref, | ||
| 2931 | => try self.writeStructInitAnon(stream, inst), | ||
| 2932 | |||
| 2933 | .field_type => try self.writeFieldType(stream, inst), | ||
| 2934 | .field_type_ref => try self.writeFieldTypeRef(stream, inst), | ||
| 2935 | |||
| 2936 | .add, | ||
| 2937 | .addwrap, | ||
| 2938 | .array_cat, | ||
| 2939 | .array_mul, | ||
| 2940 | .mul, | ||
| 2941 | .mulwrap, | ||
| 2942 | .sub, | ||
| 2943 | .subwrap, | ||
| 2944 | .bool_and, | ||
| 2945 | .bool_or, | ||
| 2946 | .cmp_lt, | ||
| 2947 | .cmp_lte, | ||
| 2948 | .cmp_eq, | ||
| 2949 | .cmp_gte, | ||
| 2950 | .cmp_gt, | ||
| 2951 | .cmp_neq, | ||
| 2952 | .div, | ||
| 2953 | .has_decl, | ||
| 2954 | .has_field, | ||
| 2955 | .mod_rem, | ||
| 2956 | .shl, | ||
| 2957 | .shl_exact, | ||
| 2958 | .shr, | ||
| 2959 | .shr_exact, | ||
| 2960 | .xor, | ||
| 2961 | .store_node, | ||
| 2962 | .error_union_type, | ||
| 2963 | .merge_error_sets, | ||
| 2964 | .bit_and, | ||
| 2965 | .bit_or, | ||
| 2966 | .float_to_int, | ||
| 2967 | .int_to_float, | ||
| 2968 | .int_to_ptr, | ||
| 2969 | .int_to_enum, | ||
| 2970 | .float_cast, | ||
| 2971 | .int_cast, | ||
| 2972 | .err_set_cast, | ||
| 2973 | .ptr_cast, | ||
| 2974 | .truncate, | ||
| 2975 | .align_cast, | ||
| 2976 | .div_exact, | ||
| 2977 | .div_floor, | ||
| 2978 | .div_trunc, | ||
| 2979 | .mod, | ||
| 2980 | .rem, | ||
| 2981 | .bit_offset_of, | ||
| 2982 | .byte_offset_of, | ||
| 2983 | .splat, | ||
| 2984 | .reduce, | ||
| 2985 | .atomic_load, | ||
| 2986 | .bitcast, | ||
| 2987 | .bitcast_result_ptr, | ||
| 2988 | .vector_type, | ||
| 2989 | => try self.writePlNodeBin(stream, inst), | ||
| 2990 | |||
| 2991 | .@"export" => try self.writePlNodeExport(stream, inst), | ||
| 2992 | |||
| 2993 | .call, | ||
| 2994 | .call_chkused, | ||
| 2995 | .call_compile_time, | ||
| 2996 | .call_nosuspend, | ||
| 2997 | .call_async, | ||
| 2998 | => try self.writePlNodeCall(stream, inst), | ||
| 2999 | |||
| 3000 | .block, | ||
| 3001 | .block_inline, | ||
| 3002 | .suspend_block, | ||
| 3003 | .loop, | ||
| 3004 | .validate_struct_init_ptr, | ||
| 3005 | .validate_array_init_ptr, | ||
| 3006 | .c_import, | ||
| 3007 | => try self.writePlNodeBlock(stream, inst), | ||
| 3008 | |||
| 3009 | .condbr, | ||
| 3010 | .condbr_inline, | ||
| 3011 | => try self.writePlNodeCondBr(stream, inst), | ||
| 3012 | |||
| 3013 | .opaque_decl => try self.writeOpaqueDecl(stream, inst, .parent), | ||
| 3014 | .opaque_decl_anon => try self.writeOpaqueDecl(stream, inst, .anon), | ||
| 3015 | .opaque_decl_func => try self.writeOpaqueDecl(stream, inst, .func), | ||
| 3016 | |||
| 3017 | .error_set_decl => try self.writeErrorSetDecl(stream, inst, .parent), | ||
| 3018 | .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), | ||
| 3019 | .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), | ||
| 3020 | |||
| 3021 | .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), | ||
| 3022 | .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 3023 | .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 3024 | .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none), | ||
| 3025 | .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 3026 | .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 3027 | |||
| 3028 | .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 3029 | .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 3030 | .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 3031 | .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 3032 | .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 3033 | .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 3034 | |||
| 3035 | .field_ptr, | ||
| 3036 | .field_val, | ||
| 3037 | => try self.writePlNodeField(stream, inst), | ||
| 3038 | |||
| 3039 | .as_node => try self.writeAs(stream, inst), | ||
| 3040 | |||
| 3041 | .breakpoint, | ||
| 3042 | .fence, | ||
| 3043 | .repeat, | ||
| 3044 | .repeat_inline, | ||
| 3045 | .alloc_inferred, | ||
| 3046 | .alloc_inferred_mut, | ||
| 3047 | .alloc_inferred_comptime, | ||
| 3048 | => try self.writeNode(stream, inst), | ||
| 3049 | |||
| 3050 | .error_value, | ||
| 3051 | .enum_literal, | ||
| 3052 | .decl_ref, | ||
| 3053 | .decl_val, | ||
| 3054 | .import, | ||
| 3055 | .arg, | ||
| 3056 | => try self.writeStrTok(stream, inst), | ||
| 3057 | |||
| 3058 | .func => try self.writeFunc(stream, inst, false), | ||
| 3059 | .func_inferred => try self.writeFunc(stream, inst, true), | ||
| 3060 | |||
| 3061 | .@"unreachable" => try self.writeUnreachable(stream, inst), | ||
| 3062 | |||
| 3063 | .switch_capture, | ||
| 3064 | .switch_capture_ref, | ||
| 3065 | .switch_capture_multi, | ||
| 3066 | .switch_capture_multi_ref, | ||
| 3067 | .switch_capture_else, | ||
| 3068 | .switch_capture_else_ref, | ||
| 3069 | => try self.writeSwitchCapture(stream, inst), | ||
| 3070 | |||
| 3071 | .dbg_stmt => try self.writeDbgStmt(stream, inst), | ||
| 3072 | |||
| 3073 | .extended => try self.writeExtended(stream, inst), | ||
| 3074 | } | ||
| 3075 | } | ||
| 3076 | |||
| 3077 | fn writeExtended(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3078 | const extended = self.code.instructions.items(.data)[inst].extended; | ||
| 3079 | try stream.print("{s}(", .{@tagName(extended.opcode)}); | ||
| 3080 | switch (extended.opcode) { | ||
| 3081 | .ret_ptr, | ||
| 3082 | .ret_type, | ||
| 3083 | .this, | ||
| 3084 | .ret_addr, | ||
| 3085 | .error_return_trace, | ||
| 3086 | .frame, | ||
| 3087 | .frame_address, | ||
| 3088 | .builtin_src, | ||
| 3089 | => try self.writeExtNode(stream, extended), | ||
| 3090 | |||
| 3091 | .@"asm" => try self.writeAsm(stream, extended), | ||
| 3092 | .func => try self.writeFuncExtended(stream, extended), | ||
| 3093 | .variable => try self.writeVarExtended(stream, extended), | ||
| 3094 | |||
| 3095 | .compile_log, | ||
| 3096 | .typeof_peer, | ||
| 3097 | => try self.writeNodeMultiOp(stream, extended), | ||
| 3098 | |||
| 3099 | .add_with_overflow, | ||
| 3100 | .sub_with_overflow, | ||
| 3101 | .mul_with_overflow, | ||
| 3102 | .shl_with_overflow, | ||
| 3103 | => try self.writeOverflowArithmetic(stream, extended), | ||
| 3104 | |||
| 3105 | .struct_decl => try self.writeStructDecl(stream, extended), | ||
| 3106 | .union_decl => try self.writeUnionDecl(stream, extended), | ||
| 3107 | .enum_decl => try self.writeEnumDecl(stream, extended), | ||
| 3108 | |||
| 3109 | .alloc, | ||
| 3110 | .builtin_extern, | ||
| 3111 | .c_undef, | ||
| 3112 | .c_include, | ||
| 3113 | .c_define, | ||
| 3114 | .wasm_memory_size, | ||
| 3115 | .wasm_memory_grow, | ||
| 3116 | => try stream.writeAll("TODO))"), | ||
| 3117 | } | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | fn writeExtNode(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3121 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | ||
| 3122 | try stream.writeAll(")) "); | ||
| 3123 | try self.writeSrc(stream, src); | ||
| 3124 | } | ||
| 3125 | |||
| 3126 | fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3127 | const inst_data = self.code.instructions.items(.data)[inst].bin; | ||
| 3128 | try self.writeInstRef(stream, inst_data.lhs); | ||
| 3129 | try stream.writeAll(", "); | ||
| 3130 | try self.writeInstRef(stream, inst_data.rhs); | ||
| 3131 | try stream.writeByte(')'); | ||
| 3132 | } | ||
| 3133 | |||
| 3134 | fn writeUnNode( | ||
| 3135 | self: *Writer, | ||
| 3136 | stream: anytype, | ||
| 3137 | inst: Inst.Index, | ||
| 3138 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3139 | const inst_data = self.code.instructions.items(.data)[inst].un_node; | ||
| 3140 | try self.writeInstRef(stream, inst_data.operand); | ||
| 3141 | try stream.writeAll(") "); | ||
| 3142 | try self.writeSrc(stream, inst_data.src()); | ||
| 3143 | } | ||
| 3144 | |||
| 3145 | fn writeUnTok( | ||
| 3146 | self: *Writer, | ||
| 3147 | stream: anytype, | ||
| 3148 | inst: Inst.Index, | ||
| 3149 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3150 | const inst_data = self.code.instructions.items(.data)[inst].un_tok; | ||
| 3151 | try self.writeInstRef(stream, inst_data.operand); | ||
| 3152 | try stream.writeAll(") "); | ||
| 3153 | try self.writeSrc(stream, inst_data.src()); | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | fn writeArrayTypeSentinel( | ||
| 3157 | self: *Writer, | ||
| 3158 | stream: anytype, | ||
| 3159 | inst: Inst.Index, | ||
| 3160 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3161 | const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel; | ||
| 3162 | try stream.writeAll("TODO)"); | ||
| 3163 | } | ||
| 3164 | |||
| 3165 | fn writeParamType( | ||
| 3166 | self: *Writer, | ||
| 3167 | stream: anytype, | ||
| 3168 | inst: Inst.Index, | ||
| 3169 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3170 | const inst_data = self.code.instructions.items(.data)[inst].param_type; | ||
| 3171 | try self.writeInstRef(stream, inst_data.callee); | ||
| 3172 | try stream.print(", {d})", .{inst_data.param_index}); | ||
| 3173 | } | ||
| 3174 | |||
| 3175 | fn writePtrTypeSimple( | ||
| 3176 | self: *Writer, | ||
| 3177 | stream: anytype, | ||
| 3178 | inst: Inst.Index, | ||
| 3179 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3180 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; | ||
| 3181 | const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else ""; | ||
| 3182 | const str_const = if (!inst_data.is_mutable) "const, " else ""; | ||
| 3183 | const str_volatile = if (inst_data.is_volatile) "volatile, " else ""; | ||
| 3184 | try self.writeInstRef(stream, inst_data.elem_type); | ||
| 3185 | try stream.print(", {s}{s}{s}{s})", .{ | ||
| 3186 | str_allowzero, | ||
| 3187 | str_const, | ||
| 3188 | str_volatile, | ||
| 3189 | @tagName(inst_data.size), | ||
| 3190 | }); | ||
| 3191 | } | ||
| 3192 | |||
| 3193 | fn writePtrType( | ||
| 3194 | self: *Writer, | ||
| 3195 | stream: anytype, | ||
| 3196 | inst: Inst.Index, | ||
| 3197 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3198 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type; | ||
| 3199 | try stream.writeAll("TODO)"); | ||
| 3200 | } | ||
| 3201 | |||
| 3202 | fn writeInt(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3203 | const inst_data = self.code.instructions.items(.data)[inst].int; | ||
| 3204 | try stream.print("{d})", .{inst_data}); | ||
| 3205 | } | ||
| 3206 | |||
| 3207 | fn writeIntBig(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3208 | const inst_data = self.code.instructions.items(.data)[inst].str; | ||
| 3209 | const byte_count = inst_data.len * @sizeOf(std.math.big.Limb); | ||
| 3210 | const limb_bytes = self.code.string_bytes[inst_data.start..][0..byte_count]; | ||
| 3211 | // limb_bytes is not aligned properly; we must allocate and copy the bytes | ||
| 3212 | // in order to accomplish this. | ||
| 3213 | const limbs = try self.gpa.alloc(std.math.big.Limb, inst_data.len); | ||
| 3214 | defer self.gpa.free(limbs); | ||
| 3215 | |||
| 3216 | mem.copy(u8, mem.sliceAsBytes(limbs), limb_bytes); | ||
| 3217 | const big_int: std.math.big.int.Const = .{ | ||
| 3218 | .limbs = limbs, | ||
| 3219 | .positive = true, | ||
| 3220 | }; | ||
| 3221 | const as_string = try big_int.toStringAlloc(self.gpa, 10, false); | ||
| 3222 | defer self.gpa.free(as_string); | ||
| 3223 | try stream.print("{s})", .{as_string}); | ||
| 3224 | } | ||
| 3225 | |||
| 3226 | fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3227 | const inst_data = self.code.instructions.items(.data)[inst].float; | ||
| 3228 | const src = inst_data.src(); | ||
| 3229 | try stream.print("{d}) ", .{inst_data.number}); | ||
| 3230 | try self.writeSrc(stream, src); | ||
| 3231 | } | ||
| 3232 | |||
| 3233 | fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3234 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3235 | const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data; | ||
| 3236 | const src = inst_data.src(); | ||
| 3237 | const number = extra.get(); | ||
| 3238 | // TODO improve std.format to be able to print f128 values | ||
| 3239 | try stream.print("{d}) ", .{@floatCast(f64, number)}); | ||
| 3240 | try self.writeSrc(stream, src); | ||
| 3241 | } | ||
| 3242 | |||
| 3243 | fn writeStr( | ||
| 3244 | self: *Writer, | ||
| 3245 | stream: anytype, | ||
| 3246 | inst: Inst.Index, | ||
| 3247 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 3248 | const inst_data = self.code.instructions.items(.data)[inst].str; | ||
| 3249 | const str = inst_data.get(self.code); | ||
| 3250 | try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); | ||
| 3251 | } | ||
| 3252 | |||
| 3253 | fn writePlNode(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3254 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3255 | try stream.writeAll("TODO) "); | ||
| 3256 | try self.writeSrc(stream, inst_data.src()); | ||
| 3257 | } | ||
| 3258 | |||
| 3259 | fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3260 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3261 | const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data; | ||
| 3262 | try self.writeInstRef(stream, extra.lhs); | ||
| 3263 | try stream.writeAll(", "); | ||
| 3264 | try self.writeInstRef(stream, extra.rhs); | ||
| 3265 | try stream.writeAll(") "); | ||
| 3266 | try self.writeSrc(stream, inst_data.src()); | ||
| 3267 | } | ||
| 3268 | |||
| 3269 | fn writePlNodeExport(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3270 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3271 | const extra = self.code.extraData(Inst.Export, inst_data.payload_index).data; | ||
| 3272 | const decl_name = self.code.nullTerminatedString(extra.decl_name); | ||
| 3273 | |||
| 3274 | try stream.print("{}, ", .{std.zig.fmtId(decl_name)}); | ||
| 3275 | try self.writeInstRef(stream, extra.options); | ||
| 3276 | try stream.writeAll(") "); | ||
| 3277 | try self.writeSrc(stream, inst_data.src()); | ||
| 3278 | } | ||
| 3279 | |||
| 3280 | fn writeStructInit(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3281 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3282 | const extra = self.code.extraData(Inst.StructInit, inst_data.payload_index); | ||
| 3283 | var field_i: u32 = 0; | ||
| 3284 | var extra_index = extra.end; | ||
| 3285 | |||
| 3286 | while (field_i < extra.data.fields_len) : (field_i += 1) { | ||
| 3287 | const item = self.code.extraData(Inst.StructInit.Item, extra_index); | ||
| 3288 | extra_index = item.end; | ||
| 3289 | |||
| 3290 | if (field_i != 0) { | ||
| 3291 | try stream.writeAll(", ["); | ||
| 3292 | } else { | ||
| 3293 | try stream.writeAll("["); | ||
| 3294 | } | ||
| 3295 | try self.writeInstIndex(stream, item.data.field_type); | ||
| 3296 | try stream.writeAll(", "); | ||
| 3297 | try self.writeInstRef(stream, item.data.init); | ||
| 3298 | try stream.writeAll("]"); | ||
| 3299 | } | ||
| 3300 | try stream.writeAll(") "); | ||
| 3301 | try self.writeSrc(stream, inst_data.src()); | ||
| 3302 | } | ||
| 3303 | |||
| 3304 | fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3305 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3306 | const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index); | ||
| 3307 | var field_i: u32 = 0; | ||
| 3308 | var extra_index = extra.end; | ||
| 3309 | |||
| 3310 | while (field_i < extra.data.fields_len) : (field_i += 1) { | ||
| 3311 | const item = self.code.extraData(Inst.StructInitAnon.Item, extra_index); | ||
| 3312 | extra_index = item.end; | ||
| 3313 | |||
| 3314 | const field_name = self.code.nullTerminatedString(item.data.field_name); | ||
| 3315 | |||
| 3316 | const prefix = if (field_i != 0) ", [" else "["; | ||
| 3317 | try stream.print("{s}[{s}=", .{ prefix, field_name }); | ||
| 3318 | try self.writeInstRef(stream, item.data.init); | ||
| 3319 | try stream.writeAll("]"); | ||
| 3320 | } | ||
| 3321 | try stream.writeAll(") "); | ||
| 3322 | try self.writeSrc(stream, inst_data.src()); | ||
| 3323 | } | ||
| 3324 | |||
| 3325 | fn writeFieldType(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3326 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3327 | const extra = self.code.extraData(Inst.FieldType, inst_data.payload_index).data; | ||
| 3328 | try self.writeInstRef(stream, extra.container_type); | ||
| 3329 | const field_name = self.code.nullTerminatedString(extra.name_start); | ||
| 3330 | try stream.print(", {s}) ", .{field_name}); | ||
| 3331 | try self.writeSrc(stream, inst_data.src()); | ||
| 3332 | } | ||
| 3333 | |||
| 3334 | fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3335 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3336 | const extra = self.code.extraData(Inst.FieldTypeRef, inst_data.payload_index).data; | ||
| 3337 | try self.writeInstRef(stream, extra.container_type); | ||
| 3338 | try stream.writeAll(", "); | ||
| 3339 | try self.writeInstRef(stream, extra.field_name); | ||
| 3340 | try stream.writeAll(") "); | ||
| 3341 | try self.writeSrc(stream, inst_data.src()); | ||
| 3342 | } | ||
| 3343 | |||
| 3344 | fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3345 | const extra = self.code.extraData(Inst.NodeMultiOp, extended.operand); | ||
| 3346 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; | ||
| 3347 | const operands = self.code.refSlice(extra.end, extended.small); | ||
| 3348 | |||
| 3349 | for (operands) |operand, i| { | ||
| 3350 | if (i != 0) try stream.writeAll(", "); | ||
| 3351 | try self.writeInstRef(stream, operand); | ||
| 3352 | } | ||
| 3353 | try stream.writeAll(")) "); | ||
| 3354 | try self.writeSrc(stream, src); | ||
| 3355 | } | ||
| 3356 | |||
| 3357 | fn writeAsm(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3358 | const extra = self.code.extraData(Inst.Asm, extended.operand); | ||
| 3359 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; | ||
| 3360 | const outputs_len = @truncate(u5, extended.small); | ||
| 3361 | const inputs_len = @truncate(u5, extended.small >> 5); | ||
| 3362 | const clobbers_len = @truncate(u5, extended.small >> 10); | ||
| 3363 | const is_volatile = @truncate(u1, extended.small >> 15) != 0; | ||
| 3364 | |||
| 3365 | try self.writeFlag(stream, "volatile, ", is_volatile); | ||
| 3366 | try self.writeInstRef(stream, extra.data.asm_source); | ||
| 3367 | try stream.writeAll(", "); | ||
| 3368 | |||
| 3369 | var extra_i: usize = extra.end; | ||
| 3370 | var output_type_bits = extra.data.output_type_bits; | ||
| 3371 | { | ||
| 3372 | var i: usize = 0; | ||
| 3373 | while (i < outputs_len) : (i += 1) { | ||
| 3374 | const output = self.code.extraData(Inst.Asm.Output, extra_i); | ||
| 3375 | extra_i = output.end; | ||
| 3376 | |||
| 3377 | const is_type = @truncate(u1, output_type_bits) != 0; | ||
| 3378 | output_type_bits >>= 1; | ||
| 3379 | |||
| 3380 | const name = self.code.nullTerminatedString(output.data.name); | ||
| 3381 | const constraint = self.code.nullTerminatedString(output.data.constraint); | ||
| 3382 | try stream.print("output({}, \"{}\", ", .{ | ||
| 3383 | std.zig.fmtId(name), std.zig.fmtEscapes(constraint), | ||
| 3384 | }); | ||
| 3385 | try self.writeFlag(stream, "->", is_type); | ||
| 3386 | try self.writeInstRef(stream, output.data.operand); | ||
| 3387 | try stream.writeAll(")"); | ||
| 3388 | if (i + 1 < outputs_len) { | ||
| 3389 | try stream.writeAll("), "); | ||
| 3390 | } | ||
| 3391 | } | ||
| 3392 | } | ||
| 3393 | { | ||
| 3394 | var i: usize = 0; | ||
| 3395 | while (i < inputs_len) : (i += 1) { | ||
| 3396 | const input = self.code.extraData(Inst.Asm.Input, extra_i); | ||
| 3397 | extra_i = input.end; | ||
| 3398 | |||
| 3399 | const name = self.code.nullTerminatedString(input.data.name); | ||
| 3400 | const constraint = self.code.nullTerminatedString(input.data.constraint); | ||
| 3401 | try stream.print("input({}, \"{}\", ", .{ | ||
| 3402 | std.zig.fmtId(name), std.zig.fmtEscapes(constraint), | ||
| 3403 | }); | ||
| 3404 | try self.writeInstRef(stream, input.data.operand); | ||
| 3405 | try stream.writeAll(")"); | ||
| 3406 | if (i + 1 < inputs_len) { | ||
| 3407 | try stream.writeAll(", "); | ||
| 3408 | } | ||
| 3409 | } | ||
| 3410 | } | ||
| 3411 | { | ||
| 3412 | var i: usize = 0; | ||
| 3413 | while (i < clobbers_len) : (i += 1) { | ||
| 3414 | const str_index = self.code.extra[extra_i]; | ||
| 3415 | extra_i += 1; | ||
| 3416 | const clobber = self.code.nullTerminatedString(str_index); | ||
| 3417 | try stream.print("{}", .{std.zig.fmtId(clobber)}); | ||
| 3418 | if (i + 1 < clobbers_len) { | ||
| 3419 | try stream.writeAll(", "); | ||
| 3420 | } | ||
| 3421 | } | ||
| 3422 | } | ||
| 3423 | try stream.writeAll(")) "); | ||
| 3424 | try self.writeSrc(stream, src); | ||
| 3425 | } | ||
| 3426 | |||
| 3427 | fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3428 | const extra = self.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; | ||
| 3429 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | ||
| 3430 | |||
| 3431 | try self.writeInstRef(stream, extra.lhs); | ||
| 3432 | try stream.writeAll(", "); | ||
| 3433 | try self.writeInstRef(stream, extra.rhs); | ||
| 3434 | try stream.writeAll(", "); | ||
| 3435 | try self.writeInstRef(stream, extra.ptr); | ||
| 3436 | try stream.writeAll(")) "); | ||
| 3437 | try self.writeSrc(stream, src); | ||
| 3438 | } | ||
| 3439 | |||
| 3440 | fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3441 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3442 | const extra = self.code.extraData(Inst.Call, inst_data.payload_index); | ||
| 3443 | const args = self.code.refSlice(extra.end, extra.data.args_len); | ||
| 3444 | |||
| 3445 | try self.writeInstRef(stream, extra.data.callee); | ||
| 3446 | try stream.writeAll(", ["); | ||
| 3447 | for (args) |arg, i| { | ||
| 3448 | if (i != 0) try stream.writeAll(", "); | ||
| 3449 | try self.writeInstRef(stream, arg); | ||
| 3450 | } | ||
| 3451 | try stream.writeAll("]) "); | ||
| 3452 | try self.writeSrc(stream, inst_data.src()); | ||
| 3453 | } | ||
| 3454 | |||
| 3455 | fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3456 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3457 | try self.writePlNodeBlockWithoutSrc(stream, inst); | ||
| 3458 | try self.writeSrc(stream, inst_data.src()); | ||
| 3459 | } | ||
| 3460 | |||
| 3461 | fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3462 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3463 | const extra = self.code.extraData(Inst.Block, inst_data.payload_index); | ||
| 3464 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 3465 | try stream.writeAll("{\n"); | ||
| 3466 | self.indent += 2; | ||
| 3467 | try self.writeBody(stream, body); | ||
| 3468 | self.indent -= 2; | ||
| 3469 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3470 | try stream.writeAll("}) "); | ||
| 3471 | } | ||
| 3472 | |||
| 3473 | fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 3474 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3475 | const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index); | ||
| 3476 | const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len]; | ||
| 3477 | const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | ||
| 3478 | try self.writeInstRef(stream, extra.data.condition); | ||
| 3479 | try stream.writeAll(", {\n"); | ||
| 3480 | self.indent += 2; | ||
| 3481 | try self.writeBody(stream, then_body); | ||
| 3482 | self.indent -= 2; | ||
| 3483 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3484 | try stream.writeAll("}, {\n"); | ||
| 3485 | self.indent += 2; | ||
| 3486 | try self.writeBody(stream, else_body); | ||
| 3487 | self.indent -= 2; | ||
| 3488 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3489 | try stream.writeAll("}) "); | ||
| 3490 | try self.writeSrc(stream, inst_data.src()); | ||
| 3491 | } | ||
| 3492 | |||
| 3493 | fn writeStructDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3494 | const small = @bitCast(Inst.StructDecl.Small, extended.small); | ||
| 3495 | |||
| 3496 | var extra_index: usize = extended.operand; | ||
| 3497 | |||
| 3498 | const src_node: ?i32 = if (small.has_src_node) blk: { | ||
| 3499 | const src_node = @bitCast(i32, self.code.extra[extra_index]); | ||
| 3500 | extra_index += 1; | ||
| 3501 | break :blk src_node; | ||
| 3502 | } else null; | ||
| 3503 | |||
| 3504 | const body_len = if (small.has_body_len) blk: { | ||
| 3505 | const body_len = self.code.extra[extra_index]; | ||
| 3506 | extra_index += 1; | ||
| 3507 | break :blk body_len; | ||
| 3508 | } else 0; | ||
| 3509 | |||
| 3510 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3511 | const fields_len = self.code.extra[extra_index]; | ||
| 3512 | extra_index += 1; | ||
| 3513 | break :blk fields_len; | ||
| 3514 | } else 0; | ||
| 3515 | |||
| 3516 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3517 | const decls_len = self.code.extra[extra_index]; | ||
| 3518 | extra_index += 1; | ||
| 3519 | break :blk decls_len; | ||
| 3520 | } else 0; | ||
| 3521 | |||
| 3522 | try stream.print("{s}, {s}, ", .{ | ||
| 3523 | @tagName(small.name_strategy), @tagName(small.layout), | ||
| 3524 | }); | ||
| 3525 | |||
| 3526 | if (decls_len == 0) { | ||
| 3527 | try stream.writeAll("{}, "); | ||
| 3528 | } else { | ||
| 3529 | try stream.writeAll("{\n"); | ||
| 3530 | self.indent += 2; | ||
| 3531 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | ||
| 3532 | self.indent -= 2; | ||
| 3533 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3534 | try stream.writeAll("}, "); | ||
| 3535 | } | ||
| 3536 | |||
| 3537 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 3538 | extra_index += body.len; | ||
| 3539 | |||
| 3540 | if (fields_len == 0) { | ||
| 3541 | assert(body.len == 0); | ||
| 3542 | try stream.writeAll("{}, {})"); | ||
| 3543 | } else { | ||
| 3544 | self.indent += 2; | ||
| 3545 | if (body.len == 0) { | ||
| 3546 | try stream.writeAll("{}, {\n"); | ||
| 3547 | } else { | ||
| 3548 | try stream.writeAll("{\n"); | ||
| 3549 | try self.writeBody(stream, body); | ||
| 3550 | |||
| 3551 | try stream.writeByteNTimes(' ', self.indent - 2); | ||
| 3552 | try stream.writeAll("}, {\n"); | ||
| 3553 | } | ||
| 3554 | |||
| 3555 | const bits_per_field = 4; | ||
| 3556 | const fields_per_u32 = 32 / bits_per_field; | ||
| 3557 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | ||
| 3558 | var bit_bag_index: usize = extra_index; | ||
| 3559 | extra_index += bit_bags_count; | ||
| 3560 | var cur_bit_bag: u32 = undefined; | ||
| 3561 | var field_i: u32 = 0; | ||
| 3562 | while (field_i < fields_len) : (field_i += 1) { | ||
| 3563 | if (field_i % fields_per_u32 == 0) { | ||
| 3564 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 3565 | bit_bag_index += 1; | ||
| 3566 | } | ||
| 3567 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 3568 | cur_bit_bag >>= 1; | ||
| 3569 | const has_default = @truncate(u1, cur_bit_bag) != 0; | ||
| 3570 | cur_bit_bag >>= 1; | ||
| 3571 | const is_comptime = @truncate(u1, cur_bit_bag) != 0; | ||
| 3572 | cur_bit_bag >>= 1; | ||
| 3573 | const unused = @truncate(u1, cur_bit_bag) != 0; | ||
| 3574 | cur_bit_bag >>= 1; | ||
| 3575 | |||
| 3576 | _ = unused; | ||
| 3577 | |||
| 3578 | const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 3579 | extra_index += 1; | ||
| 3580 | const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3581 | extra_index += 1; | ||
| 3582 | |||
| 3583 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3584 | try self.writeFlag(stream, "comptime ", is_comptime); | ||
| 3585 | try stream.print("{}: ", .{std.zig.fmtId(field_name)}); | ||
| 3586 | try self.writeInstRef(stream, field_type); | ||
| 3587 | |||
| 3588 | if (has_align) { | ||
| 3589 | const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3590 | extra_index += 1; | ||
| 3591 | |||
| 3592 | try stream.writeAll(" align("); | ||
| 3593 | try self.writeInstRef(stream, align_ref); | ||
| 3594 | try stream.writeAll(")"); | ||
| 3595 | } | ||
| 3596 | if (has_default) { | ||
| 3597 | const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3598 | extra_index += 1; | ||
| 3599 | |||
| 3600 | try stream.writeAll(" = "); | ||
| 3601 | try self.writeInstRef(stream, default_ref); | ||
| 3602 | } | ||
| 3603 | try stream.writeAll(",\n"); | ||
| 3604 | } | ||
| 3605 | |||
| 3606 | self.indent -= 2; | ||
| 3607 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3608 | try stream.writeAll("})"); | ||
| 3609 | } | ||
| 3610 | try self.writeSrcNode(stream, src_node); | ||
| 3611 | } | ||
| 3612 | |||
| 3613 | fn writeUnionDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3614 | const small = @bitCast(Inst.UnionDecl.Small, extended.small); | ||
| 3615 | |||
| 3616 | var extra_index: usize = extended.operand; | ||
| 3617 | |||
| 3618 | const src_node: ?i32 = if (small.has_src_node) blk: { | ||
| 3619 | const src_node = @bitCast(i32, self.code.extra[extra_index]); | ||
| 3620 | extra_index += 1; | ||
| 3621 | break :blk src_node; | ||
| 3622 | } else null; | ||
| 3623 | |||
| 3624 | const tag_type_ref = if (small.has_tag_type) blk: { | ||
| 3625 | const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 3626 | extra_index += 1; | ||
| 3627 | break :blk tag_type_ref; | ||
| 3628 | } else .none; | ||
| 3629 | |||
| 3630 | const body_len = if (small.has_body_len) blk: { | ||
| 3631 | const body_len = self.code.extra[extra_index]; | ||
| 3632 | extra_index += 1; | ||
| 3633 | break :blk body_len; | ||
| 3634 | } else 0; | ||
| 3635 | |||
| 3636 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3637 | const fields_len = self.code.extra[extra_index]; | ||
| 3638 | extra_index += 1; | ||
| 3639 | break :blk fields_len; | ||
| 3640 | } else 0; | ||
| 3641 | |||
| 3642 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3643 | const decls_len = self.code.extra[extra_index]; | ||
| 3644 | extra_index += 1; | ||
| 3645 | break :blk decls_len; | ||
| 3646 | } else 0; | ||
| 3647 | |||
| 3648 | try stream.print("{s}, {s}, ", .{ | ||
| 3649 | @tagName(small.name_strategy), @tagName(small.layout), | ||
| 3650 | }); | ||
| 3651 | try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag); | ||
| 3652 | |||
| 3653 | if (decls_len == 0) { | ||
| 3654 | try stream.writeAll("{}, "); | ||
| 3655 | } else { | ||
| 3656 | try stream.writeAll("{\n"); | ||
| 3657 | self.indent += 2; | ||
| 3658 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | ||
| 3659 | self.indent -= 2; | ||
| 3660 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3661 | try stream.writeAll("}, "); | ||
| 3662 | } | ||
| 3663 | |||
| 3664 | assert(fields_len != 0); | ||
| 3665 | |||
| 3666 | if (tag_type_ref != .none) { | ||
| 3667 | try self.writeInstRef(stream, tag_type_ref); | ||
| 3668 | try stream.writeAll(", "); | ||
| 3669 | } | ||
| 3670 | |||
| 3671 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 3672 | extra_index += body.len; | ||
| 3673 | |||
| 3674 | self.indent += 2; | ||
| 3675 | if (body.len == 0) { | ||
| 3676 | try stream.writeAll("{}, {\n"); | ||
| 3677 | } else { | ||
| 3678 | try stream.writeAll("{\n"); | ||
| 3679 | try self.writeBody(stream, body); | ||
| 3680 | |||
| 3681 | try stream.writeByteNTimes(' ', self.indent - 2); | ||
| 3682 | try stream.writeAll("}, {\n"); | ||
| 3683 | } | ||
| 3684 | |||
| 3685 | const bits_per_field = 4; | ||
| 3686 | const fields_per_u32 = 32 / bits_per_field; | ||
| 3687 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | ||
| 3688 | const body_end = extra_index; | ||
| 3689 | extra_index += bit_bags_count; | ||
| 3690 | var bit_bag_index: usize = body_end; | ||
| 3691 | var cur_bit_bag: u32 = undefined; | ||
| 3692 | var field_i: u32 = 0; | ||
| 3693 | while (field_i < fields_len) : (field_i += 1) { | ||
| 3694 | if (field_i % fields_per_u32 == 0) { | ||
| 3695 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 3696 | bit_bag_index += 1; | ||
| 3697 | } | ||
| 3698 | const has_type = @truncate(u1, cur_bit_bag) != 0; | ||
| 3699 | cur_bit_bag >>= 1; | ||
| 3700 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 3701 | cur_bit_bag >>= 1; | ||
| 3702 | const has_value = @truncate(u1, cur_bit_bag) != 0; | ||
| 3703 | cur_bit_bag >>= 1; | ||
| 3704 | const unused = @truncate(u1, cur_bit_bag) != 0; | ||
| 3705 | cur_bit_bag >>= 1; | ||
| 3706 | |||
| 3707 | _ = unused; | ||
| 3708 | |||
| 3709 | const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 3710 | extra_index += 1; | ||
| 3711 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3712 | try stream.print("{}", .{std.zig.fmtId(field_name)}); | ||
| 3713 | |||
| 3714 | if (has_type) { | ||
| 3715 | const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3716 | extra_index += 1; | ||
| 3717 | |||
| 3718 | try stream.writeAll(": "); | ||
| 3719 | try self.writeInstRef(stream, field_type); | ||
| 3720 | } | ||
| 3721 | if (has_align) { | ||
| 3722 | const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3723 | extra_index += 1; | ||
| 3724 | |||
| 3725 | try stream.writeAll(" align("); | ||
| 3726 | try self.writeInstRef(stream, align_ref); | ||
| 3727 | try stream.writeAll(")"); | ||
| 3728 | } | ||
| 3729 | if (has_value) { | ||
| 3730 | const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3731 | extra_index += 1; | ||
| 3732 | |||
| 3733 | try stream.writeAll(" = "); | ||
| 3734 | try self.writeInstRef(stream, default_ref); | ||
| 3735 | } | ||
| 3736 | try stream.writeAll(",\n"); | ||
| 3737 | } | ||
| 3738 | |||
| 3739 | self.indent -= 2; | ||
| 3740 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3741 | try stream.writeAll("})"); | ||
| 3742 | try self.writeSrcNode(stream, src_node); | ||
| 3743 | } | ||
| 3744 | |||
| 3745 | fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize { | ||
| 3746 | const parent_decl_node = self.parent_decl_node; | ||
| 3747 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; | ||
| 3748 | var extra_index = extra_start + bit_bags_count; | ||
| 3749 | var bit_bag_index: usize = extra_start; | ||
| 3750 | var cur_bit_bag: u32 = undefined; | ||
| 3751 | var decl_i: u32 = 0; | ||
| 3752 | while (decl_i < decls_len) : (decl_i += 1) { | ||
| 3753 | if (decl_i % 8 == 0) { | ||
| 3754 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 3755 | bit_bag_index += 1; | ||
| 3756 | } | ||
| 3757 | const is_pub = @truncate(u1, cur_bit_bag) != 0; | ||
| 3758 | cur_bit_bag >>= 1; | ||
| 3759 | const is_exported = @truncate(u1, cur_bit_bag) != 0; | ||
| 3760 | cur_bit_bag >>= 1; | ||
| 3761 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 3762 | cur_bit_bag >>= 1; | ||
| 3763 | const has_section = @truncate(u1, cur_bit_bag) != 0; | ||
| 3764 | cur_bit_bag >>= 1; | ||
| 3765 | |||
| 3766 | const sub_index = extra_index; | ||
| 3767 | |||
| 3768 | const hash_u32s = self.code.extra[extra_index..][0..4]; | ||
| 3769 | extra_index += 4; | ||
| 3770 | const line = self.code.extra[extra_index]; | ||
| 3771 | extra_index += 1; | ||
| 3772 | const decl_name_index = self.code.extra[extra_index]; | ||
| 3773 | extra_index += 1; | ||
| 3774 | const decl_index = self.code.extra[extra_index]; | ||
| 3775 | extra_index += 1; | ||
| 3776 | const align_inst: Inst.Ref = if (!has_align) .none else inst: { | ||
| 3777 | const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3778 | extra_index += 1; | ||
| 3779 | break :inst inst; | ||
| 3780 | }; | ||
| 3781 | const section_inst: Inst.Ref = if (!has_section) .none else inst: { | ||
| 3782 | const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3783 | extra_index += 1; | ||
| 3784 | break :inst inst; | ||
| 3785 | }; | ||
| 3786 | |||
| 3787 | const pub_str = if (is_pub) "pub " else ""; | ||
| 3788 | const hash_bytes = @bitCast([16]u8, hash_u32s.*); | ||
| 3789 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3790 | if (decl_name_index == 0) { | ||
| 3791 | const name = if (is_exported) "usingnamespace" else "comptime"; | ||
| 3792 | try stream.writeAll(pub_str); | ||
| 3793 | try stream.writeAll(name); | ||
| 3794 | } else if (decl_name_index == 1) { | ||
| 3795 | try stream.writeAll("test"); | ||
| 3796 | } else { | ||
| 3797 | const raw_decl_name = self.code.nullTerminatedString(decl_name_index); | ||
| 3798 | const decl_name = if (raw_decl_name.len == 0) | ||
| 3799 | self.code.nullTerminatedString(decl_name_index + 1) | ||
| 3800 | else | ||
| 3801 | raw_decl_name; | ||
| 3802 | const test_str = if (raw_decl_name.len == 0) "test " else ""; | ||
| 3803 | const export_str = if (is_exported) "export " else ""; | ||
| 3804 | try stream.print("[{d}] {s}{s}{s}{}", .{ | ||
| 3805 | sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), | ||
| 3806 | }); | ||
| 3807 | if (align_inst != .none) { | ||
| 3808 | try stream.writeAll(" align("); | ||
| 3809 | try self.writeInstRef(stream, align_inst); | ||
| 3810 | try stream.writeAll(")"); | ||
| 3811 | } | ||
| 3812 | if (section_inst != .none) { | ||
| 3813 | try stream.writeAll(" linksection("); | ||
| 3814 | try self.writeInstRef(stream, section_inst); | ||
| 3815 | try stream.writeAll(")"); | ||
| 3816 | } | ||
| 3817 | } | ||
| 3818 | const tag = self.code.instructions.items(.tag)[decl_index]; | ||
| 3819 | try stream.print(" line({d}) hash({}): %{d} = {s}(", .{ | ||
| 3820 | line, std.fmt.fmtSliceHexLower(&hash_bytes), decl_index, @tagName(tag), | ||
| 3821 | }); | ||
| 3822 | |||
| 3823 | const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node; | ||
| 3824 | const sub_decl_node_off = decl_block_inst_data.src_node; | ||
| 3825 | self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off); | ||
| 3826 | try self.writePlNodeBlockWithoutSrc(stream, decl_index); | ||
| 3827 | self.parent_decl_node = parent_decl_node; | ||
| 3828 | try self.writeSrc(stream, decl_block_inst_data.src()); | ||
| 3829 | try stream.writeAll("\n"); | ||
| 3830 | } | ||
| 3831 | return extra_index; | ||
| 3832 | } | ||
| 3833 | |||
| 3834 | fn writeEnumDecl(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 3835 | const small = @bitCast(Inst.EnumDecl.Small, extended.small); | ||
| 3836 | var extra_index: usize = extended.operand; | ||
| 3837 | |||
| 3838 | const src_node: ?i32 = if (small.has_src_node) blk: { | ||
| 3839 | const src_node = @bitCast(i32, self.code.extra[extra_index]); | ||
| 3840 | extra_index += 1; | ||
| 3841 | break :blk src_node; | ||
| 3842 | } else null; | ||
| 3843 | |||
| 3844 | const tag_type_ref = if (small.has_tag_type) blk: { | ||
| 3845 | const tag_type_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 3846 | extra_index += 1; | ||
| 3847 | break :blk tag_type_ref; | ||
| 3848 | } else .none; | ||
| 3849 | |||
| 3850 | const body_len = if (small.has_body_len) blk: { | ||
| 3851 | const body_len = self.code.extra[extra_index]; | ||
| 3852 | extra_index += 1; | ||
| 3853 | break :blk body_len; | ||
| 3854 | } else 0; | ||
| 3855 | |||
| 3856 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3857 | const fields_len = self.code.extra[extra_index]; | ||
| 3858 | extra_index += 1; | ||
| 3859 | break :blk fields_len; | ||
| 3860 | } else 0; | ||
| 3861 | |||
| 3862 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3863 | const decls_len = self.code.extra[extra_index]; | ||
| 3864 | extra_index += 1; | ||
| 3865 | break :blk decls_len; | ||
| 3866 | } else 0; | ||
| 3867 | |||
| 3868 | try stream.print("{s}, ", .{@tagName(small.name_strategy)}); | ||
| 3869 | try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive); | ||
| 3870 | |||
| 3871 | if (decls_len == 0) { | ||
| 3872 | try stream.writeAll("{}, "); | ||
| 3873 | } else { | ||
| 3874 | try stream.writeAll("{\n"); | ||
| 3875 | self.indent += 2; | ||
| 3876 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | ||
| 3877 | self.indent -= 2; | ||
| 3878 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3879 | try stream.writeAll("}, "); | ||
| 3880 | } | ||
| 3881 | |||
| 3882 | if (tag_type_ref != .none) { | ||
| 3883 | try self.writeInstRef(stream, tag_type_ref); | ||
| 3884 | try stream.writeAll(", "); | ||
| 3885 | } | ||
| 3886 | |||
| 3887 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 3888 | extra_index += body.len; | ||
| 3889 | |||
| 3890 | if (fields_len == 0) { | ||
| 3891 | assert(body.len == 0); | ||
| 3892 | try stream.writeAll("{}, {})"); | ||
| 3893 | } else { | ||
| 3894 | self.indent += 2; | ||
| 3895 | if (body.len == 0) { | ||
| 3896 | try stream.writeAll("{}, {\n"); | ||
| 3897 | } else { | ||
| 3898 | try stream.writeAll("{\n"); | ||
| 3899 | try self.writeBody(stream, body); | ||
| 3900 | |||
| 3901 | try stream.writeByteNTimes(' ', self.indent - 2); | ||
| 3902 | try stream.writeAll("}, {\n"); | ||
| 3903 | } | ||
| 3904 | |||
| 3905 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 3906 | const body_end = extra_index; | ||
| 3907 | extra_index += bit_bags_count; | ||
| 3908 | var bit_bag_index: usize = body_end; | ||
| 3909 | var cur_bit_bag: u32 = undefined; | ||
| 3910 | var field_i: u32 = 0; | ||
| 3911 | while (field_i < fields_len) : (field_i += 1) { | ||
| 3912 | if (field_i % 32 == 0) { | ||
| 3913 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 3914 | bit_bag_index += 1; | ||
| 3915 | } | ||
| 3916 | const has_tag_value = @truncate(u1, cur_bit_bag) != 0; | ||
| 3917 | cur_bit_bag >>= 1; | ||
| 3918 | |||
| 3919 | const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 3920 | extra_index += 1; | ||
| 3921 | |||
| 3922 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3923 | try stream.print("{}", .{std.zig.fmtId(field_name)}); | ||
| 3924 | |||
| 3925 | if (has_tag_value) { | ||
| 3926 | const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 3927 | extra_index += 1; | ||
| 3928 | |||
| 3929 | try stream.writeAll(" = "); | ||
| 3930 | try self.writeInstRef(stream, tag_value_ref); | ||
| 3931 | } | ||
| 3932 | try stream.writeAll(",\n"); | ||
| 3933 | } | ||
| 3934 | self.indent -= 2; | ||
| 3935 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3936 | try stream.writeAll("})"); | ||
| 3937 | } | ||
| 3938 | try self.writeSrcNode(stream, src_node); | ||
| 3939 | } | ||
| 3940 | |||
| 3941 | fn writeOpaqueDecl( | ||
| 3942 | self: *Writer, | ||
| 3943 | stream: anytype, | ||
| 3944 | inst: Inst.Index, | ||
| 3945 | name_strategy: Inst.NameStrategy, | ||
| 3946 | ) !void { | ||
| 3947 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3948 | const extra = self.code.extraData(Inst.OpaqueDecl, inst_data.payload_index); | ||
| 3949 | const decls_len = extra.data.decls_len; | ||
| 3950 | |||
| 3951 | try stream.print("{s}, ", .{@tagName(name_strategy)}); | ||
| 3952 | |||
| 3953 | if (decls_len == 0) { | ||
| 3954 | try stream.writeAll("}) "); | ||
| 3955 | } else { | ||
| 3956 | try stream.writeAll("\n"); | ||
| 3957 | self.indent += 2; | ||
| 3958 | _ = try self.writeDecls(stream, decls_len, extra.end); | ||
| 3959 | self.indent -= 2; | ||
| 3960 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3961 | try stream.writeAll("}) "); | ||
| 3962 | } | ||
| 3963 | try self.writeSrc(stream, inst_data.src()); | ||
| 3964 | } | ||
| 3965 | |||
| 3966 | fn writeErrorSetDecl( | ||
| 3967 | self: *Writer, | ||
| 3968 | stream: anytype, | ||
| 3969 | inst: Inst.Index, | ||
| 3970 | name_strategy: Inst.NameStrategy, | ||
| 3971 | ) !void { | ||
| 3972 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3973 | const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index); | ||
| 3974 | const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; | ||
| 3975 | |||
| 3976 | try stream.print("{s}, ", .{@tagName(name_strategy)}); | ||
| 3977 | |||
| 3978 | try stream.writeAll("{\n"); | ||
| 3979 | self.indent += 2; | ||
| 3980 | for (fields) |str_index| { | ||
| 3981 | const name = self.code.nullTerminatedString(str_index); | ||
| 3982 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3983 | try stream.print("{},\n", .{std.zig.fmtId(name)}); | ||
| 3984 | } | ||
| 3985 | self.indent -= 2; | ||
| 3986 | try stream.writeByteNTimes(' ', self.indent); | ||
| 3987 | try stream.writeAll("}) "); | ||
| 3988 | |||
| 3989 | try self.writeSrc(stream, inst_data.src()); | ||
| 3990 | } | ||
| 3991 | |||
| 3992 | fn writePlNodeSwitchBr( | ||
| 3993 | self: *Writer, | ||
| 3994 | stream: anytype, | ||
| 3995 | inst: Inst.Index, | ||
| 3996 | special_prong: SpecialProng, | ||
| 3997 | ) !void { | ||
| 3998 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 3999 | const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index); | ||
| 4000 | const special: struct { | ||
| 4001 | body: []const Inst.Index, | ||
| 4002 | end: usize, | ||
| 4003 | } = switch (special_prong) { | ||
| 4004 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 4005 | .under, .@"else" => blk: { | ||
| 4006 | const body_len = self.code.extra[extra.end]; | ||
| 4007 | const extra_body_start = extra.end + 1; | ||
| 4008 | break :blk .{ | ||
| 4009 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 4010 | .end = extra_body_start + body_len, | ||
| 4011 | }; | ||
| 4012 | }, | ||
| 4013 | }; | ||
| 4014 | |||
| 4015 | try self.writeInstRef(stream, extra.data.operand); | ||
| 4016 | |||
| 4017 | if (special.body.len != 0) { | ||
| 4018 | const prong_name = switch (special_prong) { | ||
| 4019 | .@"else" => "else", | ||
| 4020 | .under => "_", | ||
| 4021 | else => unreachable, | ||
| 4022 | }; | ||
| 4023 | try stream.print(", {s} => {{\n", .{prong_name}); | ||
| 4024 | self.indent += 2; | ||
| 4025 | try self.writeBody(stream, special.body); | ||
| 4026 | self.indent -= 2; | ||
| 4027 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4028 | try stream.writeAll("}"); | ||
| 4029 | } | ||
| 4030 | |||
| 4031 | var extra_index: usize = special.end; | ||
| 4032 | { | ||
| 4033 | var scalar_i: usize = 0; | ||
| 4034 | while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { | ||
| 4035 | const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 4036 | extra_index += 1; | ||
| 4037 | const body_len = self.code.extra[extra_index]; | ||
| 4038 | extra_index += 1; | ||
| 4039 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 4040 | extra_index += body_len; | ||
| 4041 | |||
| 4042 | try stream.writeAll(", "); | ||
| 4043 | try self.writeInstRef(stream, item_ref); | ||
| 4044 | try stream.writeAll(" => {\n"); | ||
| 4045 | self.indent += 2; | ||
| 4046 | try self.writeBody(stream, body); | ||
| 4047 | self.indent -= 2; | ||
| 4048 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4049 | try stream.writeAll("}"); | ||
| 4050 | } | ||
| 4051 | } | ||
| 4052 | try stream.writeAll(") "); | ||
| 4053 | try self.writeSrc(stream, inst_data.src()); | ||
| 4054 | } | ||
| 4055 | |||
| 4056 | fn writePlNodeSwitchBlockMulti( | ||
| 4057 | self: *Writer, | ||
| 4058 | stream: anytype, | ||
| 4059 | inst: Inst.Index, | ||
| 4060 | special_prong: SpecialProng, | ||
| 4061 | ) !void { | ||
| 4062 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 4063 | const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index); | ||
| 4064 | const special: struct { | ||
| 4065 | body: []const Inst.Index, | ||
| 4066 | end: usize, | ||
| 4067 | } = switch (special_prong) { | ||
| 4068 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 4069 | .under, .@"else" => blk: { | ||
| 4070 | const body_len = self.code.extra[extra.end]; | ||
| 4071 | const extra_body_start = extra.end + 1; | ||
| 4072 | break :blk .{ | ||
| 4073 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 4074 | .end = extra_body_start + body_len, | ||
| 4075 | }; | ||
| 4076 | }, | ||
| 4077 | }; | ||
| 4078 | |||
| 4079 | try self.writeInstRef(stream, extra.data.operand); | ||
| 4080 | |||
| 4081 | if (special.body.len != 0) { | ||
| 4082 | const prong_name = switch (special_prong) { | ||
| 4083 | .@"else" => "else", | ||
| 4084 | .under => "_", | ||
| 4085 | else => unreachable, | ||
| 4086 | }; | ||
| 4087 | try stream.print(", {s} => {{\n", .{prong_name}); | ||
| 4088 | self.indent += 2; | ||
| 4089 | try self.writeBody(stream, special.body); | ||
| 4090 | self.indent -= 2; | ||
| 4091 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4092 | try stream.writeAll("}"); | ||
| 4093 | } | ||
| 4094 | |||
| 4095 | var extra_index: usize = special.end; | ||
| 4096 | { | ||
| 4097 | var scalar_i: usize = 0; | ||
| 4098 | while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { | ||
| 4099 | const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 4100 | extra_index += 1; | ||
| 4101 | const body_len = self.code.extra[extra_index]; | ||
| 4102 | extra_index += 1; | ||
| 4103 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 4104 | extra_index += body_len; | ||
| 4105 | |||
| 4106 | try stream.writeAll(", "); | ||
| 4107 | try self.writeInstRef(stream, item_ref); | ||
| 4108 | try stream.writeAll(" => {\n"); | ||
| 4109 | self.indent += 2; | ||
| 4110 | try self.writeBody(stream, body); | ||
| 4111 | self.indent -= 2; | ||
| 4112 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4113 | try stream.writeAll("}"); | ||
| 4114 | } | ||
| 4115 | } | ||
| 4116 | { | ||
| 4117 | var multi_i: usize = 0; | ||
| 4118 | while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { | ||
| 4119 | const items_len = self.code.extra[extra_index]; | ||
| 4120 | extra_index += 1; | ||
| 4121 | const ranges_len = self.code.extra[extra_index]; | ||
| 4122 | extra_index += 1; | ||
| 4123 | const body_len = self.code.extra[extra_index]; | ||
| 4124 | extra_index += 1; | ||
| 4125 | const items = self.code.refSlice(extra_index, items_len); | ||
| 4126 | extra_index += items_len; | ||
| 4127 | |||
| 4128 | for (items) |item_ref| { | ||
| 4129 | try stream.writeAll(", "); | ||
| 4130 | try self.writeInstRef(stream, item_ref); | ||
| 4131 | } | ||
| 4132 | |||
| 4133 | var range_i: usize = 0; | ||
| 4134 | while (range_i < ranges_len) : (range_i += 1) { | ||
| 4135 | const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 4136 | extra_index += 1; | ||
| 4137 | const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 4138 | extra_index += 1; | ||
| 4139 | |||
| 4140 | try stream.writeAll(", "); | ||
| 4141 | try self.writeInstRef(stream, item_first); | ||
| 4142 | try stream.writeAll("..."); | ||
| 4143 | try self.writeInstRef(stream, item_last); | ||
| 4144 | } | ||
| 4145 | |||
| 4146 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 4147 | extra_index += body_len; | ||
| 4148 | try stream.writeAll(" => {\n"); | ||
| 4149 | self.indent += 2; | ||
| 4150 | try self.writeBody(stream, body); | ||
| 4151 | self.indent -= 2; | ||
| 4152 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4153 | try stream.writeAll("}"); | ||
| 4154 | } | ||
| 4155 | } | ||
| 4156 | try stream.writeAll(") "); | ||
| 4157 | try self.writeSrc(stream, inst_data.src()); | ||
| 4158 | } | ||
| 4159 | |||
| 4160 | fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4161 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 4162 | const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data; | ||
| 4163 | const name = self.code.nullTerminatedString(extra.field_name_start); | ||
| 4164 | try self.writeInstRef(stream, extra.lhs); | ||
| 4165 | try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); | ||
| 4166 | try self.writeSrc(stream, inst_data.src()); | ||
| 4167 | } | ||
| 4168 | |||
| 4169 | fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4170 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 4171 | const extra = self.code.extraData(Inst.As, inst_data.payload_index).data; | ||
| 4172 | try self.writeInstRef(stream, extra.dest_type); | ||
| 4173 | try stream.writeAll(", "); | ||
| 4174 | try self.writeInstRef(stream, extra.operand); | ||
| 4175 | try stream.writeAll(") "); | ||
| 4176 | try self.writeSrc(stream, inst_data.src()); | ||
| 4177 | } | ||
| 4178 | |||
| 4179 | fn writeNode( | ||
| 4180 | self: *Writer, | ||
| 4181 | stream: anytype, | ||
| 4182 | inst: Inst.Index, | ||
| 4183 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 4184 | const src_node = self.code.instructions.items(.data)[inst].node; | ||
| 4185 | const src: LazySrcLoc = .{ .node_offset = src_node }; | ||
| 4186 | try stream.writeAll(") "); | ||
| 4187 | try self.writeSrc(stream, src); | ||
| 4188 | } | ||
| 4189 | |||
| 4190 | fn writeStrTok( | ||
| 4191 | self: *Writer, | ||
| 4192 | stream: anytype, | ||
| 4193 | inst: Inst.Index, | ||
| 4194 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 4195 | const inst_data = self.code.instructions.items(.data)[inst].str_tok; | ||
| 4196 | const str = inst_data.get(self.code); | ||
| 4197 | try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); | ||
| 4198 | try self.writeSrc(stream, inst_data.src()); | ||
| 4199 | } | ||
| 4200 | |||
| 4201 | fn writeFunc( | ||
| 4202 | self: *Writer, | ||
| 4203 | stream: anytype, | ||
| 4204 | inst: Inst.Index, | ||
| 4205 | inferred_error_set: bool, | ||
| 4206 | ) !void { | ||
| 4207 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 4208 | const src = inst_data.src(); | ||
| 4209 | const extra = self.code.extraData(Inst.Func, inst_data.payload_index); | ||
| 4210 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | ||
| 4211 | const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len]; | ||
| 4212 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; | ||
| 4213 | if (body.len != 0) { | ||
| 4214 | const extra_index = extra.end + param_types.len + body.len; | ||
| 4215 | src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; | ||
| 4216 | } | ||
| 4217 | return self.writeFuncCommon( | ||
| 4218 | stream, | ||
| 4219 | param_types, | ||
| 4220 | extra.data.return_type, | ||
| 4221 | inferred_error_set, | ||
| 4222 | false, | ||
| 4223 | false, | ||
| 4224 | .none, | ||
| 4225 | .none, | ||
| 4226 | body, | ||
| 4227 | src, | ||
| 4228 | src_locs, | ||
| 4229 | ); | ||
| 4230 | } | ||
| 4231 | |||
| 4232 | fn writeFuncExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 4233 | const extra = self.code.extraData(Inst.ExtendedFunc, extended.operand); | ||
| 4234 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; | ||
| 4235 | const small = @bitCast(Inst.ExtendedFunc.Small, extended.small); | ||
| 4236 | |||
| 4237 | var extra_index: usize = extra.end; | ||
| 4238 | if (small.has_lib_name) { | ||
| 4239 | const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 4240 | extra_index += 1; | ||
| 4241 | try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)}); | ||
| 4242 | } | ||
| 4243 | try self.writeFlag(stream, "test, ", small.is_test); | ||
| 4244 | const cc: Inst.Ref = if (!small.has_cc) .none else blk: { | ||
| 4245 | const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 4246 | extra_index += 1; | ||
| 4247 | break :blk cc; | ||
| 4248 | }; | ||
| 4249 | const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { | ||
| 4250 | const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 4251 | extra_index += 1; | ||
| 4252 | break :blk align_inst; | ||
| 4253 | }; | ||
| 4254 | |||
| 4255 | const param_types = self.code.refSlice(extra_index, extra.data.param_types_len); | ||
| 4256 | extra_index += param_types.len; | ||
| 4257 | |||
| 4258 | const body = self.code.extra[extra_index..][0..extra.data.body_len]; | ||
| 4259 | extra_index += body.len; | ||
| 4260 | |||
| 4261 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; | ||
| 4262 | if (body.len != 0) { | ||
| 4263 | src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; | ||
| 4264 | } | ||
| 4265 | return self.writeFuncCommon( | ||
| 4266 | stream, | ||
| 4267 | param_types, | ||
| 4268 | extra.data.return_type, | ||
| 4269 | small.is_inferred_error, | ||
| 4270 | small.is_var_args, | ||
| 4271 | small.is_extern, | ||
| 4272 | cc, | ||
| 4273 | align_inst, | ||
| 4274 | body, | ||
| 4275 | src, | ||
| 4276 | src_locs, | ||
| 4277 | ); | ||
| 4278 | } | ||
| 4279 | |||
| 4280 | fn writeVarExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { | ||
| 4281 | const extra = self.code.extraData(Inst.ExtendedVar, extended.operand); | ||
| 4282 | const small = @bitCast(Inst.ExtendedVar.Small, extended.small); | ||
| 4283 | |||
| 4284 | try self.writeInstRef(stream, extra.data.var_type); | ||
| 4285 | |||
| 4286 | var extra_index: usize = extra.end; | ||
| 4287 | if (small.has_lib_name) { | ||
| 4288 | const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 4289 | extra_index += 1; | ||
| 4290 | try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)}); | ||
| 4291 | } | ||
| 4292 | const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { | ||
| 4293 | const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 4294 | extra_index += 1; | ||
| 4295 | break :blk align_inst; | ||
| 4296 | }; | ||
| 4297 | const init_inst: Inst.Ref = if (!small.has_init) .none else blk: { | ||
| 4298 | const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 4299 | extra_index += 1; | ||
| 4300 | break :blk init_inst; | ||
| 4301 | }; | ||
| 4302 | try self.writeFlag(stream, ", is_extern", small.is_extern); | ||
| 4303 | try self.writeOptionalInstRef(stream, ", align=", align_inst); | ||
| 4304 | try self.writeOptionalInstRef(stream, ", init=", init_inst); | ||
| 4305 | try stream.writeAll("))"); | ||
| 4306 | } | ||
| 4307 | |||
| 4308 | fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4309 | const inst_data = self.code.instructions.items(.data)[inst].bool_br; | ||
| 4310 | const extra = self.code.extraData(Inst.Block, inst_data.payload_index); | ||
| 4311 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 4312 | try self.writeInstRef(stream, inst_data.lhs); | ||
| 4313 | try stream.writeAll(", {\n"); | ||
| 4314 | self.indent += 2; | ||
| 4315 | try self.writeBody(stream, body); | ||
| 4316 | self.indent -= 2; | ||
| 4317 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4318 | try stream.writeAll("})"); | ||
| 4319 | } | ||
| 4320 | |||
| 4321 | fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4322 | const int_type = self.code.instructions.items(.data)[inst].int_type; | ||
| 4323 | const prefix: u8 = switch (int_type.signedness) { | ||
| 4324 | .signed => 'i', | ||
| 4325 | .unsigned => 'u', | ||
| 4326 | }; | ||
| 4327 | try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count }); | ||
| 4328 | try self.writeSrc(stream, int_type.src()); | ||
| 4329 | } | ||
| 4330 | |||
| 4331 | fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4332 | const inst_data = self.code.instructions.items(.data)[inst].@"break"; | ||
| 4333 | |||
| 4334 | try self.writeInstIndex(stream, inst_data.block_inst); | ||
| 4335 | try stream.writeAll(", "); | ||
| 4336 | try self.writeInstRef(stream, inst_data.operand); | ||
| 4337 | try stream.writeAll(")"); | ||
| 4338 | } | ||
| 4339 | |||
| 4340 | fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4341 | const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; | ||
| 4342 | const safety_str = if (inst_data.safety) "safe" else "unsafe"; | ||
| 4343 | try stream.print("{s}) ", .{safety_str}); | ||
| 4344 | try self.writeSrc(stream, inst_data.src()); | ||
| 4345 | } | ||
| 4346 | |||
| 4347 | fn writeFuncCommon( | ||
| 4348 | self: *Writer, | ||
| 4349 | stream: anytype, | ||
| 4350 | param_types: []const Inst.Ref, | ||
| 4351 | ret_ty: Inst.Ref, | ||
| 4352 | inferred_error_set: bool, | ||
| 4353 | var_args: bool, | ||
| 4354 | is_extern: bool, | ||
| 4355 | cc: Inst.Ref, | ||
| 4356 | align_inst: Inst.Ref, | ||
| 4357 | body: []const Inst.Index, | ||
| 4358 | src: LazySrcLoc, | ||
| 4359 | src_locs: Zir.Inst.Func.SrcLocs, | ||
| 4360 | ) !void { | ||
| 4361 | try stream.writeAll("["); | ||
| 4362 | for (param_types) |param_type, i| { | ||
| 4363 | if (i != 0) try stream.writeAll(", "); | ||
| 4364 | try self.writeInstRef(stream, param_type); | ||
| 4365 | } | ||
| 4366 | try stream.writeAll("], "); | ||
| 4367 | try self.writeInstRef(stream, ret_ty); | ||
| 4368 | try self.writeOptionalInstRef(stream, ", cc=", cc); | ||
| 4369 | try self.writeOptionalInstRef(stream, ", align=", align_inst); | ||
| 4370 | try self.writeFlag(stream, ", vargs", var_args); | ||
| 4371 | try self.writeFlag(stream, ", extern", is_extern); | ||
| 4372 | try self.writeFlag(stream, ", inferror", inferred_error_set); | ||
| 4373 | |||
| 4374 | if (body.len == 0) { | ||
| 4375 | try stream.writeAll(", {}) "); | ||
| 4376 | } else { | ||
| 4377 | try stream.writeAll(", {\n"); | ||
| 4378 | self.indent += 2; | ||
| 4379 | try self.writeBody(stream, body); | ||
| 4380 | self.indent -= 2; | ||
| 4381 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4382 | try stream.writeAll("}) "); | ||
| 4383 | } | ||
| 4384 | if (body.len != 0) { | ||
| 4385 | try stream.print("(lbrace={d}:{d},rbrace={d}:{d}) ", .{ | ||
| 4386 | src_locs.lbrace_line, @truncate(u16, src_locs.columns), | ||
| 4387 | src_locs.rbrace_line, @truncate(u16, src_locs.columns >> 16), | ||
| 4388 | }); | ||
| 4389 | } | ||
| 4390 | try self.writeSrc(stream, src); | ||
| 4391 | } | ||
| 4392 | |||
| 4393 | fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4394 | const inst_data = self.code.instructions.items(.data)[inst].switch_capture; | ||
| 4395 | try self.writeInstIndex(stream, inst_data.switch_inst); | ||
| 4396 | try stream.print(", {d})", .{inst_data.prong_index}); | ||
| 4397 | } | ||
| 4398 | |||
| 4399 | fn writeDbgStmt(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4400 | const inst_data = self.code.instructions.items(.data)[inst].dbg_stmt; | ||
| 4401 | try stream.print("{d}, {d})", .{ inst_data.line, inst_data.column }); | ||
| 4402 | } | ||
| 4403 | |||
| 4404 | fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void { | ||
| 4405 | var i: usize = @enumToInt(ref); | ||
| 4406 | |||
| 4407 | if (i < Inst.Ref.typed_value_map.len) { | ||
| 4408 | return stream.print("@{}", .{ref}); | ||
| 4409 | } | ||
| 4410 | i -= Inst.Ref.typed_value_map.len; | ||
| 4411 | |||
| 4412 | return self.writeInstIndex(stream, @intCast(Inst.Index, i)); | ||
| 4413 | } | ||
| 4414 | |||
| 4415 | fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 4416 | return stream.print("%{d}", .{inst}); | ||
| 4417 | } | ||
| 4418 | |||
| 4419 | fn writeOptionalInstRef( | ||
| 4420 | self: *Writer, | ||
| 4421 | stream: anytype, | ||
| 4422 | prefix: []const u8, | ||
| 4423 | inst: Inst.Ref, | ||
| 4424 | ) !void { | ||
| 4425 | if (inst == .none) return; | ||
| 4426 | try stream.writeAll(prefix); | ||
| 4427 | try self.writeInstRef(stream, inst); | ||
| 4428 | } | ||
| 4429 | |||
| 4430 | fn writeFlag( | ||
| 4431 | self: *Writer, | ||
| 4432 | stream: anytype, | ||
| 4433 | name: []const u8, | ||
| 4434 | flag: bool, | ||
| 4435 | ) !void { | ||
| 4436 | if (!flag) return; | ||
| 4437 | try stream.writeAll(name); | ||
| 4438 | } | ||
| 4439 | |||
| 4440 | fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { | ||
| 4441 | const tree = self.file.tree; | ||
| 4442 | const src_loc: Module.SrcLoc = .{ | ||
| 4443 | .file_scope = self.file, | ||
| 4444 | .parent_decl_node = self.parent_decl_node, | ||
| 4445 | .lazy = src, | ||
| 4446 | }; | ||
| 4447 | // Caller must ensure AST tree is loaded. | ||
| 4448 | const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable; | ||
| 4449 | const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); | ||
| 4450 | try stream.print("{s}:{d}:{d}", .{ | ||
| 4451 | @tagName(src), delta_line.line + 1, delta_line.column + 1, | ||
| 4452 | }); | ||
| 4453 | } | ||
| 4454 | |||
| 4455 | fn writeSrcNode(self: *Writer, stream: anytype, src_node: ?i32) !void { | ||
| 4456 | const node_offset = src_node orelse return; | ||
| 4457 | const src: LazySrcLoc = .{ .node_offset = node_offset }; | ||
| 4458 | try stream.writeAll(" "); | ||
| 4459 | return self.writeSrc(stream, src); | ||
| 4460 | } | ||
| 4461 | |||
| 4462 | fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void { | ||
| 4463 | for (body) |inst| { | ||
| 4464 | try stream.writeByteNTimes(' ', self.indent); | ||
| 4465 | try stream.print("%{d} ", .{inst}); | ||
| 4466 | try self.writeInstToStream(stream, inst); | ||
| 4467 | try stream.writeByte('\n'); | ||
| 4468 | } | ||
| 4469 | } | ||
| 4470 | }; | ||
| 4471 | |||
| 4472 | pub const DeclIterator = struct { | ||
| 4473 | extra_index: usize, | ||
| 4474 | bit_bag_index: usize, | ||
| 4475 | cur_bit_bag: u32, | ||
| 4476 | decl_i: u32, | ||
| 4477 | decls_len: u32, | ||
| 4478 | zir: Zir, | ||
| 4479 | |||
| 4480 | pub const Item = struct { | ||
| 4481 | name: [:0]const u8, | ||
| 4482 | sub_index: u32, | ||
| 4483 | }; | ||
| 4484 | |||
| 4485 | pub fn next(it: *DeclIterator) ?Item { | ||
| 4486 | if (it.decl_i >= it.decls_len) return null; | ||
| 4487 | |||
| 4488 | if (it.decl_i % 8 == 0) { | ||
| 4489 | it.cur_bit_bag = it.zir.extra[it.bit_bag_index]; | ||
| 4490 | it.bit_bag_index += 1; | ||
| 4491 | } | ||
| 4492 | it.decl_i += 1; | ||
| 4493 | |||
| 4494 | const flags = @truncate(u4, it.cur_bit_bag); | ||
| 4495 | it.cur_bit_bag >>= 4; | ||
| 4496 | |||
| 4497 | const sub_index = @intCast(u32, it.extra_index); | ||
| 4498 | it.extra_index += 5; // src_hash(4) + line(1) | ||
| 4499 | const name = it.zir.nullTerminatedString(it.zir.extra[it.extra_index]); | ||
| 4500 | it.extra_index += 2; // name(1) + value(1) | ||
| 4501 | it.extra_index += @truncate(u1, flags >> 2); | ||
| 4502 | it.extra_index += @truncate(u1, flags >> 3); | ||
| 4503 | |||
| 4504 | return Item{ | ||
| 4505 | .sub_index = sub_index, | ||
| 4506 | .name = name, | ||
| 4507 | }; | ||
| 4508 | } | ||
| 4509 | }; | ||
| 4510 | |||
| 4511 | pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator { | ||
| 4512 | const tags = zir.instructions.items(.tag); | ||
| 4513 | const datas = zir.instructions.items(.data); | ||
| 4514 | switch (tags[decl_inst]) { | ||
| 4515 | .opaque_decl, | ||
| 4516 | .opaque_decl_anon, | ||
| 4517 | .opaque_decl_func, | ||
| 4518 | => { | ||
| 4519 | const inst_data = datas[decl_inst].pl_node; | ||
| 4520 | const extra = zir.extraData(Inst.OpaqueDecl, inst_data.payload_index); | ||
| 4521 | return declIteratorInner(zir, extra.end, extra.data.decls_len); | ||
| 4522 | }, | ||
| 4523 | |||
| 4524 | // Functions are allowed and yield no iterations. | ||
| 4525 | // There is one case matching this in the extended instruction set below. | ||
| 4526 | .func, | ||
| 4527 | .func_inferred, | ||
| 4528 | => return declIteratorInner(zir, 0, 0), | ||
| 4529 | |||
| 4530 | .extended => { | ||
| 4531 | const extended = datas[decl_inst].extended; | ||
| 4532 | switch (extended.opcode) { | ||
| 4533 | .func => return declIteratorInner(zir, 0, 0), | ||
| 4534 | .struct_decl => { | ||
| 4535 | const small = @bitCast(Inst.StructDecl.Small, extended.small); | ||
| 4536 | var extra_index: usize = extended.operand; | ||
| 4537 | extra_index += @boolToInt(small.has_src_node); | ||
| 4538 | extra_index += @boolToInt(small.has_body_len); | ||
| 4539 | extra_index += @boolToInt(small.has_fields_len); | ||
| 4540 | const decls_len = if (small.has_decls_len) decls_len: { | ||
| 4541 | const decls_len = zir.extra[extra_index]; | ||
| 4542 | extra_index += 1; | ||
| 4543 | break :decls_len decls_len; | ||
| 4544 | } else 0; | ||
| 4545 | |||
| 4546 | return declIteratorInner(zir, extra_index, decls_len); | ||
| 4547 | }, | ||
| 4548 | .enum_decl => { | ||
| 4549 | const small = @bitCast(Inst.EnumDecl.Small, extended.small); | ||
| 4550 | var extra_index: usize = extended.operand; | ||
| 4551 | extra_index += @boolToInt(small.has_src_node); | ||
| 4552 | extra_index += @boolToInt(small.has_tag_type); | ||
| 4553 | extra_index += @boolToInt(small.has_body_len); | ||
| 4554 | extra_index += @boolToInt(small.has_fields_len); | ||
| 4555 | const decls_len = if (small.has_decls_len) decls_len: { | ||
| 4556 | const decls_len = zir.extra[extra_index]; | ||
| 4557 | extra_index += 1; | ||
| 4558 | break :decls_len decls_len; | ||
| 4559 | } else 0; | ||
| 4560 | |||
| 4561 | return declIteratorInner(zir, extra_index, decls_len); | ||
| 4562 | }, | ||
| 4563 | .union_decl => { | ||
| 4564 | const small = @bitCast(Inst.UnionDecl.Small, extended.small); | ||
| 4565 | var extra_index: usize = extended.operand; | ||
| 4566 | extra_index += @boolToInt(small.has_src_node); | ||
| 4567 | extra_index += @boolToInt(small.has_tag_type); | ||
| 4568 | extra_index += @boolToInt(small.has_body_len); | ||
| 4569 | extra_index += @boolToInt(small.has_fields_len); | ||
| 4570 | const decls_len = if (small.has_decls_len) decls_len: { | ||
| 4571 | const decls_len = zir.extra[extra_index]; | ||
| 4572 | extra_index += 1; | ||
| 4573 | break :decls_len decls_len; | ||
| 4574 | } else 0; | ||
| 4575 | |||
| 4576 | return declIteratorInner(zir, extra_index, decls_len); | ||
| 4577 | }, | ||
| 4578 | else => unreachable, | ||
| 4579 | } | ||
| 4580 | }, | ||
| 4581 | else => unreachable, | ||
| 4582 | } | ||
| 4583 | } | ||
| 4584 | |||
| 4585 | pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclIterator { | ||
| 4586 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; | ||
| 4587 | return .{ | ||
| 4588 | .zir = zir, | ||
| 4589 | .extra_index = extra_index + bit_bags_count, | ||
| 4590 | .bit_bag_index = extra_index, | ||
| 4591 | .cur_bit_bag = undefined, | ||
| 4592 | .decl_i = 0, | ||
| 4593 | .decls_len = decls_len, | ||
| 4594 | }; | ||
| 4595 | } | ||
| 4596 | |||
| 4597 | /// The iterator would have to allocate memory anyway to iterate. So here we populate | ||
| 4598 | /// an ArrayList as the result. | ||
| 4599 | pub fn findDecls(zir: Zir, list: *std.ArrayList(Zir.Inst.Index), decl_sub_index: u32) !void { | ||
| 4600 | const block_inst = zir.extra[decl_sub_index + 6]; | ||
| 4601 | list.clearRetainingCapacity(); | ||
| 4602 | |||
| 4603 | return zir.findDeclsInner(list, block_inst); | ||
| 4604 | } | ||
| 4605 | |||
| 4606 | fn findDeclsInner( | ||
| 4607 | zir: Zir, | ||
| 4608 | list: *std.ArrayList(Zir.Inst.Index), | ||
| 4609 | inst: Zir.Inst.Index, | ||
| 4610 | ) Allocator.Error!void { | ||
| 4611 | const tags = zir.instructions.items(.tag); | ||
| 4612 | const datas = zir.instructions.items(.data); | ||
| 4613 | |||
| 4614 | switch (tags[inst]) { | ||
| 4615 | // Decl instructions are interesting but have no body. | ||
| 4616 | // TODO yes they do have a body actually. recurse over them just like block instructions. | ||
| 4617 | .opaque_decl, | ||
| 4618 | .opaque_decl_anon, | ||
| 4619 | .opaque_decl_func, | ||
| 4620 | => return list.append(inst), | ||
| 4621 | |||
| 4622 | // Functions instructions are interesting and have a body. | ||
| 4623 | .func, | ||
| 4624 | .func_inferred, | ||
| 4625 | => { | ||
| 4626 | try list.append(inst); | ||
| 4627 | |||
| 4628 | const inst_data = datas[inst].pl_node; | ||
| 4629 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); | ||
| 4630 | const param_types_len = extra.data.param_types_len; | ||
| 4631 | const body = zir.extra[extra.end + param_types_len ..][0..extra.data.body_len]; | ||
| 4632 | return zir.findDeclsBody(list, body); | ||
| 4633 | }, | ||
| 4634 | .extended => { | ||
| 4635 | const extended = datas[inst].extended; | ||
| 4636 | switch (extended.opcode) { | ||
| 4637 | .func => { | ||
| 4638 | try list.append(inst); | ||
| 4639 | |||
| 4640 | const extra = zir.extraData(Inst.ExtendedFunc, extended.operand); | ||
| 4641 | const small = @bitCast(Inst.ExtendedFunc.Small, extended.small); | ||
| 4642 | var extra_index: usize = extra.end; | ||
| 4643 | extra_index += @boolToInt(small.has_lib_name); | ||
| 4644 | extra_index += @boolToInt(small.has_cc); | ||
| 4645 | extra_index += @boolToInt(small.has_align); | ||
| 4646 | extra_index += extra.data.param_types_len; | ||
| 4647 | const body = zir.extra[extra_index..][0..extra.data.body_len]; | ||
| 4648 | return zir.findDeclsBody(list, body); | ||
| 4649 | }, | ||
| 4650 | |||
| 4651 | .struct_decl, | ||
| 4652 | .union_decl, | ||
| 4653 | .enum_decl, | ||
| 4654 | => return list.append(inst), | ||
| 4655 | |||
| 4656 | else => return, | ||
| 4657 | } | ||
| 4658 | }, | ||
| 4659 | |||
| 4660 | // Block instructions, recurse over the bodies. | ||
| 4661 | |||
| 4662 | .block, .block_inline => { | ||
| 4663 | const inst_data = datas[inst].pl_node; | ||
| 4664 | const extra = zir.extraData(Inst.Block, inst_data.payload_index); | ||
| 4665 | const body = zir.extra[extra.end..][0..extra.data.body_len]; | ||
| 4666 | return zir.findDeclsBody(list, body); | ||
| 4667 | }, | ||
| 4668 | .condbr, .condbr_inline => { | ||
| 4669 | const inst_data = datas[inst].pl_node; | ||
| 4670 | const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); | ||
| 4671 | const then_body = zir.extra[extra.end..][0..extra.data.then_body_len]; | ||
| 4672 | const else_body = zir.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | ||
| 4673 | try zir.findDeclsBody(list, then_body); | ||
| 4674 | try zir.findDeclsBody(list, else_body); | ||
| 4675 | }, | ||
| 4676 | .switch_block => return findDeclsSwitch(zir, list, inst, .none), | ||
| 4677 | .switch_block_else => return findDeclsSwitch(zir, list, inst, .@"else"), | ||
| 4678 | .switch_block_under => return findDeclsSwitch(zir, list, inst, .under), | ||
| 4679 | .switch_block_ref => return findDeclsSwitch(zir, list, inst, .none), | ||
| 4680 | .switch_block_ref_else => return findDeclsSwitch(zir, list, inst, .@"else"), | ||
| 4681 | .switch_block_ref_under => return findDeclsSwitch(zir, list, inst, .under), | ||
| 4682 | |||
| 4683 | .switch_block_multi => return findDeclsSwitchMulti(zir, list, inst, .none), | ||
| 4684 | .switch_block_else_multi => return findDeclsSwitchMulti(zir, list, inst, .@"else"), | ||
| 4685 | .switch_block_under_multi => return findDeclsSwitchMulti(zir, list, inst, .under), | ||
| 4686 | .switch_block_ref_multi => return findDeclsSwitchMulti(zir, list, inst, .none), | ||
| 4687 | .switch_block_ref_else_multi => return findDeclsSwitchMulti(zir, list, inst, .@"else"), | ||
| 4688 | .switch_block_ref_under_multi => return findDeclsSwitchMulti(zir, list, inst, .under), | ||
| 4689 | |||
| 4690 | .suspend_block => @panic("TODO iterate suspend block"), | ||
| 4691 | |||
| 4692 | else => return, // Regular instruction, not interesting. | ||
| 4693 | } | ||
| 4694 | } | ||
| 4695 | |||
| 4696 | fn findDeclsSwitch( | ||
| 4697 | zir: Zir, | ||
| 4698 | list: *std.ArrayList(Zir.Inst.Index), | ||
| 4699 | inst: Zir.Inst.Index, | ||
| 4700 | special_prong: SpecialProng, | ||
| 4701 | ) Allocator.Error!void { | ||
| 4702 | const inst_data = zir.instructions.items(.data)[inst].pl_node; | ||
| 4703 | const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index); | ||
| 4704 | const special: struct { | ||
| 4705 | body: []const Inst.Index, | ||
| 4706 | end: usize, | ||
| 4707 | } = switch (special_prong) { | ||
| 4708 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 4709 | .under, .@"else" => blk: { | ||
| 4710 | const body_len = zir.extra[extra.end]; | ||
| 4711 | const extra_body_start = extra.end + 1; | ||
| 4712 | break :blk .{ | ||
| 4713 | .body = zir.extra[extra_body_start..][0..body_len], | ||
| 4714 | .end = extra_body_start + body_len, | ||
| 4715 | }; | ||
| 4716 | }, | ||
| 4717 | }; | ||
| 4718 | |||
| 4719 | try zir.findDeclsBody(list, special.body); | ||
| 4720 | |||
| 4721 | var extra_index: usize = special.end; | ||
| 4722 | var scalar_i: usize = 0; | ||
| 4723 | while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { | ||
| 4724 | const item_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]); | ||
| 4725 | extra_index += 1; | ||
| 4726 | const body_len = zir.extra[extra_index]; | ||
| 4727 | extra_index += 1; | ||
| 4728 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 4729 | extra_index += body_len; | ||
| 4730 | |||
| 4731 | try zir.findDeclsBody(list, body); | ||
| 4732 | } | ||
| 4733 | } | ||
| 4734 | |||
| 4735 | fn findDeclsSwitchMulti( | ||
| 4736 | zir: Zir, | ||
| 4737 | list: *std.ArrayList(Zir.Inst.Index), | ||
| 4738 | inst: Zir.Inst.Index, | ||
| 4739 | special_prong: SpecialProng, | ||
| 4740 | ) Allocator.Error!void { | ||
| 4741 | const inst_data = zir.instructions.items(.data)[inst].pl_node; | ||
| 4742 | const extra = zir.extraData(Inst.SwitchBlockMulti, inst_data.payload_index); | ||
| 4743 | const special: struct { | ||
| 4744 | body: []const Inst.Index, | ||
| 4745 | end: usize, | ||
| 4746 | } = switch (special_prong) { | ||
| 4747 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 4748 | .under, .@"else" => blk: { | ||
| 4749 | const body_len = zir.extra[extra.end]; | ||
| 4750 | const extra_body_start = extra.end + 1; | ||
| 4751 | break :blk .{ | ||
| 4752 | .body = zir.extra[extra_body_start..][0..body_len], | ||
| 4753 | .end = extra_body_start + body_len, | ||
| 4754 | }; | ||
| 4755 | }, | ||
| 4756 | }; | ||
| 4757 | |||
| 4758 | try zir.findDeclsBody(list, special.body); | ||
| 4759 | |||
| 4760 | var extra_index: usize = special.end; | ||
| 4761 | { | ||
| 4762 | var scalar_i: usize = 0; | ||
| 4763 | while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { | ||
| 4764 | const item_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]); | ||
| 4765 | extra_index += 1; | ||
| 4766 | const body_len = zir.extra[extra_index]; | ||
| 4767 | extra_index += 1; | ||
| 4768 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 4769 | extra_index += body_len; | ||
| 4770 | |||
| 4771 | try zir.findDeclsBody(list, body); | ||
| 4772 | } | ||
| 4773 | } | ||
| 4774 | { | ||
| 4775 | var multi_i: usize = 0; | ||
| 4776 | while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { | ||
| 4777 | const items_len = zir.extra[extra_index]; | ||
| 4778 | extra_index += 1; | ||
| 4779 | const ranges_len = zir.extra[extra_index]; | ||
| 4780 | extra_index += 1; | ||
| 4781 | const body_len = zir.extra[extra_index]; | ||
| 4782 | extra_index += 1; | ||
| 4783 | const items = zir.refSlice(extra_index, items_len); | ||
| 4784 | extra_index += items_len; | ||
| 4785 | |||
| 4786 | var range_i: usize = 0; | ||
| 4787 | while (range_i < ranges_len) : (range_i += 1) { | ||
| 4788 | const item_first = @intToEnum(Inst.Ref, zir.extra[extra_index]); | ||
| 4789 | extra_index += 1; | ||
| 4790 | const item_last = @intToEnum(Inst.Ref, zir.extra[extra_index]); | ||
| 4791 | extra_index += 1; | ||
| 4792 | } | ||
| 4793 | |||
| 4794 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 4795 | extra_index += body_len; | ||
| 4796 | |||
| 4797 | try zir.findDeclsBody(list, body); | ||
| 4798 | } | ||
| 4799 | } | ||
| 4800 | } | ||
| 4801 | |||
| 4802 | fn findDeclsBody( | ||
| 4803 | zir: Zir, | ||
| 4804 | list: *std.ArrayList(Zir.Inst.Index), | ||
| 4805 | body: []const Zir.Inst.Index, | ||
| 4806 | ) Allocator.Error!void { | ||
| 4807 | for (body) |member| { | ||
| 4808 | try zir.findDeclsInner(list, member); | ||
| 4809 | } | ||
| 4810 | } | ||
src/codegen.zig+70-127| ... | @@ -117,7 +117,6 @@ pub fn generateSymbol( | ... | @@ -117,7 +117,6 @@ pub fn generateSymbol( |
| 117 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 117 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 118 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 118 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 119 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 119 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 120 | .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | ||
| 121 | //.tce => return Function(.tce).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 120 | //.tce => return Function(.tce).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 122 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 121 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| 123 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), | 122 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output), |
| ... | @@ -212,20 +211,50 @@ pub fn generateSymbol( | ... | @@ -212,20 +211,50 @@ pub fn generateSymbol( |
| 212 | }, | 211 | }, |
| 213 | .Int => { | 212 | .Int => { |
| 214 | // TODO populate .debug_info for the integer | 213 | // TODO populate .debug_info for the integer |
| 214 | const endian = bin_file.options.target.cpu.arch.endian(); | ||
| 215 | const info = typed_value.ty.intInfo(bin_file.options.target); | 215 | const info = typed_value.ty.intInfo(bin_file.options.target); |
| 216 | if (info.bits == 8 and info.signedness == .unsigned) { | 216 | if (info.bits <= 8) { |
| 217 | const x = typed_value.val.toUnsignedInt(); | 217 | const x = @intCast(u8, typed_value.val.toUnsignedInt()); |
| 218 | try code.append(@intCast(u8, x)); | 218 | try code.append(x); |
| 219 | return Result{ .appended = {} }; | 219 | return Result{ .appended = {} }; |
| 220 | } | 220 | } |
| 221 | return Result{ | 221 | if (info.bits > 64) { |
| 222 | .fail = try ErrorMsg.create( | 222 | return Result{ |
| 223 | bin_file.allocator, | 223 | .fail = try ErrorMsg.create( |
| 224 | src_loc, | 224 | bin_file.allocator, |
| 225 | "TODO implement generateSymbol for int type '{}'", | 225 | src_loc, |
| 226 | .{typed_value.ty}, | 226 | "TODO implement generateSymbol for big ints ('{}')", |
| 227 | ), | 227 | .{typed_value.ty}, |
| 228 | }; | 228 | ), |
| 229 | }; | ||
| 230 | } | ||
| 231 | switch (info.signedness) { | ||
| 232 | .unsigned => { | ||
| 233 | if (info.bits <= 16) { | ||
| 234 | const x = @intCast(u16, typed_value.val.toUnsignedInt()); | ||
| 235 | mem.writeInt(u16, try code.addManyAsArray(2), x, endian); | ||
| 236 | } else if (info.bits <= 32) { | ||
| 237 | const x = @intCast(u32, typed_value.val.toUnsignedInt()); | ||
| 238 | mem.writeInt(u32, try code.addManyAsArray(4), x, endian); | ||
| 239 | } else { | ||
| 240 | const x = typed_value.val.toUnsignedInt(); | ||
| 241 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | ||
| 242 | } | ||
| 243 | }, | ||
| 244 | .signed => { | ||
| 245 | if (info.bits <= 16) { | ||
| 246 | const x = @intCast(i16, typed_value.val.toSignedInt()); | ||
| 247 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | ||
| 248 | } else if (info.bits <= 32) { | ||
| 249 | const x = @intCast(i32, typed_value.val.toSignedInt()); | ||
| 250 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | ||
| 251 | } else { | ||
| 252 | const x = typed_value.val.toSignedInt(); | ||
| 253 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | ||
| 254 | } | ||
| 255 | }, | ||
| 256 | } | ||
| 257 | return Result{ .appended = {} }; | ||
| 229 | }, | 258 | }, |
| 230 | else => |t| { | 259 | else => |t| { |
| 231 | return Result{ | 260 | return Result{ |
| ... | @@ -266,14 +295,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -266,14 +295,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 266 | src_loc: Module.SrcLoc, | 295 | src_loc: Module.SrcLoc, |
| 267 | stack_align: u32, | 296 | stack_align: u32, |
| 268 | 297 | ||
| 269 | /// Byte offset within the source file. | 298 | prev_di_line: u32, |
| 270 | prev_di_src: usize, | 299 | prev_di_column: u32, |
| 300 | /// Byte offset within the source file of the ending curly. | ||
| 301 | end_di_line: u32, | ||
| 302 | end_di_column: u32, | ||
| 271 | /// Relative to the beginning of `code`. | 303 | /// Relative to the beginning of `code`. |
| 272 | prev_di_pc: usize, | 304 | prev_di_pc: usize, |
| 273 | /// Used to find newlines and count line deltas. | ||
| 274 | source: []const u8, | ||
| 275 | /// Byte offset within the source file of the ending curly. | ||
| 276 | rbrace_src: usize, | ||
| 277 | 305 | ||
| 278 | /// The value is an offset into the `Function` `code` from the beginning. | 306 | /// The value is an offset into the `Function` `code` from the beginning. |
| 279 | /// To perform the reloc, write 32-bit signed little-endian integer | 307 | /// To perform the reloc, write 32-bit signed little-endian integer |
| ... | @@ -402,7 +430,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -402,7 +430,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 402 | 430 | ||
| 403 | const module_fn = typed_value.val.castTag(.function).?.data; | 431 | const module_fn = typed_value.val.castTag(.function).?.data; |
| 404 | 432 | ||
| 405 | const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty; | 433 | assert(module_fn.owner_decl.has_tv); |
| 434 | const fn_type = module_fn.owner_decl.ty; | ||
| 406 | 435 | ||
| 407 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); | 436 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); |
| 408 | defer { | 437 | defer { |
| ... | @@ -412,25 +441,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -412,25 +441,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 412 | } | 441 | } |
| 413 | try branch_stack.append(.{}); | 442 | try branch_stack.append(.{}); |
| 414 | 443 | ||
| 415 | const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: { | ||
| 416 | const container_scope = module_fn.owner_decl.container; | ||
| 417 | const tree = container_scope.file_scope.tree; | ||
| 418 | const node_tags = tree.nodes.items(.tag); | ||
| 419 | const node_datas = tree.nodes.items(.data); | ||
| 420 | const token_starts = tree.tokens.items(.start); | ||
| 421 | |||
| 422 | const fn_decl = module_fn.owner_decl.src_node; | ||
| 423 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 424 | const block = node_datas[fn_decl].rhs; | ||
| 425 | const lbrace_src = token_starts[tree.firstToken(block)]; | ||
| 426 | const rbrace_src = token_starts[tree.lastToken(block)]; | ||
| 427 | break :blk .{ | ||
| 428 | .lbrace_src = lbrace_src, | ||
| 429 | .rbrace_src = rbrace_src, | ||
| 430 | .source = tree.source, | ||
| 431 | }; | ||
| 432 | }; | ||
| 433 | |||
| 434 | var function = Self{ | 444 | var function = Self{ |
| 435 | .gpa = bin_file.allocator, | 445 | .gpa = bin_file.allocator, |
| 436 | .target = &bin_file.options.target, | 446 | .target = &bin_file.options.target, |
| ... | @@ -447,9 +457,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -447,9 +457,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 447 | .src_loc = src_loc, | 457 | .src_loc = src_loc, |
| 448 | .stack_align = undefined, | 458 | .stack_align = undefined, |
| 449 | .prev_di_pc = 0, | 459 | .prev_di_pc = 0, |
| 450 | .prev_di_src = src_data.lbrace_src, | 460 | .prev_di_line = module_fn.lbrace_line, |
| 451 | .rbrace_src = src_data.rbrace_src, | 461 | .prev_di_column = module_fn.lbrace_column, |
| 452 | .source = src_data.source, | 462 | .end_di_line = module_fn.rbrace_line, |
| 463 | .end_di_column = module_fn.rbrace_column, | ||
| 453 | }; | 464 | }; |
| 454 | defer function.stack.deinit(bin_file.allocator); | 465 | defer function.stack.deinit(bin_file.allocator); |
| 455 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); | 466 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| ... | @@ -702,7 +713,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -702,7 +713,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 702 | }, | 713 | }, |
| 703 | } | 714 | } |
| 704 | // Drop them off at the rbrace. | 715 | // Drop them off at the rbrace. |
| 705 | try self.dbgAdvancePCAndLine(self.rbrace_src); | 716 | try self.dbgAdvancePCAndLine(self.end_di_line, self.end_di_column); |
| 706 | } | 717 | } |
| 707 | 718 | ||
| 708 | fn genBody(self: *Self, body: ir.Body) InnerError!void { | 719 | fn genBody(self: *Self, body: ir.Body) InnerError!void { |
| ... | @@ -728,7 +739,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -728,7 +739,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 728 | switch (self.debug_output) { | 739 | switch (self.debug_output) { |
| 729 | .dwarf => |dbg_out| { | 740 | .dwarf => |dbg_out| { |
| 730 | try dbg_out.dbg_line.append(DW.LNS_set_prologue_end); | 741 | try dbg_out.dbg_line.append(DW.LNS_set_prologue_end); |
| 731 | try self.dbgAdvancePCAndLine(self.prev_di_src); | 742 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 732 | }, | 743 | }, |
| 733 | .none => {}, | 744 | .none => {}, |
| 734 | } | 745 | } |
| ... | @@ -738,27 +749,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -738,27 +749,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 738 | switch (self.debug_output) { | 749 | switch (self.debug_output) { |
| 739 | .dwarf => |dbg_out| { | 750 | .dwarf => |dbg_out| { |
| 740 | try dbg_out.dbg_line.append(DW.LNS_set_epilogue_begin); | 751 | try dbg_out.dbg_line.append(DW.LNS_set_epilogue_begin); |
| 741 | try self.dbgAdvancePCAndLine(self.prev_di_src); | 752 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 742 | }, | 753 | }, |
| 743 | .none => {}, | 754 | .none => {}, |
| 744 | } | 755 | } |
| 745 | } | 756 | } |
| 746 | 757 | ||
| 747 | fn dbgAdvancePCAndLine(self: *Self, abs_byte_off: usize) InnerError!void { | 758 | fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void { |
| 748 | self.prev_di_src = abs_byte_off; | ||
| 749 | self.prev_di_pc = self.code.items.len; | ||
| 750 | switch (self.debug_output) { | 759 | switch (self.debug_output) { |
| 751 | .dwarf => |dbg_out| { | 760 | .dwarf => |dbg_out| { |
| 752 | // TODO Look into improving the performance here by adding a token-index-to-line | 761 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 753 | // lookup table, and changing ir.Inst from storing byte offset to token. Currently | ||
| 754 | // this involves scanning over the source code for newlines | ||
| 755 | // (but only from the previous byte offset to the new one). | ||
| 756 | const delta_line = std.zig.lineDelta(self.source, self.prev_di_src, abs_byte_off); | ||
| 757 | const delta_pc = self.code.items.len - self.prev_di_pc; | 762 | const delta_pc = self.code.items.len - self.prev_di_pc; |
| 758 | // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit | 763 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 759 | // single-byte opcodes that add different numbers to both the PC and the line number | 764 | // It lets you emit single-byte opcodes that add different numbers to |
| 760 | // at the same time. | 765 | // both the PC and the line number at the same time. |
| 761 | try dbg_out.dbg_line.ensureCapacity(dbg_out.dbg_line.items.len + 11); | 766 | try dbg_out.dbg_line.ensureUnusedCapacity(11); |
| 762 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); | 767 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); |
| 763 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | 768 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; |
| 764 | if (delta_line != 0) { | 769 | if (delta_line != 0) { |
| ... | @@ -769,6 +774,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -769,6 +774,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 769 | }, | 774 | }, |
| 770 | .none => {}, | 775 | .none => {}, |
| 771 | } | 776 | } |
| 777 | self.prev_di_line = line; | ||
| 778 | self.prev_di_column = column; | ||
| 779 | self.prev_di_pc = self.code.items.len; | ||
| 772 | } | 780 | } |
| 773 | 781 | ||
| 774 | /// Asserts there is already capacity to insert into top branch inst_table. | 782 | /// Asserts there is already capacity to insert into top branch inst_table. |
| ... | @@ -2230,11 +2238,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2230,11 +2238,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2230 | .riscv64 => { | 2238 | .riscv64 => { |
| 2231 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ebreak.toU32()); | 2239 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ebreak.toU32()); |
| 2232 | }, | 2240 | }, |
| 2233 | .spu_2 => { | ||
| 2234 | try self.code.resize(self.code.items.len + 2); | ||
| 2235 | var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined1 }; | ||
| 2236 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr)); | ||
| 2237 | }, | ||
| 2238 | .arm, .armeb => { | 2241 | .arm, .armeb => { |
| 2239 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32()); | 2242 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.bkpt(0).toU32()); |
| 2240 | }, | 2243 | }, |
| ... | @@ -2343,52 +2346,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2343,52 +2346,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2343 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | 2346 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); |
| 2344 | } | 2347 | } |
| 2345 | }, | 2348 | }, |
| 2346 | .spu_2 => { | ||
| 2347 | if (inst.func.value()) |func_value| { | ||
| 2348 | if (info.args.len != 0) { | ||
| 2349 | return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{}); | ||
| 2350 | } | ||
| 2351 | if (func_value.castTag(.function)) |func_payload| { | ||
| 2352 | const func = func_payload.data; | ||
| 2353 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { | ||
| 2354 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | ||
| 2355 | break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2); | ||
| 2356 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | ||
| 2357 | @intCast(u16, coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * 2) | ||
| 2358 | else | ||
| 2359 | unreachable; | ||
| 2360 | |||
| 2361 | const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType(); | ||
| 2362 | // First, push the return address, then jump; if noreturn, don't bother with the first step | ||
| 2363 | // TODO: implement packed struct -> u16 at comptime and move the bitcast here | ||
| 2364 | var instr = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .jump, .command = .load16 }; | ||
| 2365 | if (return_type.zigTypeTag() == .NoReturn) { | ||
| 2366 | try self.code.resize(self.code.items.len + 4); | ||
| 2367 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr)); | ||
| 2368 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr); | ||
| 2369 | return MCValue.unreach; | ||
| 2370 | } else { | ||
| 2371 | try self.code.resize(self.code.items.len + 8); | ||
| 2372 | var push = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .push, .command = .ipget }; | ||
| 2373 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 8 ..][0..2], @bitCast(u16, push)); | ||
| 2374 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 6 ..][0..2], @as(u16, 4)); | ||
| 2375 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr)); | ||
| 2376 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr); | ||
| 2377 | switch (return_type.zigTypeTag()) { | ||
| 2378 | .Void => return MCValue{ .none = {} }, | ||
| 2379 | .NoReturn => unreachable, | ||
| 2380 | else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), | ||
| 2381 | } | ||
| 2382 | } | ||
| 2383 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 2384 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 2385 | } else { | ||
| 2386 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | ||
| 2387 | } | ||
| 2388 | } else { | ||
| 2389 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{}); | ||
| 2390 | } | ||
| 2391 | }, | ||
| 2392 | .arm, .armeb => { | 2349 | .arm, .armeb => { |
| 2393 | for (info.args) |mc_arg, arg_i| { | 2350 | for (info.args) |mc_arg, arg_i| { |
| 2394 | const arg = inst.args[arg_i]; | 2351 | const arg = inst.args[arg_i]; |
| ... | @@ -2777,11 +2734,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2777,11 +2734,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2777 | } | 2734 | } |
| 2778 | 2735 | ||
| 2779 | fn genDbgStmt(self: *Self, inst: *ir.Inst.DbgStmt) !MCValue { | 2736 | fn genDbgStmt(self: *Self, inst: *ir.Inst.DbgStmt) !MCValue { |
| 2780 | // TODO when reworking tzir memory layout, rework source locations here as | 2737 | // TODO when reworking AIR memory layout, rework source locations here as |
| 2781 | // well to be more efficient, as well as support inlined function calls correctly. | 2738 | // well to be more efficient, as well as support inlined function calls correctly. |
| 2782 | // For now we convert LazySrcLoc to absolute byte offset, to match what the | 2739 | // For now we convert LazySrcLoc to absolute byte offset, to match what the |
| 2783 | // existing codegen code expects. | 2740 | // existing codegen code expects. |
| 2784 | try self.dbgAdvancePCAndLine(inst.byte_offset); | 2741 | try self.dbgAdvancePCAndLine(inst.line, inst.column); |
| 2785 | assert(inst.base.isUnused()); | 2742 | assert(inst.base.isUnused()); |
| 2786 | return MCValue.dead; | 2743 | return MCValue.dead; |
| 2787 | } | 2744 | } |
| ... | @@ -3201,19 +3158,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3201,19 +3158,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3201 | if (!inst.is_volatile and inst.base.isUnused()) | 3158 | if (!inst.is_volatile and inst.base.isUnused()) |
| 3202 | return MCValue.dead; | 3159 | return MCValue.dead; |
| 3203 | switch (arch) { | 3160 | switch (arch) { |
| 3204 | .spu_2 => { | ||
| 3205 | if (inst.inputs.len > 0 or inst.output != null) { | ||
| 3206 | return self.fail(inst.base.src, "TODO implement inline asm inputs / outputs for SPU Mark II", .{}); | ||
| 3207 | } | ||
| 3208 | if (mem.eql(u8, inst.asm_source, "undefined0")) { | ||
| 3209 | try self.code.resize(self.code.items.len + 2); | ||
| 3210 | var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined0 }; | ||
| 3211 | mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr)); | ||
| 3212 | return MCValue.none; | ||
| 3213 | } else { | ||
| 3214 | return self.fail(inst.base.src, "TODO implement support for more SPU II assembly instructions", .{}); | ||
| 3215 | } | ||
| 3216 | }, | ||
| 3217 | .arm, .armeb => { | 3161 | .arm, .armeb => { |
| 3218 | for (inst.inputs) |input, i| { | 3162 | for (inst.inputs) |input, i| { |
| 3219 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { | 3163 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { |
| ... | @@ -3235,7 +3179,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3235,7 +3179,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3235 | return self.fail(inst.base.src, "TODO implement support for more arm assembly instructions", .{}); | 3179 | return self.fail(inst.base.src, "TODO implement support for more arm assembly instructions", .{}); |
| 3236 | } | 3180 | } |
| 3237 | 3181 | ||
| 3238 | if (inst.output_name) |output| { | 3182 | if (inst.output_constraint) |output| { |
| 3239 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { | 3183 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 3240 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); | 3184 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); |
| 3241 | } | 3185 | } |
| ... | @@ -3270,7 +3214,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3270,7 +3214,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3270 | return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{}); | 3214 | return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{}); |
| 3271 | } | 3215 | } |
| 3272 | 3216 | ||
| 3273 | if (inst.output_name) |output| { | 3217 | if (inst.output_constraint) |output| { |
| 3274 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { | 3218 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 3275 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); | 3219 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); |
| 3276 | } | 3220 | } |
| ... | @@ -3303,7 +3247,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3303,7 +3247,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3303 | return self.fail(inst.base.src, "TODO implement support for more riscv64 assembly instructions", .{}); | 3247 | return self.fail(inst.base.src, "TODO implement support for more riscv64 assembly instructions", .{}); |
| 3304 | } | 3248 | } |
| 3305 | 3249 | ||
| 3306 | if (inst.output_name) |output| { | 3250 | if (inst.output_constraint) |output| { |
| 3307 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { | 3251 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 3308 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); | 3252 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); |
| 3309 | } | 3253 | } |
| ... | @@ -3336,7 +3280,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3336,7 +3280,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3336 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); | 3280 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); |
| 3337 | } | 3281 | } |
| 3338 | 3282 | ||
| 3339 | if (inst.output_name) |output| { | 3283 | if (inst.output_constraint) |output| { |
| 3340 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { | 3284 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 3341 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); | 3285 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{s}'", .{output}); |
| 3342 | } | 3286 | } |
| ... | @@ -4528,7 +4472,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -4528,7 +4472,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 4528 | .i386 => @import("codegen/x86.zig"), | 4472 | .i386 => @import("codegen/x86.zig"), |
| 4529 | .x86_64 => @import("codegen/x86_64.zig"), | 4473 | .x86_64 => @import("codegen/x86_64.zig"), |
| 4530 | .riscv64 => @import("codegen/riscv64.zig"), | 4474 | .riscv64 => @import("codegen/riscv64.zig"), |
| 4531 | .spu_2 => @import("codegen/spu-mk2.zig"), | ||
| 4532 | .arm, .armeb => @import("codegen/arm.zig"), | 4475 | .arm, .armeb => @import("codegen/arm.zig"), |
| 4533 | .aarch64, .aarch64_be, .aarch64_32 => @import("codegen/aarch64.zig"), | 4476 | .aarch64, .aarch64_be, .aarch64_32 => @import("codegen/aarch64.zig"), |
| 4534 | else => struct { | 4477 | else => struct { |
src/codegen/c.zig+71-20| ... | @@ -30,6 +30,7 @@ pub const CValue = union(enum) { | ... | @@ -30,6 +30,7 @@ pub const CValue = union(enum) { |
| 30 | arg: usize, | 30 | arg: usize, |
| 31 | /// By-value | 31 | /// By-value |
| 32 | decl: *Decl, | 32 | decl: *Decl, |
| 33 | decl_ref: *Decl, | ||
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | pub const CValueMap = std.AutoHashMap(*Inst, CValue); | 36 | pub const CValueMap = std.AutoHashMap(*Inst, CValue); |
| ... | @@ -60,12 +61,13 @@ fn formatIdent( | ... | @@ -60,12 +61,13 @@ fn formatIdent( |
| 60 | for (ident) |c, i| { | 61 | for (ident) |c, i| { |
| 61 | switch (c) { | 62 | switch (c) { |
| 62 | 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c), | 63 | 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c), |
| 64 | '.' => try writer.writeByte('_'), | ||
| 63 | '0'...'9' => if (i == 0) { | 65 | '0'...'9' => if (i == 0) { |
| 64 | try writer.print("${x:2}", .{c}); | 66 | try writer.print("_{x:2}", .{c}); |
| 65 | } else { | 67 | } else { |
| 66 | try writer.writeByte(c); | 68 | try writer.writeByte(c); |
| 67 | }, | 69 | }, |
| 68 | else => try writer.print("${x:2}", .{c}), | 70 | else => try writer.print("_{x:2}", .{c}), |
| 69 | } | 71 | } |
| 70 | } | 72 | } |
| 71 | } | 73 | } |
| ... | @@ -117,6 +119,7 @@ pub const Object = struct { | ... | @@ -117,6 +119,7 @@ pub const Object = struct { |
| 117 | .constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?), | 119 | .constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?), |
| 118 | .arg => |i| return w.print("a{d}", .{i}), | 120 | .arg => |i| return w.print("a{d}", .{i}), |
| 119 | .decl => |decl| return w.writeAll(mem.span(decl.name)), | 121 | .decl => |decl| return w.writeAll(mem.span(decl.name)), |
| 122 | .decl_ref => |decl| return w.print("&{s}", .{decl.name}), | ||
| 120 | } | 123 | } |
| 121 | } | 124 | } |
| 122 | 125 | ||
| ... | @@ -190,8 +193,8 @@ pub const DeclGen = struct { | ... | @@ -190,8 +193,8 @@ pub const DeclGen = struct { |
| 190 | const decl = val.castTag(.decl_ref).?.data; | 193 | const decl = val.castTag(.decl_ref).?.data; |
| 191 | 194 | ||
| 192 | // Determine if we must pointer cast. | 195 | // Determine if we must pointer cast. |
| 193 | const decl_tv = decl.typed_value.most_recent.typed_value; | 196 | assert(decl.has_tv); |
| 194 | if (t.eql(decl_tv.ty)) { | 197 | if (t.eql(decl.ty)) { |
| 195 | try writer.print("&{s}", .{decl.name}); | 198 | try writer.print("&{s}", .{decl.name}); |
| 196 | } else { | 199 | } else { |
| 197 | try writer.writeAll("("); | 200 | try writer.writeAll("("); |
| ... | @@ -326,12 +329,11 @@ pub const DeclGen = struct { | ... | @@ -326,12 +329,11 @@ pub const DeclGen = struct { |
| 326 | if (!is_global) { | 329 | if (!is_global) { |
| 327 | try w.writeAll("static "); | 330 | try w.writeAll("static "); |
| 328 | } | 331 | } |
| 329 | const tv = dg.decl.typed_value.most_recent.typed_value; | 332 | try dg.renderType(w, dg.decl.ty.fnReturnType()); |
| 330 | try dg.renderType(w, tv.ty.fnReturnType()); | ||
| 331 | const decl_name = mem.span(dg.decl.name); | 333 | const decl_name = mem.span(dg.decl.name); |
| 332 | try w.print(" {s}(", .{decl_name}); | 334 | try w.print(" {s}(", .{decl_name}); |
| 333 | const param_len = tv.ty.fnParamLen(); | 335 | const param_len = dg.decl.ty.fnParamLen(); |
| 334 | const is_var_args = tv.ty.fnIsVarArgs(); | 336 | const is_var_args = dg.decl.ty.fnIsVarArgs(); |
| 335 | if (param_len == 0 and !is_var_args) | 337 | if (param_len == 0 and !is_var_args) |
| 336 | try w.writeAll("void") | 338 | try w.writeAll("void") |
| 337 | else { | 339 | else { |
| ... | @@ -340,7 +342,7 @@ pub const DeclGen = struct { | ... | @@ -340,7 +342,7 @@ pub const DeclGen = struct { |
| 340 | if (index > 0) { | 342 | if (index > 0) { |
| 341 | try w.writeAll(", "); | 343 | try w.writeAll(", "); |
| 342 | } | 344 | } |
| 343 | try dg.renderType(w, tv.ty.fnParamType(index)); | 345 | try dg.renderType(w, dg.decl.ty.fnParamType(index)); |
| 344 | try w.print(" a{d}", .{index}); | 346 | try w.print(" a{d}", .{index}); |
| 345 | } | 347 | } |
| 346 | } | 348 | } |
| ... | @@ -529,13 +531,17 @@ pub const DeclGen = struct { | ... | @@ -529,13 +531,17 @@ pub const DeclGen = struct { |
| 529 | } | 531 | } |
| 530 | } | 532 | } |
| 531 | 533 | ||
| 532 | fn functionIsGlobal(dg: *DeclGen, tv: TypedValue) bool { | 534 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { |
| 533 | switch (tv.val.tag()) { | 535 | switch (tv.val.tag()) { |
| 534 | .extern_fn => return true, | 536 | .extern_fn => return true, |
| 535 | .function => { | 537 | .function => { |
| 536 | const func = tv.val.castTag(.function).?.data; | 538 | const func = tv.val.castTag(.function).?.data; |
| 537 | return dg.module.decl_exports.contains(func.owner_decl); | 539 | return dg.module.decl_exports.contains(func.owner_decl); |
| 538 | }, | 540 | }, |
| 541 | .variable => { | ||
| 542 | const variable = tv.val.castTag(.variable).?.data; | ||
| 543 | return dg.module.decl_exports.contains(variable.owner_decl); | ||
| 544 | }, | ||
| 539 | else => unreachable, | 545 | else => unreachable, |
| 540 | } | 546 | } |
| 541 | } | 547 | } |
| ... | @@ -545,10 +551,12 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -545,10 +551,12 @@ pub fn genDecl(o: *Object) !void { |
| 545 | const tracy = trace(@src()); | 551 | const tracy = trace(@src()); |
| 546 | defer tracy.end(); | 552 | defer tracy.end(); |
| 547 | 553 | ||
| 548 | const tv = o.dg.decl.typed_value.most_recent.typed_value; | 554 | const tv: TypedValue = .{ |
| 549 | 555 | .ty = o.dg.decl.ty, | |
| 556 | .val = o.dg.decl.val, | ||
| 557 | }; | ||
| 550 | if (tv.val.castTag(.function)) |func_payload| { | 558 | if (tv.val.castTag(.function)) |func_payload| { |
| 551 | const is_global = o.dg.functionIsGlobal(tv); | 559 | const is_global = o.dg.declIsGlobal(tv); |
| 552 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 560 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 553 | if (is_global) { | 561 | if (is_global) { |
| 554 | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); | 562 | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); |
| ... | @@ -569,6 +577,29 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -569,6 +577,29 @@ pub fn genDecl(o: *Object) !void { |
| 569 | try writer.writeAll("ZIG_EXTERN_C "); | 577 | try writer.writeAll("ZIG_EXTERN_C "); |
| 570 | try o.dg.renderFunctionSignature(writer, true); | 578 | try o.dg.renderFunctionSignature(writer, true); |
| 571 | try writer.writeAll(";\n"); | 579 | try writer.writeAll(";\n"); |
| 580 | } else if (tv.val.castTag(.variable)) |var_payload| { | ||
| 581 | const variable: *Module.Var = var_payload.data; | ||
| 582 | const is_global = o.dg.declIsGlobal(tv); | ||
| 583 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | ||
| 584 | if (is_global or variable.is_extern) { | ||
| 585 | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); | ||
| 586 | } | ||
| 587 | if (variable.is_threadlocal) { | ||
| 588 | try fwd_decl_writer.writeAll("zig_threadlocal "); | ||
| 589 | } | ||
| 590 | try o.dg.renderType(fwd_decl_writer, o.dg.decl.ty); | ||
| 591 | const decl_name = mem.span(o.dg.decl.name); | ||
| 592 | try fwd_decl_writer.print(" {s};\n", .{decl_name}); | ||
| 593 | |||
| 594 | try o.indent_writer.insertNewline(); | ||
| 595 | const w = o.writer(); | ||
| 596 | try o.dg.renderType(w, o.dg.decl.ty); | ||
| 597 | try w.print(" {s} = ", .{decl_name}); | ||
| 598 | if (variable.init.tag() != .unreachable_value) { | ||
| 599 | try o.dg.renderValue(w, tv.ty, variable.init); | ||
| 600 | } | ||
| 601 | try w.writeAll(";"); | ||
| 602 | try o.indent_writer.insertNewline(); | ||
| 572 | } else { | 603 | } else { |
| 573 | const writer = o.writer(); | 604 | const writer = o.writer(); |
| 574 | try writer.writeAll("static "); | 605 | try writer.writeAll("static "); |
| ... | @@ -589,12 +620,15 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { | ... | @@ -589,12 +620,15 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 589 | const tracy = trace(@src()); | 620 | const tracy = trace(@src()); |
| 590 | defer tracy.end(); | 621 | defer tracy.end(); |
| 591 | 622 | ||
| 592 | const tv = dg.decl.typed_value.most_recent.typed_value; | 623 | const tv: TypedValue = .{ |
| 624 | .ty = dg.decl.ty, | ||
| 625 | .val = dg.decl.val, | ||
| 626 | }; | ||
| 593 | const writer = dg.fwd_decl.writer(); | 627 | const writer = dg.fwd_decl.writer(); |
| 594 | 628 | ||
| 595 | switch (tv.ty.zigTypeTag()) { | 629 | switch (tv.ty.zigTypeTag()) { |
| 596 | .Fn => { | 630 | .Fn => { |
| 597 | const is_global = dg.functionIsGlobal(tv); | 631 | const is_global = dg.declIsGlobal(tv); |
| 598 | if (is_global) { | 632 | if (is_global) { |
| 599 | try writer.writeAll("ZIG_EXTERN_C "); | 633 | try writer.writeAll("ZIG_EXTERN_C "); |
| 600 | } | 634 | } |
| ... | @@ -692,7 +726,7 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi | ... | @@ -692,7 +726,7 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 692 | .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?), | 726 | .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?), |
| 693 | .br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}), | 727 | .br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}), |
| 694 | .ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}), | 728 | .ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}), |
| 695 | .varptr => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for varptr", .{}), | 729 | .varptr => try genVarPtr(o, inst.castTag(.varptr).?), |
| 696 | .floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}), | 730 | .floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}), |
| 697 | }; | 731 | }; |
| 698 | switch (result_value) { | 732 | switch (result_value) { |
| ... | @@ -705,6 +739,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi | ... | @@ -705,6 +739,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 705 | try writer.writeAll("}"); | 739 | try writer.writeAll("}"); |
| 706 | } | 740 | } |
| 707 | 741 | ||
| 742 | fn genVarPtr(o: *Object, inst: *Inst.VarPtr) !CValue { | ||
| 743 | return CValue{ .decl_ref = inst.variable.owner_decl }; | ||
| 744 | } | ||
| 745 | |||
| 708 | fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue { | 746 | fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue { |
| 709 | const writer = o.writer(); | 747 | const writer = o.writer(); |
| 710 | 748 | ||
| ... | @@ -739,6 +777,12 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue { | ... | @@ -739,6 +777,12 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue { |
| 739 | try o.writeCValue(writer, wrapped); | 777 | try o.writeCValue(writer, wrapped); |
| 740 | try writer.writeAll(";\n"); | 778 | try writer.writeAll(";\n"); |
| 741 | }, | 779 | }, |
| 780 | .decl_ref => |decl| { | ||
| 781 | const wrapped: CValue = .{ .decl = decl }; | ||
| 782 | try writer.writeAll(" = "); | ||
| 783 | try o.writeCValue(writer, wrapped); | ||
| 784 | try writer.writeAll(";\n"); | ||
| 785 | }, | ||
| 742 | else => { | 786 | else => { |
| 743 | try writer.writeAll(" = *"); | 787 | try writer.writeAll(" = *"); |
| 744 | try o.writeCValue(writer, operand); | 788 | try o.writeCValue(writer, operand); |
| ... | @@ -787,6 +831,13 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue { | ... | @@ -787,6 +831,13 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue { |
| 787 | try o.writeCValue(writer, src_val); | 831 | try o.writeCValue(writer, src_val); |
| 788 | try writer.writeAll(";\n"); | 832 | try writer.writeAll(";\n"); |
| 789 | }, | 833 | }, |
| 834 | .decl_ref => |decl| { | ||
| 835 | const dest: CValue = .{ .decl = decl }; | ||
| 836 | try o.writeCValue(writer, dest); | ||
| 837 | try writer.writeAll(" = "); | ||
| 838 | try o.writeCValue(writer, src_val); | ||
| 839 | try writer.writeAll(";\n"); | ||
| 840 | }, | ||
| 790 | else => { | 841 | else => { |
| 791 | try writer.writeAll("*"); | 842 | try writer.writeAll("*"); |
| 792 | try o.writeCValue(writer, dest_ptr); | 843 | try o.writeCValue(writer, dest_ptr); |
| ... | @@ -842,7 +893,7 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue { | ... | @@ -842,7 +893,7 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue { |
| 842 | else | 893 | else |
| 843 | unreachable; | 894 | unreachable; |
| 844 | 895 | ||
| 845 | const fn_ty = fn_decl.typed_value.most_recent.typed_value.ty; | 896 | const fn_ty = fn_decl.ty; |
| 846 | const ret_ty = fn_ty.fnReturnType(); | 897 | const ret_ty = fn_ty.fnReturnType(); |
| 847 | const unused_result = inst.base.isUnused(); | 898 | const unused_result = inst.base.isUnused(); |
| 848 | var result_local: CValue = .none; | 899 | var result_local: CValue = .none; |
| ... | @@ -1036,11 +1087,11 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { | ... | @@ -1036,11 +1087,11 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 1036 | } | 1087 | } |
| 1037 | const volatile_string: []const u8 = if (as.is_volatile) "volatile " else ""; | 1088 | const volatile_string: []const u8 = if (as.is_volatile) "volatile " else ""; |
| 1038 | try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, as.asm_source }); | 1089 | try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, as.asm_source }); |
| 1039 | if (as.output) |_| { | 1090 | if (as.output_constraint) |_| { |
| 1040 | return o.dg.fail(.{ .node_offset = 0 }, "TODO inline asm output", .{}); | 1091 | return o.dg.fail(.{ .node_offset = 0 }, "TODO: CBE inline asm output", .{}); |
| 1041 | } | 1092 | } |
| 1042 | if (as.inputs.len > 0) { | 1093 | if (as.inputs.len > 0) { |
| 1043 | if (as.output == null) { | 1094 | if (as.output_constraint == null) { |
| 1044 | try writer.writeAll(" :"); | 1095 | try writer.writeAll(" :"); |
| 1045 | } | 1096 | } |
| 1046 | try writer.writeAll(": "); | 1097 | try writer.writeAll(": "); |
src/codegen/llvm.zig+35-17| ... | @@ -193,14 +193,9 @@ pub const Object = struct { | ... | @@ -193,14 +193,9 @@ pub const Object = struct { |
| 193 | try stderr.print( | 193 | try stderr.print( |
| 194 | \\Zig is expecting LLVM to understand this target: '{s}' | 194 | \\Zig is expecting LLVM to understand this target: '{s}' |
| 195 | \\However LLVM responded with: "{s}" | 195 | \\However LLVM responded with: "{s}" |
| 196 | \\Zig is unable to continue. This is a bug in Zig: | ||
| 197 | \\https://github.com/ziglang/zig/issues/438 | ||
| 198 | \\ | 196 | \\ |
| 199 | , | 197 | , |
| 200 | .{ | 198 | .{ llvm_target_triple, error_message }, |
| 201 | llvm_target_triple, | ||
| 202 | error_message, | ||
| 203 | }, | ||
| 204 | ); | 199 | ); |
| 205 | return error.InvalidLLVMTriple; | 200 | return error.InvalidLLVMTriple; |
| 206 | } | 201 | } |
| ... | @@ -325,17 +320,17 @@ pub const DeclGen = struct { | ... | @@ -325,17 +320,17 @@ pub const DeclGen = struct { |
| 325 | 320 | ||
| 326 | fn genDecl(self: *DeclGen) !void { | 321 | fn genDecl(self: *DeclGen) !void { |
| 327 | const decl = self.decl; | 322 | const decl = self.decl; |
| 328 | const typed_value = decl.typed_value.most_recent.typed_value; | 323 | assert(decl.has_tv); |
| 329 | 324 | ||
| 330 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val }); | 325 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); |
| 331 | 326 | ||
| 332 | if (typed_value.val.castTag(.function)) |func_payload| { | 327 | if (decl.val.castTag(.function)) |func_payload| { |
| 333 | const func = func_payload.data; | 328 | const func = func_payload.data; |
| 334 | 329 | ||
| 335 | const llvm_func = try self.resolveLLVMFunction(func.owner_decl); | 330 | const llvm_func = try self.resolveLLVMFunction(func.owner_decl); |
| 336 | 331 | ||
| 337 | // This gets the LLVM values from the function and stores them in `self.args`. | 332 | // This gets the LLVM values from the function and stores them in `self.args`. |
| 338 | const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen(); | 333 | const fn_param_len = func.owner_decl.ty.fnParamLen(); |
| 339 | var args = try self.gpa.alloc(*const llvm.Value, fn_param_len); | 334 | var args = try self.gpa.alloc(*const llvm.Value, fn_param_len); |
| 340 | 335 | ||
| 341 | for (args) |*arg, i| { | 336 | for (args) |*arg, i| { |
| ... | @@ -368,7 +363,7 @@ pub const DeclGen = struct { | ... | @@ -368,7 +363,7 @@ pub const DeclGen = struct { |
| 368 | defer fg.deinit(); | 363 | defer fg.deinit(); |
| 369 | 364 | ||
| 370 | try fg.genBody(func.body); | 365 | try fg.genBody(func.body); |
| 371 | } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| { | 366 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| 372 | _ = try self.resolveLLVMFunction(extern_fn.data); | 367 | _ = try self.resolveLLVMFunction(extern_fn.data); |
| 373 | } else { | 368 | } else { |
| 374 | _ = try self.resolveGlobalDecl(decl); | 369 | _ = try self.resolveGlobalDecl(decl); |
| ... | @@ -380,7 +375,8 @@ pub const DeclGen = struct { | ... | @@ -380,7 +375,8 @@ pub const DeclGen = struct { |
| 380 | // TODO: do we want to store this in our own datastructure? | 375 | // TODO: do we want to store this in our own datastructure? |
| 381 | if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn; | 376 | if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn; |
| 382 | 377 | ||
| 383 | const zig_fn_type = func.typed_value.most_recent.typed_value.ty; | 378 | assert(func.has_tv); |
| 379 | const zig_fn_type = func.ty; | ||
| 384 | const return_type = zig_fn_type.fnReturnType(); | 380 | const return_type = zig_fn_type.fnReturnType(); |
| 385 | 381 | ||
| 386 | const fn_param_len = zig_fn_type.fnParamLen(); | 382 | const fn_param_len = zig_fn_type.fnParamLen(); |
| ... | @@ -415,11 +411,11 @@ pub const DeclGen = struct { | ... | @@ -415,11 +411,11 @@ pub const DeclGen = struct { |
| 415 | // TODO: do we want to store this in our own datastructure? | 411 | // TODO: do we want to store this in our own datastructure? |
| 416 | if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val; | 412 | if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val; |
| 417 | 413 | ||
| 418 | const typed_value = decl.typed_value.most_recent.typed_value; | 414 | assert(decl.has_tv); |
| 419 | 415 | ||
| 420 | // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`. | 416 | // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`. |
| 421 | const llvm_type = try self.getLLVMType(typed_value.ty); | 417 | const llvm_type = try self.getLLVMType(decl.ty); |
| 422 | const val = try self.genTypedValue(typed_value, null); | 418 | const val = try self.genTypedValue(.{ .ty = decl.ty, .val = decl.val }, null); |
| 423 | const global = self.llvmModule().addGlobal(llvm_type, decl.name); | 419 | const global = self.llvmModule().addGlobal(llvm_type, decl.name); |
| 424 | llvm.setInitializer(global, val); | 420 | llvm.setInitializer(global, val); |
| 425 | 421 | ||
| ... | @@ -430,6 +426,7 @@ pub const DeclGen = struct { | ... | @@ -430,6 +426,7 @@ pub const DeclGen = struct { |
| 430 | } | 426 | } |
| 431 | 427 | ||
| 432 | fn getLLVMType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type { | 428 | fn getLLVMType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type { |
| 429 | log.debug("getLLVMType for {}", .{t}); | ||
| 433 | switch (t.zigTypeTag()) { | 430 | switch (t.zigTypeTag()) { |
| 434 | .Void => return self.context().voidType(), | 431 | .Void => return self.context().voidType(), |
| 435 | .NoReturn => return self.context().voidType(), | 432 | .NoReturn => return self.context().voidType(), |
| ... | @@ -464,7 +461,27 @@ pub const DeclGen = struct { | ... | @@ -464,7 +461,27 @@ pub const DeclGen = struct { |
| 464 | return self.todo("implement optional pointers as actual pointers", .{}); | 461 | return self.todo("implement optional pointers as actual pointers", .{}); |
| 465 | } | 462 | } |
| 466 | }, | 463 | }, |
| 467 | else => return self.todo("implement getLLVMType for type '{}'", .{t}), | 464 | .ComptimeInt => unreachable, |
| 465 | .ComptimeFloat => unreachable, | ||
| 466 | .Type => unreachable, | ||
| 467 | .Undefined => unreachable, | ||
| 468 | .Null => unreachable, | ||
| 469 | .EnumLiteral => unreachable, | ||
| 470 | |||
| 471 | .BoundFn => @panic("TODO remove BoundFn from the language"), | ||
| 472 | |||
| 473 | .Float, | ||
| 474 | .Struct, | ||
| 475 | .ErrorUnion, | ||
| 476 | .ErrorSet, | ||
| 477 | .Enum, | ||
| 478 | .Union, | ||
| 479 | .Fn, | ||
| 480 | .Opaque, | ||
| 481 | .Frame, | ||
| 482 | .AnyFrame, | ||
| 483 | .Vector, | ||
| 484 | => return self.todo("implement getLLVMType for type '{}'", .{t}), | ||
| 468 | } | 485 | } |
| 469 | } | 486 | } |
| 470 | 487 | ||
| ... | @@ -688,7 +705,8 @@ pub const FuncGen = struct { | ... | @@ -688,7 +705,8 @@ pub const FuncGen = struct { |
| 688 | else | 705 | else |
| 689 | unreachable; | 706 | unreachable; |
| 690 | 707 | ||
| 691 | const zig_fn_type = fn_decl.typed_value.most_recent.typed_value.ty; | 708 | assert(fn_decl.has_tv); |
| 709 | const zig_fn_type = fn_decl.ty; | ||
| 692 | const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl); | 710 | const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl); |
| 693 | 711 | ||
| 694 | const num_args = inst.args.len; | 712 | const num_args = inst.args.len; |
src/codegen/spirv.zig+37-53| ... | @@ -71,10 +71,7 @@ pub const DeclGen = struct { | ... | @@ -71,10 +71,7 @@ pub const DeclGen = struct { |
| 71 | decl: *Decl, | 71 | decl: *Decl, |
| 72 | error_msg: ?*Module.ErrorMsg, | 72 | error_msg: ?*Module.ErrorMsg, |
| 73 | 73 | ||
| 74 | const Error = error{ | 74 | const Error = error{ AnalysisFail, OutOfMemory }; |
| 75 | AnalysisFail, | ||
| 76 | OutOfMemory | ||
| 77 | }; | ||
| 78 | 75 | ||
| 79 | /// This structure is used to return information about a type typically used for arithmetic operations. | 76 | /// This structure is used to return information about a type typically used for arithmetic operations. |
| 80 | /// These types may either be integers, floats, or a vector of these. Most scalar operations also work on vectors, | 77 | /// These types may either be integers, floats, or a vector of these. Most scalar operations also work on vectors, |
| ... | @@ -153,7 +150,7 @@ pub const DeclGen = struct { | ... | @@ -153,7 +150,7 @@ pub const DeclGen = struct { |
| 153 | 150 | ||
| 154 | // 8, 16 and 64-bit integers require the Int8, Int16 and Inr64 capabilities respectively. | 151 | // 8, 16 and 64-bit integers require the Int8, Int16 and Inr64 capabilities respectively. |
| 155 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). | 152 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). |
| 156 | const ints = [_]struct{ bits: u16, feature: ?Target.spirv.Feature } { | 153 | const ints = [_]struct { bits: u16, feature: ?Target.spirv.Feature }{ |
| 157 | .{ .bits = 8, .feature = .Int8 }, | 154 | .{ .bits = 8, .feature = .Int8 }, |
| 158 | .{ .bits = 16, .feature = .Int16 }, | 155 | .{ .bits = 16, .feature = .Int16 }, |
| 159 | .{ .bits = 32, .feature = null }, | 156 | .{ .bits = 32, .feature = null }, |
| ... | @@ -215,23 +212,18 @@ pub const DeclGen = struct { | ... | @@ -215,23 +212,18 @@ pub const DeclGen = struct { |
| 215 | const int_info = ty.intInfo(target); | 212 | const int_info = ty.intInfo(target); |
| 216 | // TODO: Maybe it's useful to also return this value. | 213 | // TODO: Maybe it's useful to also return this value. |
| 217 | const maybe_backing_bits = self.backingIntBits(int_info.bits); | 214 | const maybe_backing_bits = self.backingIntBits(int_info.bits); |
| 218 | break :blk ArithmeticTypeInfo{ | 215 | break :blk ArithmeticTypeInfo{ .bits = int_info.bits, .is_vector = false, .signedness = int_info.signedness, .class = if (maybe_backing_bits) |backing_bits| |
| 219 | .bits = int_info.bits, | 216 | if (backing_bits == int_info.bits) |
| 220 | .is_vector = false, | 217 | ArithmeticTypeInfo.Class.integer |
| 221 | .signedness = int_info.signedness, | 218 | else |
| 222 | .class = if (maybe_backing_bits) |backing_bits| | 219 | ArithmeticTypeInfo.Class.strange_integer |
| 223 | if (backing_bits == int_info.bits) | 220 | else |
| 224 | ArithmeticTypeInfo.Class.integer | 221 | .composite_integer }; |
| 225 | else | ||
| 226 | ArithmeticTypeInfo.Class.strange_integer | ||
| 227 | else | ||
| 228 | .composite_integer | ||
| 229 | }; | ||
| 230 | }, | 222 | }, |
| 231 | // As of yet, there is no vector support in the self-hosted compiler. | 223 | // As of yet, there is no vector support in the self-hosted compiler. |
| 232 | .Vector => self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement arithmeticTypeInfo for Vector", .{}), | 224 | .Vector => self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement arithmeticTypeInfo for Vector", .{}), |
| 233 | // TODO: For which types is this the case? | 225 | // TODO: For which types is this the case? |
| 234 | else => self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement arithmeticTypeInfo for {}", .{ty}), | 226 | else => self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement arithmeticTypeInfo for {}", .{ty}), |
| 235 | }; | 227 | }; |
| 236 | } | 228 | } |
| 237 | 229 | ||
| ... | @@ -259,16 +251,8 @@ pub const DeclGen = struct { | ... | @@ -259,16 +251,8 @@ pub const DeclGen = struct { |
| 259 | // f16 and f32 require one word of storage. f64 requires 2, low-order first. | 251 | // f16 and f32 require one word of storage. f64 requires 2, low-order first. |
| 260 | 252 | ||
| 261 | switch (val.tag()) { | 253 | switch (val.tag()) { |
| 262 | .float_16 => try writeInstruction(code, .OpConstant, &[_]u32{ | 254 | .float_16 => try writeInstruction(code, .OpConstant, &[_]u32{ result_type_id, result_id, @bitCast(u16, val.castTag(.float_16).?.data) }), |
| 263 | result_type_id, | 255 | .float_32 => try writeInstruction(code, .OpConstant, &[_]u32{ result_type_id, result_id, @bitCast(u32, val.castTag(.float_32).?.data) }), |
| 264 | result_id, | ||
| 265 | @bitCast(u16, val.castTag(.float_16).?.data) | ||
| 266 | }), | ||
| 267 | .float_32 => try writeInstruction(code, .OpConstant, &[_]u32{ | ||
| 268 | result_type_id, | ||
| 269 | result_id, | ||
| 270 | @bitCast(u32, val.castTag(.float_32).?.data) | ||
| 271 | }), | ||
| 272 | .float_64 => { | 256 | .float_64 => { |
| 273 | const float_bits = @bitCast(u64, val.castTag(.float_64).?.data); | 257 | const float_bits = @bitCast(u64, val.castTag(.float_64).?.data); |
| 274 | try writeInstruction(code, .OpConstant, &[_]u32{ | 258 | try writeInstruction(code, .OpConstant, &[_]u32{ |
| ... | @@ -280,10 +264,10 @@ pub const DeclGen = struct { | ... | @@ -280,10 +264,10 @@ pub const DeclGen = struct { |
| 280 | }, | 264 | }, |
| 281 | .float_128 => unreachable, // Filtered out in the call to getOrGenType. | 265 | .float_128 => unreachable, // Filtered out in the call to getOrGenType. |
| 282 | // TODO: What tags do we need to handle here anyway? | 266 | // TODO: What tags do we need to handle here anyway? |
| 283 | else => return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: float constant generation of value {s}\n", .{ val.tag() }), | 267 | else => return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: float constant generation of value {s}\n", .{val.tag()}), |
| 284 | } | 268 | } |
| 285 | }, | 269 | }, |
| 286 | else => return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: constant generation of type {s}\n", .{ ty.zigTypeTag() }), | 270 | else => return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: constant generation of type {s}\n", .{ty.zigTypeTag()}), |
| 287 | } | 271 | } |
| 288 | 272 | ||
| 289 | return result_id; | 273 | return result_id; |
| ... | @@ -300,13 +284,13 @@ pub const DeclGen = struct { | ... | @@ -300,13 +284,13 @@ pub const DeclGen = struct { |
| 300 | const result_id = self.spv.allocResultId(); | 284 | const result_id = self.spv.allocResultId(); |
| 301 | 285 | ||
| 302 | switch (ty.zigTypeTag()) { | 286 | switch (ty.zigTypeTag()) { |
| 303 | .Void => try writeInstruction(code, .OpTypeVoid, &[_]u32{ result_id }), | 287 | .Void => try writeInstruction(code, .OpTypeVoid, &[_]u32{result_id}), |
| 304 | .Bool => try writeInstruction(code, .OpTypeBool, &[_]u32{ result_id }), | 288 | .Bool => try writeInstruction(code, .OpTypeBool, &[_]u32{result_id}), |
| 305 | .Int => { | 289 | .Int => { |
| 306 | const int_info = ty.intInfo(target); | 290 | const int_info = ty.intInfo(target); |
| 307 | const backing_bits = self.backingIntBits(int_info.bits) orelse { | 291 | const backing_bits = self.backingIntBits(int_info.bits) orelse { |
| 308 | // Integers too big for any native type are represented as "composite integers": An array of largestSupportedIntBits. | 292 | // Integers too big for any native type are represented as "composite integers": An array of largestSupportedIntBits. |
| 309 | return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement composite ints {}", .{ ty }); | 293 | return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement composite ints {}", .{ty}); |
| 310 | }; | 294 | }; |
| 311 | 295 | ||
| 312 | // TODO: If backing_bits != int_info.bits, a duplicate type might be generated here. | 296 | // TODO: If backing_bits != int_info.bits, a duplicate type might be generated here. |
| ... | @@ -332,7 +316,7 @@ pub const DeclGen = struct { | ... | @@ -332,7 +316,7 @@ pub const DeclGen = struct { |
| 332 | }; | 316 | }; |
| 333 | 317 | ||
| 334 | if (!supported) { | 318 | if (!supported) { |
| 335 | return self.fail(.{.node_offset = 0}, "Floating point width of {} bits is not supported for the current SPIR-V feature set", .{ bits }); | 319 | return self.fail(.{ .node_offset = 0 }, "Floating point width of {} bits is not supported for the current SPIR-V feature set", .{bits}); |
| 336 | } | 320 | } |
| 337 | 321 | ||
| 338 | try writeInstruction(code, .OpTypeFloat, &[_]u32{ result_id, bits }); | 322 | try writeInstruction(code, .OpTypeFloat, &[_]u32{ result_id, bits }); |
| ... | @@ -340,9 +324,9 @@ pub const DeclGen = struct { | ... | @@ -340,9 +324,9 @@ pub const DeclGen = struct { |
| 340 | .Fn => { | 324 | .Fn => { |
| 341 | // We only support zig-calling-convention functions, no varargs. | 325 | // We only support zig-calling-convention functions, no varargs. |
| 342 | if (ty.fnCallingConvention() != .Unspecified) | 326 | if (ty.fnCallingConvention() != .Unspecified) |
| 343 | return self.fail(.{.node_offset = 0}, "Unsupported calling convention for SPIR-V", .{}); | 327 | return self.fail(.{ .node_offset = 0 }, "Unsupported calling convention for SPIR-V", .{}); |
| 344 | if (ty.fnIsVarArgs()) | 328 | if (ty.fnIsVarArgs()) |
| 345 | return self.fail(.{.node_offset = 0}, "VarArgs unsupported for SPIR-V", .{}); | 329 | return self.fail(.{ .node_offset = 0 }, "VarArgs unsupported for SPIR-V", .{}); |
| 346 | 330 | ||
| 347 | // In order to avoid a temporary here, first generate all the required types and then simply look them up | 331 | // In order to avoid a temporary here, first generate all the required types and then simply look them up |
| 348 | // when generating the function type. | 332 | // when generating the function type. |
| ... | @@ -355,7 +339,7 @@ pub const DeclGen = struct { | ... | @@ -355,7 +339,7 @@ pub const DeclGen = struct { |
| 355 | const return_type_id = try self.getOrGenType(ty.fnReturnType()); | 339 | const return_type_id = try self.getOrGenType(ty.fnReturnType()); |
| 356 | 340 | ||
| 357 | // result id + result type id + parameter type ids. | 341 | // result id + result type id + parameter type ids. |
| 358 | try writeOpcode(code, .OpTypeFunction, 2 + @intCast(u32, ty.fnParamLen()) ); | 342 | try writeOpcode(code, .OpTypeFunction, 2 + @intCast(u32, ty.fnParamLen())); |
| 359 | try code.appendSlice(&.{ result_id, return_type_id }); | 343 | try code.appendSlice(&.{ result_id, return_type_id }); |
| 360 | 344 | ||
| 361 | i = 0; | 345 | i = 0; |
| ... | @@ -373,7 +357,7 @@ pub const DeclGen = struct { | ... | @@ -373,7 +357,7 @@ pub const DeclGen = struct { |
| 373 | // is adequate at all for this. | 357 | // is adequate at all for this. |
| 374 | 358 | ||
| 375 | // TODO: Vectors are not yet supported by the self-hosted compiler itself it seems. | 359 | // TODO: Vectors are not yet supported by the self-hosted compiler itself it seems. |
| 376 | return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement type Vector", .{}); | 360 | return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement type Vector", .{}); |
| 377 | }, | 361 | }, |
| 378 | .Null, | 362 | .Null, |
| 379 | .Undefined, | 363 | .Undefined, |
| ... | @@ -385,7 +369,7 @@ pub const DeclGen = struct { | ... | @@ -385,7 +369,7 @@ pub const DeclGen = struct { |
| 385 | 369 | ||
| 386 | .BoundFn => unreachable, // this type will be deleted from the language. | 370 | .BoundFn => unreachable, // this type will be deleted from the language. |
| 387 | 371 | ||
| 388 | else => |tag| return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement type {}s", .{ tag }), | 372 | else => |tag| return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement type {}s", .{tag}), |
| 389 | } | 373 | } |
| 390 | 374 | ||
| 391 | try self.types.putNoClobber(ty, result_id); | 375 | try self.types.putNoClobber(ty, result_id); |
| ... | @@ -393,25 +377,25 @@ pub const DeclGen = struct { | ... | @@ -393,25 +377,25 @@ pub const DeclGen = struct { |
| 393 | } | 377 | } |
| 394 | 378 | ||
| 395 | pub fn gen(self: *DeclGen) !void { | 379 | pub fn gen(self: *DeclGen) !void { |
| 396 | const result_id = self.decl.fn_link.spirv.id; | 380 | const decl = self.decl; |
| 397 | const tv = self.decl.typed_value.most_recent.typed_value; | 381 | const result_id = decl.fn_link.spirv.id; |
| 398 | 382 | ||
| 399 | if (tv.val.castTag(.function)) |func_payload| { | 383 | if (decl.val.castTag(.function)) |func_payload| { |
| 400 | std.debug.assert(tv.ty.zigTypeTag() == .Fn); | 384 | std.debug.assert(decl.ty.zigTypeTag() == .Fn); |
| 401 | const prototype_id = try self.getOrGenType(tv.ty); | 385 | const prototype_id = try self.getOrGenType(decl.ty); |
| 402 | try writeInstruction(&self.spv.fn_decls, .OpFunction, &[_]u32{ | 386 | try writeInstruction(&self.spv.fn_decls, .OpFunction, &[_]u32{ |
| 403 | self.types.get(tv.ty.fnReturnType()).?, // This type should be generated along with the prototype. | 387 | self.types.get(decl.ty.fnReturnType()).?, // This type should be generated along with the prototype. |
| 404 | result_id, | 388 | result_id, |
| 405 | @bitCast(u32, spec.FunctionControl{}), // TODO: We can set inline here if the type requires it. | 389 | @bitCast(u32, spec.FunctionControl{}), // TODO: We can set inline here if the type requires it. |
| 406 | prototype_id, | 390 | prototype_id, |
| 407 | }); | 391 | }); |
| 408 | 392 | ||
| 409 | const params = tv.ty.fnParamLen(); | 393 | const params = decl.ty.fnParamLen(); |
| 410 | var i: usize = 0; | 394 | var i: usize = 0; |
| 411 | 395 | ||
| 412 | try self.args.ensureCapacity(params); | 396 | try self.args.ensureCapacity(params); |
| 413 | while (i < params) : (i += 1) { | 397 | while (i < params) : (i += 1) { |
| 414 | const param_type_id = self.types.get(tv.ty.fnParamType(i)).?; | 398 | const param_type_id = self.types.get(decl.ty.fnParamType(i)).?; |
| 415 | const arg_result_id = self.spv.allocResultId(); | 399 | const arg_result_id = self.spv.allocResultId(); |
| 416 | try writeInstruction(&self.spv.fn_decls, .OpFunctionParameter, &[_]u32{ param_type_id, arg_result_id }); | 400 | try writeInstruction(&self.spv.fn_decls, .OpFunctionParameter, &[_]u32{ param_type_id, arg_result_id }); |
| 417 | self.args.appendAssumeCapacity(arg_result_id); | 401 | self.args.appendAssumeCapacity(arg_result_id); |
| ... | @@ -424,7 +408,7 @@ pub const DeclGen = struct { | ... | @@ -424,7 +408,7 @@ pub const DeclGen = struct { |
| 424 | 408 | ||
| 425 | try writeInstruction(&self.spv.fn_decls, .OpFunctionEnd, &[_]u32{}); | 409 | try writeInstruction(&self.spv.fn_decls, .OpFunctionEnd, &[_]u32{}); |
| 426 | } else { | 410 | } else { |
| 427 | return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: generate decl type {}", .{ tv.ty.zigTypeTag() }); | 411 | return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: generate decl type {}", .{decl.ty.zigTypeTag()}); |
| 428 | } | 412 | } |
| 429 | } | 413 | } |
| 430 | 414 | ||
| ... | @@ -462,7 +446,7 @@ pub const DeclGen = struct { | ... | @@ -462,7 +446,7 @@ pub const DeclGen = struct { |
| 462 | .ret => self.genRet(inst.castTag(.ret).?), | 446 | .ret => self.genRet(inst.castTag(.ret).?), |
| 463 | .retvoid => self.genRetVoid(), | 447 | .retvoid => self.genRetVoid(), |
| 464 | .unreach => self.genUnreach(), | 448 | .unreach => self.genUnreach(), |
| 465 | else => self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement inst {}", .{inst.tag}), | 449 | else => self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: implement inst {}", .{inst.tag}), |
| 466 | }; | 450 | }; |
| 467 | } | 451 | } |
| 468 | 452 | ||
| ... | @@ -486,7 +470,7 @@ pub const DeclGen = struct { | ... | @@ -486,7 +470,7 @@ pub const DeclGen = struct { |
| 486 | const info = try self.arithmeticTypeInfo(inst.lhs.ty); | 470 | const info = try self.arithmeticTypeInfo(inst.lhs.ty); |
| 487 | 471 | ||
| 488 | if (info.class == .composite_integer) | 472 | if (info.class == .composite_integer) |
| 489 | return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: binary operations for composite integers", .{}); | 473 | return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: binary operations for composite integers", .{}); |
| 490 | 474 | ||
| 491 | const is_bool = info.class == .bool; | 475 | const is_bool = info.class == .bool; |
| 492 | const is_float = info.class == .float; | 476 | const is_float = info.class == .float; |
| ... | @@ -533,7 +517,7 @@ pub const DeclGen = struct { | ... | @@ -533,7 +517,7 @@ pub const DeclGen = struct { |
| 533 | if (info.class != .strange_integer) | 517 | if (info.class != .strange_integer) |
| 534 | return result_id; | 518 | return result_id; |
| 535 | 519 | ||
| 536 | return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: strange integer operation mask", .{}); | 520 | return self.fail(.{ .node_offset = 0 }, "TODO: SPIR-V backend: strange integer operation mask", .{}); |
| 537 | } | 521 | } |
| 538 | 522 | ||
| 539 | fn genUnOp(self: *DeclGen, inst: *Inst.UnOp) !u32 { | 523 | fn genUnOp(self: *DeclGen, inst: *Inst.UnOp) !u32 { |
| ... | @@ -563,7 +547,7 @@ pub const DeclGen = struct { | ... | @@ -563,7 +547,7 @@ pub const DeclGen = struct { |
| 563 | fn genRet(self: *DeclGen, inst: *Inst.UnOp) !?u32 { | 547 | fn genRet(self: *DeclGen, inst: *Inst.UnOp) !?u32 { |
| 564 | const operand_id = try self.resolve(inst.operand); | 548 | const operand_id = try self.resolve(inst.operand); |
| 565 | // TODO: This instruction needs to be the last in a block. Is that guaranteed? | 549 | // TODO: This instruction needs to be the last in a block. Is that guaranteed? |
| 566 | try writeInstruction(&self.spv.fn_decls, .OpReturnValue, &[_]u32{ operand_id }); | 550 | try writeInstruction(&self.spv.fn_decls, .OpReturnValue, &[_]u32{operand_id}); |
| 567 | return null; | 551 | return null; |
| 568 | } | 552 | } |
| 569 | 553 |
src/codegen/spirv/spec.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | //! This file is auto-generated by tools/gen_spirv_spec.zig. | 1 | //! This file is auto-generated by tools/gen_spirv_spec.zig. |
| 2 | 2 | ||
| 3 | const Version = @import("builtin").Version; | 3 | const Version = @import("std").builtin.Version; |
| 4 | pub const version = Version{ .major = 1, .minor = 5, .patch = 4 }; | 4 | pub const version = Version{ .major = 1, .minor = 5, .patch = 4 }; |
| 5 | pub const magic_number: u32 = 0x07230203; | 5 | pub const magic_number: u32 = 0x07230203; |
| 6 | pub const Opcode = extern enum(u16) { | 6 | pub const Opcode = extern enum(u16) { |
src/codegen/spu-mk2.zig deleted-170| ... | @@ -1,170 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub const Interpreter = @import("spu-mk2/interpreter.zig").Interpreter; | ||
| 4 | |||
| 5 | pub const ExecutionCondition = enum(u3) { | ||
| 6 | always = 0, | ||
| 7 | when_zero = 1, | ||
| 8 | not_zero = 2, | ||
| 9 | greater_zero = 3, | ||
| 10 | less_than_zero = 4, | ||
| 11 | greater_or_equal_zero = 5, | ||
| 12 | less_or_equal_zero = 6, | ||
| 13 | overflow = 7, | ||
| 14 | }; | ||
| 15 | |||
| 16 | pub const InputBehaviour = enum(u2) { | ||
| 17 | zero = 0, | ||
| 18 | immediate = 1, | ||
| 19 | peek = 2, | ||
| 20 | pop = 3, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub const OutputBehaviour = enum(u2) { | ||
| 24 | discard = 0, | ||
| 25 | push = 1, | ||
| 26 | jump = 2, | ||
| 27 | jump_relative = 3, | ||
| 28 | }; | ||
| 29 | |||
| 30 | pub const Command = enum(u5) { | ||
| 31 | copy = 0, | ||
| 32 | ipget = 1, | ||
| 33 | get = 2, | ||
| 34 | set = 3, | ||
| 35 | store8 = 4, | ||
| 36 | store16 = 5, | ||
| 37 | load8 = 6, | ||
| 38 | load16 = 7, | ||
| 39 | undefined0 = 8, | ||
| 40 | undefined1 = 9, | ||
| 41 | frget = 10, | ||
| 42 | frset = 11, | ||
| 43 | bpget = 12, | ||
| 44 | bpset = 13, | ||
| 45 | spget = 14, | ||
| 46 | spset = 15, | ||
| 47 | add = 16, | ||
| 48 | sub = 17, | ||
| 49 | mul = 18, | ||
| 50 | div = 19, | ||
| 51 | mod = 20, | ||
| 52 | @"and" = 21, | ||
| 53 | @"or" = 22, | ||
| 54 | xor = 23, | ||
| 55 | not = 24, | ||
| 56 | signext = 25, | ||
| 57 | rol = 26, | ||
| 58 | ror = 27, | ||
| 59 | bswap = 28, | ||
| 60 | asr = 29, | ||
| 61 | lsl = 30, | ||
| 62 | lsr = 31, | ||
| 63 | }; | ||
| 64 | |||
| 65 | pub const Instruction = packed struct { | ||
| 66 | condition: ExecutionCondition, | ||
| 67 | input0: InputBehaviour, | ||
| 68 | input1: InputBehaviour, | ||
| 69 | modify_flags: bool, | ||
| 70 | output: OutputBehaviour, | ||
| 71 | command: Command, | ||
| 72 | reserved: u1 = 0, | ||
| 73 | |||
| 74 | pub fn format(instr: Instruction, comptime fmt: []const u8, options: std.fmt.FormatOptions, out: anytype) !void { | ||
| 75 | try std.fmt.format(out, "0x{x:0<4} ", .{@bitCast(u16, instr)}); | ||
| 76 | try out.writeAll(switch (instr.condition) { | ||
| 77 | .always => " ", | ||
| 78 | .when_zero => "== 0", | ||
| 79 | .not_zero => "!= 0", | ||
| 80 | .greater_zero => " > 0", | ||
| 81 | .less_than_zero => " < 0", | ||
| 82 | .greater_or_equal_zero => ">= 0", | ||
| 83 | .less_or_equal_zero => "<= 0", | ||
| 84 | .overflow => "ovfl", | ||
| 85 | }); | ||
| 86 | try out.writeAll(" "); | ||
| 87 | try out.writeAll(switch (instr.input0) { | ||
| 88 | .zero => "zero", | ||
| 89 | .immediate => "imm ", | ||
| 90 | .peek => "peek", | ||
| 91 | .pop => "pop ", | ||
| 92 | }); | ||
| 93 | try out.writeAll(" "); | ||
| 94 | try out.writeAll(switch (instr.input1) { | ||
| 95 | .zero => "zero", | ||
| 96 | .immediate => "imm ", | ||
| 97 | .peek => "peek", | ||
| 98 | .pop => "pop ", | ||
| 99 | }); | ||
| 100 | try out.writeAll(" "); | ||
| 101 | try out.writeAll(switch (instr.command) { | ||
| 102 | .copy => "copy ", | ||
| 103 | .ipget => "ipget ", | ||
| 104 | .get => "get ", | ||
| 105 | .set => "set ", | ||
| 106 | .store8 => "store8 ", | ||
| 107 | .store16 => "store16 ", | ||
| 108 | .load8 => "load8 ", | ||
| 109 | .load16 => "load16 ", | ||
| 110 | .undefined0 => "undefined", | ||
| 111 | .undefined1 => "undefined", | ||
| 112 | .frget => "frget ", | ||
| 113 | .frset => "frset ", | ||
| 114 | .bpget => "bpget ", | ||
| 115 | .bpset => "bpset ", | ||
| 116 | .spget => "spget ", | ||
| 117 | .spset => "spset ", | ||
| 118 | .add => "add ", | ||
| 119 | .sub => "sub ", | ||
| 120 | .mul => "mul ", | ||
| 121 | .div => "div ", | ||
| 122 | .mod => "mod ", | ||
| 123 | .@"and" => "and ", | ||
| 124 | .@"or" => "or ", | ||
| 125 | .xor => "xor ", | ||
| 126 | .not => "not ", | ||
| 127 | .signext => "signext ", | ||
| 128 | .rol => "rol ", | ||
| 129 | .ror => "ror ", | ||
| 130 | .bswap => "bswap ", | ||
| 131 | .asr => "asr ", | ||
| 132 | .lsl => "lsl ", | ||
| 133 | .lsr => "lsr ", | ||
| 134 | }); | ||
| 135 | try out.writeAll(" "); | ||
| 136 | try out.writeAll(switch (instr.output) { | ||
| 137 | .discard => "discard", | ||
| 138 | .push => "push ", | ||
| 139 | .jump => "jmp ", | ||
| 140 | .jump_relative => "rjmp ", | ||
| 141 | }); | ||
| 142 | try out.writeAll(" "); | ||
| 143 | try out.writeAll(if (instr.modify_flags) | ||
| 144 | "+ flags" | ||
| 145 | else | ||
| 146 | " "); | ||
| 147 | } | ||
| 148 | }; | ||
| 149 | |||
| 150 | pub const FlagRegister = packed struct { | ||
| 151 | zero: bool, | ||
| 152 | negative: bool, | ||
| 153 | carry: bool, | ||
| 154 | carry_enabled: bool, | ||
| 155 | interrupt0_enabled: bool, | ||
| 156 | interrupt1_enabled: bool, | ||
| 157 | interrupt2_enabled: bool, | ||
| 158 | interrupt3_enabled: bool, | ||
| 159 | reserved: u8 = 0, | ||
| 160 | }; | ||
| 161 | |||
| 162 | pub const Register = enum { | ||
| 163 | dummy, | ||
| 164 | |||
| 165 | pub fn allocIndex(self: Register) ?u4 { | ||
| 166 | return null; | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | |||
| 170 | pub const callee_preserved_regs = [_]Register{}; | ||
src/codegen/spu-mk2/interpreter.zig deleted-166| ... | @@ -1,166 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const log = std.log.scoped(.SPU_2_Interpreter); | ||
| 3 | const spu = @import("../spu-mk2.zig"); | ||
| 4 | const FlagRegister = spu.FlagRegister; | ||
| 5 | const Instruction = spu.Instruction; | ||
| 6 | const ExecutionCondition = spu.ExecutionCondition; | ||
| 7 | |||
| 8 | pub fn Interpreter(comptime Bus: type) type { | ||
| 9 | return struct { | ||
| 10 | ip: u16 = 0, | ||
| 11 | sp: u16 = undefined, | ||
| 12 | bp: u16 = undefined, | ||
| 13 | fr: FlagRegister = @bitCast(FlagRegister, @as(u16, 0)), | ||
| 14 | /// This is set to true when we hit an undefined0 instruction, allowing it to | ||
| 15 | /// be used as a trap for testing purposes | ||
| 16 | undefined0: bool = false, | ||
| 17 | /// This is set to true when we hit an undefined1 instruction, allowing it to | ||
| 18 | /// be used as a trap for testing purposes. undefined1 is used as a breakpoint. | ||
| 19 | undefined1: bool = false, | ||
| 20 | bus: Bus, | ||
| 21 | |||
| 22 | pub fn ExecuteBlock(self: *@This(), comptime size: ?u32) !void { | ||
| 23 | var count: usize = 0; | ||
| 24 | while (size == null or count < size.?) { | ||
| 25 | count += 1; | ||
| 26 | var instruction = @bitCast(Instruction, self.bus.read16(self.ip)); | ||
| 27 | |||
| 28 | log.debug("Executing {}\n", .{instruction}); | ||
| 29 | |||
| 30 | self.ip +%= 2; | ||
| 31 | |||
| 32 | const execute = switch (instruction.condition) { | ||
| 33 | .always => true, | ||
| 34 | .not_zero => !self.fr.zero, | ||
| 35 | .when_zero => self.fr.zero, | ||
| 36 | .overflow => self.fr.carry, | ||
| 37 | ExecutionCondition.greater_or_equal_zero => !self.fr.negative, | ||
| 38 | else => return error.Unimplemented, | ||
| 39 | }; | ||
| 40 | |||
| 41 | if (execute) { | ||
| 42 | const val0 = switch (instruction.input0) { | ||
| 43 | .zero => @as(u16, 0), | ||
| 44 | .immediate => i: { | ||
| 45 | const val = self.bus.read16(@intCast(u16, self.ip)); | ||
| 46 | self.ip +%= 2; | ||
| 47 | break :i val; | ||
| 48 | }, | ||
| 49 | else => |e| e: { | ||
| 50 | // peek or pop; show value at current SP, and if pop, increment sp | ||
| 51 | const val = self.bus.read16(self.sp); | ||
| 52 | if (e == .pop) { | ||
| 53 | self.sp +%= 2; | ||
| 54 | } | ||
| 55 | break :e val; | ||
| 56 | }, | ||
| 57 | }; | ||
| 58 | const val1 = switch (instruction.input1) { | ||
| 59 | .zero => @as(u16, 0), | ||
| 60 | .immediate => i: { | ||
| 61 | const val = self.bus.read16(@intCast(u16, self.ip)); | ||
| 62 | self.ip +%= 2; | ||
| 63 | break :i val; | ||
| 64 | }, | ||
| 65 | else => |e| e: { | ||
| 66 | // peek or pop; show value at current SP, and if pop, increment sp | ||
| 67 | const val = self.bus.read16(self.sp); | ||
| 68 | if (e == .pop) { | ||
| 69 | self.sp +%= 2; | ||
| 70 | } | ||
| 71 | break :e val; | ||
| 72 | }, | ||
| 73 | }; | ||
| 74 | |||
| 75 | const output: u16 = switch (instruction.command) { | ||
| 76 | .get => self.bus.read16(self.bp +% (2 *% val0)), | ||
| 77 | .set => a: { | ||
| 78 | self.bus.write16(self.bp +% 2 *% val0, val1); | ||
| 79 | break :a val1; | ||
| 80 | }, | ||
| 81 | .load8 => self.bus.read8(val0), | ||
| 82 | .load16 => self.bus.read16(val0), | ||
| 83 | .store8 => a: { | ||
| 84 | const val = @truncate(u8, val1); | ||
| 85 | self.bus.write8(val0, val); | ||
| 86 | break :a val; | ||
| 87 | }, | ||
| 88 | .store16 => a: { | ||
| 89 | self.bus.write16(val0, val1); | ||
| 90 | break :a val1; | ||
| 91 | }, | ||
| 92 | .copy => val0, | ||
| 93 | .add => a: { | ||
| 94 | var val: u16 = undefined; | ||
| 95 | self.fr.carry = @addWithOverflow(u16, val0, val1, &val); | ||
| 96 | break :a val; | ||
| 97 | }, | ||
| 98 | .sub => a: { | ||
| 99 | var val: u16 = undefined; | ||
| 100 | self.fr.carry = @subWithOverflow(u16, val0, val1, &val); | ||
| 101 | break :a val; | ||
| 102 | }, | ||
| 103 | .spset => a: { | ||
| 104 | self.sp = val0; | ||
| 105 | break :a val0; | ||
| 106 | }, | ||
| 107 | .bpset => a: { | ||
| 108 | self.bp = val0; | ||
| 109 | break :a val0; | ||
| 110 | }, | ||
| 111 | .frset => a: { | ||
| 112 | const val = (@bitCast(u16, self.fr) & val1) | (val0 & ~val1); | ||
| 113 | self.fr = @bitCast(FlagRegister, val); | ||
| 114 | break :a val; | ||
| 115 | }, | ||
| 116 | .bswap => (val0 >> 8) | (val0 << 8), | ||
| 117 | .bpget => self.bp, | ||
| 118 | .spget => self.sp, | ||
| 119 | .ipget => self.ip +% (2 *% val0), | ||
| 120 | .lsl => val0 << 1, | ||
| 121 | .lsr => val0 >> 1, | ||
| 122 | .@"and" => val0 & val1, | ||
| 123 | .@"or" => val0 | val1, | ||
| 124 | .xor => val0 ^ val1, | ||
| 125 | .not => ~val0, | ||
| 126 | .undefined0 => { | ||
| 127 | self.undefined0 = true; | ||
| 128 | // Break out of the loop, and let the caller decide what to do | ||
| 129 | return; | ||
| 130 | }, | ||
| 131 | .undefined1 => { | ||
| 132 | self.undefined1 = true; | ||
| 133 | // Break out of the loop, and let the caller decide what to do | ||
| 134 | return; | ||
| 135 | }, | ||
| 136 | .signext => if ((val0 & 0x80) != 0) | ||
| 137 | (val0 & 0xFF) | 0xFF00 | ||
| 138 | else | ||
| 139 | (val0 & 0xFF), | ||
| 140 | else => return error.Unimplemented, | ||
| 141 | }; | ||
| 142 | |||
| 143 | switch (instruction.output) { | ||
| 144 | .discard => {}, | ||
| 145 | .push => { | ||
| 146 | self.sp -%= 2; | ||
| 147 | self.bus.write16(self.sp, output); | ||
| 148 | }, | ||
| 149 | .jump => { | ||
| 150 | self.ip = output; | ||
| 151 | }, | ||
| 152 | else => return error.Unimplemented, | ||
| 153 | } | ||
| 154 | if (instruction.modify_flags) { | ||
| 155 | self.fr.negative = (output & 0x8000) != 0; | ||
| 156 | self.fr.zero = (output == 0x0000); | ||
| 157 | } | ||
| 158 | } else { | ||
| 159 | if (instruction.input0 == .immediate) self.ip +%= 2; | ||
| 160 | if (instruction.input1 == .immediate) self.ip +%= 2; | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | }; | ||
| 166 | } | ||
src/codegen/wasm.zig+2-1| ... | @@ -591,7 +591,8 @@ pub const Context = struct { | ... | @@ -591,7 +591,8 @@ pub const Context = struct { |
| 591 | } | 591 | } |
| 592 | 592 | ||
| 593 | fn genFunctype(self: *Context) InnerError!void { | 593 | fn genFunctype(self: *Context) InnerError!void { |
| 594 | const ty = self.decl.typed_value.most_recent.typed_value.ty; | 594 | assert(self.decl.has_tv); |
| 595 | const ty = self.decl.ty; | ||
| 595 | const writer = self.func_type_data.writer(); | 596 | const writer = self.func_type_data.writer(); |
| 596 | 597 | ||
| 597 | try writer.writeByte(wasm.function_type); | 598 | try writer.writeByte(wasm.function_type); |
src/codegen/x86_64.zig+1-1| ... | @@ -171,7 +171,7 @@ pub const Encoder = struct { | ... | @@ -171,7 +171,7 @@ pub const Encoder = struct { |
| 171 | /// This is because the helper functions will assume capacity | 171 | /// This is because the helper functions will assume capacity |
| 172 | /// in order to avoid bounds checking. | 172 | /// in order to avoid bounds checking. |
| 173 | pub fn init(code: *ArrayList(u8), maximum_inst_size: u8) !Self { | 173 | pub fn init(code: *ArrayList(u8), maximum_inst_size: u8) !Self { |
| 174 | try code.ensureCapacity(code.items.len + maximum_inst_size); | 174 | try code.ensureUnusedCapacity(maximum_inst_size); |
| 175 | return Self{ .code = code }; | 175 | return Self{ .code = code }; |
| 176 | } | 176 | } |
| 177 | 177 |
src/ir.zig+6-3| ... | @@ -255,6 +255,9 @@ pub const Inst = struct { | ... | @@ -255,6 +255,9 @@ pub const Inst = struct { |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | /// Returns `null` if runtime-known. | 257 | /// Returns `null` if runtime-known. |
| 258 | /// Should be called by codegen, not by Sema. Sema functions should call | ||
| 259 | /// `resolvePossiblyUndefinedValue` or `resolveDefinedValue` instead. | ||
| 260 | /// TODO audit Sema code for violations to the above guidance. | ||
| 258 | pub fn value(base: *Inst) ?Value { | 261 | pub fn value(base: *Inst) ?Value { |
| 259 | if (base.ty.onePossibleValue()) |opv| return opv; | 262 | if (base.ty.onePossibleValue()) |opv| return opv; |
| 260 | 263 | ||
| ... | @@ -372,8 +375,7 @@ pub const Inst = struct { | ... | @@ -372,8 +375,7 @@ pub const Inst = struct { |
| 372 | base: Inst, | 375 | base: Inst, |
| 373 | asm_source: []const u8, | 376 | asm_source: []const u8, |
| 374 | is_volatile: bool, | 377 | is_volatile: bool, |
| 375 | output: ?*Inst, | 378 | output_constraint: ?[]const u8, |
| 376 | output_name: ?[]const u8, | ||
| 377 | inputs: []const []const u8, | 379 | inputs: []const []const u8, |
| 378 | clobbers: []const []const u8, | 380 | clobbers: []const []const u8, |
| 379 | args: []const *Inst, | 381 | args: []const *Inst, |
| ... | @@ -623,7 +625,8 @@ pub const Inst = struct { | ... | @@ -623,7 +625,8 @@ pub const Inst = struct { |
| 623 | pub const base_tag = Tag.dbg_stmt; | 625 | pub const base_tag = Tag.dbg_stmt; |
| 624 | 626 | ||
| 625 | base: Inst, | 627 | base: Inst, |
| 626 | byte_offset: u32, | 628 | line: u32, |
| 629 | column: u32, | ||
| 627 | 630 | ||
| 628 | pub fn operandCount(self: *const DbgStmt) usize { | 631 | pub fn operandCount(self: *const DbgStmt) usize { |
| 629 | return 0; | 632 | return 0; |
src/libc_installation.zig+2-2| ... | @@ -383,7 +383,7 @@ pub const LibCInstallation = struct { | ... | @@ -383,7 +383,7 @@ pub const LibCInstallation = struct { |
| 383 | var result_buf = std.ArrayList(u8).init(allocator); | 383 | var result_buf = std.ArrayList(u8).init(allocator); |
| 384 | defer result_buf.deinit(); | 384 | defer result_buf.deinit(); |
| 385 | 385 | ||
| 386 | const arch_sub_dir = switch (builtin.arch) { | 386 | const arch_sub_dir = switch (builtin.target.cpu.arch) { |
| 387 | .i386 => "x86", | 387 | .i386 => "x86", |
| 388 | .x86_64 => "x64", | 388 | .x86_64 => "x64", |
| 389 | .arm, .armeb => "arm", | 389 | .arm, .armeb => "arm", |
| ... | @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { | ... | @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { |
| 437 | var result_buf = std.ArrayList(u8).init(allocator); | 437 | var result_buf = std.ArrayList(u8).init(allocator); |
| 438 | defer result_buf.deinit(); | 438 | defer result_buf.deinit(); |
| 439 | 439 | ||
| 440 | const arch_sub_dir = switch (builtin.arch) { | 440 | const arch_sub_dir = switch (builtin.target.cpu.arch) { |
| 441 | .i386 => "x86", | 441 | .i386 => "x86", |
| 442 | .x86_64 => "x64", | 442 | .x86_64 => "x64", |
| 443 | .arm, .armeb => "arm", | 443 | .arm, .armeb => "arm", |
src/link.zig+12-1| ... | @@ -30,7 +30,7 @@ pub const Options = struct { | ... | @@ -30,7 +30,7 @@ pub const Options = struct { |
| 30 | target: std.Target, | 30 | target: std.Target, |
| 31 | output_mode: std.builtin.OutputMode, | 31 | output_mode: std.builtin.OutputMode, |
| 32 | link_mode: std.builtin.LinkMode, | 32 | link_mode: std.builtin.LinkMode, |
| 33 | object_format: std.builtin.ObjectFormat, | 33 | object_format: std.Target.ObjectFormat, |
| 34 | optimize_mode: std.builtin.Mode, | 34 | optimize_mode: std.builtin.Mode, |
| 35 | machine_code_model: std.builtin.CodeModel, | 35 | machine_code_model: std.builtin.CodeModel, |
| 36 | root_name: []const u8, | 36 | root_name: []const u8, |
| ... | @@ -301,6 +301,8 @@ pub const File = struct { | ... | @@ -301,6 +301,8 @@ pub const File = struct { |
| 301 | /// May be called before or after updateDeclExports but must be called | 301 | /// May be called before or after updateDeclExports but must be called |
| 302 | /// after allocateDeclIndexes for any given Decl. | 302 | /// after allocateDeclIndexes for any given Decl. |
| 303 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { | 303 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 304 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty }); | ||
| 305 | assert(decl.has_tv); | ||
| 304 | switch (base.tag) { | 306 | switch (base.tag) { |
| 305 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl), | 307 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl), |
| 306 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), | 308 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), |
| ... | @@ -312,6 +314,10 @@ pub const File = struct { | ... | @@ -312,6 +314,10 @@ pub const File = struct { |
| 312 | } | 314 | } |
| 313 | 315 | ||
| 314 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { | 316 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 317 | log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ | ||
| 318 | decl, decl.name, decl.src_line + 1, | ||
| 319 | }); | ||
| 320 | assert(decl.has_tv); | ||
| 315 | switch (base.tag) { | 321 | switch (base.tag) { |
| 316 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), | 322 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), |
| 317 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), | 323 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), |
| ... | @@ -324,6 +330,7 @@ pub const File = struct { | ... | @@ -324,6 +330,7 @@ pub const File = struct { |
| 324 | /// Must be called before any call to updateDecl or updateDeclExports for | 330 | /// Must be called before any call to updateDecl or updateDeclExports for |
| 325 | /// any given Decl. | 331 | /// any given Decl. |
| 326 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { | 332 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { |
| 333 | log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name }); | ||
| 327 | switch (base.tag) { | 334 | switch (base.tag) { |
| 328 | .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl), | 335 | .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl), |
| 329 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), | 336 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), |
| ... | @@ -351,6 +358,7 @@ pub const File = struct { | ... | @@ -351,6 +358,7 @@ pub const File = struct { |
| 351 | base.releaseLock(); | 358 | base.releaseLock(); |
| 352 | if (base.file) |f| f.close(); | 359 | if (base.file) |f| f.close(); |
| 353 | if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path); | 360 | if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path); |
| 361 | base.options.system_libs.deinit(base.allocator); | ||
| 354 | switch (base.tag) { | 362 | switch (base.tag) { |
| 355 | .coff => { | 363 | .coff => { |
| 356 | const parent = @fieldParentPtr(Coff, "base", base); | 364 | const parent = @fieldParentPtr(Coff, "base", base); |
| ... | @@ -434,6 +442,7 @@ pub const File = struct { | ... | @@ -434,6 +442,7 @@ pub const File = struct { |
| 434 | 442 | ||
| 435 | /// Called when a Decl is deleted from the Module. | 443 | /// Called when a Decl is deleted from the Module. |
| 436 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { | 444 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { |
| 445 | log.debug("freeDecl {*} ({s})", .{ decl, decl.name }); | ||
| 437 | switch (base.tag) { | 446 | switch (base.tag) { |
| 438 | .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl), | 447 | .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl), |
| 439 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), | 448 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), |
| ... | @@ -462,6 +471,8 @@ pub const File = struct { | ... | @@ -462,6 +471,8 @@ pub const File = struct { |
| 462 | decl: *Module.Decl, | 471 | decl: *Module.Decl, |
| 463 | exports: []const *Module.Export, | 472 | exports: []const *Module.Export, |
| 464 | ) !void { | 473 | ) !void { |
| 474 | log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); | ||
| 475 | assert(decl.has_tv); | ||
| 465 | switch (base.tag) { | 476 | switch (base.tag) { |
| 466 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl, exports), | 477 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl, exports), |
| 467 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), | 478 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), |
src/link/C.zig+54-53| ... | @@ -15,6 +15,10 @@ pub const base_tag: link.File.Tag = .c; | ... | @@ -15,6 +15,10 @@ pub const base_tag: link.File.Tag = .c; |
| 15 | pub const zig_h = @embedFile("C/zig.h"); | 15 | pub const zig_h = @embedFile("C/zig.h"); |
| 16 | 16 | ||
| 17 | base: link.File, | 17 | base: link.File, |
| 18 | /// This linker backend does not try to incrementally link output C source code. | ||
| 19 | /// Instead, it tracks all declarations in this table, and iterates over it | ||
| 20 | /// in the flush function, stitching pre-rendered pieces of C code together. | ||
| 21 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, | ||
| 18 | 22 | ||
| 19 | /// Per-declaration data. For functions this is the body, and | 23 | /// Per-declaration data. For functions this is the body, and |
| 20 | /// the forward declaration is stored in the FnBlock. | 24 | /// the forward declaration is stored in the FnBlock. |
| ... | @@ -66,15 +70,16 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -66,15 +70,16 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 68 | pub fn deinit(self: *C) void { | 72 | pub fn deinit(self: *C) void { |
| 69 | const module = self.base.options.module orelse return; | 73 | for (self.decl_table.items()) |entry| { |
| 70 | for (module.decl_table.items()) |entry| { | 74 | self.freeDecl(entry.key); |
| 71 | self.freeDecl(entry.value); | ||
| 72 | } | 75 | } |
| 76 | self.decl_table.deinit(self.base.allocator); | ||
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | pub fn allocateDeclIndexes(self: *C, decl: *Module.Decl) !void {} | 79 | pub fn allocateDeclIndexes(self: *C, decl: *Module.Decl) !void {} |
| 76 | 80 | ||
| 77 | pub fn freeDecl(self: *C, decl: *Module.Decl) void { | 81 | pub fn freeDecl(self: *C, decl: *Module.Decl) void { |
| 82 | _ = self.decl_table.swapRemove(decl); | ||
| 78 | decl.link.c.code.deinit(self.base.allocator); | 83 | decl.link.c.code.deinit(self.base.allocator); |
| 79 | decl.fn_link.c.fwd_decl.deinit(self.base.allocator); | 84 | decl.fn_link.c.fwd_decl.deinit(self.base.allocator); |
| 80 | var it = decl.fn_link.c.typedefs.iterator(); | 85 | var it = decl.fn_link.c.typedefs.iterator(); |
| ... | @@ -88,6 +93,9 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | ... | @@ -88,6 +93,9 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { |
| 88 | const tracy = trace(@src()); | 93 | const tracy = trace(@src()); |
| 89 | defer tracy.end(); | 94 | defer tracy.end(); |
| 90 | 95 | ||
| 96 | // Keep track of all decls so we can iterate over them on flush(). | ||
| 97 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | ||
| 98 | |||
| 91 | const fwd_decl = &decl.fn_link.c.fwd_decl; | 99 | const fwd_decl = &decl.fn_link.c.fwd_decl; |
| 92 | const typedefs = &decl.fn_link.c.typedefs; | 100 | const typedefs = &decl.fn_link.c.typedefs; |
| 93 | const code = &decl.link.c.code; | 101 | const code = &decl.link.c.code; |
| ... | @@ -168,7 +176,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { | ... | @@ -168,7 +176,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { |
| 168 | defer all_buffers.deinit(); | 176 | defer all_buffers.deinit(); |
| 169 | 177 | ||
| 170 | // This is at least enough until we get to the function bodies without error handling. | 178 | // This is at least enough until we get to the function bodies without error handling. |
| 171 | try all_buffers.ensureCapacity(module.decl_table.count() + 2); | 179 | try all_buffers.ensureCapacity(self.decl_table.count() + 2); |
| 172 | 180 | ||
| 173 | var file_size: u64 = zig_h.len; | 181 | var file_size: u64 = zig_h.len; |
| 174 | all_buffers.appendAssumeCapacity(.{ | 182 | all_buffers.appendAssumeCapacity(.{ |
| ... | @@ -197,36 +205,32 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { | ... | @@ -197,36 +205,32 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { |
| 197 | // Typedefs, forward decls and non-functions first. | 205 | // Typedefs, forward decls and non-functions first. |
| 198 | // TODO: performance investigation: would keeping a list of Decls that we should | 206 | // TODO: performance investigation: would keeping a list of Decls that we should |
| 199 | // generate, rather than querying here, be faster? | 207 | // generate, rather than querying here, be faster? |
| 200 | for (module.decl_table.items()) |kv| { | 208 | for (self.decl_table.items()) |kv| { |
| 201 | const decl = kv.value; | 209 | const decl = kv.key; |
| 202 | switch (decl.typed_value) { | 210 | if (!decl.has_tv) continue; |
| 203 | .most_recent => |tvm| { | 211 | const buf = buf: { |
| 204 | const buf = buf: { | 212 | if (decl.val.castTag(.function)) |_| { |
| 205 | if (tvm.typed_value.val.castTag(.function)) |_| { | 213 | var it = decl.fn_link.c.typedefs.iterator(); |
| 206 | var it = decl.fn_link.c.typedefs.iterator(); | 214 | while (it.next()) |new| { |
| 207 | while (it.next()) |new| { | 215 | if (typedefs.get(new.key)) |previous| { |
| 208 | if (typedefs.get(new.key)) |previous| { | 216 | try err_typedef_writer.print("typedef {s} {s};\n", .{ previous, new.value.name }); |
| 209 | try err_typedef_writer.print("typedef {s} {s};\n", .{ previous, new.value.name }); | ||
| 210 | } else { | ||
| 211 | try typedefs.ensureCapacity(typedefs.capacity() + 1); | ||
| 212 | try err_typedef_writer.writeAll(new.value.rendered); | ||
| 213 | typedefs.putAssumeCapacityNoClobber(new.key, new.value.name); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | fn_count += 1; | ||
| 217 | break :buf decl.fn_link.c.fwd_decl.items; | ||
| 218 | } else { | 217 | } else { |
| 219 | break :buf decl.link.c.code.items; | 218 | try typedefs.ensureCapacity(typedefs.capacity() + 1); |
| 219 | try err_typedef_writer.writeAll(new.value.rendered); | ||
| 220 | typedefs.putAssumeCapacityNoClobber(new.key, new.value.name); | ||
| 220 | } | 221 | } |
| 221 | }; | 222 | } |
| 222 | all_buffers.appendAssumeCapacity(.{ | 223 | fn_count += 1; |
| 223 | .iov_base = buf.ptr, | 224 | break :buf decl.fn_link.c.fwd_decl.items; |
| 224 | .iov_len = buf.len, | 225 | } else { |
| 225 | }); | 226 | break :buf decl.link.c.code.items; |
| 226 | file_size += buf.len; | 227 | } |
| 227 | }, | 228 | }; |
| 228 | .never_succeeded => continue, | 229 | all_buffers.appendAssumeCapacity(.{ |
| 229 | } | 230 | .iov_base = buf.ptr, |
| 231 | .iov_len = buf.len, | ||
| 232 | }); | ||
| 233 | file_size += buf.len; | ||
| 230 | } | 234 | } |
| 231 | 235 | ||
| 232 | err_typedef_item.* = .{ | 236 | err_typedef_item.* = .{ |
| ... | @@ -237,20 +241,16 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { | ... | @@ -237,20 +241,16 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { |
| 237 | 241 | ||
| 238 | // Now the function bodies. | 242 | // Now the function bodies. |
| 239 | try all_buffers.ensureCapacity(all_buffers.items.len + fn_count); | 243 | try all_buffers.ensureCapacity(all_buffers.items.len + fn_count); |
| 240 | for (module.decl_table.items()) |kv| { | 244 | for (self.decl_table.items()) |kv| { |
| 241 | const decl = kv.value; | 245 | const decl = kv.key; |
| 242 | switch (decl.typed_value) { | 246 | if (!decl.has_tv) continue; |
| 243 | .most_recent => |tvm| { | 247 | if (decl.val.castTag(.function)) |_| { |
| 244 | if (tvm.typed_value.val.castTag(.function)) |_| { | 248 | const buf = decl.link.c.code.items; |
| 245 | const buf = decl.link.c.code.items; | 249 | all_buffers.appendAssumeCapacity(.{ |
| 246 | all_buffers.appendAssumeCapacity(.{ | 250 | .iov_base = buf.ptr, |
| 247 | .iov_base = buf.ptr, | 251 | .iov_len = buf.len, |
| 248 | .iov_len = buf.len, | 252 | }); |
| 249 | }); | 253 | file_size += buf.len; |
| 250 | file_size += buf.len; | ||
| 251 | } | ||
| 252 | }, | ||
| 253 | .never_succeeded => continue, | ||
| 254 | } | 254 | } |
| 255 | } | 255 | } |
| 256 | 256 | ||
| ... | @@ -263,13 +263,13 @@ pub fn flushEmitH(module: *Module) !void { | ... | @@ -263,13 +263,13 @@ pub fn flushEmitH(module: *Module) !void { |
| 263 | const tracy = trace(@src()); | 263 | const tracy = trace(@src()); |
| 264 | defer tracy.end(); | 264 | defer tracy.end(); |
| 265 | 265 | ||
| 266 | const emit_h_loc = module.emit_h orelse return; | 266 | const emit_h = module.emit_h orelse return; |
| 267 | 267 | ||
| 268 | // We collect a list of buffers to write, and write them all at once with pwritev 😎 | 268 | // We collect a list of buffers to write, and write them all at once with pwritev 😎 |
| 269 | var all_buffers = std.ArrayList(std.os.iovec_const).init(module.gpa); | 269 | var all_buffers = std.ArrayList(std.os.iovec_const).init(module.gpa); |
| 270 | defer all_buffers.deinit(); | 270 | defer all_buffers.deinit(); |
| 271 | 271 | ||
| 272 | try all_buffers.ensureCapacity(module.decl_table.count() + 1); | 272 | try all_buffers.ensureCapacity(emit_h.decl_table.count() + 1); |
| 273 | 273 | ||
| 274 | var file_size: u64 = zig_h.len; | 274 | var file_size: u64 = zig_h.len; |
| 275 | all_buffers.appendAssumeCapacity(.{ | 275 | all_buffers.appendAssumeCapacity(.{ |
| ... | @@ -277,9 +277,10 @@ pub fn flushEmitH(module: *Module) !void { | ... | @@ -277,9 +277,10 @@ pub fn flushEmitH(module: *Module) !void { |
| 277 | .iov_len = zig_h.len, | 277 | .iov_len = zig_h.len, |
| 278 | }); | 278 | }); |
| 279 | 279 | ||
| 280 | for (module.decl_table.items()) |kv| { | 280 | for (emit_h.decl_table.items()) |kv| { |
| 281 | const emit_h = kv.value.getEmitH(module); | 281 | const decl = kv.key; |
| 282 | const buf = emit_h.fwd_decl.items; | 282 | const decl_emit_h = decl.getEmitH(module); |
| 283 | const buf = decl_emit_h.fwd_decl.items; | ||
| 283 | all_buffers.appendAssumeCapacity(.{ | 284 | all_buffers.appendAssumeCapacity(.{ |
| 284 | .iov_base = buf.ptr, | 285 | .iov_base = buf.ptr, |
| 285 | .iov_len = buf.len, | 286 | .iov_len = buf.len, |
| ... | @@ -287,8 +288,8 @@ pub fn flushEmitH(module: *Module) !void { | ... | @@ -287,8 +288,8 @@ pub fn flushEmitH(module: *Module) !void { |
| 287 | file_size += buf.len; | 288 | file_size += buf.len; |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | const directory = emit_h_loc.directory orelse module.comp.local_cache_directory; | 291 | const directory = emit_h.loc.directory orelse module.comp.local_cache_directory; |
| 291 | const file = try directory.handle.createFile(emit_h_loc.basename, .{ | 292 | const file = try directory.handle.createFile(emit_h.loc.basename, .{ |
| 292 | // We set the end position explicitly below; by not truncating the file, we possibly | 293 | // We set the end position explicitly below; by not truncating the file, we possibly |
| 293 | // make it easier on the file system by doing 1 reallocation instead of two. | 294 | // make it easier on the file system by doing 1 reallocation instead of two. |
| 294 | .truncate = false, | 295 | .truncate = false, |
src/link/C/zig.h+18-14| ... | @@ -1,25 +1,15 @@ | ... | @@ -1,25 +1,15 @@ |
| 1 | #if __STDC_VERSION__ >= 199901L | ||
| 2 | #include <stdbool.h> | ||
| 3 | #else | ||
| 4 | #define bool unsigned char | ||
| 5 | #define true 1 | ||
| 6 | #define false 0 | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #if __STDC_VERSION__ >= 201112L | 1 | #if __STDC_VERSION__ >= 201112L |
| 10 | #define zig_noreturn _Noreturn | 2 | #define zig_noreturn _Noreturn |
| 3 | #define zig_threadlocal thread_local | ||
| 11 | #elif __GNUC__ | 4 | #elif __GNUC__ |
| 12 | #define zig_noreturn __attribute__ ((noreturn)) | 5 | #define zig_noreturn __attribute__ ((noreturn)) |
| 6 | #define zig_threadlocal __thread | ||
| 13 | #elif _MSC_VER | 7 | #elif _MSC_VER |
| 14 | #define zig_noreturn __declspec(noreturn) | 8 | #define zig_noreturn __declspec(noreturn) |
| 9 | #define zig_threadlocal __declspec(thread) | ||
| 15 | #else | 10 | #else |
| 16 | #define zig_noreturn | 11 | #define zig_noreturn |
| 17 | #endif | 12 | #define zig_threadlocal zig_threadlocal_unavailable |
| 18 | |||
| 19 | #if defined(__GNUC__) | ||
| 20 | #define zig_unreachable() __builtin_unreachable() | ||
| 21 | #else | ||
| 22 | #define zig_unreachable() | ||
| 23 | #endif | 13 | #endif |
| 24 | 14 | ||
| 25 | #if __STDC_VERSION__ >= 199901L | 15 | #if __STDC_VERSION__ >= 199901L |
| ... | @@ -30,6 +20,20 @@ | ... | @@ -30,6 +20,20 @@ |
| 30 | #define ZIG_RESTRICT | 20 | #define ZIG_RESTRICT |
| 31 | #endif | 21 | #endif |
| 32 | 22 | ||
| 23 | #if __STDC_VERSION__ >= 199901L | ||
| 24 | #include <stdbool.h> | ||
| 25 | #else | ||
| 26 | #define bool unsigned char | ||
| 27 | #define true 1 | ||
| 28 | #define false 0 | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if defined(__GNUC__) | ||
| 32 | #define zig_unreachable() __builtin_unreachable() | ||
| 33 | #else | ||
| 34 | #define zig_unreachable() | ||
| 35 | #endif | ||
| 36 | |||
| 33 | #ifdef __cplusplus | 37 | #ifdef __cplusplus |
| 34 | #define ZIG_EXTERN_C extern "C" | 38 | #define ZIG_EXTERN_C extern "C" |
| 35 | #else | 39 | #else |
src/link/Coff.zig+6-4| ... | @@ -662,15 +662,17 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ... | @@ -662,15 +662,17 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 662 | if (build_options.have_llvm) | 662 | if (build_options.have_llvm) |
| 663 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); | 663 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); |
| 664 | 664 | ||
| 665 | const typed_value = decl.typed_value.most_recent.typed_value; | 665 | if (decl.val.tag() == .extern_fn) { |
| 666 | if (typed_value.val.tag() == .extern_fn) { | ||
| 667 | return; // TODO Should we do more when front-end analyzed extern decl? | 666 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 668 | } | 667 | } |
| 669 | 668 | ||
| 670 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 669 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 671 | defer code_buffer.deinit(); | 670 | defer code_buffer.deinit(); |
| 672 | 671 | ||
| 673 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none); | 672 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 673 | .ty = decl.ty, | ||
| 674 | .val = decl.val, | ||
| 675 | }, &code_buffer, .none); | ||
| 674 | const code = switch (res) { | 676 | const code = switch (res) { |
| 675 | .externally_managed => |x| x, | 677 | .externally_managed => |x| x, |
| 676 | .appended => code_buffer.items, | 678 | .appended => code_buffer.items, |
| ... | @@ -681,7 +683,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ... | @@ -681,7 +683,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 681 | }, | 683 | }, |
| 682 | }; | 684 | }; |
| 683 | 685 | ||
| 684 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 686 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 685 | const curr_size = decl.link.coff.size; | 687 | const curr_size = decl.link.coff.size; |
| 686 | if (curr_size != 0) { | 688 | if (curr_size != 0) { |
| 687 | const capacity = decl.link.coff.capacity(); | 689 | const capacity = decl.link.coff.capacity(); |
src/link/Elf.zig+19-35| ... | @@ -2183,10 +2183,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2183,10 +2183,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2183 | if (build_options.have_llvm) | 2183 | if (build_options.have_llvm) |
| 2184 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); | 2184 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); |
| 2185 | 2185 | ||
| 2186 | const typed_value = decl.typed_value.most_recent.typed_value; | 2186 | if (decl.val.tag() == .extern_fn) { |
| 2187 | if (typed_value.val.tag() == .extern_fn) { | ||
| 2188 | return; // TODO Should we do more when front-end analyzed extern decl? | 2187 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2189 | } | 2188 | } |
| 2189 | if (decl.val.castTag(.variable)) |payload| { | ||
| 2190 | const variable = payload.data; | ||
| 2191 | if (variable.is_extern) { | ||
| 2192 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2193 | } | ||
| 2194 | } | ||
| 2190 | 2195 | ||
| 2191 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 2196 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2192 | defer code_buffer.deinit(); | 2197 | defer code_buffer.deinit(); |
| ... | @@ -2206,7 +2211,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2206,7 +2211,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2206 | dbg_info_type_relocs.deinit(self.base.allocator); | 2211 | dbg_info_type_relocs.deinit(self.base.allocator); |
| 2207 | } | 2212 | } |
| 2208 | 2213 | ||
| 2209 | const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { | 2214 | const is_fn: bool = switch (decl.ty.zigTypeTag()) { |
| 2210 | .Fn => true, | 2215 | .Fn => true, |
| 2211 | else => false, | 2216 | else => false, |
| 2212 | }; | 2217 | }; |
| ... | @@ -2214,21 +2219,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2214,21 +2219,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2214 | // For functions we need to add a prologue to the debug line program. | 2219 | // For functions we need to add a prologue to the debug line program. |
| 2215 | try dbg_line_buffer.ensureCapacity(26); | 2220 | try dbg_line_buffer.ensureCapacity(26); |
| 2216 | 2221 | ||
| 2217 | const line_off: u28 = blk: { | 2222 | const func = decl.val.castTag(.function).?.data; |
| 2218 | const tree = decl.container.file_scope.tree; | 2223 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 2219 | const node_tags = tree.nodes.items(.tag); | ||
| 2220 | const node_datas = tree.nodes.items(.data); | ||
| 2221 | const token_starts = tree.tokens.items(.start); | ||
| 2222 | |||
| 2223 | // TODO Look into improving the performance here by adding a token-index-to-line | ||
| 2224 | // lookup table. Currently this involves scanning over the source code for newlines. | ||
| 2225 | const fn_decl = decl.src_node; | ||
| 2226 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 2227 | const block = node_datas[fn_decl].rhs; | ||
| 2228 | const lbrace = tree.firstToken(block); | ||
| 2229 | const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); | ||
| 2230 | break :blk @intCast(u28, line_delta); | ||
| 2231 | }; | ||
| 2232 | 2224 | ||
| 2233 | const ptr_width_bytes = self.ptrWidthBytes(); | 2225 | const ptr_width_bytes = self.ptrWidthBytes(); |
| 2234 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | 2226 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ |
| ... | @@ -2262,7 +2254,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2262,7 +2254,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2262 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; | 2254 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; |
| 2263 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); | 2255 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); |
| 2264 | 2256 | ||
| 2265 | const fn_ret_type = typed_value.ty.fnReturnType(); | 2257 | const fn_ret_type = decl.ty.fnReturnType(); |
| 2266 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | 2258 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); |
| 2267 | if (fn_ret_has_bits) { | 2259 | if (fn_ret_has_bits) { |
| 2268 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | 2260 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); |
| ... | @@ -2291,7 +2283,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2291,7 +2283,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2291 | } else { | 2283 | } else { |
| 2292 | // TODO implement .debug_info for global variables | 2284 | // TODO implement .debug_info for global variables |
| 2293 | } | 2285 | } |
| 2294 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | 2286 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 2287 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | ||
| 2288 | .ty = decl.ty, | ||
| 2289 | .val = decl_val, | ||
| 2290 | }, &code_buffer, .{ | ||
| 2295 | .dwarf = .{ | 2291 | .dwarf = .{ |
| 2296 | .dbg_line = &dbg_line_buffer, | 2292 | .dbg_line = &dbg_line_buffer, |
| 2297 | .dbg_info = &dbg_info_buffer, | 2293 | .dbg_info = &dbg_info_buffer, |
| ... | @@ -2308,7 +2304,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2308,7 +2304,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2308 | }, | 2304 | }, |
| 2309 | }; | 2305 | }; |
| 2310 | 2306 | ||
| 2311 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 2307 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 2312 | 2308 | ||
| 2313 | const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; | 2309 | const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; |
| 2314 | 2310 | ||
| ... | @@ -2670,7 +2666,6 @@ pub fn updateDeclExports( | ... | @@ -2670,7 +2666,6 @@ pub fn updateDeclExports( |
| 2670 | defer tracy.end(); | 2666 | defer tracy.end(); |
| 2671 | 2667 | ||
| 2672 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); | 2668 | try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len); |
| 2673 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 2674 | if (decl.link.elf.local_sym_index == 0) return; | 2669 | if (decl.link.elf.local_sym_index == 0) return; |
| 2675 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; | 2670 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2676 | 2671 | ||
| ... | @@ -2741,19 +2736,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec | ... | @@ -2741,19 +2736,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec |
| 2741 | 2736 | ||
| 2742 | if (self.llvm_object) |_| return; | 2737 | if (self.llvm_object) |_| return; |
| 2743 | 2738 | ||
| 2744 | const tree = decl.container.file_scope.tree; | 2739 | const func = decl.val.castTag(.function).?.data; |
| 2745 | const node_tags = tree.nodes.items(.tag); | 2740 | const casted_line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 2746 | const node_datas = tree.nodes.items(.data); | ||
| 2747 | const token_starts = tree.tokens.items(.start); | ||
| 2748 | |||
| 2749 | // TODO Look into improving the performance here by adding a token-index-to-line | ||
| 2750 | // lookup table. Currently this involves scanning over the source code for newlines. | ||
| 2751 | const fn_decl = decl.src_node; | ||
| 2752 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 2753 | const block = node_datas[fn_decl].rhs; | ||
| 2754 | const lbrace = tree.firstToken(block); | ||
| 2755 | const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); | ||
| 2756 | const casted_line_off = @intCast(u28, line_delta); | ||
| 2757 | 2741 | ||
| 2758 | const shdr = &self.sections.items[self.debug_line_section_index.?]; | 2742 | const shdr = &self.sections.items[self.debug_line_section_index.?]; |
| 2759 | const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); | 2743 | const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); |
src/link/MachO.zig+56-5| ... | @@ -1200,6 +1200,15 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -1200,6 +1200,15 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 1200 | // TODO shrink the __text section size here | 1200 | // TODO shrink the __text section size here |
| 1201 | self.last_text_block = text_block.prev; | 1201 | self.last_text_block = text_block.prev; |
| 1202 | } | 1202 | } |
| 1203 | if (self.d_sym) |*ds| { | ||
| 1204 | if (ds.dbg_info_decl_first == text_block) { | ||
| 1205 | ds.dbg_info_decl_first = text_block.dbg_info_next; | ||
| 1206 | } | ||
| 1207 | if (ds.dbg_info_decl_last == text_block) { | ||
| 1208 | // TODO shrink the .debug_info section size here | ||
| 1209 | ds.dbg_info_decl_last = text_block.dbg_info_prev; | ||
| 1210 | } | ||
| 1211 | } | ||
| 1203 | 1212 | ||
| 1204 | if (text_block.prev) |prev| { | 1213 | if (text_block.prev) |prev| { |
| 1205 | prev.next = text_block.next; | 1214 | prev.next = text_block.next; |
| ... | @@ -1218,6 +1227,20 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { | ... | @@ -1218,6 +1227,20 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 1218 | } else { | 1227 | } else { |
| 1219 | text_block.next = null; | 1228 | text_block.next = null; |
| 1220 | } | 1229 | } |
| 1230 | |||
| 1231 | if (text_block.dbg_info_prev) |prev| { | ||
| 1232 | prev.dbg_info_next = text_block.dbg_info_next; | ||
| 1233 | |||
| 1234 | // TODO the free list logic like we do for text blocks above | ||
| 1235 | } else { | ||
| 1236 | text_block.dbg_info_prev = null; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | if (text_block.dbg_info_next) |next| { | ||
| 1240 | next.dbg_info_prev = text_block.dbg_info_prev; | ||
| 1241 | } else { | ||
| 1242 | text_block.dbg_info_next = null; | ||
| 1243 | } | ||
| 1221 | } | 1244 | } |
| 1222 | 1245 | ||
| 1223 | fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) void { | 1246 | fn shrinkTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64) void { |
| ... | @@ -1277,8 +1300,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1277,8 +1300,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1277 | const tracy = trace(@src()); | 1300 | const tracy = trace(@src()); |
| 1278 | defer tracy.end(); | 1301 | defer tracy.end(); |
| 1279 | 1302 | ||
| 1280 | const typed_value = decl.typed_value.most_recent.typed_value; | 1303 | if (decl.val.tag() == .extern_fn) { |
| 1281 | if (typed_value.val.tag() == .extern_fn) { | ||
| 1282 | return; // TODO Should we do more when front-end analyzed extern decl? | 1304 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1283 | } | 1305 | } |
| 1284 | 1306 | ||
| ... | @@ -1299,7 +1321,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1299,7 +1321,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1299 | } | 1321 | } |
| 1300 | 1322 | ||
| 1301 | const res = if (debug_buffers) |*dbg| | 1323 | const res = if (debug_buffers) |*dbg| |
| 1302 | try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | 1324 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 1325 | .ty = decl.ty, | ||
| 1326 | .val = decl.val, | ||
| 1327 | }, &code_buffer, .{ | ||
| 1303 | .dwarf = .{ | 1328 | .dwarf = .{ |
| 1304 | .dbg_line = &dbg.dbg_line_buffer, | 1329 | .dbg_line = &dbg.dbg_line_buffer, |
| 1305 | .dbg_info = &dbg.dbg_info_buffer, | 1330 | .dbg_info = &dbg.dbg_info_buffer, |
| ... | @@ -1307,7 +1332,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1307,7 +1332,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1307 | }, | 1332 | }, |
| 1308 | }) | 1333 | }) |
| 1309 | else | 1334 | else |
| 1310 | try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none); | 1335 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 1336 | .ty = decl.ty, | ||
| 1337 | .val = decl.val, | ||
| 1338 | }, &code_buffer, .none); | ||
| 1311 | 1339 | ||
| 1312 | const code = switch (res) { | 1340 | const code = switch (res) { |
| 1313 | .externally_managed => |x| x, | 1341 | .externally_managed => |x| x, |
| ... | @@ -1323,7 +1351,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1323,7 +1351,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1323 | }, | 1351 | }, |
| 1324 | }; | 1352 | }; |
| 1325 | 1353 | ||
| 1326 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 1354 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 1327 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() | 1355 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() |
| 1328 | const symbol = &self.locals.items[decl.link.macho.local_sym_index]; | 1356 | const symbol = &self.locals.items[decl.link.macho.local_sym_index]; |
| 1329 | 1357 | ||
| ... | @@ -1599,6 +1627,29 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -1599,6 +1627,29 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 1599 | 1627 | ||
| 1600 | decl.link.macho.local_sym_index = 0; | 1628 | decl.link.macho.local_sym_index = 0; |
| 1601 | } | 1629 | } |
| 1630 | if (self.d_sym) |*ds| { | ||
| 1631 | // TODO make this logic match freeTextBlock. Maybe abstract the logic | ||
| 1632 | // out since the same thing is desired for both. | ||
| 1633 | _ = ds.dbg_line_fn_free_list.remove(&decl.fn_link.macho); | ||
| 1634 | if (decl.fn_link.macho.prev) |prev| { | ||
| 1635 | ds.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | ||
| 1636 | prev.next = decl.fn_link.macho.next; | ||
| 1637 | if (decl.fn_link.macho.next) |next| { | ||
| 1638 | next.prev = prev; | ||
| 1639 | } else { | ||
| 1640 | ds.dbg_line_fn_last = prev; | ||
| 1641 | } | ||
| 1642 | } else if (decl.fn_link.macho.next) |next| { | ||
| 1643 | ds.dbg_line_fn_first = next; | ||
| 1644 | next.prev = null; | ||
| 1645 | } | ||
| 1646 | if (ds.dbg_line_fn_first == &decl.fn_link.macho) { | ||
| 1647 | ds.dbg_line_fn_first = decl.fn_link.macho.next; | ||
| 1648 | } | ||
| 1649 | if (ds.dbg_line_fn_last == &decl.fn_link.macho) { | ||
| 1650 | ds.dbg_line_fn_last = decl.fn_link.macho.prev; | ||
| 1651 | } | ||
| 1652 | } | ||
| 1602 | } | 1653 | } |
| 1603 | 1654 | ||
| 1604 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | 1655 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
src/link/MachO/DebugSymbols.zig+16-46| ... | @@ -904,25 +904,19 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M | ... | @@ -904,25 +904,19 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M |
| 904 | const tracy = trace(@src()); | 904 | const tracy = trace(@src()); |
| 905 | defer tracy.end(); | 905 | defer tracy.end(); |
| 906 | 906 | ||
| 907 | const tree = decl.container.file_scope.tree; | 907 | const tree = decl.namespace.file_scope.tree; |
| 908 | const node_tags = tree.nodes.items(.tag); | 908 | const node_tags = tree.nodes.items(.tag); |
| 909 | const node_datas = tree.nodes.items(.data); | 909 | const node_datas = tree.nodes.items(.data); |
| 910 | const token_starts = tree.tokens.items(.start); | 910 | const token_starts = tree.tokens.items(.start); |
| 911 | 911 | ||
| 912 | // TODO Look into improving the performance here by adding a token-index-to-line | 912 | const func = decl.val.castTag(.function).?.data; |
| 913 | // lookup table. Currently this involves scanning over the source code for newlines. | 913 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 914 | const fn_decl = decl.src_node; | ||
| 915 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 916 | const block = node_datas[fn_decl].rhs; | ||
| 917 | const lbrace = tree.firstToken(block); | ||
| 918 | const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); | ||
| 919 | const casted_line_off = @intCast(u28, line_delta); | ||
| 920 | 914 | ||
| 921 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 915 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; |
| 922 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; | 916 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 923 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); | 917 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); |
| 924 | var data: [4]u8 = undefined; | 918 | var data: [4]u8 = undefined; |
| 925 | leb.writeUnsignedFixed(4, &data, casted_line_off); | 919 | leb.writeUnsignedFixed(4, &data, line_off); |
| 926 | try self.file.pwriteAll(&data, file_pos); | 920 | try self.file.pwriteAll(&data, file_pos); |
| 927 | } | 921 | } |
| 928 | 922 | ||
| ... | @@ -946,27 +940,14 @@ pub fn initDeclDebugBuffers( | ... | @@ -946,27 +940,14 @@ pub fn initDeclDebugBuffers( |
| 946 | var dbg_info_buffer = std.ArrayList(u8).init(allocator); | 940 | var dbg_info_buffer = std.ArrayList(u8).init(allocator); |
| 947 | var dbg_info_type_relocs: link.File.DbgInfoTypeRelocsTable = .{}; | 941 | var dbg_info_type_relocs: link.File.DbgInfoTypeRelocsTable = .{}; |
| 948 | 942 | ||
| 949 | const typed_value = decl.typed_value.most_recent.typed_value; | 943 | assert(decl.has_tv); |
| 950 | switch (typed_value.ty.zigTypeTag()) { | 944 | switch (decl.ty.zigTypeTag()) { |
| 951 | .Fn => { | 945 | .Fn => { |
| 952 | // For functions we need to add a prologue to the debug line program. | 946 | // For functions we need to add a prologue to the debug line program. |
| 953 | try dbg_line_buffer.ensureCapacity(26); | 947 | try dbg_line_buffer.ensureCapacity(26); |
| 954 | 948 | ||
| 955 | const line_off: u28 = blk: { | 949 | const func = decl.val.castTag(.function).?.data; |
| 956 | const tree = decl.container.file_scope.tree; | 950 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 957 | const node_tags = tree.nodes.items(.tag); | ||
| 958 | const node_datas = tree.nodes.items(.data); | ||
| 959 | const token_starts = tree.tokens.items(.start); | ||
| 960 | |||
| 961 | // TODO Look into improving the performance here by adding a token-index-to-line | ||
| 962 | // lookup table. Currently this involves scanning over the source code for newlines. | ||
| 963 | const fn_decl = decl.src_node; | ||
| 964 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 965 | const block = node_datas[fn_decl].rhs; | ||
| 966 | const lbrace = tree.firstToken(block); | ||
| 967 | const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); | ||
| 968 | break :blk @intCast(u28, line_delta); | ||
| 969 | }; | ||
| 970 | 951 | ||
| 971 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | 952 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ |
| 972 | DW.LNS_extended_op, | 953 | DW.LNS_extended_op, |
| ... | @@ -999,7 +980,7 @@ pub fn initDeclDebugBuffers( | ... | @@ -999,7 +980,7 @@ pub fn initDeclDebugBuffers( |
| 999 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; | 980 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; |
| 1000 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 27 + decl_name_with_null.len); | 981 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 27 + decl_name_with_null.len); |
| 1001 | 982 | ||
| 1002 | const fn_ret_type = typed_value.ty.fnReturnType(); | 983 | const fn_ret_type = decl.ty.fnReturnType(); |
| 1003 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | 984 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); |
| 1004 | if (fn_ret_has_bits) { | 985 | if (fn_ret_has_bits) { |
| 1005 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | 986 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); |
| ... | @@ -1058,8 +1039,8 @@ pub fn commitDeclDebugInfo( | ... | @@ -1058,8 +1039,8 @@ pub fn commitDeclDebugInfo( |
| 1058 | const symbol = self.base.locals.items[decl.link.macho.local_sym_index]; | 1039 | const symbol = self.base.locals.items[decl.link.macho.local_sym_index]; |
| 1059 | const text_block = &decl.link.macho; | 1040 | const text_block = &decl.link.macho; |
| 1060 | // If the Decl is a function, we need to update the __debug_line program. | 1041 | // If the Decl is a function, we need to update the __debug_line program. |
| 1061 | const typed_value = decl.typed_value.most_recent.typed_value; | 1042 | assert(decl.has_tv); |
| 1062 | switch (typed_value.ty.zigTypeTag()) { | 1043 | switch (decl.ty.zigTypeTag()) { |
| 1063 | .Fn => { | 1044 | .Fn => { |
| 1064 | // Perform the relocations based on vaddr. | 1045 | // Perform the relocations based on vaddr. |
| 1065 | { | 1046 | { |
| ... | @@ -1082,22 +1063,8 @@ pub fn commitDeclDebugInfo( | ... | @@ -1082,22 +1063,8 @@ pub fn commitDeclDebugInfo( |
| 1082 | try leb.writeULEB128(dbg_line_buffer.writer(), text_block.size); | 1063 | try leb.writeULEB128(dbg_line_buffer.writer(), text_block.size); |
| 1083 | 1064 | ||
| 1084 | try dbg_line_buffer.append(DW.LNS_advance_line); | 1065 | try dbg_line_buffer.append(DW.LNS_advance_line); |
| 1085 | const line_off: u28 = blk: { | 1066 | const func = decl.val.castTag(.function).?.data; |
| 1086 | const tree = decl.container.file_scope.tree; | 1067 | const line_off = @intCast(u28, func.rbrace_line - func.lbrace_line); |
| 1087 | const node_tags = tree.nodes.items(.tag); | ||
| 1088 | const node_datas = tree.nodes.items(.data); | ||
| 1089 | const token_starts = tree.tokens.items(.start); | ||
| 1090 | |||
| 1091 | // TODO Look into improving the performance here by adding a token-index-to-line | ||
| 1092 | // lookup table. Currently this involves scanning over the source code for newlines. | ||
| 1093 | const fn_decl = decl.src_node; | ||
| 1094 | assert(node_tags[fn_decl] == .fn_decl); | ||
| 1095 | const block = node_datas[fn_decl].rhs; | ||
| 1096 | const lbrace = tree.firstToken(block); | ||
| 1097 | const rbrace = tree.lastToken(block); | ||
| 1098 | const line_delta = std.zig.lineDelta(tree.source, token_starts[lbrace], token_starts[rbrace]); | ||
| 1099 | break :blk @intCast(u28, line_delta); | ||
| 1100 | }; | ||
| 1101 | try leb.writeULEB128(dbg_line_buffer.writer(), line_off); | 1068 | try leb.writeULEB128(dbg_line_buffer.writer(), line_off); |
| 1102 | } | 1069 | } |
| 1103 | 1070 | ||
| ... | @@ -1188,6 +1155,9 @@ pub fn commitDeclDebugInfo( | ... | @@ -1188,6 +1155,9 @@ pub fn commitDeclDebugInfo( |
| 1188 | else => {}, | 1155 | else => {}, |
| 1189 | } | 1156 | } |
| 1190 | 1157 | ||
| 1158 | if (dbg_info_buffer.items.len == 0) | ||
| 1159 | return; | ||
| 1160 | |||
| 1191 | // Now we emit the .debug_info types of the Decl. These will count towards the size of | 1161 | // Now we emit the .debug_info types of the Decl. These will count towards the size of |
| 1192 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual | 1162 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual |
| 1193 | // relocations yet. | 1163 | // relocations yet. |
src/link/SpirV.zig+25-16| ... | @@ -37,13 +37,17 @@ const spec = @import("../codegen/spirv/spec.zig"); | ... | @@ -37,13 +37,17 @@ const spec = @import("../codegen/spirv/spec.zig"); |
| 37 | 37 | ||
| 38 | // TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl? | 38 | // TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl? |
| 39 | pub const FnData = struct { | 39 | pub const FnData = struct { |
| 40 | // We're going to fill these in flushModule, and we're going to fill them unconditionally, | 40 | // We're going to fill these in flushModule, and we're going to fill them unconditionally, |
| 41 | // so just set it to undefined. | 41 | // so just set it to undefined. |
| 42 | id: u32 = undefined | 42 | id: u32 = undefined }; |
| 43 | }; | ||
| 44 | 43 | ||
| 45 | base: link.File, | 44 | base: link.File, |
| 46 | 45 | ||
| 46 | /// This linker backend does not try to incrementally link output SPIR-V code. | ||
| 47 | /// Instead, it tracks all declarations in this table, and iterates over it | ||
| 48 | /// in the flush function. | ||
| 49 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, | ||
| 50 | |||
| 47 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*SpirV { | 51 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*SpirV { |
| 48 | const spirv = try gpa.create(SpirV); | 52 | const spirv = try gpa.create(SpirV); |
| 49 | spirv.* = .{ | 53 | spirv.* = .{ |
| ... | @@ -90,9 +94,14 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -90,9 +94,14 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 90 | return spirv; | 94 | return spirv; |
| 91 | } | 95 | } |
| 92 | 96 | ||
| 93 | pub fn deinit(self: *SpirV) void {} | 97 | pub fn deinit(self: *SpirV) void { |
| 98 | self.decl_table.deinit(self.base.allocator); | ||
| 99 | } | ||
| 94 | 100 | ||
| 95 | pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {} | 101 | pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void { |
| 102 | // Keep track of all decls so we can iterate over them on flush(). | ||
| 103 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | ||
| 104 | } | ||
| 96 | 105 | ||
| 97 | pub fn updateDeclExports( | 106 | pub fn updateDeclExports( |
| 98 | self: *SpirV, | 107 | self: *SpirV, |
| ... | @@ -101,7 +110,9 @@ pub fn updateDeclExports( | ... | @@ -101,7 +110,9 @@ pub fn updateDeclExports( |
| 101 | exports: []const *Module.Export, | 110 | exports: []const *Module.Export, |
| 102 | ) !void {} | 111 | ) !void {} |
| 103 | 112 | ||
| 104 | pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {} | 113 | pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void { |
| 114 | self.decl_table.removeAssertDiscard(decl); | ||
| 115 | } | ||
| 105 | 116 | ||
| 106 | pub fn flush(self: *SpirV, comp: *Compilation) !void { | 117 | pub fn flush(self: *SpirV, comp: *Compilation) !void { |
| 107 | if (build_options.have_llvm and self.base.options.use_lld) { | 118 | if (build_options.have_llvm and self.base.options.use_lld) { |
| ... | @@ -127,10 +138,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { | ... | @@ -127,10 +138,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { |
| 127 | // declarations which don't generate a result? | 138 | // declarations which don't generate a result? |
| 128 | // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though. | 139 | // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though. |
| 129 | { | 140 | { |
| 130 | for (module.decl_table.items()) |entry| { | 141 | for (self.decl_table.items()) |entry| { |
| 131 | const decl = entry.value; | 142 | const decl = entry.key; |
| 132 | if (decl.typed_value != .most_recent) | 143 | if (!decl.has_tv) continue; |
| 133 | continue; | ||
| 134 | 144 | ||
| 135 | decl.fn_link.spirv.id = spv.allocResultId(); | 145 | decl.fn_link.spirv.id = spv.allocResultId(); |
| 136 | log.debug("Allocating id {} to '{s}'", .{ decl.fn_link.spirv.id, std.mem.spanZ(decl.name) }); | 146 | log.debug("Allocating id {} to '{s}'", .{ decl.fn_link.spirv.id, std.mem.spanZ(decl.name) }); |
| ... | @@ -157,10 +167,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { | ... | @@ -157,10 +167,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { |
| 157 | defer decl_gen.types.deinit(); | 167 | defer decl_gen.types.deinit(); |
| 158 | defer decl_gen.args.deinit(); | 168 | defer decl_gen.args.deinit(); |
| 159 | 169 | ||
| 160 | for (module.decl_table.items()) |entry| { | 170 | for (self.decl_table.items()) |entry| { |
| 161 | const decl = entry.value; | 171 | const decl = entry.key; |
| 162 | if (decl.typed_value != .most_recent) | 172 | if (!decl.has_tv) continue; |
| 163 | continue; | ||
| 164 | 173 | ||
| 165 | decl_gen.args.items.len = 0; | 174 | decl_gen.args.items.len = 0; |
| 166 | decl_gen.next_arg_index = 0; | 175 | decl_gen.next_arg_index = 0; |
| ... | @@ -253,4 +262,4 @@ fn wordsToIovConst(words: []const u32) std.os.iovec_const { | ... | @@ -253,4 +262,4 @@ fn wordsToIovConst(words: []const u32) std.os.iovec_const { |
| 253 | .iov_base = bytes.ptr, | 262 | .iov_base = bytes.ptr, |
| 254 | .iov_len = bytes.len, | 263 | .iov_len = bytes.len, |
| 255 | }; | 264 | }; |
| 256 | } | ||
| \ No newline at end of file | |||
| 265 | } | ||
src/link/Wasm.zig+7-9| ... | @@ -175,9 +175,8 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -175,9 +175,8 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 175 | 175 | ||
| 176 | self.offset_table.items[block.offset_index] = 0; | 176 | self.offset_table.items[block.offset_index] = 0; |
| 177 | 177 | ||
| 178 | const typed_value = decl.typed_value.most_recent.typed_value; | 178 | if (decl.ty.zigTypeTag() == .Fn) { |
| 179 | if (typed_value.ty.zigTypeTag() == .Fn) { | 179 | switch (decl.val.tag()) { |
| 180 | switch (typed_value.val.tag()) { | ||
| 181 | // dependent on function type, appends it to the correct list | 180 | // dependent on function type, appends it to the correct list |
| 182 | .function => try self.funcs.append(self.base.allocator, decl), | 181 | .function => try self.funcs.append(self.base.allocator, decl), |
| 183 | .extern_fn => try self.ext_funcs.append(self.base.allocator, decl), | 182 | .extern_fn => try self.ext_funcs.append(self.base.allocator, decl), |
| ... | @@ -191,7 +190,6 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -191,7 +190,6 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 191 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | 190 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 192 | std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes() | 191 | std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes() |
| 193 | 192 | ||
| 194 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 195 | const fn_data = &decl.fn_link.wasm; | 193 | const fn_data = &decl.fn_link.wasm; |
| 196 | fn_data.functype.items.len = 0; | 194 | fn_data.functype.items.len = 0; |
| 197 | fn_data.code.items.len = 0; | 195 | fn_data.code.items.len = 0; |
| ... | @@ -210,7 +208,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | ... | @@ -210,7 +208,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 210 | defer context.deinit(); | 208 | defer context.deinit(); |
| 211 | 209 | ||
| 212 | // generate the 'code' section for the function declaration | 210 | // generate the 'code' section for the function declaration |
| 213 | const result = context.gen(typed_value) catch |err| switch (err) { | 211 | const result = context.gen(.{ .ty = decl.ty, .val = decl.val }) catch |err| switch (err) { |
| 214 | error.CodegenFail => { | 212 | error.CodegenFail => { |
| 215 | decl.analysis = .codegen_failure; | 213 | decl.analysis = .codegen_failure; |
| 216 | try module.failed_decls.put(module.gpa, decl, context.err_msg); | 214 | try module.failed_decls.put(module.gpa, decl, context.err_msg); |
| ... | @@ -228,7 +226,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | ... | @@ -228,7 +226,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 228 | fn_data.functype = context.func_type_data.toUnmanaged(); | 226 | fn_data.functype = context.func_type_data.toUnmanaged(); |
| 229 | 227 | ||
| 230 | const block = &decl.link.wasm; | 228 | const block = &decl.link.wasm; |
| 231 | if (typed_value.ty.zigTypeTag() == .Fn) { | 229 | if (decl.ty.zigTypeTag() == .Fn) { |
| 232 | // as locals are patched afterwards, the offsets of funcidx's are off, | 230 | // as locals are patched afterwards, the offsets of funcidx's are off, |
| 233 | // here we update them to correct them | 231 | // here we update them to correct them |
| 234 | for (fn_data.idx_refs.items) |*func| { | 232 | for (fn_data.idx_refs.items) |*func| { |
| ... | @@ -262,7 +260,7 @@ pub fn updateDeclExports( | ... | @@ -262,7 +260,7 @@ pub fn updateDeclExports( |
| 262 | 260 | ||
| 263 | pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { | 261 | pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 264 | if (self.getFuncidx(decl)) |func_idx| { | 262 | if (self.getFuncidx(decl)) |func_idx| { |
| 265 | switch (decl.typed_value.most_recent.typed_value.val.tag()) { | 263 | switch (decl.val.tag()) { |
| 266 | .function => _ = self.funcs.swapRemove(func_idx), | 264 | .function => _ = self.funcs.swapRemove(func_idx), |
| 267 | .extern_fn => _ = self.ext_funcs.swapRemove(func_idx), | 265 | .extern_fn => _ = self.ext_funcs.swapRemove(func_idx), |
| 268 | else => unreachable, | 266 | else => unreachable, |
| ... | @@ -429,7 +427,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -429,7 +427,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 429 | try leb.writeULEB128(writer, @intCast(u32, exprt.options.name.len)); | 427 | try leb.writeULEB128(writer, @intCast(u32, exprt.options.name.len)); |
| 430 | try writer.writeAll(exprt.options.name); | 428 | try writer.writeAll(exprt.options.name); |
| 431 | 429 | ||
| 432 | switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) { | 430 | switch (exprt.exported_decl.ty.zigTypeTag()) { |
| 433 | .Fn => { | 431 | .Fn => { |
| 434 | // Type of the export | 432 | // Type of the export |
| 435 | try writer.writeByte(wasm.externalKind(.function)); | 433 | try writer.writeByte(wasm.externalKind(.function)); |
| ... | @@ -802,7 +800,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -802,7 +800,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 802 | /// TODO: we could maintain a hash map to potentially make this simpler | 800 | /// TODO: we could maintain a hash map to potentially make this simpler |
| 803 | fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 { | 801 | fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 { |
| 804 | var offset: u32 = 0; | 802 | var offset: u32 = 0; |
| 805 | const slice = switch (decl.typed_value.most_recent.typed_value.val.tag()) { | 803 | const slice = switch (decl.val.tag()) { |
| 806 | .function => blk: { | 804 | .function => blk: { |
| 807 | // when the target is a regular function, we have to calculate | 805 | // when the target is a regular function, we have to calculate |
| 808 | // the offset of where the index starts | 806 | // the offset of where the index starts |
src/main.zig+516-139| ... | @@ -12,7 +12,6 @@ const warn = std.log.warn; | ... | @@ -12,7 +12,6 @@ const warn = std.log.warn; |
| 12 | const Compilation = @import("Compilation.zig"); | 12 | const Compilation = @import("Compilation.zig"); |
| 13 | const link = @import("link.zig"); | 13 | const link = @import("link.zig"); |
| 14 | const Package = @import("Package.zig"); | 14 | const Package = @import("Package.zig"); |
| 15 | const zir = @import("zir.zig"); | ||
| 16 | const build_options = @import("build_options"); | 15 | const build_options = @import("build_options"); |
| 17 | const introspect = @import("introspect.zig"); | 16 | const introspect = @import("introspect.zig"); |
| 18 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 17 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| ... | @@ -26,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn { | ... | @@ -26,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn { |
| 26 | process.exit(1); | 25 | process.exit(1); |
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB | 28 | /// There are many assumptions in the entire codebase that Zig source files can |
| 29 | /// be byte-indexed with a u32 integer. | ||
| 30 | pub const max_src_size = std.math.maxInt(u32); | ||
| 31 | |||
| 32 | pub const debug_extensions_enabled = std.builtin.mode == .Debug; | ||
| 30 | 33 | ||
| 31 | pub const Color = enum { | 34 | pub const Color = enum { |
| 32 | auto, | 35 | auto, |
| ... | @@ -34,7 +37,7 @@ pub const Color = enum { | ... | @@ -34,7 +37,7 @@ pub const Color = enum { |
| 34 | on, | 37 | on, |
| 35 | }; | 38 | }; |
| 36 | 39 | ||
| 37 | const usage = | 40 | const normal_usage = |
| 38 | \\Usage: zig [command] [options] | 41 | \\Usage: zig [command] [options] |
| 39 | \\ | 42 | \\ |
| 40 | \\Commands: | 43 | \\Commands: |
| ... | @@ -64,6 +67,17 @@ const usage = | ... | @@ -64,6 +67,17 @@ const usage = |
| 64 | \\ | 67 | \\ |
| 65 | ; | 68 | ; |
| 66 | 69 | ||
| 70 | const debug_usage = normal_usage ++ | ||
| 71 | \\ | ||
| 72 | \\Debug Commands: | ||
| 73 | \\ | ||
| 74 | \\ astgen Print ZIR code for a .zig source file | ||
| 75 | \\ changelist Compute mappings from old ZIR to new ZIR | ||
| 76 | \\ | ||
| 77 | ; | ||
| 78 | |||
| 79 | const usage = if (debug_extensions_enabled) debug_usage else normal_usage; | ||
| 80 | |||
| 67 | pub const log_level: std.log.Level = switch (std.builtin.mode) { | 81 | pub const log_level: std.log.Level = switch (std.builtin.mode) { |
| 68 | .Debug => .debug, | 82 | .Debug => .debug, |
| 69 | .ReleaseSafe, .ReleaseFast => .info, | 83 | .ReleaseSafe, .ReleaseFast => .info, |
| ... | @@ -107,7 +121,9 @@ pub fn log( | ... | @@ -107,7 +121,9 @@ pub fn log( |
| 107 | std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args); | 121 | std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args); |
| 108 | } | 122 | } |
| 109 | 123 | ||
| 110 | var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; | 124 | var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{ |
| 125 | .stack_trace_frames = build_options.mem_leak_frames, | ||
| 126 | }){}; | ||
| 111 | 127 | ||
| 112 | pub fn main() anyerror!void { | 128 | pub fn main() anyerror!void { |
| 113 | const gpa = if (std.builtin.link_libc) | 129 | const gpa = if (std.builtin.link_libc) |
| ... | @@ -207,13 +223,17 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v | ... | @@ -207,13 +223,17 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 207 | const stdout = io.getStdOut().writer(); | 223 | const stdout = io.getStdOut().writer(); |
| 208 | return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target); | 224 | return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target); |
| 209 | } else if (mem.eql(u8, cmd, "version")) { | 225 | } else if (mem.eql(u8, cmd, "version")) { |
| 210 | try std.io.getStdOut().writeAll(build_options.version ++ "\n"); | 226 | return std.io.getStdOut().writeAll(build_options.version ++ "\n"); |
| 211 | } else if (mem.eql(u8, cmd, "env")) { | 227 | } else if (mem.eql(u8, cmd, "env")) { |
| 212 | try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); | 228 | return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); |
| 213 | } else if (mem.eql(u8, cmd, "zen")) { | 229 | } else if (mem.eql(u8, cmd, "zen")) { |
| 214 | try io.getStdOut().writeAll(info_zen); | 230 | return io.getStdOut().writeAll(info_zen); |
| 215 | } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) { | 231 | } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) { |
| 216 | try io.getStdOut().writeAll(usage); | 232 | return io.getStdOut().writeAll(usage); |
| 233 | } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) { | ||
| 234 | return cmdAstgen(gpa, arena, cmd_args); | ||
| 235 | } else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) { | ||
| 236 | return cmdChangelist(gpa, arena, cmd_args); | ||
| 217 | } else { | 237 | } else { |
| 218 | std.log.info("{s}", .{usage}); | 238 | std.log.info("{s}", .{usage}); |
| 219 | fatal("unknown command: {s}", .{args[1]}); | 239 | fatal("unknown command: {s}", .{args[1]}); |
| ... | @@ -377,9 +397,11 @@ const usage_build_generic = | ... | @@ -377,9 +397,11 @@ const usage_build_generic = |
| 377 | 397 | ||
| 378 | const repl_help = | 398 | const repl_help = |
| 379 | \\Commands: | 399 | \\Commands: |
| 380 | \\ update Detect changes to source files and update output files. | 400 | \\ update Detect changes to source files and update output files. |
| 381 | \\ help Print this text | 401 | \\ run Execute the output file, if it is an executable or test. |
| 382 | \\ exit Quit this repl | 402 | \\ update-and-run Perform an `update` followed by `run`. |
| 403 | \\ help Print this text | ||
| 404 | \\ exit Quit this repl | ||
| 383 | \\ | 405 | \\ |
| 384 | ; | 406 | ; |
| 385 | 407 | ||
| ... | @@ -468,18 +490,20 @@ fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 { | ... | @@ -468,18 +490,20 @@ fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 { |
| 468 | } | 490 | } |
| 469 | } | 491 | } |
| 470 | 492 | ||
| 493 | const ArgMode = union(enum) { | ||
| 494 | build: std.builtin.OutputMode, | ||
| 495 | cc, | ||
| 496 | cpp, | ||
| 497 | translate_c, | ||
| 498 | zig_test, | ||
| 499 | run, | ||
| 500 | }; | ||
| 501 | |||
| 471 | fn buildOutputType( | 502 | fn buildOutputType( |
| 472 | gpa: *Allocator, | 503 | gpa: *Allocator, |
| 473 | arena: *Allocator, | 504 | arena: *Allocator, |
| 474 | all_args: []const []const u8, | 505 | all_args: []const []const u8, |
| 475 | arg_mode: union(enum) { | 506 | arg_mode: ArgMode, |
| 476 | build: std.builtin.OutputMode, | ||
| 477 | cc, | ||
| 478 | cpp, | ||
| 479 | translate_c, | ||
| 480 | zig_test, | ||
| 481 | run, | ||
| 482 | }, | ||
| 483 | ) !void { | 507 | ) !void { |
| 484 | var color: Color = .auto; | 508 | var color: Color = .auto; |
| 485 | var optimize_mode: std.builtin.Mode = .Debug; | 509 | var optimize_mode: std.builtin.Mode = .Debug; |
| ... | @@ -606,7 +630,6 @@ fn buildOutputType( | ... | @@ -606,7 +630,6 @@ fn buildOutputType( |
| 606 | var pkg_tree_root: Package = .{ | 630 | var pkg_tree_root: Package = .{ |
| 607 | .root_src_directory = .{ .path = null, .handle = fs.cwd() }, | 631 | .root_src_directory = .{ .path = null, .handle = fs.cwd() }, |
| 608 | .root_src_path = &[0]u8{}, | 632 | .root_src_path = &[0]u8{}, |
| 609 | .namespace_hash = Package.root_namespace_hash, | ||
| 610 | }; | 633 | }; |
| 611 | defer freePkgTree(gpa, &pkg_tree_root, false); | 634 | defer freePkgTree(gpa, &pkg_tree_root, false); |
| 612 | var cur_pkg: *Package = &pkg_tree_root; | 635 | var cur_pkg: *Package = &pkg_tree_root; |
| ... | @@ -1744,7 +1767,6 @@ fn buildOutputType( | ... | @@ -1744,7 +1767,6 @@ fn buildOutputType( |
| 1744 | if (root_pkg) |pkg| { | 1767 | if (root_pkg) |pkg| { |
| 1745 | pkg.table = pkg_tree_root.table; | 1768 | pkg.table = pkg_tree_root.table; |
| 1746 | pkg_tree_root.table = .{}; | 1769 | pkg_tree_root.table = .{}; |
| 1747 | pkg.namespace_hash = pkg_tree_root.namespace_hash; | ||
| 1748 | } | 1770 | } |
| 1749 | 1771 | ||
| 1750 | const self_exe_path = try fs.selfExePathAlloc(arena); | 1772 | const self_exe_path = try fs.selfExePathAlloc(arena); |
| ... | @@ -1954,114 +1976,36 @@ fn buildOutputType( | ... | @@ -1954,114 +1976,36 @@ fn buildOutputType( |
| 1954 | .run, .zig_test => true, | 1976 | .run, .zig_test => true, |
| 1955 | else => false, | 1977 | else => false, |
| 1956 | }; | 1978 | }; |
| 1957 | if (run_or_test) run: { | 1979 | if (run_or_test) { |
| 1958 | const exe_loc = emit_bin_loc orelse break :run; | 1980 | try runOrTest( |
| 1959 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; | 1981 | comp, |
| 1960 | const exe_path = try fs.path.join(arena, &[_][]const u8{ | 1982 | gpa, |
| 1961 | exe_directory.path orelse ".", exe_loc.basename, | 1983 | arena, |
| 1962 | }); | 1984 | emit_bin_loc, |
| 1963 | 1985 | test_exec_args.items, | |
| 1964 | var argv = std.ArrayList([]const u8).init(gpa); | 1986 | self_exe_path, |
| 1965 | defer argv.deinit(); | 1987 | arg_mode, |
| 1966 | 1988 | target_info.target, | |
| 1967 | if (test_exec_args.items.len == 0) { | 1989 | watch, |
| 1968 | if (!std.Target.current.canExecBinariesOf(target_info.target)) { | 1990 | &comp_destroyed, |
| 1969 | switch (arg_mode) { | 1991 | all_args, |
| 1970 | .zig_test => { | 1992 | runtime_args_start, |
| 1971 | warn("created {s} but skipping execution because it is non-native", .{exe_path}); | 1993 | ); |
| 1972 | if (!watch) return cleanExit(); | ||
| 1973 | break :run; | ||
| 1974 | }, | ||
| 1975 | .run => fatal("unable to execute {s}: non-native", .{exe_path}), | ||
| 1976 | else => unreachable, | ||
| 1977 | } | ||
| 1978 | } | ||
| 1979 | // when testing pass the zig_exe_path to argv | ||
| 1980 | if (arg_mode == .zig_test) | ||
| 1981 | try argv.appendSlice(&[_][]const u8{ | ||
| 1982 | exe_path, self_exe_path, | ||
| 1983 | }) | ||
| 1984 | // when running just pass the current exe | ||
| 1985 | else | ||
| 1986 | try argv.appendSlice(&[_][]const u8{ | ||
| 1987 | exe_path, | ||
| 1988 | }); | ||
| 1989 | } else { | ||
| 1990 | for (test_exec_args.items) |arg| { | ||
| 1991 | if (arg) |a| { | ||
| 1992 | try argv.append(a); | ||
| 1993 | } else { | ||
| 1994 | try argv.appendSlice(&[_][]const u8{ | ||
| 1995 | exe_path, self_exe_path, | ||
| 1996 | }); | ||
| 1997 | } | ||
| 1998 | } | ||
| 1999 | } | ||
| 2000 | if (runtime_args_start) |i| { | ||
| 2001 | try argv.appendSlice(all_args[i..]); | ||
| 2002 | } | ||
| 2003 | // We do not execve for tests because if the test fails we want to print | ||
| 2004 | // the error message and invocation below. | ||
| 2005 | if (std.process.can_execv and arg_mode == .run and !watch) { | ||
| 2006 | // execv releases the locks; no need to destroy the Compilation here. | ||
| 2007 | const err = std.process.execv(gpa, argv.items); | ||
| 2008 | const cmd = try argvCmd(arena, argv.items); | ||
| 2009 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); | ||
| 2010 | } else { | ||
| 2011 | const child = try std.ChildProcess.init(argv.items, gpa); | ||
| 2012 | defer child.deinit(); | ||
| 2013 | |||
| 2014 | child.stdin_behavior = .Inherit; | ||
| 2015 | child.stdout_behavior = .Inherit; | ||
| 2016 | child.stderr_behavior = .Inherit; | ||
| 2017 | |||
| 2018 | if (!watch) { | ||
| 2019 | // Here we release all the locks associated with the Compilation so | ||
| 2020 | // that whatever this child process wants to do won't deadlock. | ||
| 2021 | comp.destroy(); | ||
| 2022 | comp_destroyed = true; | ||
| 2023 | } | ||
| 2024 | |||
| 2025 | const term = try child.spawnAndWait(); | ||
| 2026 | switch (arg_mode) { | ||
| 2027 | .run => { | ||
| 2028 | switch (term) { | ||
| 2029 | .Exited => |code| { | ||
| 2030 | if (code == 0) { | ||
| 2031 | if (!watch) return cleanExit(); | ||
| 2032 | } else { | ||
| 2033 | // TODO https://github.com/ziglang/zig/issues/6342 | ||
| 2034 | process.exit(1); | ||
| 2035 | } | ||
| 2036 | }, | ||
| 2037 | else => process.exit(1), | ||
| 2038 | } | ||
| 2039 | }, | ||
| 2040 | .zig_test => { | ||
| 2041 | switch (term) { | ||
| 2042 | .Exited => |code| { | ||
| 2043 | if (code == 0) { | ||
| 2044 | if (!watch) return cleanExit(); | ||
| 2045 | } else { | ||
| 2046 | const cmd = try argvCmd(arena, argv.items); | ||
| 2047 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); | ||
| 2048 | } | ||
| 2049 | }, | ||
| 2050 | else => { | ||
| 2051 | const cmd = try argvCmd(arena, argv.items); | ||
| 2052 | fatal("the following test command crashed:\n{s}", .{cmd}); | ||
| 2053 | }, | ||
| 2054 | } | ||
| 2055 | }, | ||
| 2056 | else => unreachable, | ||
| 2057 | } | ||
| 2058 | } | ||
| 2059 | } | 1994 | } |
| 2060 | 1995 | ||
| 2061 | const stdin = std.io.getStdIn().reader(); | 1996 | const stdin = std.io.getStdIn().reader(); |
| 2062 | const stderr = std.io.getStdErr().writer(); | 1997 | const stderr = std.io.getStdErr().writer(); |
| 2063 | var repl_buf: [1024]u8 = undefined; | 1998 | var repl_buf: [1024]u8 = undefined; |
| 2064 | 1999 | ||
| 2000 | const ReplCmd = enum { | ||
| 2001 | update, | ||
| 2002 | help, | ||
| 2003 | run, | ||
| 2004 | update_and_run, | ||
| 2005 | }; | ||
| 2006 | |||
| 2007 | var last_cmd: ReplCmd = .help; | ||
| 2008 | |||
| 2065 | while (watch) { | 2009 | while (watch) { |
| 2066 | try stderr.print("(zig) ", .{}); | 2010 | try stderr.print("(zig) ", .{}); |
| 2067 | try comp.makeBinFileExecutable(); | 2011 | try comp.makeBinFileExecutable(); |
| ... | @@ -2070,26 +2014,213 @@ fn buildOutputType( | ... | @@ -2070,26 +2014,213 @@ fn buildOutputType( |
| 2070 | continue; | 2014 | continue; |
| 2071 | }) |line| { | 2015 | }) |line| { |
| 2072 | const actual_line = mem.trimRight(u8, line, "\r\n "); | 2016 | const actual_line = mem.trimRight(u8, line, "\r\n "); |
| 2073 | 2017 | const cmd: ReplCmd = blk: { | |
| 2074 | if (mem.eql(u8, actual_line, "update")) { | 2018 | if (mem.eql(u8, actual_line, "update")) { |
| 2075 | if (output_mode == .Exe) { | 2019 | break :blk .update; |
| 2076 | try comp.makeBinFileWritable(); | 2020 | } else if (mem.eql(u8, actual_line, "exit")) { |
| 2021 | break; | ||
| 2022 | } else if (mem.eql(u8, actual_line, "help")) { | ||
| 2023 | break :blk .help; | ||
| 2024 | } else if (mem.eql(u8, actual_line, "run")) { | ||
| 2025 | break :blk .run; | ||
| 2026 | } else if (mem.eql(u8, actual_line, "update-and-run")) { | ||
| 2027 | break :blk .update_and_run; | ||
| 2028 | } else if (actual_line.len == 0) { | ||
| 2029 | break :blk last_cmd; | ||
| 2030 | } else { | ||
| 2031 | try stderr.print("unknown command: {s}\n", .{actual_line}); | ||
| 2032 | continue; | ||
| 2077 | } | 2033 | } |
| 2078 | updateModule(gpa, comp, hook) catch |err| switch (err) { | 2034 | }; |
| 2079 | error.SemanticAnalyzeFail => continue, | 2035 | last_cmd = cmd; |
| 2080 | else => |e| return e, | 2036 | switch (cmd) { |
| 2081 | }; | 2037 | .update => { |
| 2082 | } else if (mem.eql(u8, actual_line, "exit")) { | 2038 | if (output_mode == .Exe) { |
| 2083 | break; | 2039 | try comp.makeBinFileWritable(); |
| 2084 | } else if (mem.eql(u8, actual_line, "help")) { | 2040 | } |
| 2085 | try stderr.writeAll(repl_help); | 2041 | updateModule(gpa, comp, hook) catch |err| switch (err) { |
| 2086 | } else { | 2042 | error.SemanticAnalyzeFail => continue, |
| 2087 | try stderr.print("unknown command: {s}\n", .{actual_line}); | 2043 | else => |e| return e, |
| 2044 | }; | ||
| 2045 | }, | ||
| 2046 | .help => { | ||
| 2047 | try stderr.writeAll(repl_help); | ||
| 2048 | }, | ||
| 2049 | .run => { | ||
| 2050 | try runOrTest( | ||
| 2051 | comp, | ||
| 2052 | gpa, | ||
| 2053 | arena, | ||
| 2054 | emit_bin_loc, | ||
| 2055 | test_exec_args.items, | ||
| 2056 | self_exe_path, | ||
| 2057 | arg_mode, | ||
| 2058 | target_info.target, | ||
| 2059 | watch, | ||
| 2060 | &comp_destroyed, | ||
| 2061 | all_args, | ||
| 2062 | runtime_args_start, | ||
| 2063 | ); | ||
| 2064 | }, | ||
| 2065 | .update_and_run => { | ||
| 2066 | if (output_mode == .Exe) { | ||
| 2067 | try comp.makeBinFileWritable(); | ||
| 2068 | } | ||
| 2069 | updateModule(gpa, comp, hook) catch |err| switch (err) { | ||
| 2070 | error.SemanticAnalyzeFail => continue, | ||
| 2071 | else => |e| return e, | ||
| 2072 | }; | ||
| 2073 | try comp.makeBinFileExecutable(); | ||
| 2074 | try runOrTest( | ||
| 2075 | comp, | ||
| 2076 | gpa, | ||
| 2077 | arena, | ||
| 2078 | emit_bin_loc, | ||
| 2079 | test_exec_args.items, | ||
| 2080 | self_exe_path, | ||
| 2081 | arg_mode, | ||
| 2082 | target_info.target, | ||
| 2083 | watch, | ||
| 2084 | &comp_destroyed, | ||
| 2085 | all_args, | ||
| 2086 | runtime_args_start, | ||
| 2087 | ); | ||
| 2088 | }, | ||
| 2088 | } | 2089 | } |
| 2089 | } else { | 2090 | } else { |
| 2090 | break; | 2091 | break; |
| 2091 | } | 2092 | } |
| 2092 | } | 2093 | } |
| 2094 | // Skip resource deallocation in release builds; let the OS do it. | ||
| 2095 | return cleanExit(); | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | fn runOrTest( | ||
| 2099 | comp: *Compilation, | ||
| 2100 | gpa: *Allocator, | ||
| 2101 | arena: *Allocator, | ||
| 2102 | emit_bin_loc: ?Compilation.EmitLoc, | ||
| 2103 | test_exec_args: []const ?[]const u8, | ||
| 2104 | self_exe_path: []const u8, | ||
| 2105 | arg_mode: ArgMode, | ||
| 2106 | target: std.Target, | ||
| 2107 | watch: bool, | ||
| 2108 | comp_destroyed: *bool, | ||
| 2109 | all_args: []const []const u8, | ||
| 2110 | runtime_args_start: ?usize, | ||
| 2111 | ) !void { | ||
| 2112 | const exe_loc = emit_bin_loc orelse return; | ||
| 2113 | const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; | ||
| 2114 | const exe_path = try fs.path.join(arena, &[_][]const u8{ | ||
| 2115 | exe_directory.path orelse ".", exe_loc.basename, | ||
| 2116 | }); | ||
| 2117 | |||
| 2118 | var argv = std.ArrayList([]const u8).init(gpa); | ||
| 2119 | defer argv.deinit(); | ||
| 2120 | |||
| 2121 | if (test_exec_args.len == 0) { | ||
| 2122 | if (!std.Target.current.canExecBinariesOf(target)) { | ||
| 2123 | switch (arg_mode) { | ||
| 2124 | .zig_test => { | ||
| 2125 | warn("created {s} but skipping execution because it is non-native", .{exe_path}); | ||
| 2126 | if (!watch) return cleanExit(); | ||
| 2127 | return; | ||
| 2128 | }, | ||
| 2129 | else => { | ||
| 2130 | std.log.err("unable to execute {s}: non-native", .{exe_path}); | ||
| 2131 | if (!watch) process.exit(1); | ||
| 2132 | return; | ||
| 2133 | }, | ||
| 2134 | } | ||
| 2135 | } | ||
| 2136 | // when testing pass the zig_exe_path to argv | ||
| 2137 | if (arg_mode == .zig_test) | ||
| 2138 | try argv.appendSlice(&[_][]const u8{ | ||
| 2139 | exe_path, self_exe_path, | ||
| 2140 | }) | ||
| 2141 | // when running just pass the current exe | ||
| 2142 | else | ||
| 2143 | try argv.appendSlice(&[_][]const u8{ | ||
| 2144 | exe_path, | ||
| 2145 | }); | ||
| 2146 | } else { | ||
| 2147 | for (test_exec_args) |arg| { | ||
| 2148 | if (arg) |a| { | ||
| 2149 | try argv.append(a); | ||
| 2150 | } else { | ||
| 2151 | try argv.appendSlice(&[_][]const u8{ | ||
| 2152 | exe_path, self_exe_path, | ||
| 2153 | }); | ||
| 2154 | } | ||
| 2155 | } | ||
| 2156 | } | ||
| 2157 | if (runtime_args_start) |i| { | ||
| 2158 | try argv.appendSlice(all_args[i..]); | ||
| 2159 | } | ||
| 2160 | // We do not execve for tests because if the test fails we want to print | ||
| 2161 | // the error message and invocation below. | ||
| 2162 | if (std.process.can_execv and arg_mode == .run and !watch) { | ||
| 2163 | // execv releases the locks; no need to destroy the Compilation here. | ||
| 2164 | const err = std.process.execv(gpa, argv.items); | ||
| 2165 | const cmd = try argvCmd(arena, argv.items); | ||
| 2166 | fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); | ||
| 2167 | } else { | ||
| 2168 | const child = try std.ChildProcess.init(argv.items, gpa); | ||
| 2169 | defer child.deinit(); | ||
| 2170 | |||
| 2171 | child.stdin_behavior = .Inherit; | ||
| 2172 | child.stdout_behavior = .Inherit; | ||
| 2173 | child.stderr_behavior = .Inherit; | ||
| 2174 | |||
| 2175 | if (!watch) { | ||
| 2176 | // Here we release all the locks associated with the Compilation so | ||
| 2177 | // that whatever this child process wants to do won't deadlock. | ||
| 2178 | comp.destroy(); | ||
| 2179 | comp_destroyed.* = true; | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | const term = try child.spawnAndWait(); | ||
| 2183 | switch (arg_mode) { | ||
| 2184 | .run, .build => { | ||
| 2185 | switch (term) { | ||
| 2186 | .Exited => |code| { | ||
| 2187 | if (code == 0) { | ||
| 2188 | if (!watch) return cleanExit(); | ||
| 2189 | } else if (watch) { | ||
| 2190 | warn("process exited with code {d}", .{code}); | ||
| 2191 | } else { | ||
| 2192 | // TODO https://github.com/ziglang/zig/issues/6342 | ||
| 2193 | process.exit(1); | ||
| 2194 | } | ||
| 2195 | }, | ||
| 2196 | else => { | ||
| 2197 | if (watch) { | ||
| 2198 | warn("process aborted abnormally", .{}); | ||
| 2199 | } else { | ||
| 2200 | process.exit(1); | ||
| 2201 | } | ||
| 2202 | }, | ||
| 2203 | } | ||
| 2204 | }, | ||
| 2205 | .zig_test => { | ||
| 2206 | switch (term) { | ||
| 2207 | .Exited => |code| { | ||
| 2208 | if (code == 0) { | ||
| 2209 | if (!watch) return cleanExit(); | ||
| 2210 | } else { | ||
| 2211 | const cmd = try argvCmd(arena, argv.items); | ||
| 2212 | fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); | ||
| 2213 | } | ||
| 2214 | }, | ||
| 2215 | else => { | ||
| 2216 | const cmd = try argvCmd(arena, argv.items); | ||
| 2217 | fatal("the following test command crashed:\n{s}", .{cmd}); | ||
| 2218 | }, | ||
| 2219 | } | ||
| 2220 | }, | ||
| 2221 | else => unreachable, | ||
| 2222 | } | ||
| 2223 | } | ||
| 2093 | } | 2224 | } |
| 2094 | 2225 | ||
| 2095 | const AfterUpdateHook = union(enum) { | 2226 | const AfterUpdateHook = union(enum) { |
| ... | @@ -2524,7 +2655,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v | ... | @@ -2524,7 +2655,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 2524 | .handle = try zig_lib_directory.handle.openDir(std_special, .{}), | 2655 | .handle = try zig_lib_directory.handle.openDir(std_special, .{}), |
| 2525 | }, | 2656 | }, |
| 2526 | .root_src_path = "build_runner.zig", | 2657 | .root_src_path = "build_runner.zig", |
| 2527 | .namespace_hash = Package.root_namespace_hash, | ||
| 2528 | }; | 2658 | }; |
| 2529 | defer root_pkg.root_src_directory.handle.close(); | 2659 | defer root_pkg.root_src_directory.handle.close(); |
| 2530 | 2660 | ||
| ... | @@ -2570,7 +2700,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v | ... | @@ -2570,7 +2700,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 2570 | var build_pkg: Package = .{ | 2700 | var build_pkg: Package = .{ |
| 2571 | .root_src_directory = build_directory, | 2701 | .root_src_directory = build_directory, |
| 2572 | .root_src_path = build_zig_basename, | 2702 | .root_src_path = build_zig_basename, |
| 2573 | .namespace_hash = undefined, | ||
| 2574 | }; | 2703 | }; |
| 2575 | try root_pkg.addAndAdopt(arena, "@build", &build_pkg); | 2704 | try root_pkg.addAndAdopt(arena, "@build", &build_pkg); |
| 2576 | 2705 | ||
| ... | @@ -3423,3 +3552,251 @@ pub fn cleanExit() void { | ... | @@ -3423,3 +3552,251 @@ pub fn cleanExit() void { |
| 3423 | process.exit(0); | 3552 | process.exit(0); |
| 3424 | } | 3553 | } |
| 3425 | } | 3554 | } |
| 3555 | |||
| 3556 | /// This is only enabled for debug builds. | ||
| 3557 | pub fn cmdAstgen( | ||
| 3558 | gpa: *Allocator, | ||
| 3559 | arena: *Allocator, | ||
| 3560 | args: []const []const u8, | ||
| 3561 | ) !void { | ||
| 3562 | const Module = @import("Module.zig"); | ||
| 3563 | const AstGen = @import("AstGen.zig"); | ||
| 3564 | const Zir = @import("Zir.zig"); | ||
| 3565 | |||
| 3566 | const zig_source_file = args[0]; | ||
| 3567 | |||
| 3568 | var f = try fs.cwd().openFile(zig_source_file, .{}); | ||
| 3569 | defer f.close(); | ||
| 3570 | |||
| 3571 | const stat = try f.stat(); | ||
| 3572 | |||
| 3573 | if (stat.size > max_src_size) | ||
| 3574 | return error.FileTooBig; | ||
| 3575 | |||
| 3576 | var file: Module.Scope.File = .{ | ||
| 3577 | .status = .never_loaded, | ||
| 3578 | .source_loaded = false, | ||
| 3579 | .tree_loaded = false, | ||
| 3580 | .zir_loaded = false, | ||
| 3581 | .sub_file_path = zig_source_file, | ||
| 3582 | .source = undefined, | ||
| 3583 | .stat_size = stat.size, | ||
| 3584 | .stat_inode = stat.inode, | ||
| 3585 | .stat_mtime = stat.mtime, | ||
| 3586 | .tree = undefined, | ||
| 3587 | .zir = undefined, | ||
| 3588 | .pkg = undefined, | ||
| 3589 | .root_decl = null, | ||
| 3590 | }; | ||
| 3591 | |||
| 3592 | const source = try arena.allocSentinel(u8, stat.size, 0); | ||
| 3593 | const amt = try f.readAll(source); | ||
| 3594 | if (amt != stat.size) | ||
| 3595 | return error.UnexpectedEndOfFile; | ||
| 3596 | file.source = source; | ||
| 3597 | file.source_loaded = true; | ||
| 3598 | |||
| 3599 | file.tree = try std.zig.parse(gpa, file.source); | ||
| 3600 | file.tree_loaded = true; | ||
| 3601 | defer file.tree.deinit(gpa); | ||
| 3602 | |||
| 3603 | for (file.tree.errors) |parse_error| { | ||
| 3604 | try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto); | ||
| 3605 | } | ||
| 3606 | if (file.tree.errors.len != 0) { | ||
| 3607 | process.exit(1); | ||
| 3608 | } | ||
| 3609 | |||
| 3610 | file.zir = try AstGen.generate(gpa, file.tree); | ||
| 3611 | file.zir_loaded = true; | ||
| 3612 | defer file.zir.deinit(gpa); | ||
| 3613 | |||
| 3614 | { | ||
| 3615 | const token_bytes = @sizeOf(std.zig.ast.TokenList) + | ||
| 3616 | file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(std.zig.ast.ByteOffset)); | ||
| 3617 | const tree_bytes = @sizeOf(std.zig.ast.Tree) + file.tree.nodes.len * | ||
| 3618 | (@sizeOf(std.zig.ast.Node.Tag) + | ||
| 3619 | @sizeOf(std.zig.ast.Node.Data) + | ||
| 3620 | @sizeOf(std.zig.ast.TokenIndex)); | ||
| 3621 | const instruction_bytes = file.zir.instructions.len * | ||
| 3622 | // Here we don't use @sizeOf(Zir.Inst.Data) because it would include | ||
| 3623 | // the debug safety tag but we want to measure release size. | ||
| 3624 | (@sizeOf(Zir.Inst.Tag) + 8); | ||
| 3625 | const extra_bytes = file.zir.extra.len * @sizeOf(u32); | ||
| 3626 | const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + | ||
| 3627 | file.zir.string_bytes.len * @sizeOf(u8); | ||
| 3628 | const stdout = io.getStdOut(); | ||
| 3629 | const fmtIntSizeBin = std.fmt.fmtIntSizeBin; | ||
| 3630 | // zig fmt: off | ||
| 3631 | try stdout.writer().print( | ||
| 3632 | \\# Source bytes: {} | ||
| 3633 | \\# Tokens: {} ({}) | ||
| 3634 | \\# AST Nodes: {} ({}) | ||
| 3635 | \\# Total ZIR bytes: {} | ||
| 3636 | \\# Instructions: {d} ({}) | ||
| 3637 | \\# String Table Bytes: {} | ||
| 3638 | \\# Extra Data Items: {d} ({}) | ||
| 3639 | \\ | ||
| 3640 | , .{ | ||
| 3641 | fmtIntSizeBin(source.len), | ||
| 3642 | file.tree.tokens.len, fmtIntSizeBin(token_bytes), | ||
| 3643 | file.tree.nodes.len, fmtIntSizeBin(tree_bytes), | ||
| 3644 | fmtIntSizeBin(total_bytes), | ||
| 3645 | file.zir.instructions.len, fmtIntSizeBin(instruction_bytes), | ||
| 3646 | fmtIntSizeBin(file.zir.string_bytes.len), | ||
| 3647 | file.zir.extra.len, fmtIntSizeBin(extra_bytes), | ||
| 3648 | }); | ||
| 3649 | // zig fmt: on | ||
| 3650 | } | ||
| 3651 | |||
| 3652 | if (file.zir.hasCompileErrors()) { | ||
| 3653 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); | ||
| 3654 | try Compilation.AllErrors.addZir(arena, &errors, &file); | ||
| 3655 | const ttyconf = std.debug.detectTTYConfig(); | ||
| 3656 | for (errors.items) |full_err_msg| { | ||
| 3657 | full_err_msg.renderToStdErr(ttyconf); | ||
| 3658 | } | ||
| 3659 | process.exit(1); | ||
| 3660 | } | ||
| 3661 | |||
| 3662 | return Zir.renderAsTextToFile(gpa, &file, io.getStdOut()); | ||
| 3663 | } | ||
| 3664 | |||
| 3665 | /// This is only enabled for debug builds. | ||
| 3666 | pub fn cmdChangelist( | ||
| 3667 | gpa: *Allocator, | ||
| 3668 | arena: *Allocator, | ||
| 3669 | args: []const []const u8, | ||
| 3670 | ) !void { | ||
| 3671 | const Module = @import("Module.zig"); | ||
| 3672 | const AstGen = @import("AstGen.zig"); | ||
| 3673 | const Zir = @import("Zir.zig"); | ||
| 3674 | |||
| 3675 | const old_source_file = args[0]; | ||
| 3676 | const new_source_file = args[1]; | ||
| 3677 | |||
| 3678 | var f = try fs.cwd().openFile(old_source_file, .{}); | ||
| 3679 | defer f.close(); | ||
| 3680 | |||
| 3681 | const stat = try f.stat(); | ||
| 3682 | |||
| 3683 | if (stat.size > max_src_size) | ||
| 3684 | return error.FileTooBig; | ||
| 3685 | |||
| 3686 | var file: Module.Scope.File = .{ | ||
| 3687 | .status = .never_loaded, | ||
| 3688 | .source_loaded = false, | ||
| 3689 | .tree_loaded = false, | ||
| 3690 | .zir_loaded = false, | ||
| 3691 | .sub_file_path = old_source_file, | ||
| 3692 | .source = undefined, | ||
| 3693 | .stat_size = stat.size, | ||
| 3694 | .stat_inode = stat.inode, | ||
| 3695 | .stat_mtime = stat.mtime, | ||
| 3696 | .tree = undefined, | ||
| 3697 | .zir = undefined, | ||
| 3698 | .pkg = undefined, | ||
| 3699 | .root_decl = null, | ||
| 3700 | }; | ||
| 3701 | |||
| 3702 | const source = try arena.allocSentinel(u8, stat.size, 0); | ||
| 3703 | const amt = try f.readAll(source); | ||
| 3704 | if (amt != stat.size) | ||
| 3705 | return error.UnexpectedEndOfFile; | ||
| 3706 | file.source = source; | ||
| 3707 | file.source_loaded = true; | ||
| 3708 | |||
| 3709 | file.tree = try std.zig.parse(gpa, file.source); | ||
| 3710 | file.tree_loaded = true; | ||
| 3711 | defer file.tree.deinit(gpa); | ||
| 3712 | |||
| 3713 | for (file.tree.errors) |parse_error| { | ||
| 3714 | try printErrMsgToFile(gpa, parse_error, file.tree, old_source_file, io.getStdErr(), .auto); | ||
| 3715 | } | ||
| 3716 | if (file.tree.errors.len != 0) { | ||
| 3717 | process.exit(1); | ||
| 3718 | } | ||
| 3719 | |||
| 3720 | file.zir = try AstGen.generate(gpa, file.tree); | ||
| 3721 | file.zir_loaded = true; | ||
| 3722 | defer file.zir.deinit(gpa); | ||
| 3723 | |||
| 3724 | if (file.zir.hasCompileErrors()) { | ||
| 3725 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); | ||
| 3726 | try Compilation.AllErrors.addZir(arena, &errors, &file); | ||
| 3727 | const ttyconf = std.debug.detectTTYConfig(); | ||
| 3728 | for (errors.items) |full_err_msg| { | ||
| 3729 | full_err_msg.renderToStdErr(ttyconf); | ||
| 3730 | } | ||
| 3731 | process.exit(1); | ||
| 3732 | } | ||
| 3733 | |||
| 3734 | var new_f = try fs.cwd().openFile(new_source_file, .{}); | ||
| 3735 | defer new_f.close(); | ||
| 3736 | |||
| 3737 | const new_stat = try new_f.stat(); | ||
| 3738 | |||
| 3739 | if (new_stat.size > max_src_size) | ||
| 3740 | return error.FileTooBig; | ||
| 3741 | |||
| 3742 | const new_source = try arena.allocSentinel(u8, new_stat.size, 0); | ||
| 3743 | const new_amt = try new_f.readAll(new_source); | ||
| 3744 | if (new_amt != new_stat.size) | ||
| 3745 | return error.UnexpectedEndOfFile; | ||
| 3746 | |||
| 3747 | var new_tree = try std.zig.parse(gpa, new_source); | ||
| 3748 | defer new_tree.deinit(gpa); | ||
| 3749 | |||
| 3750 | for (new_tree.errors) |parse_error| { | ||
| 3751 | try printErrMsgToFile(gpa, parse_error, new_tree, new_source_file, io.getStdErr(), .auto); | ||
| 3752 | } | ||
| 3753 | if (new_tree.errors.len != 0) { | ||
| 3754 | process.exit(1); | ||
| 3755 | } | ||
| 3756 | |||
| 3757 | var old_zir = file.zir; | ||
| 3758 | defer old_zir.deinit(gpa); | ||
| 3759 | file.zir_loaded = false; | ||
| 3760 | file.zir = try AstGen.generate(gpa, new_tree); | ||
| 3761 | file.zir_loaded = true; | ||
| 3762 | |||
| 3763 | if (file.zir.hasCompileErrors()) { | ||
| 3764 | var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); | ||
| 3765 | try Compilation.AllErrors.addZir(arena, &errors, &file); | ||
| 3766 | const ttyconf = std.debug.detectTTYConfig(); | ||
| 3767 | for (errors.items) |full_err_msg| { | ||
| 3768 | full_err_msg.renderToStdErr(ttyconf); | ||
| 3769 | } | ||
| 3770 | process.exit(1); | ||
| 3771 | } | ||
| 3772 | |||
| 3773 | var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; | ||
| 3774 | defer inst_map.deinit(gpa); | ||
| 3775 | |||
| 3776 | var extra_map: std.AutoHashMapUnmanaged(u32, u32) = .{}; | ||
| 3777 | defer extra_map.deinit(gpa); | ||
| 3778 | |||
| 3779 | try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map, &extra_map); | ||
| 3780 | |||
| 3781 | var bw = io.bufferedWriter(io.getStdOut().writer()); | ||
| 3782 | const stdout = bw.writer(); | ||
| 3783 | { | ||
| 3784 | try stdout.print("Instruction mappings:\n", .{}); | ||
| 3785 | var it = inst_map.iterator(); | ||
| 3786 | while (it.next()) |entry| { | ||
| 3787 | try stdout.print(" %{d} => %{d}\n", .{ | ||
| 3788 | entry.key, entry.value, | ||
| 3789 | }); | ||
| 3790 | } | ||
| 3791 | } | ||
| 3792 | { | ||
| 3793 | try stdout.print("Extra mappings:\n", .{}); | ||
| 3794 | var it = extra_map.iterator(); | ||
| 3795 | while (it.next()) |entry| { | ||
| 3796 | try stdout.print(" {d} => {d}\n", .{ | ||
| 3797 | entry.key, entry.value, | ||
| 3798 | }); | ||
| 3799 | } | ||
| 3800 | } | ||
| 3801 | try bw.flush(); | ||
| 3802 | } |
src/stage1/codegen.cpp+24-18| ... | @@ -8931,10 +8931,10 @@ static const char *bool_to_str(bool b) { | ... | @@ -8931,10 +8931,10 @@ static const char *bool_to_str(bool b) { |
| 8931 | 8931 | ||
| 8932 | static const char *build_mode_to_str(BuildMode build_mode) { | 8932 | static const char *build_mode_to_str(BuildMode build_mode) { |
| 8933 | switch (build_mode) { | 8933 | switch (build_mode) { |
| 8934 | case BuildModeDebug: return "Mode.Debug"; | 8934 | case BuildModeDebug: return "Debug"; |
| 8935 | case BuildModeSafeRelease: return "Mode.ReleaseSafe"; | 8935 | case BuildModeSafeRelease: return "ReleaseSafe"; |
| 8936 | case BuildModeFastRelease: return "Mode.ReleaseFast"; | 8936 | case BuildModeFastRelease: return "ReleaseFast"; |
| 8937 | case BuildModeSmallRelease: return "Mode.ReleaseSmall"; | 8937 | case BuildModeSmallRelease: return "ReleaseSmall"; |
| 8938 | } | 8938 | } |
| 8939 | zig_unreachable(); | 8939 | zig_unreachable(); |
| 8940 | } | 8940 | } |
| ... | @@ -9005,7 +9005,9 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -9005,7 +9005,9 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 9005 | g->have_err_ret_tracing = detect_err_ret_tracing(g); | 9005 | g->have_err_ret_tracing = detect_err_ret_tracing(g); |
| 9006 | 9006 | ||
| 9007 | Buf *contents = buf_alloc(); | 9007 | Buf *contents = buf_alloc(); |
| 9008 | buf_appendf(contents, "usingnamespace @import(\"std\").builtin;\n\n"); | 9008 | buf_appendf(contents, |
| 9009 | "const std = @import(\"std\");\n" | ||
| 9010 | ); | ||
| 9009 | 9011 | ||
| 9010 | const char *cur_os = nullptr; | 9012 | const char *cur_os = nullptr; |
| 9011 | { | 9013 | { |
| ... | @@ -9100,19 +9102,23 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -9100,19 +9102,23 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 9100 | static_assert(TargetSubsystemEfiRom == 6, ""); | 9102 | static_assert(TargetSubsystemEfiRom == 6, ""); |
| 9101 | static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); | 9103 | static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); |
| 9102 | 9104 | ||
| 9103 | buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch`\n"); | 9105 | buf_appendf(contents, "pub const output_mode = std.builtin.OutputMode.Obj;\n"); |
| 9104 | buf_append_str(contents, "pub const arch = Target.current.cpu.arch;\n"); | 9106 | buf_appendf(contents, "pub const link_mode = std.builtin.LinkMode.%s;\n", ZIG_QUOTE(ZIG_LINK_MODE)); |
| 9105 | buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch.endian()`\n"); | ||
| 9106 | buf_append_str(contents, "pub const endian = Target.current.cpu.arch.endian();\n"); | ||
| 9107 | buf_appendf(contents, "pub const output_mode = OutputMode.Obj;\n"); | ||
| 9108 | buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", ZIG_QUOTE(ZIG_LINK_MODE)); | ||
| 9109 | buf_appendf(contents, "pub const is_test = false;\n"); | 9107 | buf_appendf(contents, "pub const is_test = false;\n"); |
| 9110 | buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); | 9108 | buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); |
| 9111 | buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi); | 9109 | buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi); |
| 9112 | buf_appendf(contents, "pub const cpu: Cpu = Target.Cpu.baseline(.%s);\n", cur_arch); | 9110 | buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch); |
| 9113 | buf_appendf(contents, "pub const os = Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os); | 9111 | buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os); |
| 9114 | buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt); | 9112 | buf_appendf(contents, |
| 9115 | buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode)); | 9113 | "pub const target = std.Target{\n" |
| 9114 | " .cpu = cpu,\n" | ||
| 9115 | " .os = os,\n" | ||
| 9116 | " .abi = abi,\n" | ||
| 9117 | "};\n" | ||
| 9118 | ); | ||
| 9119 | |||
| 9120 | buf_appendf(contents, "pub const object_format = std.Target.ObjectFormat.%s;\n", cur_obj_fmt); | ||
| 9121 | buf_appendf(contents, "pub const mode = std.builtin.Mode.%s;\n", build_mode_to_str(g->build_mode)); | ||
| 9116 | buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc)); | 9122 | buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc)); |
| 9117 | buf_appendf(contents, "pub const link_libcpp = %s;\n", bool_to_str(g->link_libcpp)); | 9123 | buf_appendf(contents, "pub const link_libcpp = %s;\n", bool_to_str(g->link_libcpp)); |
| 9118 | buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); | 9124 | buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); |
| ... | @@ -9120,13 +9126,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -9120,13 +9126,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 9120 | buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); | 9126 | buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); |
| 9121 | buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie)); | 9127 | buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie)); |
| 9122 | buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); | 9128 | buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); |
| 9123 | buf_appendf(contents, "pub const code_model = CodeModel.default;\n"); | 9129 | buf_appendf(contents, "pub const code_model = std.builtin.CodeModel.default;\n"); |
| 9124 | buf_appendf(contents, "pub const zig_is_stage2 = false;\n"); | 9130 | buf_appendf(contents, "pub const zig_is_stage2 = false;\n"); |
| 9125 | 9131 | ||
| 9126 | { | 9132 | { |
| 9127 | TargetSubsystem detected_subsystem = detect_subsystem(g); | 9133 | TargetSubsystem detected_subsystem = detect_subsystem(g); |
| 9128 | if (detected_subsystem != TargetSubsystemAuto) { | 9134 | if (detected_subsystem != TargetSubsystemAuto) { |
| 9129 | buf_appendf(contents, "pub const explicit_subsystem = SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); | 9135 | buf_appendf(contents, "pub const explicit_subsystem = std.builtin.SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); |
| 9130 | } | 9136 | } |
| 9131 | } | 9137 | } |
| 9132 | 9138 |
src/stage1/ir.cpp+7-16| ... | @@ -30541,22 +30541,13 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou | ... | @@ -30541,22 +30541,13 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 30541 | case ZigTypeIdVector: | 30541 | case ZigTypeIdVector: |
| 30542 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, | 30542 | return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, |
| 30543 | val->type->data.vector.len); | 30543 | val->type->data.vector.len); |
| 30544 | case ZigTypeIdEnum: | 30544 | case ZigTypeIdEnum: { |
| 30545 | switch (val->type->data.enumeration.layout) { | 30545 | ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; |
| 30546 | case ContainerLayoutAuto: | 30546 | src_assert(tag_int_type->id == ZigTypeIdInt, source_node); |
| 30547 | zig_panic("TODO buf_read_value_bytes enum auto"); | 30547 | bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, |
| 30548 | case ContainerLayoutPacked: | 30548 | codegen->is_big_endian, tag_int_type->data.integral.is_signed); |
| 30549 | zig_panic("TODO buf_read_value_bytes enum packed"); | 30549 | return ErrorNone; |
| 30550 | case ContainerLayoutExtern: { | 30550 | } case ZigTypeIdStruct: |
| 30551 | ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; | ||
| 30552 | src_assert(tag_int_type->id == ZigTypeIdInt, source_node); | ||
| 30553 | bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, | ||
| 30554 | codegen->is_big_endian, tag_int_type->data.integral.is_signed); | ||
| 30555 | return ErrorNone; | ||
| 30556 | } | ||
| 30557 | } | ||
| 30558 | zig_unreachable(); | ||
| 30559 | case ZigTypeIdStruct: | ||
| 30560 | switch (val->type->data.structure.layout) { | 30551 | switch (val->type->data.structure.layout) { |
| 30561 | case ContainerLayoutAuto: { | 30552 | case ContainerLayoutAuto: { |
| 30562 | switch(val->type->data.structure.special){ | 30553 | switch(val->type->data.structure.special){ |
src/test.zig+22-131| ... | @@ -2,7 +2,6 @@ const std = @import("std"); | ... | @@ -2,7 +2,6 @@ const std = @import("std"); |
| 2 | const link = @import("link.zig"); | 2 | const link = @import("link.zig"); |
| 3 | const Compilation = @import("Compilation.zig"); | 3 | const Compilation = @import("Compilation.zig"); |
| 4 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const zir = @import("zir.zig"); | ||
| 6 | const Package = @import("Package.zig"); | 5 | const Package = @import("Package.zig"); |
| 7 | const introspect = @import("introspect.zig"); | 6 | const introspect = @import("introspect.zig"); |
| 8 | const build_options = @import("build_options"); | 7 | const build_options = @import("build_options"); |
| ... | @@ -16,7 +15,7 @@ const CrossTarget = std.zig.CrossTarget; | ... | @@ -16,7 +15,7 @@ const CrossTarget = std.zig.CrossTarget; |
| 16 | 15 | ||
| 17 | const zig_h = link.File.C.zig_h; | 16 | const zig_h = link.File.C.zig_h; |
| 18 | 17 | ||
| 19 | const hr = "=" ** 40; | 18 | const hr = "=" ** 80; |
| 20 | 19 | ||
| 21 | test "self-hosted" { | 20 | test "self-hosted" { |
| 22 | var ctx = TestContext.init(); | 21 | var ctx = TestContext.init(); |
| ... | @@ -137,7 +136,7 @@ pub const TestContext = struct { | ... | @@ -137,7 +136,7 @@ pub const TestContext = struct { |
| 137 | /// to Executable. | 136 | /// to Executable. |
| 138 | output_mode: std.builtin.OutputMode, | 137 | output_mode: std.builtin.OutputMode, |
| 139 | updates: std.ArrayList(Update), | 138 | updates: std.ArrayList(Update), |
| 140 | object_format: ?std.builtin.ObjectFormat = null, | 139 | object_format: ?std.Target.ObjectFormat = null, |
| 141 | emit_h: bool = false, | 140 | emit_h: bool = false, |
| 142 | llvm_backend: bool = false, | 141 | llvm_backend: bool = false, |
| 143 | 142 | ||
| ... | @@ -543,6 +542,8 @@ pub const TestContext = struct { | ... | @@ -543,6 +542,8 @@ pub const TestContext = struct { |
| 543 | }; | 542 | }; |
| 544 | defer std.testing.allocator.free(global_cache_directory.path.?); | 543 | defer std.testing.allocator.free(global_cache_directory.path.?); |
| 545 | 544 | ||
| 545 | var fail_count: usize = 0; | ||
| 546 | |||
| 546 | for (self.cases.items) |case| { | 547 | for (self.cases.items) |case| { |
| 547 | if (build_options.skip_non_native and case.target.getCpuArch() != std.Target.current.cpu.arch) | 548 | if (build_options.skip_non_native and case.target.getCpuArch() != std.Target.current.cpu.arch) |
| 548 | continue; | 549 | continue; |
| ... | @@ -560,14 +561,21 @@ pub const TestContext = struct { | ... | @@ -560,14 +561,21 @@ pub const TestContext = struct { |
| 560 | progress.initial_delay_ns = 0; | 561 | progress.initial_delay_ns = 0; |
| 561 | progress.refresh_rate_ns = 0; | 562 | progress.refresh_rate_ns = 0; |
| 562 | 563 | ||
| 563 | try self.runOneCase( | 564 | self.runOneCase( |
| 564 | std.testing.allocator, | 565 | std.testing.allocator, |
| 565 | &prg_node, | 566 | &prg_node, |
| 566 | case, | 567 | case, |
| 567 | zig_lib_directory, | 568 | zig_lib_directory, |
| 568 | &thread_pool, | 569 | &thread_pool, |
| 569 | global_cache_directory, | 570 | global_cache_directory, |
| 570 | ); | 571 | ) catch |err| { |
| 572 | fail_count += 1; | ||
| 573 | std.debug.print("test '{s}' failed: {s}\n\n", .{ case.name, @errorName(err) }); | ||
| 574 | }; | ||
| 575 | } | ||
| 576 | if (fail_count != 0) { | ||
| 577 | std.debug.print("{d} tests failed\n", .{fail_count}); | ||
| 578 | return error.TestFailed; | ||
| 571 | } | 579 | } |
| 572 | } | 580 | } |
| 573 | 581 | ||
| ... | @@ -603,7 +611,6 @@ pub const TestContext = struct { | ... | @@ -603,7 +611,6 @@ pub const TestContext = struct { |
| 603 | var root_pkg: Package = .{ | 611 | var root_pkg: Package = .{ |
| 604 | .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir }, | 612 | .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir }, |
| 605 | .root_src_path = tmp_src_path, | 613 | .root_src_path = tmp_src_path, |
| 606 | .namespace_hash = Package.root_namespace_hash, | ||
| 607 | }; | 614 | }; |
| 608 | defer root_pkg.table.deinit(allocator); | 615 | defer root_pkg.table.deinit(allocator); |
| 609 | 616 | ||
| ... | @@ -695,8 +702,7 @@ pub const TestContext = struct { | ... | @@ -695,8 +702,7 @@ pub const TestContext = struct { |
| 695 | } | 702 | } |
| 696 | } | 703 | } |
| 697 | // TODO print generated C code | 704 | // TODO print generated C code |
| 698 | std.debug.print("Test failed.\n", .{}); | 705 | return error.UnexpectedCompileErrors; |
| 699 | std.process.exit(1); | ||
| 700 | } | 706 | } |
| 701 | } | 707 | } |
| 702 | 708 | ||
| ... | @@ -819,10 +825,8 @@ pub const TestContext = struct { | ... | @@ -819,10 +825,8 @@ pub const TestContext = struct { |
| 819 | } | 825 | } |
| 820 | 826 | ||
| 821 | if (any_failed) { | 827 | if (any_failed) { |
| 822 | std.debug.print("\nTest case '{s}' failed, update_index={d}.\n", .{ | 828 | std.debug.print("\nupdate_index={d} ", .{update_index}); |
| 823 | case.name, update_index, | 829 | return error.WrongCompileErrors; |
| 824 | }); | ||
| 825 | std.process.exit(1); | ||
| 826 | } | 830 | } |
| 827 | }, | 831 | }, |
| 828 | .Execution => |expected_stdout| { | 832 | .Execution => |expected_stdout| { |
| ... | @@ -858,10 +862,7 @@ pub const TestContext = struct { | ... | @@ -858,10 +862,7 @@ pub const TestContext = struct { |
| 858 | }); | 862 | }); |
| 859 | } else switch (case.target.getExternalExecutor()) { | 863 | } else switch (case.target.getExternalExecutor()) { |
| 860 | .native => try argv.append(exe_path), | 864 | .native => try argv.append(exe_path), |
| 861 | .unavailable => { | 865 | .unavailable => return, // Pass test. |
| 862 | try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name); | ||
| 863 | return; // Pass test. | ||
| 864 | }, | ||
| 865 | 866 | ||
| 866 | .qemu => |qemu_bin_name| if (enable_qemu) { | 867 | .qemu => |qemu_bin_name| if (enable_qemu) { |
| 867 | // TODO Ability for test cases to specify whether to link libc. | 868 | // TODO Ability for test cases to specify whether to link libc. |
| ... | @@ -920,11 +921,11 @@ pub const TestContext = struct { | ... | @@ -920,11 +921,11 @@ pub const TestContext = struct { |
| 920 | .cwd_dir = tmp.dir, | 921 | .cwd_dir = tmp.dir, |
| 921 | .cwd = tmp_dir_path, | 922 | .cwd = tmp_dir_path, |
| 922 | }) catch |err| { | 923 | }) catch |err| { |
| 923 | std.debug.print("\nThe following command failed with {s}:\n", .{ | 924 | std.debug.print("\nupdate_index={d} The following command failed with {s}:\n", .{ |
| 924 | @errorName(err), | 925 | update_index, @errorName(err), |
| 925 | }); | 926 | }); |
| 926 | dumpArgs(argv.items); | 927 | dumpArgs(argv.items); |
| 927 | return error.ZigTestFailed; | 928 | return error.ChildProcessExecution; |
| 928 | }; | 929 | }; |
| 929 | }; | 930 | }; |
| 930 | var test_node = update_node.start("test", 0); | 931 | var test_node = update_node.start("test", 0); |
| ... | @@ -939,7 +940,7 @@ pub const TestContext = struct { | ... | @@ -939,7 +940,7 @@ pub const TestContext = struct { |
| 939 | exec_result.stderr, case.name, code, | 940 | exec_result.stderr, case.name, code, |
| 940 | }); | 941 | }); |
| 941 | dumpArgs(argv.items); | 942 | dumpArgs(argv.items); |
| 942 | return error.ZigTestFailed; | 943 | return error.ChildProcessExecution; |
| 943 | } | 944 | } |
| 944 | }, | 945 | }, |
| 945 | else => { | 946 | else => { |
| ... | @@ -947,7 +948,7 @@ pub const TestContext = struct { | ... | @@ -947,7 +948,7 @@ pub const TestContext = struct { |
| 947 | exec_result.stderr, case.name, | 948 | exec_result.stderr, case.name, |
| 948 | }); | 949 | }); |
| 949 | dumpArgs(argv.items); | 950 | dumpArgs(argv.items); |
| 950 | return error.ZigTestFailed; | 951 | return error.ChildProcessExecution; |
| 951 | }, | 952 | }, |
| 952 | } | 953 | } |
| 953 | try std.testing.expectEqualStrings(expected_stdout, exec_result.stdout); | 954 | try std.testing.expectEqualStrings(expected_stdout, exec_result.stdout); |
| ... | @@ -959,116 +960,6 @@ pub const TestContext = struct { | ... | @@ -959,116 +960,6 @@ pub const TestContext = struct { |
| 959 | } | 960 | } |
| 960 | } | 961 | } |
| 961 | 962 | ||
| 962 | fn runInterpreterIfAvailable( | ||
| 963 | self: *TestContext, | ||
| 964 | gpa: *Allocator, | ||
| 965 | node: *std.Progress.Node, | ||
| 966 | case: Case, | ||
| 967 | tmp_dir: std.fs.Dir, | ||
| 968 | bin_name: []const u8, | ||
| 969 | ) !void { | ||
| 970 | const arch = case.target.cpu_arch orelse return; | ||
| 971 | switch (arch) { | ||
| 972 | .spu_2 => return self.runSpu2Interpreter(gpa, node, case, tmp_dir, bin_name), | ||
| 973 | else => return, | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | fn runSpu2Interpreter( | ||
| 978 | self: *TestContext, | ||
| 979 | gpa: *Allocator, | ||
| 980 | update_node: *std.Progress.Node, | ||
| 981 | case: Case, | ||
| 982 | tmp_dir: std.fs.Dir, | ||
| 983 | bin_name: []const u8, | ||
| 984 | ) !void { | ||
| 985 | const spu = @import("codegen/spu-mk2.zig"); | ||
| 986 | if (case.target.os_tag) |os| { | ||
| 987 | if (os != .freestanding) { | ||
| 988 | std.debug.panic("Only freestanding makes sense for SPU-II tests!", .{}); | ||
| 989 | } | ||
| 990 | } else { | ||
| 991 | std.debug.panic("SPU_2 has no native OS, check the test!", .{}); | ||
| 992 | } | ||
| 993 | |||
| 994 | var interpreter = spu.Interpreter(struct { | ||
| 995 | RAM: [0x10000]u8 = undefined, | ||
| 996 | |||
| 997 | pub fn read8(bus: @This(), addr: u16) u8 { | ||
| 998 | return bus.RAM[addr]; | ||
| 999 | } | ||
| 1000 | pub fn read16(bus: @This(), addr: u16) u16 { | ||
| 1001 | return std.mem.readIntLittle(u16, bus.RAM[addr..][0..2]); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | pub fn write8(bus: *@This(), addr: u16, val: u8) void { | ||
| 1005 | bus.RAM[addr] = val; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | pub fn write16(bus: *@This(), addr: u16, val: u16) void { | ||
| 1009 | std.mem.writeIntLittle(u16, bus.RAM[addr..][0..2], val); | ||
| 1010 | } | ||
| 1011 | }){ | ||
| 1012 | .bus = .{}, | ||
| 1013 | }; | ||
| 1014 | |||
| 1015 | { | ||
| 1016 | var load_node = update_node.start("load", 0); | ||
| 1017 | load_node.activate(); | ||
| 1018 | defer load_node.end(); | ||
| 1019 | |||
| 1020 | var file = try tmp_dir.openFile(bin_name, .{ .read = true }); | ||
| 1021 | defer file.close(); | ||
| 1022 | |||
| 1023 | const header = try std.elf.Header.read(&file); | ||
| 1024 | var iterator = header.program_header_iterator(&file); | ||
| 1025 | |||
| 1026 | var none_loaded = true; | ||
| 1027 | |||
| 1028 | while (try iterator.next()) |phdr| { | ||
| 1029 | if (phdr.p_type != std.elf.PT_LOAD) { | ||
| 1030 | std.debug.print("Encountered unexpected ELF program header: type {}\n", .{phdr.p_type}); | ||
| 1031 | std.process.exit(1); | ||
| 1032 | } | ||
| 1033 | if (phdr.p_paddr != phdr.p_vaddr) { | ||
| 1034 | std.debug.print("Physical address does not match virtual address in ELF header!\n", .{}); | ||
| 1035 | std.process.exit(1); | ||
| 1036 | } | ||
| 1037 | if (phdr.p_filesz != phdr.p_memsz) { | ||
| 1038 | std.debug.print("Physical size does not match virtual size in ELF header!\n", .{}); | ||
| 1039 | std.process.exit(1); | ||
| 1040 | } | ||
| 1041 | if ((try file.pread(interpreter.bus.RAM[phdr.p_paddr .. phdr.p_paddr + phdr.p_filesz], phdr.p_offset)) != phdr.p_filesz) { | ||
| 1042 | std.debug.print("Read less than expected from ELF file!", .{}); | ||
| 1043 | std.process.exit(1); | ||
| 1044 | } | ||
| 1045 | std.log.scoped(.spu2_test).debug("Loaded 0x{x} bytes to 0x{x:0<4}\n", .{ phdr.p_filesz, phdr.p_paddr }); | ||
| 1046 | none_loaded = false; | ||
| 1047 | } | ||
| 1048 | if (none_loaded) { | ||
| 1049 | std.debug.print("No data found in ELF file!\n", .{}); | ||
| 1050 | std.process.exit(1); | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | var exec_node = update_node.start("execute", 0); | ||
| 1055 | exec_node.activate(); | ||
| 1056 | defer exec_node.end(); | ||
| 1057 | |||
| 1058 | var blocks: u16 = 1000; | ||
| 1059 | const block_size = 1000; | ||
| 1060 | while (!interpreter.undefined0) { | ||
| 1061 | const pre_ip = interpreter.ip; | ||
| 1062 | if (blocks > 0) { | ||
| 1063 | blocks -= 1; | ||
| 1064 | try interpreter.ExecuteBlock(block_size); | ||
| 1065 | if (pre_ip == interpreter.ip) { | ||
| 1066 | std.debug.print("Infinite loop detected in SPU II test!\n", .{}); | ||
| 1067 | std.process.exit(1); | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | } | ||
| 1071 | } | ||
| 1072 | }; | 963 | }; |
| 1073 | 964 | ||
| 1074 | fn dumpArgs(argv: []const []const u8) void { | 965 | fn dumpArgs(argv: []const []const u8) void { |
src/type.zig+600-45| ... | @@ -69,7 +69,14 @@ pub const Type = extern union { | ... | @@ -69,7 +69,14 @@ pub const Type = extern union { |
| 69 | .fn_ccc_void_no_args => return .Fn, | 69 | .fn_ccc_void_no_args => return .Fn, |
| 70 | .function => return .Fn, | 70 | .function => return .Fn, |
| 71 | 71 | ||
| 72 | .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, | 72 | .array, |
| 73 | .array_u8_sentinel_0, | ||
| 74 | .array_u8, | ||
| 75 | .array_sentinel, | ||
| 76 | => return .Array, | ||
| 77 | |||
| 78 | .vector => return .Vector, | ||
| 79 | |||
| 73 | .single_const_pointer_to_comptime_int, | 80 | .single_const_pointer_to_comptime_int, |
| 74 | .const_slice_u8, | 81 | .const_slice_u8, |
| 75 | .single_const_pointer, | 82 | .single_const_pointer, |
| ... | @@ -83,6 +90,8 @@ pub const Type = extern union { | ... | @@ -83,6 +90,8 @@ pub const Type = extern union { |
| 83 | .pointer, | 90 | .pointer, |
| 84 | .inferred_alloc_const, | 91 | .inferred_alloc_const, |
| 85 | .inferred_alloc_mut, | 92 | .inferred_alloc_mut, |
| 93 | .manyptr_u8, | ||
| 94 | .manyptr_const_u8, | ||
| 86 | => return .Pointer, | 95 | => return .Pointer, |
| 87 | 96 | ||
| 88 | .optional, | 97 | .optional, |
| ... | @@ -93,16 +102,30 @@ pub const Type = extern union { | ... | @@ -93,16 +102,30 @@ pub const Type = extern union { |
| 93 | 102 | ||
| 94 | .anyerror_void_error_union, .error_union => return .ErrorUnion, | 103 | .anyerror_void_error_union, .error_union => return .ErrorUnion, |
| 95 | 104 | ||
| 105 | .anyframe_T, .@"anyframe" => return .AnyFrame, | ||
| 106 | |||
| 96 | .empty_struct, | 107 | .empty_struct, |
| 97 | .empty_struct_literal, | 108 | .empty_struct_literal, |
| 98 | .@"struct", | 109 | .@"struct", |
| 110 | .call_options, | ||
| 111 | .export_options, | ||
| 112 | .extern_options, | ||
| 99 | => return .Struct, | 113 | => return .Struct, |
| 100 | 114 | ||
| 101 | .enum_full, | 115 | .enum_full, |
| 102 | .enum_nonexhaustive, | 116 | .enum_nonexhaustive, |
| 103 | .enum_simple, | 117 | .enum_simple, |
| 118 | .atomic_ordering, | ||
| 119 | .atomic_rmw_op, | ||
| 120 | .calling_convention, | ||
| 121 | .float_mode, | ||
| 122 | .reduce_op, | ||
| 104 | => return .Enum, | 123 | => return .Enum, |
| 105 | 124 | ||
| 125 | .@"union", | ||
| 126 | .union_tagged, | ||
| 127 | => return .Union, | ||
| 128 | |||
| 106 | .var_args_param => unreachable, // can be any type | 129 | .var_args_param => unreachable, // can be any type |
| 107 | } | 130 | } |
| 108 | } | 131 | } |
| ... | @@ -205,6 +228,8 @@ pub const Type = extern union { | ... | @@ -205,6 +228,8 @@ pub const Type = extern union { |
| 205 | .mut_slice, | 228 | .mut_slice, |
| 206 | .optional_single_const_pointer, | 229 | .optional_single_const_pointer, |
| 207 | .optional_single_mut_pointer, | 230 | .optional_single_mut_pointer, |
| 231 | .manyptr_u8, | ||
| 232 | .manyptr_const_u8, | ||
| 208 | => self.cast(Payload.ElemType), | 233 | => self.cast(Payload.ElemType), |
| 209 | 234 | ||
| 210 | .inferred_alloc_const => unreachable, | 235 | .inferred_alloc_const => unreachable, |
| ... | @@ -271,6 +296,17 @@ pub const Type = extern union { | ... | @@ -271,6 +296,17 @@ pub const Type = extern union { |
| 271 | .@"volatile" = false, | 296 | .@"volatile" = false, |
| 272 | .size = .Many, | 297 | .size = .Many, |
| 273 | } }, | 298 | } }, |
| 299 | .manyptr_const_u8 => return .{ .data = .{ | ||
| 300 | .pointee_type = Type.initTag(.u8), | ||
| 301 | .sentinel = null, | ||
| 302 | .@"align" = 0, | ||
| 303 | .bit_offset = 0, | ||
| 304 | .host_size = 0, | ||
| 305 | .@"allowzero" = false, | ||
| 306 | .mutable = false, | ||
| 307 | .@"volatile" = false, | ||
| 308 | .size = .Many, | ||
| 309 | } }, | ||
| 274 | .many_mut_pointer => return .{ .data = .{ | 310 | .many_mut_pointer => return .{ .data = .{ |
| 275 | .pointee_type = self.castPointer().?.data, | 311 | .pointee_type = self.castPointer().?.data, |
| 276 | .sentinel = null, | 312 | .sentinel = null, |
| ... | @@ -282,6 +318,17 @@ pub const Type = extern union { | ... | @@ -282,6 +318,17 @@ pub const Type = extern union { |
| 282 | .@"volatile" = false, | 318 | .@"volatile" = false, |
| 283 | .size = .Many, | 319 | .size = .Many, |
| 284 | } }, | 320 | } }, |
| 321 | .manyptr_u8 => return .{ .data = .{ | ||
| 322 | .pointee_type = Type.initTag(.u8), | ||
| 323 | .sentinel = null, | ||
| 324 | .@"align" = 0, | ||
| 325 | .bit_offset = 0, | ||
| 326 | .host_size = 0, | ||
| 327 | .@"allowzero" = false, | ||
| 328 | .mutable = true, | ||
| 329 | .@"volatile" = false, | ||
| 330 | .size = .Many, | ||
| 331 | } }, | ||
| 285 | .c_const_pointer => return .{ .data = .{ | 332 | .c_const_pointer => return .{ .data = .{ |
| 286 | .pointee_type = self.castPointer().?.data, | 333 | .pointee_type = self.castPointer().?.data, |
| 287 | .sentinel = null, | 334 | .sentinel = null, |
| ... | @@ -402,7 +449,7 @@ pub const Type = extern union { | ... | @@ -402,7 +449,7 @@ pub const Type = extern union { |
| 402 | const info_b = b.intInfo(@as(Target, undefined)); | 449 | const info_b = b.intInfo(@as(Target, undefined)); |
| 403 | return info_a.signedness == info_b.signedness and info_a.bits == info_b.bits; | 450 | return info_a.signedness == info_b.signedness and info_a.bits == info_b.bits; |
| 404 | }, | 451 | }, |
| 405 | .Array => { | 452 | .Array, .Vector => { |
| 406 | if (a.arrayLen() != b.arrayLen()) | 453 | if (a.arrayLen() != b.arrayLen()) |
| 407 | return false; | 454 | return false; |
| 408 | if (!a.elemType().eql(b.elemType())) | 455 | if (!a.elemType().eql(b.elemType())) |
| ... | @@ -442,16 +489,41 @@ pub const Type = extern union { | ... | @@ -442,16 +489,41 @@ pub const Type = extern union { |
| 442 | var buf_b: Payload.ElemType = undefined; | 489 | var buf_b: Payload.ElemType = undefined; |
| 443 | return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); | 490 | return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); |
| 444 | }, | 491 | }, |
| 492 | .Struct => { | ||
| 493 | if (a.castTag(.@"struct")) |a_payload| { | ||
| 494 | if (b.castTag(.@"struct")) |b_payload| { | ||
| 495 | return a_payload.data == b_payload.data; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | return a.tag() == b.tag(); | ||
| 499 | }, | ||
| 500 | .Enum => { | ||
| 501 | if (a.cast(Payload.EnumFull)) |a_payload| { | ||
| 502 | if (b.cast(Payload.EnumFull)) |b_payload| { | ||
| 503 | return a_payload.data == b_payload.data; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | if (a.cast(Payload.EnumSimple)) |a_payload| { | ||
| 507 | if (b.cast(Payload.EnumSimple)) |b_payload| { | ||
| 508 | return a_payload.data == b_payload.data; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | return a.tag() == b.tag(); | ||
| 512 | }, | ||
| 513 | .Union => { | ||
| 514 | if (a.cast(Payload.Union)) |a_payload| { | ||
| 515 | if (b.cast(Payload.Union)) |b_payload| { | ||
| 516 | return a_payload.data == b_payload.data; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | return a.tag() == b.tag(); | ||
| 520 | }, | ||
| 521 | .Opaque, | ||
| 445 | .Float, | 522 | .Float, |
| 446 | .Struct, | ||
| 447 | .ErrorUnion, | 523 | .ErrorUnion, |
| 448 | .ErrorSet, | 524 | .ErrorSet, |
| 449 | .Enum, | ||
| 450 | .Union, | ||
| 451 | .BoundFn, | 525 | .BoundFn, |
| 452 | .Opaque, | ||
| 453 | .Frame, | 526 | .Frame, |
| 454 | .Vector, | ||
| 455 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), | 527 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
| 456 | } | 528 | } |
| 457 | } | 529 | } |
| ... | @@ -486,7 +558,7 @@ pub const Type = extern union { | ... | @@ -486,7 +558,7 @@ pub const Type = extern union { |
| 486 | std.hash.autoHash(&hasher, info.bits); | 558 | std.hash.autoHash(&hasher, info.bits); |
| 487 | } | 559 | } |
| 488 | }, | 560 | }, |
| 489 | .Array => { | 561 | .Array, .Vector => { |
| 490 | std.hash.autoHash(&hasher, self.arrayLen()); | 562 | std.hash.autoHash(&hasher, self.arrayLen()); |
| 491 | std.hash.autoHash(&hasher, self.elemType().hash()); | 563 | std.hash.autoHash(&hasher, self.elemType().hash()); |
| 492 | // TODO hash array sentinel | 564 | // TODO hash array sentinel |
| ... | @@ -516,7 +588,6 @@ pub const Type = extern union { | ... | @@ -516,7 +588,6 @@ pub const Type = extern union { |
| 516 | .Opaque, | 588 | .Opaque, |
| 517 | .Frame, | 589 | .Frame, |
| 518 | .AnyFrame, | 590 | .AnyFrame, |
| 519 | .Vector, | ||
| 520 | .EnumLiteral, | 591 | .EnumLiteral, |
| 521 | => { | 592 | => { |
| 522 | // TODO implement more type hashing | 593 | // TODO implement more type hashing |
| ... | @@ -576,6 +647,17 @@ pub const Type = extern union { | ... | @@ -576,6 +647,17 @@ pub const Type = extern union { |
| 576 | .inferred_alloc_mut, | 647 | .inferred_alloc_mut, |
| 577 | .var_args_param, | 648 | .var_args_param, |
| 578 | .empty_struct_literal, | 649 | .empty_struct_literal, |
| 650 | .manyptr_u8, | ||
| 651 | .manyptr_const_u8, | ||
| 652 | .atomic_ordering, | ||
| 653 | .atomic_rmw_op, | ||
| 654 | .calling_convention, | ||
| 655 | .float_mode, | ||
| 656 | .reduce_op, | ||
| 657 | .call_options, | ||
| 658 | .export_options, | ||
| 659 | .extern_options, | ||
| 660 | .@"anyframe", | ||
| 579 | => unreachable, | 661 | => unreachable, |
| 580 | 662 | ||
| 581 | .array_u8, | 663 | .array_u8, |
| ... | @@ -593,12 +675,20 @@ pub const Type = extern union { | ... | @@ -593,12 +675,20 @@ pub const Type = extern union { |
| 593 | .optional, | 675 | .optional, |
| 594 | .optional_single_mut_pointer, | 676 | .optional_single_mut_pointer, |
| 595 | .optional_single_const_pointer, | 677 | .optional_single_const_pointer, |
| 678 | .anyframe_T, | ||
| 596 | => return self.copyPayloadShallow(allocator, Payload.ElemType), | 679 | => return self.copyPayloadShallow(allocator, Payload.ElemType), |
| 597 | 680 | ||
| 598 | .int_signed, | 681 | .int_signed, |
| 599 | .int_unsigned, | 682 | .int_unsigned, |
| 600 | => return self.copyPayloadShallow(allocator, Payload.Bits), | 683 | => return self.copyPayloadShallow(allocator, Payload.Bits), |
| 601 | 684 | ||
| 685 | .vector => { | ||
| 686 | const payload = self.castTag(.vector).?.data; | ||
| 687 | return Tag.vector.create(allocator, .{ | ||
| 688 | .len = payload.len, | ||
| 689 | .elem_type = try payload.elem_type.copy(allocator), | ||
| 690 | }); | ||
| 691 | }, | ||
| 602 | .array => { | 692 | .array => { |
| 603 | const payload = self.castTag(.array).?.data; | 693 | const payload = self.castTag(.array).?.data; |
| 604 | return Tag.array.create(allocator, .{ | 694 | return Tag.array.create(allocator, .{ |
| ... | @@ -656,6 +746,7 @@ pub const Type = extern union { | ... | @@ -656,6 +746,7 @@ pub const Type = extern union { |
| 656 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), | 746 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), |
| 657 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), | 747 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), |
| 658 | .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), | 748 | .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), |
| 749 | .@"union", .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union), | ||
| 659 | .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), | 750 | .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), |
| 660 | .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), | 751 | .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), |
| 661 | .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque), | 752 | .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque), |
| ... | @@ -710,6 +801,7 @@ pub const Type = extern union { | ... | @@ -710,6 +801,7 @@ pub const Type = extern union { |
| 710 | .void, | 801 | .void, |
| 711 | .type, | 802 | .type, |
| 712 | .anyerror, | 803 | .anyerror, |
| 804 | .@"anyframe", | ||
| 713 | .comptime_int, | 805 | .comptime_int, |
| 714 | .comptime_float, | 806 | .comptime_float, |
| 715 | .noreturn, | 807 | .noreturn, |
| ... | @@ -726,6 +818,10 @@ pub const Type = extern union { | ... | @@ -726,6 +818,10 @@ pub const Type = extern union { |
| 726 | const struct_obj = ty.castTag(.@"struct").?.data; | 818 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 727 | return struct_obj.owner_decl.renderFullyQualifiedName(writer); | 819 | return struct_obj.owner_decl.renderFullyQualifiedName(writer); |
| 728 | }, | 820 | }, |
| 821 | .@"union", .union_tagged => { | ||
| 822 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 823 | return union_obj.owner_decl.renderFullyQualifiedName(writer); | ||
| 824 | }, | ||
| 729 | .enum_full, .enum_nonexhaustive => { | 825 | .enum_full, .enum_nonexhaustive => { |
| 730 | const enum_full = ty.cast(Payload.EnumFull).?.data; | 826 | const enum_full = ty.cast(Payload.EnumFull).?.data; |
| 731 | return enum_full.owner_decl.renderFullyQualifiedName(writer); | 827 | return enum_full.owner_decl.renderFullyQualifiedName(writer); |
| ... | @@ -746,6 +842,16 @@ pub const Type = extern union { | ... | @@ -746,6 +842,16 @@ pub const Type = extern union { |
| 746 | .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), | 842 | .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), |
| 747 | .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"), | 843 | .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"), |
| 748 | .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), | 844 | .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), |
| 845 | .manyptr_u8 => return writer.writeAll("[*]u8"), | ||
| 846 | .manyptr_const_u8 => return writer.writeAll("[*]const u8"), | ||
| 847 | .atomic_ordering => return writer.writeAll("std.builtin.AtomicOrdering"), | ||
| 848 | .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"), | ||
| 849 | .calling_convention => return writer.writeAll("std.builtin.CallingConvention"), | ||
| 850 | .float_mode => return writer.writeAll("std.builtin.FloatMode"), | ||
| 851 | .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), | ||
| 852 | .call_options => return writer.writeAll("std.builtin.CallOptions"), | ||
| 853 | .export_options => return writer.writeAll("std.builtin.ExportOptions"), | ||
| 854 | .extern_options => return writer.writeAll("std.builtin.ExternOptions"), | ||
| 749 | .function => { | 855 | .function => { |
| 750 | const payload = ty.castTag(.function).?.data; | 856 | const payload = ty.castTag(.function).?.data; |
| 751 | try writer.writeAll("fn("); | 857 | try writer.writeAll("fn("); |
| ... | @@ -766,6 +872,12 @@ pub const Type = extern union { | ... | @@ -766,6 +872,12 @@ pub const Type = extern union { |
| 766 | continue; | 872 | continue; |
| 767 | }, | 873 | }, |
| 768 | 874 | ||
| 875 | .anyframe_T => { | ||
| 876 | const return_type = ty.castTag(.anyframe_T).?.data; | ||
| 877 | try writer.print("anyframe->", .{}); | ||
| 878 | ty = return_type; | ||
| 879 | continue; | ||
| 880 | }, | ||
| 769 | .array_u8 => { | 881 | .array_u8 => { |
| 770 | const len = ty.castTag(.array_u8).?.data; | 882 | const len = ty.castTag(.array_u8).?.data; |
| 771 | return writer.print("[{d}]u8", .{len}); | 883 | return writer.print("[{d}]u8", .{len}); |
| ... | @@ -774,6 +886,12 @@ pub const Type = extern union { | ... | @@ -774,6 +886,12 @@ pub const Type = extern union { |
| 774 | const len = ty.castTag(.array_u8_sentinel_0).?.data; | 886 | const len = ty.castTag(.array_u8_sentinel_0).?.data; |
| 775 | return writer.print("[{d}:0]u8", .{len}); | 887 | return writer.print("[{d}:0]u8", .{len}); |
| 776 | }, | 888 | }, |
| 889 | .vector => { | ||
| 890 | const payload = ty.castTag(.vector).?.data; | ||
| 891 | try writer.print("@Vector({d}, ", .{payload.len}); | ||
| 892 | try payload.elem_type.format("", .{}, writer); | ||
| 893 | return writer.writeAll(")"); | ||
| 894 | }, | ||
| 777 | .array => { | 895 | .array => { |
| 778 | const payload = ty.castTag(.array).?.data; | 896 | const payload = ty.castTag(.array).?.data; |
| 779 | try writer.print("[{d}]", .{payload.len}); | 897 | try writer.print("[{d}]", .{payload.len}); |
| ... | @@ -940,6 +1058,7 @@ pub const Type = extern union { | ... | @@ -940,6 +1058,7 @@ pub const Type = extern union { |
| 940 | .void => return Value.initTag(.void_type), | 1058 | .void => return Value.initTag(.void_type), |
| 941 | .type => return Value.initTag(.type_type), | 1059 | .type => return Value.initTag(.type_type), |
| 942 | .anyerror => return Value.initTag(.anyerror_type), | 1060 | .anyerror => return Value.initTag(.anyerror_type), |
| 1061 | .@"anyframe" => return Value.initTag(.anyframe_type), | ||
| 943 | .comptime_int => return Value.initTag(.comptime_int_type), | 1062 | .comptime_int => return Value.initTag(.comptime_int_type), |
| 944 | .comptime_float => return Value.initTag(.comptime_float_type), | 1063 | .comptime_float => return Value.initTag(.comptime_float_type), |
| 945 | .noreturn => return Value.initTag(.noreturn_type), | 1064 | .noreturn => return Value.initTag(.noreturn_type), |
| ... | @@ -952,6 +1071,16 @@ pub const Type = extern union { | ... | @@ -952,6 +1071,16 @@ pub const Type = extern union { |
| 952 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), | 1071 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), |
| 953 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), | 1072 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 954 | .enum_literal => return Value.initTag(.enum_literal_type), | 1073 | .enum_literal => return Value.initTag(.enum_literal_type), |
| 1074 | .manyptr_u8 => return Value.initTag(.manyptr_u8_type), | ||
| 1075 | .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type), | ||
| 1076 | .atomic_ordering => return Value.initTag(.atomic_ordering_type), | ||
| 1077 | .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type), | ||
| 1078 | .calling_convention => return Value.initTag(.calling_convention_type), | ||
| 1079 | .float_mode => return Value.initTag(.float_mode_type), | ||
| 1080 | .reduce_op => return Value.initTag(.reduce_op_type), | ||
| 1081 | .call_options => return Value.initTag(.call_options_type), | ||
| 1082 | .export_options => return Value.initTag(.export_options_type), | ||
| 1083 | .extern_options => return Value.initTag(.extern_options_type), | ||
| 955 | .inferred_alloc_const => unreachable, | 1084 | .inferred_alloc_const => unreachable, |
| 956 | .inferred_alloc_mut => unreachable, | 1085 | .inferred_alloc_mut => unreachable, |
| 957 | else => return Value.Tag.ty.create(allocator, self), | 1086 | else => return Value.Tag.ty.create(allocator, self), |
| ... | @@ -1001,6 +1130,18 @@ pub const Type = extern union { | ... | @@ -1001,6 +1130,18 @@ pub const Type = extern union { |
| 1001 | .anyerror_void_error_union, | 1130 | .anyerror_void_error_union, |
| 1002 | .error_set, | 1131 | .error_set, |
| 1003 | .error_set_single, | 1132 | .error_set_single, |
| 1133 | .manyptr_u8, | ||
| 1134 | .manyptr_const_u8, | ||
| 1135 | .atomic_ordering, | ||
| 1136 | .atomic_rmw_op, | ||
| 1137 | .calling_convention, | ||
| 1138 | .float_mode, | ||
| 1139 | .reduce_op, | ||
| 1140 | .call_options, | ||
| 1141 | .export_options, | ||
| 1142 | .extern_options, | ||
| 1143 | .@"anyframe", | ||
| 1144 | .anyframe_T, | ||
| 1004 | => true, | 1145 | => true, |
| 1005 | 1146 | ||
| 1006 | .@"struct" => { | 1147 | .@"struct" => { |
| ... | @@ -1026,9 +1167,30 @@ pub const Type = extern union { | ... | @@ -1026,9 +1167,30 @@ pub const Type = extern union { |
| 1026 | const int_tag_ty = self.intTagType(&buffer); | 1167 | const int_tag_ty = self.intTagType(&buffer); |
| 1027 | return int_tag_ty.hasCodeGenBits(); | 1168 | return int_tag_ty.hasCodeGenBits(); |
| 1028 | }, | 1169 | }, |
| 1170 | .@"union" => { | ||
| 1171 | const union_obj = self.castTag(.@"union").?.data; | ||
| 1172 | for (union_obj.fields.entries.items) |entry| { | ||
| 1173 | if (entry.value.ty.hasCodeGenBits()) | ||
| 1174 | return true; | ||
| 1175 | } else { | ||
| 1176 | return false; | ||
| 1177 | } | ||
| 1178 | }, | ||
| 1179 | .union_tagged => { | ||
| 1180 | const union_obj = self.castTag(.@"union").?.data; | ||
| 1181 | if (union_obj.tag_ty.hasCodeGenBits()) { | ||
| 1182 | return true; | ||
| 1183 | } | ||
| 1184 | for (union_obj.fields.entries.items) |entry| { | ||
| 1185 | if (entry.value.ty.hasCodeGenBits()) | ||
| 1186 | return true; | ||
| 1187 | } else { | ||
| 1188 | return false; | ||
| 1189 | } | ||
| 1190 | }, | ||
| 1029 | 1191 | ||
| 1030 | // TODO lazy types | 1192 | // TODO lazy types |
| 1031 | .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, | 1193 | .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, |
| 1032 | .array_u8 => self.arrayLen() != 0, | 1194 | .array_u8 => self.arrayLen() != 0, |
| 1033 | .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), | 1195 | .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), |
| 1034 | .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0, | 1196 | .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0, |
| ... | @@ -1079,14 +1241,17 @@ pub const Type = extern union { | ... | @@ -1079,14 +1241,17 @@ pub const Type = extern union { |
| 1079 | .optional_single_mut_pointer, | 1241 | .optional_single_mut_pointer, |
| 1080 | => return self.cast(Payload.ElemType).?.data.abiAlignment(target), | 1242 | => return self.cast(Payload.ElemType).?.data.abiAlignment(target), |
| 1081 | 1243 | ||
| 1082 | .const_slice_u8 => return 1, | 1244 | .manyptr_u8, |
| 1245 | .manyptr_const_u8, | ||
| 1246 | .const_slice_u8, | ||
| 1247 | => return 1, | ||
| 1083 | 1248 | ||
| 1084 | .pointer => { | 1249 | .pointer => { |
| 1085 | const ptr_info = self.castTag(.pointer).?.data; | 1250 | const ptr_info = self.castTag(.pointer).?.data; |
| 1086 | if (ptr_info.@"align" != 0) { | 1251 | if (ptr_info.@"align" != 0) { |
| 1087 | return ptr_info.@"align"; | 1252 | return ptr_info.@"align"; |
| 1088 | } else { | 1253 | } else { |
| 1089 | return ptr_info.pointee_type.abiAlignment(); | 1254 | return ptr_info.pointee_type.abiAlignment(target); |
| 1090 | } | 1255 | } |
| 1091 | }, | 1256 | }, |
| 1092 | 1257 | ||
| ... | @@ -1102,6 +1267,14 @@ pub const Type = extern union { | ... | @@ -1102,6 +1267,14 @@ pub const Type = extern union { |
| 1102 | .bool, | 1267 | .bool, |
| 1103 | .array_u8_sentinel_0, | 1268 | .array_u8_sentinel_0, |
| 1104 | .array_u8, | 1269 | .array_u8, |
| 1270 | .atomic_ordering, | ||
| 1271 | .atomic_rmw_op, | ||
| 1272 | .calling_convention, | ||
| 1273 | .float_mode, | ||
| 1274 | .reduce_op, | ||
| 1275 | .call_options, | ||
| 1276 | .export_options, | ||
| 1277 | .extern_options, | ||
| 1105 | => return 1, | 1278 | => return 1, |
| 1106 | 1279 | ||
| 1107 | .fn_noreturn_no_args, // represents machine code; not a pointer | 1280 | .fn_noreturn_no_args, // represents machine code; not a pointer |
| ... | @@ -1136,6 +1309,10 @@ pub const Type = extern union { | ... | @@ -1136,6 +1309,10 @@ pub const Type = extern union { |
| 1136 | .optional_single_const_pointer, | 1309 | .optional_single_const_pointer, |
| 1137 | .optional_single_mut_pointer, | 1310 | .optional_single_mut_pointer, |
| 1138 | .pointer, | 1311 | .pointer, |
| 1312 | .manyptr_u8, | ||
| 1313 | .manyptr_const_u8, | ||
| 1314 | .@"anyframe", | ||
| 1315 | .anyframe_T, | ||
| 1139 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | 1316 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), |
| 1140 | 1317 | ||
| 1141 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), | 1318 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| ... | @@ -1161,6 +1338,10 @@ pub const Type = extern union { | ... | @@ -1161,6 +1338,10 @@ pub const Type = extern union { |
| 1161 | 1338 | ||
| 1162 | .array, .array_sentinel => return self.elemType().abiAlignment(target), | 1339 | .array, .array_sentinel => return self.elemType().abiAlignment(target), |
| 1163 | 1340 | ||
| 1341 | // TODO audit this - is there any more complicated logic to determine | ||
| 1342 | // ABI alignment of vectors? | ||
| 1343 | .vector => return 16, | ||
| 1344 | |||
| 1164 | .int_signed, .int_unsigned => { | 1345 | .int_signed, .int_unsigned => { |
| 1165 | const bits: u16 = self.cast(Payload.Bits).?.data; | 1346 | const bits: u16 = self.cast(Payload.Bits).?.data; |
| 1166 | return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); | 1347 | return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8); |
| ... | @@ -1215,6 +1396,34 @@ pub const Type = extern union { | ... | @@ -1215,6 +1396,34 @@ pub const Type = extern union { |
| 1215 | const int_tag_ty = self.intTagType(&buffer); | 1396 | const int_tag_ty = self.intTagType(&buffer); |
| 1216 | return int_tag_ty.abiAlignment(target); | 1397 | return int_tag_ty.abiAlignment(target); |
| 1217 | }, | 1398 | }, |
| 1399 | .union_tagged => { | ||
| 1400 | const union_obj = self.castTag(.union_tagged).?.data; | ||
| 1401 | var biggest: u32 = union_obj.tag_ty.abiAlignment(target); | ||
| 1402 | for (union_obj.fields.entries.items) |entry| { | ||
| 1403 | const field_ty = entry.value.ty; | ||
| 1404 | if (!field_ty.hasCodeGenBits()) continue; | ||
| 1405 | const field_align = field_ty.abiAlignment(target); | ||
| 1406 | if (field_align > biggest) { | ||
| 1407 | biggest = field_align; | ||
| 1408 | } | ||
| 1409 | } | ||
| 1410 | assert(biggest != 0); | ||
| 1411 | return biggest; | ||
| 1412 | }, | ||
| 1413 | .@"union" => { | ||
| 1414 | const union_obj = self.castTag(.@"union").?.data; | ||
| 1415 | var biggest: u32 = 0; | ||
| 1416 | for (union_obj.fields.entries.items) |entry| { | ||
| 1417 | const field_ty = entry.value.ty; | ||
| 1418 | if (!field_ty.hasCodeGenBits()) continue; | ||
| 1419 | const field_align = field_ty.abiAlignment(target); | ||
| 1420 | if (field_align > biggest) { | ||
| 1421 | biggest = field_align; | ||
| 1422 | } | ||
| 1423 | } | ||
| 1424 | assert(biggest != 0); | ||
| 1425 | return biggest; | ||
| 1426 | }, | ||
| 1218 | .c_void, | 1427 | .c_void, |
| 1219 | .void, | 1428 | .void, |
| 1220 | .type, | 1429 | .type, |
| ... | @@ -1267,16 +1476,27 @@ pub const Type = extern union { | ... | @@ -1267,16 +1476,27 @@ pub const Type = extern union { |
| 1267 | const int_tag_ty = self.intTagType(&buffer); | 1476 | const int_tag_ty = self.intTagType(&buffer); |
| 1268 | return int_tag_ty.abiSize(target); | 1477 | return int_tag_ty.abiSize(target); |
| 1269 | }, | 1478 | }, |
| 1479 | .@"union", .union_tagged => { | ||
| 1480 | @panic("TODO abiSize unions"); | ||
| 1481 | }, | ||
| 1270 | 1482 | ||
| 1271 | .u8, | 1483 | .u8, |
| 1272 | .i8, | 1484 | .i8, |
| 1273 | .bool, | 1485 | .bool, |
| 1486 | .atomic_ordering, | ||
| 1487 | .atomic_rmw_op, | ||
| 1488 | .calling_convention, | ||
| 1489 | .float_mode, | ||
| 1490 | .reduce_op, | ||
| 1491 | .call_options, | ||
| 1492 | .export_options, | ||
| 1493 | .extern_options, | ||
| 1274 | => return 1, | 1494 | => return 1, |
| 1275 | 1495 | ||
| 1276 | .array_u8 => self.castTag(.array_u8).?.data, | 1496 | .array_u8 => self.castTag(.array_u8).?.data, |
| 1277 | .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1, | 1497 | .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1, |
| 1278 | .array => { | 1498 | .array, .vector => { |
| 1279 | const payload = self.castTag(.array).?.data; | 1499 | const payload = self.cast(Payload.Array).?.data; |
| 1280 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | 1500 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); |
| 1281 | return payload.len * elem_size; | 1501 | return payload.len * elem_size; |
| 1282 | }, | 1502 | }, |
| ... | @@ -1293,7 +1513,11 @@ pub const Type = extern union { | ... | @@ -1293,7 +1513,11 @@ pub const Type = extern union { |
| 1293 | .i64, .u64 => return 8, | 1513 | .i64, .u64 => return 8, |
| 1294 | .u128, .i128 => return 16, | 1514 | .u128, .i128 => return 16, |
| 1295 | 1515 | ||
| 1296 | .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | 1516 | .isize, |
| 1517 | .usize, | ||
| 1518 | .@"anyframe", | ||
| 1519 | .anyframe_T, | ||
| 1520 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | ||
| 1297 | 1521 | ||
| 1298 | .const_slice, | 1522 | .const_slice, |
| 1299 | .mut_slice, | 1523 | .mut_slice, |
| ... | @@ -1322,6 +1546,10 @@ pub const Type = extern union { | ... | @@ -1322,6 +1546,10 @@ pub const Type = extern union { |
| 1322 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); | 1546 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); |
| 1323 | }, | 1547 | }, |
| 1324 | 1548 | ||
| 1549 | .manyptr_u8, | ||
| 1550 | .manyptr_const_u8, | ||
| 1551 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), | ||
| 1552 | |||
| 1325 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), | 1553 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| 1326 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), | 1554 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), |
| 1327 | .c_int => return @divExact(CType.int.sizeInBits(target), 8), | 1555 | .c_int => return @divExact(CType.int.sizeInBits(target), 8), |
| ... | @@ -1377,6 +1605,177 @@ pub const Type = extern union { | ... | @@ -1377,6 +1605,177 @@ pub const Type = extern union { |
| 1377 | }; | 1605 | }; |
| 1378 | } | 1606 | } |
| 1379 | 1607 | ||
| 1608 | /// Asserts the type has the bit size already resolved. | ||
| 1609 | pub fn bitSize(self: Type, target: Target) u64 { | ||
| 1610 | return switch (self.tag()) { | ||
| 1611 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | ||
| 1612 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | ||
| 1613 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | ||
| 1614 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer | ||
| 1615 | .function => unreachable, // represents machine code; not a pointer | ||
| 1616 | .c_void => unreachable, | ||
| 1617 | .void => unreachable, | ||
| 1618 | .type => unreachable, | ||
| 1619 | .comptime_int => unreachable, | ||
| 1620 | .comptime_float => unreachable, | ||
| 1621 | .noreturn => unreachable, | ||
| 1622 | .@"null" => unreachable, | ||
| 1623 | .@"undefined" => unreachable, | ||
| 1624 | .enum_literal => unreachable, | ||
| 1625 | .single_const_pointer_to_comptime_int => unreachable, | ||
| 1626 | .empty_struct => unreachable, | ||
| 1627 | .empty_struct_literal => unreachable, | ||
| 1628 | .inferred_alloc_const => unreachable, | ||
| 1629 | .inferred_alloc_mut => unreachable, | ||
| 1630 | .@"opaque" => unreachable, | ||
| 1631 | .var_args_param => unreachable, | ||
| 1632 | |||
| 1633 | .@"struct" => { | ||
| 1634 | @panic("TODO bitSize struct"); | ||
| 1635 | }, | ||
| 1636 | .enum_simple, .enum_full, .enum_nonexhaustive => { | ||
| 1637 | var buffer: Payload.Bits = undefined; | ||
| 1638 | const int_tag_ty = self.intTagType(&buffer); | ||
| 1639 | return int_tag_ty.bitSize(target); | ||
| 1640 | }, | ||
| 1641 | .@"union", .union_tagged => { | ||
| 1642 | @panic("TODO bitSize unions"); | ||
| 1643 | }, | ||
| 1644 | |||
| 1645 | .u8, .i8 => 8, | ||
| 1646 | |||
| 1647 | .bool => 1, | ||
| 1648 | |||
| 1649 | .vector => { | ||
| 1650 | const payload = self.castTag(.vector).?.data; | ||
| 1651 | const elem_bit_size = payload.elem_type.bitSize(target); | ||
| 1652 | return elem_bit_size * payload.len; | ||
| 1653 | }, | ||
| 1654 | .array_u8 => 8 * self.castTag(.array_u8).?.data, | ||
| 1655 | .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1), | ||
| 1656 | .array => { | ||
| 1657 | const payload = self.castTag(.array).?.data; | ||
| 1658 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | ||
| 1659 | if (elem_size == 0 or payload.len == 0) | ||
| 1660 | return 0; | ||
| 1661 | return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target); | ||
| 1662 | }, | ||
| 1663 | .array_sentinel => { | ||
| 1664 | const payload = self.castTag(.array_sentinel).?.data; | ||
| 1665 | const elem_size = std.math.max( | ||
| 1666 | payload.elem_type.abiAlignment(target), | ||
| 1667 | payload.elem_type.abiSize(target), | ||
| 1668 | ); | ||
| 1669 | return payload.len * 8 * elem_size + payload.elem_type.bitSize(target); | ||
| 1670 | }, | ||
| 1671 | .i16, .u16, .f16 => 16, | ||
| 1672 | .i32, .u32, .f32 => 32, | ||
| 1673 | .i64, .u64, .f64 => 64, | ||
| 1674 | .u128, .i128, .f128 => 128, | ||
| 1675 | |||
| 1676 | .isize, | ||
| 1677 | .usize, | ||
| 1678 | .@"anyframe", | ||
| 1679 | .anyframe_T, | ||
| 1680 | => target.cpu.arch.ptrBitWidth(), | ||
| 1681 | |||
| 1682 | .const_slice, | ||
| 1683 | .mut_slice, | ||
| 1684 | => { | ||
| 1685 | if (self.elemType().hasCodeGenBits()) { | ||
| 1686 | return target.cpu.arch.ptrBitWidth() * 2; | ||
| 1687 | } else { | ||
| 1688 | return target.cpu.arch.ptrBitWidth(); | ||
| 1689 | } | ||
| 1690 | }, | ||
| 1691 | .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2, | ||
| 1692 | |||
| 1693 | .optional_single_const_pointer, | ||
| 1694 | .optional_single_mut_pointer, | ||
| 1695 | => { | ||
| 1696 | if (self.elemType().hasCodeGenBits()) { | ||
| 1697 | return target.cpu.arch.ptrBitWidth(); | ||
| 1698 | } else { | ||
| 1699 | return 1; | ||
| 1700 | } | ||
| 1701 | }, | ||
| 1702 | |||
| 1703 | .single_const_pointer, | ||
| 1704 | .single_mut_pointer, | ||
| 1705 | .many_const_pointer, | ||
| 1706 | .many_mut_pointer, | ||
| 1707 | .c_const_pointer, | ||
| 1708 | .c_mut_pointer, | ||
| 1709 | .pointer, | ||
| 1710 | => { | ||
| 1711 | if (self.elemType().hasCodeGenBits()) { | ||
| 1712 | return target.cpu.arch.ptrBitWidth(); | ||
| 1713 | } else { | ||
| 1714 | return 0; | ||
| 1715 | } | ||
| 1716 | }, | ||
| 1717 | |||
| 1718 | .manyptr_u8, | ||
| 1719 | .manyptr_const_u8, | ||
| 1720 | => return target.cpu.arch.ptrBitWidth(), | ||
| 1721 | |||
| 1722 | .c_short => return CType.short.sizeInBits(target), | ||
| 1723 | .c_ushort => return CType.ushort.sizeInBits(target), | ||
| 1724 | .c_int => return CType.int.sizeInBits(target), | ||
| 1725 | .c_uint => return CType.uint.sizeInBits(target), | ||
| 1726 | .c_long => return CType.long.sizeInBits(target), | ||
| 1727 | .c_ulong => return CType.ulong.sizeInBits(target), | ||
| 1728 | .c_longlong => return CType.longlong.sizeInBits(target), | ||
| 1729 | .c_ulonglong => return CType.ulonglong.sizeInBits(target), | ||
| 1730 | .c_longdouble => 128, | ||
| 1731 | |||
| 1732 | .error_set, | ||
| 1733 | .error_set_single, | ||
| 1734 | .anyerror_void_error_union, | ||
| 1735 | .anyerror, | ||
| 1736 | => return 16, // TODO revisit this when we have the concept of the error tag type | ||
| 1737 | |||
| 1738 | .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data, | ||
| 1739 | |||
| 1740 | .optional => { | ||
| 1741 | var buf: Payload.ElemType = undefined; | ||
| 1742 | const child_type = self.optionalChild(&buf); | ||
| 1743 | if (!child_type.hasCodeGenBits()) return 8; | ||
| 1744 | |||
| 1745 | if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) | ||
| 1746 | return target.cpu.arch.ptrBitWidth(); | ||
| 1747 | |||
| 1748 | // Optional types are represented as a struct with the child type as the first | ||
| 1749 | // field and a boolean as the second. Since the child type's abi alignment is | ||
| 1750 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | ||
| 1751 | // to the child type's ABI alignment. | ||
| 1752 | return child_type.bitSize(target) + 1; | ||
| 1753 | }, | ||
| 1754 | |||
| 1755 | .error_union => { | ||
| 1756 | const payload = self.castTag(.error_union).?.data; | ||
| 1757 | if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) { | ||
| 1758 | return 0; | ||
| 1759 | } else if (!payload.error_set.hasCodeGenBits()) { | ||
| 1760 | return payload.payload.bitSize(target); | ||
| 1761 | } else if (!payload.payload.hasCodeGenBits()) { | ||
| 1762 | return payload.error_set.bitSize(target); | ||
| 1763 | } | ||
| 1764 | @panic("TODO bitSize error union"); | ||
| 1765 | }, | ||
| 1766 | |||
| 1767 | .atomic_ordering, | ||
| 1768 | .atomic_rmw_op, | ||
| 1769 | .calling_convention, | ||
| 1770 | .float_mode, | ||
| 1771 | .reduce_op, | ||
| 1772 | .call_options, | ||
| 1773 | .export_options, | ||
| 1774 | .extern_options, | ||
| 1775 | => @panic("TODO at some point we gotta resolve builtin types"), | ||
| 1776 | }; | ||
| 1777 | } | ||
| 1778 | |||
| 1380 | /// Asserts the type is an enum. | 1779 | /// Asserts the type is an enum. |
| 1381 | pub fn intTagType(self: Type, buffer: *Payload.Bits) Type { | 1780 | pub fn intTagType(self: Type, buffer: *Payload.Bits) Type { |
| 1382 | switch (self.tag()) { | 1781 | switch (self.tag()) { |
| ... | @@ -1419,6 +1818,8 @@ pub const Type = extern union { | ... | @@ -1419,6 +1818,8 @@ pub const Type = extern union { |
| 1419 | 1818 | ||
| 1420 | .many_const_pointer, | 1819 | .many_const_pointer, |
| 1421 | .many_mut_pointer, | 1820 | .many_mut_pointer, |
| 1821 | .manyptr_u8, | ||
| 1822 | .manyptr_const_u8, | ||
| 1422 | => .Many, | 1823 | => .Many, |
| 1423 | 1824 | ||
| 1424 | .c_const_pointer, | 1825 | .c_const_pointer, |
| ... | @@ -1459,6 +1860,7 @@ pub const Type = extern union { | ... | @@ -1459,6 +1860,7 @@ pub const Type = extern union { |
| 1459 | .single_const_pointer_to_comptime_int, | 1860 | .single_const_pointer_to_comptime_int, |
| 1460 | .const_slice_u8, | 1861 | .const_slice_u8, |
| 1461 | .const_slice, | 1862 | .const_slice, |
| 1863 | .manyptr_const_u8, | ||
| 1462 | => true, | 1864 | => true, |
| 1463 | 1865 | ||
| 1464 | .pointer => !self.castTag(.pointer).?.data.mutable, | 1866 | .pointer => !self.castTag(.pointer).?.data.mutable, |
| ... | @@ -1526,7 +1928,6 @@ pub const Type = extern union { | ... | @@ -1526,7 +1928,6 @@ pub const Type = extern union { |
| 1526 | .Enum, | 1928 | .Enum, |
| 1527 | .Frame, | 1929 | .Frame, |
| 1528 | .AnyFrame, | 1930 | .AnyFrame, |
| 1529 | .Vector, | ||
| 1530 | => return true, | 1931 | => return true, |
| 1531 | 1932 | ||
| 1532 | .Opaque => return is_extern, | 1933 | .Opaque => return is_extern, |
| ... | @@ -1545,7 +1946,7 @@ pub const Type = extern union { | ... | @@ -1545,7 +1946,7 @@ pub const Type = extern union { |
| 1545 | var buf: Payload.ElemType = undefined; | 1946 | var buf: Payload.ElemType = undefined; |
| 1546 | return ty.optionalChild(&buf).isValidVarType(is_extern); | 1947 | return ty.optionalChild(&buf).isValidVarType(is_extern); |
| 1547 | }, | 1948 | }, |
| 1548 | .Pointer, .Array => ty = ty.elemType(), | 1949 | .Pointer, .Array, .Vector => ty = ty.elemType(), |
| 1549 | .ErrorUnion => ty = ty.errorUnionChild(), | 1950 | .ErrorUnion => ty = ty.errorUnionChild(), |
| 1550 | 1951 | ||
| 1551 | .Fn => @panic("TODO fn isValidVarType"), | 1952 | .Fn => @panic("TODO fn isValidVarType"), |
| ... | @@ -1561,6 +1962,7 @@ pub const Type = extern union { | ... | @@ -1561,6 +1962,7 @@ pub const Type = extern union { |
| 1561 | /// Asserts the type is a pointer or array type. | 1962 | /// Asserts the type is a pointer or array type. |
| 1562 | pub fn elemType(self: Type) Type { | 1963 | pub fn elemType(self: Type) Type { |
| 1563 | return switch (self.tag()) { | 1964 | return switch (self.tag()) { |
| 1965 | .vector => self.castTag(.vector).?.data.elem_type, | ||
| 1564 | .array => self.castTag(.array).?.data.elem_type, | 1966 | .array => self.castTag(.array).?.data.elem_type, |
| 1565 | .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, | 1967 | .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, |
| 1566 | .single_const_pointer, | 1968 | .single_const_pointer, |
| ... | @@ -1573,7 +1975,13 @@ pub const Type = extern union { | ... | @@ -1573,7 +1975,13 @@ pub const Type = extern union { |
| 1573 | .mut_slice, | 1975 | .mut_slice, |
| 1574 | => self.castPointer().?.data, | 1976 | => self.castPointer().?.data, |
| 1575 | 1977 | ||
| 1576 | .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), | 1978 | .array_u8, |
| 1979 | .array_u8_sentinel_0, | ||
| 1980 | .const_slice_u8, | ||
| 1981 | .manyptr_u8, | ||
| 1982 | .manyptr_const_u8, | ||
| 1983 | => Type.initTag(.u8), | ||
| 1984 | |||
| 1577 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), | 1985 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 1578 | .pointer => self.castTag(.pointer).?.data.pointee_type, | 1986 | .pointer => self.castTag(.pointer).?.data.pointee_type, |
| 1579 | 1987 | ||
| ... | @@ -1645,6 +2053,7 @@ pub const Type = extern union { | ... | @@ -1645,6 +2053,7 @@ pub const Type = extern union { |
| 1645 | /// Asserts the type is an array or vector. | 2053 | /// Asserts the type is an array or vector. |
| 1646 | pub fn arrayLen(self: Type) u64 { | 2054 | pub fn arrayLen(self: Type) u64 { |
| 1647 | return switch (self.tag()) { | 2055 | return switch (self.tag()) { |
| 2056 | .vector => self.castTag(.vector).?.data.len, | ||
| 1648 | .array => self.castTag(.array).?.data.len, | 2057 | .array => self.castTag(.array).?.data.len, |
| 1649 | .array_sentinel => self.castTag(.array_sentinel).?.data.len, | 2058 | .array_sentinel => self.castTag(.array_sentinel).?.data.len, |
| 1650 | .array_u8 => self.castTag(.array_u8).?.data, | 2059 | .array_u8 => self.castTag(.array_u8).?.data, |
| ... | @@ -1664,8 +2073,11 @@ pub const Type = extern union { | ... | @@ -1664,8 +2073,11 @@ pub const Type = extern union { |
| 1664 | .c_const_pointer, | 2073 | .c_const_pointer, |
| 1665 | .c_mut_pointer, | 2074 | .c_mut_pointer, |
| 1666 | .single_const_pointer_to_comptime_int, | 2075 | .single_const_pointer_to_comptime_int, |
| 2076 | .vector, | ||
| 1667 | .array, | 2077 | .array, |
| 1668 | .array_u8, | 2078 | .array_u8, |
| 2079 | .manyptr_u8, | ||
| 2080 | .manyptr_const_u8, | ||
| 1669 | => return null, | 2081 | => return null, |
| 1670 | 2082 | ||
| 1671 | .pointer => return self.castTag(.pointer).?.data.sentinel, | 2083 | .pointer => return self.castTag(.pointer).?.data.sentinel, |
| ... | @@ -1922,6 +2334,8 @@ pub const Type = extern union { | ... | @@ -1922,6 +2334,8 @@ pub const Type = extern union { |
| 1922 | }; | 2334 | }; |
| 1923 | } | 2335 | } |
| 1924 | 2336 | ||
| 2337 | /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which | ||
| 2338 | /// resolves field types rather than asserting they are already resolved. | ||
| 1925 | pub fn onePossibleValue(starting_type: Type) ?Value { | 2339 | pub fn onePossibleValue(starting_type: Type) ?Value { |
| 1926 | var ty = starting_type; | 2340 | var ty = starting_type; |
| 1927 | while (true) switch (ty.tag()) { | 2341 | while (true) switch (ty.tag()) { |
| ... | @@ -1977,10 +2391,30 @@ pub const Type = extern union { | ... | @@ -1977,10 +2391,30 @@ pub const Type = extern union { |
| 1977 | .error_set_single, | 2391 | .error_set_single, |
| 1978 | .@"opaque", | 2392 | .@"opaque", |
| 1979 | .var_args_param, | 2393 | .var_args_param, |
| 2394 | .manyptr_u8, | ||
| 2395 | .manyptr_const_u8, | ||
| 2396 | .atomic_ordering, | ||
| 2397 | .atomic_rmw_op, | ||
| 2398 | .calling_convention, | ||
| 2399 | .float_mode, | ||
| 2400 | .reduce_op, | ||
| 2401 | .call_options, | ||
| 2402 | .export_options, | ||
| 2403 | .extern_options, | ||
| 2404 | .@"anyframe", | ||
| 2405 | .anyframe_T, | ||
| 2406 | .many_const_pointer, | ||
| 2407 | .many_mut_pointer, | ||
| 2408 | .c_const_pointer, | ||
| 2409 | .c_mut_pointer, | ||
| 2410 | .single_const_pointer, | ||
| 2411 | .single_mut_pointer, | ||
| 2412 | .pointer, | ||
| 1980 | => return null, | 2413 | => return null, |
| 1981 | 2414 | ||
| 1982 | .@"struct" => { | 2415 | .@"struct" => { |
| 1983 | const s = ty.castTag(.@"struct").?.data; | 2416 | const s = ty.castTag(.@"struct").?.data; |
| 2417 | assert(s.haveFieldTypes()); | ||
| 1984 | for (s.fields.entries.items) |entry| { | 2418 | for (s.fields.entries.items) |entry| { |
| 1985 | const field_ty = entry.value.ty; | 2419 | const field_ty = entry.value.ty; |
| 1986 | if (field_ty.onePossibleValue() == null) { | 2420 | if (field_ty.onePossibleValue() == null) { |
| ... | @@ -2006,6 +2440,12 @@ pub const Type = extern union { | ... | @@ -2006,6 +2440,12 @@ pub const Type = extern union { |
| 2006 | } | 2440 | } |
| 2007 | }, | 2441 | }, |
| 2008 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, | 2442 | .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, |
| 2443 | .@"union" => { | ||
| 2444 | return null; // TODO | ||
| 2445 | }, | ||
| 2446 | .union_tagged => { | ||
| 2447 | return null; // TODO | ||
| 2448 | }, | ||
| 2009 | 2449 | ||
| 2010 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | 2450 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), |
| 2011 | .void => return Value.initTag(.void_value), | 2451 | .void => return Value.initTag(.void_value), |
| ... | @@ -2020,26 +2460,13 @@ pub const Type = extern union { | ... | @@ -2020,26 +2460,13 @@ pub const Type = extern union { |
| 2020 | return null; | 2460 | return null; |
| 2021 | } | 2461 | } |
| 2022 | }, | 2462 | }, |
| 2023 | .array, .array_u8 => { | 2463 | .vector, .array, .array_u8 => { |
| 2024 | if (ty.arrayLen() == 0) | 2464 | if (ty.arrayLen() == 0) |
| 2025 | return Value.initTag(.empty_array); | 2465 | return Value.initTag(.empty_array); |
| 2026 | ty = ty.elemType(); | 2466 | ty = ty.elemType(); |
| 2027 | continue; | 2467 | continue; |
| 2028 | }, | 2468 | }, |
| 2029 | .many_const_pointer, | 2469 | |
| 2030 | .many_mut_pointer, | ||
| 2031 | .c_const_pointer, | ||
| 2032 | .c_mut_pointer, | ||
| 2033 | .single_const_pointer, | ||
| 2034 | .single_mut_pointer, | ||
| 2035 | => { | ||
| 2036 | ty = ty.castPointer().?.data; | ||
| 2037 | continue; | ||
| 2038 | }, | ||
| 2039 | .pointer => { | ||
| 2040 | ty = ty.castTag(.pointer).?.data.pointee_type; | ||
| 2041 | continue; | ||
| 2042 | }, | ||
| 2043 | .inferred_alloc_const => unreachable, | 2470 | .inferred_alloc_const => unreachable, |
| 2044 | .inferred_alloc_mut => unreachable, | 2471 | .inferred_alloc_mut => unreachable, |
| 2045 | }; | 2472 | }; |
| ... | @@ -2052,13 +2479,15 @@ pub const Type = extern union { | ... | @@ -2052,13 +2479,15 @@ pub const Type = extern union { |
| 2052 | (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array); | 2479 | (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array); |
| 2053 | } | 2480 | } |
| 2054 | 2481 | ||
| 2055 | /// Returns null if the type has no container. | 2482 | /// Returns null if the type has no namespace. |
| 2056 | pub fn getContainerScope(self: Type) ?*Module.Scope.Container { | 2483 | pub fn getNamespace(self: Type) ?*Module.Scope.Namespace { |
| 2057 | return switch (self.tag()) { | 2484 | return switch (self.tag()) { |
| 2058 | .@"struct" => &self.castTag(.@"struct").?.data.container, | 2485 | .@"struct" => &self.castTag(.@"struct").?.data.namespace, |
| 2059 | .enum_full => &self.castTag(.enum_full).?.data.container, | 2486 | .enum_full => &self.castTag(.enum_full).?.data.namespace, |
| 2060 | .empty_struct => self.castTag(.empty_struct).?.data, | 2487 | .empty_struct => self.castTag(.empty_struct).?.data, |
| 2061 | .@"opaque" => &self.castTag(.@"opaque").?.data, | 2488 | .@"opaque" => &self.castTag(.@"opaque").?.data, |
| 2489 | .@"union" => &self.castTag(.@"union").?.data.namespace, | ||
| 2490 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, | ||
| 2062 | 2491 | ||
| 2063 | else => null, | 2492 | else => null, |
| 2064 | }; | 2493 | }; |
| ... | @@ -2136,6 +2565,16 @@ pub const Type = extern union { | ... | @@ -2136,6 +2565,16 @@ pub const Type = extern union { |
| 2136 | const enum_simple = ty.castTag(.enum_simple).?.data; | 2565 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 2137 | return enum_simple.fields.count(); | 2566 | return enum_simple.fields.count(); |
| 2138 | }, | 2567 | }, |
| 2568 | .atomic_ordering, | ||
| 2569 | .atomic_rmw_op, | ||
| 2570 | .calling_convention, | ||
| 2571 | .float_mode, | ||
| 2572 | .reduce_op, | ||
| 2573 | .call_options, | ||
| 2574 | .export_options, | ||
| 2575 | .extern_options, | ||
| 2576 | => @panic("TODO resolve std.builtin types"), | ||
| 2577 | |||
| 2139 | else => unreachable, | 2578 | else => unreachable, |
| 2140 | } | 2579 | } |
| 2141 | } | 2580 | } |
| ... | @@ -2150,6 +2589,15 @@ pub const Type = extern union { | ... | @@ -2150,6 +2589,15 @@ pub const Type = extern union { |
| 2150 | const enum_simple = ty.castTag(.enum_simple).?.data; | 2589 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 2151 | return enum_simple.fields.entries.items[field_index].key; | 2590 | return enum_simple.fields.entries.items[field_index].key; |
| 2152 | }, | 2591 | }, |
| 2592 | .atomic_ordering, | ||
| 2593 | .atomic_rmw_op, | ||
| 2594 | .calling_convention, | ||
| 2595 | .float_mode, | ||
| 2596 | .reduce_op, | ||
| 2597 | .call_options, | ||
| 2598 | .export_options, | ||
| 2599 | .extern_options, | ||
| 2600 | => @panic("TODO resolve std.builtin types"), | ||
| 2153 | else => unreachable, | 2601 | else => unreachable, |
| 2154 | } | 2602 | } |
| 2155 | } | 2603 | } |
| ... | @@ -2164,6 +2612,15 @@ pub const Type = extern union { | ... | @@ -2164,6 +2612,15 @@ pub const Type = extern union { |
| 2164 | const enum_simple = ty.castTag(.enum_simple).?.data; | 2612 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 2165 | return enum_simple.fields.getIndex(field_name); | 2613 | return enum_simple.fields.getIndex(field_name); |
| 2166 | }, | 2614 | }, |
| 2615 | .atomic_ordering, | ||
| 2616 | .atomic_rmw_op, | ||
| 2617 | .calling_convention, | ||
| 2618 | .float_mode, | ||
| 2619 | .reduce_op, | ||
| 2620 | .call_options, | ||
| 2621 | .export_options, | ||
| 2622 | .extern_options, | ||
| 2623 | => @panic("TODO resolve std.builtin types"), | ||
| 2167 | else => unreachable, | 2624 | else => unreachable, |
| 2168 | } | 2625 | } |
| 2169 | } | 2626 | } |
| ... | @@ -2200,6 +2657,15 @@ pub const Type = extern union { | ... | @@ -2200,6 +2657,15 @@ pub const Type = extern union { |
| 2200 | const enum_simple = ty.castTag(.enum_simple).?.data; | 2657 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 2201 | return S.fieldWithRange(enum_tag, enum_simple.fields.count()); | 2658 | return S.fieldWithRange(enum_tag, enum_simple.fields.count()); |
| 2202 | }, | 2659 | }, |
| 2660 | .atomic_ordering, | ||
| 2661 | .atomic_rmw_op, | ||
| 2662 | .calling_convention, | ||
| 2663 | .float_mode, | ||
| 2664 | .reduce_op, | ||
| 2665 | .call_options, | ||
| 2666 | .export_options, | ||
| 2667 | .extern_options, | ||
| 2668 | => @panic("TODO resolve std.builtin types"), | ||
| 2203 | else => unreachable, | 2669 | else => unreachable, |
| 2204 | } | 2670 | } |
| 2205 | } | 2671 | } |
| ... | @@ -2222,6 +2688,55 @@ pub const Type = extern union { | ... | @@ -2222,6 +2688,55 @@ pub const Type = extern union { |
| 2222 | const error_set = ty.castTag(.error_set).?.data; | 2688 | const error_set = ty.castTag(.error_set).?.data; |
| 2223 | return error_set.srcLoc(); | 2689 | return error_set.srcLoc(); |
| 2224 | }, | 2690 | }, |
| 2691 | .@"union", .union_tagged => { | ||
| 2692 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 2693 | return union_obj.srcLoc(); | ||
| 2694 | }, | ||
| 2695 | .atomic_ordering, | ||
| 2696 | .atomic_rmw_op, | ||
| 2697 | .calling_convention, | ||
| 2698 | .float_mode, | ||
| 2699 | .reduce_op, | ||
| 2700 | .call_options, | ||
| 2701 | .export_options, | ||
| 2702 | .extern_options, | ||
| 2703 | => @panic("TODO resolve std.builtin types"), | ||
| 2704 | else => unreachable, | ||
| 2705 | } | ||
| 2706 | } | ||
| 2707 | |||
| 2708 | pub fn getOwnerDecl(ty: Type) *Module.Decl { | ||
| 2709 | switch (ty.tag()) { | ||
| 2710 | .enum_full, .enum_nonexhaustive => { | ||
| 2711 | const enum_full = ty.cast(Payload.EnumFull).?.data; | ||
| 2712 | return enum_full.owner_decl; | ||
| 2713 | }, | ||
| 2714 | .enum_simple => { | ||
| 2715 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 2716 | return enum_simple.owner_decl; | ||
| 2717 | }, | ||
| 2718 | .@"struct" => { | ||
| 2719 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 2720 | return struct_obj.owner_decl; | ||
| 2721 | }, | ||
| 2722 | .error_set => { | ||
| 2723 | const error_set = ty.castTag(.error_set).?.data; | ||
| 2724 | return error_set.owner_decl; | ||
| 2725 | }, | ||
| 2726 | .@"union", .union_tagged => { | ||
| 2727 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 2728 | return union_obj.owner_decl; | ||
| 2729 | }, | ||
| 2730 | .@"opaque" => @panic("TODO"), | ||
| 2731 | .atomic_ordering, | ||
| 2732 | .atomic_rmw_op, | ||
| 2733 | .calling_convention, | ||
| 2734 | .float_mode, | ||
| 2735 | .reduce_op, | ||
| 2736 | .call_options, | ||
| 2737 | .export_options, | ||
| 2738 | .extern_options, | ||
| 2739 | => @panic("TODO resolve std.builtin types"), | ||
| 2225 | else => unreachable, | 2740 | else => unreachable, |
| 2226 | } | 2741 | } |
| 2227 | } | 2742 | } |
| ... | @@ -2254,6 +2769,15 @@ pub const Type = extern union { | ... | @@ -2254,6 +2769,15 @@ pub const Type = extern union { |
| 2254 | const enum_simple = ty.castTag(.enum_simple).?.data; | 2769 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 2255 | return S.intInRange(int, enum_simple.fields.count()); | 2770 | return S.intInRange(int, enum_simple.fields.count()); |
| 2256 | }, | 2771 | }, |
| 2772 | .atomic_ordering, | ||
| 2773 | .atomic_rmw_op, | ||
| 2774 | .calling_convention, | ||
| 2775 | .float_mode, | ||
| 2776 | .reduce_op, | ||
| 2777 | .call_options, | ||
| 2778 | .export_options, | ||
| 2779 | .extern_options, | ||
| 2780 | => @panic("TODO resolve std.builtin types"), | ||
| 2257 | 2781 | ||
| 2258 | else => unreachable, | 2782 | else => unreachable, |
| 2259 | } | 2783 | } |
| ... | @@ -2300,16 +2824,27 @@ pub const Type = extern union { | ... | @@ -2300,16 +2824,27 @@ pub const Type = extern union { |
| 2300 | comptime_int, | 2824 | comptime_int, |
| 2301 | comptime_float, | 2825 | comptime_float, |
| 2302 | noreturn, | 2826 | noreturn, |
| 2303 | enum_literal, | 2827 | @"anyframe", |
| 2304 | @"null", | 2828 | @"null", |
| 2305 | @"undefined", | 2829 | @"undefined", |
| 2830 | enum_literal, | ||
| 2831 | atomic_ordering, | ||
| 2832 | atomic_rmw_op, | ||
| 2833 | calling_convention, | ||
| 2834 | float_mode, | ||
| 2835 | reduce_op, | ||
| 2836 | call_options, | ||
| 2837 | export_options, | ||
| 2838 | extern_options, | ||
| 2839 | manyptr_u8, | ||
| 2840 | manyptr_const_u8, | ||
| 2306 | fn_noreturn_no_args, | 2841 | fn_noreturn_no_args, |
| 2307 | fn_void_no_args, | 2842 | fn_void_no_args, |
| 2308 | fn_naked_noreturn_no_args, | 2843 | fn_naked_noreturn_no_args, |
| 2309 | fn_ccc_void_no_args, | 2844 | fn_ccc_void_no_args, |
| 2310 | single_const_pointer_to_comptime_int, | 2845 | single_const_pointer_to_comptime_int, |
| 2311 | anyerror_void_error_union, | ||
| 2312 | const_slice_u8, | 2846 | const_slice_u8, |
| 2847 | anyerror_void_error_union, | ||
| 2313 | /// This is a special type for variadic parameters of a function call. | 2848 | /// This is a special type for variadic parameters of a function call. |
| 2314 | /// Casts to it will validate that the type can be passed to a c calling convetion function. | 2849 | /// Casts to it will validate that the type can be passed to a c calling convetion function. |
| 2315 | var_args_param, | 2850 | var_args_param, |
| ... | @@ -2327,6 +2862,7 @@ pub const Type = extern union { | ... | @@ -2327,6 +2862,7 @@ pub const Type = extern union { |
| 2327 | array_u8_sentinel_0, | 2862 | array_u8_sentinel_0, |
| 2328 | array, | 2863 | array, |
| 2329 | array_sentinel, | 2864 | array_sentinel, |
| 2865 | vector, | ||
| 2330 | pointer, | 2866 | pointer, |
| 2331 | single_const_pointer, | 2867 | single_const_pointer, |
| 2332 | single_mut_pointer, | 2868 | single_mut_pointer, |
| ... | @@ -2343,11 +2879,14 @@ pub const Type = extern union { | ... | @@ -2343,11 +2879,14 @@ pub const Type = extern union { |
| 2343 | optional_single_mut_pointer, | 2879 | optional_single_mut_pointer, |
| 2344 | optional_single_const_pointer, | 2880 | optional_single_const_pointer, |
| 2345 | error_union, | 2881 | error_union, |
| 2882 | anyframe_T, | ||
| 2346 | error_set, | 2883 | error_set, |
| 2347 | error_set_single, | 2884 | error_set_single, |
| 2348 | empty_struct, | 2885 | empty_struct, |
| 2349 | @"opaque", | 2886 | @"opaque", |
| 2350 | @"struct", | 2887 | @"struct", |
| 2888 | @"union", | ||
| 2889 | union_tagged, | ||
| 2351 | enum_simple, | 2890 | enum_simple, |
| 2352 | enum_full, | 2891 | enum_full, |
| 2353 | enum_nonexhaustive, | 2892 | enum_nonexhaustive, |
| ... | @@ -2404,6 +2943,17 @@ pub const Type = extern union { | ... | @@ -2404,6 +2943,17 @@ pub const Type = extern union { |
| 2404 | .inferred_alloc_mut, | 2943 | .inferred_alloc_mut, |
| 2405 | .var_args_param, | 2944 | .var_args_param, |
| 2406 | .empty_struct_literal, | 2945 | .empty_struct_literal, |
| 2946 | .manyptr_u8, | ||
| 2947 | .manyptr_const_u8, | ||
| 2948 | .atomic_ordering, | ||
| 2949 | .atomic_rmw_op, | ||
| 2950 | .calling_convention, | ||
| 2951 | .float_mode, | ||
| 2952 | .reduce_op, | ||
| 2953 | .call_options, | ||
| 2954 | .export_options, | ||
| 2955 | .extern_options, | ||
| 2956 | .@"anyframe", | ||
| 2407 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), | 2957 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), |
| 2408 | 2958 | ||
| 2409 | .array_u8, | 2959 | .array_u8, |
| ... | @@ -2421,6 +2971,7 @@ pub const Type = extern union { | ... | @@ -2421,6 +2971,7 @@ pub const Type = extern union { |
| 2421 | .optional, | 2971 | .optional, |
| 2422 | .optional_single_mut_pointer, | 2972 | .optional_single_mut_pointer, |
| 2423 | .optional_single_const_pointer, | 2973 | .optional_single_const_pointer, |
| 2974 | .anyframe_T, | ||
| 2424 | => Payload.ElemType, | 2975 | => Payload.ElemType, |
| 2425 | 2976 | ||
| 2426 | .int_signed, | 2977 | .int_signed, |
| ... | @@ -2429,7 +2980,7 @@ pub const Type = extern union { | ... | @@ -2429,7 +2980,7 @@ pub const Type = extern union { |
| 2429 | 2980 | ||
| 2430 | .error_set => Payload.ErrorSet, | 2981 | .error_set => Payload.ErrorSet, |
| 2431 | 2982 | ||
| 2432 | .array => Payload.Array, | 2983 | .array, .vector => Payload.Array, |
| 2433 | .array_sentinel => Payload.ArraySentinel, | 2984 | .array_sentinel => Payload.ArraySentinel, |
| 2434 | .pointer => Payload.Pointer, | 2985 | .pointer => Payload.Pointer, |
| 2435 | .function => Payload.Function, | 2986 | .function => Payload.Function, |
| ... | @@ -2437,6 +2988,7 @@ pub const Type = extern union { | ... | @@ -2437,6 +2988,7 @@ pub const Type = extern union { |
| 2437 | .error_set_single => Payload.Name, | 2988 | .error_set_single => Payload.Name, |
| 2438 | .@"opaque" => Payload.Opaque, | 2989 | .@"opaque" => Payload.Opaque, |
| 2439 | .@"struct" => Payload.Struct, | 2990 | .@"struct" => Payload.Struct, |
| 2991 | .@"union", .union_tagged => Payload.Union, | ||
| 2440 | .enum_full, .enum_nonexhaustive => Payload.EnumFull, | 2992 | .enum_full, .enum_nonexhaustive => Payload.EnumFull, |
| 2441 | .enum_simple => Payload.EnumSimple, | 2993 | .enum_simple => Payload.EnumSimple, |
| 2442 | .empty_struct => Payload.ContainerScope, | 2994 | .empty_struct => Payload.ContainerScope, |
| ... | @@ -2472,9 +3024,7 @@ pub const Type = extern union { | ... | @@ -2472,9 +3024,7 @@ pub const Type = extern union { |
| 2472 | }; | 3024 | }; |
| 2473 | 3025 | ||
| 2474 | pub const Array = struct { | 3026 | pub const Array = struct { |
| 2475 | pub const base_tag = Tag.array; | 3027 | base: Payload, |
| 2476 | |||
| 2477 | base: Payload = Payload{ .tag = base_tag }, | ||
| 2478 | data: struct { | 3028 | data: struct { |
| 2479 | len: u64, | 3029 | len: u64, |
| 2480 | elem_type: Type, | 3030 | elem_type: Type, |
| ... | @@ -2564,12 +3114,12 @@ pub const Type = extern union { | ... | @@ -2564,12 +3114,12 @@ pub const Type = extern union { |
| 2564 | /// Most commonly used for files. | 3114 | /// Most commonly used for files. |
| 2565 | pub const ContainerScope = struct { | 3115 | pub const ContainerScope = struct { |
| 2566 | base: Payload, | 3116 | base: Payload, |
| 2567 | data: *Module.Scope.Container, | 3117 | data: *Module.Scope.Namespace, |
| 2568 | }; | 3118 | }; |
| 2569 | 3119 | ||
| 2570 | pub const Opaque = struct { | 3120 | pub const Opaque = struct { |
| 2571 | base: Payload = .{ .tag = .@"opaque" }, | 3121 | base: Payload = .{ .tag = .@"opaque" }, |
| 2572 | data: Module.Scope.Container, | 3122 | data: Module.Scope.Namespace, |
| 2573 | }; | 3123 | }; |
| 2574 | 3124 | ||
| 2575 | pub const Struct = struct { | 3125 | pub const Struct = struct { |
| ... | @@ -2577,6 +3127,11 @@ pub const Type = extern union { | ... | @@ -2577,6 +3127,11 @@ pub const Type = extern union { |
| 2577 | data: *Module.Struct, | 3127 | data: *Module.Struct, |
| 2578 | }; | 3128 | }; |
| 2579 | 3129 | ||
| 3130 | pub const Union = struct { | ||
| 3131 | base: Payload, | ||
| 3132 | data: *Module.Union, | ||
| 3133 | }; | ||
| 3134 | |||
| 2580 | pub const EnumFull = struct { | 3135 | pub const EnumFull = struct { |
| 2581 | base: Payload, | 3136 | base: Payload, |
| 2582 | data: *Module.EnumFull, | 3137 | data: *Module.EnumFull, |
src/value.zig+203-9| ... | @@ -55,15 +55,26 @@ pub const Value = extern union { | ... | @@ -55,15 +55,26 @@ pub const Value = extern union { |
| 55 | comptime_int_type, | 55 | comptime_int_type, |
| 56 | comptime_float_type, | 56 | comptime_float_type, |
| 57 | noreturn_type, | 57 | noreturn_type, |
| 58 | anyframe_type, | ||
| 58 | null_type, | 59 | null_type, |
| 59 | undefined_type, | 60 | undefined_type, |
| 61 | enum_literal_type, | ||
| 62 | atomic_ordering_type, | ||
| 63 | atomic_rmw_op_type, | ||
| 64 | calling_convention_type, | ||
| 65 | float_mode_type, | ||
| 66 | reduce_op_type, | ||
| 67 | call_options_type, | ||
| 68 | export_options_type, | ||
| 69 | extern_options_type, | ||
| 70 | manyptr_u8_type, | ||
| 71 | manyptr_const_u8_type, | ||
| 60 | fn_noreturn_no_args_type, | 72 | fn_noreturn_no_args_type, |
| 61 | fn_void_no_args_type, | 73 | fn_void_no_args_type, |
| 62 | fn_naked_noreturn_no_args_type, | 74 | fn_naked_noreturn_no_args_type, |
| 63 | fn_ccc_void_no_args_type, | 75 | fn_ccc_void_no_args_type, |
| 64 | single_const_pointer_to_comptime_int_type, | 76 | single_const_pointer_to_comptime_int_type, |
| 65 | const_slice_u8_type, | 77 | const_slice_u8_type, |
| 66 | enum_literal_type, | ||
| 67 | 78 | ||
| 68 | undef, | 79 | undef, |
| 69 | zero, | 80 | zero, |
| ... | @@ -93,6 +104,7 @@ pub const Value = extern union { | ... | @@ -93,6 +104,7 @@ pub const Value = extern union { |
| 93 | /// Represents a pointer to a decl, not the value of the decl. | 104 | /// Represents a pointer to a decl, not the value of the decl. |
| 94 | decl_ref, | 105 | decl_ref, |
| 95 | elem_ptr, | 106 | elem_ptr, |
| 107 | field_ptr, | ||
| 96 | /// A slice of u8 whose memory is managed externally. | 108 | /// A slice of u8 whose memory is managed externally. |
| 97 | bytes, | 109 | bytes, |
| 98 | /// This value is repeated some number of times. The amount of times to repeat | 110 | /// This value is repeated some number of times. The amount of times to repeat |
| ... | @@ -107,6 +119,10 @@ pub const Value = extern union { | ... | @@ -107,6 +119,10 @@ pub const Value = extern union { |
| 107 | enum_field_index, | 119 | enum_field_index, |
| 108 | @"error", | 120 | @"error", |
| 109 | error_union, | 121 | error_union, |
| 122 | /// An instance of a struct. | ||
| 123 | @"struct", | ||
| 124 | /// An instance of a union. | ||
| 125 | @"union", | ||
| 110 | /// This is a special value that tracks a set of types that have been stored | 126 | /// This is a special value that tracks a set of types that have been stored |
| 111 | /// to an inferred allocation. It does not support any of the normal value queries. | 127 | /// to an inferred allocation. It does not support any of the normal value queries. |
| 112 | inferred_alloc, | 128 | inferred_alloc, |
| ... | @@ -156,6 +172,7 @@ pub const Value = extern union { | ... | @@ -156,6 +172,7 @@ pub const Value = extern union { |
| 156 | .fn_naked_noreturn_no_args_type, | 172 | .fn_naked_noreturn_no_args_type, |
| 157 | .fn_ccc_void_no_args_type, | 173 | .fn_ccc_void_no_args_type, |
| 158 | .single_const_pointer_to_comptime_int_type, | 174 | .single_const_pointer_to_comptime_int_type, |
| 175 | .anyframe_type, | ||
| 159 | .const_slice_u8_type, | 176 | .const_slice_u8_type, |
| 160 | .enum_literal_type, | 177 | .enum_literal_type, |
| 161 | .undef, | 178 | .undef, |
| ... | @@ -169,6 +186,16 @@ pub const Value = extern union { | ... | @@ -169,6 +186,16 @@ pub const Value = extern union { |
| 169 | .bool_true, | 186 | .bool_true, |
| 170 | .bool_false, | 187 | .bool_false, |
| 171 | .abi_align_default, | 188 | .abi_align_default, |
| 189 | .manyptr_u8_type, | ||
| 190 | .manyptr_const_u8_type, | ||
| 191 | .atomic_ordering_type, | ||
| 192 | .atomic_rmw_op_type, | ||
| 193 | .calling_convention_type, | ||
| 194 | .float_mode_type, | ||
| 195 | .reduce_op_type, | ||
| 196 | .call_options_type, | ||
| 197 | .export_options_type, | ||
| 198 | .extern_options_type, | ||
| 172 | => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), | 199 | => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), |
| 173 | 200 | ||
| 174 | .int_big_positive, | 201 | .int_big_positive, |
| ... | @@ -197,12 +224,15 @@ pub const Value = extern union { | ... | @@ -197,12 +224,15 @@ pub const Value = extern union { |
| 197 | .function => Payload.Function, | 224 | .function => Payload.Function, |
| 198 | .variable => Payload.Variable, | 225 | .variable => Payload.Variable, |
| 199 | .elem_ptr => Payload.ElemPtr, | 226 | .elem_ptr => Payload.ElemPtr, |
| 227 | .field_ptr => Payload.FieldPtr, | ||
| 200 | .float_16 => Payload.Float_16, | 228 | .float_16 => Payload.Float_16, |
| 201 | .float_32 => Payload.Float_32, | 229 | .float_32 => Payload.Float_32, |
| 202 | .float_64 => Payload.Float_64, | 230 | .float_64 => Payload.Float_64, |
| 203 | .float_128 => Payload.Float_128, | 231 | .float_128 => Payload.Float_128, |
| 204 | .@"error" => Payload.Error, | 232 | .@"error" => Payload.Error, |
| 205 | .inferred_alloc => Payload.InferredAlloc, | 233 | .inferred_alloc => Payload.InferredAlloc, |
| 234 | .@"struct" => Payload.Struct, | ||
| 235 | .@"union" => Payload.Union, | ||
| 206 | }; | 236 | }; |
| 207 | } | 237 | } |
| 208 | 238 | ||
| ... | @@ -314,6 +344,7 @@ pub const Value = extern union { | ... | @@ -314,6 +344,7 @@ pub const Value = extern union { |
| 314 | .fn_naked_noreturn_no_args_type, | 344 | .fn_naked_noreturn_no_args_type, |
| 315 | .fn_ccc_void_no_args_type, | 345 | .fn_ccc_void_no_args_type, |
| 316 | .single_const_pointer_to_comptime_int_type, | 346 | .single_const_pointer_to_comptime_int_type, |
| 347 | .anyframe_type, | ||
| 317 | .const_slice_u8_type, | 348 | .const_slice_u8_type, |
| 318 | .enum_literal_type, | 349 | .enum_literal_type, |
| 319 | .undef, | 350 | .undef, |
| ... | @@ -327,6 +358,16 @@ pub const Value = extern union { | ... | @@ -327,6 +358,16 @@ pub const Value = extern union { |
| 327 | .bool_false, | 358 | .bool_false, |
| 328 | .empty_struct_value, | 359 | .empty_struct_value, |
| 329 | .abi_align_default, | 360 | .abi_align_default, |
| 361 | .manyptr_u8_type, | ||
| 362 | .manyptr_const_u8_type, | ||
| 363 | .atomic_ordering_type, | ||
| 364 | .atomic_rmw_op_type, | ||
| 365 | .calling_convention_type, | ||
| 366 | .float_mode_type, | ||
| 367 | .reduce_op_type, | ||
| 368 | .call_options_type, | ||
| 369 | .export_options_type, | ||
| 370 | .extern_options_type, | ||
| 330 | => unreachable, | 371 | => unreachable, |
| 331 | 372 | ||
| 332 | .ty => { | 373 | .ty => { |
| ... | @@ -375,6 +416,18 @@ pub const Value = extern union { | ... | @@ -375,6 +416,18 @@ pub const Value = extern union { |
| 375 | }; | 416 | }; |
| 376 | return Value{ .ptr_otherwise = &new_payload.base }; | 417 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 377 | }, | 418 | }, |
| 419 | .field_ptr => { | ||
| 420 | const payload = self.castTag(.field_ptr).?; | ||
| 421 | const new_payload = try allocator.create(Payload.FieldPtr); | ||
| 422 | new_payload.* = .{ | ||
| 423 | .base = payload.base, | ||
| 424 | .data = .{ | ||
| 425 | .container_ptr = try payload.data.container_ptr.copy(allocator), | ||
| 426 | .field_index = payload.data.field_index, | ||
| 427 | }, | ||
| 428 | }; | ||
| 429 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 430 | }, | ||
| 378 | .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), | 431 | .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), |
| 379 | .repeated => { | 432 | .repeated => { |
| 380 | const payload = self.castTag(.repeated).?; | 433 | const payload = self.castTag(.repeated).?; |
| ... | @@ -409,6 +462,8 @@ pub const Value = extern union { | ... | @@ -409,6 +462,8 @@ pub const Value = extern union { |
| 409 | }; | 462 | }; |
| 410 | return Value{ .ptr_otherwise = &new_payload.base }; | 463 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 411 | }, | 464 | }, |
| 465 | .@"struct" => @panic("TODO can't copy struct value without knowing the type"), | ||
| 466 | .@"union" => @panic("TODO can't copy union value without knowing the type"), | ||
| 412 | 467 | ||
| 413 | .inferred_alloc => unreachable, | 468 | .inferred_alloc => unreachable, |
| 414 | } | 469 | } |
| ... | @@ -472,11 +527,28 @@ pub const Value = extern union { | ... | @@ -472,11 +527,28 @@ pub const Value = extern union { |
| 472 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 527 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), |
| 473 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), | 528 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), |
| 474 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), | 529 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), |
| 530 | .anyframe_type => return out_stream.writeAll("anyframe"), | ||
| 475 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), | 531 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), |
| 476 | .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), | 532 | .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), |
| 533 | .manyptr_u8_type => return out_stream.writeAll("[*]u8"), | ||
| 534 | .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"), | ||
| 535 | .atomic_ordering_type => return out_stream.writeAll("std.builtin.AtomicOrdering"), | ||
| 536 | .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"), | ||
| 537 | .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"), | ||
| 538 | .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), | ||
| 539 | .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), | ||
| 540 | .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"), | ||
| 541 | .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"), | ||
| 542 | .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"), | ||
| 477 | .abi_align_default => return out_stream.writeAll("(default ABI alignment)"), | 543 | .abi_align_default => return out_stream.writeAll("(default ABI alignment)"), |
| 478 | 544 | ||
| 479 | .empty_struct_value => return out_stream.writeAll("struct {}{}"), | 545 | .empty_struct_value => return out_stream.writeAll("struct {}{}"), |
| 546 | .@"struct" => { | ||
| 547 | return out_stream.writeAll("(struct value)"); | ||
| 548 | }, | ||
| 549 | .@"union" => { | ||
| 550 | return out_stream.writeAll("(union value)"); | ||
| 551 | }, | ||
| 480 | .null_value => return out_stream.writeAll("null"), | 552 | .null_value => return out_stream.writeAll("null"), |
| 481 | .undef => return out_stream.writeAll("undefined"), | 553 | .undef => return out_stream.writeAll("undefined"), |
| 482 | .zero => return out_stream.writeAll("0"), | 554 | .zero => return out_stream.writeAll("0"), |
| ... | @@ -511,6 +583,11 @@ pub const Value = extern union { | ... | @@ -511,6 +583,11 @@ pub const Value = extern union { |
| 511 | try out_stream.print("&[{}] ", .{elem_ptr.index}); | 583 | try out_stream.print("&[{}] ", .{elem_ptr.index}); |
| 512 | val = elem_ptr.array_ptr; | 584 | val = elem_ptr.array_ptr; |
| 513 | }, | 585 | }, |
| 586 | .field_ptr => { | ||
| 587 | const field_ptr = val.castTag(.field_ptr).?.data; | ||
| 588 | try out_stream.print("fieldptr({d}) ", .{field_ptr.field_index}); | ||
| 589 | val = field_ptr.container_ptr; | ||
| 590 | }, | ||
| 514 | .empty_array => return out_stream.writeAll(".{}"), | 591 | .empty_array => return out_stream.writeAll(".{}"), |
| 515 | .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}), | 592 | .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}), |
| 516 | .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}), | 593 | .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}), |
| ... | @@ -593,8 +670,19 @@ pub const Value = extern union { | ... | @@ -593,8 +670,19 @@ pub const Value = extern union { |
| 593 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), | 670 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), |
| 594 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), | 671 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), |
| 595 | .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), | 672 | .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), |
| 673 | .anyframe_type => Type.initTag(.@"anyframe"), | ||
| 596 | .const_slice_u8_type => Type.initTag(.const_slice_u8), | 674 | .const_slice_u8_type => Type.initTag(.const_slice_u8), |
| 597 | .enum_literal_type => Type.initTag(.enum_literal), | 675 | .enum_literal_type => Type.initTag(.enum_literal), |
| 676 | .manyptr_u8_type => Type.initTag(.manyptr_u8), | ||
| 677 | .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8), | ||
| 678 | .atomic_ordering_type => Type.initTag(.atomic_ordering), | ||
| 679 | .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op), | ||
| 680 | .calling_convention_type => Type.initTag(.calling_convention), | ||
| 681 | .float_mode_type => Type.initTag(.float_mode), | ||
| 682 | .reduce_op_type => Type.initTag(.reduce_op), | ||
| 683 | .call_options_type => Type.initTag(.call_options), | ||
| 684 | .export_options_type => Type.initTag(.export_options), | ||
| 685 | .extern_options_type => Type.initTag(.extern_options), | ||
| 598 | 686 | ||
| 599 | .int_type => { | 687 | .int_type => { |
| 600 | const payload = self.castTag(.int_type).?.data; | 688 | const payload = self.castTag(.int_type).?.data; |
| ... | @@ -627,6 +715,7 @@ pub const Value = extern union { | ... | @@ -627,6 +715,7 @@ pub const Value = extern union { |
| 627 | .ref_val, | 715 | .ref_val, |
| 628 | .decl_ref, | 716 | .decl_ref, |
| 629 | .elem_ptr, | 717 | .elem_ptr, |
| 718 | .field_ptr, | ||
| 630 | .bytes, | 719 | .bytes, |
| 631 | .repeated, | 720 | .repeated, |
| 632 | .float_16, | 721 | .float_16, |
| ... | @@ -638,12 +727,23 @@ pub const Value = extern union { | ... | @@ -638,12 +727,23 @@ pub const Value = extern union { |
| 638 | .@"error", | 727 | .@"error", |
| 639 | .error_union, | 728 | .error_union, |
| 640 | .empty_struct_value, | 729 | .empty_struct_value, |
| 730 | .@"struct", | ||
| 731 | .@"union", | ||
| 641 | .inferred_alloc, | 732 | .inferred_alloc, |
| 642 | .abi_align_default, | 733 | .abi_align_default, |
| 643 | => unreachable, | 734 | => unreachable, |
| 644 | }; | 735 | }; |
| 645 | } | 736 | } |
| 646 | 737 | ||
| 738 | /// Asserts the type is an enum type. | ||
| 739 | pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E { | ||
| 740 | // TODO this needs to resolve other kinds of Value tags rather than | ||
| 741 | // assuming the tag will be .enum_field_index. | ||
| 742 | const field_index = val.castTag(.enum_field_index).?.data; | ||
| 743 | // TODO should `@intToEnum` do this `@intCast` for you? | ||
| 744 | return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); | ||
| 745 | } | ||
| 746 | |||
| 647 | /// Asserts the value is an integer. | 747 | /// Asserts the value is an integer. |
| 648 | pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst { | 748 | pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst { |
| 649 | switch (self.tag()) { | 749 | switch (self.tag()) { |
| ... | @@ -930,7 +1030,11 @@ pub const Value = extern union { | ... | @@ -930,7 +1030,11 @@ pub const Value = extern union { |
| 930 | 1030 | ||
| 931 | /// Asserts the value is comparable. | 1031 | /// Asserts the value is comparable. |
| 932 | pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool { | 1032 | pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool { |
| 933 | return order(lhs, rhs).compare(op); | 1033 | return switch (op) { |
| 1034 | .eq => lhs.eql(rhs), | ||
| 1035 | .neq => !lhs.eql(rhs), | ||
| 1036 | else => order(lhs, rhs).compare(op), | ||
| 1037 | }; | ||
| 934 | } | 1038 | } |
| 935 | 1039 | ||
| 936 | /// Asserts the value is comparable. | 1040 | /// Asserts the value is comparable. |
| ... | @@ -942,12 +1046,19 @@ pub const Value = extern union { | ... | @@ -942,12 +1046,19 @@ pub const Value = extern union { |
| 942 | const a_tag = a.tag(); | 1046 | const a_tag = a.tag(); |
| 943 | const b_tag = b.tag(); | 1047 | const b_tag = b.tag(); |
| 944 | if (a_tag == b_tag) { | 1048 | if (a_tag == b_tag) { |
| 945 | if (a_tag == .void_value or a_tag == .null_value) { | 1049 | switch (a_tag) { |
| 946 | return true; | 1050 | .void_value, .null_value => return true, |
| 947 | } else if (a_tag == .enum_literal) { | 1051 | .enum_literal => { |
| 948 | const a_name = a.castTag(.enum_literal).?.data; | 1052 | const a_name = a.castTag(.enum_literal).?.data; |
| 949 | const b_name = b.castTag(.enum_literal).?.data; | 1053 | const b_name = b.castTag(.enum_literal).?.data; |
| 950 | return std.mem.eql(u8, a_name, b_name); | 1054 | return std.mem.eql(u8, a_name, b_name); |
| 1055 | }, | ||
| 1056 | .enum_field_index => { | ||
| 1057 | const a_field_index = a.castTag(.enum_field_index).?.data; | ||
| 1058 | const b_field_index = b.castTag(.enum_field_index).?.data; | ||
| 1059 | return a_field_index == b_field_index; | ||
| 1060 | }, | ||
| 1061 | else => {}, | ||
| 951 | } | 1062 | } |
| 952 | } | 1063 | } |
| 953 | if (a.isType() and b.isType()) { | 1064 | if (a.isType() and b.isType()) { |
| ... | @@ -958,7 +1069,7 @@ pub const Value = extern union { | ... | @@ -958,7 +1069,7 @@ pub const Value = extern union { |
| 958 | const b_type = b.toType(&fib.allocator) catch unreachable; | 1069 | const b_type = b.toType(&fib.allocator) catch unreachable; |
| 959 | return a_type.eql(b_type); | 1070 | return a_type.eql(b_type); |
| 960 | } | 1071 | } |
| 961 | return compare(a, .eq, b); | 1072 | return order(a, b).compare(.eq); |
| 962 | } | 1073 | } |
| 963 | 1074 | ||
| 964 | pub fn hash_u32(self: Value) u32 { | 1075 | pub fn hash_u32(self: Value) u32 { |
| ... | @@ -1009,6 +1120,7 @@ pub const Value = extern union { | ... | @@ -1009,6 +1120,7 @@ pub const Value = extern union { |
| 1009 | .fn_naked_noreturn_no_args_type, | 1120 | .fn_naked_noreturn_no_args_type, |
| 1010 | .fn_ccc_void_no_args_type, | 1121 | .fn_ccc_void_no_args_type, |
| 1011 | .single_const_pointer_to_comptime_int_type, | 1122 | .single_const_pointer_to_comptime_int_type, |
| 1123 | .anyframe_type, | ||
| 1012 | .const_slice_u8_type, | 1124 | .const_slice_u8_type, |
| 1013 | .enum_literal_type, | 1125 | .enum_literal_type, |
| 1014 | .ty, | 1126 | .ty, |
| ... | @@ -1096,6 +1208,11 @@ pub const Value = extern union { | ... | @@ -1096,6 +1208,11 @@ pub const Value = extern union { |
| 1096 | std.hash.autoHash(&hasher, payload.array_ptr.hash()); | 1208 | std.hash.autoHash(&hasher, payload.array_ptr.hash()); |
| 1097 | std.hash.autoHash(&hasher, payload.index); | 1209 | std.hash.autoHash(&hasher, payload.index); |
| 1098 | }, | 1210 | }, |
| 1211 | .field_ptr => { | ||
| 1212 | const payload = self.castTag(.field_ptr).?.data; | ||
| 1213 | std.hash.autoHash(&hasher, payload.container_ptr.hash()); | ||
| 1214 | std.hash.autoHash(&hasher, payload.field_index); | ||
| 1215 | }, | ||
| 1099 | .decl_ref => { | 1216 | .decl_ref => { |
| 1100 | const decl = self.castTag(.decl_ref).?.data; | 1217 | const decl = self.castTag(.decl_ref).?.data; |
| 1101 | std.hash.autoHash(&hasher, decl); | 1218 | std.hash.autoHash(&hasher, decl); |
| ... | @@ -1121,6 +1238,20 @@ pub const Value = extern union { | ... | @@ -1121,6 +1238,20 @@ pub const Value = extern union { |
| 1121 | std.hash.autoHash(&hasher, payload.hash()); | 1238 | std.hash.autoHash(&hasher, payload.hash()); |
| 1122 | }, | 1239 | }, |
| 1123 | .inferred_alloc => unreachable, | 1240 | .inferred_alloc => unreachable, |
| 1241 | |||
| 1242 | .manyptr_u8_type, | ||
| 1243 | .manyptr_const_u8_type, | ||
| 1244 | .atomic_ordering_type, | ||
| 1245 | .atomic_rmw_op_type, | ||
| 1246 | .calling_convention_type, | ||
| 1247 | .float_mode_type, | ||
| 1248 | .reduce_op_type, | ||
| 1249 | .call_options_type, | ||
| 1250 | .export_options_type, | ||
| 1251 | .extern_options_type, | ||
| 1252 | .@"struct", | ||
| 1253 | .@"union", | ||
| 1254 | => @panic("TODO this hash function looks pretty broken. audit it"), | ||
| 1124 | } | 1255 | } |
| 1125 | return hasher.final(); | 1256 | return hasher.final(); |
| 1126 | } | 1257 | } |
| ... | @@ -1136,6 +1267,11 @@ pub const Value = extern union { | ... | @@ -1136,6 +1267,11 @@ pub const Value = extern union { |
| 1136 | const array_val = try elem_ptr.array_ptr.pointerDeref(allocator); | 1267 | const array_val = try elem_ptr.array_ptr.pointerDeref(allocator); |
| 1137 | return array_val.elemValue(allocator, elem_ptr.index); | 1268 | return array_val.elemValue(allocator, elem_ptr.index); |
| 1138 | }, | 1269 | }, |
| 1270 | .field_ptr => { | ||
| 1271 | const field_ptr = self.castTag(.field_ptr).?.data; | ||
| 1272 | const container_val = try field_ptr.container_ptr.pointerDeref(allocator); | ||
| 1273 | return container_val.fieldValue(allocator, field_ptr.field_index); | ||
| 1274 | }, | ||
| 1139 | 1275 | ||
| 1140 | else => unreachable, | 1276 | else => unreachable, |
| 1141 | }; | 1277 | }; |
| ... | @@ -1156,6 +1292,22 @@ pub const Value = extern union { | ... | @@ -1156,6 +1292,22 @@ pub const Value = extern union { |
| 1156 | } | 1292 | } |
| 1157 | } | 1293 | } |
| 1158 | 1294 | ||
| 1295 | pub fn fieldValue(val: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value { | ||
| 1296 | switch (val.tag()) { | ||
| 1297 | .@"struct" => { | ||
| 1298 | const field_values = val.castTag(.@"struct").?.data; | ||
| 1299 | return field_values[index]; | ||
| 1300 | }, | ||
| 1301 | .@"union" => { | ||
| 1302 | const payload = val.castTag(.@"union").?.data; | ||
| 1303 | // TODO assert the tag is correct | ||
| 1304 | return payload.val; | ||
| 1305 | }, | ||
| 1306 | |||
| 1307 | else => unreachable, | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | |||
| 1159 | /// Returns a pointer to the element value at the index. | 1311 | /// Returns a pointer to the element value at the index. |
| 1160 | pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value { | 1312 | pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value { |
| 1161 | if (self.castTag(.elem_ptr)) |elem_ptr| { | 1313 | if (self.castTag(.elem_ptr)) |elem_ptr| { |
| ... | @@ -1265,8 +1417,19 @@ pub const Value = extern union { | ... | @@ -1265,8 +1417,19 @@ pub const Value = extern union { |
| 1265 | .fn_naked_noreturn_no_args_type, | 1417 | .fn_naked_noreturn_no_args_type, |
| 1266 | .fn_ccc_void_no_args_type, | 1418 | .fn_ccc_void_no_args_type, |
| 1267 | .single_const_pointer_to_comptime_int_type, | 1419 | .single_const_pointer_to_comptime_int_type, |
| 1420 | .anyframe_type, | ||
| 1268 | .const_slice_u8_type, | 1421 | .const_slice_u8_type, |
| 1269 | .enum_literal_type, | 1422 | .enum_literal_type, |
| 1423 | .manyptr_u8_type, | ||
| 1424 | .manyptr_const_u8_type, | ||
| 1425 | .atomic_ordering_type, | ||
| 1426 | .atomic_rmw_op_type, | ||
| 1427 | .calling_convention_type, | ||
| 1428 | .float_mode_type, | ||
| 1429 | .reduce_op_type, | ||
| 1430 | .call_options_type, | ||
| 1431 | .export_options_type, | ||
| 1432 | .extern_options_type, | ||
| 1270 | => true, | 1433 | => true, |
| 1271 | 1434 | ||
| 1272 | .zero, | 1435 | .zero, |
| ... | @@ -1284,6 +1447,7 @@ pub const Value = extern union { | ... | @@ -1284,6 +1447,7 @@ pub const Value = extern union { |
| 1284 | .ref_val, | 1447 | .ref_val, |
| 1285 | .decl_ref, | 1448 | .decl_ref, |
| 1286 | .elem_ptr, | 1449 | .elem_ptr, |
| 1450 | .field_ptr, | ||
| 1287 | .bytes, | 1451 | .bytes, |
| 1288 | .repeated, | 1452 | .repeated, |
| 1289 | .float_16, | 1453 | .float_16, |
| ... | @@ -1296,6 +1460,8 @@ pub const Value = extern union { | ... | @@ -1296,6 +1460,8 @@ pub const Value = extern union { |
| 1296 | .@"error", | 1460 | .@"error", |
| 1297 | .error_union, | 1461 | .error_union, |
| 1298 | .empty_struct_value, | 1462 | .empty_struct_value, |
| 1463 | .@"struct", | ||
| 1464 | .@"union", | ||
| 1299 | .null_value, | 1465 | .null_value, |
| 1300 | .abi_align_default, | 1466 | .abi_align_default, |
| 1301 | => false, | 1467 | => false, |
| ... | @@ -1369,6 +1535,16 @@ pub const Value = extern union { | ... | @@ -1369,6 +1535,16 @@ pub const Value = extern union { |
| 1369 | }, | 1535 | }, |
| 1370 | }; | 1536 | }; |
| 1371 | 1537 | ||
| 1538 | pub const FieldPtr = struct { | ||
| 1539 | pub const base_tag = Tag.field_ptr; | ||
| 1540 | |||
| 1541 | base: Payload = Payload{ .tag = base_tag }, | ||
| 1542 | data: struct { | ||
| 1543 | container_ptr: Value, | ||
| 1544 | field_index: usize, | ||
| 1545 | }, | ||
| 1546 | }; | ||
| 1547 | |||
| 1372 | pub const Bytes = struct { | 1548 | pub const Bytes = struct { |
| 1373 | base: Payload, | 1549 | base: Payload, |
| 1374 | data: []const u8, | 1550 | data: []const u8, |
| ... | @@ -1439,6 +1615,24 @@ pub const Value = extern union { | ... | @@ -1439,6 +1615,24 @@ pub const Value = extern union { |
| 1439 | stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{}, | 1615 | stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{}, |
| 1440 | }, | 1616 | }, |
| 1441 | }; | 1617 | }; |
| 1618 | |||
| 1619 | pub const Struct = struct { | ||
| 1620 | pub const base_tag = Tag.@"struct"; | ||
| 1621 | |||
| 1622 | base: Payload = .{ .tag = base_tag }, | ||
| 1623 | /// Field values. The number and type are according to the struct type. | ||
| 1624 | data: [*]Value, | ||
| 1625 | }; | ||
| 1626 | |||
| 1627 | pub const Union = struct { | ||
| 1628 | pub const base_tag = Tag.@"union"; | ||
| 1629 | |||
| 1630 | base: Payload = .{ .tag = base_tag }, | ||
| 1631 | data: struct { | ||
| 1632 | tag: Value, | ||
| 1633 | val: Value, | ||
| 1634 | }, | ||
| 1635 | }; | ||
| 1442 | }; | 1636 | }; |
| 1443 | 1637 | ||
| 1444 | /// Big enough to fit any non-BigInt value | 1638 | /// Big enough to fit any non-BigInt value |
src/zir.zig deleted-2439| ... | @@ -1,2439 +0,0 @@ | ||
| 1 | //! Zig Intermediate Representation. Astgen.zig converts AST nodes to these | ||
| 2 | //! untyped IR instructions. Next, Sema.zig processes these into TZIR. | ||
| 3 | |||
| 4 | const std = @import("std"); | ||
| 5 | const mem = std.mem; | ||
| 6 | const Allocator = std.mem.Allocator; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const BigIntConst = std.math.big.int.Const; | ||
| 9 | const BigIntMutable = std.math.big.int.Mutable; | ||
| 10 | const ast = std.zig.ast; | ||
| 11 | |||
| 12 | const Type = @import("type.zig").Type; | ||
| 13 | const Value = @import("value.zig").Value; | ||
| 14 | const TypedValue = @import("TypedValue.zig"); | ||
| 15 | const ir = @import("ir.zig"); | ||
| 16 | const Module = @import("Module.zig"); | ||
| 17 | const LazySrcLoc = Module.LazySrcLoc; | ||
| 18 | |||
| 19 | /// The minimum amount of information needed to represent a list of ZIR instructions. | ||
| 20 | /// Once this structure is completed, it can be used to generate TZIR, followed by | ||
| 21 | /// machine code, without any memory access into the AST tree token list, node list, | ||
| 22 | /// or source bytes. Exceptions include: | ||
| 23 | /// * Compile errors, which may need to reach into these data structures to | ||
| 24 | /// create a useful report. | ||
| 25 | /// * In the future, possibly inline assembly, which needs to get parsed and | ||
| 26 | /// handled by the codegen backend, and errors reported there. However for now, | ||
| 27 | /// inline assembly is not an exception. | ||
| 28 | pub const Code = struct { | ||
| 29 | /// There is always implicitly a `block` instruction at index 0. | ||
| 30 | /// This is so that `break_inline` can break from the root block. | ||
| 31 | instructions: std.MultiArrayList(Inst).Slice, | ||
| 32 | /// In order to store references to strings in fewer bytes, we copy all | ||
| 33 | /// string bytes into here. String bytes can be null. It is up to whomever | ||
| 34 | /// is referencing the data here whether they want to store both index and length, | ||
| 35 | /// thus allowing null bytes, or store only index, and use null-termination. The | ||
| 36 | /// `string_bytes` array is agnostic to either usage. | ||
| 37 | string_bytes: []u8, | ||
| 38 | /// The meaning of this data is determined by `Inst.Tag` value. | ||
| 39 | extra: []u32, | ||
| 40 | |||
| 41 | /// Returns the requested data, as well as the new index which is at the start of the | ||
| 42 | /// trailers for the object. | ||
| 43 | pub fn extraData(code: Code, comptime T: type, index: usize) struct { data: T, end: usize } { | ||
| 44 | const fields = std.meta.fields(T); | ||
| 45 | var i: usize = index; | ||
| 46 | var result: T = undefined; | ||
| 47 | inline for (fields) |field| { | ||
| 48 | @field(result, field.name) = switch (field.field_type) { | ||
| 49 | u32 => code.extra[i], | ||
| 50 | Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]), | ||
| 51 | else => unreachable, | ||
| 52 | }; | ||
| 53 | i += 1; | ||
| 54 | } | ||
| 55 | return .{ | ||
| 56 | .data = result, | ||
| 57 | .end = i, | ||
| 58 | }; | ||
| 59 | } | ||
| 60 | |||
| 61 | /// Given an index into `string_bytes` returns the null-terminated string found there. | ||
| 62 | pub fn nullTerminatedString(code: Code, index: usize) [:0]const u8 { | ||
| 63 | var end: usize = index; | ||
| 64 | while (code.string_bytes[end] != 0) { | ||
| 65 | end += 1; | ||
| 66 | } | ||
| 67 | return code.string_bytes[index..end :0]; | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn refSlice(code: Code, start: usize, len: usize) []Inst.Ref { | ||
| 71 | const raw_slice = code.extra[start..][0..len]; | ||
| 72 | return @bitCast([]Inst.Ref, raw_slice); | ||
| 73 | } | ||
| 74 | |||
| 75 | pub fn deinit(code: *Code, gpa: *Allocator) void { | ||
| 76 | code.instructions.deinit(gpa); | ||
| 77 | gpa.free(code.string_bytes); | ||
| 78 | gpa.free(code.extra); | ||
| 79 | code.* = undefined; | ||
| 80 | } | ||
| 81 | |||
| 82 | /// For debugging purposes, like dumpFn but for unanalyzed zir blocks | ||
| 83 | pub fn dump( | ||
| 84 | code: Code, | ||
| 85 | gpa: *Allocator, | ||
| 86 | kind: []const u8, | ||
| 87 | scope: *Module.Scope, | ||
| 88 | param_count: usize, | ||
| 89 | ) !void { | ||
| 90 | var arena = std.heap.ArenaAllocator.init(gpa); | ||
| 91 | defer arena.deinit(); | ||
| 92 | |||
| 93 | var writer: Writer = .{ | ||
| 94 | .gpa = gpa, | ||
| 95 | .arena = &arena.allocator, | ||
| 96 | .scope = scope, | ||
| 97 | .code = code, | ||
| 98 | .indent = 0, | ||
| 99 | .param_count = param_count, | ||
| 100 | }; | ||
| 101 | |||
| 102 | const decl_name = scope.srcDecl().?.name; | ||
| 103 | const stderr = std.io.getStdErr().writer(); | ||
| 104 | try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name }); | ||
| 105 | try writer.writeInstToStream(stderr, 0); | ||
| 106 | try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name }); | ||
| 107 | } | ||
| 108 | }; | ||
| 109 | |||
| 110 | /// These are untyped instructions generated from an Abstract Syntax Tree. | ||
| 111 | /// The data here is immutable because it is possible to have multiple | ||
| 112 | /// analyses on the same ZIR happening at the same time. | ||
| 113 | pub const Inst = struct { | ||
| 114 | tag: Tag, | ||
| 115 | data: Data, | ||
| 116 | |||
| 117 | /// These names are used directly as the instruction names in the text format. | ||
| 118 | pub const Tag = enum(u8) { | ||
| 119 | /// Arithmetic addition, asserts no integer overflow. | ||
| 120 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 121 | add, | ||
| 122 | /// Twos complement wrapping integer addition. | ||
| 123 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 124 | addwrap, | ||
| 125 | /// Allocates stack local memory. | ||
| 126 | /// Uses the `un_node` union field. The operand is the type of the allocated object. | ||
| 127 | /// The node source location points to a var decl node. | ||
| 128 | /// Indicates the beginning of a new statement in debug info. | ||
| 129 | alloc, | ||
| 130 | /// Same as `alloc` except mutable. | ||
| 131 | alloc_mut, | ||
| 132 | /// Same as `alloc` except the type is inferred. | ||
| 133 | /// Uses the `node` union field. | ||
| 134 | alloc_inferred, | ||
| 135 | /// Same as `alloc_inferred` except mutable. | ||
| 136 | alloc_inferred_mut, | ||
| 137 | /// Array concatenation. `a ++ b` | ||
| 138 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 139 | array_cat, | ||
| 140 | /// Array multiplication `a ** b` | ||
| 141 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 142 | array_mul, | ||
| 143 | /// `[N]T` syntax. No source location provided. | ||
| 144 | /// Uses the `bin` union field. lhs is length, rhs is element type. | ||
| 145 | array_type, | ||
| 146 | /// `[N:S]T` syntax. No source location provided. | ||
| 147 | /// Uses the `array_type_sentinel` field. | ||
| 148 | array_type_sentinel, | ||
| 149 | /// Given a pointer to an indexable object, returns the len property. This is | ||
| 150 | /// used by for loops. This instruction also emits a for-loop specific compile | ||
| 151 | /// error if the indexable object is not indexable. | ||
| 152 | /// Uses the `un_node` field. The AST node is the for loop node. | ||
| 153 | indexable_ptr_len, | ||
| 154 | /// Type coercion. No source location attached. | ||
| 155 | /// Uses the `bin` field. | ||
| 156 | as, | ||
| 157 | /// Type coercion to the function's return type. | ||
| 158 | /// Uses the `pl_node` field. Payload is `As`. AST node could be many things. | ||
| 159 | as_node, | ||
| 160 | /// Inline assembly. Non-volatile. | ||
| 161 | /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node. | ||
| 162 | @"asm", | ||
| 163 | /// Inline assembly with the volatile attribute. | ||
| 164 | /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node. | ||
| 165 | asm_volatile, | ||
| 166 | /// Bitwise AND. `&` | ||
| 167 | bit_and, | ||
| 168 | /// Bitcast a value to a different type. | ||
| 169 | /// Uses the pl_node field with payload `Bin`. | ||
| 170 | bitcast, | ||
| 171 | /// A typed result location pointer is bitcasted to a new result location pointer. | ||
| 172 | /// The new result location pointer has an inferred type. | ||
| 173 | /// Uses the un_node field. | ||
| 174 | bitcast_result_ptr, | ||
| 175 | /// Bitwise NOT. `~` | ||
| 176 | /// Uses `un_node`. | ||
| 177 | bit_not, | ||
| 178 | /// Bitwise OR. `|` | ||
| 179 | bit_or, | ||
| 180 | /// A labeled block of code, which can return a value. | ||
| 181 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 182 | block, | ||
| 183 | /// A list of instructions which are analyzed in the parent context, without | ||
| 184 | /// generating a runtime block. Must terminate with an "inline" variant of | ||
| 185 | /// a noreturn instruction. | ||
| 186 | /// Uses the `pl_node` union field. Payload is `Block`. | ||
| 187 | block_inline, | ||
| 188 | /// Boolean AND. See also `bit_and`. | ||
| 189 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 190 | bool_and, | ||
| 191 | /// Boolean NOT. See also `bit_not`. | ||
| 192 | /// Uses the `un_node` field. | ||
| 193 | bool_not, | ||
| 194 | /// Boolean OR. See also `bit_or`. | ||
| 195 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 196 | bool_or, | ||
| 197 | /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand | ||
| 198 | /// is a block, which is evaluated if `lhs` is `true`. | ||
| 199 | /// Uses the `bool_br` union field. | ||
| 200 | bool_br_and, | ||
| 201 | /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand | ||
| 202 | /// is a block, which is evaluated if `lhs` is `false`. | ||
| 203 | /// Uses the `bool_br` union field. | ||
| 204 | bool_br_or, | ||
| 205 | /// Return a value from a block. | ||
| 206 | /// Uses the `break` union field. | ||
| 207 | /// Uses the source information from previous instruction. | ||
| 208 | @"break", | ||
| 209 | /// Return a value from a block. This instruction is used as the terminator | ||
| 210 | /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`. | ||
| 211 | /// This instruction may also be used when it is known that there is only one | ||
| 212 | /// break instruction in a block, and the target block is the parent. | ||
| 213 | /// Uses the `break` union field. | ||
| 214 | break_inline, | ||
| 215 | /// Uses the `node` union field. | ||
| 216 | breakpoint, | ||
| 217 | /// Function call with modifier `.auto`. | ||
| 218 | /// Uses `pl_node`. AST node is the function call. Payload is `Call`. | ||
| 219 | call, | ||
| 220 | /// Same as `call` but it also does `ensure_result_used` on the return value. | ||
| 221 | call_chkused, | ||
| 222 | /// Same as `call` but with modifier `.compile_time`. | ||
| 223 | call_compile_time, | ||
| 224 | /// Function call with modifier `.auto`, empty parameter list. | ||
| 225 | /// Uses the `un_node` field. Operand is callee. AST node is the function call. | ||
| 226 | call_none, | ||
| 227 | /// Same as `call_none` but it also does `ensure_result_used` on the return value. | ||
| 228 | call_none_chkused, | ||
| 229 | /// `<` | ||
| 230 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 231 | cmp_lt, | ||
| 232 | /// `<=` | ||
| 233 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 234 | cmp_lte, | ||
| 235 | /// `==` | ||
| 236 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 237 | cmp_eq, | ||
| 238 | /// `>=` | ||
| 239 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 240 | cmp_gte, | ||
| 241 | /// `>` | ||
| 242 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 243 | cmp_gt, | ||
| 244 | /// `!=` | ||
| 245 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 246 | cmp_neq, | ||
| 247 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- | ||
| 248 | /// as type coercion from the new element type to the old element type. | ||
| 249 | /// Uses the `bin` union field. | ||
| 250 | /// LHS is destination element type, RHS is result pointer. | ||
| 251 | coerce_result_ptr, | ||
| 252 | /// Emit an error message and fail compilation. | ||
| 253 | /// Uses the `un_node` field. | ||
| 254 | compile_error, | ||
| 255 | /// Log compile time variables and emit an error message. | ||
| 256 | /// Uses the `pl_node` union field. The AST node is the compile log builtin call. | ||
| 257 | /// The payload is `MultiOp`. | ||
| 258 | compile_log, | ||
| 259 | /// Conditional branch. Splits control flow based on a boolean condition value. | ||
| 260 | /// Uses the `pl_node` union field. AST node is an if, while, for, etc. | ||
| 261 | /// Payload is `CondBr`. | ||
| 262 | condbr, | ||
| 263 | /// Same as `condbr`, except the condition is coerced to a comptime value, and | ||
| 264 | /// only the taken branch is analyzed. The then block and else block must | ||
| 265 | /// terminate with an "inline" variant of a noreturn instruction. | ||
| 266 | condbr_inline, | ||
| 267 | /// A struct type definition. Contains references to ZIR instructions for | ||
| 268 | /// the field types, defaults, and alignments. | ||
| 269 | /// Uses the `pl_node` union field. Payload is `StructDecl`. | ||
| 270 | struct_decl, | ||
| 271 | /// Same as `struct_decl`, except has the `packed` layout. | ||
| 272 | struct_decl_packed, | ||
| 273 | /// Same as `struct_decl`, except has the `extern` layout. | ||
| 274 | struct_decl_extern, | ||
| 275 | /// A union type definition. Contains references to ZIR instructions for | ||
| 276 | /// the field types and optional type tag expression. | ||
| 277 | /// Uses the `pl_node` union field. Payload is `UnionDecl`. | ||
| 278 | union_decl, | ||
| 279 | /// An enum type definition. Contains references to ZIR instructions for | ||
| 280 | /// the field value expressions and optional type tag expression. | ||
| 281 | /// Uses the `pl_node` union field. Payload is `EnumDecl`. | ||
| 282 | enum_decl, | ||
| 283 | /// Same as `enum_decl`, except the enum is non-exhaustive. | ||
| 284 | enum_decl_nonexhaustive, | ||
| 285 | /// An opaque type definition. Provides an AST node only. | ||
| 286 | /// Uses the `node` union field. | ||
| 287 | opaque_decl, | ||
| 288 | /// Declares the beginning of a statement. Used for debug info. | ||
| 289 | /// Uses the `node` union field. | ||
| 290 | dbg_stmt_node, | ||
| 291 | /// Represents a pointer to a global decl. | ||
| 292 | /// Uses the `pl_node` union field. `payload_index` is into `decls`. | ||
| 293 | decl_ref, | ||
| 294 | /// Equivalent to a decl_ref followed by load. | ||
| 295 | /// Uses the `pl_node` union field. `payload_index` is into `decls`. | ||
| 296 | decl_val, | ||
| 297 | /// Load the value from a pointer. Assumes `x.*` syntax. | ||
| 298 | /// Uses `un_node` field. AST node is the `x.*` syntax. | ||
| 299 | load, | ||
| 300 | /// Arithmetic division. Asserts no integer overflow. | ||
| 301 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 302 | div, | ||
| 303 | /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at | ||
| 304 | /// the provided index. Uses the `bin` union field. Source location is implied | ||
| 305 | /// to be the same as the previous instruction. | ||
| 306 | elem_ptr, | ||
| 307 | /// Same as `elem_ptr` except also stores a source location node. | ||
| 308 | /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. | ||
| 309 | elem_ptr_node, | ||
| 310 | /// Given an array, slice, or pointer, returns the element at the provided index. | ||
| 311 | /// Uses the `bin` union field. Source location is implied to be the same | ||
| 312 | /// as the previous instruction. | ||
| 313 | elem_val, | ||
| 314 | /// Same as `elem_val` except also stores a source location node. | ||
| 315 | /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. | ||
| 316 | elem_val_node, | ||
| 317 | /// This instruction has been deleted late in the astgen phase. It must | ||
| 318 | /// be ignored, and the corresponding `Data` is undefined. | ||
| 319 | elided, | ||
| 320 | /// Emits a compile error if the operand is not `void`. | ||
| 321 | /// Uses the `un_node` field. | ||
| 322 | ensure_result_used, | ||
| 323 | /// Emits a compile error if an error is ignored. | ||
| 324 | /// Uses the `un_node` field. | ||
| 325 | ensure_result_non_error, | ||
| 326 | /// Create a `E!T` type. | ||
| 327 | /// Uses the `pl_node` field with `Bin` payload. | ||
| 328 | error_union_type, | ||
| 329 | /// `error.Foo` syntax. Uses the `str_tok` field of the Data union. | ||
| 330 | error_value, | ||
| 331 | /// Implements the `@export` builtin function. | ||
| 332 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 333 | @"export", | ||
| 334 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | ||
| 335 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. | ||
| 336 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. | ||
| 337 | field_ptr, | ||
| 338 | /// Given a struct or object that contains virtual fields, returns the named field. | ||
| 339 | /// The field name is stored in string_bytes. Used by a.b syntax. | ||
| 340 | /// This instruction also accepts a pointer. | ||
| 341 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. | ||
| 342 | field_val, | ||
| 343 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | ||
| 344 | /// to the named field. The field name is a comptime instruction. Used by @field. | ||
| 345 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. | ||
| 346 | field_ptr_named, | ||
| 347 | /// Given a struct or object that contains virtual fields, returns the named field. | ||
| 348 | /// The field name is a comptime instruction. Used by @field. | ||
| 349 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. | ||
| 350 | field_val_named, | ||
| 351 | /// Convert a larger float type to any other float type, possibly causing | ||
| 352 | /// a loss of precision. | ||
| 353 | /// Uses the `pl_node` field. AST is the `@floatCast` syntax. | ||
| 354 | /// Payload is `Bin` with lhs as the dest type, rhs the operand. | ||
| 355 | floatcast, | ||
| 356 | /// Returns a function type, assuming unspecified calling convention. | ||
| 357 | /// Uses the `pl_node` union field. `payload_index` points to a `FnType`. | ||
| 358 | fn_type, | ||
| 359 | /// Same as `fn_type` but the function is variadic. | ||
| 360 | fn_type_var_args, | ||
| 361 | /// Returns a function type, with a calling convention instruction operand. | ||
| 362 | /// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`. | ||
| 363 | fn_type_cc, | ||
| 364 | /// Same as `fn_type_cc` but the function is variadic. | ||
| 365 | fn_type_cc_var_args, | ||
| 366 | /// Implements the `@hasDecl` builtin. | ||
| 367 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 368 | has_decl, | ||
| 369 | /// `@import(operand)`. | ||
| 370 | /// Uses the `un_node` field. | ||
| 371 | import, | ||
| 372 | /// Integer literal that fits in a u64. Uses the int union value. | ||
| 373 | int, | ||
| 374 | /// A float literal that fits in a f32. Uses the float union value. | ||
| 375 | float, | ||
| 376 | /// A float literal that fits in a f128. Uses the `pl_node` union value. | ||
| 377 | /// Payload is `Float128`. | ||
| 378 | float128, | ||
| 379 | /// Convert an integer value to another integer type, asserting that the destination type | ||
| 380 | /// can hold the same mathematical value. | ||
| 381 | /// Uses the `pl_node` field. AST is the `@intCast` syntax. | ||
| 382 | /// Payload is `Bin` with lhs as the dest type, rhs the operand. | ||
| 383 | intcast, | ||
| 384 | /// Make an integer type out of signedness and bit count. | ||
| 385 | /// Payload is `int_type` | ||
| 386 | int_type, | ||
| 387 | /// Convert an error type to `u16` | ||
| 388 | error_to_int, | ||
| 389 | /// Convert a `u16` to `anyerror` | ||
| 390 | int_to_error, | ||
| 391 | /// Return a boolean false if an optional is null. `x != null` | ||
| 392 | /// Uses the `un_node` field. | ||
| 393 | is_non_null, | ||
| 394 | /// Return a boolean true if an optional is null. `x == null` | ||
| 395 | /// Uses the `un_node` field. | ||
| 396 | is_null, | ||
| 397 | /// Return a boolean false if an optional is null. `x.* != null` | ||
| 398 | /// Uses the `un_node` field. | ||
| 399 | is_non_null_ptr, | ||
| 400 | /// Return a boolean true if an optional is null. `x.* == null` | ||
| 401 | /// Uses the `un_node` field. | ||
| 402 | is_null_ptr, | ||
| 403 | /// Return a boolean true if value is an error | ||
| 404 | /// Uses the `un_node` field. | ||
| 405 | is_err, | ||
| 406 | /// Return a boolean true if dereferenced pointer is an error | ||
| 407 | /// Uses the `un_node` field. | ||
| 408 | is_err_ptr, | ||
| 409 | /// A labeled block of code that loops forever. At the end of the body will have either | ||
| 410 | /// a `repeat` instruction or a `repeat_inline` instruction. | ||
| 411 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. | ||
| 412 | /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema | ||
| 413 | /// needs to emit more than 1 TZIR block for this instruction. | ||
| 414 | /// The payload is `Block`. | ||
| 415 | loop, | ||
| 416 | /// Sends runtime control flow back to the beginning of the current block. | ||
| 417 | /// Uses the `node` field. | ||
| 418 | repeat, | ||
| 419 | /// Sends comptime control flow back to the beginning of the current block. | ||
| 420 | /// Uses the `node` field. | ||
| 421 | repeat_inline, | ||
| 422 | /// Merge two error sets into one, `E1 || E2`. | ||
| 423 | /// Uses the `pl_node` field with payload `Bin`. | ||
| 424 | merge_error_sets, | ||
| 425 | /// Ambiguously remainder division or modulus. If the computation would possibly have | ||
| 426 | /// a different value depending on whether the operation is remainder division or modulus, | ||
| 427 | /// a compile error is emitted. Otherwise the computation is performed. | ||
| 428 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 429 | mod_rem, | ||
| 430 | /// Arithmetic multiplication. Asserts no integer overflow. | ||
| 431 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 432 | mul, | ||
| 433 | /// Twos complement wrapping integer multiplication. | ||
| 434 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 435 | mulwrap, | ||
| 436 | /// Given a reference to a function and a parameter index, returns the | ||
| 437 | /// type of the parameter. The only usage of this instruction is for the | ||
| 438 | /// result location of parameters of function calls. In the case of a function's | ||
| 439 | /// parameter type being `anytype`, it is the type coercion's job to detect this | ||
| 440 | /// scenario and skip the coercion, so that semantic analysis of this instruction | ||
| 441 | /// is not in a position where it must create an invalid type. | ||
| 442 | /// Uses the `param_type` union field. | ||
| 443 | param_type, | ||
| 444 | /// Convert a pointer to a `usize` integer. | ||
| 445 | /// Uses the `un_node` field. The AST node is the builtin fn call node. | ||
| 446 | ptrtoint, | ||
| 447 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, | ||
| 448 | /// stores it in a memory location, and returns a const pointer to it. If the value | ||
| 449 | /// is `comptime`, the memory location is global static constant data. Otherwise, | ||
| 450 | /// the memory location is in the stack frame, local to the scope containing the | ||
| 451 | /// instruction. | ||
| 452 | /// Uses the `un_tok` union field. | ||
| 453 | ref, | ||
| 454 | /// Obtains a pointer to the return value. | ||
| 455 | /// Uses the `node` union field. | ||
| 456 | ret_ptr, | ||
| 457 | /// Obtains the return type of the in-scope function. | ||
| 458 | /// Uses the `node` union field. | ||
| 459 | ret_type, | ||
| 460 | /// Sends control flow back to the function's callee. | ||
| 461 | /// Includes an operand as the return value. | ||
| 462 | /// Includes an AST node source location. | ||
| 463 | /// Uses the `un_node` union field. | ||
| 464 | ret_node, | ||
| 465 | /// Sends control flow back to the function's callee. | ||
| 466 | /// Includes an operand as the return value. | ||
| 467 | /// Includes a token source location. | ||
| 468 | /// Uses the `un_tok` union field. | ||
| 469 | ret_tok, | ||
| 470 | /// Same as `ret_tok` except the operand needs to get coerced to the function's | ||
| 471 | /// return type. | ||
| 472 | ret_coerce, | ||
| 473 | /// Changes the maximum number of backwards branches that compile-time | ||
| 474 | /// code execution can use before giving up and making a compile error. | ||
| 475 | /// Uses the `un_node` union field. | ||
| 476 | set_eval_branch_quota, | ||
| 477 | /// Integer shift-left. Zeroes are shifted in from the right hand side. | ||
| 478 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 479 | shl, | ||
| 480 | /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. | ||
| 481 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 482 | shr, | ||
| 483 | /// Create a pointer type that does not have a sentinel, alignment, or bit range specified. | ||
| 484 | /// Uses the `ptr_type_simple` union field. | ||
| 485 | ptr_type_simple, | ||
| 486 | /// Create a pointer type which can have a sentinel, alignment, and/or bit range. | ||
| 487 | /// Uses the `ptr_type` union field. | ||
| 488 | ptr_type, | ||
| 489 | /// Each `store_to_inferred_ptr` puts the type of the stored value into a set, | ||
| 490 | /// and then `resolve_inferred_alloc` triggers peer type resolution on the set. | ||
| 491 | /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which | ||
| 492 | /// is the allocation that needs to have its type inferred. | ||
| 493 | /// Uses the `un_node` field. The AST node is the var decl. | ||
| 494 | resolve_inferred_alloc, | ||
| 495 | /// Slice operation `lhs[rhs..]`. No sentinel and no end offset. | ||
| 496 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`. | ||
| 497 | slice_start, | ||
| 498 | /// Slice operation `array_ptr[start..end]`. No sentinel. | ||
| 499 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`. | ||
| 500 | slice_end, | ||
| 501 | /// Slice operation `array_ptr[start..end:sentinel]`. | ||
| 502 | /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`. | ||
| 503 | slice_sentinel, | ||
| 504 | /// Write a value to a pointer. For loading, see `load`. | ||
| 505 | /// Source location is assumed to be same as previous instruction. | ||
| 506 | /// Uses the `bin` union field. | ||
| 507 | store, | ||
| 508 | /// Same as `store` except provides a source location. | ||
| 509 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 510 | store_node, | ||
| 511 | /// Same as `store` but the type of the value being stored will be used to infer | ||
| 512 | /// the block type. The LHS is the pointer to store to. | ||
| 513 | /// Uses the `bin` union field. | ||
| 514 | store_to_block_ptr, | ||
| 515 | /// Same as `store` but the type of the value being stored will be used to infer | ||
| 516 | /// the pointer type. | ||
| 517 | /// Uses the `bin` union field - Astgen.zig depends on the ability to change | ||
| 518 | /// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr` | ||
| 519 | /// without changing the data. | ||
| 520 | store_to_inferred_ptr, | ||
| 521 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. | ||
| 522 | /// Uses the `str` union field. | ||
| 523 | str, | ||
| 524 | /// Arithmetic subtraction. Asserts no integer overflow. | ||
| 525 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 526 | sub, | ||
| 527 | /// Twos complement wrapping integer subtraction. | ||
| 528 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 529 | subwrap, | ||
| 530 | /// Arithmetic negation. Asserts no integer overflow. | ||
| 531 | /// Same as sub with a lhs of 0, split into a separate instruction to save memory. | ||
| 532 | /// Uses `un_node`. | ||
| 533 | negate, | ||
| 534 | /// Twos complement wrapping integer negation. | ||
| 535 | /// Same as subwrap with a lhs of 0, split into a separate instruction to save memory. | ||
| 536 | /// Uses `un_node`. | ||
| 537 | negate_wrap, | ||
| 538 | /// Returns the type of a value. | ||
| 539 | /// Uses the `un_tok` field. | ||
| 540 | typeof, | ||
| 541 | /// Given a value which is a pointer, returns the element type. | ||
| 542 | /// Uses the `un_node` field. | ||
| 543 | typeof_elem, | ||
| 544 | /// The builtin `@TypeOf` which returns the type after Peer Type Resolution | ||
| 545 | /// of one or more params. | ||
| 546 | /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`. | ||
| 547 | typeof_peer, | ||
| 548 | /// Asserts control-flow will not reach this instruction (`unreachable`). | ||
| 549 | /// Uses the `unreachable` union field. | ||
| 550 | @"unreachable", | ||
| 551 | /// Bitwise XOR. `^` | ||
| 552 | /// Uses the `pl_node` union field. Payload is `Bin`. | ||
| 553 | xor, | ||
| 554 | /// Create an optional type '?T' | ||
| 555 | /// Uses the `un_node` field. | ||
| 556 | optional_type, | ||
| 557 | /// Create an optional type '?T'. The operand is a pointer value. The optional type will | ||
| 558 | /// be the type of the pointer element, wrapped in an optional. | ||
| 559 | /// Uses the `un_node` field. | ||
| 560 | optional_type_from_ptr_elem, | ||
| 561 | /// ?T => T with safety. | ||
| 562 | /// Given an optional value, returns the payload value, with a safety check that | ||
| 563 | /// the value is non-null. Used for `orelse`, `if` and `while`. | ||
| 564 | /// Uses the `un_node` field. | ||
| 565 | optional_payload_safe, | ||
| 566 | /// ?T => T without safety. | ||
| 567 | /// Given an optional value, returns the payload value. No safety checks. | ||
| 568 | /// Uses the `un_node` field. | ||
| 569 | optional_payload_unsafe, | ||
| 570 | /// *?T => *T with safety. | ||
| 571 | /// Given a pointer to an optional value, returns a pointer to the payload value, | ||
| 572 | /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`. | ||
| 573 | /// Uses the `un_node` field. | ||
| 574 | optional_payload_safe_ptr, | ||
| 575 | /// *?T => *T without safety. | ||
| 576 | /// Given a pointer to an optional value, returns a pointer to the payload value. | ||
| 577 | /// No safety checks. | ||
| 578 | /// Uses the `un_node` field. | ||
| 579 | optional_payload_unsafe_ptr, | ||
| 580 | /// E!T => T with safety. | ||
| 581 | /// Given an error union value, returns the payload value, with a safety check | ||
| 582 | /// that the value is not an error. Used for catch, if, and while. | ||
| 583 | /// Uses the `un_node` field. | ||
| 584 | err_union_payload_safe, | ||
| 585 | /// E!T => T without safety. | ||
| 586 | /// Given an error union value, returns the payload value. No safety checks. | ||
| 587 | /// Uses the `un_node` field. | ||
| 588 | err_union_payload_unsafe, | ||
| 589 | /// *E!T => *T with safety. | ||
| 590 | /// Given a pointer to an error union value, returns a pointer to the payload value, | ||
| 591 | /// with a safety check that the value is not an error. Used for catch, if, and while. | ||
| 592 | /// Uses the `un_node` field. | ||
| 593 | err_union_payload_safe_ptr, | ||
| 594 | /// *E!T => *T without safety. | ||
| 595 | /// Given a pointer to a error union value, returns a pointer to the payload value. | ||
| 596 | /// No safety checks. | ||
| 597 | /// Uses the `un_node` field. | ||
| 598 | err_union_payload_unsafe_ptr, | ||
| 599 | /// E!T => E without safety. | ||
| 600 | /// Given an error union value, returns the error code. No safety checks. | ||
| 601 | /// Uses the `un_node` field. | ||
| 602 | err_union_code, | ||
| 603 | /// *E!T => E without safety. | ||
| 604 | /// Given a pointer to an error union value, returns the error code. No safety checks. | ||
| 605 | /// Uses the `un_node` field. | ||
| 606 | err_union_code_ptr, | ||
| 607 | /// Takes a *E!T and raises a compiler error if T != void | ||
| 608 | /// Uses the `un_tok` field. | ||
| 609 | ensure_err_payload_void, | ||
| 610 | /// An enum literal. Uses the `str_tok` union field. | ||
| 611 | enum_literal, | ||
| 612 | /// An enum literal 8 or fewer bytes. No source location. | ||
| 613 | /// Uses the `small_str` field. | ||
| 614 | enum_literal_small, | ||
| 615 | /// A switch expression. Uses the `pl_node` union field. | ||
| 616 | /// AST node is the switch, payload is `SwitchBlock`. | ||
| 617 | /// All prongs of target handled. | ||
| 618 | switch_block, | ||
| 619 | /// Same as switch_block, except one or more prongs have multiple items. | ||
| 620 | switch_block_multi, | ||
| 621 | /// Same as switch_block, except has an else prong. | ||
| 622 | switch_block_else, | ||
| 623 | /// Same as switch_block_else, except one or more prongs have multiple items. | ||
| 624 | switch_block_else_multi, | ||
| 625 | /// Same as switch_block, except has an underscore prong. | ||
| 626 | switch_block_under, | ||
| 627 | /// Same as switch_block, except one or more prongs have multiple items. | ||
| 628 | switch_block_under_multi, | ||
| 629 | /// Same as `switch_block` but the target is a pointer to the value being switched on. | ||
| 630 | switch_block_ref, | ||
| 631 | /// Same as `switch_block_multi` but the target is a pointer to the value being switched on. | ||
| 632 | switch_block_ref_multi, | ||
| 633 | /// Same as `switch_block_else` but the target is a pointer to the value being switched on. | ||
| 634 | switch_block_ref_else, | ||
| 635 | /// Same as `switch_block_else_multi` but the target is a pointer to the | ||
| 636 | /// value being switched on. | ||
| 637 | switch_block_ref_else_multi, | ||
| 638 | /// Same as `switch_block_under` but the target is a pointer to the value | ||
| 639 | /// being switched on. | ||
| 640 | switch_block_ref_under, | ||
| 641 | /// Same as `switch_block_under_multi` but the target is a pointer to | ||
| 642 | /// the value being switched on. | ||
| 643 | switch_block_ref_under_multi, | ||
| 644 | /// Produces the capture value for a switch prong. | ||
| 645 | /// Uses the `switch_capture` field. | ||
| 646 | switch_capture, | ||
| 647 | /// Produces the capture value for a switch prong. | ||
| 648 | /// Result is a pointer to the value. | ||
| 649 | /// Uses the `switch_capture` field. | ||
| 650 | switch_capture_ref, | ||
| 651 | /// Produces the capture value for a switch prong. | ||
| 652 | /// The prong is one of the multi cases. | ||
| 653 | /// Uses the `switch_capture` field. | ||
| 654 | switch_capture_multi, | ||
| 655 | /// Produces the capture value for a switch prong. | ||
| 656 | /// The prong is one of the multi cases. | ||
| 657 | /// Result is a pointer to the value. | ||
| 658 | /// Uses the `switch_capture` field. | ||
| 659 | switch_capture_multi_ref, | ||
| 660 | /// Produces the capture value for the else/'_' switch prong. | ||
| 661 | /// Uses the `switch_capture` field. | ||
| 662 | switch_capture_else, | ||
| 663 | /// Produces the capture value for the else/'_' switch prong. | ||
| 664 | /// Result is a pointer to the value. | ||
| 665 | /// Uses the `switch_capture` field. | ||
| 666 | switch_capture_else_ref, | ||
| 667 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct | ||
| 668 | /// initialization expression, and emits compile errors for duplicate fields | ||
| 669 | /// as well as missing fields, if applicable. | ||
| 670 | /// This instruction asserts that there is at least one field_ptr instruction, | ||
| 671 | /// because it must use one of them to find out the struct type. | ||
| 672 | /// Uses the `pl_node` field. Payload is `Block`. | ||
| 673 | validate_struct_init_ptr, | ||
| 674 | /// A struct literal with a specified type, with no fields. | ||
| 675 | /// Uses the `un_node` field. | ||
| 676 | struct_init_empty, | ||
| 677 | /// Given a struct, union, enum, or opaque and a field name, returns the field type. | ||
| 678 | /// Uses the `pl_node` field. Payload is `FieldType`. | ||
| 679 | field_type, | ||
| 680 | /// Finalizes a typed struct initialization, performs validation, and returns the | ||
| 681 | /// struct value. | ||
| 682 | /// Uses the `pl_node` field. Payload is `StructInit`. | ||
| 683 | struct_init, | ||
| 684 | /// Converts an integer into an enum value. | ||
| 685 | /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand. | ||
| 686 | int_to_enum, | ||
| 687 | /// Converts an enum value into an integer. Resulting type will be the tag type | ||
| 688 | /// of the enum. Uses `un_node`. | ||
| 689 | enum_to_int, | ||
| 690 | /// Implements the `@typeInfo` builtin. Uses `un_node`. | ||
| 691 | type_info, | ||
| 692 | |||
| 693 | /// Returns whether the instruction is one of the control flow "noreturn" types. | ||
| 694 | /// Function calls do not count. | ||
| 695 | pub fn isNoReturn(tag: Tag) bool { | ||
| 696 | return switch (tag) { | ||
| 697 | .add, | ||
| 698 | .addwrap, | ||
| 699 | .alloc, | ||
| 700 | .alloc_mut, | ||
| 701 | .alloc_inferred, | ||
| 702 | .alloc_inferred_mut, | ||
| 703 | .array_cat, | ||
| 704 | .array_mul, | ||
| 705 | .array_type, | ||
| 706 | .array_type_sentinel, | ||
| 707 | .indexable_ptr_len, | ||
| 708 | .as, | ||
| 709 | .as_node, | ||
| 710 | .@"asm", | ||
| 711 | .asm_volatile, | ||
| 712 | .bit_and, | ||
| 713 | .bitcast, | ||
| 714 | .bitcast_result_ptr, | ||
| 715 | .bit_or, | ||
| 716 | .block, | ||
| 717 | .block_inline, | ||
| 718 | .loop, | ||
| 719 | .bool_br_and, | ||
| 720 | .bool_br_or, | ||
| 721 | .bool_not, | ||
| 722 | .bool_and, | ||
| 723 | .bool_or, | ||
| 724 | .breakpoint, | ||
| 725 | .call, | ||
| 726 | .call_chkused, | ||
| 727 | .call_compile_time, | ||
| 728 | .call_none, | ||
| 729 | .call_none_chkused, | ||
| 730 | .cmp_lt, | ||
| 731 | .cmp_lte, | ||
| 732 | .cmp_eq, | ||
| 733 | .cmp_gte, | ||
| 734 | .cmp_gt, | ||
| 735 | .cmp_neq, | ||
| 736 | .coerce_result_ptr, | ||
| 737 | .struct_decl, | ||
| 738 | .struct_decl_packed, | ||
| 739 | .struct_decl_extern, | ||
| 740 | .union_decl, | ||
| 741 | .enum_decl, | ||
| 742 | .enum_decl_nonexhaustive, | ||
| 743 | .opaque_decl, | ||
| 744 | .dbg_stmt_node, | ||
| 745 | .decl_ref, | ||
| 746 | .decl_val, | ||
| 747 | .load, | ||
| 748 | .div, | ||
| 749 | .elem_ptr, | ||
| 750 | .elem_val, | ||
| 751 | .elem_ptr_node, | ||
| 752 | .elem_val_node, | ||
| 753 | .ensure_result_used, | ||
| 754 | .ensure_result_non_error, | ||
| 755 | .@"export", | ||
| 756 | .floatcast, | ||
| 757 | .field_ptr, | ||
| 758 | .field_val, | ||
| 759 | .field_ptr_named, | ||
| 760 | .field_val_named, | ||
| 761 | .fn_type, | ||
| 762 | .fn_type_var_args, | ||
| 763 | .fn_type_cc, | ||
| 764 | .fn_type_cc_var_args, | ||
| 765 | .has_decl, | ||
| 766 | .int, | ||
| 767 | .float, | ||
| 768 | .float128, | ||
| 769 | .intcast, | ||
| 770 | .int_type, | ||
| 771 | .is_non_null, | ||
| 772 | .is_null, | ||
| 773 | .is_non_null_ptr, | ||
| 774 | .is_null_ptr, | ||
| 775 | .is_err, | ||
| 776 | .is_err_ptr, | ||
| 777 | .mod_rem, | ||
| 778 | .mul, | ||
| 779 | .mulwrap, | ||
| 780 | .param_type, | ||
| 781 | .ptrtoint, | ||
| 782 | .ref, | ||
| 783 | .ret_ptr, | ||
| 784 | .ret_type, | ||
| 785 | .shl, | ||
| 786 | .shr, | ||
| 787 | .store, | ||
| 788 | .store_node, | ||
| 789 | .store_to_block_ptr, | ||
| 790 | .store_to_inferred_ptr, | ||
| 791 | .str, | ||
| 792 | .sub, | ||
| 793 | .subwrap, | ||
| 794 | .negate, | ||
| 795 | .negate_wrap, | ||
| 796 | .typeof, | ||
| 797 | .typeof_elem, | ||
| 798 | .xor, | ||
| 799 | .optional_type, | ||
| 800 | .optional_type_from_ptr_elem, | ||
| 801 | .optional_payload_safe, | ||
| 802 | .optional_payload_unsafe, | ||
| 803 | .optional_payload_safe_ptr, | ||
| 804 | .optional_payload_unsafe_ptr, | ||
| 805 | .err_union_payload_safe, | ||
| 806 | .err_union_payload_unsafe, | ||
| 807 | .err_union_payload_safe_ptr, | ||
| 808 | .err_union_payload_unsafe_ptr, | ||
| 809 | .err_union_code, | ||
| 810 | .err_union_code_ptr, | ||
| 811 | .error_to_int, | ||
| 812 | .int_to_error, | ||
| 813 | .ptr_type, | ||
| 814 | .ptr_type_simple, | ||
| 815 | .ensure_err_payload_void, | ||
| 816 | .enum_literal, | ||
| 817 | .enum_literal_small, | ||
| 818 | .merge_error_sets, | ||
| 819 | .error_union_type, | ||
| 820 | .bit_not, | ||
| 821 | .error_value, | ||
| 822 | .slice_start, | ||
| 823 | .slice_end, | ||
| 824 | .slice_sentinel, | ||
| 825 | .import, | ||
| 826 | .typeof_peer, | ||
| 827 | .resolve_inferred_alloc, | ||
| 828 | .set_eval_branch_quota, | ||
| 829 | .compile_log, | ||
| 830 | .elided, | ||
| 831 | .switch_capture, | ||
| 832 | .switch_capture_ref, | ||
| 833 | .switch_capture_multi, | ||
| 834 | .switch_capture_multi_ref, | ||
| 835 | .switch_capture_else, | ||
| 836 | .switch_capture_else_ref, | ||
| 837 | .switch_block, | ||
| 838 | .switch_block_multi, | ||
| 839 | .switch_block_else, | ||
| 840 | .switch_block_else_multi, | ||
| 841 | .switch_block_under, | ||
| 842 | .switch_block_under_multi, | ||
| 843 | .switch_block_ref, | ||
| 844 | .switch_block_ref_multi, | ||
| 845 | .switch_block_ref_else, | ||
| 846 | .switch_block_ref_else_multi, | ||
| 847 | .switch_block_ref_under, | ||
| 848 | .switch_block_ref_under_multi, | ||
| 849 | .validate_struct_init_ptr, | ||
| 850 | .struct_init_empty, | ||
| 851 | .struct_init, | ||
| 852 | .field_type, | ||
| 853 | .int_to_enum, | ||
| 854 | .enum_to_int, | ||
| 855 | .type_info, | ||
| 856 | => false, | ||
| 857 | |||
| 858 | .@"break", | ||
| 859 | .break_inline, | ||
| 860 | .condbr, | ||
| 861 | .condbr_inline, | ||
| 862 | .compile_error, | ||
| 863 | .ret_node, | ||
| 864 | .ret_tok, | ||
| 865 | .ret_coerce, | ||
| 866 | .@"unreachable", | ||
| 867 | .repeat, | ||
| 868 | .repeat_inline, | ||
| 869 | => true, | ||
| 870 | }; | ||
| 871 | } | ||
| 872 | }; | ||
| 873 | |||
| 874 | /// The position of a ZIR instruction within the `Code` instructions array. | ||
| 875 | pub const Index = u32; | ||
| 876 | |||
| 877 | /// A reference to a TypedValue, parameter of the current function, | ||
| 878 | /// or ZIR instruction. | ||
| 879 | /// | ||
| 880 | /// If the Ref has a tag in this enum, it refers to a TypedValue which may be | ||
| 881 | /// retrieved with Ref.toTypedValue(). | ||
| 882 | /// | ||
| 883 | /// If the value of a Ref does not have a tag, it referes to either a parameter | ||
| 884 | /// of the current function or a ZIR instruction. | ||
| 885 | /// | ||
| 886 | /// The first values after the the last tag refer to parameters which may be | ||
| 887 | /// derived by subtracting typed_value_map.len. | ||
| 888 | /// | ||
| 889 | /// All further values refer to ZIR instructions which may be derived by | ||
| 890 | /// subtracting typed_value_map.len and the number of parameters. | ||
| 891 | /// | ||
| 892 | /// When adding a tag to this enum, consider adding a corresponding entry to | ||
| 893 | /// `simple_types` in astgen. | ||
| 894 | /// | ||
| 895 | /// The tag type is specified so that it is safe to bitcast between `[]u32` | ||
| 896 | /// and `[]Ref`. | ||
| 897 | pub const Ref = enum(u32) { | ||
| 898 | /// This Ref does not correspond to any ZIR instruction or constant | ||
| 899 | /// value and may instead be used as a sentinel to indicate null. | ||
| 900 | none, | ||
| 901 | |||
| 902 | u8_type, | ||
| 903 | i8_type, | ||
| 904 | u16_type, | ||
| 905 | i16_type, | ||
| 906 | u32_type, | ||
| 907 | i32_type, | ||
| 908 | u64_type, | ||
| 909 | i64_type, | ||
| 910 | usize_type, | ||
| 911 | isize_type, | ||
| 912 | c_short_type, | ||
| 913 | c_ushort_type, | ||
| 914 | c_int_type, | ||
| 915 | c_uint_type, | ||
| 916 | c_long_type, | ||
| 917 | c_ulong_type, | ||
| 918 | c_longlong_type, | ||
| 919 | c_ulonglong_type, | ||
| 920 | c_longdouble_type, | ||
| 921 | f16_type, | ||
| 922 | f32_type, | ||
| 923 | f64_type, | ||
| 924 | f128_type, | ||
| 925 | c_void_type, | ||
| 926 | bool_type, | ||
| 927 | void_type, | ||
| 928 | type_type, | ||
| 929 | anyerror_type, | ||
| 930 | comptime_int_type, | ||
| 931 | comptime_float_type, | ||
| 932 | noreturn_type, | ||
| 933 | null_type, | ||
| 934 | undefined_type, | ||
| 935 | fn_noreturn_no_args_type, | ||
| 936 | fn_void_no_args_type, | ||
| 937 | fn_naked_noreturn_no_args_type, | ||
| 938 | fn_ccc_void_no_args_type, | ||
| 939 | single_const_pointer_to_comptime_int_type, | ||
| 940 | const_slice_u8_type, | ||
| 941 | enum_literal_type, | ||
| 942 | |||
| 943 | /// `undefined` (untyped) | ||
| 944 | undef, | ||
| 945 | /// `0` (comptime_int) | ||
| 946 | zero, | ||
| 947 | /// `1` (comptime_int) | ||
| 948 | one, | ||
| 949 | /// `{}` | ||
| 950 | void_value, | ||
| 951 | /// `unreachable` (noreturn type) | ||
| 952 | unreachable_value, | ||
| 953 | /// `null` (untyped) | ||
| 954 | null_value, | ||
| 955 | /// `true` | ||
| 956 | bool_true, | ||
| 957 | /// `false` | ||
| 958 | bool_false, | ||
| 959 | /// `.{}` (untyped) | ||
| 960 | empty_struct, | ||
| 961 | /// `0` (usize) | ||
| 962 | zero_usize, | ||
| 963 | /// `1` (usize) | ||
| 964 | one_usize, | ||
| 965 | |||
| 966 | _, | ||
| 967 | |||
| 968 | pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{ | ||
| 969 | .none = undefined, | ||
| 970 | |||
| 971 | .u8_type = .{ | ||
| 972 | .ty = Type.initTag(.type), | ||
| 973 | .val = Value.initTag(.u8_type), | ||
| 974 | }, | ||
| 975 | .i8_type = .{ | ||
| 976 | .ty = Type.initTag(.type), | ||
| 977 | .val = Value.initTag(.i8_type), | ||
| 978 | }, | ||
| 979 | .u16_type = .{ | ||
| 980 | .ty = Type.initTag(.type), | ||
| 981 | .val = Value.initTag(.u16_type), | ||
| 982 | }, | ||
| 983 | .i16_type = .{ | ||
| 984 | .ty = Type.initTag(.type), | ||
| 985 | .val = Value.initTag(.i16_type), | ||
| 986 | }, | ||
| 987 | .u32_type = .{ | ||
| 988 | .ty = Type.initTag(.type), | ||
| 989 | .val = Value.initTag(.u32_type), | ||
| 990 | }, | ||
| 991 | .i32_type = .{ | ||
| 992 | .ty = Type.initTag(.type), | ||
| 993 | .val = Value.initTag(.i32_type), | ||
| 994 | }, | ||
| 995 | .u64_type = .{ | ||
| 996 | .ty = Type.initTag(.type), | ||
| 997 | .val = Value.initTag(.u64_type), | ||
| 998 | }, | ||
| 999 | .i64_type = .{ | ||
| 1000 | .ty = Type.initTag(.type), | ||
| 1001 | .val = Value.initTag(.i64_type), | ||
| 1002 | }, | ||
| 1003 | .usize_type = .{ | ||
| 1004 | .ty = Type.initTag(.type), | ||
| 1005 | .val = Value.initTag(.usize_type), | ||
| 1006 | }, | ||
| 1007 | .isize_type = .{ | ||
| 1008 | .ty = Type.initTag(.type), | ||
| 1009 | .val = Value.initTag(.isize_type), | ||
| 1010 | }, | ||
| 1011 | .c_short_type = .{ | ||
| 1012 | .ty = Type.initTag(.type), | ||
| 1013 | .val = Value.initTag(.c_short_type), | ||
| 1014 | }, | ||
| 1015 | .c_ushort_type = .{ | ||
| 1016 | .ty = Type.initTag(.type), | ||
| 1017 | .val = Value.initTag(.c_ushort_type), | ||
| 1018 | }, | ||
| 1019 | .c_int_type = .{ | ||
| 1020 | .ty = Type.initTag(.type), | ||
| 1021 | .val = Value.initTag(.c_int_type), | ||
| 1022 | }, | ||
| 1023 | .c_uint_type = .{ | ||
| 1024 | .ty = Type.initTag(.type), | ||
| 1025 | .val = Value.initTag(.c_uint_type), | ||
| 1026 | }, | ||
| 1027 | .c_long_type = .{ | ||
| 1028 | .ty = Type.initTag(.type), | ||
| 1029 | .val = Value.initTag(.c_long_type), | ||
| 1030 | }, | ||
| 1031 | .c_ulong_type = .{ | ||
| 1032 | .ty = Type.initTag(.type), | ||
| 1033 | .val = Value.initTag(.c_ulong_type), | ||
| 1034 | }, | ||
| 1035 | .c_longlong_type = .{ | ||
| 1036 | .ty = Type.initTag(.type), | ||
| 1037 | .val = Value.initTag(.c_longlong_type), | ||
| 1038 | }, | ||
| 1039 | .c_ulonglong_type = .{ | ||
| 1040 | .ty = Type.initTag(.type), | ||
| 1041 | .val = Value.initTag(.c_ulonglong_type), | ||
| 1042 | }, | ||
| 1043 | .c_longdouble_type = .{ | ||
| 1044 | .ty = Type.initTag(.type), | ||
| 1045 | .val = Value.initTag(.c_longdouble_type), | ||
| 1046 | }, | ||
| 1047 | .f16_type = .{ | ||
| 1048 | .ty = Type.initTag(.type), | ||
| 1049 | .val = Value.initTag(.f16_type), | ||
| 1050 | }, | ||
| 1051 | .f32_type = .{ | ||
| 1052 | .ty = Type.initTag(.type), | ||
| 1053 | .val = Value.initTag(.f32_type), | ||
| 1054 | }, | ||
| 1055 | .f64_type = .{ | ||
| 1056 | .ty = Type.initTag(.type), | ||
| 1057 | .val = Value.initTag(.f64_type), | ||
| 1058 | }, | ||
| 1059 | .f128_type = .{ | ||
| 1060 | .ty = Type.initTag(.type), | ||
| 1061 | .val = Value.initTag(.f128_type), | ||
| 1062 | }, | ||
| 1063 | .c_void_type = .{ | ||
| 1064 | .ty = Type.initTag(.type), | ||
| 1065 | .val = Value.initTag(.c_void_type), | ||
| 1066 | }, | ||
| 1067 | .bool_type = .{ | ||
| 1068 | .ty = Type.initTag(.type), | ||
| 1069 | .val = Value.initTag(.bool_type), | ||
| 1070 | }, | ||
| 1071 | .void_type = .{ | ||
| 1072 | .ty = Type.initTag(.type), | ||
| 1073 | .val = Value.initTag(.void_type), | ||
| 1074 | }, | ||
| 1075 | .type_type = .{ | ||
| 1076 | .ty = Type.initTag(.type), | ||
| 1077 | .val = Value.initTag(.type_type), | ||
| 1078 | }, | ||
| 1079 | .anyerror_type = .{ | ||
| 1080 | .ty = Type.initTag(.type), | ||
| 1081 | .val = Value.initTag(.anyerror_type), | ||
| 1082 | }, | ||
| 1083 | .comptime_int_type = .{ | ||
| 1084 | .ty = Type.initTag(.type), | ||
| 1085 | .val = Value.initTag(.comptime_int_type), | ||
| 1086 | }, | ||
| 1087 | .comptime_float_type = .{ | ||
| 1088 | .ty = Type.initTag(.type), | ||
| 1089 | .val = Value.initTag(.comptime_float_type), | ||
| 1090 | }, | ||
| 1091 | .noreturn_type = .{ | ||
| 1092 | .ty = Type.initTag(.type), | ||
| 1093 | .val = Value.initTag(.noreturn_type), | ||
| 1094 | }, | ||
| 1095 | .null_type = .{ | ||
| 1096 | .ty = Type.initTag(.type), | ||
| 1097 | .val = Value.initTag(.null_type), | ||
| 1098 | }, | ||
| 1099 | .undefined_type = .{ | ||
| 1100 | .ty = Type.initTag(.type), | ||
| 1101 | .val = Value.initTag(.undefined_type), | ||
| 1102 | }, | ||
| 1103 | .fn_noreturn_no_args_type = .{ | ||
| 1104 | .ty = Type.initTag(.type), | ||
| 1105 | .val = Value.initTag(.fn_noreturn_no_args_type), | ||
| 1106 | }, | ||
| 1107 | .fn_void_no_args_type = .{ | ||
| 1108 | .ty = Type.initTag(.type), | ||
| 1109 | .val = Value.initTag(.fn_void_no_args_type), | ||
| 1110 | }, | ||
| 1111 | .fn_naked_noreturn_no_args_type = .{ | ||
| 1112 | .ty = Type.initTag(.type), | ||
| 1113 | .val = Value.initTag(.fn_naked_noreturn_no_args_type), | ||
| 1114 | }, | ||
| 1115 | .fn_ccc_void_no_args_type = .{ | ||
| 1116 | .ty = Type.initTag(.type), | ||
| 1117 | .val = Value.initTag(.fn_ccc_void_no_args_type), | ||
| 1118 | }, | ||
| 1119 | .single_const_pointer_to_comptime_int_type = .{ | ||
| 1120 | .ty = Type.initTag(.type), | ||
| 1121 | .val = Value.initTag(.single_const_pointer_to_comptime_int_type), | ||
| 1122 | }, | ||
| 1123 | .const_slice_u8_type = .{ | ||
| 1124 | .ty = Type.initTag(.type), | ||
| 1125 | .val = Value.initTag(.const_slice_u8_type), | ||
| 1126 | }, | ||
| 1127 | .enum_literal_type = .{ | ||
| 1128 | .ty = Type.initTag(.type), | ||
| 1129 | .val = Value.initTag(.enum_literal_type), | ||
| 1130 | }, | ||
| 1131 | |||
| 1132 | .undef = .{ | ||
| 1133 | .ty = Type.initTag(.@"undefined"), | ||
| 1134 | .val = Value.initTag(.undef), | ||
| 1135 | }, | ||
| 1136 | .zero = .{ | ||
| 1137 | .ty = Type.initTag(.comptime_int), | ||
| 1138 | .val = Value.initTag(.zero), | ||
| 1139 | }, | ||
| 1140 | .zero_usize = .{ | ||
| 1141 | .ty = Type.initTag(.usize), | ||
| 1142 | .val = Value.initTag(.zero), | ||
| 1143 | }, | ||
| 1144 | .one = .{ | ||
| 1145 | .ty = Type.initTag(.comptime_int), | ||
| 1146 | .val = Value.initTag(.one), | ||
| 1147 | }, | ||
| 1148 | .one_usize = .{ | ||
| 1149 | .ty = Type.initTag(.usize), | ||
| 1150 | .val = Value.initTag(.one), | ||
| 1151 | }, | ||
| 1152 | .void_value = .{ | ||
| 1153 | .ty = Type.initTag(.void), | ||
| 1154 | .val = Value.initTag(.void_value), | ||
| 1155 | }, | ||
| 1156 | .unreachable_value = .{ | ||
| 1157 | .ty = Type.initTag(.noreturn), | ||
| 1158 | .val = Value.initTag(.unreachable_value), | ||
| 1159 | }, | ||
| 1160 | .null_value = .{ | ||
| 1161 | .ty = Type.initTag(.@"null"), | ||
| 1162 | .val = Value.initTag(.null_value), | ||
| 1163 | }, | ||
| 1164 | .bool_true = .{ | ||
| 1165 | .ty = Type.initTag(.bool), | ||
| 1166 | .val = Value.initTag(.bool_true), | ||
| 1167 | }, | ||
| 1168 | .bool_false = .{ | ||
| 1169 | .ty = Type.initTag(.bool), | ||
| 1170 | .val = Value.initTag(.bool_false), | ||
| 1171 | }, | ||
| 1172 | .empty_struct = .{ | ||
| 1173 | .ty = Type.initTag(.empty_struct_literal), | ||
| 1174 | .val = Value.initTag(.empty_struct_value), | ||
| 1175 | }, | ||
| 1176 | }); | ||
| 1177 | }; | ||
| 1178 | |||
| 1179 | /// All instructions have an 8-byte payload, which is contained within | ||
| 1180 | /// this union. `Tag` determines which union field is active, as well as | ||
| 1181 | /// how to interpret the data within. | ||
| 1182 | pub const Data = union { | ||
| 1183 | /// Used for unary operators, with an AST node source location. | ||
| 1184 | un_node: struct { | ||
| 1185 | /// Offset from Decl AST node index. | ||
| 1186 | src_node: i32, | ||
| 1187 | /// The meaning of this operand depends on the corresponding `Tag`. | ||
| 1188 | operand: Ref, | ||
| 1189 | |||
| 1190 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1191 | return .{ .node_offset = self.src_node }; | ||
| 1192 | } | ||
| 1193 | }, | ||
| 1194 | /// Used for unary operators, with a token source location. | ||
| 1195 | un_tok: struct { | ||
| 1196 | /// Offset from Decl AST token index. | ||
| 1197 | src_tok: ast.TokenIndex, | ||
| 1198 | /// The meaning of this operand depends on the corresponding `Tag`. | ||
| 1199 | operand: Ref, | ||
| 1200 | |||
| 1201 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1202 | return .{ .token_offset = self.src_tok }; | ||
| 1203 | } | ||
| 1204 | }, | ||
| 1205 | pl_node: struct { | ||
| 1206 | /// Offset from Decl AST node index. | ||
| 1207 | /// `Tag` determines which kind of AST node this points to. | ||
| 1208 | src_node: i32, | ||
| 1209 | /// index into extra. | ||
| 1210 | /// `Tag` determines what lives there. | ||
| 1211 | payload_index: u32, | ||
| 1212 | |||
| 1213 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1214 | return .{ .node_offset = self.src_node }; | ||
| 1215 | } | ||
| 1216 | }, | ||
| 1217 | bin: Bin, | ||
| 1218 | /// For strings which may contain null bytes. | ||
| 1219 | str: struct { | ||
| 1220 | /// Offset into `string_bytes`. | ||
| 1221 | start: u32, | ||
| 1222 | /// Number of bytes in the string. | ||
| 1223 | len: u32, | ||
| 1224 | |||
| 1225 | pub fn get(self: @This(), code: Code) []const u8 { | ||
| 1226 | return code.string_bytes[self.start..][0..self.len]; | ||
| 1227 | } | ||
| 1228 | }, | ||
| 1229 | /// Strings 8 or fewer bytes which may not contain null bytes. | ||
| 1230 | small_str: struct { | ||
| 1231 | bytes: [8]u8, | ||
| 1232 | |||
| 1233 | pub fn get(self: @This()) []const u8 { | ||
| 1234 | const end = for (self.bytes) |byte, i| { | ||
| 1235 | if (byte == 0) break i; | ||
| 1236 | } else self.bytes.len; | ||
| 1237 | return self.bytes[0..end]; | ||
| 1238 | } | ||
| 1239 | }, | ||
| 1240 | str_tok: struct { | ||
| 1241 | /// Offset into `string_bytes`. Null-terminated. | ||
| 1242 | start: u32, | ||
| 1243 | /// Offset from Decl AST token index. | ||
| 1244 | src_tok: u32, | ||
| 1245 | |||
| 1246 | pub fn get(self: @This(), code: Code) [:0]const u8 { | ||
| 1247 | return code.nullTerminatedString(self.start); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1251 | return .{ .token_offset = self.src_tok }; | ||
| 1252 | } | ||
| 1253 | }, | ||
| 1254 | /// Offset from Decl AST token index. | ||
| 1255 | tok: ast.TokenIndex, | ||
| 1256 | /// Offset from Decl AST node index. | ||
| 1257 | node: i32, | ||
| 1258 | int: u64, | ||
| 1259 | float: struct { | ||
| 1260 | /// Offset from Decl AST node index. | ||
| 1261 | /// `Tag` determines which kind of AST node this points to. | ||
| 1262 | src_node: i32, | ||
| 1263 | number: f32, | ||
| 1264 | |||
| 1265 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1266 | return .{ .node_offset = self.src_node }; | ||
| 1267 | } | ||
| 1268 | }, | ||
| 1269 | array_type_sentinel: struct { | ||
| 1270 | len: Ref, | ||
| 1271 | /// index into extra, points to an `ArrayTypeSentinel` | ||
| 1272 | payload_index: u32, | ||
| 1273 | }, | ||
| 1274 | ptr_type_simple: struct { | ||
| 1275 | is_allowzero: bool, | ||
| 1276 | is_mutable: bool, | ||
| 1277 | is_volatile: bool, | ||
| 1278 | size: std.builtin.TypeInfo.Pointer.Size, | ||
| 1279 | elem_type: Ref, | ||
| 1280 | }, | ||
| 1281 | ptr_type: struct { | ||
| 1282 | flags: packed struct { | ||
| 1283 | is_allowzero: bool, | ||
| 1284 | is_mutable: bool, | ||
| 1285 | is_volatile: bool, | ||
| 1286 | has_sentinel: bool, | ||
| 1287 | has_align: bool, | ||
| 1288 | has_bit_range: bool, | ||
| 1289 | _: u2 = undefined, | ||
| 1290 | }, | ||
| 1291 | size: std.builtin.TypeInfo.Pointer.Size, | ||
| 1292 | /// Index into extra. See `PtrType`. | ||
| 1293 | payload_index: u32, | ||
| 1294 | }, | ||
| 1295 | int_type: struct { | ||
| 1296 | /// Offset from Decl AST node index. | ||
| 1297 | /// `Tag` determines which kind of AST node this points to. | ||
| 1298 | src_node: i32, | ||
| 1299 | signedness: std.builtin.Signedness, | ||
| 1300 | bit_count: u16, | ||
| 1301 | |||
| 1302 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1303 | return .{ .node_offset = self.src_node }; | ||
| 1304 | } | ||
| 1305 | }, | ||
| 1306 | bool_br: struct { | ||
| 1307 | lhs: Ref, | ||
| 1308 | /// Points to a `Block`. | ||
| 1309 | payload_index: u32, | ||
| 1310 | }, | ||
| 1311 | param_type: struct { | ||
| 1312 | callee: Ref, | ||
| 1313 | param_index: u32, | ||
| 1314 | }, | ||
| 1315 | @"unreachable": struct { | ||
| 1316 | /// Offset from Decl AST node index. | ||
| 1317 | /// `Tag` determines which kind of AST node this points to. | ||
| 1318 | src_node: i32, | ||
| 1319 | /// `false`: Not safety checked - the compiler will assume the | ||
| 1320 | /// correctness of this instruction. | ||
| 1321 | /// `true`: In safety-checked modes, this will generate a call | ||
| 1322 | /// to the panic function unless it can be proven unreachable by the compiler. | ||
| 1323 | safety: bool, | ||
| 1324 | |||
| 1325 | pub fn src(self: @This()) LazySrcLoc { | ||
| 1326 | return .{ .node_offset = self.src_node }; | ||
| 1327 | } | ||
| 1328 | }, | ||
| 1329 | @"break": struct { | ||
| 1330 | block_inst: Index, | ||
| 1331 | operand: Ref, | ||
| 1332 | }, | ||
| 1333 | switch_capture: struct { | ||
| 1334 | switch_inst: Index, | ||
| 1335 | prong_index: u32, | ||
| 1336 | }, | ||
| 1337 | |||
| 1338 | // Make sure we don't accidentally add a field to make this union | ||
| 1339 | // bigger than expected. Note that in Debug builds, Zig is allowed | ||
| 1340 | // to insert a secret field for safety checks. | ||
| 1341 | comptime { | ||
| 1342 | if (std.builtin.mode != .Debug) { | ||
| 1343 | assert(@sizeOf(Data) == 8); | ||
| 1344 | } | ||
| 1345 | } | ||
| 1346 | }; | ||
| 1347 | |||
| 1348 | /// Stored in extra. Trailing is: | ||
| 1349 | /// * output_name: u32 // index into string_bytes (null terminated) if output is present | ||
| 1350 | /// * arg: Ref // for every args_len. | ||
| 1351 | /// * constraint: u32 // index into string_bytes (null terminated) for every args_len. | ||
| 1352 | /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len. | ||
| 1353 | pub const Asm = struct { | ||
| 1354 | asm_source: Ref, | ||
| 1355 | return_type: Ref, | ||
| 1356 | /// May be omitted. | ||
| 1357 | output: Ref, | ||
| 1358 | args_len: u32, | ||
| 1359 | clobbers_len: u32, | ||
| 1360 | }; | ||
| 1361 | |||
| 1362 | /// This data is stored inside extra, with trailing parameter type indexes | ||
| 1363 | /// according to `param_types_len`. | ||
| 1364 | /// Each param type is a `Ref`. | ||
| 1365 | pub const FnTypeCc = struct { | ||
| 1366 | return_type: Ref, | ||
| 1367 | cc: Ref, | ||
| 1368 | param_types_len: u32, | ||
| 1369 | }; | ||
| 1370 | |||
| 1371 | /// This data is stored inside extra, with trailing parameter type indexes | ||
| 1372 | /// according to `param_types_len`. | ||
| 1373 | /// Each param type is a `Ref`. | ||
| 1374 | pub const FnType = struct { | ||
| 1375 | return_type: Ref, | ||
| 1376 | param_types_len: u32, | ||
| 1377 | }; | ||
| 1378 | |||
| 1379 | /// This data is stored inside extra, with trailing operands according to `operands_len`. | ||
| 1380 | /// Each operand is a `Ref`. | ||
| 1381 | pub const MultiOp = struct { | ||
| 1382 | operands_len: u32, | ||
| 1383 | }; | ||
| 1384 | |||
| 1385 | /// This data is stored inside extra, with trailing operands according to `body_len`. | ||
| 1386 | /// Each operand is an `Index`. | ||
| 1387 | pub const Block = struct { | ||
| 1388 | body_len: u32, | ||
| 1389 | }; | ||
| 1390 | |||
| 1391 | /// Stored inside extra, with trailing arguments according to `args_len`. | ||
| 1392 | /// Each argument is a `Ref`. | ||
| 1393 | pub const Call = struct { | ||
| 1394 | callee: Ref, | ||
| 1395 | args_len: u32, | ||
| 1396 | }; | ||
| 1397 | |||
| 1398 | /// This data is stored inside extra, with two sets of trailing `Ref`: | ||
| 1399 | /// * 0. the then body, according to `then_body_len`. | ||
| 1400 | /// * 1. the else body, according to `else_body_len`. | ||
| 1401 | pub const CondBr = struct { | ||
| 1402 | condition: Ref, | ||
| 1403 | then_body_len: u32, | ||
| 1404 | else_body_len: u32, | ||
| 1405 | }; | ||
| 1406 | |||
| 1407 | /// Stored in extra. Depending on the flags in Data, there will be up to 4 | ||
| 1408 | /// trailing Ref fields: | ||
| 1409 | /// 0. sentinel: Ref // if `has_sentinel` flag is set | ||
| 1410 | /// 1. align: Ref // if `has_align` flag is set | ||
| 1411 | /// 2. bit_start: Ref // if `has_bit_range` flag is set | ||
| 1412 | /// 3. bit_end: Ref // if `has_bit_range` flag is set | ||
| 1413 | pub const PtrType = struct { | ||
| 1414 | elem_type: Ref, | ||
| 1415 | }; | ||
| 1416 | |||
| 1417 | pub const ArrayTypeSentinel = struct { | ||
| 1418 | sentinel: Ref, | ||
| 1419 | elem_type: Ref, | ||
| 1420 | }; | ||
| 1421 | |||
| 1422 | pub const SliceStart = struct { | ||
| 1423 | lhs: Ref, | ||
| 1424 | start: Ref, | ||
| 1425 | }; | ||
| 1426 | |||
| 1427 | pub const SliceEnd = struct { | ||
| 1428 | lhs: Ref, | ||
| 1429 | start: Ref, | ||
| 1430 | end: Ref, | ||
| 1431 | }; | ||
| 1432 | |||
| 1433 | pub const SliceSentinel = struct { | ||
| 1434 | lhs: Ref, | ||
| 1435 | start: Ref, | ||
| 1436 | end: Ref, | ||
| 1437 | sentinel: Ref, | ||
| 1438 | }; | ||
| 1439 | |||
| 1440 | /// The meaning of these operands depends on the corresponding `Tag`. | ||
| 1441 | pub const Bin = struct { | ||
| 1442 | lhs: Ref, | ||
| 1443 | rhs: Ref, | ||
| 1444 | }; | ||
| 1445 | |||
| 1446 | /// This form is supported when there are no ranges, and exactly 1 item per block. | ||
| 1447 | /// Depending on zir tag and len fields, extra fields trail | ||
| 1448 | /// this one in the extra array. | ||
| 1449 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 1450 | /// body_len: u32, | ||
| 1451 | /// body member Index for every body_len | ||
| 1452 | /// } | ||
| 1453 | /// 1. cases: { | ||
| 1454 | /// item: Ref, | ||
| 1455 | /// body_len: u32, | ||
| 1456 | /// body member Index for every body_len | ||
| 1457 | /// } for every cases_len | ||
| 1458 | pub const SwitchBlock = struct { | ||
| 1459 | operand: Ref, | ||
| 1460 | cases_len: u32, | ||
| 1461 | }; | ||
| 1462 | |||
| 1463 | /// This form is required when there exists a block which has more than one item, | ||
| 1464 | /// or a range. | ||
| 1465 | /// Depending on zir tag and len fields, extra fields trail | ||
| 1466 | /// this one in the extra array. | ||
| 1467 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 1468 | /// body_len: u32, | ||
| 1469 | /// body member Index for every body_len | ||
| 1470 | /// } | ||
| 1471 | /// 1. scalar_cases: { // for every scalar_cases_len | ||
| 1472 | /// item: Ref, | ||
| 1473 | /// body_len: u32, | ||
| 1474 | /// body member Index for every body_len | ||
| 1475 | /// } | ||
| 1476 | /// 2. multi_cases: { // for every multi_cases_len | ||
| 1477 | /// items_len: u32, | ||
| 1478 | /// ranges_len: u32, | ||
| 1479 | /// body_len: u32, | ||
| 1480 | /// item: Ref // for every items_len | ||
| 1481 | /// ranges: { // for every ranges_len | ||
| 1482 | /// item_first: Ref, | ||
| 1483 | /// item_last: Ref, | ||
| 1484 | /// } | ||
| 1485 | /// body member Index for every body_len | ||
| 1486 | /// } | ||
| 1487 | pub const SwitchBlockMulti = struct { | ||
| 1488 | operand: Ref, | ||
| 1489 | scalar_cases_len: u32, | ||
| 1490 | multi_cases_len: u32, | ||
| 1491 | }; | ||
| 1492 | |||
| 1493 | pub const Field = struct { | ||
| 1494 | lhs: Ref, | ||
| 1495 | /// Offset into `string_bytes`. | ||
| 1496 | field_name_start: u32, | ||
| 1497 | }; | ||
| 1498 | |||
| 1499 | pub const FieldNamed = struct { | ||
| 1500 | lhs: Ref, | ||
| 1501 | field_name: Ref, | ||
| 1502 | }; | ||
| 1503 | |||
| 1504 | pub const As = struct { | ||
| 1505 | dest_type: Ref, | ||
| 1506 | operand: Ref, | ||
| 1507 | }; | ||
| 1508 | |||
| 1509 | /// Trailing: | ||
| 1510 | /// 0. has_bits: u32 // for every 16 fields | ||
| 1511 | /// - sets of 2 bits: | ||
| 1512 | /// 0b0X: whether corresponding field has an align expression | ||
| 1513 | /// 0bX0: whether corresponding field has a default expression | ||
| 1514 | /// 1. fields: { // for every fields_len | ||
| 1515 | /// field_name: u32, | ||
| 1516 | /// field_type: Ref, | ||
| 1517 | /// align: Ref, // if corresponding bit is set | ||
| 1518 | /// default_value: Ref, // if corresponding bit is set | ||
| 1519 | /// } | ||
| 1520 | pub const StructDecl = struct { | ||
| 1521 | fields_len: u32, | ||
| 1522 | }; | ||
| 1523 | |||
| 1524 | /// Trailing: | ||
| 1525 | /// 0. has_bits: u32 // for every 32 fields | ||
| 1526 | /// - the bit is whether corresponding field has an value expression | ||
| 1527 | /// 1. field_name: u32 // for every field: null terminated string index | ||
| 1528 | /// 2. value: Ref // for every field for which corresponding bit is set | ||
| 1529 | pub const EnumDecl = struct { | ||
| 1530 | /// Can be `Ref.none`. | ||
| 1531 | tag_type: Ref, | ||
| 1532 | fields_len: u32, | ||
| 1533 | }; | ||
| 1534 | |||
| 1535 | /// Trailing: | ||
| 1536 | /// 0. has_bits: u32 // for every 10 fields (+1) | ||
| 1537 | /// - first bit is special: set if and only if auto enum tag is enabled. | ||
| 1538 | /// - sets of 3 bits: | ||
| 1539 | /// 0b00X: whether corresponding field has a type expression | ||
| 1540 | /// 0b0X0: whether corresponding field has a align expression | ||
| 1541 | /// 0bX00: whether corresponding field has a tag value expression | ||
| 1542 | /// 1. field_name: u32 // for every field: null terminated string index | ||
| 1543 | /// 2. opt_exprs // Ref for every field for which corresponding bit is set | ||
| 1544 | /// - interleaved. type if present, align if present, tag value if present. | ||
| 1545 | pub const UnionDecl = struct { | ||
| 1546 | /// Can be `Ref.none`. | ||
| 1547 | tag_type: Ref, | ||
| 1548 | fields_len: u32, | ||
| 1549 | }; | ||
| 1550 | |||
| 1551 | /// A f128 value, broken up into 4 u32 parts. | ||
| 1552 | pub const Float128 = struct { | ||
| 1553 | piece0: u32, | ||
| 1554 | piece1: u32, | ||
| 1555 | piece2: u32, | ||
| 1556 | piece3: u32, | ||
| 1557 | |||
| 1558 | pub fn get(self: Float128) f128 { | ||
| 1559 | const int_bits = @as(u128, self.piece0) | | ||
| 1560 | (@as(u128, self.piece1) << 32) | | ||
| 1561 | (@as(u128, self.piece2) << 64) | | ||
| 1562 | (@as(u128, self.piece3) << 96); | ||
| 1563 | return @bitCast(f128, int_bits); | ||
| 1564 | } | ||
| 1565 | }; | ||
| 1566 | |||
| 1567 | /// Trailing is an item per field. | ||
| 1568 | pub const StructInit = struct { | ||
| 1569 | fields_len: u32, | ||
| 1570 | |||
| 1571 | pub const Item = struct { | ||
| 1572 | /// The `field_type` ZIR instruction for this field init. | ||
| 1573 | field_type: Index, | ||
| 1574 | /// The field init expression to be used as the field value. | ||
| 1575 | init: Ref, | ||
| 1576 | }; | ||
| 1577 | }; | ||
| 1578 | |||
| 1579 | pub const FieldType = struct { | ||
| 1580 | container_type: Ref, | ||
| 1581 | /// Offset into `string_bytes`, null terminated. | ||
| 1582 | name_start: u32, | ||
| 1583 | }; | ||
| 1584 | }; | ||
| 1585 | |||
| 1586 | pub const SpecialProng = enum { none, @"else", under }; | ||
| 1587 | |||
| 1588 | const Writer = struct { | ||
| 1589 | gpa: *Allocator, | ||
| 1590 | arena: *Allocator, | ||
| 1591 | scope: *Module.Scope, | ||
| 1592 | code: Code, | ||
| 1593 | indent: usize, | ||
| 1594 | param_count: usize, | ||
| 1595 | |||
| 1596 | fn writeInstToStream( | ||
| 1597 | self: *Writer, | ||
| 1598 | stream: anytype, | ||
| 1599 | inst: Inst.Index, | ||
| 1600 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1601 | const tags = self.code.instructions.items(.tag); | ||
| 1602 | const tag = tags[inst]; | ||
| 1603 | try stream.print("= {s}(", .{@tagName(tags[inst])}); | ||
| 1604 | switch (tag) { | ||
| 1605 | .array_type, | ||
| 1606 | .as, | ||
| 1607 | .coerce_result_ptr, | ||
| 1608 | .elem_ptr, | ||
| 1609 | .elem_val, | ||
| 1610 | .intcast, | ||
| 1611 | .store, | ||
| 1612 | .store_to_block_ptr, | ||
| 1613 | .store_to_inferred_ptr, | ||
| 1614 | => try self.writeBin(stream, inst), | ||
| 1615 | |||
| 1616 | .alloc, | ||
| 1617 | .alloc_mut, | ||
| 1618 | .indexable_ptr_len, | ||
| 1619 | .bit_not, | ||
| 1620 | .bool_not, | ||
| 1621 | .negate, | ||
| 1622 | .negate_wrap, | ||
| 1623 | .call_none, | ||
| 1624 | .call_none_chkused, | ||
| 1625 | .compile_error, | ||
| 1626 | .load, | ||
| 1627 | .ensure_result_used, | ||
| 1628 | .ensure_result_non_error, | ||
| 1629 | .import, | ||
| 1630 | .ptrtoint, | ||
| 1631 | .ret_node, | ||
| 1632 | .set_eval_branch_quota, | ||
| 1633 | .resolve_inferred_alloc, | ||
| 1634 | .optional_type, | ||
| 1635 | .optional_type_from_ptr_elem, | ||
| 1636 | .optional_payload_safe, | ||
| 1637 | .optional_payload_unsafe, | ||
| 1638 | .optional_payload_safe_ptr, | ||
| 1639 | .optional_payload_unsafe_ptr, | ||
| 1640 | .err_union_payload_safe, | ||
| 1641 | .err_union_payload_unsafe, | ||
| 1642 | .err_union_payload_safe_ptr, | ||
| 1643 | .err_union_payload_unsafe_ptr, | ||
| 1644 | .err_union_code, | ||
| 1645 | .err_union_code_ptr, | ||
| 1646 | .int_to_error, | ||
| 1647 | .error_to_int, | ||
| 1648 | .is_non_null, | ||
| 1649 | .is_null, | ||
| 1650 | .is_non_null_ptr, | ||
| 1651 | .is_null_ptr, | ||
| 1652 | .is_err, | ||
| 1653 | .is_err_ptr, | ||
| 1654 | .typeof, | ||
| 1655 | .typeof_elem, | ||
| 1656 | .struct_init_empty, | ||
| 1657 | .enum_to_int, | ||
| 1658 | .type_info, | ||
| 1659 | => try self.writeUnNode(stream, inst), | ||
| 1660 | |||
| 1661 | .ref, | ||
| 1662 | .ret_tok, | ||
| 1663 | .ret_coerce, | ||
| 1664 | .ensure_err_payload_void, | ||
| 1665 | => try self.writeUnTok(stream, inst), | ||
| 1666 | |||
| 1667 | .bool_br_and, | ||
| 1668 | .bool_br_or, | ||
| 1669 | => try self.writeBoolBr(stream, inst), | ||
| 1670 | |||
| 1671 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), | ||
| 1672 | .param_type => try self.writeParamType(stream, inst), | ||
| 1673 | .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), | ||
| 1674 | .ptr_type => try self.writePtrType(stream, inst), | ||
| 1675 | .int => try self.writeInt(stream, inst), | ||
| 1676 | .float => try self.writeFloat(stream, inst), | ||
| 1677 | .float128 => try self.writeFloat128(stream, inst), | ||
| 1678 | .str => try self.writeStr(stream, inst), | ||
| 1679 | .elided => try stream.writeAll(")"), | ||
| 1680 | .int_type => try self.writeIntType(stream, inst), | ||
| 1681 | |||
| 1682 | .@"break", | ||
| 1683 | .break_inline, | ||
| 1684 | => try self.writeBreak(stream, inst), | ||
| 1685 | |||
| 1686 | .@"asm", | ||
| 1687 | .asm_volatile, | ||
| 1688 | .elem_ptr_node, | ||
| 1689 | .elem_val_node, | ||
| 1690 | .field_ptr_named, | ||
| 1691 | .field_val_named, | ||
| 1692 | .floatcast, | ||
| 1693 | .slice_start, | ||
| 1694 | .slice_end, | ||
| 1695 | .slice_sentinel, | ||
| 1696 | .union_decl, | ||
| 1697 | .enum_decl, | ||
| 1698 | .enum_decl_nonexhaustive, | ||
| 1699 | .struct_init, | ||
| 1700 | .field_type, | ||
| 1701 | => try self.writePlNode(stream, inst), | ||
| 1702 | |||
| 1703 | .add, | ||
| 1704 | .addwrap, | ||
| 1705 | .array_cat, | ||
| 1706 | .array_mul, | ||
| 1707 | .mul, | ||
| 1708 | .mulwrap, | ||
| 1709 | .sub, | ||
| 1710 | .subwrap, | ||
| 1711 | .bool_and, | ||
| 1712 | .bool_or, | ||
| 1713 | .cmp_lt, | ||
| 1714 | .cmp_lte, | ||
| 1715 | .cmp_eq, | ||
| 1716 | .cmp_gte, | ||
| 1717 | .cmp_gt, | ||
| 1718 | .cmp_neq, | ||
| 1719 | .div, | ||
| 1720 | .has_decl, | ||
| 1721 | .mod_rem, | ||
| 1722 | .shl, | ||
| 1723 | .shr, | ||
| 1724 | .xor, | ||
| 1725 | .store_node, | ||
| 1726 | .error_union_type, | ||
| 1727 | .@"export", | ||
| 1728 | .merge_error_sets, | ||
| 1729 | .bit_and, | ||
| 1730 | .bit_or, | ||
| 1731 | .int_to_enum, | ||
| 1732 | => try self.writePlNodeBin(stream, inst), | ||
| 1733 | |||
| 1734 | .call, | ||
| 1735 | .call_chkused, | ||
| 1736 | .call_compile_time, | ||
| 1737 | => try self.writePlNodeCall(stream, inst), | ||
| 1738 | |||
| 1739 | .block, | ||
| 1740 | .block_inline, | ||
| 1741 | .loop, | ||
| 1742 | .validate_struct_init_ptr, | ||
| 1743 | => try self.writePlNodeBlock(stream, inst), | ||
| 1744 | |||
| 1745 | .condbr, | ||
| 1746 | .condbr_inline, | ||
| 1747 | => try self.writePlNodeCondBr(stream, inst), | ||
| 1748 | |||
| 1749 | .struct_decl, | ||
| 1750 | .struct_decl_packed, | ||
| 1751 | .struct_decl_extern, | ||
| 1752 | => try self.writeStructDecl(stream, inst), | ||
| 1753 | |||
| 1754 | .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), | ||
| 1755 | .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 1756 | .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 1757 | .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none), | ||
| 1758 | .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 1759 | .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 1760 | |||
| 1761 | .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 1762 | .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 1763 | .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 1764 | .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 1765 | .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 1766 | .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 1767 | |||
| 1768 | .compile_log, | ||
| 1769 | .typeof_peer, | ||
| 1770 | => try self.writePlNodeMultiOp(stream, inst), | ||
| 1771 | |||
| 1772 | .decl_ref, | ||
| 1773 | .decl_val, | ||
| 1774 | => try self.writePlNodeDecl(stream, inst), | ||
| 1775 | |||
| 1776 | .field_ptr, | ||
| 1777 | .field_val, | ||
| 1778 | => try self.writePlNodeField(stream, inst), | ||
| 1779 | |||
| 1780 | .as_node => try self.writeAs(stream, inst), | ||
| 1781 | |||
| 1782 | .breakpoint, | ||
| 1783 | .opaque_decl, | ||
| 1784 | .dbg_stmt_node, | ||
| 1785 | .ret_ptr, | ||
| 1786 | .ret_type, | ||
| 1787 | .repeat, | ||
| 1788 | .repeat_inline, | ||
| 1789 | .alloc_inferred, | ||
| 1790 | .alloc_inferred_mut, | ||
| 1791 | => try self.writeNode(stream, inst), | ||
| 1792 | |||
| 1793 | .error_value, | ||
| 1794 | .enum_literal, | ||
| 1795 | => try self.writeStrTok(stream, inst), | ||
| 1796 | |||
| 1797 | .fn_type => try self.writeFnType(stream, inst, false), | ||
| 1798 | .fn_type_cc => try self.writeFnTypeCc(stream, inst, false), | ||
| 1799 | .fn_type_var_args => try self.writeFnType(stream, inst, true), | ||
| 1800 | .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true), | ||
| 1801 | |||
| 1802 | .@"unreachable" => try self.writeUnreachable(stream, inst), | ||
| 1803 | |||
| 1804 | .enum_literal_small => try self.writeSmallStr(stream, inst), | ||
| 1805 | |||
| 1806 | .switch_capture, | ||
| 1807 | .switch_capture_ref, | ||
| 1808 | .switch_capture_multi, | ||
| 1809 | .switch_capture_multi_ref, | ||
| 1810 | .switch_capture_else, | ||
| 1811 | .switch_capture_else_ref, | ||
| 1812 | => try self.writeSwitchCapture(stream, inst), | ||
| 1813 | |||
| 1814 | .bitcast, | ||
| 1815 | .bitcast_result_ptr, | ||
| 1816 | => try stream.writeAll("TODO)"), | ||
| 1817 | } | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1821 | const inst_data = self.code.instructions.items(.data)[inst].bin; | ||
| 1822 | try self.writeInstRef(stream, inst_data.lhs); | ||
| 1823 | try stream.writeAll(", "); | ||
| 1824 | try self.writeInstRef(stream, inst_data.rhs); | ||
| 1825 | try stream.writeByte(')'); | ||
| 1826 | } | ||
| 1827 | |||
| 1828 | fn writeUnNode( | ||
| 1829 | self: *Writer, | ||
| 1830 | stream: anytype, | ||
| 1831 | inst: Inst.Index, | ||
| 1832 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1833 | const inst_data = self.code.instructions.items(.data)[inst].un_node; | ||
| 1834 | try self.writeInstRef(stream, inst_data.operand); | ||
| 1835 | try stream.writeAll(") "); | ||
| 1836 | try self.writeSrc(stream, inst_data.src()); | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | fn writeUnTok( | ||
| 1840 | self: *Writer, | ||
| 1841 | stream: anytype, | ||
| 1842 | inst: Inst.Index, | ||
| 1843 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1844 | const inst_data = self.code.instructions.items(.data)[inst].un_tok; | ||
| 1845 | try self.writeInstRef(stream, inst_data.operand); | ||
| 1846 | try stream.writeAll(") "); | ||
| 1847 | try self.writeSrc(stream, inst_data.src()); | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | fn writeArrayTypeSentinel( | ||
| 1851 | self: *Writer, | ||
| 1852 | stream: anytype, | ||
| 1853 | inst: Inst.Index, | ||
| 1854 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1855 | const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel; | ||
| 1856 | try stream.writeAll("TODO)"); | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | fn writeParamType( | ||
| 1860 | self: *Writer, | ||
| 1861 | stream: anytype, | ||
| 1862 | inst: Inst.Index, | ||
| 1863 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1864 | const inst_data = self.code.instructions.items(.data)[inst].param_type; | ||
| 1865 | try self.writeInstRef(stream, inst_data.callee); | ||
| 1866 | try stream.print(", {d})", .{inst_data.param_index}); | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | fn writePtrTypeSimple( | ||
| 1870 | self: *Writer, | ||
| 1871 | stream: anytype, | ||
| 1872 | inst: Inst.Index, | ||
| 1873 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1874 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple; | ||
| 1875 | try stream.writeAll("TODO)"); | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | fn writePtrType( | ||
| 1879 | self: *Writer, | ||
| 1880 | stream: anytype, | ||
| 1881 | inst: Inst.Index, | ||
| 1882 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1883 | const inst_data = self.code.instructions.items(.data)[inst].ptr_type; | ||
| 1884 | try stream.writeAll("TODO)"); | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | fn writeInt( | ||
| 1888 | self: *Writer, | ||
| 1889 | stream: anytype, | ||
| 1890 | inst: Inst.Index, | ||
| 1891 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1892 | const inst_data = self.code.instructions.items(.data)[inst].int; | ||
| 1893 | try stream.print("{d})", .{inst_data}); | ||
| 1894 | } | ||
| 1895 | |||
| 1896 | fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1897 | const inst_data = self.code.instructions.items(.data)[inst].float; | ||
| 1898 | const src = inst_data.src(); | ||
| 1899 | try stream.print("{d}) ", .{inst_data.number}); | ||
| 1900 | try self.writeSrc(stream, src); | ||
| 1901 | } | ||
| 1902 | |||
| 1903 | fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1904 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1905 | const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data; | ||
| 1906 | const src = inst_data.src(); | ||
| 1907 | const number = extra.get(); | ||
| 1908 | // TODO improve std.format to be able to print f128 values | ||
| 1909 | try stream.print("{d}) ", .{@floatCast(f64, number)}); | ||
| 1910 | try self.writeSrc(stream, src); | ||
| 1911 | } | ||
| 1912 | |||
| 1913 | fn writeStr( | ||
| 1914 | self: *Writer, | ||
| 1915 | stream: anytype, | ||
| 1916 | inst: Inst.Index, | ||
| 1917 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1918 | const inst_data = self.code.instructions.items(.data)[inst].str; | ||
| 1919 | const str = inst_data.get(self.code); | ||
| 1920 | try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | fn writePlNode( | ||
| 1924 | self: *Writer, | ||
| 1925 | stream: anytype, | ||
| 1926 | inst: Inst.Index, | ||
| 1927 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 1928 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1929 | try stream.writeAll("TODO) "); | ||
| 1930 | try self.writeSrc(stream, inst_data.src()); | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1934 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1935 | const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data; | ||
| 1936 | try self.writeInstRef(stream, extra.lhs); | ||
| 1937 | try stream.writeAll(", "); | ||
| 1938 | try self.writeInstRef(stream, extra.rhs); | ||
| 1939 | try stream.writeAll(") "); | ||
| 1940 | try self.writeSrc(stream, inst_data.src()); | ||
| 1941 | } | ||
| 1942 | |||
| 1943 | fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1944 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1945 | const extra = self.code.extraData(Inst.Call, inst_data.payload_index); | ||
| 1946 | const args = self.code.refSlice(extra.end, extra.data.args_len); | ||
| 1947 | |||
| 1948 | try self.writeInstRef(stream, extra.data.callee); | ||
| 1949 | try stream.writeAll(", ["); | ||
| 1950 | for (args) |arg, i| { | ||
| 1951 | if (i != 0) try stream.writeAll(", "); | ||
| 1952 | try self.writeInstRef(stream, arg); | ||
| 1953 | } | ||
| 1954 | try stream.writeAll("]) "); | ||
| 1955 | try self.writeSrc(stream, inst_data.src()); | ||
| 1956 | } | ||
| 1957 | |||
| 1958 | fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1959 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1960 | const extra = self.code.extraData(Inst.Block, inst_data.payload_index); | ||
| 1961 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 1962 | try stream.writeAll("{\n"); | ||
| 1963 | self.indent += 2; | ||
| 1964 | try self.writeBody(stream, body); | ||
| 1965 | self.indent -= 2; | ||
| 1966 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1967 | try stream.writeAll("}) "); | ||
| 1968 | try self.writeSrc(stream, inst_data.src()); | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1972 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1973 | const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index); | ||
| 1974 | const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len]; | ||
| 1975 | const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | ||
| 1976 | try self.writeInstRef(stream, extra.data.condition); | ||
| 1977 | try stream.writeAll(", {\n"); | ||
| 1978 | self.indent += 2; | ||
| 1979 | try self.writeBody(stream, then_body); | ||
| 1980 | self.indent -= 2; | ||
| 1981 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1982 | try stream.writeAll("}, {\n"); | ||
| 1983 | self.indent += 2; | ||
| 1984 | try self.writeBody(stream, else_body); | ||
| 1985 | self.indent -= 2; | ||
| 1986 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1987 | try stream.writeAll("}) "); | ||
| 1988 | try self.writeSrc(stream, inst_data.src()); | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | fn writeStructDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 1992 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1993 | const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index); | ||
| 1994 | const fields_len = extra.data.fields_len; | ||
| 1995 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; | ||
| 1996 | |||
| 1997 | try stream.writeAll("{\n"); | ||
| 1998 | self.indent += 2; | ||
| 1999 | |||
| 2000 | var field_index: usize = extra.end + bit_bags_count; | ||
| 2001 | var bit_bag_index: usize = extra.end; | ||
| 2002 | var cur_bit_bag: u32 = undefined; | ||
| 2003 | var field_i: u32 = 0; | ||
| 2004 | while (field_i < fields_len) : (field_i += 1) { | ||
| 2005 | if (field_i % 16 == 0) { | ||
| 2006 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 2007 | bit_bag_index += 1; | ||
| 2008 | } | ||
| 2009 | const has_align = @truncate(u1, cur_bit_bag) != 0; | ||
| 2010 | cur_bit_bag >>= 1; | ||
| 2011 | const has_default = @truncate(u1, cur_bit_bag) != 0; | ||
| 2012 | cur_bit_bag >>= 1; | ||
| 2013 | |||
| 2014 | const field_name = self.code.nullTerminatedString(self.code.extra[field_index]); | ||
| 2015 | field_index += 1; | ||
| 2016 | const field_type = @intToEnum(Inst.Ref, self.code.extra[field_index]); | ||
| 2017 | field_index += 1; | ||
| 2018 | |||
| 2019 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2020 | try stream.print("{}: ", .{std.zig.fmtId(field_name)}); | ||
| 2021 | try self.writeInstRef(stream, field_type); | ||
| 2022 | |||
| 2023 | if (has_align) { | ||
| 2024 | const align_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]); | ||
| 2025 | field_index += 1; | ||
| 2026 | |||
| 2027 | try stream.writeAll(" align("); | ||
| 2028 | try self.writeInstRef(stream, align_ref); | ||
| 2029 | try stream.writeAll(")"); | ||
| 2030 | } | ||
| 2031 | if (has_default) { | ||
| 2032 | const default_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]); | ||
| 2033 | field_index += 1; | ||
| 2034 | |||
| 2035 | try stream.writeAll(" = "); | ||
| 2036 | try self.writeInstRef(stream, default_ref); | ||
| 2037 | } | ||
| 2038 | try stream.writeAll(",\n"); | ||
| 2039 | } | ||
| 2040 | |||
| 2041 | self.indent -= 2; | ||
| 2042 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2043 | try stream.writeAll("}) "); | ||
| 2044 | try self.writeSrc(stream, inst_data.src()); | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | fn writePlNodeSwitchBr( | ||
| 2048 | self: *Writer, | ||
| 2049 | stream: anytype, | ||
| 2050 | inst: Inst.Index, | ||
| 2051 | special_prong: SpecialProng, | ||
| 2052 | ) !void { | ||
| 2053 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2054 | const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index); | ||
| 2055 | const special: struct { | ||
| 2056 | body: []const Inst.Index, | ||
| 2057 | end: usize, | ||
| 2058 | } = switch (special_prong) { | ||
| 2059 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 2060 | .under, .@"else" => blk: { | ||
| 2061 | const body_len = self.code.extra[extra.end]; | ||
| 2062 | const extra_body_start = extra.end + 1; | ||
| 2063 | break :blk .{ | ||
| 2064 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 2065 | .end = extra_body_start + body_len, | ||
| 2066 | }; | ||
| 2067 | }, | ||
| 2068 | }; | ||
| 2069 | |||
| 2070 | try self.writeInstRef(stream, extra.data.operand); | ||
| 2071 | |||
| 2072 | if (special.body.len != 0) { | ||
| 2073 | const prong_name = switch (special_prong) { | ||
| 2074 | .@"else" => "else", | ||
| 2075 | .under => "_", | ||
| 2076 | else => unreachable, | ||
| 2077 | }; | ||
| 2078 | try stream.print(", {s} => {{\n", .{prong_name}); | ||
| 2079 | self.indent += 2; | ||
| 2080 | try self.writeBody(stream, special.body); | ||
| 2081 | self.indent -= 2; | ||
| 2082 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2083 | try stream.writeAll("}"); | ||
| 2084 | } | ||
| 2085 | |||
| 2086 | var extra_index: usize = special.end; | ||
| 2087 | { | ||
| 2088 | var scalar_i: usize = 0; | ||
| 2089 | while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { | ||
| 2090 | const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 2091 | extra_index += 1; | ||
| 2092 | const body_len = self.code.extra[extra_index]; | ||
| 2093 | extra_index += 1; | ||
| 2094 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 2095 | extra_index += body_len; | ||
| 2096 | |||
| 2097 | try stream.writeAll(", "); | ||
| 2098 | try self.writeInstRef(stream, item_ref); | ||
| 2099 | try stream.writeAll(" => {\n"); | ||
| 2100 | self.indent += 2; | ||
| 2101 | try self.writeBody(stream, body); | ||
| 2102 | self.indent -= 2; | ||
| 2103 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2104 | try stream.writeAll("}"); | ||
| 2105 | } | ||
| 2106 | } | ||
| 2107 | try stream.writeAll(") "); | ||
| 2108 | try self.writeSrc(stream, inst_data.src()); | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | fn writePlNodeSwitchBlockMulti( | ||
| 2112 | self: *Writer, | ||
| 2113 | stream: anytype, | ||
| 2114 | inst: Inst.Index, | ||
| 2115 | special_prong: SpecialProng, | ||
| 2116 | ) !void { | ||
| 2117 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2118 | const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index); | ||
| 2119 | const special: struct { | ||
| 2120 | body: []const Inst.Index, | ||
| 2121 | end: usize, | ||
| 2122 | } = switch (special_prong) { | ||
| 2123 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 2124 | .under, .@"else" => blk: { | ||
| 2125 | const body_len = self.code.extra[extra.end]; | ||
| 2126 | const extra_body_start = extra.end + 1; | ||
| 2127 | break :blk .{ | ||
| 2128 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 2129 | .end = extra_body_start + body_len, | ||
| 2130 | }; | ||
| 2131 | }, | ||
| 2132 | }; | ||
| 2133 | |||
| 2134 | try self.writeInstRef(stream, extra.data.operand); | ||
| 2135 | |||
| 2136 | if (special.body.len != 0) { | ||
| 2137 | const prong_name = switch (special_prong) { | ||
| 2138 | .@"else" => "else", | ||
| 2139 | .under => "_", | ||
| 2140 | else => unreachable, | ||
| 2141 | }; | ||
| 2142 | try stream.print(", {s} => {{\n", .{prong_name}); | ||
| 2143 | self.indent += 2; | ||
| 2144 | try self.writeBody(stream, special.body); | ||
| 2145 | self.indent -= 2; | ||
| 2146 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2147 | try stream.writeAll("}"); | ||
| 2148 | } | ||
| 2149 | |||
| 2150 | var extra_index: usize = special.end; | ||
| 2151 | { | ||
| 2152 | var scalar_i: usize = 0; | ||
| 2153 | while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { | ||
| 2154 | const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 2155 | extra_index += 1; | ||
| 2156 | const body_len = self.code.extra[extra_index]; | ||
| 2157 | extra_index += 1; | ||
| 2158 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 2159 | extra_index += body_len; | ||
| 2160 | |||
| 2161 | try stream.writeAll(", "); | ||
| 2162 | try self.writeInstRef(stream, item_ref); | ||
| 2163 | try stream.writeAll(" => {\n"); | ||
| 2164 | self.indent += 2; | ||
| 2165 | try self.writeBody(stream, body); | ||
| 2166 | self.indent -= 2; | ||
| 2167 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2168 | try stream.writeAll("}"); | ||
| 2169 | } | ||
| 2170 | } | ||
| 2171 | { | ||
| 2172 | var multi_i: usize = 0; | ||
| 2173 | while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { | ||
| 2174 | const items_len = self.code.extra[extra_index]; | ||
| 2175 | extra_index += 1; | ||
| 2176 | const ranges_len = self.code.extra[extra_index]; | ||
| 2177 | extra_index += 1; | ||
| 2178 | const body_len = self.code.extra[extra_index]; | ||
| 2179 | extra_index += 1; | ||
| 2180 | const items = self.code.refSlice(extra_index, items_len); | ||
| 2181 | extra_index += items_len; | ||
| 2182 | |||
| 2183 | for (items) |item_ref| { | ||
| 2184 | try stream.writeAll(", "); | ||
| 2185 | try self.writeInstRef(stream, item_ref); | ||
| 2186 | } | ||
| 2187 | |||
| 2188 | var range_i: usize = 0; | ||
| 2189 | while (range_i < ranges_len) : (range_i += 1) { | ||
| 2190 | const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 2191 | extra_index += 1; | ||
| 2192 | const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 2193 | extra_index += 1; | ||
| 2194 | |||
| 2195 | try stream.writeAll(", "); | ||
| 2196 | try self.writeInstRef(stream, item_first); | ||
| 2197 | try stream.writeAll("..."); | ||
| 2198 | try self.writeInstRef(stream, item_last); | ||
| 2199 | } | ||
| 2200 | |||
| 2201 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 2202 | extra_index += body_len; | ||
| 2203 | try stream.writeAll(" => {\n"); | ||
| 2204 | self.indent += 2; | ||
| 2205 | try self.writeBody(stream, body); | ||
| 2206 | self.indent -= 2; | ||
| 2207 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2208 | try stream.writeAll("}"); | ||
| 2209 | } | ||
| 2210 | } | ||
| 2211 | try stream.writeAll(") "); | ||
| 2212 | try self.writeSrc(stream, inst_data.src()); | ||
| 2213 | } | ||
| 2214 | |||
| 2215 | fn writePlNodeMultiOp(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2216 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2217 | const extra = self.code.extraData(Inst.MultiOp, inst_data.payload_index); | ||
| 2218 | const operands = self.code.refSlice(extra.end, extra.data.operands_len); | ||
| 2219 | |||
| 2220 | for (operands) |operand, i| { | ||
| 2221 | if (i != 0) try stream.writeAll(", "); | ||
| 2222 | try self.writeInstRef(stream, operand); | ||
| 2223 | } | ||
| 2224 | try stream.writeAll(") "); | ||
| 2225 | try self.writeSrc(stream, inst_data.src()); | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2229 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2230 | const owner_decl = self.scope.ownerDecl().?; | ||
| 2231 | const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key; | ||
| 2232 | try stream.print("{s}) ", .{decl.name}); | ||
| 2233 | try self.writeSrc(stream, inst_data.src()); | ||
| 2234 | } | ||
| 2235 | |||
| 2236 | fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2237 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2238 | const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data; | ||
| 2239 | const name = self.code.nullTerminatedString(extra.field_name_start); | ||
| 2240 | try self.writeInstRef(stream, extra.lhs); | ||
| 2241 | try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); | ||
| 2242 | try self.writeSrc(stream, inst_data.src()); | ||
| 2243 | } | ||
| 2244 | |||
| 2245 | fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2246 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2247 | const extra = self.code.extraData(Inst.As, inst_data.payload_index).data; | ||
| 2248 | try self.writeInstRef(stream, extra.dest_type); | ||
| 2249 | try stream.writeAll(", "); | ||
| 2250 | try self.writeInstRef(stream, extra.operand); | ||
| 2251 | try stream.writeAll(") "); | ||
| 2252 | try self.writeSrc(stream, inst_data.src()); | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | fn writeNode( | ||
| 2256 | self: *Writer, | ||
| 2257 | stream: anytype, | ||
| 2258 | inst: Inst.Index, | ||
| 2259 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 2260 | const src_node = self.code.instructions.items(.data)[inst].node; | ||
| 2261 | const src: LazySrcLoc = .{ .node_offset = src_node }; | ||
| 2262 | try stream.writeAll(") "); | ||
| 2263 | try self.writeSrc(stream, src); | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | fn writeStrTok( | ||
| 2267 | self: *Writer, | ||
| 2268 | stream: anytype, | ||
| 2269 | inst: Inst.Index, | ||
| 2270 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 2271 | const inst_data = self.code.instructions.items(.data)[inst].str_tok; | ||
| 2272 | const str = inst_data.get(self.code); | ||
| 2273 | try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); | ||
| 2274 | try self.writeSrc(stream, inst_data.src()); | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | fn writeFnType( | ||
| 2278 | self: *Writer, | ||
| 2279 | stream: anytype, | ||
| 2280 | inst: Inst.Index, | ||
| 2281 | var_args: bool, | ||
| 2282 | ) !void { | ||
| 2283 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2284 | const src = inst_data.src(); | ||
| 2285 | const extra = self.code.extraData(Inst.FnType, inst_data.payload_index); | ||
| 2286 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | ||
| 2287 | return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, .none, src); | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | fn writeFnTypeCc( | ||
| 2291 | self: *Writer, | ||
| 2292 | stream: anytype, | ||
| 2293 | inst: Inst.Index, | ||
| 2294 | var_args: bool, | ||
| 2295 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 2296 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2297 | const src = inst_data.src(); | ||
| 2298 | const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index); | ||
| 2299 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | ||
| 2300 | const cc = extra.data.cc; | ||
| 2301 | return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, cc, src); | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2305 | const inst_data = self.code.instructions.items(.data)[inst].bool_br; | ||
| 2306 | const extra = self.code.extraData(Inst.Block, inst_data.payload_index); | ||
| 2307 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 2308 | try self.writeInstRef(stream, inst_data.lhs); | ||
| 2309 | try stream.writeAll(", {\n"); | ||
| 2310 | self.indent += 2; | ||
| 2311 | try self.writeBody(stream, body); | ||
| 2312 | self.indent -= 2; | ||
| 2313 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2314 | try stream.writeAll("})"); | ||
| 2315 | } | ||
| 2316 | |||
| 2317 | fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2318 | const int_type = self.code.instructions.items(.data)[inst].int_type; | ||
| 2319 | const prefix: u8 = switch (int_type.signedness) { | ||
| 2320 | .signed => 'i', | ||
| 2321 | .unsigned => 'u', | ||
| 2322 | }; | ||
| 2323 | try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count }); | ||
| 2324 | try self.writeSrc(stream, int_type.src()); | ||
| 2325 | } | ||
| 2326 | |||
| 2327 | fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2328 | const inst_data = self.code.instructions.items(.data)[inst].@"break"; | ||
| 2329 | |||
| 2330 | try self.writeInstIndex(stream, inst_data.block_inst); | ||
| 2331 | try stream.writeAll(", "); | ||
| 2332 | try self.writeInstRef(stream, inst_data.operand); | ||
| 2333 | try stream.writeAll(")"); | ||
| 2334 | } | ||
| 2335 | |||
| 2336 | fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2337 | const inst_data = self.code.instructions.items(.data)[inst].@"unreachable"; | ||
| 2338 | const safety_str = if (inst_data.safety) "safe" else "unsafe"; | ||
| 2339 | try stream.print("{s}) ", .{safety_str}); | ||
| 2340 | try self.writeSrc(stream, inst_data.src()); | ||
| 2341 | } | ||
| 2342 | |||
| 2343 | fn writeFnTypeCommon( | ||
| 2344 | self: *Writer, | ||
| 2345 | stream: anytype, | ||
| 2346 | param_types: []const Inst.Ref, | ||
| 2347 | ret_ty: Inst.Ref, | ||
| 2348 | var_args: bool, | ||
| 2349 | cc: Inst.Ref, | ||
| 2350 | src: LazySrcLoc, | ||
| 2351 | ) !void { | ||
| 2352 | try stream.writeAll("["); | ||
| 2353 | for (param_types) |param_type, i| { | ||
| 2354 | if (i != 0) try stream.writeAll(", "); | ||
| 2355 | try self.writeInstRef(stream, param_type); | ||
| 2356 | } | ||
| 2357 | try stream.writeAll("], "); | ||
| 2358 | try self.writeInstRef(stream, ret_ty); | ||
| 2359 | try self.writeOptionalInstRef(stream, ", cc=", cc); | ||
| 2360 | try self.writeFlag(stream, ", var_args", var_args); | ||
| 2361 | try stream.writeAll(") "); | ||
| 2362 | try self.writeSrc(stream, src); | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | fn writeSmallStr( | ||
| 2366 | self: *Writer, | ||
| 2367 | stream: anytype, | ||
| 2368 | inst: Inst.Index, | ||
| 2369 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 2370 | const str = self.code.instructions.items(.data)[inst].small_str.get(); | ||
| 2371 | try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2375 | const inst_data = self.code.instructions.items(.data)[inst].switch_capture; | ||
| 2376 | try self.writeInstIndex(stream, inst_data.switch_inst); | ||
| 2377 | try stream.print(", {d})", .{inst_data.prong_index}); | ||
| 2378 | } | ||
| 2379 | |||
| 2380 | fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void { | ||
| 2381 | var i: usize = @enumToInt(ref); | ||
| 2382 | |||
| 2383 | if (i < Inst.Ref.typed_value_map.len) { | ||
| 2384 | return stream.print("@{}", .{ref}); | ||
| 2385 | } | ||
| 2386 | i -= Inst.Ref.typed_value_map.len; | ||
| 2387 | |||
| 2388 | if (i < self.param_count) { | ||
| 2389 | return stream.print("${d}", .{i}); | ||
| 2390 | } | ||
| 2391 | i -= self.param_count; | ||
| 2392 | |||
| 2393 | return self.writeInstIndex(stream, @intCast(Inst.Index, i)); | ||
| 2394 | } | ||
| 2395 | |||
| 2396 | fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2397 | return stream.print("%{d}", .{inst}); | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | fn writeOptionalInstRef( | ||
| 2401 | self: *Writer, | ||
| 2402 | stream: anytype, | ||
| 2403 | prefix: []const u8, | ||
| 2404 | inst: Inst.Ref, | ||
| 2405 | ) !void { | ||
| 2406 | if (inst == .none) return; | ||
| 2407 | try stream.writeAll(prefix); | ||
| 2408 | try self.writeInstRef(stream, inst); | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | fn writeFlag( | ||
| 2412 | self: *Writer, | ||
| 2413 | stream: anytype, | ||
| 2414 | name: []const u8, | ||
| 2415 | flag: bool, | ||
| 2416 | ) !void { | ||
| 2417 | if (!flag) return; | ||
| 2418 | try stream.writeAll(name); | ||
| 2419 | } | ||
| 2420 | |||
| 2421 | fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { | ||
| 2422 | const tree = self.scope.tree(); | ||
| 2423 | const src_loc = src.toSrcLoc(self.scope); | ||
| 2424 | const abs_byte_off = try src_loc.byteOffset(); | ||
| 2425 | const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); | ||
| 2426 | try stream.print("{s}:{d}:{d}", .{ | ||
| 2427 | @tagName(src), delta_line.line + 1, delta_line.column + 1, | ||
| 2428 | }); | ||
| 2429 | } | ||
| 2430 | |||
| 2431 | fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void { | ||
| 2432 | for (body) |inst| { | ||
| 2433 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2434 | try stream.print("%{d} ", .{inst}); | ||
| 2435 | try self.writeInstToStream(stream, inst); | ||
| 2436 | try stream.writeByte('\n'); | ||
| 2437 | } | ||
| 2438 | } | ||
| 2439 | }; | ||
test/behavior.zig created+153| ... | @@ -0,0 +1,153 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | |||
| 3 | comptime { | ||
| 4 | // Tests that pass for both. | ||
| 5 | {} | ||
| 6 | |||
| 7 | if (builtin.zig_is_stage2) { | ||
| 8 | // Tests that only pass for stage2. | ||
| 9 | } else { | ||
| 10 | // Tests that only pass for stage1. | ||
| 11 | _ = @import("behavior/align.zig"); | ||
| 12 | _ = @import("behavior/alignof.zig"); | ||
| 13 | _ = @import("behavior/array.zig"); | ||
| 14 | if (builtin.os.tag != .wasi) { | ||
| 15 | _ = @import("behavior/asm.zig"); | ||
| 16 | _ = @import("behavior/async_fn.zig"); | ||
| 17 | } | ||
| 18 | _ = @import("behavior/atomics.zig"); | ||
| 19 | _ = @import("behavior/await_struct.zig"); | ||
| 20 | _ = @import("behavior/bit_shifting.zig"); | ||
| 21 | _ = @import("behavior/bitcast.zig"); | ||
| 22 | _ = @import("behavior/bitreverse.zig"); | ||
| 23 | _ = @import("behavior/bool.zig"); | ||
| 24 | _ = @import("behavior/bugs/1025.zig"); | ||
| 25 | _ = @import("behavior/bugs/1076.zig"); | ||
| 26 | _ = @import("behavior/bugs/1111.zig"); | ||
| 27 | _ = @import("behavior/bugs/1120.zig"); | ||
| 28 | _ = @import("behavior/bugs/1277.zig"); | ||
| 29 | _ = @import("behavior/bugs/1310.zig"); | ||
| 30 | _ = @import("behavior/bugs/1322.zig"); | ||
| 31 | _ = @import("behavior/bugs/1381.zig"); | ||
| 32 | _ = @import("behavior/bugs/1421.zig"); | ||
| 33 | _ = @import("behavior/bugs/1442.zig"); | ||
| 34 | _ = @import("behavior/bugs/1486.zig"); | ||
| 35 | _ = @import("behavior/bugs/1500.zig"); | ||
| 36 | _ = @import("behavior/bugs/1607.zig"); | ||
| 37 | _ = @import("behavior/bugs/1735.zig"); | ||
| 38 | _ = @import("behavior/bugs/1741.zig"); | ||
| 39 | _ = @import("behavior/bugs/1851.zig"); | ||
| 40 | _ = @import("behavior/bugs/1914.zig"); | ||
| 41 | _ = @import("behavior/bugs/2006.zig"); | ||
| 42 | _ = @import("behavior/bugs/2114.zig"); | ||
| 43 | _ = @import("behavior/bugs/2346.zig"); | ||
| 44 | _ = @import("behavior/bugs/2578.zig"); | ||
| 45 | _ = @import("behavior/bugs/2692.zig"); | ||
| 46 | _ = @import("behavior/bugs/2889.zig"); | ||
| 47 | _ = @import("behavior/bugs/3007.zig"); | ||
| 48 | _ = @import("behavior/bugs/3046.zig"); | ||
| 49 | _ = @import("behavior/bugs/3112.zig"); | ||
| 50 | _ = @import("behavior/bugs/3367.zig"); | ||
| 51 | _ = @import("behavior/bugs/3384.zig"); | ||
| 52 | _ = @import("behavior/bugs/3586.zig"); | ||
| 53 | _ = @import("behavior/bugs/3742.zig"); | ||
| 54 | _ = @import("behavior/bugs/4328.zig"); | ||
| 55 | _ = @import("behavior/bugs/4560.zig"); | ||
| 56 | _ = @import("behavior/bugs/4769_a.zig"); | ||
| 57 | _ = @import("behavior/bugs/4769_b.zig"); | ||
| 58 | _ = @import("behavior/bugs/4769_c.zig"); | ||
| 59 | _ = @import("behavior/bugs/4954.zig"); | ||
| 60 | _ = @import("behavior/bugs/5398.zig"); | ||
| 61 | _ = @import("behavior/bugs/5413.zig"); | ||
| 62 | _ = @import("behavior/bugs/5474.zig"); | ||
| 63 | _ = @import("behavior/bugs/5487.zig"); | ||
| 64 | _ = @import("behavior/bugs/6456.zig"); | ||
| 65 | _ = @import("behavior/bugs/6781.zig"); | ||
| 66 | _ = @import("behavior/bugs/6850.zig"); | ||
| 67 | _ = @import("behavior/bugs/7027.zig"); | ||
| 68 | _ = @import("behavior/bugs/7047.zig"); | ||
| 69 | _ = @import("behavior/bugs/7003.zig"); | ||
| 70 | _ = @import("behavior/bugs/7250.zig"); | ||
| 71 | _ = @import("behavior/bugs/394.zig"); | ||
| 72 | _ = @import("behavior/bugs/421.zig"); | ||
| 73 | _ = @import("behavior/bugs/529.zig"); | ||
| 74 | _ = @import("behavior/bugs/624.zig"); | ||
| 75 | _ = @import("behavior/bugs/655.zig"); | ||
| 76 | _ = @import("behavior/bugs/656.zig"); | ||
| 77 | _ = @import("behavior/bugs/679.zig"); | ||
| 78 | _ = @import("behavior/bugs/704.zig"); | ||
| 79 | _ = @import("behavior/bugs/718.zig"); | ||
| 80 | _ = @import("behavior/bugs/726.zig"); | ||
| 81 | _ = @import("behavior/bugs/828.zig"); | ||
| 82 | _ = @import("behavior/bugs/920.zig"); | ||
| 83 | _ = @import("behavior/byteswap.zig"); | ||
| 84 | _ = @import("behavior/byval_arg_var.zig"); | ||
| 85 | _ = @import("behavior/call.zig"); | ||
| 86 | _ = @import("behavior/cast.zig"); | ||
| 87 | _ = @import("behavior/const_slice_child.zig"); | ||
| 88 | _ = @import("behavior/defer.zig"); | ||
| 89 | _ = @import("behavior/enum.zig"); | ||
| 90 | _ = @import("behavior/enum_with_members.zig"); | ||
| 91 | _ = @import("behavior/error.zig"); | ||
| 92 | _ = @import("behavior/eval.zig"); | ||
| 93 | _ = @import("behavior/field_parent_ptr.zig"); | ||
| 94 | _ = @import("behavior/floatop.zig"); | ||
| 95 | _ = @import("behavior/fn.zig"); | ||
| 96 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); | ||
| 97 | _ = @import("behavior/fn_delegation.zig"); | ||
| 98 | _ = @import("behavior/for.zig"); | ||
| 99 | _ = @import("behavior/generics.zig"); | ||
| 100 | _ = @import("behavior/hasdecl.zig"); | ||
| 101 | _ = @import("behavior/hasfield.zig"); | ||
| 102 | _ = @import("behavior/if.zig"); | ||
| 103 | _ = @import("behavior/import.zig"); | ||
| 104 | _ = @import("behavior/incomplete_struct_param_tld.zig"); | ||
| 105 | _ = @import("behavior/inttoptr.zig"); | ||
| 106 | _ = @import("behavior/ir_block_deps.zig"); | ||
| 107 | _ = @import("behavior/math.zig"); | ||
| 108 | _ = @import("behavior/merge_error_sets.zig"); | ||
| 109 | _ = @import("behavior/misc.zig"); | ||
| 110 | _ = @import("behavior/muladd.zig"); | ||
| 111 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | ||
| 112 | _ = @import("behavior/null.zig"); | ||
| 113 | _ = @import("behavior/optional.zig"); | ||
| 114 | _ = @import("behavior/pointers.zig"); | ||
| 115 | _ = @import("behavior/popcount.zig"); | ||
| 116 | _ = @import("behavior/ptrcast.zig"); | ||
| 117 | _ = @import("behavior/pub_enum.zig"); | ||
| 118 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | ||
| 119 | _ = @import("behavior/reflection.zig"); | ||
| 120 | _ = @import("behavior/shuffle.zig"); | ||
| 121 | _ = @import("behavior/sizeof_and_typeof.zig"); | ||
| 122 | _ = @import("behavior/slice.zig"); | ||
| 123 | _ = @import("behavior/slice_sentinel_comptime.zig"); | ||
| 124 | _ = @import("behavior/struct.zig"); | ||
| 125 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | ||
| 126 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | ||
| 127 | _ = @import("behavior/switch.zig"); | ||
| 128 | _ = @import("behavior/switch_prong_err_enum.zig"); | ||
| 129 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | ||
| 130 | _ = @import("behavior/syntax.zig"); | ||
| 131 | _ = @import("behavior/this.zig"); | ||
| 132 | _ = @import("behavior/truncate.zig"); | ||
| 133 | _ = @import("behavior/try.zig"); | ||
| 134 | _ = @import("behavior/tuple.zig"); | ||
| 135 | _ = @import("behavior/type.zig"); | ||
| 136 | _ = @import("behavior/type_info.zig"); | ||
| 137 | _ = @import("behavior/typename.zig"); | ||
| 138 | _ = @import("behavior/undefined.zig"); | ||
| 139 | _ = @import("behavior/underscore.zig"); | ||
| 140 | _ = @import("behavior/union.zig"); | ||
| 141 | _ = @import("behavior/usingnamespace.zig"); | ||
| 142 | _ = @import("behavior/var_args.zig"); | ||
| 143 | _ = @import("behavior/vector.zig"); | ||
| 144 | _ = @import("behavior/void.zig"); | ||
| 145 | if (builtin.target.cpu.arch == .wasm32) { | ||
| 146 | _ = @import("behavior/wasm.zig"); | ||
| 147 | } | ||
| 148 | _ = @import("behavior/while.zig"); | ||
| 149 | _ = @import("behavior/widening.zig"); | ||
| 150 | _ = @import("behavior/src.zig"); | ||
| 151 | _ = @import("behavior/translate_c_macros.zig"); | ||
| 152 | } | ||
| 153 | } | ||
test/behavior/align.zig created+350| ... | @@ -0,0 +1,350 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const native_arch = builtin.target.cpu.arch; | ||
| 5 | |||
| 6 | var foo: u8 align(4) = 100; | ||
| 7 | |||
| 8 | test "global variable alignment" { | ||
| 9 | comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); | ||
| 10 | comptime try expect(@TypeOf(&foo) == *align(4) u8); | ||
| 11 | { | ||
| 12 | const slice = @as(*[1]u8, &foo)[0..]; | ||
| 13 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 14 | } | ||
| 15 | { | ||
| 16 | var runtime_zero: usize = 0; | ||
| 17 | const slice = @as(*[1]u8, &foo)[runtime_zero..]; | ||
| 18 | comptime try expect(@TypeOf(slice) == []align(4) u8); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | fn derp() align(@sizeOf(usize) * 2) i32 { | ||
| 23 | return 1234; | ||
| 24 | } | ||
| 25 | fn noop1() align(1) void {} | ||
| 26 | fn noop4() align(4) void {} | ||
| 27 | |||
| 28 | test "function alignment" { | ||
| 29 | // function alignment is a compile error on wasm32/wasm64 | ||
| 30 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | ||
| 31 | |||
| 32 | try expect(derp() == 1234); | ||
| 33 | try expect(@TypeOf(noop1) == fn () align(1) void); | ||
| 34 | try expect(@TypeOf(noop4) == fn () align(4) void); | ||
| 35 | noop1(); | ||
| 36 | noop4(); | ||
| 37 | } | ||
| 38 | |||
| 39 | var baz: packed struct { | ||
| 40 | a: u32, | ||
| 41 | b: u32, | ||
| 42 | } = undefined; | ||
| 43 | |||
| 44 | test "packed struct alignment" { | ||
| 45 | try expect(@TypeOf(&baz.b) == *align(1) u32); | ||
| 46 | } | ||
| 47 | |||
| 48 | const blah: packed struct { | ||
| 49 | a: u3, | ||
| 50 | b: u3, | ||
| 51 | c: u2, | ||
| 52 | } = undefined; | ||
| 53 | |||
| 54 | test "bit field alignment" { | ||
| 55 | try expect(@TypeOf(&blah.b) == *align(1:3:1) const u3); | ||
| 56 | } | ||
| 57 | |||
| 58 | test "default alignment allows unspecified in type syntax" { | ||
| 59 | try expect(*u32 == *align(@alignOf(u32)) u32); | ||
| 60 | } | ||
| 61 | |||
| 62 | test "implicitly decreasing pointer alignment" { | ||
| 63 | const a: u32 align(4) = 3; | ||
| 64 | const b: u32 align(8) = 4; | ||
| 65 | try expect(addUnaligned(&a, &b) == 7); | ||
| 66 | } | ||
| 67 | |||
| 68 | fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { | ||
| 69 | return a.* + b.*; | ||
| 70 | } | ||
| 71 | |||
| 72 | test "implicitly decreasing slice alignment" { | ||
| 73 | const a: u32 align(4) = 3; | ||
| 74 | const b: u32 align(8) = 4; | ||
| 75 | try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7); | ||
| 76 | } | ||
| 77 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { | ||
| 78 | return a[0] + b[0]; | ||
| 79 | } | ||
| 80 | |||
| 81 | test "specifying alignment allows pointer cast" { | ||
| 82 | try testBytesAlign(0x33); | ||
| 83 | } | ||
| 84 | fn testBytesAlign(b: u8) !void { | ||
| 85 | var bytes align(4) = [_]u8{ | ||
| 86 | b, | ||
| 87 | b, | ||
| 88 | b, | ||
| 89 | b, | ||
| 90 | }; | ||
| 91 | const ptr = @ptrCast(*u32, &bytes[0]); | ||
| 92 | try expect(ptr.* == 0x33333333); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "@alignCast pointers" { | ||
| 96 | var x: u32 align(4) = 1; | ||
| 97 | expectsOnly1(&x); | ||
| 98 | try expect(x == 2); | ||
| 99 | } | ||
| 100 | fn expectsOnly1(x: *align(1) u32) void { | ||
| 101 | expects4(@alignCast(4, x)); | ||
| 102 | } | ||
| 103 | fn expects4(x: *align(4) u32) void { | ||
| 104 | x.* += 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | test "@alignCast slices" { | ||
| 108 | var array align(4) = [_]u32{ | ||
| 109 | 1, | ||
| 110 | 1, | ||
| 111 | }; | ||
| 112 | const slice = array[0..]; | ||
| 113 | sliceExpectsOnly1(slice); | ||
| 114 | try expect(slice[0] == 2); | ||
| 115 | } | ||
| 116 | fn sliceExpectsOnly1(slice: []align(1) u32) void { | ||
| 117 | sliceExpects4(@alignCast(4, slice)); | ||
| 118 | } | ||
| 119 | fn sliceExpects4(slice: []align(4) u32) void { | ||
| 120 | slice[0] += 1; | ||
| 121 | } | ||
| 122 | |||
| 123 | test "implicitly decreasing fn alignment" { | ||
| 124 | // function alignment is a compile error on wasm32/wasm64 | ||
| 125 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | ||
| 126 | |||
| 127 | try testImplicitlyDecreaseFnAlign(alignedSmall, 1234); | ||
| 128 | try testImplicitlyDecreaseFnAlign(alignedBig, 5678); | ||
| 129 | } | ||
| 130 | |||
| 131 | fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) !void { | ||
| 132 | try expect(ptr() == answer); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn alignedSmall() align(8) i32 { | ||
| 136 | return 1234; | ||
| 137 | } | ||
| 138 | fn alignedBig() align(16) i32 { | ||
| 139 | return 5678; | ||
| 140 | } | ||
| 141 | |||
| 142 | test "@alignCast functions" { | ||
| 143 | // function alignment is a compile error on wasm32/wasm64 | ||
| 144 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | ||
| 145 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 146 | |||
| 147 | try expect(fnExpectsOnly1(simple4) == 0x19); | ||
| 148 | } | ||
| 149 | fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { | ||
| 150 | return fnExpects4(@alignCast(4, ptr)); | ||
| 151 | } | ||
| 152 | fn fnExpects4(ptr: fn () align(4) i32) i32 { | ||
| 153 | return ptr(); | ||
| 154 | } | ||
| 155 | fn simple4() align(4) i32 { | ||
| 156 | return 0x19; | ||
| 157 | } | ||
| 158 | |||
| 159 | test "generic function with align param" { | ||
| 160 | // function alignment is a compile error on wasm32/wasm64 | ||
| 161 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | ||
| 162 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 163 | |||
| 164 | try expect(whyWouldYouEverDoThis(1) == 0x1); | ||
| 165 | try expect(whyWouldYouEverDoThis(4) == 0x1); | ||
| 166 | try expect(whyWouldYouEverDoThis(8) == 0x1); | ||
| 167 | } | ||
| 168 | |||
| 169 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { | ||
| 170 | return 0x1; | ||
| 171 | } | ||
| 172 | |||
| 173 | test "@ptrCast preserves alignment of bigger source" { | ||
| 174 | var x: u32 align(16) = 1234; | ||
| 175 | const ptr = @ptrCast(*u8, &x); | ||
| 176 | try expect(@TypeOf(ptr) == *align(16) u8); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "runtime known array index has best alignment possible" { | ||
| 180 | // take full advantage of over-alignment | ||
| 181 | var array align(4) = [_]u8{ 1, 2, 3, 4 }; | ||
| 182 | try expect(@TypeOf(&array[0]) == *align(4) u8); | ||
| 183 | try expect(@TypeOf(&array[1]) == *u8); | ||
| 184 | try expect(@TypeOf(&array[2]) == *align(2) u8); | ||
| 185 | try expect(@TypeOf(&array[3]) == *u8); | ||
| 186 | |||
| 187 | // because align is too small but we still figure out to use 2 | ||
| 188 | var bigger align(2) = [_]u64{ 1, 2, 3, 4 }; | ||
| 189 | try expect(@TypeOf(&bigger[0]) == *align(2) u64); | ||
| 190 | try expect(@TypeOf(&bigger[1]) == *align(2) u64); | ||
| 191 | try expect(@TypeOf(&bigger[2]) == *align(2) u64); | ||
| 192 | try expect(@TypeOf(&bigger[3]) == *align(2) u64); | ||
| 193 | |||
| 194 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | ||
| 195 | var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; | ||
| 196 | var runtime_zero: usize = 0; | ||
| 197 | comptime try expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); | ||
| 198 | comptime try expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); | ||
| 199 | try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); | ||
| 200 | try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); | ||
| 201 | try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); | ||
| 202 | try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); | ||
| 203 | |||
| 204 | // has to use ABI alignment because index known at runtime only | ||
| 205 | try testIndex2(array[runtime_zero..].ptr, 0, *u8); | ||
| 206 | try testIndex2(array[runtime_zero..].ptr, 1, *u8); | ||
| 207 | try testIndex2(array[runtime_zero..].ptr, 2, *u8); | ||
| 208 | try testIndex2(array[runtime_zero..].ptr, 3, *u8); | ||
| 209 | } | ||
| 210 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void { | ||
| 211 | comptime try expect(@TypeOf(&smaller[index]) == T); | ||
| 212 | } | ||
| 213 | fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void { | ||
| 214 | comptime try expect(@TypeOf(&ptr[index]) == T); | ||
| 215 | } | ||
| 216 | |||
| 217 | test "alignstack" { | ||
| 218 | try expect(fnWithAlignedStack() == 1234); | ||
| 219 | } | ||
| 220 | |||
| 221 | fn fnWithAlignedStack() i32 { | ||
| 222 | @setAlignStack(256); | ||
| 223 | return 1234; | ||
| 224 | } | ||
| 225 | |||
| 226 | test "alignment of structs" { | ||
| 227 | try expect(@alignOf(struct { | ||
| 228 | a: i32, | ||
| 229 | b: *i32, | ||
| 230 | }) == @alignOf(usize)); | ||
| 231 | } | ||
| 232 | |||
| 233 | test "alignment of function with c calling convention" { | ||
| 234 | var runtime_nothing = nothing; | ||
| 235 | const casted1 = @ptrCast(*const u8, runtime_nothing); | ||
| 236 | const casted2 = @ptrCast(fn () callconv(.C) void, casted1); | ||
| 237 | casted2(); | ||
| 238 | } | ||
| 239 | |||
| 240 | fn nothing() callconv(.C) void {} | ||
| 241 | |||
| 242 | test "return error union with 128-bit integer" { | ||
| 243 | try expect(3 == try give()); | ||
| 244 | } | ||
| 245 | fn give() anyerror!u128 { | ||
| 246 | return 3; | ||
| 247 | } | ||
| 248 | |||
| 249 | test "alignment of >= 128-bit integer type" { | ||
| 250 | try expect(@alignOf(u128) == 16); | ||
| 251 | try expect(@alignOf(u129) == 16); | ||
| 252 | } | ||
| 253 | |||
| 254 | test "alignment of struct with 128-bit field" { | ||
| 255 | try expect(@alignOf(struct { | ||
| 256 | x: u128, | ||
| 257 | }) == 16); | ||
| 258 | |||
| 259 | comptime { | ||
| 260 | try expect(@alignOf(struct { | ||
| 261 | x: u128, | ||
| 262 | }) == 16); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | test "size of extern struct with 128-bit field" { | ||
| 267 | try expect(@sizeOf(extern struct { | ||
| 268 | x: u128, | ||
| 269 | y: u8, | ||
| 270 | }) == 32); | ||
| 271 | |||
| 272 | comptime { | ||
| 273 | try expect(@sizeOf(extern struct { | ||
| 274 | x: u128, | ||
| 275 | y: u8, | ||
| 276 | }) == 32); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | const DefaultAligned = struct { | ||
| 281 | nevermind: u32, | ||
| 282 | badguy: i128, | ||
| 283 | }; | ||
| 284 | |||
| 285 | test "read 128-bit field from default aligned struct in stack memory" { | ||
| 286 | var default_aligned = DefaultAligned{ | ||
| 287 | .nevermind = 1, | ||
| 288 | .badguy = 12, | ||
| 289 | }; | ||
| 290 | try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0); | ||
| 291 | try expect(12 == default_aligned.badguy); | ||
| 292 | } | ||
| 293 | |||
| 294 | var default_aligned_global = DefaultAligned{ | ||
| 295 | .nevermind = 1, | ||
| 296 | .badguy = 12, | ||
| 297 | }; | ||
| 298 | |||
| 299 | test "read 128-bit field from default aligned struct in global memory" { | ||
| 300 | try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); | ||
| 301 | try expect(12 == default_aligned_global.badguy); | ||
| 302 | } | ||
| 303 | |||
| 304 | test "struct field explicit alignment" { | ||
| 305 | const S = struct { | ||
| 306 | const Node = struct { | ||
| 307 | next: *Node, | ||
| 308 | massive_byte: u8 align(64), | ||
| 309 | }; | ||
| 310 | }; | ||
| 311 | |||
| 312 | var node: S.Node = undefined; | ||
| 313 | node.massive_byte = 100; | ||
| 314 | try expect(node.massive_byte == 100); | ||
| 315 | comptime try expect(@TypeOf(&node.massive_byte) == *align(64) u8); | ||
| 316 | try expect(@ptrToInt(&node.massive_byte) % 64 == 0); | ||
| 317 | } | ||
| 318 | |||
| 319 | test "align(@alignOf(T)) T does not force resolution of T" { | ||
| 320 | const S = struct { | ||
| 321 | const A = struct { | ||
| 322 | a: *align(@alignOf(A)) A, | ||
| 323 | }; | ||
| 324 | fn doTheTest() void { | ||
| 325 | suspend { | ||
| 326 | resume @frame(); | ||
| 327 | } | ||
| 328 | _ = bar(@Frame(doTheTest)); | ||
| 329 | } | ||
| 330 | fn bar(comptime T: type) *align(@alignOf(T)) T { | ||
| 331 | ok = true; | ||
| 332 | return undefined; | ||
| 333 | } | ||
| 334 | |||
| 335 | var ok = false; | ||
| 336 | }; | ||
| 337 | _ = async S.doTheTest(); | ||
| 338 | try expect(S.ok); | ||
| 339 | } | ||
| 340 | |||
| 341 | test "align(N) on functions" { | ||
| 342 | // function alignment is a compile error on wasm32/wasm64 | ||
| 343 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | ||
| 344 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 345 | |||
| 346 | try expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); | ||
| 347 | } | ||
| 348 | fn overaligned_fn() align(0x1000) i32 { | ||
| 349 | return 42; | ||
| 350 | } | ||
test/behavior/alignof.zig created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const native_arch = builtin.target.cpu.arch; | ||
| 5 | const maxInt = std.math.maxInt; | ||
| 6 | |||
| 7 | const Foo = struct { | ||
| 8 | x: u32, | ||
| 9 | y: u32, | ||
| 10 | z: u32, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "@alignOf(T) before referencing T" { | ||
| 14 | comptime try expect(@alignOf(Foo) != maxInt(usize)); | ||
| 15 | if (native_arch == .x86_64) { | ||
| 16 | comptime try expect(@alignOf(Foo) == 4); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "comparison of @alignOf(T) against zero" { | ||
| 21 | { | ||
| 22 | const T = struct { x: u32 }; | ||
| 23 | try expect(!(@alignOf(T) == 0)); | ||
| 24 | try expect(@alignOf(T) != 0); | ||
| 25 | try expect(!(@alignOf(T) < 0)); | ||
| 26 | try expect(!(@alignOf(T) <= 0)); | ||
| 27 | try expect(@alignOf(T) > 0); | ||
| 28 | try expect(@alignOf(T) >= 0); | ||
| 29 | } | ||
| 30 | { | ||
| 31 | const T = struct {}; | ||
| 32 | try expect(@alignOf(T) == 0); | ||
| 33 | try expect(!(@alignOf(T) != 0)); | ||
| 34 | try expect(!(@alignOf(T) < 0)); | ||
| 35 | try expect(@alignOf(T) <= 0); | ||
| 36 | try expect(!(@alignOf(T) > 0)); | ||
| 37 | try expect(@alignOf(T) >= 0); | ||
| 38 | } | ||
| 39 | } | ||
test/behavior/array.zig created+489| ... | @@ -0,0 +1,489 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const mem = std.mem; | ||
| 4 | const expect = testing.expect; | ||
| 5 | const expectEqual = testing.expectEqual; | ||
| 6 | |||
| 7 | test "arrays" { | ||
| 8 | var array: [5]u32 = undefined; | ||
| 9 | |||
| 10 | var i: u32 = 0; | ||
| 11 | while (i < 5) { | ||
| 12 | array[i] = i + 1; | ||
| 13 | i = array[i]; | ||
| 14 | } | ||
| 15 | |||
| 16 | i = 0; | ||
| 17 | var accumulator = @as(u32, 0); | ||
| 18 | while (i < 5) { | ||
| 19 | accumulator += array[i]; | ||
| 20 | |||
| 21 | i += 1; | ||
| 22 | } | ||
| 23 | |||
| 24 | try expect(accumulator == 15); | ||
| 25 | try expect(getArrayLen(&array) == 5); | ||
| 26 | } | ||
| 27 | fn getArrayLen(a: []const u32) usize { | ||
| 28 | return a.len; | ||
| 29 | } | ||
| 30 | |||
| 31 | test "array with sentinels" { | ||
| 32 | const S = struct { | ||
| 33 | fn doTheTest(is_ct: bool) !void { | ||
| 34 | if (is_ct) { | ||
| 35 | var zero_sized: [0:0xde]u8 = [_:0xde]u8{}; | ||
| 36 | // Disabled at runtime because of | ||
| 37 | // https://github.com/ziglang/zig/issues/4372 | ||
| 38 | try expectEqual(@as(u8, 0xde), zero_sized[0]); | ||
| 39 | var reinterpreted = @ptrCast(*[1]u8, &zero_sized); | ||
| 40 | try expectEqual(@as(u8, 0xde), reinterpreted[0]); | ||
| 41 | } | ||
| 42 | var arr: [3:0x55]u8 = undefined; | ||
| 43 | // Make sure the sentinel pointer is pointing after the last element | ||
| 44 | if (!is_ct) { | ||
| 45 | const sentinel_ptr = @ptrToInt(&arr[3]); | ||
| 46 | const last_elem_ptr = @ptrToInt(&arr[2]); | ||
| 47 | try expectEqual(@as(usize, 1), sentinel_ptr - last_elem_ptr); | ||
| 48 | } | ||
| 49 | // Make sure the sentinel is writeable | ||
| 50 | arr[3] = 0x55; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | try S.doTheTest(false); | ||
| 55 | comptime try S.doTheTest(true); | ||
| 56 | } | ||
| 57 | |||
| 58 | test "void arrays" { | ||
| 59 | var array: [4]void = undefined; | ||
| 60 | array[0] = void{}; | ||
| 61 | array[1] = array[2]; | ||
| 62 | try expect(@sizeOf(@TypeOf(array)) == 0); | ||
| 63 | try expect(array.len == 4); | ||
| 64 | } | ||
| 65 | |||
| 66 | test "array literal" { | ||
| 67 | const hex_mult = [_]u16{ | ||
| 68 | 4096, | ||
| 69 | 256, | ||
| 70 | 16, | ||
| 71 | 1, | ||
| 72 | }; | ||
| 73 | |||
| 74 | try expect(hex_mult.len == 4); | ||
| 75 | try expect(hex_mult[1] == 256); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "array dot len const expr" { | ||
| 79 | try expect(comptime x: { | ||
| 80 | break :x some_array.len == 4; | ||
| 81 | }); | ||
| 82 | } | ||
| 83 | |||
| 84 | const ArrayDotLenConstExpr = struct { | ||
| 85 | y: [some_array.len]u8, | ||
| 86 | }; | ||
| 87 | const some_array = [_]u8{ | ||
| 88 | 0, | ||
| 89 | 1, | ||
| 90 | 2, | ||
| 91 | 3, | ||
| 92 | }; | ||
| 93 | |||
| 94 | test "nested arrays" { | ||
| 95 | const array_of_strings = [_][]const u8{ | ||
| 96 | "hello", | ||
| 97 | "this", | ||
| 98 | "is", | ||
| 99 | "my", | ||
| 100 | "thing", | ||
| 101 | }; | ||
| 102 | for (array_of_strings) |s, i| { | ||
| 103 | if (i == 0) try expect(mem.eql(u8, s, "hello")); | ||
| 104 | if (i == 1) try expect(mem.eql(u8, s, "this")); | ||
| 105 | if (i == 2) try expect(mem.eql(u8, s, "is")); | ||
| 106 | if (i == 3) try expect(mem.eql(u8, s, "my")); | ||
| 107 | if (i == 4) try expect(mem.eql(u8, s, "thing")); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | var s_array: [8]Sub = undefined; | ||
| 112 | const Sub = struct { | ||
| 113 | b: u8, | ||
| 114 | }; | ||
| 115 | const Str = struct { | ||
| 116 | a: []Sub, | ||
| 117 | }; | ||
| 118 | test "set global var array via slice embedded in struct" { | ||
| 119 | var s = Str{ .a = s_array[0..] }; | ||
| 120 | |||
| 121 | s.a[0].b = 1; | ||
| 122 | s.a[1].b = 2; | ||
| 123 | s.a[2].b = 3; | ||
| 124 | |||
| 125 | try expect(s_array[0].b == 1); | ||
| 126 | try expect(s_array[1].b == 2); | ||
| 127 | try expect(s_array[2].b == 3); | ||
| 128 | } | ||
| 129 | |||
| 130 | test "array literal with specified size" { | ||
| 131 | var array = [2]u8{ | ||
| 132 | 1, | ||
| 133 | 2, | ||
| 134 | }; | ||
| 135 | try expect(array[0] == 1); | ||
| 136 | try expect(array[1] == 2); | ||
| 137 | } | ||
| 138 | |||
| 139 | test "array len field" { | ||
| 140 | var arr = [4]u8{ 0, 0, 0, 0 }; | ||
| 141 | var ptr = &arr; | ||
| 142 | try expect(arr.len == 4); | ||
| 143 | comptime try expect(arr.len == 4); | ||
| 144 | try expect(ptr.len == 4); | ||
| 145 | comptime try expect(ptr.len == 4); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "single-item pointer to array indexing and slicing" { | ||
| 149 | try testSingleItemPtrArrayIndexSlice(); | ||
| 150 | comptime try testSingleItemPtrArrayIndexSlice(); | ||
| 151 | } | ||
| 152 | |||
| 153 | fn testSingleItemPtrArrayIndexSlice() !void { | ||
| 154 | { | ||
| 155 | var array: [4]u8 = "aaaa".*; | ||
| 156 | doSomeMangling(&array); | ||
| 157 | try expect(mem.eql(u8, "azya", &array)); | ||
| 158 | } | ||
| 159 | { | ||
| 160 | var array = "aaaa".*; | ||
| 161 | doSomeMangling(&array); | ||
| 162 | try expect(mem.eql(u8, "azya", &array)); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | fn doSomeMangling(array: *[4]u8) void { | ||
| 167 | array[1] = 'z'; | ||
| 168 | array[2..3][0] = 'y'; | ||
| 169 | } | ||
| 170 | |||
| 171 | test "implicit cast single-item pointer" { | ||
| 172 | try testImplicitCastSingleItemPtr(); | ||
| 173 | comptime try testImplicitCastSingleItemPtr(); | ||
| 174 | } | ||
| 175 | |||
| 176 | fn testImplicitCastSingleItemPtr() !void { | ||
| 177 | var byte: u8 = 100; | ||
| 178 | const slice = @as(*[1]u8, &byte)[0..]; | ||
| 179 | slice[0] += 1; | ||
| 180 | try expect(byte == 101); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn testArrayByValAtComptime(b: [2]u8) u8 { | ||
| 184 | return b[0]; | ||
| 185 | } | ||
| 186 | |||
| 187 | test "comptime evalutating function that takes array by value" { | ||
| 188 | const arr = [_]u8{ 0, 1 }; | ||
| 189 | _ = comptime testArrayByValAtComptime(arr); | ||
| 190 | _ = comptime testArrayByValAtComptime(arr); | ||
| 191 | } | ||
| 192 | |||
| 193 | test "implicit comptime in array type size" { | ||
| 194 | var arr: [plusOne(10)]bool = undefined; | ||
| 195 | try expect(arr.len == 11); | ||
| 196 | } | ||
| 197 | |||
| 198 | fn plusOne(x: u32) u32 { | ||
| 199 | return x + 1; | ||
| 200 | } | ||
| 201 | |||
| 202 | test "runtime initialize array elem and then implicit cast to slice" { | ||
| 203 | var two: i32 = 2; | ||
| 204 | const x: []const i32 = &[_]i32{two}; | ||
| 205 | try expect(x[0] == 2); | ||
| 206 | } | ||
| 207 | |||
| 208 | test "array literal as argument to function" { | ||
| 209 | const S = struct { | ||
| 210 | fn entry(two: i32) !void { | ||
| 211 | try foo(&[_]i32{ | ||
| 212 | 1, | ||
| 213 | 2, | ||
| 214 | 3, | ||
| 215 | }); | ||
| 216 | try foo(&[_]i32{ | ||
| 217 | 1, | ||
| 218 | two, | ||
| 219 | 3, | ||
| 220 | }); | ||
| 221 | try foo2(true, &[_]i32{ | ||
| 222 | 1, | ||
| 223 | 2, | ||
| 224 | 3, | ||
| 225 | }); | ||
| 226 | try foo2(true, &[_]i32{ | ||
| 227 | 1, | ||
| 228 | two, | ||
| 229 | 3, | ||
| 230 | }); | ||
| 231 | } | ||
| 232 | fn foo(x: []const i32) !void { | ||
| 233 | try expect(x[0] == 1); | ||
| 234 | try expect(x[1] == 2); | ||
| 235 | try expect(x[2] == 3); | ||
| 236 | } | ||
| 237 | fn foo2(trash: bool, x: []const i32) !void { | ||
| 238 | try expect(trash); | ||
| 239 | try expect(x[0] == 1); | ||
| 240 | try expect(x[1] == 2); | ||
| 241 | try expect(x[2] == 3); | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | try S.entry(2); | ||
| 245 | comptime try S.entry(2); | ||
| 246 | } | ||
| 247 | |||
| 248 | test "double nested array to const slice cast in array literal" { | ||
| 249 | const S = struct { | ||
| 250 | fn entry(two: i32) !void { | ||
| 251 | const cases = [_][]const []const i32{ | ||
| 252 | &[_][]const i32{&[_]i32{1}}, | ||
| 253 | &[_][]const i32{&[_]i32{ 2, 3 }}, | ||
| 254 | &[_][]const i32{ | ||
| 255 | &[_]i32{4}, | ||
| 256 | &[_]i32{ 5, 6, 7 }, | ||
| 257 | }, | ||
| 258 | }; | ||
| 259 | try check(&cases); | ||
| 260 | |||
| 261 | const cases2 = [_][]const i32{ | ||
| 262 | &[_]i32{1}, | ||
| 263 | &[_]i32{ two, 3 }, | ||
| 264 | }; | ||
| 265 | try expect(cases2.len == 2); | ||
| 266 | try expect(cases2[0].len == 1); | ||
| 267 | try expect(cases2[0][0] == 1); | ||
| 268 | try expect(cases2[1].len == 2); | ||
| 269 | try expect(cases2[1][0] == 2); | ||
| 270 | try expect(cases2[1][1] == 3); | ||
| 271 | |||
| 272 | const cases3 = [_][]const []const i32{ | ||
| 273 | &[_][]const i32{&[_]i32{1}}, | ||
| 274 | &[_][]const i32{&[_]i32{ two, 3 }}, | ||
| 275 | &[_][]const i32{ | ||
| 276 | &[_]i32{4}, | ||
| 277 | &[_]i32{ 5, 6, 7 }, | ||
| 278 | }, | ||
| 279 | }; | ||
| 280 | try check(&cases3); | ||
| 281 | } | ||
| 282 | |||
| 283 | fn check(cases: []const []const []const i32) !void { | ||
| 284 | try expect(cases.len == 3); | ||
| 285 | try expect(cases[0].len == 1); | ||
| 286 | try expect(cases[0][0].len == 1); | ||
| 287 | try expect(cases[0][0][0] == 1); | ||
| 288 | try expect(cases[1].len == 1); | ||
| 289 | try expect(cases[1][0].len == 2); | ||
| 290 | try expect(cases[1][0][0] == 2); | ||
| 291 | try expect(cases[1][0][1] == 3); | ||
| 292 | try expect(cases[2].len == 2); | ||
| 293 | try expect(cases[2][0].len == 1); | ||
| 294 | try expect(cases[2][0][0] == 4); | ||
| 295 | try expect(cases[2][1].len == 3); | ||
| 296 | try expect(cases[2][1][0] == 5); | ||
| 297 | try expect(cases[2][1][1] == 6); | ||
| 298 | try expect(cases[2][1][2] == 7); | ||
| 299 | } | ||
| 300 | }; | ||
| 301 | try S.entry(2); | ||
| 302 | comptime try S.entry(2); | ||
| 303 | } | ||
| 304 | |||
| 305 | test "read/write through global variable array of struct fields initialized via array mult" { | ||
| 306 | const S = struct { | ||
| 307 | fn doTheTest() !void { | ||
| 308 | try expect(storage[0].term == 1); | ||
| 309 | storage[0] = MyStruct{ .term = 123 }; | ||
| 310 | try expect(storage[0].term == 123); | ||
| 311 | } | ||
| 312 | |||
| 313 | pub const MyStruct = struct { | ||
| 314 | term: usize, | ||
| 315 | }; | ||
| 316 | |||
| 317 | var storage: [1]MyStruct = [_]MyStruct{MyStruct{ .term = 1 }} ** 1; | ||
| 318 | }; | ||
| 319 | try S.doTheTest(); | ||
| 320 | } | ||
| 321 | |||
| 322 | test "implicit cast zero sized array ptr to slice" { | ||
| 323 | { | ||
| 324 | var b = "".*; | ||
| 325 | const c: []const u8 = &b; | ||
| 326 | try expect(c.len == 0); | ||
| 327 | } | ||
| 328 | { | ||
| 329 | var b: [0]u8 = "".*; | ||
| 330 | const c: []const u8 = &b; | ||
| 331 | try expect(c.len == 0); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | test "anonymous list literal syntax" { | ||
| 336 | const S = struct { | ||
| 337 | fn doTheTest() !void { | ||
| 338 | var array: [4]u8 = .{ 1, 2, 3, 4 }; | ||
| 339 | try expect(array[0] == 1); | ||
| 340 | try expect(array[1] == 2); | ||
| 341 | try expect(array[2] == 3); | ||
| 342 | try expect(array[3] == 4); | ||
| 343 | } | ||
| 344 | }; | ||
| 345 | try S.doTheTest(); | ||
| 346 | comptime try S.doTheTest(); | ||
| 347 | } | ||
| 348 | |||
| 349 | test "anonymous literal in array" { | ||
| 350 | const S = struct { | ||
| 351 | const Foo = struct { | ||
| 352 | a: usize = 2, | ||
| 353 | b: usize = 4, | ||
| 354 | }; | ||
| 355 | fn doTheTest() !void { | ||
| 356 | var array: [2]Foo = .{ | ||
| 357 | .{ .a = 3 }, | ||
| 358 | .{ .b = 3 }, | ||
| 359 | }; | ||
| 360 | try expect(array[0].a == 3); | ||
| 361 | try expect(array[0].b == 4); | ||
| 362 | try expect(array[1].a == 2); | ||
| 363 | try expect(array[1].b == 3); | ||
| 364 | } | ||
| 365 | }; | ||
| 366 | try S.doTheTest(); | ||
| 367 | comptime try S.doTheTest(); | ||
| 368 | } | ||
| 369 | |||
| 370 | test "access the null element of a null terminated array" { | ||
| 371 | const S = struct { | ||
| 372 | fn doTheTest() !void { | ||
| 373 | var array: [4:0]u8 = .{ 'a', 'o', 'e', 'u' }; | ||
| 374 | try expect(array[4] == 0); | ||
| 375 | var len: usize = 4; | ||
| 376 | try expect(array[len] == 0); | ||
| 377 | } | ||
| 378 | }; | ||
| 379 | try S.doTheTest(); | ||
| 380 | comptime try S.doTheTest(); | ||
| 381 | } | ||
| 382 | |||
| 383 | test "type deduction for array subscript expression" { | ||
| 384 | const S = struct { | ||
| 385 | fn doTheTest() !void { | ||
| 386 | var array = [_]u8{ 0x55, 0xAA }; | ||
| 387 | var v0 = true; | ||
| 388 | try expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]); | ||
| 389 | var v1 = false; | ||
| 390 | try expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]); | ||
| 391 | } | ||
| 392 | }; | ||
| 393 | try S.doTheTest(); | ||
| 394 | comptime try S.doTheTest(); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "sentinel element count towards the ABI size calculation" { | ||
| 398 | const S = struct { | ||
| 399 | fn doTheTest() !void { | ||
| 400 | const T = packed struct { | ||
| 401 | fill_pre: u8 = 0x55, | ||
| 402 | data: [0:0]u8 = undefined, | ||
| 403 | fill_post: u8 = 0xAA, | ||
| 404 | }; | ||
| 405 | var x = T{}; | ||
| 406 | var as_slice = mem.asBytes(&x); | ||
| 407 | try expectEqual(@as(usize, 3), as_slice.len); | ||
| 408 | try expectEqual(@as(u8, 0x55), as_slice[0]); | ||
| 409 | try expectEqual(@as(u8, 0xAA), as_slice[2]); | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | |||
| 413 | try S.doTheTest(); | ||
| 414 | comptime try S.doTheTest(); | ||
| 415 | } | ||
| 416 | |||
| 417 | test "zero-sized array with recursive type definition" { | ||
| 418 | const U = struct { | ||
| 419 | fn foo(comptime T: type, comptime n: usize) type { | ||
| 420 | return struct { | ||
| 421 | s: [n]T, | ||
| 422 | x: usize = n, | ||
| 423 | }; | ||
| 424 | } | ||
| 425 | }; | ||
| 426 | |||
| 427 | const S = struct { | ||
| 428 | list: U.foo(@This(), 0), | ||
| 429 | }; | ||
| 430 | |||
| 431 | var t: S = .{ .list = .{ .s = undefined } }; | ||
| 432 | try expectEqual(@as(usize, 0), t.list.x); | ||
| 433 | } | ||
| 434 | |||
| 435 | test "type coercion of anon struct literal to array" { | ||
| 436 | const S = struct { | ||
| 437 | const U = union { | ||
| 438 | a: u32, | ||
| 439 | b: bool, | ||
| 440 | c: []const u8, | ||
| 441 | }; | ||
| 442 | |||
| 443 | fn doTheTest() !void { | ||
| 444 | var x1: u8 = 42; | ||
| 445 | const t1 = .{ x1, 56, 54 }; | ||
| 446 | var arr1: [3]u8 = t1; | ||
| 447 | try expect(arr1[0] == 42); | ||
| 448 | try expect(arr1[1] == 56); | ||
| 449 | try expect(arr1[2] == 54); | ||
| 450 | |||
| 451 | var x2: U = .{ .a = 42 }; | ||
| 452 | const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } }; | ||
| 453 | var arr2: [3]U = t2; | ||
| 454 | try expect(arr2[0].a == 42); | ||
| 455 | try expect(arr2[1].b == true); | ||
| 456 | try expect(mem.eql(u8, arr2[2].c, "hello")); | ||
| 457 | } | ||
| 458 | }; | ||
| 459 | try S.doTheTest(); | ||
| 460 | comptime try S.doTheTest(); | ||
| 461 | } | ||
| 462 | |||
| 463 | test "type coercion of pointer to anon struct literal to pointer to array" { | ||
| 464 | const S = struct { | ||
| 465 | const U = union { | ||
| 466 | a: u32, | ||
| 467 | b: bool, | ||
| 468 | c: []const u8, | ||
| 469 | }; | ||
| 470 | |||
| 471 | fn doTheTest() !void { | ||
| 472 | var x1: u8 = 42; | ||
| 473 | const t1 = &.{ x1, 56, 54 }; | ||
| 474 | var arr1: *const [3]u8 = t1; | ||
| 475 | try expect(arr1[0] == 42); | ||
| 476 | try expect(arr1[1] == 56); | ||
| 477 | try expect(arr1[2] == 54); | ||
| 478 | |||
| 479 | var x2: U = .{ .a = 42 }; | ||
| 480 | const t2 = &.{ x2, .{ .b = true }, .{ .c = "hello" } }; | ||
| 481 | var arr2: *const [3]U = t2; | ||
| 482 | try expect(arr2[0].a == 42); | ||
| 483 | try expect(arr2[1].b == true); | ||
| 484 | try expect(mem.eql(u8, arr2[2].c, "hello")); | ||
| 485 | } | ||
| 486 | }; | ||
| 487 | try S.doTheTest(); | ||
| 488 | comptime try S.doTheTest(); | ||
| 489 | } | ||
test/behavior/asm.zig created+109| ... | @@ -0,0 +1,109 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const is_x86_64_linux = std.Target.current.cpu.arch == .x86_64 and std.Target.current.os.tag == .linux; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (is_x86_64_linux) { | ||
| 8 | asm ( | ||
| 9 | \\.globl this_is_my_alias; | ||
| 10 | \\.type this_is_my_alias, @function; | ||
| 11 | \\.set this_is_my_alias, derp; | ||
| 12 | ); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | test "module level assembly" { | ||
| 17 | if (is_x86_64_linux) { | ||
| 18 | try expect(this_is_my_alias() == 1234); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | test "output constraint modifiers" { | ||
| 23 | // This is only testing compilation. | ||
| 24 | var a: u32 = 3; | ||
| 25 | asm volatile ("" | ||
| 26 | : [_] "=m,r" (a) | ||
| 27 | : | ||
| 28 | : "" | ||
| 29 | ); | ||
| 30 | asm volatile ("" | ||
| 31 | : [_] "=r,m" (a) | ||
| 32 | : | ||
| 33 | : "" | ||
| 34 | ); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "alternative constraints" { | ||
| 38 | // Make sure we allow commas as a separator for alternative constraints. | ||
| 39 | var a: u32 = 3; | ||
| 40 | asm volatile ("" | ||
| 41 | : [_] "=r,m" (a) | ||
| 42 | : [_] "r,m" (a) | ||
| 43 | : "" | ||
| 44 | ); | ||
| 45 | } | ||
| 46 | |||
| 47 | test "sized integer/float in asm input" { | ||
| 48 | asm volatile ("" | ||
| 49 | : | ||
| 50 | : [_] "m" (@as(usize, 3)) | ||
| 51 | : "" | ||
| 52 | ); | ||
| 53 | asm volatile ("" | ||
| 54 | : | ||
| 55 | : [_] "m" (@as(i15, -3)) | ||
| 56 | : "" | ||
| 57 | ); | ||
| 58 | asm volatile ("" | ||
| 59 | : | ||
| 60 | : [_] "m" (@as(u3, 3)) | ||
| 61 | : "" | ||
| 62 | ); | ||
| 63 | asm volatile ("" | ||
| 64 | : | ||
| 65 | : [_] "m" (@as(i3, 3)) | ||
| 66 | : "" | ||
| 67 | ); | ||
| 68 | asm volatile ("" | ||
| 69 | : | ||
| 70 | : [_] "m" (@as(u121, 3)) | ||
| 71 | : "" | ||
| 72 | ); | ||
| 73 | asm volatile ("" | ||
| 74 | : | ||
| 75 | : [_] "m" (@as(i121, 3)) | ||
| 76 | : "" | ||
| 77 | ); | ||
| 78 | asm volatile ("" | ||
| 79 | : | ||
| 80 | : [_] "m" (@as(f32, 3.17)) | ||
| 81 | : "" | ||
| 82 | ); | ||
| 83 | asm volatile ("" | ||
| 84 | : | ||
| 85 | : [_] "m" (@as(f64, 3.17)) | ||
| 86 | : "" | ||
| 87 | ); | ||
| 88 | } | ||
| 89 | |||
| 90 | test "struct/array/union types as input values" { | ||
| 91 | asm volatile ("" | ||
| 92 | : | ||
| 93 | : [_] "m" (@as([1]u32, undefined)) | ||
| 94 | ); // fails | ||
| 95 | asm volatile ("" | ||
| 96 | : | ||
| 97 | : [_] "m" (@as(struct { x: u32, y: u8 }, undefined)) | ||
| 98 | ); // fails | ||
| 99 | asm volatile ("" | ||
| 100 | : | ||
| 101 | : [_] "m" (@as(union { x: u32, y: u8 }, undefined)) | ||
| 102 | ); // fails | ||
| 103 | } | ||
| 104 | |||
| 105 | extern fn this_is_my_alias() i32; | ||
| 106 | |||
| 107 | export fn derp() i32 { | ||
| 108 | return 1234; | ||
| 109 | } | ||
test/behavior/async_fn.zig created+1676| ... | @@ -0,0 +1,1676 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 6 | const expectError = std.testing.expectError; | ||
| 7 | |||
| 8 | var global_x: i32 = 1; | ||
| 9 | |||
| 10 | test "simple coroutine suspend and resume" { | ||
| 11 | var frame = async simpleAsyncFn(); | ||
| 12 | try expect(global_x == 2); | ||
| 13 | resume frame; | ||
| 14 | try expect(global_x == 3); | ||
| 15 | const af: anyframe->void = &frame; | ||
| 16 | resume frame; | ||
| 17 | try expect(global_x == 4); | ||
| 18 | } | ||
| 19 | fn simpleAsyncFn() void { | ||
| 20 | global_x += 1; | ||
| 21 | suspend {} | ||
| 22 | global_x += 1; | ||
| 23 | suspend {} | ||
| 24 | global_x += 1; | ||
| 25 | } | ||
| 26 | |||
| 27 | var global_y: i32 = 1; | ||
| 28 | |||
| 29 | test "pass parameter to coroutine" { | ||
| 30 | var p = async simpleAsyncFnWithArg(2); | ||
| 31 | try expect(global_y == 3); | ||
| 32 | resume p; | ||
| 33 | try expect(global_y == 5); | ||
| 34 | } | ||
| 35 | fn simpleAsyncFnWithArg(delta: i32) void { | ||
| 36 | global_y += delta; | ||
| 37 | suspend {} | ||
| 38 | global_y += delta; | ||
| 39 | } | ||
| 40 | |||
| 41 | test "suspend at end of function" { | ||
| 42 | const S = struct { | ||
| 43 | var x: i32 = 1; | ||
| 44 | |||
| 45 | fn doTheTest() !void { | ||
| 46 | try expect(x == 1); | ||
| 47 | const p = async suspendAtEnd(); | ||
| 48 | try expect(x == 2); | ||
| 49 | } | ||
| 50 | |||
| 51 | fn suspendAtEnd() void { | ||
| 52 | x += 1; | ||
| 53 | suspend {} | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | try S.doTheTest(); | ||
| 57 | } | ||
| 58 | |||
| 59 | test "local variable in async function" { | ||
| 60 | const S = struct { | ||
| 61 | var x: i32 = 0; | ||
| 62 | |||
| 63 | fn doTheTest() !void { | ||
| 64 | try expect(x == 0); | ||
| 65 | var p = async add(1, 2); | ||
| 66 | try expect(x == 0); | ||
| 67 | resume p; | ||
| 68 | try expect(x == 0); | ||
| 69 | resume p; | ||
| 70 | try expect(x == 0); | ||
| 71 | resume p; | ||
| 72 | try expect(x == 3); | ||
| 73 | } | ||
| 74 | |||
| 75 | fn add(a: i32, b: i32) void { | ||
| 76 | var accum: i32 = 0; | ||
| 77 | suspend {} | ||
| 78 | accum += a; | ||
| 79 | suspend {} | ||
| 80 | accum += b; | ||
| 81 | suspend {} | ||
| 82 | x = accum; | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | try S.doTheTest(); | ||
| 86 | } | ||
| 87 | |||
| 88 | test "calling an inferred async function" { | ||
| 89 | const S = struct { | ||
| 90 | var x: i32 = 1; | ||
| 91 | var other_frame: *@Frame(other) = undefined; | ||
| 92 | |||
| 93 | fn doTheTest() !void { | ||
| 94 | _ = async first(); | ||
| 95 | try expect(x == 1); | ||
| 96 | resume other_frame.*; | ||
| 97 | try expect(x == 2); | ||
| 98 | } | ||
| 99 | |||
| 100 | fn first() void { | ||
| 101 | other(); | ||
| 102 | } | ||
| 103 | fn other() void { | ||
| 104 | other_frame = @frame(); | ||
| 105 | suspend {} | ||
| 106 | x += 1; | ||
| 107 | } | ||
| 108 | }; | ||
| 109 | try S.doTheTest(); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "@frameSize" { | ||
| 113 | if (builtin.target.cpu.arch == .thumb or builtin.target.cpu.arch == .thumbeb) | ||
| 114 | return error.SkipZigTest; | ||
| 115 | |||
| 116 | const S = struct { | ||
| 117 | fn doTheTest() !void { | ||
| 118 | { | ||
| 119 | var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); | ||
| 120 | const size = @frameSize(ptr); | ||
| 121 | try expect(size == @sizeOf(@Frame(other))); | ||
| 122 | } | ||
| 123 | { | ||
| 124 | var ptr = @ptrCast(fn () callconv(.Async) void, first); | ||
| 125 | const size = @frameSize(ptr); | ||
| 126 | try expect(size == @sizeOf(@Frame(first))); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | fn first() void { | ||
| 131 | other(1); | ||
| 132 | } | ||
| 133 | fn other(param: i32) void { | ||
| 134 | var local: i32 = undefined; | ||
| 135 | suspend {} | ||
| 136 | } | ||
| 137 | }; | ||
| 138 | try S.doTheTest(); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "coroutine suspend, resume" { | ||
| 142 | const S = struct { | ||
| 143 | var frame: anyframe = undefined; | ||
| 144 | |||
| 145 | fn doTheTest() !void { | ||
| 146 | _ = async amain(); | ||
| 147 | seq('d'); | ||
| 148 | resume frame; | ||
| 149 | seq('h'); | ||
| 150 | |||
| 151 | try expect(std.mem.eql(u8, &points, "abcdefgh")); | ||
| 152 | } | ||
| 153 | |||
| 154 | fn amain() void { | ||
| 155 | seq('a'); | ||
| 156 | var f = async testAsyncSeq(); | ||
| 157 | seq('c'); | ||
| 158 | await f; | ||
| 159 | seq('g'); | ||
| 160 | } | ||
| 161 | |||
| 162 | fn testAsyncSeq() void { | ||
| 163 | defer seq('f'); | ||
| 164 | |||
| 165 | seq('b'); | ||
| 166 | suspend { | ||
| 167 | frame = @frame(); | ||
| 168 | } | ||
| 169 | seq('e'); | ||
| 170 | } | ||
| 171 | var points = [_]u8{'x'} ** "abcdefgh".len; | ||
| 172 | var index: usize = 0; | ||
| 173 | |||
| 174 | fn seq(c: u8) void { | ||
| 175 | points[index] = c; | ||
| 176 | index += 1; | ||
| 177 | } | ||
| 178 | }; | ||
| 179 | try S.doTheTest(); | ||
| 180 | } | ||
| 181 | |||
| 182 | test "coroutine suspend with block" { | ||
| 183 | const p = async testSuspendBlock(); | ||
| 184 | try expect(!global_result); | ||
| 185 | resume a_promise; | ||
| 186 | try expect(global_result); | ||
| 187 | } | ||
| 188 | |||
| 189 | var a_promise: anyframe = undefined; | ||
| 190 | var global_result = false; | ||
| 191 | fn testSuspendBlock() callconv(.Async) void { | ||
| 192 | suspend { | ||
| 193 | comptime expect(@TypeOf(@frame()) == *@Frame(testSuspendBlock)) catch unreachable; | ||
| 194 | a_promise = @frame(); | ||
| 195 | } | ||
| 196 | |||
| 197 | // Test to make sure that @frame() works as advertised (issue #1296) | ||
| 198 | // var our_handle: anyframe = @frame(); | ||
| 199 | expect(a_promise == @as(anyframe, @frame())) catch @panic("test failed"); | ||
| 200 | |||
| 201 | global_result = true; | ||
| 202 | } | ||
| 203 | |||
| 204 | var await_a_promise: anyframe = undefined; | ||
| 205 | var await_final_result: i32 = 0; | ||
| 206 | |||
| 207 | test "coroutine await" { | ||
| 208 | await_seq('a'); | ||
| 209 | var p = async await_amain(); | ||
| 210 | await_seq('f'); | ||
| 211 | resume await_a_promise; | ||
| 212 | await_seq('i'); | ||
| 213 | try expect(await_final_result == 1234); | ||
| 214 | try expect(std.mem.eql(u8, &await_points, "abcdefghi")); | ||
| 215 | } | ||
| 216 | fn await_amain() callconv(.Async) void { | ||
| 217 | await_seq('b'); | ||
| 218 | var p = async await_another(); | ||
| 219 | await_seq('e'); | ||
| 220 | await_final_result = await p; | ||
| 221 | await_seq('h'); | ||
| 222 | } | ||
| 223 | fn await_another() callconv(.Async) i32 { | ||
| 224 | await_seq('c'); | ||
| 225 | suspend { | ||
| 226 | await_seq('d'); | ||
| 227 | await_a_promise = @frame(); | ||
| 228 | } | ||
| 229 | await_seq('g'); | ||
| 230 | return 1234; | ||
| 231 | } | ||
| 232 | |||
| 233 | var await_points = [_]u8{0} ** "abcdefghi".len; | ||
| 234 | var await_seq_index: usize = 0; | ||
| 235 | |||
| 236 | fn await_seq(c: u8) void { | ||
| 237 | await_points[await_seq_index] = c; | ||
| 238 | await_seq_index += 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | var early_final_result: i32 = 0; | ||
| 242 | |||
| 243 | test "coroutine await early return" { | ||
| 244 | early_seq('a'); | ||
| 245 | var p = async early_amain(); | ||
| 246 | early_seq('f'); | ||
| 247 | try expect(early_final_result == 1234); | ||
| 248 | try expect(std.mem.eql(u8, &early_points, "abcdef")); | ||
| 249 | } | ||
| 250 | fn early_amain() callconv(.Async) void { | ||
| 251 | early_seq('b'); | ||
| 252 | var p = async early_another(); | ||
| 253 | early_seq('d'); | ||
| 254 | early_final_result = await p; | ||
| 255 | early_seq('e'); | ||
| 256 | } | ||
| 257 | fn early_another() callconv(.Async) i32 { | ||
| 258 | early_seq('c'); | ||
| 259 | return 1234; | ||
| 260 | } | ||
| 261 | |||
| 262 | var early_points = [_]u8{0} ** "abcdef".len; | ||
| 263 | var early_seq_index: usize = 0; | ||
| 264 | |||
| 265 | fn early_seq(c: u8) void { | ||
| 266 | early_points[early_seq_index] = c; | ||
| 267 | early_seq_index += 1; | ||
| 268 | } | ||
| 269 | |||
| 270 | test "async function with dot syntax" { | ||
| 271 | const S = struct { | ||
| 272 | var y: i32 = 1; | ||
| 273 | fn foo() callconv(.Async) void { | ||
| 274 | y += 1; | ||
| 275 | suspend {} | ||
| 276 | } | ||
| 277 | }; | ||
| 278 | const p = async S.foo(); | ||
| 279 | try expect(S.y == 2); | ||
| 280 | } | ||
| 281 | |||
| 282 | test "async fn pointer in a struct field" { | ||
| 283 | var data: i32 = 1; | ||
| 284 | const Foo = struct { | ||
| 285 | bar: fn (*i32) callconv(.Async) void, | ||
| 286 | }; | ||
| 287 | var foo = Foo{ .bar = simpleAsyncFn2 }; | ||
| 288 | var bytes: [64]u8 align(16) = undefined; | ||
| 289 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | ||
| 290 | comptime try expect(@TypeOf(f) == anyframe->void); | ||
| 291 | try expect(data == 2); | ||
| 292 | resume f; | ||
| 293 | try expect(data == 4); | ||
| 294 | _ = async doTheAwait(f); | ||
| 295 | try expect(data == 4); | ||
| 296 | } | ||
| 297 | |||
| 298 | fn doTheAwait(f: anyframe->void) void { | ||
| 299 | await f; | ||
| 300 | } | ||
| 301 | fn simpleAsyncFn2(y: *i32) callconv(.Async) void { | ||
| 302 | defer y.* += 2; | ||
| 303 | y.* += 1; | ||
| 304 | suspend {} | ||
| 305 | } | ||
| 306 | |||
| 307 | test "@asyncCall with return type" { | ||
| 308 | const Foo = struct { | ||
| 309 | bar: fn () callconv(.Async) i32, | ||
| 310 | |||
| 311 | var global_frame: anyframe = undefined; | ||
| 312 | fn middle() callconv(.Async) i32 { | ||
| 313 | return afunc(); | ||
| 314 | } | ||
| 315 | |||
| 316 | fn afunc() i32 { | ||
| 317 | global_frame = @frame(); | ||
| 318 | suspend {} | ||
| 319 | return 1234; | ||
| 320 | } | ||
| 321 | }; | ||
| 322 | var foo = Foo{ .bar = Foo.middle }; | ||
| 323 | var bytes: [150]u8 align(16) = undefined; | ||
| 324 | var aresult: i32 = 0; | ||
| 325 | _ = @asyncCall(&bytes, &aresult, foo.bar, .{}); | ||
| 326 | try expect(aresult == 0); | ||
| 327 | resume Foo.global_frame; | ||
| 328 | try expect(aresult == 1234); | ||
| 329 | } | ||
| 330 | |||
| 331 | test "async fn with inferred error set" { | ||
| 332 | const S = struct { | ||
| 333 | var global_frame: anyframe = undefined; | ||
| 334 | |||
| 335 | fn doTheTest() !void { | ||
| 336 | var frame: [1]@Frame(middle) = undefined; | ||
| 337 | var fn_ptr = middle; | ||
| 338 | var result: @typeInfo(@typeInfo(@TypeOf(fn_ptr)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; | ||
| 339 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); | ||
| 340 | resume global_frame; | ||
| 341 | try std.testing.expectError(error.Fail, result); | ||
| 342 | } | ||
| 343 | fn middle() callconv(.Async) !void { | ||
| 344 | var f = async middle2(); | ||
| 345 | return await f; | ||
| 346 | } | ||
| 347 | |||
| 348 | fn middle2() !void { | ||
| 349 | return failing(); | ||
| 350 | } | ||
| 351 | |||
| 352 | fn failing() !void { | ||
| 353 | global_frame = @frame(); | ||
| 354 | suspend {} | ||
| 355 | return error.Fail; | ||
| 356 | } | ||
| 357 | }; | ||
| 358 | try S.doTheTest(); | ||
| 359 | } | ||
| 360 | |||
| 361 | test "error return trace across suspend points - early return" { | ||
| 362 | const p = nonFailing(); | ||
| 363 | resume p; | ||
| 364 | const p2 = async printTrace(p); | ||
| 365 | } | ||
| 366 | |||
| 367 | test "error return trace across suspend points - async return" { | ||
| 368 | const p = nonFailing(); | ||
| 369 | const p2 = async printTrace(p); | ||
| 370 | resume p; | ||
| 371 | } | ||
| 372 | |||
| 373 | fn nonFailing() (anyframe->anyerror!void) { | ||
| 374 | const Static = struct { | ||
| 375 | var frame: @Frame(suspendThenFail) = undefined; | ||
| 376 | }; | ||
| 377 | Static.frame = async suspendThenFail(); | ||
| 378 | return &Static.frame; | ||
| 379 | } | ||
| 380 | fn suspendThenFail() callconv(.Async) anyerror!void { | ||
| 381 | suspend {} | ||
| 382 | return error.Fail; | ||
| 383 | } | ||
| 384 | fn printTrace(p: anyframe->(anyerror!void)) callconv(.Async) void { | ||
| 385 | (await p) catch |e| { | ||
| 386 | std.testing.expect(e == error.Fail) catch @panic("test failure"); | ||
| 387 | if (@errorReturnTrace()) |trace| { | ||
| 388 | expect(trace.index == 1) catch @panic("test failure"); | ||
| 389 | } else switch (builtin.mode) { | ||
| 390 | .Debug, .ReleaseSafe => @panic("expected return trace"), | ||
| 391 | .ReleaseFast, .ReleaseSmall => {}, | ||
| 392 | } | ||
| 393 | }; | ||
| 394 | } | ||
| 395 | |||
| 396 | test "break from suspend" { | ||
| 397 | var my_result: i32 = 1; | ||
| 398 | const p = async testBreakFromSuspend(&my_result); | ||
| 399 | try std.testing.expect(my_result == 2); | ||
| 400 | } | ||
| 401 | fn testBreakFromSuspend(my_result: *i32) callconv(.Async) void { | ||
| 402 | suspend { | ||
| 403 | resume @frame(); | ||
| 404 | } | ||
| 405 | my_result.* += 1; | ||
| 406 | suspend {} | ||
| 407 | my_result.* += 1; | ||
| 408 | } | ||
| 409 | |||
| 410 | test "heap allocated async function frame" { | ||
| 411 | const S = struct { | ||
| 412 | var x: i32 = 42; | ||
| 413 | |||
| 414 | fn doTheTest() !void { | ||
| 415 | const frame = try std.testing.allocator.create(@Frame(someFunc)); | ||
| 416 | defer std.testing.allocator.destroy(frame); | ||
| 417 | |||
| 418 | try expect(x == 42); | ||
| 419 | frame.* = async someFunc(); | ||
| 420 | try expect(x == 43); | ||
| 421 | resume frame; | ||
| 422 | try expect(x == 44); | ||
| 423 | } | ||
| 424 | |||
| 425 | fn someFunc() void { | ||
| 426 | x += 1; | ||
| 427 | suspend {} | ||
| 428 | x += 1; | ||
| 429 | } | ||
| 430 | }; | ||
| 431 | try S.doTheTest(); | ||
| 432 | } | ||
| 433 | |||
| 434 | test "async function call return value" { | ||
| 435 | const S = struct { | ||
| 436 | var frame: anyframe = undefined; | ||
| 437 | var pt = Point{ .x = 10, .y = 11 }; | ||
| 438 | |||
| 439 | fn doTheTest() !void { | ||
| 440 | try expectEqual(pt.x, 10); | ||
| 441 | try expectEqual(pt.y, 11); | ||
| 442 | _ = async first(); | ||
| 443 | try expectEqual(pt.x, 10); | ||
| 444 | try expectEqual(pt.y, 11); | ||
| 445 | resume frame; | ||
| 446 | try expectEqual(pt.x, 1); | ||
| 447 | try expectEqual(pt.y, 2); | ||
| 448 | } | ||
| 449 | |||
| 450 | fn first() void { | ||
| 451 | pt = second(1, 2); | ||
| 452 | } | ||
| 453 | |||
| 454 | fn second(x: i32, y: i32) Point { | ||
| 455 | return other(x, y); | ||
| 456 | } | ||
| 457 | |||
| 458 | fn other(x: i32, y: i32) Point { | ||
| 459 | frame = @frame(); | ||
| 460 | suspend {} | ||
| 461 | return Point{ | ||
| 462 | .x = x, | ||
| 463 | .y = y, | ||
| 464 | }; | ||
| 465 | } | ||
| 466 | |||
| 467 | const Point = struct { | ||
| 468 | x: i32, | ||
| 469 | y: i32, | ||
| 470 | }; | ||
| 471 | }; | ||
| 472 | try S.doTheTest(); | ||
| 473 | } | ||
| 474 | |||
| 475 | test "suspension points inside branching control flow" { | ||
| 476 | const S = struct { | ||
| 477 | var result: i32 = 10; | ||
| 478 | |||
| 479 | fn doTheTest() !void { | ||
| 480 | try expect(10 == result); | ||
| 481 | var frame = async func(true); | ||
| 482 | try expect(10 == result); | ||
| 483 | resume frame; | ||
| 484 | try expect(11 == result); | ||
| 485 | resume frame; | ||
| 486 | try expect(12 == result); | ||
| 487 | resume frame; | ||
| 488 | try expect(13 == result); | ||
| 489 | } | ||
| 490 | |||
| 491 | fn func(b: bool) void { | ||
| 492 | while (b) { | ||
| 493 | suspend {} | ||
| 494 | result += 1; | ||
| 495 | } | ||
| 496 | } | ||
| 497 | }; | ||
| 498 | try S.doTheTest(); | ||
| 499 | } | ||
| 500 | |||
| 501 | test "call async function which has struct return type" { | ||
| 502 | const S = struct { | ||
| 503 | var frame: anyframe = undefined; | ||
| 504 | |||
| 505 | fn doTheTest() void { | ||
| 506 | _ = async atest(); | ||
| 507 | resume frame; | ||
| 508 | } | ||
| 509 | |||
| 510 | fn atest() void { | ||
| 511 | const result = func(); | ||
| 512 | expect(result.x == 5) catch @panic("test failed"); | ||
| 513 | expect(result.y == 6) catch @panic("test failed"); | ||
| 514 | } | ||
| 515 | |||
| 516 | const Point = struct { | ||
| 517 | x: usize, | ||
| 518 | y: usize, | ||
| 519 | }; | ||
| 520 | |||
| 521 | fn func() Point { | ||
| 522 | suspend { | ||
| 523 | frame = @frame(); | ||
| 524 | } | ||
| 525 | return Point{ | ||
| 526 | .x = 5, | ||
| 527 | .y = 6, | ||
| 528 | }; | ||
| 529 | } | ||
| 530 | }; | ||
| 531 | S.doTheTest(); | ||
| 532 | } | ||
| 533 | |||
| 534 | test "pass string literal to async function" { | ||
| 535 | const S = struct { | ||
| 536 | var frame: anyframe = undefined; | ||
| 537 | var ok: bool = false; | ||
| 538 | |||
| 539 | fn doTheTest() !void { | ||
| 540 | _ = async hello("hello"); | ||
| 541 | resume frame; | ||
| 542 | try expect(ok); | ||
| 543 | } | ||
| 544 | |||
| 545 | fn hello(msg: []const u8) void { | ||
| 546 | frame = @frame(); | ||
| 547 | suspend {} | ||
| 548 | expectEqualStrings("hello", msg) catch @panic("test failed"); | ||
| 549 | ok = true; | ||
| 550 | } | ||
| 551 | }; | ||
| 552 | try S.doTheTest(); | ||
| 553 | } | ||
| 554 | |||
| 555 | test "await inside an errdefer" { | ||
| 556 | const S = struct { | ||
| 557 | var frame: anyframe = undefined; | ||
| 558 | |||
| 559 | fn doTheTest() !void { | ||
| 560 | _ = async amainWrap(); | ||
| 561 | resume frame; | ||
| 562 | } | ||
| 563 | |||
| 564 | fn amainWrap() !void { | ||
| 565 | var foo = async func(); | ||
| 566 | errdefer await foo; | ||
| 567 | return error.Bad; | ||
| 568 | } | ||
| 569 | |||
| 570 | fn func() void { | ||
| 571 | frame = @frame(); | ||
| 572 | suspend {} | ||
| 573 | } | ||
| 574 | }; | ||
| 575 | try S.doTheTest(); | ||
| 576 | } | ||
| 577 | |||
| 578 | test "try in an async function with error union and non-zero-bit payload" { | ||
| 579 | const S = struct { | ||
| 580 | var frame: anyframe = undefined; | ||
| 581 | var ok = false; | ||
| 582 | |||
| 583 | fn doTheTest() !void { | ||
| 584 | _ = async amain(); | ||
| 585 | resume frame; | ||
| 586 | try expect(ok); | ||
| 587 | } | ||
| 588 | |||
| 589 | fn amain() void { | ||
| 590 | std.testing.expectError(error.Bad, theProblem()) catch @panic("test failed"); | ||
| 591 | ok = true; | ||
| 592 | } | ||
| 593 | |||
| 594 | fn theProblem() ![]u8 { | ||
| 595 | frame = @frame(); | ||
| 596 | suspend {} | ||
| 597 | const result = try other(); | ||
| 598 | return result; | ||
| 599 | } | ||
| 600 | |||
| 601 | fn other() ![]u8 { | ||
| 602 | return error.Bad; | ||
| 603 | } | ||
| 604 | }; | ||
| 605 | try S.doTheTest(); | ||
| 606 | } | ||
| 607 | |||
| 608 | test "returning a const error from async function" { | ||
| 609 | const S = struct { | ||
| 610 | var frame: anyframe = undefined; | ||
| 611 | var ok = false; | ||
| 612 | |||
| 613 | fn doTheTest() !void { | ||
| 614 | _ = async amain(); | ||
| 615 | resume frame; | ||
| 616 | try expect(ok); | ||
| 617 | } | ||
| 618 | |||
| 619 | fn amain() !void { | ||
| 620 | var download_frame = async fetchUrl(10, "a string"); | ||
| 621 | const download_text = try await download_frame; | ||
| 622 | |||
| 623 | @panic("should not get here"); | ||
| 624 | } | ||
| 625 | |||
| 626 | fn fetchUrl(unused: i32, url: []const u8) ![]u8 { | ||
| 627 | frame = @frame(); | ||
| 628 | suspend {} | ||
| 629 | ok = true; | ||
| 630 | return error.OutOfMemory; | ||
| 631 | } | ||
| 632 | }; | ||
| 633 | try S.doTheTest(); | ||
| 634 | } | ||
| 635 | |||
| 636 | test "async/await typical usage" { | ||
| 637 | inline for ([_]bool{ false, true }) |b1| { | ||
| 638 | inline for ([_]bool{ false, true }) |b2| { | ||
| 639 | inline for ([_]bool{ false, true }) |b3| { | ||
| 640 | inline for ([_]bool{ false, true }) |b4| { | ||
| 641 | testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest(); | ||
| 642 | } | ||
| 643 | } | ||
| 644 | } | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 648 | fn testAsyncAwaitTypicalUsage( | ||
| 649 | comptime simulate_fail_download: bool, | ||
| 650 | comptime simulate_fail_file: bool, | ||
| 651 | comptime suspend_download: bool, | ||
| 652 | comptime suspend_file: bool, | ||
| 653 | ) type { | ||
| 654 | return struct { | ||
| 655 | fn doTheTest() void { | ||
| 656 | _ = async amainWrap(); | ||
| 657 | if (suspend_file) { | ||
| 658 | resume global_file_frame; | ||
| 659 | } | ||
| 660 | if (suspend_download) { | ||
| 661 | resume global_download_frame; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | fn amainWrap() void { | ||
| 665 | if (amain()) |_| { | ||
| 666 | expect(!simulate_fail_download) catch @panic("test failure"); | ||
| 667 | expect(!simulate_fail_file) catch @panic("test failure"); | ||
| 668 | } else |e| switch (e) { | ||
| 669 | error.NoResponse => expect(simulate_fail_download) catch @panic("test failure"), | ||
| 670 | error.FileNotFound => expect(simulate_fail_file) catch @panic("test failure"), | ||
| 671 | else => @panic("test failure"), | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | fn amain() !void { | ||
| 676 | const allocator = std.testing.allocator; | ||
| 677 | var download_frame = async fetchUrl(allocator, "https://example.com/"); | ||
| 678 | var download_awaited = false; | ||
| 679 | errdefer if (!download_awaited) { | ||
| 680 | if (await download_frame) |x| allocator.free(x) else |_| {} | ||
| 681 | }; | ||
| 682 | |||
| 683 | var file_frame = async readFile(allocator, "something.txt"); | ||
| 684 | var file_awaited = false; | ||
| 685 | errdefer if (!file_awaited) { | ||
| 686 | if (await file_frame) |x| allocator.free(x) else |_| {} | ||
| 687 | }; | ||
| 688 | |||
| 689 | download_awaited = true; | ||
| 690 | const download_text = try await download_frame; | ||
| 691 | defer allocator.free(download_text); | ||
| 692 | |||
| 693 | file_awaited = true; | ||
| 694 | const file_text = try await file_frame; | ||
| 695 | defer allocator.free(file_text); | ||
| 696 | |||
| 697 | try expect(std.mem.eql(u8, "expected download text", download_text)); | ||
| 698 | try expect(std.mem.eql(u8, "expected file text", file_text)); | ||
| 699 | } | ||
| 700 | |||
| 701 | var global_download_frame: anyframe = undefined; | ||
| 702 | fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 { | ||
| 703 | const result = try std.mem.dupe(allocator, u8, "expected download text"); | ||
| 704 | errdefer allocator.free(result); | ||
| 705 | if (suspend_download) { | ||
| 706 | suspend { | ||
| 707 | global_download_frame = @frame(); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | if (simulate_fail_download) return error.NoResponse; | ||
| 711 | return result; | ||
| 712 | } | ||
| 713 | |||
| 714 | var global_file_frame: anyframe = undefined; | ||
| 715 | fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 { | ||
| 716 | const result = try std.mem.dupe(allocator, u8, "expected file text"); | ||
| 717 | errdefer allocator.free(result); | ||
| 718 | if (suspend_file) { | ||
| 719 | suspend { | ||
| 720 | global_file_frame = @frame(); | ||
| 721 | } | ||
| 722 | } | ||
| 723 | if (simulate_fail_file) return error.FileNotFound; | ||
| 724 | return result; | ||
| 725 | } | ||
| 726 | }; | ||
| 727 | } | ||
| 728 | |||
| 729 | test "alignment of local variables in async functions" { | ||
| 730 | const S = struct { | ||
| 731 | fn doTheTest() !void { | ||
| 732 | var y: u8 = 123; | ||
| 733 | var x: u8 align(128) = 1; | ||
| 734 | try expect(@ptrToInt(&x) % 128 == 0); | ||
| 735 | } | ||
| 736 | }; | ||
| 737 | try S.doTheTest(); | ||
| 738 | } | ||
| 739 | |||
| 740 | test "no reason to resolve frame still works" { | ||
| 741 | _ = async simpleNothing(); | ||
| 742 | } | ||
| 743 | fn simpleNothing() void { | ||
| 744 | var x: i32 = 1234; | ||
| 745 | } | ||
| 746 | |||
| 747 | test "async call a generic function" { | ||
| 748 | const S = struct { | ||
| 749 | fn doTheTest() !void { | ||
| 750 | var f = async func(i32, 2); | ||
| 751 | const result = await f; | ||
| 752 | try expect(result == 3); | ||
| 753 | } | ||
| 754 | |||
| 755 | fn func(comptime T: type, inc: T) T { | ||
| 756 | var x: T = 1; | ||
| 757 | suspend { | ||
| 758 | resume @frame(); | ||
| 759 | } | ||
| 760 | x += inc; | ||
| 761 | return x; | ||
| 762 | } | ||
| 763 | }; | ||
| 764 | _ = async S.doTheTest(); | ||
| 765 | } | ||
| 766 | |||
| 767 | test "return from suspend block" { | ||
| 768 | const S = struct { | ||
| 769 | fn doTheTest() !void { | ||
| 770 | expect(func() == 1234) catch @panic("test failure"); | ||
| 771 | } | ||
| 772 | fn func() i32 { | ||
| 773 | suspend { | ||
| 774 | return 1234; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | }; | ||
| 778 | _ = async S.doTheTest(); | ||
| 779 | } | ||
| 780 | |||
| 781 | test "struct parameter to async function is copied to the frame" { | ||
| 782 | const S = struct { | ||
| 783 | const Point = struct { | ||
| 784 | x: i32, | ||
| 785 | y: i32, | ||
| 786 | }; | ||
| 787 | |||
| 788 | var frame: anyframe = undefined; | ||
| 789 | |||
| 790 | fn doTheTest() void { | ||
| 791 | _ = async atest(); | ||
| 792 | resume frame; | ||
| 793 | } | ||
| 794 | |||
| 795 | fn atest() void { | ||
| 796 | var f: @Frame(foo) = undefined; | ||
| 797 | bar(&f); | ||
| 798 | clobberStack(10); | ||
| 799 | } | ||
| 800 | |||
| 801 | fn clobberStack(x: i32) void { | ||
| 802 | if (x == 0) return; | ||
| 803 | clobberStack(x - 1); | ||
| 804 | var y: i32 = x; | ||
| 805 | } | ||
| 806 | |||
| 807 | fn bar(f: *@Frame(foo)) void { | ||
| 808 | var pt = Point{ .x = 1, .y = 2 }; | ||
| 809 | f.* = async foo(pt); | ||
| 810 | var result = await f; | ||
| 811 | expect(result == 1) catch @panic("test failure"); | ||
| 812 | } | ||
| 813 | |||
| 814 | fn foo(point: Point) i32 { | ||
| 815 | suspend { | ||
| 816 | frame = @frame(); | ||
| 817 | } | ||
| 818 | return point.x; | ||
| 819 | } | ||
| 820 | }; | ||
| 821 | S.doTheTest(); | ||
| 822 | } | ||
| 823 | |||
| 824 | test "cast fn to async fn when it is inferred to be async" { | ||
| 825 | const S = struct { | ||
| 826 | var frame: anyframe = undefined; | ||
| 827 | var ok = false; | ||
| 828 | |||
| 829 | fn doTheTest() void { | ||
| 830 | var ptr: fn () callconv(.Async) i32 = undefined; | ||
| 831 | ptr = func; | ||
| 832 | var buf: [100]u8 align(16) = undefined; | ||
| 833 | var result: i32 = undefined; | ||
| 834 | const f = @asyncCall(&buf, &result, ptr, .{}); | ||
| 835 | _ = await f; | ||
| 836 | expect(result == 1234) catch @panic("test failure"); | ||
| 837 | ok = true; | ||
| 838 | } | ||
| 839 | |||
| 840 | fn func() i32 { | ||
| 841 | suspend { | ||
| 842 | frame = @frame(); | ||
| 843 | } | ||
| 844 | return 1234; | ||
| 845 | } | ||
| 846 | }; | ||
| 847 | _ = async S.doTheTest(); | ||
| 848 | resume S.frame; | ||
| 849 | try expect(S.ok); | ||
| 850 | } | ||
| 851 | |||
| 852 | test "cast fn to async fn when it is inferred to be async, awaited directly" { | ||
| 853 | const S = struct { | ||
| 854 | var frame: anyframe = undefined; | ||
| 855 | var ok = false; | ||
| 856 | |||
| 857 | fn doTheTest() void { | ||
| 858 | var ptr: fn () callconv(.Async) i32 = undefined; | ||
| 859 | ptr = func; | ||
| 860 | var buf: [100]u8 align(16) = undefined; | ||
| 861 | var result: i32 = undefined; | ||
| 862 | _ = await @asyncCall(&buf, &result, ptr, .{}); | ||
| 863 | expect(result == 1234) catch @panic("test failure"); | ||
| 864 | ok = true; | ||
| 865 | } | ||
| 866 | |||
| 867 | fn func() i32 { | ||
| 868 | suspend { | ||
| 869 | frame = @frame(); | ||
| 870 | } | ||
| 871 | return 1234; | ||
| 872 | } | ||
| 873 | }; | ||
| 874 | _ = async S.doTheTest(); | ||
| 875 | resume S.frame; | ||
| 876 | try expect(S.ok); | ||
| 877 | } | ||
| 878 | |||
| 879 | test "await does not force async if callee is blocking" { | ||
| 880 | const S = struct { | ||
| 881 | fn simple() i32 { | ||
| 882 | return 1234; | ||
| 883 | } | ||
| 884 | }; | ||
| 885 | var x = async S.simple(); | ||
| 886 | try expect(await x == 1234); | ||
| 887 | } | ||
| 888 | |||
| 889 | test "recursive async function" { | ||
| 890 | try expect(recursiveAsyncFunctionTest(false).doTheTest() == 55); | ||
| 891 | try expect(recursiveAsyncFunctionTest(true).doTheTest() == 55); | ||
| 892 | } | ||
| 893 | |||
| 894 | fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type { | ||
| 895 | return struct { | ||
| 896 | fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 { | ||
| 897 | if (x <= 1) return x; | ||
| 898 | |||
| 899 | if (suspending_implementation) { | ||
| 900 | suspend { | ||
| 901 | resume @frame(); | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | const f1 = try allocator.create(@Frame(fib)); | ||
| 906 | defer allocator.destroy(f1); | ||
| 907 | |||
| 908 | const f2 = try allocator.create(@Frame(fib)); | ||
| 909 | defer allocator.destroy(f2); | ||
| 910 | |||
| 911 | f1.* = async fib(allocator, x - 1); | ||
| 912 | var f1_awaited = false; | ||
| 913 | errdefer if (!f1_awaited) { | ||
| 914 | _ = await f1; | ||
| 915 | }; | ||
| 916 | |||
| 917 | f2.* = async fib(allocator, x - 2); | ||
| 918 | var f2_awaited = false; | ||
| 919 | errdefer if (!f2_awaited) { | ||
| 920 | _ = await f2; | ||
| 921 | }; | ||
| 922 | |||
| 923 | var sum: u32 = 0; | ||
| 924 | |||
| 925 | f1_awaited = true; | ||
| 926 | sum += try await f1; | ||
| 927 | |||
| 928 | f2_awaited = true; | ||
| 929 | sum += try await f2; | ||
| 930 | |||
| 931 | return sum; | ||
| 932 | } | ||
| 933 | |||
| 934 | fn doTheTest() u32 { | ||
| 935 | if (suspending_implementation) { | ||
| 936 | var result: u32 = undefined; | ||
| 937 | _ = async amain(&result); | ||
| 938 | return result; | ||
| 939 | } else { | ||
| 940 | return fib(std.testing.allocator, 10) catch unreachable; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | fn amain(result: *u32) void { | ||
| 945 | var x = async fib(std.testing.allocator, 10); | ||
| 946 | result.* = (await x) catch unreachable; | ||
| 947 | } | ||
| 948 | }; | ||
| 949 | } | ||
| 950 | |||
| 951 | test "@asyncCall with comptime-known function, but not awaited directly" { | ||
| 952 | const S = struct { | ||
| 953 | var global_frame: anyframe = undefined; | ||
| 954 | |||
| 955 | fn doTheTest() !void { | ||
| 956 | var frame: [1]@Frame(middle) = undefined; | ||
| 957 | var result: @typeInfo(@typeInfo(@TypeOf(middle)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; | ||
| 958 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); | ||
| 959 | resume global_frame; | ||
| 960 | try std.testing.expectError(error.Fail, result); | ||
| 961 | } | ||
| 962 | fn middle() callconv(.Async) !void { | ||
| 963 | var f = async middle2(); | ||
| 964 | return await f; | ||
| 965 | } | ||
| 966 | |||
| 967 | fn middle2() !void { | ||
| 968 | return failing(); | ||
| 969 | } | ||
| 970 | |||
| 971 | fn failing() !void { | ||
| 972 | global_frame = @frame(); | ||
| 973 | suspend {} | ||
| 974 | return error.Fail; | ||
| 975 | } | ||
| 976 | }; | ||
| 977 | try S.doTheTest(); | ||
| 978 | } | ||
| 979 | |||
| 980 | test "@asyncCall with actual frame instead of byte buffer" { | ||
| 981 | const S = struct { | ||
| 982 | fn func() i32 { | ||
| 983 | suspend {} | ||
| 984 | return 1234; | ||
| 985 | } | ||
| 986 | }; | ||
| 987 | var frame: @Frame(S.func) = undefined; | ||
| 988 | var result: i32 = undefined; | ||
| 989 | const ptr = @asyncCall(&frame, &result, S.func, .{}); | ||
| 990 | resume ptr; | ||
| 991 | try expect(result == 1234); | ||
| 992 | } | ||
| 993 | |||
| 994 | test "@asyncCall using the result location inside the frame" { | ||
| 995 | const S = struct { | ||
| 996 | fn simple2(y: *i32) callconv(.Async) i32 { | ||
| 997 | defer y.* += 2; | ||
| 998 | y.* += 1; | ||
| 999 | suspend {} | ||
| 1000 | return 1234; | ||
| 1001 | } | ||
| 1002 | fn getAnswer(f: anyframe->i32, out: *i32) void { | ||
| 1003 | out.* = await f; | ||
| 1004 | } | ||
| 1005 | }; | ||
| 1006 | var data: i32 = 1; | ||
| 1007 | const Foo = struct { | ||
| 1008 | bar: fn (*i32) callconv(.Async) i32, | ||
| 1009 | }; | ||
| 1010 | var foo = Foo{ .bar = S.simple2 }; | ||
| 1011 | var bytes: [64]u8 align(16) = undefined; | ||
| 1012 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | ||
| 1013 | comptime try expect(@TypeOf(f) == anyframe->i32); | ||
| 1014 | try expect(data == 2); | ||
| 1015 | resume f; | ||
| 1016 | try expect(data == 4); | ||
| 1017 | _ = async S.getAnswer(f, &data); | ||
| 1018 | try expect(data == 1234); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | test "@TypeOf an async function call of generic fn with error union type" { | ||
| 1022 | const S = struct { | ||
| 1023 | fn func(comptime x: anytype) anyerror!i32 { | ||
| 1024 | const T = @TypeOf(async func(x)); | ||
| 1025 | comptime try expect(T == @typeInfo(@TypeOf(@frame())).Pointer.child); | ||
| 1026 | return undefined; | ||
| 1027 | } | ||
| 1028 | }; | ||
| 1029 | _ = async S.func(i32); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | test "using @TypeOf on a generic function call" { | ||
| 1033 | const S = struct { | ||
| 1034 | var global_frame: anyframe = undefined; | ||
| 1035 | var global_ok = false; | ||
| 1036 | |||
| 1037 | var buf: [100]u8 align(16) = undefined; | ||
| 1038 | |||
| 1039 | fn amain(x: anytype) void { | ||
| 1040 | if (x == 0) { | ||
| 1041 | global_ok = true; | ||
| 1042 | return; | ||
| 1043 | } | ||
| 1044 | suspend { | ||
| 1045 | global_frame = @frame(); | ||
| 1046 | } | ||
| 1047 | const F = @TypeOf(async amain(x - 1)); | ||
| 1048 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | ||
| 1049 | return await @asyncCall(frame, {}, amain, .{x - 1}); | ||
| 1050 | } | ||
| 1051 | }; | ||
| 1052 | _ = async S.amain(@as(u32, 1)); | ||
| 1053 | resume S.global_frame; | ||
| 1054 | try expect(S.global_ok); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | test "recursive call of await @asyncCall with struct return type" { | ||
| 1058 | const S = struct { | ||
| 1059 | var global_frame: anyframe = undefined; | ||
| 1060 | var global_ok = false; | ||
| 1061 | |||
| 1062 | var buf: [100]u8 align(16) = undefined; | ||
| 1063 | |||
| 1064 | fn amain(x: anytype) Foo { | ||
| 1065 | if (x == 0) { | ||
| 1066 | global_ok = true; | ||
| 1067 | return Foo{ .x = 1, .y = 2, .z = 3 }; | ||
| 1068 | } | ||
| 1069 | suspend { | ||
| 1070 | global_frame = @frame(); | ||
| 1071 | } | ||
| 1072 | const F = @TypeOf(async amain(x - 1)); | ||
| 1073 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | ||
| 1074 | return await @asyncCall(frame, {}, amain, .{x - 1}); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | const Foo = struct { | ||
| 1078 | x: u64, | ||
| 1079 | y: u64, | ||
| 1080 | z: u64, | ||
| 1081 | }; | ||
| 1082 | }; | ||
| 1083 | var res: S.Foo = undefined; | ||
| 1084 | var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined; | ||
| 1085 | _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)}); | ||
| 1086 | resume S.global_frame; | ||
| 1087 | try expect(S.global_ok); | ||
| 1088 | try expect(res.x == 1); | ||
| 1089 | try expect(res.y == 2); | ||
| 1090 | try expect(res.z == 3); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | test "nosuspend function call" { | ||
| 1094 | const S = struct { | ||
| 1095 | fn doTheTest() !void { | ||
| 1096 | const result = nosuspend add(50, 100); | ||
| 1097 | try expect(result == 150); | ||
| 1098 | } | ||
| 1099 | fn add(a: i32, b: i32) i32 { | ||
| 1100 | if (a > 100) { | ||
| 1101 | suspend {} | ||
| 1102 | } | ||
| 1103 | return a + b; | ||
| 1104 | } | ||
| 1105 | }; | ||
| 1106 | try S.doTheTest(); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "await used in expression and awaiting fn with no suspend but async calling convention" { | ||
| 1110 | const S = struct { | ||
| 1111 | fn atest() void { | ||
| 1112 | var f1 = async add(1, 2); | ||
| 1113 | var f2 = async add(3, 4); | ||
| 1114 | |||
| 1115 | const sum = (await f1) + (await f2); | ||
| 1116 | expect(sum == 10) catch @panic("test failure"); | ||
| 1117 | } | ||
| 1118 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1119 | return a + b; | ||
| 1120 | } | ||
| 1121 | }; | ||
| 1122 | _ = async S.atest(); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | test "await used in expression after a fn call" { | ||
| 1126 | const S = struct { | ||
| 1127 | fn atest() void { | ||
| 1128 | var f1 = async add(3, 4); | ||
| 1129 | var sum: i32 = 0; | ||
| 1130 | sum = foo() + await f1; | ||
| 1131 | expect(sum == 8) catch @panic("test failure"); | ||
| 1132 | } | ||
| 1133 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1134 | return a + b; | ||
| 1135 | } | ||
| 1136 | fn foo() i32 { | ||
| 1137 | return 1; | ||
| 1138 | } | ||
| 1139 | }; | ||
| 1140 | _ = async S.atest(); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | test "async fn call used in expression after a fn call" { | ||
| 1144 | const S = struct { | ||
| 1145 | fn atest() void { | ||
| 1146 | var sum: i32 = 0; | ||
| 1147 | sum = foo() + add(3, 4); | ||
| 1148 | expect(sum == 8) catch @panic("test failure"); | ||
| 1149 | } | ||
| 1150 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1151 | return a + b; | ||
| 1152 | } | ||
| 1153 | fn foo() i32 { | ||
| 1154 | return 1; | ||
| 1155 | } | ||
| 1156 | }; | ||
| 1157 | _ = async S.atest(); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | test "suspend in for loop" { | ||
| 1161 | const S = struct { | ||
| 1162 | var global_frame: ?anyframe = null; | ||
| 1163 | |||
| 1164 | fn doTheTest() void { | ||
| 1165 | _ = async atest(); | ||
| 1166 | while (global_frame) |f| resume f; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | fn atest() void { | ||
| 1170 | expect(func(&[_]u8{ 1, 2, 3 }) == 6) catch @panic("test failure"); | ||
| 1171 | } | ||
| 1172 | fn func(stuff: []const u8) u32 { | ||
| 1173 | global_frame = @frame(); | ||
| 1174 | var sum: u32 = 0; | ||
| 1175 | for (stuff) |x| { | ||
| 1176 | suspend {} | ||
| 1177 | sum += x; | ||
| 1178 | } | ||
| 1179 | global_frame = null; | ||
| 1180 | return sum; | ||
| 1181 | } | ||
| 1182 | }; | ||
| 1183 | S.doTheTest(); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | test "suspend in while loop" { | ||
| 1187 | const S = struct { | ||
| 1188 | var global_frame: ?anyframe = null; | ||
| 1189 | |||
| 1190 | fn doTheTest() void { | ||
| 1191 | _ = async atest(); | ||
| 1192 | while (global_frame) |f| resume f; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | fn atest() void { | ||
| 1196 | expect(optional(6) == 6) catch @panic("test failure"); | ||
| 1197 | expect(errunion(6) == 6) catch @panic("test failure"); | ||
| 1198 | } | ||
| 1199 | fn optional(stuff: ?u32) u32 { | ||
| 1200 | global_frame = @frame(); | ||
| 1201 | defer global_frame = null; | ||
| 1202 | while (stuff) |val| { | ||
| 1203 | suspend {} | ||
| 1204 | return val; | ||
| 1205 | } | ||
| 1206 | return 0; | ||
| 1207 | } | ||
| 1208 | fn errunion(stuff: anyerror!u32) u32 { | ||
| 1209 | global_frame = @frame(); | ||
| 1210 | defer global_frame = null; | ||
| 1211 | while (stuff) |val| { | ||
| 1212 | suspend {} | ||
| 1213 | return val; | ||
| 1214 | } else |err| { | ||
| 1215 | return 0; | ||
| 1216 | } | ||
| 1217 | } | ||
| 1218 | }; | ||
| 1219 | S.doTheTest(); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | test "correctly spill when returning the error union result of another async fn" { | ||
| 1223 | const S = struct { | ||
| 1224 | var global_frame: anyframe = undefined; | ||
| 1225 | |||
| 1226 | fn doTheTest() !void { | ||
| 1227 | expect((atest() catch unreachable) == 1234) catch @panic("test failure"); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | fn atest() !i32 { | ||
| 1231 | return fallible1(); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | fn fallible1() anyerror!i32 { | ||
| 1235 | suspend { | ||
| 1236 | global_frame = @frame(); | ||
| 1237 | } | ||
| 1238 | return 1234; | ||
| 1239 | } | ||
| 1240 | }; | ||
| 1241 | _ = async S.doTheTest(); | ||
| 1242 | resume S.global_frame; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | test "spill target expr in a for loop" { | ||
| 1246 | const S = struct { | ||
| 1247 | var global_frame: anyframe = undefined; | ||
| 1248 | |||
| 1249 | fn doTheTest() !void { | ||
| 1250 | var foo = Foo{ | ||
| 1251 | .slice = &[_]i32{ 1, 2 }, | ||
| 1252 | }; | ||
| 1253 | expect(atest(&foo) == 3) catch @panic("test failure"); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | const Foo = struct { | ||
| 1257 | slice: []const i32, | ||
| 1258 | }; | ||
| 1259 | |||
| 1260 | fn atest(foo: *Foo) i32 { | ||
| 1261 | var sum: i32 = 0; | ||
| 1262 | for (foo.slice) |x| { | ||
| 1263 | suspend { | ||
| 1264 | global_frame = @frame(); | ||
| 1265 | } | ||
| 1266 | sum += x; | ||
| 1267 | } | ||
| 1268 | return sum; | ||
| 1269 | } | ||
| 1270 | }; | ||
| 1271 | _ = async S.doTheTest(); | ||
| 1272 | resume S.global_frame; | ||
| 1273 | resume S.global_frame; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | test "spill target expr in a for loop, with a var decl in the loop body" { | ||
| 1277 | const S = struct { | ||
| 1278 | var global_frame: anyframe = undefined; | ||
| 1279 | |||
| 1280 | fn doTheTest() !void { | ||
| 1281 | var foo = Foo{ | ||
| 1282 | .slice = &[_]i32{ 1, 2 }, | ||
| 1283 | }; | ||
| 1284 | expect(atest(&foo) == 3) catch @panic("test failure"); | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | const Foo = struct { | ||
| 1288 | slice: []const i32, | ||
| 1289 | }; | ||
| 1290 | |||
| 1291 | fn atest(foo: *Foo) i32 { | ||
| 1292 | var sum: i32 = 0; | ||
| 1293 | for (foo.slice) |x| { | ||
| 1294 | // Previously this var decl would prevent spills. This test makes sure | ||
| 1295 | // the for loop spills still happen even though there is a VarDecl in scope | ||
| 1296 | // before the suspend. | ||
| 1297 | var anything = true; | ||
| 1298 | _ = anything; | ||
| 1299 | suspend { | ||
| 1300 | global_frame = @frame(); | ||
| 1301 | } | ||
| 1302 | sum += x; | ||
| 1303 | } | ||
| 1304 | return sum; | ||
| 1305 | } | ||
| 1306 | }; | ||
| 1307 | _ = async S.doTheTest(); | ||
| 1308 | resume S.global_frame; | ||
| 1309 | resume S.global_frame; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | test "async call with @call" { | ||
| 1313 | const S = struct { | ||
| 1314 | var global_frame: anyframe = undefined; | ||
| 1315 | fn doTheTest() void { | ||
| 1316 | _ = @call(.{ .modifier = .async_kw }, atest, .{}); | ||
| 1317 | resume global_frame; | ||
| 1318 | } | ||
| 1319 | fn atest() void { | ||
| 1320 | var frame = @call(.{ .modifier = .async_kw }, afoo, .{}); | ||
| 1321 | const res = await frame; | ||
| 1322 | expect(res == 42) catch @panic("test failure"); | ||
| 1323 | } | ||
| 1324 | fn afoo() i32 { | ||
| 1325 | suspend { | ||
| 1326 | global_frame = @frame(); | ||
| 1327 | } | ||
| 1328 | return 42; | ||
| 1329 | } | ||
| 1330 | }; | ||
| 1331 | S.doTheTest(); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | test "async function passed 0-bit arg after non-0-bit arg" { | ||
| 1335 | const S = struct { | ||
| 1336 | var global_frame: anyframe = undefined; | ||
| 1337 | var global_int: i32 = 0; | ||
| 1338 | |||
| 1339 | fn foo() void { | ||
| 1340 | bar(1, .{}) catch unreachable; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | fn bar(x: i32, args: anytype) anyerror!void { | ||
| 1344 | global_frame = @frame(); | ||
| 1345 | suspend {} | ||
| 1346 | global_int = x; | ||
| 1347 | } | ||
| 1348 | }; | ||
| 1349 | _ = async S.foo(); | ||
| 1350 | resume S.global_frame; | ||
| 1351 | try expect(S.global_int == 1); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | test "async function passed align(16) arg after align(8) arg" { | ||
| 1355 | const S = struct { | ||
| 1356 | var global_frame: anyframe = undefined; | ||
| 1357 | var global_int: u128 = 0; | ||
| 1358 | |||
| 1359 | fn foo() void { | ||
| 1360 | var a: u128 = 99; | ||
| 1361 | bar(10, .{a}) catch unreachable; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | fn bar(x: u64, args: anytype) anyerror!void { | ||
| 1365 | try expect(x == 10); | ||
| 1366 | global_frame = @frame(); | ||
| 1367 | suspend {} | ||
| 1368 | global_int = args[0]; | ||
| 1369 | } | ||
| 1370 | }; | ||
| 1371 | _ = async S.foo(); | ||
| 1372 | resume S.global_frame; | ||
| 1373 | try expect(S.global_int == 99); | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | test "async function call resolves target fn frame, comptime func" { | ||
| 1377 | const S = struct { | ||
| 1378 | var global_frame: anyframe = undefined; | ||
| 1379 | var global_int: i32 = 9; | ||
| 1380 | |||
| 1381 | fn foo() anyerror!void { | ||
| 1382 | const stack_size = 1000; | ||
| 1383 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; | ||
| 1384 | return await @asyncCall(&stack_frame, {}, bar, .{}); | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | fn bar() anyerror!void { | ||
| 1388 | global_frame = @frame(); | ||
| 1389 | suspend {} | ||
| 1390 | global_int += 1; | ||
| 1391 | } | ||
| 1392 | }; | ||
| 1393 | _ = async S.foo(); | ||
| 1394 | resume S.global_frame; | ||
| 1395 | try expect(S.global_int == 10); | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | test "async function call resolves target fn frame, runtime func" { | ||
| 1399 | const S = struct { | ||
| 1400 | var global_frame: anyframe = undefined; | ||
| 1401 | var global_int: i32 = 9; | ||
| 1402 | |||
| 1403 | fn foo() anyerror!void { | ||
| 1404 | const stack_size = 1000; | ||
| 1405 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; | ||
| 1406 | var func: fn () callconv(.Async) anyerror!void = bar; | ||
| 1407 | return await @asyncCall(&stack_frame, {}, func, .{}); | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | fn bar() anyerror!void { | ||
| 1411 | global_frame = @frame(); | ||
| 1412 | suspend {} | ||
| 1413 | global_int += 1; | ||
| 1414 | } | ||
| 1415 | }; | ||
| 1416 | _ = async S.foo(); | ||
| 1417 | resume S.global_frame; | ||
| 1418 | try expect(S.global_int == 10); | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | test "properly spill optional payload capture value" { | ||
| 1422 | const S = struct { | ||
| 1423 | var global_frame: anyframe = undefined; | ||
| 1424 | var global_int: usize = 2; | ||
| 1425 | |||
| 1426 | fn foo() void { | ||
| 1427 | var opt: ?usize = 1234; | ||
| 1428 | if (opt) |x| { | ||
| 1429 | bar(); | ||
| 1430 | global_int += x; | ||
| 1431 | } | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | fn bar() void { | ||
| 1435 | global_frame = @frame(); | ||
| 1436 | suspend {} | ||
| 1437 | global_int += 1; | ||
| 1438 | } | ||
| 1439 | }; | ||
| 1440 | _ = async S.foo(); | ||
| 1441 | resume S.global_frame; | ||
| 1442 | try expect(S.global_int == 1237); | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | test "handle defer interfering with return value spill" { | ||
| 1446 | const S = struct { | ||
| 1447 | var global_frame1: anyframe = undefined; | ||
| 1448 | var global_frame2: anyframe = undefined; | ||
| 1449 | var finished = false; | ||
| 1450 | var baz_happened = false; | ||
| 1451 | |||
| 1452 | fn doTheTest() !void { | ||
| 1453 | _ = async testFoo(); | ||
| 1454 | resume global_frame1; | ||
| 1455 | resume global_frame2; | ||
| 1456 | try expect(baz_happened); | ||
| 1457 | try expect(finished); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | fn testFoo() void { | ||
| 1461 | expectError(error.Bad, foo()) catch @panic("test failure"); | ||
| 1462 | finished = true; | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | fn foo() anyerror!void { | ||
| 1466 | defer baz(); | ||
| 1467 | return bar() catch |err| return err; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | fn bar() anyerror!void { | ||
| 1471 | global_frame1 = @frame(); | ||
| 1472 | suspend {} | ||
| 1473 | return error.Bad; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | fn baz() void { | ||
| 1477 | global_frame2 = @frame(); | ||
| 1478 | suspend {} | ||
| 1479 | baz_happened = true; | ||
| 1480 | } | ||
| 1481 | }; | ||
| 1482 | try S.doTheTest(); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | test "take address of temporary async frame" { | ||
| 1486 | const S = struct { | ||
| 1487 | var global_frame: anyframe = undefined; | ||
| 1488 | var finished = false; | ||
| 1489 | |||
| 1490 | fn doTheTest() !void { | ||
| 1491 | _ = async asyncDoTheTest(); | ||
| 1492 | resume global_frame; | ||
| 1493 | try expect(finished); | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | fn asyncDoTheTest() void { | ||
| 1497 | expect(finishIt(&async foo(10)) == 1245) catch @panic("test failure"); | ||
| 1498 | finished = true; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | fn foo(arg: i32) i32 { | ||
| 1502 | global_frame = @frame(); | ||
| 1503 | suspend {} | ||
| 1504 | return arg + 1234; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | fn finishIt(frame: anyframe->i32) i32 { | ||
| 1508 | return (await frame) + 1; | ||
| 1509 | } | ||
| 1510 | }; | ||
| 1511 | try S.doTheTest(); | ||
| 1512 | } | ||
| 1513 | |||
| 1514 | test "nosuspend await" { | ||
| 1515 | const S = struct { | ||
| 1516 | var finished = false; | ||
| 1517 | |||
| 1518 | fn doTheTest() !void { | ||
| 1519 | var frame = async foo(false); | ||
| 1520 | try expect(nosuspend await frame == 42); | ||
| 1521 | finished = true; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | fn foo(want_suspend: bool) i32 { | ||
| 1525 | if (want_suspend) { | ||
| 1526 | suspend {} | ||
| 1527 | } | ||
| 1528 | return 42; | ||
| 1529 | } | ||
| 1530 | }; | ||
| 1531 | try S.doTheTest(); | ||
| 1532 | try expect(S.finished); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | test "nosuspend on function calls" { | ||
| 1536 | const S0 = struct { | ||
| 1537 | b: i32 = 42, | ||
| 1538 | }; | ||
| 1539 | const S1 = struct { | ||
| 1540 | fn c() S0 { | ||
| 1541 | return S0{}; | ||
| 1542 | } | ||
| 1543 | fn d() !S0 { | ||
| 1544 | return S0{}; | ||
| 1545 | } | ||
| 1546 | }; | ||
| 1547 | try expectEqual(@as(i32, 42), nosuspend S1.c().b); | ||
| 1548 | try expectEqual(@as(i32, 42), (try nosuspend S1.d()).b); | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | test "nosuspend on async function calls" { | ||
| 1552 | const S0 = struct { | ||
| 1553 | b: i32 = 42, | ||
| 1554 | }; | ||
| 1555 | const S1 = struct { | ||
| 1556 | fn c() S0 { | ||
| 1557 | return S0{}; | ||
| 1558 | } | ||
| 1559 | fn d() !S0 { | ||
| 1560 | return S0{}; | ||
| 1561 | } | ||
| 1562 | }; | ||
| 1563 | var frame_c = nosuspend async S1.c(); | ||
| 1564 | try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1565 | var frame_d = nosuspend async S1.d(); | ||
| 1566 | try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | // test "resume nosuspend async function calls" { | ||
| 1570 | // const S0 = struct { | ||
| 1571 | // b: i32 = 42, | ||
| 1572 | // }; | ||
| 1573 | // const S1 = struct { | ||
| 1574 | // fn c() S0 { | ||
| 1575 | // suspend {} | ||
| 1576 | // return S0{}; | ||
| 1577 | // } | ||
| 1578 | // fn d() !S0 { | ||
| 1579 | // suspend {} | ||
| 1580 | // return S0{}; | ||
| 1581 | // } | ||
| 1582 | // }; | ||
| 1583 | // var frame_c = nosuspend async S1.c(); | ||
| 1584 | // resume frame_c; | ||
| 1585 | // try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1586 | // var frame_d = nosuspend async S1.d(); | ||
| 1587 | // resume frame_d; | ||
| 1588 | // try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1589 | // } | ||
| 1590 | |||
| 1591 | test "nosuspend resume async function calls" { | ||
| 1592 | const S0 = struct { | ||
| 1593 | b: i32 = 42, | ||
| 1594 | }; | ||
| 1595 | const S1 = struct { | ||
| 1596 | fn c() S0 { | ||
| 1597 | suspend {} | ||
| 1598 | return S0{}; | ||
| 1599 | } | ||
| 1600 | fn d() !S0 { | ||
| 1601 | suspend {} | ||
| 1602 | return S0{}; | ||
| 1603 | } | ||
| 1604 | }; | ||
| 1605 | var frame_c = async S1.c(); | ||
| 1606 | nosuspend resume frame_c; | ||
| 1607 | try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1608 | var frame_d = async S1.d(); | ||
| 1609 | nosuspend resume frame_d; | ||
| 1610 | try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | test "avoid forcing frame alignment resolution implicit cast to *c_void" { | ||
| 1614 | const S = struct { | ||
| 1615 | var x: ?*c_void = null; | ||
| 1616 | |||
| 1617 | fn foo() bool { | ||
| 1618 | suspend { | ||
| 1619 | x = @frame(); | ||
| 1620 | } | ||
| 1621 | return true; | ||
| 1622 | } | ||
| 1623 | }; | ||
| 1624 | var frame = async S.foo(); | ||
| 1625 | resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x)); | ||
| 1626 | try expect(nosuspend await frame); | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | test "@asyncCall with pass-by-value arguments" { | ||
| 1630 | const F0: u64 = 0xbeefbeefbeefbeef; | ||
| 1631 | const F1: u64 = 0xf00df00df00df00d; | ||
| 1632 | const F2: u64 = 0xcafecafecafecafe; | ||
| 1633 | |||
| 1634 | const S = struct { | ||
| 1635 | pub const ST = struct { f0: usize, f1: usize }; | ||
| 1636 | pub const AT = [5]u8; | ||
| 1637 | |||
| 1638 | pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.Async) void { | ||
| 1639 | // Check that the array and struct arguments passed by value don't | ||
| 1640 | // end up overflowing the adjacent fields in the frame structure. | ||
| 1641 | expectEqual(F0, _fill0) catch @panic("test failure"); | ||
| 1642 | expectEqual(F1, _fill1) catch @panic("test failure"); | ||
| 1643 | expectEqual(F2, _fill2) catch @panic("test failure"); | ||
| 1644 | } | ||
| 1645 | }; | ||
| 1646 | |||
| 1647 | var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; | ||
| 1648 | // The function pointer must not be comptime-known. | ||
| 1649 | var t = S.f; | ||
| 1650 | var frame_ptr = @asyncCall(&buffer, {}, t, .{ | ||
| 1651 | F0, | ||
| 1652 | .{ .f0 = 1, .f1 = 2 }, | ||
| 1653 | F1, | ||
| 1654 | [_]u8{ 1, 2, 3, 4, 5 }, | ||
| 1655 | F2, | ||
| 1656 | }); | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | test "@asyncCall with arguments having non-standard alignment" { | ||
| 1660 | const F0: u64 = 0xbeefbeef; | ||
| 1661 | const F1: u64 = 0xf00df00df00df00d; | ||
| 1662 | |||
| 1663 | const S = struct { | ||
| 1664 | pub fn f(_fill0: u32, s: struct { x: u64 align(16) }, _fill1: u64) callconv(.Async) void { | ||
| 1665 | // The compiler inserts extra alignment for s, check that the | ||
| 1666 | // generated code picks the right slot for fill1. | ||
| 1667 | expectEqual(F0, _fill0) catch @panic("test failure"); | ||
| 1668 | expectEqual(F1, _fill1) catch @panic("test failure"); | ||
| 1669 | } | ||
| 1670 | }; | ||
| 1671 | |||
| 1672 | var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; | ||
| 1673 | // The function pointer must not be comptime-known. | ||
| 1674 | var t = S.f; | ||
| 1675 | var frame_ptr = @asyncCall(&buffer, {}, t, .{ F0, undefined, F1 }); | ||
| 1676 | } | ||
test/behavior/atomics.zig created+219| ... | @@ -0,0 +1,219 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const builtin = @import("builtin"); | ||
| 5 | |||
| 6 | test "cmpxchg" { | ||
| 7 | try testCmpxchg(); | ||
| 8 | comptime try testCmpxchg(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testCmpxchg() !void { | ||
| 12 | var x: i32 = 1234; | ||
| 13 | if (@cmpxchgWeak(i32, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 14 | try expect(x1 == 1234); | ||
| 15 | } else { | ||
| 16 | @panic("cmpxchg should have failed"); | ||
| 17 | } | ||
| 18 | |||
| 19 | while (@cmpxchgWeak(i32, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 20 | try expect(x1 == 1234); | ||
| 21 | } | ||
| 22 | try expect(x == 5678); | ||
| 23 | |||
| 24 | try expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null); | ||
| 25 | try expect(x == 42); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "fence" { | ||
| 29 | var x: i32 = 1234; | ||
| 30 | @fence(.SeqCst); | ||
| 31 | x = 5678; | ||
| 32 | } | ||
| 33 | |||
| 34 | test "atomicrmw and atomicload" { | ||
| 35 | var data: u8 = 200; | ||
| 36 | try testAtomicRmw(&data); | ||
| 37 | try expect(data == 42); | ||
| 38 | try testAtomicLoad(&data); | ||
| 39 | } | ||
| 40 | |||
| 41 | fn testAtomicRmw(ptr: *u8) !void { | ||
| 42 | const prev_value = @atomicRmw(u8, ptr, .Xchg, 42, .SeqCst); | ||
| 43 | try expect(prev_value == 200); | ||
| 44 | comptime { | ||
| 45 | var x: i32 = 1234; | ||
| 46 | const y: i32 = 12345; | ||
| 47 | try expect(@atomicLoad(i32, &x, .SeqCst) == 1234); | ||
| 48 | try expect(@atomicLoad(i32, &y, .SeqCst) == 12345); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | fn testAtomicLoad(ptr: *u8) !void { | ||
| 53 | const x = @atomicLoad(u8, ptr, .SeqCst); | ||
| 54 | try expect(x == 42); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "cmpxchg with ptr" { | ||
| 58 | var data1: i32 = 1234; | ||
| 59 | var data2: i32 = 5678; | ||
| 60 | var data3: i32 = 9101; | ||
| 61 | var x: *i32 = &data1; | ||
| 62 | if (@cmpxchgWeak(*i32, &x, &data2, &data3, .SeqCst, .SeqCst)) |x1| { | ||
| 63 | try expect(x1 == &data1); | ||
| 64 | } else { | ||
| 65 | @panic("cmpxchg should have failed"); | ||
| 66 | } | ||
| 67 | |||
| 68 | while (@cmpxchgWeak(*i32, &x, &data1, &data3, .SeqCst, .SeqCst)) |x1| { | ||
| 69 | try expect(x1 == &data1); | ||
| 70 | } | ||
| 71 | try expect(x == &data3); | ||
| 72 | |||
| 73 | try expect(@cmpxchgStrong(*i32, &x, &data3, &data2, .SeqCst, .SeqCst) == null); | ||
| 74 | try expect(x == &data2); | ||
| 75 | } | ||
| 76 | |||
| 77 | // TODO this test is disabled until this issue is resolved: | ||
| 78 | // https://github.com/ziglang/zig/issues/2883 | ||
| 79 | // otherwise cross compiling will result in: | ||
| 80 | // lld: error: undefined symbol: __sync_val_compare_and_swap_16 | ||
| 81 | //test "128-bit cmpxchg" { | ||
| 82 | // var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987 | ||
| 83 | // if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 84 | // try expect(x1 == 1234); | ||
| 85 | // } else { | ||
| 86 | // @panic("cmpxchg should have failed"); | ||
| 87 | // } | ||
| 88 | // | ||
| 89 | // while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 90 | // try expect(x1 == 1234); | ||
| 91 | // } | ||
| 92 | // try expect(x == 5678); | ||
| 93 | // | ||
| 94 | // try expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null); | ||
| 95 | // try expect(x == 42); | ||
| 96 | //} | ||
| 97 | |||
| 98 | test "cmpxchg with ignored result" { | ||
| 99 | var x: i32 = 1234; | ||
| 100 | var ptr = &x; | ||
| 101 | |||
| 102 | _ = @cmpxchgStrong(i32, &x, 1234, 5678, .Monotonic, .Monotonic); | ||
| 103 | |||
| 104 | try expectEqual(@as(i32, 5678), x); | ||
| 105 | } | ||
| 106 | |||
| 107 | var a_global_variable = @as(u32, 1234); | ||
| 108 | |||
| 109 | test "cmpxchg on a global variable" { | ||
| 110 | _ = @cmpxchgWeak(u32, &a_global_variable, 1234, 42, .Acquire, .Monotonic); | ||
| 111 | try expectEqual(@as(u32, 42), a_global_variable); | ||
| 112 | } | ||
| 113 | |||
| 114 | test "atomic load and rmw with enum" { | ||
| 115 | const Value = enum(u8) { | ||
| 116 | a, | ||
| 117 | b, | ||
| 118 | c, | ||
| 119 | }; | ||
| 120 | var x = Value.a; | ||
| 121 | |||
| 122 | try expect(@atomicLoad(Value, &x, .SeqCst) != .b); | ||
| 123 | |||
| 124 | _ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst); | ||
| 125 | try expect(@atomicLoad(Value, &x, .SeqCst) == .c); | ||
| 126 | try expect(@atomicLoad(Value, &x, .SeqCst) != .a); | ||
| 127 | try expect(@atomicLoad(Value, &x, .SeqCst) != .b); | ||
| 128 | } | ||
| 129 | |||
| 130 | test "atomic store" { | ||
| 131 | var x: u32 = 0; | ||
| 132 | @atomicStore(u32, &x, 1, .SeqCst); | ||
| 133 | try expect(@atomicLoad(u32, &x, .SeqCst) == 1); | ||
| 134 | @atomicStore(u32, &x, 12345678, .SeqCst); | ||
| 135 | try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "atomic store comptime" { | ||
| 139 | comptime try testAtomicStore(); | ||
| 140 | try testAtomicStore(); | ||
| 141 | } | ||
| 142 | |||
| 143 | fn testAtomicStore() !void { | ||
| 144 | var x: u32 = 0; | ||
| 145 | @atomicStore(u32, &x, 1, .SeqCst); | ||
| 146 | try expect(@atomicLoad(u32, &x, .SeqCst) == 1); | ||
| 147 | @atomicStore(u32, &x, 12345678, .SeqCst); | ||
| 148 | try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "atomicrmw with floats" { | ||
| 152 | switch (builtin.target.cpu.arch) { | ||
| 153 | // https://github.com/ziglang/zig/issues/4457 | ||
| 154 | .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest, | ||
| 155 | else => {}, | ||
| 156 | } | ||
| 157 | try testAtomicRmwFloat(); | ||
| 158 | comptime try testAtomicRmwFloat(); | ||
| 159 | } | ||
| 160 | |||
| 161 | fn testAtomicRmwFloat() !void { | ||
| 162 | var x: f32 = 0; | ||
| 163 | try expect(x == 0); | ||
| 164 | _ = @atomicRmw(f32, &x, .Xchg, 1, .SeqCst); | ||
| 165 | try expect(x == 1); | ||
| 166 | _ = @atomicRmw(f32, &x, .Add, 5, .SeqCst); | ||
| 167 | try expect(x == 6); | ||
| 168 | _ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst); | ||
| 169 | try expect(x == 4); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "atomicrmw with ints" { | ||
| 173 | try testAtomicRmwInt(); | ||
| 174 | comptime try testAtomicRmwInt(); | ||
| 175 | } | ||
| 176 | |||
| 177 | fn testAtomicRmwInt() !void { | ||
| 178 | var x: u8 = 1; | ||
| 179 | var res = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst); | ||
| 180 | try expect(x == 3 and res == 1); | ||
| 181 | _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst); | ||
| 182 | try expect(x == 6); | ||
| 183 | _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst); | ||
| 184 | try expect(x == 5); | ||
| 185 | _ = @atomicRmw(u8, &x, .And, 4, .SeqCst); | ||
| 186 | try expect(x == 4); | ||
| 187 | _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst); | ||
| 188 | try expect(x == 0xfb); | ||
| 189 | _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst); | ||
| 190 | try expect(x == 0xff); | ||
| 191 | _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst); | ||
| 192 | try expect(x == 0xfd); | ||
| 193 | |||
| 194 | _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst); | ||
| 195 | try expect(x == 0xfd); | ||
| 196 | _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst); | ||
| 197 | try expect(x == 1); | ||
| 198 | } | ||
| 199 | |||
| 200 | test "atomics with different types" { | ||
| 201 | try testAtomicsWithType(bool, true, false); | ||
| 202 | inline for (.{ u1, i4, u5, i15, u24 }) |T| { | ||
| 203 | var x: T = 0; | ||
| 204 | try testAtomicsWithType(T, 0, 1); | ||
| 205 | } | ||
| 206 | try testAtomicsWithType(u0, 0, 0); | ||
| 207 | try testAtomicsWithType(i0, 0, 0); | ||
| 208 | } | ||
| 209 | |||
| 210 | fn testAtomicsWithType(comptime T: type, a: T, b: T) !void { | ||
| 211 | var x: T = b; | ||
| 212 | @atomicStore(T, &x, a, .SeqCst); | ||
| 213 | try expect(x == a); | ||
| 214 | try expect(@atomicLoad(T, &x, .SeqCst) == a); | ||
| 215 | try expect(@atomicRmw(T, &x, .Xchg, b, .SeqCst) == a); | ||
| 216 | try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst) == null); | ||
| 217 | if (@sizeOf(T) != 0) | ||
| 218 | try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a); | ||
| 219 | } | ||
test/behavior/await_struct.zig created+44| ... | @@ -0,0 +1,44 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const Foo = struct { | ||
| 6 | x: i32, | ||
| 7 | }; | ||
| 8 | |||
| 9 | var await_a_promise: anyframe = undefined; | ||
| 10 | var await_final_result = Foo{ .x = 0 }; | ||
| 11 | |||
| 12 | test "coroutine await struct" { | ||
| 13 | await_seq('a'); | ||
| 14 | var p = async await_amain(); | ||
| 15 | await_seq('f'); | ||
| 16 | resume await_a_promise; | ||
| 17 | await_seq('i'); | ||
| 18 | try expect(await_final_result.x == 1234); | ||
| 19 | try expect(std.mem.eql(u8, &await_points, "abcdefghi")); | ||
| 20 | } | ||
| 21 | fn await_amain() callconv(.Async) void { | ||
| 22 | await_seq('b'); | ||
| 23 | var p = async await_another(); | ||
| 24 | await_seq('e'); | ||
| 25 | await_final_result = await p; | ||
| 26 | await_seq('h'); | ||
| 27 | } | ||
| 28 | fn await_another() callconv(.Async) Foo { | ||
| 29 | await_seq('c'); | ||
| 30 | suspend { | ||
| 31 | await_seq('d'); | ||
| 32 | await_a_promise = @frame(); | ||
| 33 | } | ||
| 34 | await_seq('g'); | ||
| 35 | return Foo{ .x = 1234 }; | ||
| 36 | } | ||
| 37 | |||
| 38 | var await_points = [_]u8{0} ** "abcdefghi".len; | ||
| 39 | var await_seq_index: usize = 0; | ||
| 40 | |||
| 41 | fn await_seq(c: u8) void { | ||
| 42 | await_points[await_seq_index] = c; | ||
| 43 | await_seq_index += 1; | ||
| 44 | } | ||
test/behavior/bit_shifting.zig created+104| ... | @@ -0,0 +1,104 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { | ||
| 5 | const key_bits = @typeInfo(Key).Int.bits; | ||
| 6 | std.debug.assert(Key == std.meta.Int(.unsigned, key_bits)); | ||
| 7 | std.debug.assert(key_bits >= mask_bit_count); | ||
| 8 | const shard_key_bits = mask_bit_count; | ||
| 9 | const ShardKey = std.meta.Int(.unsigned, mask_bit_count); | ||
| 10 | const shift_amount = key_bits - shard_key_bits; | ||
| 11 | return struct { | ||
| 12 | const Self = @This(); | ||
| 13 | shards: [1 << shard_key_bits]?*Node, | ||
| 14 | |||
| 15 | pub fn create() Self { | ||
| 16 | return Self{ .shards = [_]?*Node{null} ** (1 << shard_key_bits) }; | ||
| 17 | } | ||
| 18 | |||
| 19 | fn getShardKey(key: Key) ShardKey { | ||
| 20 | // https://github.com/ziglang/zig/issues/1544 | ||
| 21 | // this special case is needed because you can't u32 >> 32. | ||
| 22 | if (ShardKey == u0) return 0; | ||
| 23 | |||
| 24 | // this can be u1 >> u0 | ||
| 25 | const shard_key = key >> shift_amount; | ||
| 26 | |||
| 27 | // TODO: https://github.com/ziglang/zig/issues/1544 | ||
| 28 | // This cast could be implicit if we teach the compiler that | ||
| 29 | // u32 >> 30 -> u2 | ||
| 30 | return @intCast(ShardKey, shard_key); | ||
| 31 | } | ||
| 32 | |||
| 33 | pub fn put(self: *Self, node: *Node) void { | ||
| 34 | const shard_key = Self.getShardKey(node.key); | ||
| 35 | node.next = self.shards[shard_key]; | ||
| 36 | self.shards[shard_key] = node; | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn get(self: *Self, key: Key) ?*Node { | ||
| 40 | const shard_key = Self.getShardKey(key); | ||
| 41 | var maybe_node = self.shards[shard_key]; | ||
| 42 | while (maybe_node) |node| : (maybe_node = node.next) { | ||
| 43 | if (node.key == key) return node; | ||
| 44 | } | ||
| 45 | return null; | ||
| 46 | } | ||
| 47 | |||
| 48 | pub const Node = struct { | ||
| 49 | key: Key, | ||
| 50 | value: V, | ||
| 51 | next: ?*Node, | ||
| 52 | |||
| 53 | pub fn init(self: *Node, key: Key, value: V) void { | ||
| 54 | self.key = key; | ||
| 55 | self.value = value; | ||
| 56 | self.next = null; | ||
| 57 | } | ||
| 58 | }; | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | test "sharded table" { | ||
| 63 | // realistic 16-way sharding | ||
| 64 | try testShardedTable(u32, 4, 8); | ||
| 65 | |||
| 66 | try testShardedTable(u5, 0, 32); // ShardKey == u0 | ||
| 67 | try testShardedTable(u5, 2, 32); | ||
| 68 | try testShardedTable(u5, 5, 32); | ||
| 69 | |||
| 70 | try testShardedTable(u1, 0, 2); | ||
| 71 | try testShardedTable(u1, 1, 2); // this does u1 >> u0 | ||
| 72 | |||
| 73 | try testShardedTable(u0, 0, 1); | ||
| 74 | } | ||
| 75 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) !void { | ||
| 76 | const Table = ShardedTable(Key, mask_bit_count, void); | ||
| 77 | |||
| 78 | var table = Table.create(); | ||
| 79 | var node_buffer: [node_count]Table.Node = undefined; | ||
| 80 | for (node_buffer) |*node, i| { | ||
| 81 | const key = @intCast(Key, i); | ||
| 82 | try expect(table.get(key) == null); | ||
| 83 | node.init(key, {}); | ||
| 84 | table.put(node); | ||
| 85 | } | ||
| 86 | |||
| 87 | for (node_buffer) |*node, i| { | ||
| 88 | try expect(table.get(@intCast(Key, i)) == node); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | // #2225 | ||
| 93 | test "comptime shr of BigInt" { | ||
| 94 | comptime { | ||
| 95 | var n0 = 0xdeadbeef0000000000000000; | ||
| 96 | try expect(n0 >> 64 == 0xdeadbeef); | ||
| 97 | var n1 = 17908056155735594659; | ||
| 98 | try expect(n1 >> 64 == 0); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | test "comptime shift safety check" { | ||
| 103 | const x = @as(usize, 42) << @sizeOf(usize); | ||
| 104 | } | ||
test/behavior/bitcast.zig created+197| ... | @@ -0,0 +1,197 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const maxInt = std.math.maxInt; | ||
| 6 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 7 | |||
| 8 | test "@bitCast i32 -> u32" { | ||
| 9 | try testBitCast_i32_u32(); | ||
| 10 | comptime try testBitCast_i32_u32(); | ||
| 11 | } | ||
| 12 | |||
| 13 | fn testBitCast_i32_u32() !void { | ||
| 14 | try expect(conv(-1) == maxInt(u32)); | ||
| 15 | try expect(conv2(maxInt(u32)) == -1); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn conv(x: i32) u32 { | ||
| 19 | return @bitCast(u32, x); | ||
| 20 | } | ||
| 21 | fn conv2(x: u32) i32 { | ||
| 22 | return @bitCast(i32, x); | ||
| 23 | } | ||
| 24 | |||
| 25 | test "@bitCast extern enum to its integer type" { | ||
| 26 | const SOCK = extern enum { | ||
| 27 | A, | ||
| 28 | B, | ||
| 29 | |||
| 30 | fn testBitCastExternEnum() !void { | ||
| 31 | var SOCK_DGRAM = @This().B; | ||
| 32 | var sock_dgram = @bitCast(c_int, SOCK_DGRAM); | ||
| 33 | try expect(sock_dgram == 1); | ||
| 34 | } | ||
| 35 | }; | ||
| 36 | |||
| 37 | try SOCK.testBitCastExternEnum(); | ||
| 38 | comptime try SOCK.testBitCastExternEnum(); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "@bitCast packed structs at runtime and comptime" { | ||
| 42 | const Full = packed struct { | ||
| 43 | number: u16, | ||
| 44 | }; | ||
| 45 | const Divided = packed struct { | ||
| 46 | half1: u8, | ||
| 47 | quarter3: u4, | ||
| 48 | quarter4: u4, | ||
| 49 | }; | ||
| 50 | const S = struct { | ||
| 51 | fn doTheTest() !void { | ||
| 52 | var full = Full{ .number = 0x1234 }; | ||
| 53 | var two_halves = @bitCast(Divided, full); | ||
| 54 | switch (native_endian) { | ||
| 55 | .Big => { | ||
| 56 | try expect(two_halves.half1 == 0x12); | ||
| 57 | try expect(two_halves.quarter3 == 0x3); | ||
| 58 | try expect(two_halves.quarter4 == 0x4); | ||
| 59 | }, | ||
| 60 | .Little => { | ||
| 61 | try expect(two_halves.half1 == 0x34); | ||
| 62 | try expect(two_halves.quarter3 == 0x2); | ||
| 63 | try expect(two_halves.quarter4 == 0x1); | ||
| 64 | }, | ||
| 65 | } | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | try S.doTheTest(); | ||
| 69 | comptime try S.doTheTest(); | ||
| 70 | } | ||
| 71 | |||
| 72 | test "@bitCast extern structs at runtime and comptime" { | ||
| 73 | const Full = extern struct { | ||
| 74 | number: u16, | ||
| 75 | }; | ||
| 76 | const TwoHalves = extern struct { | ||
| 77 | half1: u8, | ||
| 78 | half2: u8, | ||
| 79 | }; | ||
| 80 | const S = struct { | ||
| 81 | fn doTheTest() !void { | ||
| 82 | var full = Full{ .number = 0x1234 }; | ||
| 83 | var two_halves = @bitCast(TwoHalves, full); | ||
| 84 | switch (native_endian) { | ||
| 85 | .Big => { | ||
| 86 | try expect(two_halves.half1 == 0x12); | ||
| 87 | try expect(two_halves.half2 == 0x34); | ||
| 88 | }, | ||
| 89 | .Little => { | ||
| 90 | try expect(two_halves.half1 == 0x34); | ||
| 91 | try expect(two_halves.half2 == 0x12); | ||
| 92 | }, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | }; | ||
| 96 | try S.doTheTest(); | ||
| 97 | comptime try S.doTheTest(); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "bitcast packed struct to integer and back" { | ||
| 101 | const LevelUpMove = packed struct { | ||
| 102 | move_id: u9, | ||
| 103 | level: u7, | ||
| 104 | }; | ||
| 105 | const S = struct { | ||
| 106 | fn doTheTest() !void { | ||
| 107 | var move = LevelUpMove{ .move_id = 1, .level = 2 }; | ||
| 108 | var v = @bitCast(u16, move); | ||
| 109 | var back_to_a_move = @bitCast(LevelUpMove, v); | ||
| 110 | try expect(back_to_a_move.move_id == 1); | ||
| 111 | try expect(back_to_a_move.level == 2); | ||
| 112 | } | ||
| 113 | }; | ||
| 114 | try S.doTheTest(); | ||
| 115 | comptime try S.doTheTest(); | ||
| 116 | } | ||
| 117 | |||
| 118 | test "implicit cast to error union by returning" { | ||
| 119 | const S = struct { | ||
| 120 | fn entry() !void { | ||
| 121 | try expect((func(-1) catch unreachable) == maxInt(u64)); | ||
| 122 | } | ||
| 123 | pub fn func(sz: i64) anyerror!u64 { | ||
| 124 | return @bitCast(u64, sz); | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | try S.entry(); | ||
| 128 | comptime try S.entry(); | ||
| 129 | } | ||
| 130 | |||
| 131 | // issue #3010: compiler segfault | ||
| 132 | test "bitcast literal [4]u8 param to u32" { | ||
| 133 | const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); | ||
| 134 | try expect(ip == maxInt(u32)); | ||
| 135 | } | ||
| 136 | |||
| 137 | test "bitcast packed struct literal to byte" { | ||
| 138 | const Foo = packed struct { | ||
| 139 | value: u8, | ||
| 140 | }; | ||
| 141 | const casted = @bitCast(u8, Foo{ .value = 0xF }); | ||
| 142 | try expect(casted == 0xf); | ||
| 143 | } | ||
| 144 | |||
| 145 | test "comptime bitcast used in expression has the correct type" { | ||
| 146 | const Foo = packed struct { | ||
| 147 | value: u8, | ||
| 148 | }; | ||
| 149 | try expect(@bitCast(u8, Foo{ .value = 0xF }) == 0xf); | ||
| 150 | } | ||
| 151 | |||
| 152 | test "bitcast result to _" { | ||
| 153 | _ = @bitCast(u8, @as(i8, 1)); | ||
| 154 | } | ||
| 155 | |||
| 156 | test "nested bitcast" { | ||
| 157 | const S = struct { | ||
| 158 | fn moo(x: isize) !void { | ||
| 159 | try @import("std").testing.expectEqual(@intCast(isize, 42), x); | ||
| 160 | } | ||
| 161 | |||
| 162 | fn foo(x: isize) !void { | ||
| 163 | try @This().moo( | ||
| 164 | @bitCast(isize, if (x != 0) @bitCast(usize, x) else @bitCast(usize, x)), | ||
| 165 | ); | ||
| 166 | } | ||
| 167 | }; | ||
| 168 | |||
| 169 | try S.foo(42); | ||
| 170 | comptime try S.foo(42); | ||
| 171 | } | ||
| 172 | |||
| 173 | test "bitcast passed as tuple element" { | ||
| 174 | const S = struct { | ||
| 175 | fn foo(args: anytype) !void { | ||
| 176 | comptime try expect(@TypeOf(args[0]) == f32); | ||
| 177 | try expect(args[0] == 12.34); | ||
| 178 | } | ||
| 179 | }; | ||
| 180 | try S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))}); | ||
| 181 | } | ||
| 182 | |||
| 183 | test "triple level result location with bitcast sandwich passed as tuple element" { | ||
| 184 | const S = struct { | ||
| 185 | fn foo(args: anytype) !void { | ||
| 186 | comptime try expect(@TypeOf(args[0]) == f64); | ||
| 187 | try expect(args[0] > 12.33 and args[0] < 12.35); | ||
| 188 | } | ||
| 189 | }; | ||
| 190 | try S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); | ||
| 191 | } | ||
| 192 | |||
| 193 | test "bitcast generates a temporary value" { | ||
| 194 | var y = @as(u16, 0x55AA); | ||
| 195 | const x = @bitCast(u16, @bitCast([2]u8, y)); | ||
| 196 | try expectEqual(y, x); | ||
| 197 | } | ||
test/behavior/bitreverse.zig created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const minInt = std.math.minInt; | ||
| 4 | |||
| 5 | test "@bitReverse" { | ||
| 6 | comptime try testBitReverse(); | ||
| 7 | try testBitReverse(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitReverse() !void { | ||
| 11 | // using comptime_ints, unsigned | ||
| 12 | try expect(@bitReverse(u0, 0) == 0); | ||
| 13 | try expect(@bitReverse(u5, 0x12) == 0x9); | ||
| 14 | try expect(@bitReverse(u8, 0x12) == 0x48); | ||
| 15 | try expect(@bitReverse(u16, 0x1234) == 0x2c48); | ||
| 16 | try expect(@bitReverse(u24, 0x123456) == 0x6a2c48); | ||
| 17 | try expect(@bitReverse(u32, 0x12345678) == 0x1e6a2c48); | ||
| 18 | try expect(@bitReverse(u40, 0x123456789a) == 0x591e6a2c48); | ||
| 19 | try expect(@bitReverse(u48, 0x123456789abc) == 0x3d591e6a2c48); | ||
| 20 | try expect(@bitReverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); | ||
| 21 | try expect(@bitReverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); | ||
| 22 | try expect(@bitReverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 23 | |||
| 24 | // using runtime uints, unsigned | ||
| 25 | var num0: u0 = 0; | ||
| 26 | try expect(@bitReverse(u0, num0) == 0); | ||
| 27 | var num5: u5 = 0x12; | ||
| 28 | try expect(@bitReverse(u5, num5) == 0x9); | ||
| 29 | var num8: u8 = 0x12; | ||
| 30 | try expect(@bitReverse(u8, num8) == 0x48); | ||
| 31 | var num16: u16 = 0x1234; | ||
| 32 | try expect(@bitReverse(u16, num16) == 0x2c48); | ||
| 33 | var num24: u24 = 0x123456; | ||
| 34 | try expect(@bitReverse(u24, num24) == 0x6a2c48); | ||
| 35 | var num32: u32 = 0x12345678; | ||
| 36 | try expect(@bitReverse(u32, num32) == 0x1e6a2c48); | ||
| 37 | var num40: u40 = 0x123456789a; | ||
| 38 | try expect(@bitReverse(u40, num40) == 0x591e6a2c48); | ||
| 39 | var num48: u48 = 0x123456789abc; | ||
| 40 | try expect(@bitReverse(u48, num48) == 0x3d591e6a2c48); | ||
| 41 | var num56: u56 = 0x123456789abcde; | ||
| 42 | try expect(@bitReverse(u56, num56) == 0x7b3d591e6a2c48); | ||
| 43 | var num64: u64 = 0x123456789abcdef1; | ||
| 44 | try expect(@bitReverse(u64, num64) == 0x8f7b3d591e6a2c48); | ||
| 45 | var num128: u128 = 0x123456789abcdef11121314151617181; | ||
| 46 | try expect(@bitReverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 47 | |||
| 48 | // using comptime_ints, signed, positive | ||
| 49 | try expect(@bitReverse(u8, @as(u8, 0)) == 0); | ||
| 50 | try expect(@bitReverse(i8, @bitCast(i8, @as(u8, 0x92))) == @bitCast(i8, @as(u8, 0x49))); | ||
| 51 | try expect(@bitReverse(i16, @bitCast(i16, @as(u16, 0x1234))) == @bitCast(i16, @as(u16, 0x2c48))); | ||
| 52 | try expect(@bitReverse(i24, @bitCast(i24, @as(u24, 0x123456))) == @bitCast(i24, @as(u24, 0x6a2c48))); | ||
| 53 | try expect(@bitReverse(i32, @bitCast(i32, @as(u32, 0x12345678))) == @bitCast(i32, @as(u32, 0x1e6a2c48))); | ||
| 54 | try expect(@bitReverse(i40, @bitCast(i40, @as(u40, 0x123456789a))) == @bitCast(i40, @as(u40, 0x591e6a2c48))); | ||
| 55 | try expect(@bitReverse(i48, @bitCast(i48, @as(u48, 0x123456789abc))) == @bitCast(i48, @as(u48, 0x3d591e6a2c48))); | ||
| 56 | try expect(@bitReverse(i56, @bitCast(i56, @as(u56, 0x123456789abcde))) == @bitCast(i56, @as(u56, 0x7b3d591e6a2c48))); | ||
| 57 | try expect(@bitReverse(i64, @bitCast(i64, @as(u64, 0x123456789abcdef1))) == @bitCast(i64, @as(u64, 0x8f7b3d591e6a2c48))); | ||
| 58 | try expect(@bitReverse(i128, @bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181))) == @bitCast(i128, @as(u128, 0x818e868a828c84888f7b3d591e6a2c48))); | ||
| 59 | |||
| 60 | // using signed, negative. Compare to runtime ints returned from llvm. | ||
| 61 | var neg8: i8 = -18; | ||
| 62 | try expect(@bitReverse(i8, @as(i8, -18)) == @bitReverse(i8, neg8)); | ||
| 63 | var neg16: i16 = -32694; | ||
| 64 | try expect(@bitReverse(i16, @as(i16, -32694)) == @bitReverse(i16, neg16)); | ||
| 65 | var neg24: i24 = -6773785; | ||
| 66 | try expect(@bitReverse(i24, @as(i24, -6773785)) == @bitReverse(i24, neg24)); | ||
| 67 | var neg32: i32 = -16773785; | ||
| 68 | try expect(@bitReverse(i32, @as(i32, -16773785)) == @bitReverse(i32, neg32)); | ||
| 69 | } | ||
test/behavior/bool.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "bool literals" { | ||
| 4 | try expect(true); | ||
| 5 | try expect(!false); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "cast bool to int" { | ||
| 9 | const t = true; | ||
| 10 | const f = false; | ||
| 11 | try expect(@boolToInt(t) == @as(u32, 1)); | ||
| 12 | try expect(@boolToInt(f) == @as(u32, 0)); | ||
| 13 | try nonConstCastBoolToInt(t, f); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn nonConstCastBoolToInt(t: bool, f: bool) !void { | ||
| 17 | try expect(@boolToInt(t) == @as(u32, 1)); | ||
| 18 | try expect(@boolToInt(f) == @as(u32, 0)); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "bool cmp" { | ||
| 22 | try expect(testBoolCmp(true, false) == false); | ||
| 23 | } | ||
| 24 | fn testBoolCmp(a: bool, b: bool) bool { | ||
| 25 | return a == b; | ||
| 26 | } | ||
| 27 | |||
| 28 | const global_f = false; | ||
| 29 | const global_t = true; | ||
| 30 | const not_global_f = !global_f; | ||
| 31 | const not_global_t = !global_t; | ||
| 32 | test "compile time bool not" { | ||
| 33 | try expect(not_global_f); | ||
| 34 | try expect(!not_global_t); | ||
| 35 | } | ||
test/behavior/bugs/1025.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const A = struct { | ||
| 2 | B: type, | ||
| 3 | }; | ||
| 4 | |||
| 5 | fn getA() A { | ||
| 6 | return A{ .B = u8 }; | ||
| 7 | } | ||
| 8 | |||
| 9 | test "bug 1025" { | ||
| 10 | const a = getA(); | ||
| 11 | try @import("std").testing.expect(a.B == u8); | ||
| 12 | } | ||
test/behavior/bugs/1076.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "comptime code should not modify constant data" { | ||
| 6 | try testCastPtrOfArrayToSliceAndPtr(); | ||
| 7 | comptime try testCastPtrOfArrayToSliceAndPtr(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testCastPtrOfArrayToSliceAndPtr() !void { | ||
| 11 | { | ||
| 12 | var array = "aoeu".*; | ||
| 13 | const x: [*]u8 = &array; | ||
| 14 | x[0] += 1; | ||
| 15 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var array: [4]u8 = "aoeu".*; | ||
| 19 | const x: [*]u8 = &array; | ||
| 20 | x[0] += 1; | ||
| 21 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 22 | } | ||
| 23 | } | ||
test/behavior/bugs/1111.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const Foo = extern enum { | ||
| 2 | Bar = -1, | ||
| 3 | }; | ||
| 4 | |||
| 5 | test "issue 1111 fixed" { | ||
| 6 | const v = Foo.Bar; | ||
| 7 | |||
| 8 | switch (v) { | ||
| 9 | Foo.Bar => return, | ||
| 10 | } | ||
| 11 | } | ||
test/behavior/bugs/1120.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const A = packed struct { | ||
| 5 | a: u2, | ||
| 6 | b: u6, | ||
| 7 | }; | ||
| 8 | const B = packed struct { | ||
| 9 | q: u8, | ||
| 10 | a: u2, | ||
| 11 | b: u6, | ||
| 12 | }; | ||
| 13 | test "bug 1120" { | ||
| 14 | var a = A{ .a = 2, .b = 2 }; | ||
| 15 | var b = B{ .q = 22, .a = 3, .b = 2 }; | ||
| 16 | var t: usize = 0; | ||
| 17 | const ptr = switch (t) { | ||
| 18 | 0 => &a.a, | ||
| 19 | 1 => &b.a, | ||
| 20 | else => unreachable, | ||
| 21 | }; | ||
| 22 | try expect(ptr.* == 2); | ||
| 23 | } | ||
test/behavior/bugs/1277.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const S = struct { | ||
| 4 | f: ?fn () i32, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const s = S{ .f = f }; | ||
| 8 | |||
| 9 | fn f() i32 { | ||
| 10 | return 1234; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "don't emit an LLVM global for a const function when it's in an optional in a struct" { | ||
| 14 | try std.testing.expect(s.f.?() == 1234); | ||
| 15 | } | ||
test/behavior/bugs/1310.zig created+24| ... | @@ -0,0 +1,24 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | pub const VM = ?[*]const struct_InvocationTable_; | ||
| 5 | pub const struct_InvocationTable_ = extern struct { | ||
| 6 | GetVM: ?fn (?[*]VM) callconv(.C) c_int, | ||
| 7 | }; | ||
| 8 | |||
| 9 | pub const struct_VM_ = extern struct { | ||
| 10 | functions: ?[*]const struct_InvocationTable_, | ||
| 11 | }; | ||
| 12 | |||
| 13 | //excised output from stdlib.h etc | ||
| 14 | |||
| 15 | pub const InvocationTable_ = struct_InvocationTable_; | ||
| 16 | pub const VM_ = struct_VM_; | ||
| 17 | |||
| 18 | fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 { | ||
| 19 | return 11; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "fixed" { | ||
| 23 | try expect(agent_callback(undefined, undefined) == 11); | ||
| 24 | } | ||
test/behavior/bugs/1322.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | c: C, | ||
| 5 | None, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = struct { | ||
| 9 | b: B, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const C = struct {}; | ||
| 13 | |||
| 14 | test "tagged union with all void fields but a meaningful tag" { | ||
| 15 | var a: A = A{ .b = B{ .c = C{} } }; | ||
| 16 | try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).c); | ||
| 17 | a = A{ .b = B.None }; | ||
| 18 | try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).None); | ||
| 19 | } | ||
test/behavior/bugs/1381.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | D: u8, | ||
| 5 | E: u16, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = union(enum) { | ||
| 9 | B: B, | ||
| 10 | C: u8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "union that needs padding bytes inside an array" { | ||
| 14 | var as = [_]A{ | ||
| 15 | A{ .B = B{ .D = 1 } }, | ||
| 16 | A{ .B = B{ .D = 1 } }, | ||
| 17 | }; | ||
| 18 | |||
| 19 | const a = as[0].B; | ||
| 20 | try std.testing.expect(a.D == 1); | ||
| 21 | } | ||
test/behavior/bugs/1421.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const S = struct { | ||
| 5 | fn method() std.builtin.TypeInfo { | ||
| 6 | return @typeInfo(S); | ||
| 7 | } | ||
| 8 | }; | ||
| 9 | |||
| 10 | test "functions with return type required to be comptime are generic" { | ||
| 11 | const ti = S.method(); | ||
| 12 | try expect(@as(std.builtin.TypeId, ti) == std.builtin.TypeId.Struct); | ||
| 13 | } | ||
test/behavior/bugs/1442.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Union = union(enum) { | ||
| 4 | Text: []const u8, | ||
| 5 | Color: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | test "const error union field alignment" { | ||
| 9 | var union_or_err: anyerror!Union = Union{ .Color = 1234 }; | ||
| 10 | try std.testing.expect((union_or_err catch unreachable).Color == 1234); | ||
| 11 | } | ||
test/behavior/bugs/1467.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | pub const E = enum(u32) { A, B, C }; | ||
| 2 | pub const S = extern struct { | ||
| 3 | e: E, | ||
| 4 | }; | ||
| 5 | test "bug 1467" { | ||
| 6 | const s: S = undefined; | ||
| 7 | } | ||
test/behavior/bugs/1486.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const ptr = &global; | ||
| 4 | var global: u64 = 123; | ||
| 5 | |||
| 6 | test "constant pointer to global variable causes runtime load" { | ||
| 7 | global = 1234; | ||
| 8 | try expect(&global == ptr); | ||
| 9 | try expect(ptr.* == 1234); | ||
| 10 | } | ||
test/behavior/bugs/1500.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | const A = struct { | ||
| 2 | b: B, | ||
| 3 | }; | ||
| 4 | |||
| 5 | const B = fn (A) void; | ||
| 6 | |||
| 7 | test "allow these dependencies" { | ||
| 8 | var a: A = undefined; | ||
| 9 | var b: B = undefined; | ||
| 10 | } | ||
test/behavior/bugs/1607.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | |||
| 4 | const a = [_]u8{ 1, 2, 3 }; | ||
| 5 | |||
| 6 | fn checkAddress(s: []const u8) !void { | ||
| 7 | for (s) |*i, j| { | ||
| 8 | try testing.expect(i == &a[j]); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | test "slices pointing at the same address as global array." { | ||
| 13 | try checkAddress(&a); | ||
| 14 | comptime try checkAddress(&a); | ||
| 15 | } | ||
test/behavior/bugs/1735.zig created+46| ... | @@ -0,0 +1,46 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const mystruct = struct { | ||
| 4 | pending: ?listofstructs, | ||
| 5 | }; | ||
| 6 | pub fn TailQueue(comptime T: type) type { | ||
| 7 | return struct { | ||
| 8 | const Self = @This(); | ||
| 9 | |||
| 10 | pub const Node = struct { | ||
| 11 | prev: ?*Node, | ||
| 12 | next: ?*Node, | ||
| 13 | data: T, | ||
| 14 | }; | ||
| 15 | |||
| 16 | first: ?*Node, | ||
| 17 | last: ?*Node, | ||
| 18 | len: usize, | ||
| 19 | |||
| 20 | pub fn init() Self { | ||
| 21 | return Self{ | ||
| 22 | .first = null, | ||
| 23 | .last = null, | ||
| 24 | .len = 0, | ||
| 25 | }; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | } | ||
| 29 | const listofstructs = TailQueue(mystruct); | ||
| 30 | |||
| 31 | const a = struct { | ||
| 32 | const Self = @This(); | ||
| 33 | |||
| 34 | foo: listofstructs, | ||
| 35 | |||
| 36 | pub fn init() Self { | ||
| 37 | return Self{ | ||
| 38 | .foo = listofstructs.init(), | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | test "intialization" { | ||
| 44 | var t = a.init(); | ||
| 45 | try std.testing.expect(t.foo.len == 0); | ||
| 46 | } | ||
test/behavior/bugs/1741.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "fixed" { | ||
| 4 | const x: f32 align(128) = 12.34; | ||
| 5 | try std.testing.expect(@ptrToInt(&x) % 128 == 0); | ||
| 6 | } | ||
test/behavior/bugs/1851.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "allocation and looping over 3-byte integer" { | ||
| 5 | try expect(@sizeOf(u24) == 4); | ||
| 6 | try expect(@sizeOf([1]u24) == 4); | ||
| 7 | try expect(@alignOf(u24) == 4); | ||
| 8 | try expect(@alignOf([1]u24) == 4); | ||
| 9 | |||
| 10 | var x = try std.testing.allocator.alloc(u24, 2); | ||
| 11 | defer std.testing.allocator.free(x); | ||
| 12 | try expect(x.len == 2); | ||
| 13 | x[0] = 0xFFFFFF; | ||
| 14 | x[1] = 0xFFFFFF; | ||
| 15 | |||
| 16 | const bytes = std.mem.sliceAsBytes(x); | ||
| 17 | try expect(@TypeOf(bytes) == []align(4) u8); | ||
| 18 | try expect(bytes.len == 8); | ||
| 19 | |||
| 20 | for (bytes) |*b| { | ||
| 21 | b.* = 0x00; | ||
| 22 | } | ||
| 23 | |||
| 24 | try expect(x[0] == 0x00); | ||
| 25 | try expect(x[1] == 0x00); | ||
| 26 | } | ||
test/behavior/bugs/1914.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const A = struct { | ||
| 4 | b_list_pointer: *const []B, | ||
| 5 | }; | ||
| 6 | const B = struct { | ||
| 7 | a_pointer: *const A, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const b_list: []B = &[_]B{}; | ||
| 11 | const a = A{ .b_list_pointer = &b_list }; | ||
| 12 | |||
| 13 | test "segfault bug" { | ||
| 14 | const assert = std.debug.assert; | ||
| 15 | const obj = B{ .a_pointer = &a }; | ||
| 16 | assert(obj.a_pointer == &a); // this makes zig crash | ||
| 17 | } | ||
| 18 | |||
| 19 | const A2 = struct { | ||
| 20 | pointer: *B, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub const B2 = struct { | ||
| 24 | pointer_array: []*A2, | ||
| 25 | }; | ||
| 26 | |||
| 27 | var b_value = B2{ .pointer_array = &[_]*A2{} }; | ||
| 28 | |||
| 29 | test "basic stuff" { | ||
| 30 | std.debug.assert(&b_value == &b_value); | ||
| 31 | } | ||
test/behavior/bugs/2006.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const S = struct { | ||
| 5 | p: *S, | ||
| 6 | }; | ||
| 7 | test "bug 2006" { | ||
| 8 | var a: S = undefined; | ||
| 9 | a = S{ .p = undefined }; | ||
| 10 | try expect(@sizeOf(S) != 0); | ||
| 11 | try expect(@sizeOf(*void) == 0); | ||
| 12 | } | ||
test/behavior/bugs/2114.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const math = std.math; | ||
| 4 | |||
| 5 | fn ctz(x: anytype) usize { | ||
| 6 | return @ctz(@TypeOf(x), x); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "fixed" { | ||
| 10 | try testClz(); | ||
| 11 | comptime try testClz(); | ||
| 12 | } | ||
| 13 | |||
| 14 | fn testClz() !void { | ||
| 15 | try expect(ctz(@as(u128, 0x40000000000000000000000000000000)) == 126); | ||
| 16 | try expect(math.rotl(u128, @as(u128, 0x40000000000000000000000000000000), @as(u8, 1)) == @as(u128, 0x80000000000000000000000000000000)); | ||
| 17 | try expect(ctz(@as(u128, 0x80000000000000000000000000000000)) == 127); | ||
| 18 | try expect(ctz(math.rotl(u128, @as(u128, 0x40000000000000000000000000000000), @as(u8, 1))) == 127); | ||
| 19 | } | ||
test/behavior/bugs/2346.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | test "fixed" { | ||
| 2 | const a: *void = undefined; | ||
| 3 | const b: *[1]void = a; | ||
| 4 | const c: *[0]u8 = undefined; | ||
| 5 | const d: []u8 = c; | ||
| 6 | } | ||
test/behavior/bugs/2578.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | y: u8, | ||
| 3 | }; | ||
| 4 | |||
| 5 | var foo: Foo = undefined; | ||
| 6 | const t = &foo; | ||
| 7 | |||
| 8 | fn bar(pointer: ?*c_void) void {} | ||
| 9 | |||
| 10 | test "fixed" { | ||
| 11 | bar(t); | ||
| 12 | } | ||
test/behavior/bugs/2692.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | fn foo(a: []u8) void {} | ||
| 2 | |||
| 3 | test "address of 0 length array" { | ||
| 4 | var pt: [0]u8 = undefined; | ||
| 5 | foo(&pt); | ||
| 6 | } | ||
test/behavior/bugs/2889.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const source = "A-"; | ||
| 4 | |||
| 5 | fn parseNote() ?i32 { | ||
| 6 | const letter = source[0]; | ||
| 7 | const modifier = source[1]; | ||
| 8 | |||
| 9 | const semitone = blk: { | ||
| 10 | if (letter == 'C' and modifier == '-') break :blk @as(i32, 0); | ||
| 11 | if (letter == 'C' and modifier == '#') break :blk @as(i32, 1); | ||
| 12 | if (letter == 'D' and modifier == '-') break :blk @as(i32, 2); | ||
| 13 | if (letter == 'D' and modifier == '#') break :blk @as(i32, 3); | ||
| 14 | if (letter == 'E' and modifier == '-') break :blk @as(i32, 4); | ||
| 15 | if (letter == 'F' and modifier == '-') break :blk @as(i32, 5); | ||
| 16 | if (letter == 'F' and modifier == '#') break :blk @as(i32, 6); | ||
| 17 | if (letter == 'G' and modifier == '-') break :blk @as(i32, 7); | ||
| 18 | if (letter == 'G' and modifier == '#') break :blk @as(i32, 8); | ||
| 19 | if (letter == 'A' and modifier == '-') break :blk @as(i32, 9); | ||
| 20 | if (letter == 'A' and modifier == '#') break :blk @as(i32, 10); | ||
| 21 | if (letter == 'B' and modifier == '-') break :blk @as(i32, 11); | ||
| 22 | return null; | ||
| 23 | }; | ||
| 24 | |||
| 25 | return semitone; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "fixed" { | ||
| 29 | const result = parseNote(); | ||
| 30 | try std.testing.expect(result.? == 9); | ||
| 31 | } | ||
test/behavior/bugs/3007.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | free: bool, | ||
| 5 | |||
| 6 | pub const FooError = error{NotFree}; | ||
| 7 | }; | ||
| 8 | |||
| 9 | var foo = Foo{ .free = true }; | ||
| 10 | var default_foo: ?*Foo = null; | ||
| 11 | |||
| 12 | fn get_foo() Foo.FooError!*Foo { | ||
| 13 | if (foo.free) { | ||
| 14 | foo.free = false; | ||
| 15 | return &foo; | ||
| 16 | } | ||
| 17 | return error.NotFree; | ||
| 18 | } | ||
| 19 | |||
| 20 | test "fixed" { | ||
| 21 | default_foo = get_foo() catch null; // This Line | ||
| 22 | try std.testing.expect(!default_foo.?.free); | ||
| 23 | } | ||
test/behavior/bugs/3046.zig created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const SomeStruct = struct { | ||
| 5 | field: i32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn couldFail() anyerror!i32 { | ||
| 9 | return 1; | ||
| 10 | } | ||
| 11 | |||
| 12 | var some_struct: SomeStruct = undefined; | ||
| 13 | |||
| 14 | test "fixed" { | ||
| 15 | some_struct = SomeStruct{ | ||
| 16 | .field = couldFail() catch |_| @as(i32, 0), | ||
| 17 | }; | ||
| 18 | try expect(some_struct.field == 1); | ||
| 19 | } | ||
test/behavior/bugs/3112.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const State = struct { | ||
| 5 | const Self = @This(); | ||
| 6 | enter: fn (previous: ?Self) void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | fn prev(p: ?State) void { | ||
| 10 | expect(p == null) catch @panic("test failure"); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "zig test crash" { | ||
| 14 | var global: State = undefined; | ||
| 15 | global.enter = prev; | ||
| 16 | global.enter(null); | ||
| 17 | } | ||
test/behavior/bugs/3367.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | usingnamespace Mixin; | ||
| 3 | }; | ||
| 4 | |||
| 5 | const Mixin = struct { | ||
| 6 | pub fn two(self: Foo) void {} | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "container member access usingnamespace decls" { | ||
| 10 | var foo = Foo{}; | ||
| 11 | foo.two(); | ||
| 12 | } | ||
test/behavior/bugs/3384.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "resolve array slice using builtin" { | ||
| 5 | try expect(@hasDecl(@This(), "std") == true); | ||
| 6 | try expect(@hasDecl(@This(), "std"[0..0]) == false); | ||
| 7 | try expect(@hasDecl(@This(), "std"[0..1]) == false); | ||
| 8 | try expect(@hasDecl(@This(), "std"[0..2]) == false); | ||
| 9 | try expect(@hasDecl(@This(), "std"[0..3]) == true); | ||
| 10 | try expect(@hasDecl(@This(), "std"[0..]) == true); | ||
| 11 | } | ||
test/behavior/bugs/3468.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | // zig fmt: off | ||
| 2 | test "pointer deref next to assignment" { | ||
| 3 | var a:i32=2; | ||
| 4 | var b=&a; | ||
| 5 | b.*=3; | ||
| 6 | } | ||
test/behavior/bugs/3586.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const NoteParams = struct {}; | ||
| 2 | |||
| 3 | const Container = struct { | ||
| 4 | params: ?NoteParams, | ||
| 5 | }; | ||
| 6 | |||
| 7 | test "fixed" { | ||
| 8 | var ctr = Container{ | ||
| 9 | .params = NoteParams{}, | ||
| 10 | }; | ||
| 11 | } | ||
test/behavior/bugs/3742.zig created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub const GET = struct { | ||
| 4 | key: []const u8, | ||
| 5 | |||
| 6 | pub fn init(key: []const u8) GET { | ||
| 7 | return .{ .key = key }; | ||
| 8 | } | ||
| 9 | |||
| 10 | pub const Redis = struct { | ||
| 11 | pub const Command = struct { | ||
| 12 | pub fn serialize(self: GET, comptime rootSerializer: type) void { | ||
| 13 | return rootSerializer.serializeCommand(.{ "GET", self.key }); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub fn isCommand(comptime T: type) bool { | ||
| 20 | const tid = @typeInfo(T); | ||
| 21 | return (tid == .Struct or tid == .Enum or tid == .Union) and | ||
| 22 | @hasDecl(T, "Redis") and @hasDecl(T.Redis, "Command"); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub const ArgSerializer = struct { | ||
| 26 | pub fn serializeCommand(command: anytype) void { | ||
| 27 | const CmdT = @TypeOf(command); | ||
| 28 | |||
| 29 | if (comptime isCommand(CmdT)) { | ||
| 30 | // COMMENTING THE NEXT LINE REMOVES THE ERROR | ||
| 31 | return CmdT.Redis.Command.serialize(command, ArgSerializer); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | test "fixed" { | ||
| 37 | ArgSerializer.serializeCommand(GET.init("banana")); | ||
| 38 | } | ||
test/behavior/bugs/394.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const E = union(enum) { | ||
| 2 | A: [9]u8, | ||
| 3 | B: u64, | ||
| 4 | }; | ||
| 5 | const S = struct { | ||
| 6 | x: u8, | ||
| 7 | y: E, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const expect = @import("std").testing.expect; | ||
| 11 | |||
| 12 | test "bug 394 fixed" { | ||
| 13 | const x = S{ | ||
| 14 | .x = 3, | ||
| 15 | .y = E{ .B = 1 }, | ||
| 16 | }; | ||
| 17 | try expect(x.x == 3); | ||
| 18 | } | ||
test/behavior/bugs/421.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "bitCast to array" { | ||
| 4 | comptime try testBitCastArray(); | ||
| 5 | try testBitCastArray(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testBitCastArray() !void { | ||
| 9 | try expect(extractOne64(0x0123456789abcdef0123456789abcdef) == 0x0123456789abcdef); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn extractOne64(a: u128) u64 { | ||
| 13 | const x = @bitCast([2]u64, a); | ||
| 14 | return x[1]; | ||
| 15 | } | ||
test/behavior/bugs/4328.zig created+71| ... | @@ -0,0 +1,71 @@ | ||
| 1 | const expectEqual = @import("std").testing.expectEqual; | ||
| 2 | |||
| 3 | const FILE = extern struct { | ||
| 4 | dummy_field: u8, | ||
| 5 | }; | ||
| 6 | |||
| 7 | extern fn printf([*c]const u8, ...) c_int; | ||
| 8 | extern fn fputs([*c]const u8, noalias [*c]FILE) c_int; | ||
| 9 | extern fn ftell([*c]FILE) c_long; | ||
| 10 | extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE; | ||
| 11 | |||
| 12 | const S = extern struct { | ||
| 13 | state: c_short, | ||
| 14 | |||
| 15 | extern fn s_do_thing([*c]S, b: c_int) c_short; | ||
| 16 | }; | ||
| 17 | |||
| 18 | test "Extern function calls in @TypeOf" { | ||
| 19 | const Test = struct { | ||
| 20 | fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) { | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn test_fn_2(a: anytype) @TypeOf((S{ .state = 0 }).s_do_thing(a)) { | ||
| 25 | return 1; | ||
| 26 | } | ||
| 27 | |||
| 28 | fn doTheTest() !void { | ||
| 29 | try expectEqual(c_int, @TypeOf(test_fn_1(0, 42))); | ||
| 30 | try expectEqual(c_short, @TypeOf(test_fn_2(0))); | ||
| 31 | } | ||
| 32 | }; | ||
| 33 | |||
| 34 | try Test.doTheTest(); | ||
| 35 | comptime try Test.doTheTest(); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "Peer resolution of extern function calls in @TypeOf" { | ||
| 39 | const Test = struct { | ||
| 40 | fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | fn doTheTest() !void { | ||
| 45 | try expectEqual(c_long, @TypeOf(test_fn())); | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | try Test.doTheTest(); | ||
| 50 | comptime try Test.doTheTest(); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "Extern function calls, dereferences and field access in @TypeOf" { | ||
| 54 | const Test = struct { | ||
| 55 | fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) { | ||
| 56 | return .{ .dummy_field = 0 }; | ||
| 57 | } | ||
| 58 | |||
| 59 | fn test_fn_2(a: anytype) @TypeOf(fopen("test", "r").*.dummy_field) { | ||
| 60 | return 255; | ||
| 61 | } | ||
| 62 | |||
| 63 | fn doTheTest() !void { | ||
| 64 | try expectEqual(FILE, @TypeOf(test_fn_1(0))); | ||
| 65 | try expectEqual(u8, @TypeOf(test_fn_2(0))); | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | |||
| 69 | try Test.doTheTest(); | ||
| 70 | comptime try Test.doTheTest(); | ||
| 71 | } | ||
test/behavior/bugs/4560.zig created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "fixed" { | ||
| 4 | var s: S = .{ | ||
| 5 | .a = 1, | ||
| 6 | .b = .{ | ||
| 7 | .size = 123, | ||
| 8 | .max_distance_from_start_index = 456, | ||
| 9 | }, | ||
| 10 | }; | ||
| 11 | try std.testing.expect(s.a == 1); | ||
| 12 | try std.testing.expect(s.b.size == 123); | ||
| 13 | try std.testing.expect(s.b.max_distance_from_start_index == 456); | ||
| 14 | } | ||
| 15 | |||
| 16 | const S = struct { | ||
| 17 | a: u32, | ||
| 18 | b: Map, | ||
| 19 | |||
| 20 | const Map = StringHashMap(*S); | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub fn StringHashMap(comptime V: type) type { | ||
| 24 | return HashMap([]const u8, V); | ||
| 25 | } | ||
| 26 | |||
| 27 | pub fn HashMap(comptime K: type, comptime V: type) type { | ||
| 28 | return struct { | ||
| 29 | size: usize, | ||
| 30 | max_distance_from_start_index: usize, | ||
| 31 | }; | ||
| 32 | } | ||
test/behavior/bugs/4769_a.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | // | ||
test/behavior/bugs/4769_b.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | //! | ||
test/behavior/bugs/4769_c.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | /// | ||
| \ No newline at end of file | |||
test/behavior/bugs/4954.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | fn f(buf: []u8) void { | ||
| 2 | var ptr = &buf[@sizeOf(u32)]; | ||
| 3 | } | ||
| 4 | |||
| 5 | test "crash" { | ||
| 6 | var buf: [4096]u8 = undefined; | ||
| 7 | f(&buf); | ||
| 8 | } | ||
test/behavior/bugs/529.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | |||
| 5 | extern fn issue529(?*A) void; | ||
| 6 | |||
| 7 | comptime { | ||
| 8 | _ = @import("529_other_file_2.zig"); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "issue 529 fixed" { | ||
| 12 | @import("529_other_file.zig").issue529(null); | ||
| 13 | issue529(null); | ||
| 14 | } | ||
test/behavior/bugs/529_other_file.zig created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | pub const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | |||
| 5 | pub extern fn issue529(?*A) void; | ||
test/behavior/bugs/529_other_file_2.zig created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | pub const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | export fn issue529(a: ?*A) void {} | ||
test/behavior/bugs/5398.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | |||
| 4 | pub const Mesh = struct { | ||
| 5 | id: u32, | ||
| 6 | }; | ||
| 7 | pub const Material = struct { | ||
| 8 | transparent: bool = true, | ||
| 9 | emits_shadows: bool = true, | ||
| 10 | render_color: bool = true, | ||
| 11 | }; | ||
| 12 | pub const Renderable = struct { | ||
| 13 | material: Material, | ||
| 14 | // The compiler inserts some padding here to ensure Mesh is correctly aligned. | ||
| 15 | mesh: Mesh, | ||
| 16 | }; | ||
| 17 | |||
| 18 | var renderable: Renderable = undefined; | ||
| 19 | |||
| 20 | test "assignment of field with padding" { | ||
| 21 | renderable = Renderable{ | ||
| 22 | .mesh = Mesh{ .id = 0 }, | ||
| 23 | .material = Material{ | ||
| 24 | .transparent = false, | ||
| 25 | .emits_shadows = false, | ||
| 26 | }, | ||
| 27 | }; | ||
| 28 | try testing.expectEqual(false, renderable.material.transparent); | ||
| 29 | try testing.expectEqual(false, renderable.material.emits_shadows); | ||
| 30 | try testing.expectEqual(true, renderable.material.render_color); | ||
| 31 | } | ||
test/behavior/bugs/5413.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "Peer type resolution with string literals and unknown length u8 pointers" { | ||
| 4 | try expect(@TypeOf("", "a", @as([*:0]const u8, "")) == [*:0]const u8); | ||
| 5 | try expect(@TypeOf(@as([*:0]const u8, "baz"), "foo", "bar") == [*:0]const u8); | ||
| 6 | } | ||
test/behavior/bugs/5474.zig created+57| ... | @@ -0,0 +1,57 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | // baseline (control) struct with array of scalar | ||
| 4 | const Box0 = struct { | ||
| 5 | items: [4]Item, | ||
| 6 | |||
| 7 | const Item = struct { | ||
| 8 | num: u32, | ||
| 9 | }; | ||
| 10 | }; | ||
| 11 | |||
| 12 | // struct with array of empty struct | ||
| 13 | const Box1 = struct { | ||
| 14 | items: [4]Item, | ||
| 15 | |||
| 16 | const Item = struct {}; | ||
| 17 | }; | ||
| 18 | |||
| 19 | // struct with array of zero-size struct | ||
| 20 | const Box2 = struct { | ||
| 21 | items: [4]Item, | ||
| 22 | |||
| 23 | const Item = struct { | ||
| 24 | nothing: void, | ||
| 25 | }; | ||
| 26 | }; | ||
| 27 | |||
| 28 | fn doTest() !void { | ||
| 29 | // var | ||
| 30 | { | ||
| 31 | var box0: Box0 = .{ .items = undefined }; | ||
| 32 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == false); | ||
| 33 | |||
| 34 | var box1: Box1 = .{ .items = undefined }; | ||
| 35 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == false); | ||
| 36 | |||
| 37 | var box2: Box2 = .{ .items = undefined }; | ||
| 38 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == false); | ||
| 39 | } | ||
| 40 | |||
| 41 | // const | ||
| 42 | { | ||
| 43 | const box0: Box0 = .{ .items = undefined }; | ||
| 44 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == true); | ||
| 45 | |||
| 46 | const box1: Box1 = .{ .items = undefined }; | ||
| 47 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == true); | ||
| 48 | |||
| 49 | const box2: Box2 = .{ .items = undefined }; | ||
| 50 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == true); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | test "pointer-to-array constness for zero-size elements" { | ||
| 55 | try doTest(); | ||
| 56 | comptime try doTest(); | ||
| 57 | } | ||
test/behavior/bugs/5487.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const io = @import("std").io; | ||
| 2 | |||
| 3 | pub fn write(_: void, bytes: []const u8) !usize { | ||
| 4 | return 0; | ||
| 5 | } | ||
| 6 | pub fn writer() io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write) { | ||
| 7 | return io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write){ .context = {} }; | ||
| 8 | } | ||
| 9 | |||
| 10 | test "crash" { | ||
| 11 | _ = io.multiWriter(.{writer()}); | ||
| 12 | } | ||
test/behavior/bugs/624.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const TestContext = struct { | ||
| 5 | server_context: *ListenerContext, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const ListenerContext = struct { | ||
| 9 | context_alloc: *ContextAllocator, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const ContextAllocator = MemoryPool(TestContext); | ||
| 13 | |||
| 14 | fn MemoryPool(comptime T: type) type { | ||
| 15 | return struct { | ||
| 16 | n: usize, | ||
| 17 | }; | ||
| 18 | } | ||
| 19 | |||
| 20 | test "foo" { | ||
| 21 | var allocator = ContextAllocator{ .n = 10 }; | ||
| 22 | try expect(allocator.n == 10); | ||
| 23 | } | ||
test/behavior/bugs/6456.zig created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const StructField = std.builtin.TypeInfo.StructField; | ||
| 4 | const Declaration = std.builtin.TypeInfo.Declaration; | ||
| 5 | |||
| 6 | const text = | ||
| 7 | \\f1 | ||
| 8 | \\f2 | ||
| 9 | \\f3 | ||
| 10 | ; | ||
| 11 | |||
| 12 | test "issue 6456" { | ||
| 13 | comptime { | ||
| 14 | var fields: []const StructField = &[0]StructField{}; | ||
| 15 | |||
| 16 | var it = std.mem.tokenize(text, "\n"); | ||
| 17 | while (it.next()) |name| { | ||
| 18 | fields = fields ++ &[_]StructField{StructField{ | ||
| 19 | .alignment = 0, | ||
| 20 | .name = name, | ||
| 21 | .field_type = usize, | ||
| 22 | .default_value = @as(?usize, null), | ||
| 23 | .is_comptime = false, | ||
| 24 | }}; | ||
| 25 | } | ||
| 26 | |||
| 27 | const T = @Type(.{ | ||
| 28 | .Struct = .{ | ||
| 29 | .layout = .Auto, | ||
| 30 | .is_tuple = false, | ||
| 31 | .fields = fields, | ||
| 32 | .decls = &[_]Declaration{}, | ||
| 33 | }, | ||
| 34 | }); | ||
| 35 | |||
| 36 | const gen_fields = @typeInfo(T).Struct.fields; | ||
| 37 | try testing.expectEqual(3, gen_fields.len); | ||
| 38 | try testing.expectEqualStrings("f1", gen_fields[0].name); | ||
| 39 | try testing.expectEqualStrings("f2", gen_fields[1].name); | ||
| 40 | try testing.expectEqualStrings("f3", gen_fields[2].name); | ||
| 41 | } | ||
| 42 | } | ||
test/behavior/bugs/655.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const other_file = @import("655_other_file.zig"); | ||
| 3 | |||
| 4 | test "function with *const parameter with type dereferenced by namespace" { | ||
| 5 | const x: other_file.Integer = 1234; | ||
| 6 | comptime try std.testing.expect(@TypeOf(&x) == *const other_file.Integer); | ||
| 7 | try foo(&x); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn foo(x: *const other_file.Integer) !void { | ||
| 11 | try std.testing.expect(x.* == 1234); | ||
| 12 | } | ||
test/behavior/bugs/655_other_file.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const Integer = u32; | ||
test/behavior/bugs/656.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const PrefixOp = union(enum) { | ||
| 4 | Return, | ||
| 5 | AddrOf: Value, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Value = struct { | ||
| 9 | align_expr: ?u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { | ||
| 13 | try foo(false, true); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(a: bool, b: bool) !void { | ||
| 17 | var prefix_op = PrefixOp{ | ||
| 18 | .AddrOf = Value{ .align_expr = 1234 }, | ||
| 19 | }; | ||
| 20 | if (a) {} else { | ||
| 21 | switch (prefix_op) { | ||
| 22 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 23 | if (b) {} | ||
| 24 | if (addr_of_info.align_expr) |align_expr| { | ||
| 25 | try expect(align_expr == 1234); | ||
| 26 | } | ||
| 27 | }, | ||
| 28 | PrefixOp.Return => {}, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
test/behavior/bugs/6781.zig created+74| ... | @@ -0,0 +1,74 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | const segfault = true; | ||
| 5 | |||
| 6 | pub const JournalHeader = packed struct { | ||
| 7 | hash_chain_root: u128 = undefined, | ||
| 8 | prev_hash_chain_root: u128, | ||
| 9 | checksum: u128 = undefined, | ||
| 10 | magic: u64, | ||
| 11 | command: u32, | ||
| 12 | size: u32, | ||
| 13 | |||
| 14 | pub fn calculate_checksum(self: *const JournalHeader, entry: []const u8) u128 { | ||
| 15 | assert(entry.len >= @sizeOf(JournalHeader)); | ||
| 16 | assert(entry.len == self.size); | ||
| 17 | |||
| 18 | const checksum_offset = @byteOffsetOf(JournalHeader, "checksum"); | ||
| 19 | const checksum_size = @sizeOf(@TypeOf(self.checksum)); | ||
| 20 | assert(checksum_offset == 0 + 16 + 16); | ||
| 21 | assert(checksum_size == 16); | ||
| 22 | |||
| 23 | var target: [32]u8 = undefined; | ||
| 24 | std.crypto.hash.Blake3.hash(entry[checksum_offset + checksum_size ..], target[0..], .{}); | ||
| 25 | return @bitCast(u128, target[0..checksum_size].*); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn calculate_hash_chain_root(self: *const JournalHeader) u128 { | ||
| 29 | const hash_chain_root_size = @sizeOf(@TypeOf(self.hash_chain_root)); | ||
| 30 | assert(hash_chain_root_size == 16); | ||
| 31 | |||
| 32 | const prev_hash_chain_root_offset = @byteOffsetOf(JournalHeader, "prev_hash_chain_root"); | ||
| 33 | const prev_hash_chain_root_size = @sizeOf(@TypeOf(self.prev_hash_chain_root)); | ||
| 34 | assert(prev_hash_chain_root_offset == 0 + 16); | ||
| 35 | assert(prev_hash_chain_root_size == 16); | ||
| 36 | |||
| 37 | const checksum_offset = @byteOffsetOf(JournalHeader, "checksum"); | ||
| 38 | const checksum_size = @sizeOf(@TypeOf(self.checksum)); | ||
| 39 | assert(checksum_offset == 0 + 16 + 16); | ||
| 40 | assert(checksum_size == 16); | ||
| 41 | |||
| 42 | assert(prev_hash_chain_root_offset + prev_hash_chain_root_size == checksum_offset); | ||
| 43 | |||
| 44 | const header = @bitCast([@sizeOf(JournalHeader)]u8, self.*); | ||
| 45 | const source = header[prev_hash_chain_root_offset .. checksum_offset + checksum_size]; | ||
| 46 | assert(source.len == prev_hash_chain_root_size + checksum_size); | ||
| 47 | var target: [32]u8 = undefined; | ||
| 48 | std.crypto.hash.Blake3.hash(source, target[0..], .{}); | ||
| 49 | if (segfault) { | ||
| 50 | return @bitCast(u128, target[0..hash_chain_root_size].*); | ||
| 51 | } else { | ||
| 52 | var array = target[0..hash_chain_root_size].*; | ||
| 53 | return @bitCast(u128, array); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn set_checksum_and_hash_chain_root(self: *JournalHeader, entry: []const u8) void { | ||
| 58 | self.checksum = self.calculate_checksum(entry); | ||
| 59 | self.hash_chain_root = self.calculate_hash_chain_root(); | ||
| 60 | } | ||
| 61 | }; | ||
| 62 | |||
| 63 | test "fixed" { | ||
| 64 | var buffer = [_]u8{0} ** 65536; | ||
| 65 | var entry = std.mem.bytesAsValue(JournalHeader, buffer[0..@sizeOf(JournalHeader)]); | ||
| 66 | entry.* = .{ | ||
| 67 | .prev_hash_chain_root = 0, | ||
| 68 | .magic = 0, | ||
| 69 | .command = 0, | ||
| 70 | .size = 64 + 128, | ||
| 71 | }; | ||
| 72 | entry.set_checksum_and_hash_chain_root(buffer[0..entry.size]); | ||
| 73 | try std.io.null_writer.print("{}\n", .{entry}); | ||
| 74 | } | ||
test/behavior/bugs/679.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | pub fn List(comptime T: type) type { | ||
| 5 | return u32; | ||
| 6 | } | ||
| 7 | |||
| 8 | const ElementList = List(Element); | ||
| 9 | const Element = struct { | ||
| 10 | link: ElementList, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "false dependency loop in struct definition" { | ||
| 14 | const listType = ElementList; | ||
| 15 | var x: listType = 42; | ||
| 16 | try expect(x == 42); | ||
| 17 | } | ||
test/behavior/bugs/6850.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "lazy sizeof comparison with zero" { | ||
| 4 | const Empty = struct {}; | ||
| 5 | const T = *Empty; | ||
| 6 | |||
| 7 | try std.testing.expect(hasNoBits(T)); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn hasNoBits(comptime T: type) bool { | ||
| 11 | return @sizeOf(T) == 0; | ||
| 12 | } | ||
test/behavior/bugs/7003.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | test "@Type should resolve its children types" { | ||
| 2 | const sparse = enum(u2) { a, b, c }; | ||
| 3 | const dense = enum(u2) { a, b, c, d }; | ||
| 4 | |||
| 5 | comptime var sparse_info = @typeInfo(anyerror!sparse); | ||
| 6 | sparse_info.ErrorUnion.payload = dense; | ||
| 7 | const B = @Type(sparse_info); | ||
| 8 | } | ||
test/behavior/bugs/7027.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const Foobar = struct { | ||
| 2 | myTypes: [128]type, | ||
| 3 | str: [1024]u8, | ||
| 4 | |||
| 5 | fn foo() @This() { | ||
| 6 | comptime var foobar: Foobar = undefined; | ||
| 7 | foobar.str = [_]u8{'a'} ** 1024; | ||
| 8 | return foobar; | ||
| 9 | } | ||
| 10 | }; | ||
| 11 | |||
| 12 | fn foo(arg: anytype) void {} | ||
| 13 | |||
| 14 | test "" { | ||
| 15 | comptime var foobar = Foobar.foo(); | ||
| 16 | foo(foobar.str[0..10]); | ||
| 17 | } | ||
test/behavior/bugs/704.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | const xxx = struct { | ||
| 2 | pub fn bar(self: *xxx) void {} | ||
| 3 | }; | ||
| 4 | test "bug 704" { | ||
| 5 | var x: xxx = undefined; | ||
| 6 | x.bar(); | ||
| 7 | } | ||
test/behavior/bugs/7047.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const U = union(enum) { | ||
| 4 | T: type, | ||
| 5 | N: void, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn S(comptime query: U) type { | ||
| 9 | return struct { | ||
| 10 | fn tag() type { | ||
| 11 | return query.T; | ||
| 12 | } | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "compiler doesn't consider equal unions with different 'type' payload" { | ||
| 17 | const s1 = S(U{ .T = u32 }).tag(); | ||
| 18 | try std.testing.expectEqual(u32, s1); | ||
| 19 | |||
| 20 | const s2 = S(U{ .T = u64 }).tag(); | ||
| 21 | try std.testing.expectEqual(u64, s2); | ||
| 22 | } | ||
test/behavior/bugs/718.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const Keys = struct { | ||
| 5 | up: bool, | ||
| 6 | down: bool, | ||
| 7 | left: bool, | ||
| 8 | right: bool, | ||
| 9 | }; | ||
| 10 | var keys: Keys = undefined; | ||
| 11 | test "zero keys with @memset" { | ||
| 12 | @memset(@ptrCast([*]u8, &keys), 0, @sizeOf(@TypeOf(keys))); | ||
| 13 | try expect(!keys.up); | ||
| 14 | try expect(!keys.down); | ||
| 15 | try expect(!keys.left); | ||
| 16 | try expect(!keys.right); | ||
| 17 | } | ||
test/behavior/bugs/7250.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const nrfx_uart_t = extern struct { | ||
| 2 | p_reg: [*c]u32, | ||
| 3 | drv_inst_idx: u8, | ||
| 4 | }; | ||
| 5 | |||
| 6 | pub fn nrfx_uart_rx(p_instance: [*c]const nrfx_uart_t) void {} | ||
| 7 | |||
| 8 | threadlocal var g_uart0 = nrfx_uart_t{ | ||
| 9 | .p_reg = 0, | ||
| 10 | .drv_inst_idx = 0, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "reference a global threadlocal variable" { | ||
| 14 | _ = nrfx_uart_rx(&g_uart0); | ||
| 15 | } | ||
test/behavior/bugs/726.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@ptrCast from const to nullable" { | ||
| 4 | const c: u8 = 4; | ||
| 5 | var x: ?*const u8 = @ptrCast(?*const u8, &c); | ||
| 6 | try expect(x.?.* == 4); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "@ptrCast from var in empty struct to nullable" { | ||
| 10 | const container = struct { | ||
| 11 | var c: u8 = 4; | ||
| 12 | }; | ||
| 13 | var x: ?*const u8 = @ptrCast(?*const u8, &container.c); | ||
| 14 | try expect(x.?.* == 4); | ||
| 15 | } | ||
test/behavior/bugs/828.zig created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | const CountBy = struct { | ||
| 2 | a: usize, | ||
| 3 | |||
| 4 | const One = CountBy{ .a = 1 }; | ||
| 5 | |||
| 6 | pub fn counter(self: *const CountBy) Counter { | ||
| 7 | return Counter{ .i = 0 }; | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Counter = struct { | ||
| 12 | i: usize, | ||
| 13 | |||
| 14 | pub fn count(self: *Counter) bool { | ||
| 15 | self.i += 1; | ||
| 16 | return self.i <= 10; | ||
| 17 | } | ||
| 18 | }; | ||
| 19 | |||
| 20 | fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { | ||
| 21 | comptime { | ||
| 22 | var cnt = cb.counter(); | ||
| 23 | if (cnt.i != 0) @compileError("Counter instance reused!"); | ||
| 24 | while (cnt.count()) {} | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "comptime struct return should not return the same instance" { | ||
| 29 | //the first parameter must be passed by reference to trigger the bug | ||
| 30 | //a second parameter is required to trigger the bug | ||
| 31 | const ValA = constCount(&CountBy.One, 12); | ||
| 32 | const ValB = constCount(&CountBy.One, 15); | ||
| 33 | } | ||
test/behavior/bugs/920.zig created+65| ... | @@ -0,0 +1,65 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const Random = std.rand.Random; | ||
| 4 | |||
| 5 | const ZigTable = struct { | ||
| 6 | r: f64, | ||
| 7 | x: [257]f64, | ||
| 8 | f: [257]f64, | ||
| 9 | |||
| 10 | pdf: fn (f64) f64, | ||
| 11 | is_symmetric: bool, | ||
| 12 | zero_case: fn (*Random, f64) f64, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { | ||
| 16 | var tables: ZigTable = undefined; | ||
| 17 | |||
| 18 | tables.is_symmetric = is_symmetric; | ||
| 19 | tables.r = r; | ||
| 20 | tables.pdf = f; | ||
| 21 | tables.zero_case = zero_case; | ||
| 22 | |||
| 23 | tables.x[0] = v / f(r); | ||
| 24 | tables.x[1] = r; | ||
| 25 | |||
| 26 | for (tables.x[2..256]) |*entry, i| { | ||
| 27 | const last = tables.x[2 + i - 1]; | ||
| 28 | entry.* = f_inv(v / last + f(last)); | ||
| 29 | } | ||
| 30 | tables.x[256] = 0; | ||
| 31 | |||
| 32 | for (tables.f[0..]) |*entry, i| { | ||
| 33 | entry.* = f(tables.x[i]); | ||
| 34 | } | ||
| 35 | |||
| 36 | return tables; | ||
| 37 | } | ||
| 38 | |||
| 39 | const norm_r = 3.6541528853610088; | ||
| 40 | const norm_v = 0.00492867323399; | ||
| 41 | |||
| 42 | fn norm_f(x: f64) f64 { | ||
| 43 | return math.exp(-x * x / 2.0); | ||
| 44 | } | ||
| 45 | fn norm_f_inv(y: f64) f64 { | ||
| 46 | return math.sqrt(-2.0 * math.ln(y)); | ||
| 47 | } | ||
| 48 | fn norm_zero_case(random: *Random, u: f64) f64 { | ||
| 49 | return 0.0; | ||
| 50 | } | ||
| 51 | |||
| 52 | const NormalDist = blk: { | ||
| 53 | @setEvalBranchQuota(30000); | ||
| 54 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 55 | }; | ||
| 56 | |||
| 57 | test "bug 920 fixed" { | ||
| 58 | const NormalDist1 = blk: { | ||
| 59 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 60 | }; | ||
| 61 | |||
| 62 | for (NormalDist1.f) |_, i| { | ||
| 63 | try std.testing.expectEqual(NormalDist1.f[i], NormalDist.f[i]); | ||
| 64 | } | ||
| 65 | } | ||
test/behavior/byteswap.zig created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "@byteSwap integers" { | ||
| 5 | const ByteSwapIntTest = struct { | ||
| 6 | fn run() !void { | ||
| 7 | try t(u0, 0, 0); | ||
| 8 | try t(u8, 0x12, 0x12); | ||
| 9 | try t(u16, 0x1234, 0x3412); | ||
| 10 | try t(u24, 0x123456, 0x563412); | ||
| 11 | try t(u32, 0x12345678, 0x78563412); | ||
| 12 | try t(u40, 0x123456789a, 0x9a78563412); | ||
| 13 | try t(i48, 0x123456789abc, @bitCast(i48, @as(u48, 0xbc9a78563412))); | ||
| 14 | try t(u56, 0x123456789abcde, 0xdebc9a78563412); | ||
| 15 | try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); | ||
| 16 | try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | ||
| 17 | |||
| 18 | try t(u0, @as(u0, 0), 0); | ||
| 19 | try t(i8, @as(i8, -50), -50); | ||
| 20 | try t(i16, @bitCast(i16, @as(u16, 0x1234)), @bitCast(i16, @as(u16, 0x3412))); | ||
| 21 | try t(i24, @bitCast(i24, @as(u24, 0x123456)), @bitCast(i24, @as(u24, 0x563412))); | ||
| 22 | try t(i32, @bitCast(i32, @as(u32, 0x12345678)), @bitCast(i32, @as(u32, 0x78563412))); | ||
| 23 | try t(u40, @bitCast(i40, @as(u40, 0x123456789a)), @as(u40, 0x9a78563412)); | ||
| 24 | try t(i48, @bitCast(i48, @as(u48, 0x123456789abc)), @bitCast(i48, @as(u48, 0xbc9a78563412))); | ||
| 25 | try t(i56, @bitCast(i56, @as(u56, 0x123456789abcde)), @bitCast(i56, @as(u56, 0xdebc9a78563412))); | ||
| 26 | try t(i64, @bitCast(i64, @as(u64, 0x123456789abcdef1)), @bitCast(i64, @as(u64, 0xf1debc9a78563412))); | ||
| 27 | try t( | ||
| 28 | i128, | ||
| 29 | @bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181)), | ||
| 30 | @bitCast(i128, @as(u128, 0x8171615141312111f1debc9a78563412)), | ||
| 31 | ); | ||
| 32 | } | ||
| 33 | fn t(comptime I: type, input: I, expected_output: I) !void { | ||
| 34 | try std.testing.expectEqual(expected_output, @byteSwap(I, input)); | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | comptime try ByteSwapIntTest.run(); | ||
| 38 | try ByteSwapIntTest.run(); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "@byteSwap vectors" { | ||
| 42 | // https://github.com/ziglang/zig/issues/3563 | ||
| 43 | if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest; | ||
| 44 | |||
| 45 | // https://github.com/ziglang/zig/issues/3317 | ||
| 46 | if (std.Target.current.cpu.arch == .mipsel or std.Target.current.cpu.arch == .mips) return error.SkipZigTest; | ||
| 47 | |||
| 48 | const ByteSwapVectorTest = struct { | ||
| 49 | fn run() !void { | ||
| 50 | try t(u8, 2, [_]u8{ 0x12, 0x13 }, [_]u8{ 0x12, 0x13 }); | ||
| 51 | try t(u16, 2, [_]u16{ 0x1234, 0x2345 }, [_]u16{ 0x3412, 0x4523 }); | ||
| 52 | try t(u24, 2, [_]u24{ 0x123456, 0x234567 }, [_]u24{ 0x563412, 0x674523 }); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn t( | ||
| 56 | comptime I: type, | ||
| 57 | comptime n: comptime_int, | ||
| 58 | input: std.meta.Vector(n, I), | ||
| 59 | expected_vector: std.meta.Vector(n, I), | ||
| 60 | ) !void { | ||
| 61 | const actual_output: [n]I = @byteSwap(I, input); | ||
| 62 | const expected_output: [n]I = expected_vector; | ||
| 63 | try std.testing.expectEqual(expected_output, actual_output); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | comptime try ByteSwapVectorTest.run(); | ||
| 67 | try ByteSwapVectorTest.run(); | ||
| 68 | } | ||
test/behavior/byval_arg_var.zig created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var result: []const u8 = "wrong"; | ||
| 4 | |||
| 5 | test "pass string literal byvalue to a generic var param" { | ||
| 6 | start(); | ||
| 7 | blowUpStack(10); | ||
| 8 | |||
| 9 | try std.testing.expect(std.mem.eql(u8, result, "string literal")); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn start() void { | ||
| 13 | foo("string literal"); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(x: anytype) void { | ||
| 17 | bar(x); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn bar(x: anytype) void { | ||
| 21 | result = x; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn blowUpStack(x: u32) void { | ||
| 25 | if (x == 0) return; | ||
| 26 | blowUpStack(x - 1); | ||
| 27 | } | ||
test/behavior/call.zig created+74| ... | @@ -0,0 +1,74 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | |||
| 5 | test "basic invocations" { | ||
| 6 | const foo = struct { | ||
| 7 | fn foo() i32 { | ||
| 8 | return 1234; | ||
| 9 | } | ||
| 10 | }.foo; | ||
| 11 | try expect(@call(.{}, foo, .{}) == 1234); | ||
| 12 | comptime { | ||
| 13 | // modifiers that allow comptime calls | ||
| 14 | try expect(@call(.{}, foo, .{}) == 1234); | ||
| 15 | try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234); | ||
| 16 | try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234); | ||
| 17 | try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234); | ||
| 18 | } | ||
| 19 | { | ||
| 20 | // comptime call without comptime keyword | ||
| 21 | const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234; | ||
| 22 | comptime try expect(result); | ||
| 23 | } | ||
| 24 | { | ||
| 25 | // call of non comptime-known function | ||
| 26 | var alias_foo = foo; | ||
| 27 | try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234); | ||
| 28 | try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234); | ||
| 29 | try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | test "tuple parameters" { | ||
| 34 | const add = struct { | ||
| 35 | fn add(a: i32, b: i32) i32 { | ||
| 36 | return a + b; | ||
| 37 | } | ||
| 38 | }.add; | ||
| 39 | var a: i32 = 12; | ||
| 40 | var b: i32 = 34; | ||
| 41 | try expect(@call(.{}, add, .{ a, 34 }) == 46); | ||
| 42 | try expect(@call(.{}, add, .{ 12, b }) == 46); | ||
| 43 | try expect(@call(.{}, add, .{ a, b }) == 46); | ||
| 44 | try expect(@call(.{}, add, .{ 12, 34 }) == 46); | ||
| 45 | comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); | ||
| 46 | { | ||
| 47 | const separate_args0 = .{ a, b }; | ||
| 48 | const separate_args1 = .{ a, 34 }; | ||
| 49 | const separate_args2 = .{ 12, 34 }; | ||
| 50 | const separate_args3 = .{ 12, b }; | ||
| 51 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46); | ||
| 52 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46); | ||
| 53 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46); | ||
| 54 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | test "comptime call with bound function as parameter" { | ||
| 59 | const S = struct { | ||
| 60 | fn ReturnType(func: anytype) type { | ||
| 61 | return switch (@typeInfo(@TypeOf(func))) { | ||
| 62 | .BoundFn => |info| info, | ||
| 63 | else => unreachable, | ||
| 64 | }.return_type orelse void; | ||
| 65 | } | ||
| 66 | |||
| 67 | fn call_me_maybe() ?i32 { | ||
| 68 | return 123; | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | |||
| 72 | var inst: S = undefined; | ||
| 73 | try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); | ||
| 74 | } | ||
test/behavior/cast.zig created+927| ... | @@ -0,0 +1,927 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | const Vector = std.meta.Vector; | ||
| 6 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 7 | |||
| 8 | test "int to ptr cast" { | ||
| 9 | const x = @as(usize, 13); | ||
| 10 | const y = @intToPtr(*u8, x); | ||
| 11 | const z = @ptrToInt(y); | ||
| 12 | try expect(z == 13); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "integer literal to pointer cast" { | ||
| 16 | const vga_mem = @intToPtr(*u16, 0xB8000); | ||
| 17 | try expect(@ptrToInt(vga_mem) == 0xB8000); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "pointer reinterpret const float to int" { | ||
| 21 | // The hex representation is 0x3fe3333333333303. | ||
| 22 | const float: f64 = 5.99999999999994648725e-01; | ||
| 23 | const float_ptr = &float; | ||
| 24 | const int_ptr = @ptrCast(*const i32, float_ptr); | ||
| 25 | const int_val = int_ptr.*; | ||
| 26 | if (native_endian == .Little) | ||
| 27 | try expect(int_val == 0x33333303) | ||
| 28 | else | ||
| 29 | try expect(int_val == 0x3fe33333); | ||
| 30 | } | ||
| 31 | |||
| 32 | test "implicitly cast indirect pointer to maybe-indirect pointer" { | ||
| 33 | const S = struct { | ||
| 34 | const Self = @This(); | ||
| 35 | x: u8, | ||
| 36 | fn constConst(p: *const *const Self) u8 { | ||
| 37 | return p.*.x; | ||
| 38 | } | ||
| 39 | fn maybeConstConst(p: ?*const *const Self) u8 { | ||
| 40 | return p.?.*.x; | ||
| 41 | } | ||
| 42 | fn constConstConst(p: *const *const *const Self) u8 { | ||
| 43 | return p.*.*.x; | ||
| 44 | } | ||
| 45 | fn maybeConstConstConst(p: ?*const *const *const Self) u8 { | ||
| 46 | return p.?.*.*.x; | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | const s = S{ .x = 42 }; | ||
| 50 | const p = &s; | ||
| 51 | const q = &p; | ||
| 52 | const r = &q; | ||
| 53 | try expect(42 == S.constConst(q)); | ||
| 54 | try expect(42 == S.maybeConstConst(q)); | ||
| 55 | try expect(42 == S.constConstConst(r)); | ||
| 56 | try expect(42 == S.maybeConstConstConst(r)); | ||
| 57 | } | ||
| 58 | |||
| 59 | test "explicit cast from integer to error type" { | ||
| 60 | try testCastIntToErr(error.ItBroke); | ||
| 61 | comptime try testCastIntToErr(error.ItBroke); | ||
| 62 | } | ||
| 63 | fn testCastIntToErr(err: anyerror) !void { | ||
| 64 | const x = @errorToInt(err); | ||
| 65 | const y = @intToError(x); | ||
| 66 | try expect(error.ItBroke == y); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "peer resolve arrays of different size to const slice" { | ||
| 70 | try expect(mem.eql(u8, boolToStr(true), "true")); | ||
| 71 | try expect(mem.eql(u8, boolToStr(false), "false")); | ||
| 72 | comptime try expect(mem.eql(u8, boolToStr(true), "true")); | ||
| 73 | comptime try expect(mem.eql(u8, boolToStr(false), "false")); | ||
| 74 | } | ||
| 75 | fn boolToStr(b: bool) []const u8 { | ||
| 76 | return if (b) "true" else "false"; | ||
| 77 | } | ||
| 78 | |||
| 79 | test "peer resolve array and const slice" { | ||
| 80 | try testPeerResolveArrayConstSlice(true); | ||
| 81 | comptime try testPeerResolveArrayConstSlice(true); | ||
| 82 | } | ||
| 83 | fn testPeerResolveArrayConstSlice(b: bool) !void { | ||
| 84 | const value1 = if (b) "aoeu" else @as([]const u8, "zz"); | ||
| 85 | const value2 = if (b) @as([]const u8, "zz") else "aoeu"; | ||
| 86 | try expect(mem.eql(u8, value1, "aoeu")); | ||
| 87 | try expect(mem.eql(u8, value2, "zz")); | ||
| 88 | } | ||
| 89 | |||
| 90 | test "implicitly cast from T to anyerror!?T" { | ||
| 91 | try castToOptionalTypeError(1); | ||
| 92 | comptime try castToOptionalTypeError(1); | ||
| 93 | } | ||
| 94 | |||
| 95 | const A = struct { | ||
| 96 | a: i32, | ||
| 97 | }; | ||
| 98 | fn castToOptionalTypeError(z: i32) !void { | ||
| 99 | const x = @as(i32, 1); | ||
| 100 | const y: anyerror!?i32 = x; | ||
| 101 | try expect((try y).? == 1); | ||
| 102 | |||
| 103 | const f = z; | ||
| 104 | const g: anyerror!?i32 = f; | ||
| 105 | |||
| 106 | const a = A{ .a = z }; | ||
| 107 | const b: anyerror!?A = a; | ||
| 108 | try expect((b catch unreachable).?.a == 1); | ||
| 109 | } | ||
| 110 | |||
| 111 | test "implicitly cast from int to anyerror!?T" { | ||
| 112 | implicitIntLitToOptional(); | ||
| 113 | comptime implicitIntLitToOptional(); | ||
| 114 | } | ||
| 115 | fn implicitIntLitToOptional() void { | ||
| 116 | const f: ?i32 = 1; | ||
| 117 | const g: anyerror!?i32 = 1; | ||
| 118 | } | ||
| 119 | |||
| 120 | test "return null from fn() anyerror!?&T" { | ||
| 121 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 122 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 123 | try expect((try a) == null and (try b) == null); | ||
| 124 | } | ||
| 125 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 126 | const a: ?*A = null; | ||
| 127 | return a; | ||
| 128 | } | ||
| 129 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 130 | return null; | ||
| 131 | } | ||
| 132 | |||
| 133 | test "peer type resolution: ?T and T" { | ||
| 134 | try expect(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 135 | try expect(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 136 | comptime { | ||
| 137 | try expect(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 138 | try expect(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { | ||
| 142 | if (c) { | ||
| 143 | return if (b) null else @as(usize, 0); | ||
| 144 | } | ||
| 145 | |||
| 146 | return @as(usize, 3); | ||
| 147 | } | ||
| 148 | |||
| 149 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 150 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 151 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 152 | comptime { | ||
| 153 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 154 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 158 | if (a) { | ||
| 159 | return &[_]u8{}; | ||
| 160 | } | ||
| 161 | |||
| 162 | return slice[0..1]; | ||
| 163 | } | ||
| 164 | |||
| 165 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 166 | try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 167 | comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 168 | } | ||
| 169 | |||
| 170 | fn castToOptionalSlice() ?[]const u8 { | ||
| 171 | return "hi"; | ||
| 172 | } | ||
| 173 | |||
| 174 | test "implicitly cast from [0]T to anyerror![]T" { | ||
| 175 | try testCastZeroArrayToErrSliceMut(); | ||
| 176 | comptime try testCastZeroArrayToErrSliceMut(); | ||
| 177 | } | ||
| 178 | |||
| 179 | fn testCastZeroArrayToErrSliceMut() !void { | ||
| 180 | try expect((gimmeErrOrSlice() catch unreachable).len == 0); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn gimmeErrOrSlice() anyerror![]u8 { | ||
| 184 | return &[_]u8{}; | ||
| 185 | } | ||
| 186 | |||
| 187 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { | ||
| 188 | const S = struct { | ||
| 189 | fn doTheTest() anyerror!void { | ||
| 190 | { | ||
| 191 | var data = "hi".*; | ||
| 192 | const slice = data[0..]; | ||
| 193 | try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 194 | try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 195 | } | ||
| 196 | { | ||
| 197 | var data: [2]u8 = "hi".*; | ||
| 198 | const slice = data[0..]; | ||
| 199 | try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 200 | try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | }; | ||
| 204 | try S.doTheTest(); | ||
| 205 | comptime try S.doTheTest(); | ||
| 206 | } | ||
| 207 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { | ||
| 208 | if (a) { | ||
| 209 | return &[_]u8{}; | ||
| 210 | } | ||
| 211 | |||
| 212 | return slice[0..1]; | ||
| 213 | } | ||
| 214 | |||
| 215 | test "resolve undefined with integer" { | ||
| 216 | try testResolveUndefWithInt(true, 1234); | ||
| 217 | comptime try testResolveUndefWithInt(true, 1234); | ||
| 218 | } | ||
| 219 | fn testResolveUndefWithInt(b: bool, x: i32) !void { | ||
| 220 | const value = if (b) x else undefined; | ||
| 221 | if (b) { | ||
| 222 | try expect(value == x); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | test "implicit cast from &const [N]T to []const T" { | ||
| 227 | try testCastConstArrayRefToConstSlice(); | ||
| 228 | comptime try testCastConstArrayRefToConstSlice(); | ||
| 229 | } | ||
| 230 | |||
| 231 | fn testCastConstArrayRefToConstSlice() !void { | ||
| 232 | { | ||
| 233 | const blah = "aoeu".*; | ||
| 234 | const const_array_ref = &blah; | ||
| 235 | try expect(@TypeOf(const_array_ref) == *const [4:0]u8); | ||
| 236 | const slice: []const u8 = const_array_ref; | ||
| 237 | try expect(mem.eql(u8, slice, "aoeu")); | ||
| 238 | } | ||
| 239 | { | ||
| 240 | const blah: [4]u8 = "aoeu".*; | ||
| 241 | const const_array_ref = &blah; | ||
| 242 | try expect(@TypeOf(const_array_ref) == *const [4]u8); | ||
| 243 | const slice: []const u8 = const_array_ref; | ||
| 244 | try expect(mem.eql(u8, slice, "aoeu")); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | test "peer type resolution: error and [N]T" { | ||
| 249 | try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 250 | comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 251 | try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 252 | comptime try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn testPeerErrorAndArray(x: u8) anyerror![]const u8 { | ||
| 256 | return switch (x) { | ||
| 257 | 0x00 => "OK", | ||
| 258 | else => error.BadValue, | ||
| 259 | }; | ||
| 260 | } | ||
| 261 | fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { | ||
| 262 | return switch (x) { | ||
| 263 | 0x00 => "OK", | ||
| 264 | 0x01 => "OKK", | ||
| 265 | else => error.BadValue, | ||
| 266 | }; | ||
| 267 | } | ||
| 268 | |||
| 269 | test "@floatToInt" { | ||
| 270 | try testFloatToInts(); | ||
| 271 | comptime try testFloatToInts(); | ||
| 272 | } | ||
| 273 | |||
| 274 | fn testFloatToInts() !void { | ||
| 275 | const x = @as(i32, 1e4); | ||
| 276 | try expect(x == 10000); | ||
| 277 | const y = @floatToInt(i32, @as(f32, 1e4)); | ||
| 278 | try expect(y == 10000); | ||
| 279 | try expectFloatToInt(f16, 255.1, u8, 255); | ||
| 280 | try expectFloatToInt(f16, 127.2, i8, 127); | ||
| 281 | try expectFloatToInt(f16, -128.2, i8, -128); | ||
| 282 | try expectFloatToInt(f32, 255.1, u8, 255); | ||
| 283 | try expectFloatToInt(f32, 127.2, i8, 127); | ||
| 284 | try expectFloatToInt(f32, -128.2, i8, -128); | ||
| 285 | try expectFloatToInt(comptime_int, 1234, i16, 1234); | ||
| 286 | } | ||
| 287 | |||
| 288 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { | ||
| 289 | try expect(@floatToInt(I, f) == i); | ||
| 290 | } | ||
| 291 | |||
| 292 | test "cast u128 to f128 and back" { | ||
| 293 | comptime try testCast128(); | ||
| 294 | try testCast128(); | ||
| 295 | } | ||
| 296 | |||
| 297 | fn testCast128() !void { | ||
| 298 | try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 299 | } | ||
| 300 | |||
| 301 | fn cast128Int(x: f128) u128 { | ||
| 302 | return @bitCast(u128, x); | ||
| 303 | } | ||
| 304 | |||
| 305 | fn cast128Float(x: u128) f128 { | ||
| 306 | return @bitCast(f128, x); | ||
| 307 | } | ||
| 308 | |||
| 309 | test "single-item pointer of array to slice and to unknown length pointer" { | ||
| 310 | try testCastPtrOfArrayToSliceAndPtr(); | ||
| 311 | comptime try testCastPtrOfArrayToSliceAndPtr(); | ||
| 312 | } | ||
| 313 | |||
| 314 | fn testCastPtrOfArrayToSliceAndPtr() !void { | ||
| 315 | { | ||
| 316 | var array = "aoeu".*; | ||
| 317 | const x: [*]u8 = &array; | ||
| 318 | x[0] += 1; | ||
| 319 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 320 | const y: []u8 = &array; | ||
| 321 | y[0] += 1; | ||
| 322 | try expect(mem.eql(u8, array[0..], "coeu")); | ||
| 323 | } | ||
| 324 | { | ||
| 325 | var array: [4]u8 = "aoeu".*; | ||
| 326 | const x: [*]u8 = &array; | ||
| 327 | x[0] += 1; | ||
| 328 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 329 | const y: []u8 = &array; | ||
| 330 | y[0] += 1; | ||
| 331 | try expect(mem.eql(u8, array[0..], "coeu")); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | ||
| 336 | const window_name = [1][*]const u8{"window name"}; | ||
| 337 | const x: [*]const ?[*]const u8 = &window_name; | ||
| 338 | try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name")); | ||
| 339 | } | ||
| 340 | |||
| 341 | test "@intCast comptime_int" { | ||
| 342 | const result = @intCast(i32, 1234); | ||
| 343 | try expect(@TypeOf(result) == i32); | ||
| 344 | try expect(result == 1234); | ||
| 345 | } | ||
| 346 | |||
| 347 | test "@floatCast comptime_int and comptime_float" { | ||
| 348 | { | ||
| 349 | const result = @floatCast(f16, 1234); | ||
| 350 | try expect(@TypeOf(result) == f16); | ||
| 351 | try expect(result == 1234.0); | ||
| 352 | } | ||
| 353 | { | ||
| 354 | const result = @floatCast(f16, 1234.0); | ||
| 355 | try expect(@TypeOf(result) == f16); | ||
| 356 | try expect(result == 1234.0); | ||
| 357 | } | ||
| 358 | { | ||
| 359 | const result = @floatCast(f32, 1234); | ||
| 360 | try expect(@TypeOf(result) == f32); | ||
| 361 | try expect(result == 1234.0); | ||
| 362 | } | ||
| 363 | { | ||
| 364 | const result = @floatCast(f32, 1234.0); | ||
| 365 | try expect(@TypeOf(result) == f32); | ||
| 366 | try expect(result == 1234.0); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | test "vector casts" { | ||
| 371 | const S = struct { | ||
| 372 | fn doTheTest() !void { | ||
| 373 | // Upcast (implicit, equivalent to @intCast) | ||
| 374 | var up0: Vector(2, u8) = [_]u8{ 0x55, 0xaa }; | ||
| 375 | var up1 = @as(Vector(2, u16), up0); | ||
| 376 | var up2 = @as(Vector(2, u32), up0); | ||
| 377 | var up3 = @as(Vector(2, u64), up0); | ||
| 378 | // Downcast (safety-checked) | ||
| 379 | var down0 = up3; | ||
| 380 | var down1 = @intCast(Vector(2, u32), down0); | ||
| 381 | var down2 = @intCast(Vector(2, u16), down0); | ||
| 382 | var down3 = @intCast(Vector(2, u8), down0); | ||
| 383 | |||
| 384 | try expect(mem.eql(u16, &@as([2]u16, up1), &[2]u16{ 0x55, 0xaa })); | ||
| 385 | try expect(mem.eql(u32, &@as([2]u32, up2), &[2]u32{ 0x55, 0xaa })); | ||
| 386 | try expect(mem.eql(u64, &@as([2]u64, up3), &[2]u64{ 0x55, 0xaa })); | ||
| 387 | |||
| 388 | try expect(mem.eql(u32, &@as([2]u32, down1), &[2]u32{ 0x55, 0xaa })); | ||
| 389 | try expect(mem.eql(u16, &@as([2]u16, down2), &[2]u16{ 0x55, 0xaa })); | ||
| 390 | try expect(mem.eql(u8, &@as([2]u8, down3), &[2]u8{ 0x55, 0xaa })); | ||
| 391 | } | ||
| 392 | |||
| 393 | fn doTheTestFloat() !void { | ||
| 394 | var vec = @splat(2, @as(f32, 1234.0)); | ||
| 395 | var wider: Vector(2, f64) = vec; | ||
| 396 | try expect(wider[0] == 1234.0); | ||
| 397 | try expect(wider[1] == 1234.0); | ||
| 398 | } | ||
| 399 | }; | ||
| 400 | |||
| 401 | try S.doTheTest(); | ||
| 402 | comptime try S.doTheTest(); | ||
| 403 | try S.doTheTestFloat(); | ||
| 404 | comptime try S.doTheTestFloat(); | ||
| 405 | } | ||
| 406 | |||
| 407 | test "comptime_int @intToFloat" { | ||
| 408 | { | ||
| 409 | const result = @intToFloat(f16, 1234); | ||
| 410 | try expect(@TypeOf(result) == f16); | ||
| 411 | try expect(result == 1234.0); | ||
| 412 | } | ||
| 413 | { | ||
| 414 | const result = @intToFloat(f32, 1234); | ||
| 415 | try expect(@TypeOf(result) == f32); | ||
| 416 | try expect(result == 1234.0); | ||
| 417 | } | ||
| 418 | { | ||
| 419 | const result = @intToFloat(f64, 1234); | ||
| 420 | try expect(@TypeOf(result) == f64); | ||
| 421 | try expect(result == 1234.0); | ||
| 422 | } | ||
| 423 | { | ||
| 424 | const result = @intToFloat(f128, 1234); | ||
| 425 | try expect(@TypeOf(result) == f128); | ||
| 426 | try expect(result == 1234.0); | ||
| 427 | } | ||
| 428 | // big comptime_int (> 64 bits) to f128 conversion | ||
| 429 | { | ||
| 430 | const result = @intToFloat(f128, 0x1_0000_0000_0000_0000); | ||
| 431 | try expect(@TypeOf(result) == f128); | ||
| 432 | try expect(result == 0x1_0000_0000_0000_0000.0); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | test "@intCast i32 to u7" { | ||
| 437 | var x: u128 = maxInt(u128); | ||
| 438 | var y: i32 = 120; | ||
| 439 | var z = x >> @intCast(u7, y); | ||
| 440 | try expect(z == 0xff); | ||
| 441 | } | ||
| 442 | |||
| 443 | test "@floatCast cast down" { | ||
| 444 | { | ||
| 445 | var double: f64 = 0.001534; | ||
| 446 | var single = @floatCast(f32, double); | ||
| 447 | try expect(single == 0.001534); | ||
| 448 | } | ||
| 449 | { | ||
| 450 | const double: f64 = 0.001534; | ||
| 451 | const single = @floatCast(f32, double); | ||
| 452 | try expect(single == 0.001534); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | test "implicit cast undefined to optional" { | ||
| 457 | try expect(MakeType(void).getNull() == null); | ||
| 458 | try expect(MakeType(void).getNonNull() != null); | ||
| 459 | } | ||
| 460 | |||
| 461 | fn MakeType(comptime T: type) type { | ||
| 462 | return struct { | ||
| 463 | fn getNull() ?T { | ||
| 464 | return null; | ||
| 465 | } | ||
| 466 | |||
| 467 | fn getNonNull() ?T { | ||
| 468 | return @as(T, undefined); | ||
| 469 | } | ||
| 470 | }; | ||
| 471 | } | ||
| 472 | |||
| 473 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 474 | var x: ?[*]u16 = null; | ||
| 475 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 476 | |||
| 477 | x = &y; | ||
| 478 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 479 | x.?[0] = 8; | ||
| 480 | y[3] = 6; | ||
| 481 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 482 | } | ||
| 483 | |||
| 484 | test "implicit cast from *[N]T to [*c]T" { | ||
| 485 | var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 486 | var y: [*c]u16 = &x; | ||
| 487 | |||
| 488 | try expect(std.mem.eql(u16, x[0..4], y[0..4])); | ||
| 489 | x[0] = 8; | ||
| 490 | y[3] = 6; | ||
| 491 | try expect(std.mem.eql(u16, x[0..4], y[0..4])); | ||
| 492 | } | ||
| 493 | |||
| 494 | test "implicit cast from *T to ?*c_void" { | ||
| 495 | var a: u8 = 1; | ||
| 496 | incrementVoidPtrValue(&a); | ||
| 497 | try std.testing.expect(a == 2); | ||
| 498 | } | ||
| 499 | |||
| 500 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 501 | @ptrCast(*u8, value.?).* += 1; | ||
| 502 | } | ||
| 503 | |||
| 504 | test "implicit cast from [*]T to ?*c_void" { | ||
| 505 | var a = [_]u8{ 3, 2, 1 }; | ||
| 506 | var runtime_zero: usize = 0; | ||
| 507 | incrementVoidPtrArray(a[runtime_zero..].ptr, 3); | ||
| 508 | try expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); | ||
| 509 | } | ||
| 510 | |||
| 511 | fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { | ||
| 512 | var n: usize = 0; | ||
| 513 | while (n < len) : (n += 1) { | ||
| 514 | @ptrCast([*]u8, array.?)[n] += 1; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | test "*usize to *void" { | ||
| 519 | var i = @as(usize, 0); | ||
| 520 | var v = @ptrCast(*void, &i); | ||
| 521 | v.* = {}; | ||
| 522 | } | ||
| 523 | |||
| 524 | test "compile time int to ptr of function" { | ||
| 525 | try foobar(FUNCTION_CONSTANT); | ||
| 526 | } | ||
| 527 | |||
| 528 | pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); | ||
| 529 | pub const PFN_void = fn (*c_void) callconv(.C) void; | ||
| 530 | |||
| 531 | fn foobar(func: PFN_void) !void { | ||
| 532 | try std.testing.expect(@ptrToInt(func) == maxInt(usize)); | ||
| 533 | } | ||
| 534 | |||
| 535 | test "implicit ptr to *c_void" { | ||
| 536 | var a: u32 = 1; | ||
| 537 | var ptr: *align(@alignOf(u32)) c_void = &a; | ||
| 538 | var b: *u32 = @ptrCast(*u32, ptr); | ||
| 539 | try expect(b.* == 1); | ||
| 540 | var ptr2: ?*align(@alignOf(u32)) c_void = &a; | ||
| 541 | var c: *u32 = @ptrCast(*u32, ptr2.?); | ||
| 542 | try expect(c.* == 1); | ||
| 543 | } | ||
| 544 | |||
| 545 | test "@intCast to comptime_int" { | ||
| 546 | try expect(@intCast(comptime_int, 0) == 0); | ||
| 547 | } | ||
| 548 | |||
| 549 | test "implicit cast comptime numbers to any type when the value fits" { | ||
| 550 | const a: u64 = 255; | ||
| 551 | var b: u8 = a; | ||
| 552 | try expect(b == 255); | ||
| 553 | } | ||
| 554 | |||
| 555 | test "@intToEnum passed a comptime_int to an enum with one item" { | ||
| 556 | const E = enum { | ||
| 557 | A, | ||
| 558 | }; | ||
| 559 | const x = @intToEnum(E, 0); | ||
| 560 | try expect(x == E.A); | ||
| 561 | } | ||
| 562 | |||
| 563 | test "@intToEnum runtime to an extern enum with duplicate values" { | ||
| 564 | const E = extern enum(u8) { | ||
| 565 | A = 1, | ||
| 566 | B = 1, | ||
| 567 | }; | ||
| 568 | var a: u8 = 1; | ||
| 569 | var x = @intToEnum(E, a); | ||
| 570 | try expect(x == E.A); | ||
| 571 | try expect(x == E.B); | ||
| 572 | } | ||
| 573 | |||
| 574 | test "@intCast to u0 and use the result" { | ||
| 575 | const S = struct { | ||
| 576 | fn doTheTest(zero: u1, one: u1, bigzero: i32) !void { | ||
| 577 | try expect((one << @intCast(u0, bigzero)) == 1); | ||
| 578 | try expect((zero << @intCast(u0, bigzero)) == 0); | ||
| 579 | } | ||
| 580 | }; | ||
| 581 | try S.doTheTest(0, 1, 0); | ||
| 582 | comptime try S.doTheTest(0, 1, 0); | ||
| 583 | } | ||
| 584 | |||
| 585 | test "peer type resolution: unreachable, null, slice" { | ||
| 586 | const S = struct { | ||
| 587 | fn doTheTest(num: usize, word: []const u8) !void { | ||
| 588 | const result = switch (num) { | ||
| 589 | 0 => null, | ||
| 590 | 1 => word, | ||
| 591 | else => unreachable, | ||
| 592 | }; | ||
| 593 | try expect(mem.eql(u8, result.?, "hi")); | ||
| 594 | } | ||
| 595 | }; | ||
| 596 | try S.doTheTest(1, "hi"); | ||
| 597 | } | ||
| 598 | |||
| 599 | test "peer type resolution: unreachable, error set, unreachable" { | ||
| 600 | const Error = error{ | ||
| 601 | FileDescriptorAlreadyPresentInSet, | ||
| 602 | OperationCausesCircularLoop, | ||
| 603 | FileDescriptorNotRegistered, | ||
| 604 | SystemResources, | ||
| 605 | UserResourceLimitReached, | ||
| 606 | FileDescriptorIncompatibleWithEpoll, | ||
| 607 | Unexpected, | ||
| 608 | }; | ||
| 609 | var err = Error.SystemResources; | ||
| 610 | const transformed_err = switch (err) { | ||
| 611 | error.FileDescriptorAlreadyPresentInSet => unreachable, | ||
| 612 | error.OperationCausesCircularLoop => unreachable, | ||
| 613 | error.FileDescriptorNotRegistered => unreachable, | ||
| 614 | error.SystemResources => error.SystemResources, | ||
| 615 | error.UserResourceLimitReached => error.UserResourceLimitReached, | ||
| 616 | error.FileDescriptorIncompatibleWithEpoll => unreachable, | ||
| 617 | error.Unexpected => unreachable, | ||
| 618 | }; | ||
| 619 | try expect(transformed_err == error.SystemResources); | ||
| 620 | } | ||
| 621 | |||
| 622 | test "implicit cast comptime_int to comptime_float" { | ||
| 623 | comptime try expect(@as(comptime_float, 10) == @as(f32, 10)); | ||
| 624 | try expect(2 == 2.0); | ||
| 625 | } | ||
| 626 | |||
| 627 | test "implicit cast *[0]T to E![]const u8" { | ||
| 628 | var x = @as(anyerror![]const u8, &[0]u8{}); | ||
| 629 | try expect((x catch unreachable).len == 0); | ||
| 630 | } | ||
| 631 | |||
| 632 | test "peer cast *[0]T to E![]const T" { | ||
| 633 | var buffer: [5]u8 = "abcde".*; | ||
| 634 | var buf: anyerror![]const u8 = buffer[0..]; | ||
| 635 | var b = false; | ||
| 636 | var y = if (b) &[0]u8{} else buf; | ||
| 637 | try expect(mem.eql(u8, "abcde", y catch unreachable)); | ||
| 638 | } | ||
| 639 | |||
| 640 | test "peer cast *[0]T to []const T" { | ||
| 641 | var buffer: [5]u8 = "abcde".*; | ||
| 642 | var buf: []const u8 = buffer[0..]; | ||
| 643 | var b = false; | ||
| 644 | var y = if (b) &[0]u8{} else buf; | ||
| 645 | try expect(mem.eql(u8, "abcde", y)); | ||
| 646 | } | ||
| 647 | |||
| 648 | var global_array: [4]u8 = undefined; | ||
| 649 | test "cast from array reference to fn" { | ||
| 650 | const f = @ptrCast(fn () callconv(.C) void, &global_array); | ||
| 651 | try expect(@ptrToInt(f) == @ptrToInt(&global_array)); | ||
| 652 | } | ||
| 653 | |||
| 654 | test "*const [N]null u8 to ?[]const u8" { | ||
| 655 | const S = struct { | ||
| 656 | fn doTheTest() !void { | ||
| 657 | var a = "Hello"; | ||
| 658 | var b: ?[]const u8 = a; | ||
| 659 | try expect(mem.eql(u8, b.?, "Hello")); | ||
| 660 | } | ||
| 661 | }; | ||
| 662 | try S.doTheTest(); | ||
| 663 | comptime try S.doTheTest(); | ||
| 664 | } | ||
| 665 | |||
| 666 | test "peer resolution of string literals" { | ||
| 667 | const S = struct { | ||
| 668 | const E = extern enum { | ||
| 669 | a, | ||
| 670 | b, | ||
| 671 | c, | ||
| 672 | d, | ||
| 673 | }; | ||
| 674 | |||
| 675 | fn doTheTest(e: E) !void { | ||
| 676 | const cmd = switch (e) { | ||
| 677 | .a => "one", | ||
| 678 | .b => "two", | ||
| 679 | .c => "three", | ||
| 680 | .d => "four", | ||
| 681 | }; | ||
| 682 | try expect(mem.eql(u8, cmd, "two")); | ||
| 683 | } | ||
| 684 | }; | ||
| 685 | try S.doTheTest(.b); | ||
| 686 | comptime try S.doTheTest(.b); | ||
| 687 | } | ||
| 688 | |||
| 689 | test "type coercion related to sentinel-termination" { | ||
| 690 | const S = struct { | ||
| 691 | fn doTheTest() !void { | ||
| 692 | // [:x]T to []T | ||
| 693 | { | ||
| 694 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 695 | var slice: [:0]i32 = &array; | ||
| 696 | var dest: []i32 = slice; | ||
| 697 | try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 698 | } | ||
| 699 | |||
| 700 | // [*:x]T to [*]T | ||
| 701 | { | ||
| 702 | var array = [4:99]i32{ 1, 2, 3, 4 }; | ||
| 703 | var dest: [*]i32 = &array; | ||
| 704 | try expect(dest[0] == 1); | ||
| 705 | try expect(dest[1] == 2); | ||
| 706 | try expect(dest[2] == 3); | ||
| 707 | try expect(dest[3] == 4); | ||
| 708 | try expect(dest[4] == 99); | ||
| 709 | } | ||
| 710 | |||
| 711 | // [N:x]T to [N]T | ||
| 712 | { | ||
| 713 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 714 | var dest: [4]i32 = array; | ||
| 715 | try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 716 | } | ||
| 717 | |||
| 718 | // *[N:x]T to *[N]T | ||
| 719 | { | ||
| 720 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 721 | var dest: *[4]i32 = &array; | ||
| 722 | try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 723 | } | ||
| 724 | |||
| 725 | // [:x]T to [*:x]T | ||
| 726 | { | ||
| 727 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 728 | var slice: [:0]i32 = &array; | ||
| 729 | var dest: [*:0]i32 = slice; | ||
| 730 | try expect(dest[0] == 1); | ||
| 731 | try expect(dest[1] == 2); | ||
| 732 | try expect(dest[2] == 3); | ||
| 733 | try expect(dest[3] == 4); | ||
| 734 | try expect(dest[4] == 0); | ||
| 735 | } | ||
| 736 | } | ||
| 737 | }; | ||
| 738 | try S.doTheTest(); | ||
| 739 | comptime try S.doTheTest(); | ||
| 740 | } | ||
| 741 | |||
| 742 | test "cast i8 fn call peers to i32 result" { | ||
| 743 | const S = struct { | ||
| 744 | fn doTheTest() !void { | ||
| 745 | var cond = true; | ||
| 746 | const value: i32 = if (cond) smallBoi() else bigBoi(); | ||
| 747 | try expect(value == 123); | ||
| 748 | } | ||
| 749 | fn smallBoi() i8 { | ||
| 750 | return 123; | ||
| 751 | } | ||
| 752 | fn bigBoi() i16 { | ||
| 753 | return 1234; | ||
| 754 | } | ||
| 755 | }; | ||
| 756 | try S.doTheTest(); | ||
| 757 | comptime try S.doTheTest(); | ||
| 758 | } | ||
| 759 | |||
| 760 | test "return u8 coercing into ?u32 return type" { | ||
| 761 | const S = struct { | ||
| 762 | fn doTheTest() !void { | ||
| 763 | try expect(foo(123).? == 123); | ||
| 764 | } | ||
| 765 | fn foo(arg: u8) ?u32 { | ||
| 766 | return arg; | ||
| 767 | } | ||
| 768 | }; | ||
| 769 | try S.doTheTest(); | ||
| 770 | comptime try S.doTheTest(); | ||
| 771 | } | ||
| 772 | |||
| 773 | test "peer result null and comptime_int" { | ||
| 774 | const S = struct { | ||
| 775 | fn blah(n: i32) ?i32 { | ||
| 776 | if (n == 0) { | ||
| 777 | return null; | ||
| 778 | } else if (n < 0) { | ||
| 779 | return -1; | ||
| 780 | } else { | ||
| 781 | return 1; | ||
| 782 | } | ||
| 783 | } | ||
| 784 | }; | ||
| 785 | |||
| 786 | try expect(S.blah(0) == null); | ||
| 787 | comptime try expect(S.blah(0) == null); | ||
| 788 | try expect(S.blah(10).? == 1); | ||
| 789 | comptime try expect(S.blah(10).? == 1); | ||
| 790 | try expect(S.blah(-10).? == -1); | ||
| 791 | comptime try expect(S.blah(-10).? == -1); | ||
| 792 | } | ||
| 793 | |||
| 794 | test "peer type resolution implicit cast to return type" { | ||
| 795 | const S = struct { | ||
| 796 | fn doTheTest() !void { | ||
| 797 | for ("hello") |c| _ = f(c); | ||
| 798 | } | ||
| 799 | fn f(c: u8) []const u8 { | ||
| 800 | return switch (c) { | ||
| 801 | 'h', 'e' => &[_]u8{c}, // should cast to slice | ||
| 802 | 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice | ||
| 803 | else => ([_]u8{c})[0..], // is a slice | ||
| 804 | }; | ||
| 805 | } | ||
| 806 | }; | ||
| 807 | try S.doTheTest(); | ||
| 808 | comptime try S.doTheTest(); | ||
| 809 | } | ||
| 810 | |||
| 811 | test "peer type resolution implicit cast to variable type" { | ||
| 812 | const S = struct { | ||
| 813 | fn doTheTest() !void { | ||
| 814 | var x: []const u8 = undefined; | ||
| 815 | for ("hello") |c| x = switch (c) { | ||
| 816 | 'h', 'e' => &[_]u8{c}, // should cast to slice | ||
| 817 | 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice | ||
| 818 | else => ([_]u8{c})[0..], // is a slice | ||
| 819 | }; | ||
| 820 | } | ||
| 821 | }; | ||
| 822 | try S.doTheTest(); | ||
| 823 | comptime try S.doTheTest(); | ||
| 824 | } | ||
| 825 | |||
| 826 | test "variable initialization uses result locations properly with regards to the type" { | ||
| 827 | var b = true; | ||
| 828 | const x: i32 = if (b) 1 else 2; | ||
| 829 | try expect(x == 1); | ||
| 830 | } | ||
| 831 | |||
| 832 | test "cast between [*c]T and ?[*:0]T on fn parameter" { | ||
| 833 | const S = struct { | ||
| 834 | const Handler = ?fn ([*c]const u8) callconv(.C) void; | ||
| 835 | fn addCallback(handler: Handler) void {} | ||
| 836 | |||
| 837 | fn myCallback(cstr: ?[*:0]const u8) callconv(.C) void {} | ||
| 838 | |||
| 839 | fn doTheTest() void { | ||
| 840 | addCallback(myCallback); | ||
| 841 | } | ||
| 842 | }; | ||
| 843 | S.doTheTest(); | ||
| 844 | } | ||
| 845 | |||
| 846 | test "cast between C pointer with different but compatible types" { | ||
| 847 | const S = struct { | ||
| 848 | fn foo(arg: [*]c_ushort) u16 { | ||
| 849 | return arg[0]; | ||
| 850 | } | ||
| 851 | fn doTheTest() !void { | ||
| 852 | var x = [_]u16{ 4, 2, 1, 3 }; | ||
| 853 | try expect(foo(@ptrCast([*]u16, &x)) == 4); | ||
| 854 | } | ||
| 855 | }; | ||
| 856 | try S.doTheTest(); | ||
| 857 | } | ||
| 858 | |||
| 859 | var global_struct: struct { f0: usize } = undefined; | ||
| 860 | |||
| 861 | test "assignment to optional pointer result loc" { | ||
| 862 | var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; | ||
| 863 | try expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); | ||
| 864 | } | ||
| 865 | |||
| 866 | test "peer type resolve string lit with sentinel-terminated mutable slice" { | ||
| 867 | var array: [4:0]u8 = undefined; | ||
| 868 | array[4] = 0; // TODO remove this when #4372 is solved | ||
| 869 | var slice: [:0]u8 = array[0..4 :0]; | ||
| 870 | comptime try expect(@TypeOf(slice, "hi") == [:0]const u8); | ||
| 871 | comptime try expect(@TypeOf("hi", slice) == [:0]const u8); | ||
| 872 | } | ||
| 873 | |||
| 874 | test "peer type unsigned int to signed" { | ||
| 875 | var w: u31 = 5; | ||
| 876 | var x: u8 = 7; | ||
| 877 | var y: i32 = -5; | ||
| 878 | var a = w + y + x; | ||
| 879 | comptime try expect(@TypeOf(a) == i32); | ||
| 880 | try expect(a == 7); | ||
| 881 | } | ||
| 882 | |||
| 883 | test "peer type resolve array pointers, one of them const" { | ||
| 884 | var array1: [4]u8 = undefined; | ||
| 885 | const array2: [5]u8 = undefined; | ||
| 886 | comptime try expect(@TypeOf(&array1, &array2) == []const u8); | ||
| 887 | comptime try expect(@TypeOf(&array2, &array1) == []const u8); | ||
| 888 | } | ||
| 889 | |||
| 890 | test "peer type resolve array pointer and unknown pointer" { | ||
| 891 | const const_array: [4]u8 = undefined; | ||
| 892 | var array: [4]u8 = undefined; | ||
| 893 | var const_ptr: [*]const u8 = undefined; | ||
| 894 | var ptr: [*]u8 = undefined; | ||
| 895 | |||
| 896 | comptime try expect(@TypeOf(&array, ptr) == [*]u8); | ||
| 897 | comptime try expect(@TypeOf(ptr, &array) == [*]u8); | ||
| 898 | |||
| 899 | comptime try expect(@TypeOf(&const_array, ptr) == [*]const u8); | ||
| 900 | comptime try expect(@TypeOf(ptr, &const_array) == [*]const u8); | ||
| 901 | |||
| 902 | comptime try expect(@TypeOf(&array, const_ptr) == [*]const u8); | ||
| 903 | comptime try expect(@TypeOf(const_ptr, &array) == [*]const u8); | ||
| 904 | |||
| 905 | comptime try expect(@TypeOf(&const_array, const_ptr) == [*]const u8); | ||
| 906 | comptime try expect(@TypeOf(const_ptr, &const_array) == [*]const u8); | ||
| 907 | } | ||
| 908 | |||
| 909 | test "comptime float casts" { | ||
| 910 | const a = @intToFloat(comptime_float, 1); | ||
| 911 | try expect(a == 1); | ||
| 912 | try expect(@TypeOf(a) == comptime_float); | ||
| 913 | const b = @floatToInt(comptime_int, 2); | ||
| 914 | try expect(b == 2); | ||
| 915 | try expect(@TypeOf(b) == comptime_int); | ||
| 916 | } | ||
| 917 | |||
| 918 | test "cast from ?[*]T to ??[*]T" { | ||
| 919 | const a: ??[*]u8 = @as(?[*]u8, null); | ||
| 920 | try expect(a != null and a.? == null); | ||
| 921 | } | ||
| 922 | |||
| 923 | test "cast between *[N]void and []void" { | ||
| 924 | var a: [4]void = undefined; | ||
| 925 | var b: []void = &a; | ||
| 926 | try expect(b.len == 4); | ||
| 927 | } | ||
test/behavior/const_slice_child.zig created+47| ... | @@ -0,0 +1,47 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const debug = std.debug; | ||
| 3 | const testing = std.testing; | ||
| 4 | const expect = testing.expect; | ||
| 5 | |||
| 6 | var argv: [*]const [*]const u8 = undefined; | ||
| 7 | |||
| 8 | test "const slice child" { | ||
| 9 | const strs = [_][*]const u8{ | ||
| 10 | "one", | ||
| 11 | "two", | ||
| 12 | "three", | ||
| 13 | }; | ||
| 14 | argv = &strs; | ||
| 15 | try bar(strs.len); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn foo(args: [][]const u8) !void { | ||
| 19 | try expect(args.len == 3); | ||
| 20 | try expect(streql(args[0], "one")); | ||
| 21 | try expect(streql(args[1], "two")); | ||
| 22 | try expect(streql(args[2], "three")); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn bar(argc: usize) !void { | ||
| 26 | const args = testing.allocator.alloc([]const u8, argc) catch unreachable; | ||
| 27 | defer testing.allocator.free(args); | ||
| 28 | for (args) |_, i| { | ||
| 29 | const ptr = argv[i]; | ||
| 30 | args[i] = ptr[0..strlen(ptr)]; | ||
| 31 | } | ||
| 32 | try foo(args); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn strlen(ptr: [*]const u8) usize { | ||
| 36 | var count: usize = 0; | ||
| 37 | while (ptr[count] != 0) : (count += 1) {} | ||
| 38 | return count; | ||
| 39 | } | ||
| 40 | |||
| 41 | fn streql(a: []const u8, b: []const u8) bool { | ||
| 42 | if (a.len != b.len) return false; | ||
| 43 | for (a) |item, index| { | ||
| 44 | if (b[index] != item) return false; | ||
| 45 | } | ||
| 46 | return true; | ||
| 47 | } | ||
test/behavior/defer.zig created+114| ... | @@ -0,0 +1,114 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const expectError = std.testing.expectError; | ||
| 5 | |||
| 6 | var result: [3]u8 = undefined; | ||
| 7 | var index: usize = undefined; | ||
| 8 | |||
| 9 | fn runSomeErrorDefers(x: bool) !bool { | ||
| 10 | index = 0; | ||
| 11 | defer { | ||
| 12 | result[index] = 'a'; | ||
| 13 | index += 1; | ||
| 14 | } | ||
| 15 | errdefer { | ||
| 16 | result[index] = 'b'; | ||
| 17 | index += 1; | ||
| 18 | } | ||
| 19 | defer { | ||
| 20 | result[index] = 'c'; | ||
| 21 | index += 1; | ||
| 22 | } | ||
| 23 | return if (x) x else error.FalseNotAllowed; | ||
| 24 | } | ||
| 25 | |||
| 26 | test "mixing normal and error defers" { | ||
| 27 | try expect(runSomeErrorDefers(true) catch unreachable); | ||
| 28 | try expect(result[0] == 'c'); | ||
| 29 | try expect(result[1] == 'a'); | ||
| 30 | |||
| 31 | const ok = runSomeErrorDefers(false) catch |err| x: { | ||
| 32 | try expect(err == error.FalseNotAllowed); | ||
| 33 | break :x true; | ||
| 34 | }; | ||
| 35 | try expect(ok); | ||
| 36 | try expect(result[0] == 'c'); | ||
| 37 | try expect(result[1] == 'b'); | ||
| 38 | try expect(result[2] == 'a'); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "break and continue inside loop inside defer expression" { | ||
| 42 | testBreakContInDefer(10); | ||
| 43 | comptime testBreakContInDefer(10); | ||
| 44 | } | ||
| 45 | |||
| 46 | fn testBreakContInDefer(x: usize) void { | ||
| 47 | defer { | ||
| 48 | var i: usize = 0; | ||
| 49 | while (i < x) : (i += 1) { | ||
| 50 | if (i < 5) continue; | ||
| 51 | if (i == 5) break; | ||
| 52 | } | ||
| 53 | expect(i == 5) catch @panic("test failure"); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | test "defer and labeled break" { | ||
| 58 | var i = @as(usize, 0); | ||
| 59 | |||
| 60 | blk: { | ||
| 61 | defer i += 1; | ||
| 62 | break :blk; | ||
| 63 | } | ||
| 64 | |||
| 65 | try expect(i == 1); | ||
| 66 | } | ||
| 67 | |||
| 68 | test "errdefer does not apply to fn inside fn" { | ||
| 69 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad); | ||
| 70 | } | ||
| 71 | |||
| 72 | fn testNestedFnErrDefer() anyerror!void { | ||
| 73 | var a: i32 = 0; | ||
| 74 | errdefer a += 1; | ||
| 75 | const S = struct { | ||
| 76 | fn baz() anyerror { | ||
| 77 | return error.Bad; | ||
| 78 | } | ||
| 79 | }; | ||
| 80 | return S.baz(); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "return variable while defer expression in scope to modify it" { | ||
| 84 | const S = struct { | ||
| 85 | fn doTheTest() !void { | ||
| 86 | try expect(notNull().? == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn notNull() ?u8 { | ||
| 90 | var res: ?u8 = 1; | ||
| 91 | defer res = null; | ||
| 92 | return res; | ||
| 93 | } | ||
| 94 | }; | ||
| 95 | |||
| 96 | try S.doTheTest(); | ||
| 97 | comptime try S.doTheTest(); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "errdefer with payload" { | ||
| 101 | const S = struct { | ||
| 102 | fn foo() !i32 { | ||
| 103 | errdefer |a| { | ||
| 104 | expectEqual(error.One, a) catch @panic("test failure"); | ||
| 105 | } | ||
| 106 | return error.One; | ||
| 107 | } | ||
| 108 | fn doTheTest() !void { | ||
| 109 | try expectError(error.One, foo()); | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | try S.doTheTest(); | ||
| 113 | comptime try S.doTheTest(); | ||
| 114 | } | ||
test/behavior/enum.zig created+1204| ... | @@ -0,0 +1,1204 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const Tag = @import("std").meta.Tag; | ||
| 4 | |||
| 5 | test "extern enum" { | ||
| 6 | const S = struct { | ||
| 7 | const i = extern enum { | ||
| 8 | n = 0, | ||
| 9 | o = 2, | ||
| 10 | p = 4, | ||
| 11 | q = 4, | ||
| 12 | }; | ||
| 13 | fn doTheTest(y: c_int) void { | ||
| 14 | var x = i.o; | ||
| 15 | switch (x) { | ||
| 16 | .n, .p => unreachable, | ||
| 17 | .o => {}, | ||
| 18 | } | ||
| 19 | } | ||
| 20 | }; | ||
| 21 | S.doTheTest(52); | ||
| 22 | comptime S.doTheTest(52); | ||
| 23 | } | ||
| 24 | |||
| 25 | test "non-exhaustive enum" { | ||
| 26 | const S = struct { | ||
| 27 | const E = enum(u8) { | ||
| 28 | a, | ||
| 29 | b, | ||
| 30 | _, | ||
| 31 | }; | ||
| 32 | fn doTheTest(y: u8) !void { | ||
| 33 | var e: E = .b; | ||
| 34 | try expect(switch (e) { | ||
| 35 | .a => false, | ||
| 36 | .b => true, | ||
| 37 | _ => false, | ||
| 38 | }); | ||
| 39 | e = @intToEnum(E, 12); | ||
| 40 | try expect(switch (e) { | ||
| 41 | .a => false, | ||
| 42 | .b => false, | ||
| 43 | _ => true, | ||
| 44 | }); | ||
| 45 | |||
| 46 | try expect(switch (e) { | ||
| 47 | .a => false, | ||
| 48 | .b => false, | ||
| 49 | else => true, | ||
| 50 | }); | ||
| 51 | e = .b; | ||
| 52 | try expect(switch (e) { | ||
| 53 | .a => false, | ||
| 54 | else => true, | ||
| 55 | }); | ||
| 56 | |||
| 57 | try expect(@typeInfo(E).Enum.fields.len == 2); | ||
| 58 | e = @intToEnum(E, 12); | ||
| 59 | try expect(@enumToInt(e) == 12); | ||
| 60 | e = @intToEnum(E, y); | ||
| 61 | try expect(@enumToInt(e) == 52); | ||
| 62 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 63 | } | ||
| 64 | }; | ||
| 65 | try S.doTheTest(52); | ||
| 66 | comptime try S.doTheTest(52); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "empty non-exhaustive enum" { | ||
| 70 | const S = struct { | ||
| 71 | const E = enum(u8) { | ||
| 72 | _, | ||
| 73 | }; | ||
| 74 | fn doTheTest(y: u8) !void { | ||
| 75 | var e = @intToEnum(E, y); | ||
| 76 | try expect(switch (e) { | ||
| 77 | _ => true, | ||
| 78 | }); | ||
| 79 | try expect(@enumToInt(e) == y); | ||
| 80 | |||
| 81 | try expect(@typeInfo(E).Enum.fields.len == 0); | ||
| 82 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | try S.doTheTest(42); | ||
| 86 | comptime try S.doTheTest(42); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "single field non-exhaustive enum" { | ||
| 90 | const S = struct { | ||
| 91 | const E = enum(u8) { | ||
| 92 | a, | ||
| 93 | _, | ||
| 94 | }; | ||
| 95 | fn doTheTest(y: u8) !void { | ||
| 96 | var e: E = .a; | ||
| 97 | try expect(switch (e) { | ||
| 98 | .a => true, | ||
| 99 | _ => false, | ||
| 100 | }); | ||
| 101 | e = @intToEnum(E, 12); | ||
| 102 | try expect(switch (e) { | ||
| 103 | .a => false, | ||
| 104 | _ => true, | ||
| 105 | }); | ||
| 106 | |||
| 107 | try expect(switch (e) { | ||
| 108 | .a => false, | ||
| 109 | else => true, | ||
| 110 | }); | ||
| 111 | e = .a; | ||
| 112 | try expect(switch (e) { | ||
| 113 | .a => true, | ||
| 114 | else => false, | ||
| 115 | }); | ||
| 116 | |||
| 117 | try expect(@enumToInt(@intToEnum(E, y)) == y); | ||
| 118 | try expect(@typeInfo(E).Enum.fields.len == 1); | ||
| 119 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | try S.doTheTest(23); | ||
| 123 | comptime try S.doTheTest(23); | ||
| 124 | } | ||
| 125 | |||
| 126 | test "enum type" { | ||
| 127 | const foo1 = Foo{ .One = 13 }; | ||
| 128 | const foo2 = Foo{ | ||
| 129 | .Two = Point{ | ||
| 130 | .x = 1234, | ||
| 131 | .y = 5678, | ||
| 132 | }, | ||
| 133 | }; | ||
| 134 | const bar = Bar.B; | ||
| 135 | |||
| 136 | try expect(bar == Bar.B); | ||
| 137 | try expect(@typeInfo(Foo).Union.fields.len == 3); | ||
| 138 | try expect(@typeInfo(Bar).Enum.fields.len == 4); | ||
| 139 | try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); | ||
| 140 | try expect(@sizeOf(Bar) == 1); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "enum as return value" { | ||
| 144 | switch (returnAnInt(13)) { | ||
| 145 | Foo.One => |value| try expect(value == 13), | ||
| 146 | else => unreachable, | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | const Point = struct { | ||
| 151 | x: u64, | ||
| 152 | y: u64, | ||
| 153 | }; | ||
| 154 | const Foo = union(enum) { | ||
| 155 | One: i32, | ||
| 156 | Two: Point, | ||
| 157 | Three: void, | ||
| 158 | }; | ||
| 159 | const FooNoVoid = union(enum) { | ||
| 160 | One: i32, | ||
| 161 | Two: Point, | ||
| 162 | }; | ||
| 163 | const Bar = enum { | ||
| 164 | A, | ||
| 165 | B, | ||
| 166 | C, | ||
| 167 | D, | ||
| 168 | }; | ||
| 169 | |||
| 170 | fn returnAnInt(x: i32) Foo { | ||
| 171 | return Foo{ .One = x }; | ||
| 172 | } | ||
| 173 | |||
| 174 | test "constant enum with payload" { | ||
| 175 | var empty = AnEnumWithPayload{ .Empty = {} }; | ||
| 176 | var full = AnEnumWithPayload{ .Full = 13 }; | ||
| 177 | shouldBeEmpty(empty); | ||
| 178 | shouldBeNotEmpty(full); | ||
| 179 | } | ||
| 180 | |||
| 181 | fn shouldBeEmpty(x: AnEnumWithPayload) void { | ||
| 182 | switch (x) { | ||
| 183 | AnEnumWithPayload.Empty => {}, | ||
| 184 | else => unreachable, | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | fn shouldBeNotEmpty(x: AnEnumWithPayload) void { | ||
| 189 | switch (x) { | ||
| 190 | AnEnumWithPayload.Empty => unreachable, | ||
| 191 | else => {}, | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | const AnEnumWithPayload = union(enum) { | ||
| 196 | Empty: void, | ||
| 197 | Full: i32, | ||
| 198 | }; | ||
| 199 | |||
| 200 | const Number = enum { | ||
| 201 | Zero, | ||
| 202 | One, | ||
| 203 | Two, | ||
| 204 | Three, | ||
| 205 | Four, | ||
| 206 | }; | ||
| 207 | |||
| 208 | test "enum to int" { | ||
| 209 | try shouldEqual(Number.Zero, 0); | ||
| 210 | try shouldEqual(Number.One, 1); | ||
| 211 | try shouldEqual(Number.Two, 2); | ||
| 212 | try shouldEqual(Number.Three, 3); | ||
| 213 | try shouldEqual(Number.Four, 4); | ||
| 214 | } | ||
| 215 | |||
| 216 | fn shouldEqual(n: Number, expected: u3) !void { | ||
| 217 | try expect(@enumToInt(n) == expected); | ||
| 218 | } | ||
| 219 | |||
| 220 | test "int to enum" { | ||
| 221 | try testIntToEnumEval(3); | ||
| 222 | } | ||
| 223 | fn testIntToEnumEval(x: i32) !void { | ||
| 224 | try expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); | ||
| 225 | } | ||
| 226 | const IntToEnumNumber = enum { | ||
| 227 | Zero, | ||
| 228 | One, | ||
| 229 | Two, | ||
| 230 | Three, | ||
| 231 | Four, | ||
| 232 | }; | ||
| 233 | |||
| 234 | test "@tagName" { | ||
| 235 | try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 236 | comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "@tagName extern enum with duplicates" { | ||
| 240 | try expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | ||
| 241 | comptime try expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | ||
| 242 | } | ||
| 243 | |||
| 244 | test "@tagName non-exhaustive enum" { | ||
| 245 | try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | ||
| 246 | comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | ||
| 247 | } | ||
| 248 | |||
| 249 | fn testEnumTagNameBare(n: anytype) []const u8 { | ||
| 250 | return @tagName(n); | ||
| 251 | } | ||
| 252 | |||
| 253 | const BareNumber = enum { | ||
| 254 | One, | ||
| 255 | Two, | ||
| 256 | Three, | ||
| 257 | }; | ||
| 258 | |||
| 259 | const ExternDuplicates = extern enum(u8) { | ||
| 260 | A = 1, | ||
| 261 | B = 1, | ||
| 262 | }; | ||
| 263 | |||
| 264 | const NonExhaustive = enum(u8) { | ||
| 265 | A, | ||
| 266 | B, | ||
| 267 | _, | ||
| 268 | }; | ||
| 269 | |||
| 270 | test "enum alignment" { | ||
| 271 | comptime { | ||
| 272 | try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); | ||
| 273 | try expect(@alignOf(AlignTestEnum) >= @alignOf(u64)); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | const AlignTestEnum = union(enum) { | ||
| 278 | A: [9]u8, | ||
| 279 | B: u64, | ||
| 280 | }; | ||
| 281 | |||
| 282 | const ValueCount1 = enum { | ||
| 283 | I0, | ||
| 284 | }; | ||
| 285 | const ValueCount2 = enum { | ||
| 286 | I0, | ||
| 287 | I1, | ||
| 288 | }; | ||
| 289 | const ValueCount256 = enum { | ||
| 290 | I0, | ||
| 291 | I1, | ||
| 292 | I2, | ||
| 293 | I3, | ||
| 294 | I4, | ||
| 295 | I5, | ||
| 296 | I6, | ||
| 297 | I7, | ||
| 298 | I8, | ||
| 299 | I9, | ||
| 300 | I10, | ||
| 301 | I11, | ||
| 302 | I12, | ||
| 303 | I13, | ||
| 304 | I14, | ||
| 305 | I15, | ||
| 306 | I16, | ||
| 307 | I17, | ||
| 308 | I18, | ||
| 309 | I19, | ||
| 310 | I20, | ||
| 311 | I21, | ||
| 312 | I22, | ||
| 313 | I23, | ||
| 314 | I24, | ||
| 315 | I25, | ||
| 316 | I26, | ||
| 317 | I27, | ||
| 318 | I28, | ||
| 319 | I29, | ||
| 320 | I30, | ||
| 321 | I31, | ||
| 322 | I32, | ||
| 323 | I33, | ||
| 324 | I34, | ||
| 325 | I35, | ||
| 326 | I36, | ||
| 327 | I37, | ||
| 328 | I38, | ||
| 329 | I39, | ||
| 330 | I40, | ||
| 331 | I41, | ||
| 332 | I42, | ||
| 333 | I43, | ||
| 334 | I44, | ||
| 335 | I45, | ||
| 336 | I46, | ||
| 337 | I47, | ||
| 338 | I48, | ||
| 339 | I49, | ||
| 340 | I50, | ||
| 341 | I51, | ||
| 342 | I52, | ||
| 343 | I53, | ||
| 344 | I54, | ||
| 345 | I55, | ||
| 346 | I56, | ||
| 347 | I57, | ||
| 348 | I58, | ||
| 349 | I59, | ||
| 350 | I60, | ||
| 351 | I61, | ||
| 352 | I62, | ||
| 353 | I63, | ||
| 354 | I64, | ||
| 355 | I65, | ||
| 356 | I66, | ||
| 357 | I67, | ||
| 358 | I68, | ||
| 359 | I69, | ||
| 360 | I70, | ||
| 361 | I71, | ||
| 362 | I72, | ||
| 363 | I73, | ||
| 364 | I74, | ||
| 365 | I75, | ||
| 366 | I76, | ||
| 367 | I77, | ||
| 368 | I78, | ||
| 369 | I79, | ||
| 370 | I80, | ||
| 371 | I81, | ||
| 372 | I82, | ||
| 373 | I83, | ||
| 374 | I84, | ||
| 375 | I85, | ||
| 376 | I86, | ||
| 377 | I87, | ||
| 378 | I88, | ||
| 379 | I89, | ||
| 380 | I90, | ||
| 381 | I91, | ||
| 382 | I92, | ||
| 383 | I93, | ||
| 384 | I94, | ||
| 385 | I95, | ||
| 386 | I96, | ||
| 387 | I97, | ||
| 388 | I98, | ||
| 389 | I99, | ||
| 390 | I100, | ||
| 391 | I101, | ||
| 392 | I102, | ||
| 393 | I103, | ||
| 394 | I104, | ||
| 395 | I105, | ||
| 396 | I106, | ||
| 397 | I107, | ||
| 398 | I108, | ||
| 399 | I109, | ||
| 400 | I110, | ||
| 401 | I111, | ||
| 402 | I112, | ||
| 403 | I113, | ||
| 404 | I114, | ||
| 405 | I115, | ||
| 406 | I116, | ||
| 407 | I117, | ||
| 408 | I118, | ||
| 409 | I119, | ||
| 410 | I120, | ||
| 411 | I121, | ||
| 412 | I122, | ||
| 413 | I123, | ||
| 414 | I124, | ||
| 415 | I125, | ||
| 416 | I126, | ||
| 417 | I127, | ||
| 418 | I128, | ||
| 419 | I129, | ||
| 420 | I130, | ||
| 421 | I131, | ||
| 422 | I132, | ||
| 423 | I133, | ||
| 424 | I134, | ||
| 425 | I135, | ||
| 426 | I136, | ||
| 427 | I137, | ||
| 428 | I138, | ||
| 429 | I139, | ||
| 430 | I140, | ||
| 431 | I141, | ||
| 432 | I142, | ||
| 433 | I143, | ||
| 434 | I144, | ||
| 435 | I145, | ||
| 436 | I146, | ||
| 437 | I147, | ||
| 438 | I148, | ||
| 439 | I149, | ||
| 440 | I150, | ||
| 441 | I151, | ||
| 442 | I152, | ||
| 443 | I153, | ||
| 444 | I154, | ||
| 445 | I155, | ||
| 446 | I156, | ||
| 447 | I157, | ||
| 448 | I158, | ||
| 449 | I159, | ||
| 450 | I160, | ||
| 451 | I161, | ||
| 452 | I162, | ||
| 453 | I163, | ||
| 454 | I164, | ||
| 455 | I165, | ||
| 456 | I166, | ||
| 457 | I167, | ||
| 458 | I168, | ||
| 459 | I169, | ||
| 460 | I170, | ||
| 461 | I171, | ||
| 462 | I172, | ||
| 463 | I173, | ||
| 464 | I174, | ||
| 465 | I175, | ||
| 466 | I176, | ||
| 467 | I177, | ||
| 468 | I178, | ||
| 469 | I179, | ||
| 470 | I180, | ||
| 471 | I181, | ||
| 472 | I182, | ||
| 473 | I183, | ||
| 474 | I184, | ||
| 475 | I185, | ||
| 476 | I186, | ||
| 477 | I187, | ||
| 478 | I188, | ||
| 479 | I189, | ||
| 480 | I190, | ||
| 481 | I191, | ||
| 482 | I192, | ||
| 483 | I193, | ||
| 484 | I194, | ||
| 485 | I195, | ||
| 486 | I196, | ||
| 487 | I197, | ||
| 488 | I198, | ||
| 489 | I199, | ||
| 490 | I200, | ||
| 491 | I201, | ||
| 492 | I202, | ||
| 493 | I203, | ||
| 494 | I204, | ||
| 495 | I205, | ||
| 496 | I206, | ||
| 497 | I207, | ||
| 498 | I208, | ||
| 499 | I209, | ||
| 500 | I210, | ||
| 501 | I211, | ||
| 502 | I212, | ||
| 503 | I213, | ||
| 504 | I214, | ||
| 505 | I215, | ||
| 506 | I216, | ||
| 507 | I217, | ||
| 508 | I218, | ||
| 509 | I219, | ||
| 510 | I220, | ||
| 511 | I221, | ||
| 512 | I222, | ||
| 513 | I223, | ||
| 514 | I224, | ||
| 515 | I225, | ||
| 516 | I226, | ||
| 517 | I227, | ||
| 518 | I228, | ||
| 519 | I229, | ||
| 520 | I230, | ||
| 521 | I231, | ||
| 522 | I232, | ||
| 523 | I233, | ||
| 524 | I234, | ||
| 525 | I235, | ||
| 526 | I236, | ||
| 527 | I237, | ||
| 528 | I238, | ||
| 529 | I239, | ||
| 530 | I240, | ||
| 531 | I241, | ||
| 532 | I242, | ||
| 533 | I243, | ||
| 534 | I244, | ||
| 535 | I245, | ||
| 536 | I246, | ||
| 537 | I247, | ||
| 538 | I248, | ||
| 539 | I249, | ||
| 540 | I250, | ||
| 541 | I251, | ||
| 542 | I252, | ||
| 543 | I253, | ||
| 544 | I254, | ||
| 545 | I255, | ||
| 546 | }; | ||
| 547 | const ValueCount257 = enum { | ||
| 548 | I0, | ||
| 549 | I1, | ||
| 550 | I2, | ||
| 551 | I3, | ||
| 552 | I4, | ||
| 553 | I5, | ||
| 554 | I6, | ||
| 555 | I7, | ||
| 556 | I8, | ||
| 557 | I9, | ||
| 558 | I10, | ||
| 559 | I11, | ||
| 560 | I12, | ||
| 561 | I13, | ||
| 562 | I14, | ||
| 563 | I15, | ||
| 564 | I16, | ||
| 565 | I17, | ||
| 566 | I18, | ||
| 567 | I19, | ||
| 568 | I20, | ||
| 569 | I21, | ||
| 570 | I22, | ||
| 571 | I23, | ||
| 572 | I24, | ||
| 573 | I25, | ||
| 574 | I26, | ||
| 575 | I27, | ||
| 576 | I28, | ||
| 577 | I29, | ||
| 578 | I30, | ||
| 579 | I31, | ||
| 580 | I32, | ||
| 581 | I33, | ||
| 582 | I34, | ||
| 583 | I35, | ||
| 584 | I36, | ||
| 585 | I37, | ||
| 586 | I38, | ||
| 587 | I39, | ||
| 588 | I40, | ||
| 589 | I41, | ||
| 590 | I42, | ||
| 591 | I43, | ||
| 592 | I44, | ||
| 593 | I45, | ||
| 594 | I46, | ||
| 595 | I47, | ||
| 596 | I48, | ||
| 597 | I49, | ||
| 598 | I50, | ||
| 599 | I51, | ||
| 600 | I52, | ||
| 601 | I53, | ||
| 602 | I54, | ||
| 603 | I55, | ||
| 604 | I56, | ||
| 605 | I57, | ||
| 606 | I58, | ||
| 607 | I59, | ||
| 608 | I60, | ||
| 609 | I61, | ||
| 610 | I62, | ||
| 611 | I63, | ||
| 612 | I64, | ||
| 613 | I65, | ||
| 614 | I66, | ||
| 615 | I67, | ||
| 616 | I68, | ||
| 617 | I69, | ||
| 618 | I70, | ||
| 619 | I71, | ||
| 620 | I72, | ||
| 621 | I73, | ||
| 622 | I74, | ||
| 623 | I75, | ||
| 624 | I76, | ||
| 625 | I77, | ||
| 626 | I78, | ||
| 627 | I79, | ||
| 628 | I80, | ||
| 629 | I81, | ||
| 630 | I82, | ||
| 631 | I83, | ||
| 632 | I84, | ||
| 633 | I85, | ||
| 634 | I86, | ||
| 635 | I87, | ||
| 636 | I88, | ||
| 637 | I89, | ||
| 638 | I90, | ||
| 639 | I91, | ||
| 640 | I92, | ||
| 641 | I93, | ||
| 642 | I94, | ||
| 643 | I95, | ||
| 644 | I96, | ||
| 645 | I97, | ||
| 646 | I98, | ||
| 647 | I99, | ||
| 648 | I100, | ||
| 649 | I101, | ||
| 650 | I102, | ||
| 651 | I103, | ||
| 652 | I104, | ||
| 653 | I105, | ||
| 654 | I106, | ||
| 655 | I107, | ||
| 656 | I108, | ||
| 657 | I109, | ||
| 658 | I110, | ||
| 659 | I111, | ||
| 660 | I112, | ||
| 661 | I113, | ||
| 662 | I114, | ||
| 663 | I115, | ||
| 664 | I116, | ||
| 665 | I117, | ||
| 666 | I118, | ||
| 667 | I119, | ||
| 668 | I120, | ||
| 669 | I121, | ||
| 670 | I122, | ||
| 671 | I123, | ||
| 672 | I124, | ||
| 673 | I125, | ||
| 674 | I126, | ||
| 675 | I127, | ||
| 676 | I128, | ||
| 677 | I129, | ||
| 678 | I130, | ||
| 679 | I131, | ||
| 680 | I132, | ||
| 681 | I133, | ||
| 682 | I134, | ||
| 683 | I135, | ||
| 684 | I136, | ||
| 685 | I137, | ||
| 686 | I138, | ||
| 687 | I139, | ||
| 688 | I140, | ||
| 689 | I141, | ||
| 690 | I142, | ||
| 691 | I143, | ||
| 692 | I144, | ||
| 693 | I145, | ||
| 694 | I146, | ||
| 695 | I147, | ||
| 696 | I148, | ||
| 697 | I149, | ||
| 698 | I150, | ||
| 699 | I151, | ||
| 700 | I152, | ||
| 701 | I153, | ||
| 702 | I154, | ||
| 703 | I155, | ||
| 704 | I156, | ||
| 705 | I157, | ||
| 706 | I158, | ||
| 707 | I159, | ||
| 708 | I160, | ||
| 709 | I161, | ||
| 710 | I162, | ||
| 711 | I163, | ||
| 712 | I164, | ||
| 713 | I165, | ||
| 714 | I166, | ||
| 715 | I167, | ||
| 716 | I168, | ||
| 717 | I169, | ||
| 718 | I170, | ||
| 719 | I171, | ||
| 720 | I172, | ||
| 721 | I173, | ||
| 722 | I174, | ||
| 723 | I175, | ||
| 724 | I176, | ||
| 725 | I177, | ||
| 726 | I178, | ||
| 727 | I179, | ||
| 728 | I180, | ||
| 729 | I181, | ||
| 730 | I182, | ||
| 731 | I183, | ||
| 732 | I184, | ||
| 733 | I185, | ||
| 734 | I186, | ||
| 735 | I187, | ||
| 736 | I188, | ||
| 737 | I189, | ||
| 738 | I190, | ||
| 739 | I191, | ||
| 740 | I192, | ||
| 741 | I193, | ||
| 742 | I194, | ||
| 743 | I195, | ||
| 744 | I196, | ||
| 745 | I197, | ||
| 746 | I198, | ||
| 747 | I199, | ||
| 748 | I200, | ||
| 749 | I201, | ||
| 750 | I202, | ||
| 751 | I203, | ||
| 752 | I204, | ||
| 753 | I205, | ||
| 754 | I206, | ||
| 755 | I207, | ||
| 756 | I208, | ||
| 757 | I209, | ||
| 758 | I210, | ||
| 759 | I211, | ||
| 760 | I212, | ||
| 761 | I213, | ||
| 762 | I214, | ||
| 763 | I215, | ||
| 764 | I216, | ||
| 765 | I217, | ||
| 766 | I218, | ||
| 767 | I219, | ||
| 768 | I220, | ||
| 769 | I221, | ||
| 770 | I222, | ||
| 771 | I223, | ||
| 772 | I224, | ||
| 773 | I225, | ||
| 774 | I226, | ||
| 775 | I227, | ||
| 776 | I228, | ||
| 777 | I229, | ||
| 778 | I230, | ||
| 779 | I231, | ||
| 780 | I232, | ||
| 781 | I233, | ||
| 782 | I234, | ||
| 783 | I235, | ||
| 784 | I236, | ||
| 785 | I237, | ||
| 786 | I238, | ||
| 787 | I239, | ||
| 788 | I240, | ||
| 789 | I241, | ||
| 790 | I242, | ||
| 791 | I243, | ||
| 792 | I244, | ||
| 793 | I245, | ||
| 794 | I246, | ||
| 795 | I247, | ||
| 796 | I248, | ||
| 797 | I249, | ||
| 798 | I250, | ||
| 799 | I251, | ||
| 800 | I252, | ||
| 801 | I253, | ||
| 802 | I254, | ||
| 803 | I255, | ||
| 804 | I256, | ||
| 805 | }; | ||
| 806 | |||
| 807 | test "enum sizes" { | ||
| 808 | comptime { | ||
| 809 | try expect(@sizeOf(ValueCount1) == 0); | ||
| 810 | try expect(@sizeOf(ValueCount2) == 1); | ||
| 811 | try expect(@sizeOf(ValueCount256) == 1); | ||
| 812 | try expect(@sizeOf(ValueCount257) == 2); | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | const Small2 = enum(u2) { | ||
| 817 | One, | ||
| 818 | Two, | ||
| 819 | }; | ||
| 820 | const Small = enum(u2) { | ||
| 821 | One, | ||
| 822 | Two, | ||
| 823 | Three, | ||
| 824 | Four, | ||
| 825 | }; | ||
| 826 | |||
| 827 | test "set enum tag type" { | ||
| 828 | { | ||
| 829 | var x = Small.One; | ||
| 830 | x = Small.Two; | ||
| 831 | comptime try expect(Tag(Small) == u2); | ||
| 832 | } | ||
| 833 | { | ||
| 834 | var x = Small2.One; | ||
| 835 | x = Small2.Two; | ||
| 836 | comptime try expect(Tag(Small2) == u2); | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | const A = enum(u3) { | ||
| 841 | One, | ||
| 842 | Two, | ||
| 843 | Three, | ||
| 844 | Four, | ||
| 845 | One2, | ||
| 846 | Two2, | ||
| 847 | Three2, | ||
| 848 | Four2, | ||
| 849 | }; | ||
| 850 | |||
| 851 | const B = enum(u3) { | ||
| 852 | One3, | ||
| 853 | Two3, | ||
| 854 | Three3, | ||
| 855 | Four3, | ||
| 856 | One23, | ||
| 857 | Two23, | ||
| 858 | Three23, | ||
| 859 | Four23, | ||
| 860 | }; | ||
| 861 | |||
| 862 | const C = enum(u2) { | ||
| 863 | One4, | ||
| 864 | Two4, | ||
| 865 | Three4, | ||
| 866 | Four4, | ||
| 867 | }; | ||
| 868 | |||
| 869 | const BitFieldOfEnums = packed struct { | ||
| 870 | a: A, | ||
| 871 | b: B, | ||
| 872 | c: C, | ||
| 873 | }; | ||
| 874 | |||
| 875 | const bit_field_1 = BitFieldOfEnums{ | ||
| 876 | .a = A.Two, | ||
| 877 | .b = B.Three3, | ||
| 878 | .c = C.Four4, | ||
| 879 | }; | ||
| 880 | |||
| 881 | test "bit field access with enum fields" { | ||
| 882 | var data = bit_field_1; | ||
| 883 | try expect(getA(&data) == A.Two); | ||
| 884 | try expect(getB(&data) == B.Three3); | ||
| 885 | try expect(getC(&data) == C.Four4); | ||
| 886 | comptime try expect(@sizeOf(BitFieldOfEnums) == 1); | ||
| 887 | |||
| 888 | data.b = B.Four3; | ||
| 889 | try expect(data.b == B.Four3); | ||
| 890 | |||
| 891 | data.a = A.Three; | ||
| 892 | try expect(data.a == A.Three); | ||
| 893 | try expect(data.b == B.Four3); | ||
| 894 | } | ||
| 895 | |||
| 896 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 897 | return data.a; | ||
| 898 | } | ||
| 899 | |||
| 900 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 901 | return data.b; | ||
| 902 | } | ||
| 903 | |||
| 904 | fn getC(data: *const BitFieldOfEnums) C { | ||
| 905 | return data.c; | ||
| 906 | } | ||
| 907 | |||
| 908 | test "casting enum to its tag type" { | ||
| 909 | try testCastEnumTag(Small2.Two); | ||
| 910 | comptime try testCastEnumTag(Small2.Two); | ||
| 911 | } | ||
| 912 | |||
| 913 | fn testCastEnumTag(value: Small2) !void { | ||
| 914 | try expect(@enumToInt(value) == 1); | ||
| 915 | } | ||
| 916 | |||
| 917 | const MultipleChoice = enum(u32) { | ||
| 918 | A = 20, | ||
| 919 | B = 40, | ||
| 920 | C = 60, | ||
| 921 | D = 1000, | ||
| 922 | }; | ||
| 923 | |||
| 924 | test "enum with specified tag values" { | ||
| 925 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 926 | comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 927 | } | ||
| 928 | |||
| 929 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { | ||
| 930 | try expect(@enumToInt(x) == 60); | ||
| 931 | try expect(1234 == switch (x) { | ||
| 932 | MultipleChoice.A => 1, | ||
| 933 | MultipleChoice.B => 2, | ||
| 934 | MultipleChoice.C => @as(u32, 1234), | ||
| 935 | MultipleChoice.D => 4, | ||
| 936 | }); | ||
| 937 | } | ||
| 938 | |||
| 939 | const MultipleChoice2 = enum(u32) { | ||
| 940 | Unspecified1, | ||
| 941 | A = 20, | ||
| 942 | Unspecified2, | ||
| 943 | B = 40, | ||
| 944 | Unspecified3, | ||
| 945 | C = 60, | ||
| 946 | Unspecified4, | ||
| 947 | D = 1000, | ||
| 948 | Unspecified5, | ||
| 949 | }; | ||
| 950 | |||
| 951 | test "enum with specified and unspecified tag values" { | ||
| 952 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 953 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 954 | } | ||
| 955 | |||
| 956 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { | ||
| 957 | try expect(@enumToInt(x) == 1000); | ||
| 958 | try expect(1234 == switch (x) { | ||
| 959 | MultipleChoice2.A => 1, | ||
| 960 | MultipleChoice2.B => 2, | ||
| 961 | MultipleChoice2.C => 3, | ||
| 962 | MultipleChoice2.D => @as(u32, 1234), | ||
| 963 | MultipleChoice2.Unspecified1 => 5, | ||
| 964 | MultipleChoice2.Unspecified2 => 6, | ||
| 965 | MultipleChoice2.Unspecified3 => 7, | ||
| 966 | MultipleChoice2.Unspecified4 => 8, | ||
| 967 | MultipleChoice2.Unspecified5 => 9, | ||
| 968 | }); | ||
| 969 | } | ||
| 970 | |||
| 971 | test "cast integer literal to enum" { | ||
| 972 | try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | ||
| 973 | try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | ||
| 974 | } | ||
| 975 | |||
| 976 | const EnumWithOneMember = enum { | ||
| 977 | Eof, | ||
| 978 | }; | ||
| 979 | |||
| 980 | fn doALoopThing(id: EnumWithOneMember) void { | ||
| 981 | while (true) { | ||
| 982 | if (id == EnumWithOneMember.Eof) { | ||
| 983 | break; | ||
| 984 | } | ||
| 985 | @compileError("above if condition should be comptime"); | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | test "comparison operator on enum with one member is comptime known" { | ||
| 990 | doALoopThing(EnumWithOneMember.Eof); | ||
| 991 | } | ||
| 992 | |||
| 993 | const State = enum { | ||
| 994 | Start, | ||
| 995 | }; | ||
| 996 | test "switch on enum with one member is comptime known" { | ||
| 997 | var state = State.Start; | ||
| 998 | switch (state) { | ||
| 999 | State.Start => return, | ||
| 1000 | } | ||
| 1001 | @compileError("analysis should not reach here"); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | const EnumWithTagValues = enum(u4) { | ||
| 1005 | A = 1 << 0, | ||
| 1006 | B = 1 << 1, | ||
| 1007 | C = 1 << 2, | ||
| 1008 | D = 1 << 3, | ||
| 1009 | }; | ||
| 1010 | test "enum with tag values don't require parens" { | ||
| 1011 | try expect(@enumToInt(EnumWithTagValues.C) == 0b0100); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | test "enum with 1 field but explicit tag type should still have the tag type" { | ||
| 1015 | const Enum = enum(u8) { | ||
| 1016 | B = 2, | ||
| 1017 | }; | ||
| 1018 | comptime try expect(@sizeOf(Enum) == @sizeOf(u8)); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | test "empty extern enum with members" { | ||
| 1022 | const E = extern enum { | ||
| 1023 | A, | ||
| 1024 | B, | ||
| 1025 | C, | ||
| 1026 | }; | ||
| 1027 | try expect(@sizeOf(E) == @sizeOf(c_int)); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | test "tag name with assigned enum values" { | ||
| 1031 | const LocalFoo = enum { | ||
| 1032 | A = 1, | ||
| 1033 | B = 0, | ||
| 1034 | }; | ||
| 1035 | var b = LocalFoo.B; | ||
| 1036 | try expect(mem.eql(u8, @tagName(b), "B")); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | test "enum literal equality" { | ||
| 1040 | const x = .hi; | ||
| 1041 | const y = .ok; | ||
| 1042 | const z = .hi; | ||
| 1043 | |||
| 1044 | try expect(x != y); | ||
| 1045 | try expect(x == z); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | test "enum literal cast to enum" { | ||
| 1049 | const Color = enum { | ||
| 1050 | Auto, | ||
| 1051 | Off, | ||
| 1052 | On, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | var color1: Color = .Auto; | ||
| 1056 | var color2 = Color.Auto; | ||
| 1057 | try expect(color1 == color2); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | test "peer type resolution with enum literal" { | ||
| 1061 | const Items = enum { | ||
| 1062 | one, | ||
| 1063 | two, | ||
| 1064 | }; | ||
| 1065 | |||
| 1066 | try expect(Items.two == .two); | ||
| 1067 | try expect(.two == Items.two); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | test "enum literal in array literal" { | ||
| 1071 | const Items = enum { | ||
| 1072 | one, | ||
| 1073 | two, | ||
| 1074 | }; | ||
| 1075 | |||
| 1076 | const array = [_]Items{ | ||
| 1077 | .one, | ||
| 1078 | .two, | ||
| 1079 | }; | ||
| 1080 | |||
| 1081 | try expect(array[0] == .one); | ||
| 1082 | try expect(array[1] == .two); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | test "signed integer as enum tag" { | ||
| 1086 | const SignedEnum = enum(i2) { | ||
| 1087 | A0 = -1, | ||
| 1088 | A1 = 0, | ||
| 1089 | A2 = 1, | ||
| 1090 | }; | ||
| 1091 | |||
| 1092 | try expect(@enumToInt(SignedEnum.A0) == -1); | ||
| 1093 | try expect(@enumToInt(SignedEnum.A1) == 0); | ||
| 1094 | try expect(@enumToInt(SignedEnum.A2) == 1); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | test "enum value allocation" { | ||
| 1098 | const LargeEnum = enum(u32) { | ||
| 1099 | A0 = 0x80000000, | ||
| 1100 | A1, | ||
| 1101 | A2, | ||
| 1102 | }; | ||
| 1103 | |||
| 1104 | try expect(@enumToInt(LargeEnum.A0) == 0x80000000); | ||
| 1105 | try expect(@enumToInt(LargeEnum.A1) == 0x80000001); | ||
| 1106 | try expect(@enumToInt(LargeEnum.A2) == 0x80000002); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "enum literal casting to tagged union" { | ||
| 1110 | const Arch = union(enum) { | ||
| 1111 | x86_64, | ||
| 1112 | arm: Arm32, | ||
| 1113 | |||
| 1114 | const Arm32 = enum { | ||
| 1115 | v8_5a, | ||
| 1116 | v8_4a, | ||
| 1117 | }; | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | var t = true; | ||
| 1121 | var x: Arch = .x86_64; | ||
| 1122 | var y = if (t) x else .x86_64; | ||
| 1123 | switch (y) { | ||
| 1124 | .x86_64 => {}, | ||
| 1125 | else => @panic("fail"), | ||
| 1126 | } | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | test "enum with one member and custom tag type" { | ||
| 1130 | const E = enum(u2) { | ||
| 1131 | One, | ||
| 1132 | }; | ||
| 1133 | try expect(@enumToInt(E.One) == 0); | ||
| 1134 | const E2 = enum(u2) { | ||
| 1135 | One = 2, | ||
| 1136 | }; | ||
| 1137 | try expect(@enumToInt(E2.One) == 2); | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | test "enum literal casting to optional" { | ||
| 1141 | var bar: ?Bar = undefined; | ||
| 1142 | bar = .B; | ||
| 1143 | |||
| 1144 | try expect(bar.? == Bar.B); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | test "enum literal casting to error union with payload enum" { | ||
| 1148 | var bar: error{B}!Bar = undefined; | ||
| 1149 | bar = .B; // should never cast to the error set | ||
| 1150 | |||
| 1151 | try expect((try bar) == Bar.B); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | test "enum with one member and u1 tag type @enumToInt" { | ||
| 1155 | const Enum = enum(u1) { | ||
| 1156 | Test, | ||
| 1157 | }; | ||
| 1158 | try expect(@enumToInt(Enum.Test) == 0); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | test "enum with comptime_int tag type" { | ||
| 1162 | const Enum = enum(comptime_int) { | ||
| 1163 | One = 3, | ||
| 1164 | Two = 2, | ||
| 1165 | Three = 1, | ||
| 1166 | }; | ||
| 1167 | comptime try expect(Tag(Enum) == comptime_int); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | test "enum with one member default to u0 tag type" { | ||
| 1171 | const E0 = enum { | ||
| 1172 | X, | ||
| 1173 | }; | ||
| 1174 | comptime try expect(Tag(E0) == u0); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | test "tagName on enum literals" { | ||
| 1178 | try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); | ||
| 1179 | comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | test "method call on an enum" { | ||
| 1183 | const S = struct { | ||
| 1184 | const E = enum { | ||
| 1185 | one, | ||
| 1186 | two, | ||
| 1187 | |||
| 1188 | fn method(self: *E) bool { | ||
| 1189 | return self.* == .two; | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | fn generic_method(self: *E, foo: anytype) bool { | ||
| 1193 | return self.* == .two and foo == bool; | ||
| 1194 | } | ||
| 1195 | }; | ||
| 1196 | fn doTheTest() !void { | ||
| 1197 | var e = E.two; | ||
| 1198 | try expect(e.method()); | ||
| 1199 | try expect(e.generic_method(bool)); | ||
| 1200 | } | ||
| 1201 | }; | ||
| 1202 | try S.doTheTest(); | ||
| 1203 | comptime try S.doTheTest(); | ||
| 1204 | } | ||
test/behavior/enum_with_members.zig created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const fmt = @import("std").fmt; | ||
| 4 | |||
| 5 | const ET = union(enum) { | ||
| 6 | SINT: i32, | ||
| 7 | UINT: u32, | ||
| 8 | |||
| 9 | pub fn print(a: *const ET, buf: []u8) anyerror!usize { | ||
| 10 | return switch (a.*) { | ||
| 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}), | ||
| 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}), | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | |||
| 17 | test "enum with members" { | ||
| 18 | const a = ET{ .SINT = -42 }; | ||
| 19 | const b = ET{ .UINT = 42 }; | ||
| 20 | var buf: [20]u8 = undefined; | ||
| 21 | |||
| 22 | try expect((a.print(buf[0..]) catch unreachable) == 3); | ||
| 23 | try expect(mem.eql(u8, buf[0..3], "-42")); | ||
| 24 | |||
| 25 | try expect((b.print(buf[0..]) catch unreachable) == 2); | ||
| 26 | try expect(mem.eql(u8, buf[0..2], "42")); | ||
| 27 | } | ||
test/behavior/error.zig created+452| ... | @@ -0,0 +1,452 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectError = std.testing.expectError; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | pub fn foo() anyerror!i32 { | ||
| 8 | const x = try bar(); | ||
| 9 | return x + 1; | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn bar() anyerror!i32 { | ||
| 13 | return 13; | ||
| 14 | } | ||
| 15 | |||
| 16 | pub fn baz() anyerror!i32 { | ||
| 17 | const y = foo() catch 1234; | ||
| 18 | return y + 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "error wrapping" { | ||
| 22 | try expect((baz() catch unreachable) == 15); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn gimmeItBroke() []const u8 { | ||
| 26 | return @errorName(error.ItBroke); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "@errorName" { | ||
| 30 | try expect(mem.eql(u8, @errorName(error.AnError), "AnError")); | ||
| 31 | try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "error values" { | ||
| 35 | const a = @errorToInt(error.err1); | ||
| 36 | const b = @errorToInt(error.err2); | ||
| 37 | try expect(a != b); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "redefinition of error values allowed" { | ||
| 41 | shouldBeNotEqual(error.AnError, error.SecondError); | ||
| 42 | } | ||
| 43 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { | ||
| 44 | if (a == b) unreachable; | ||
| 45 | } | ||
| 46 | |||
| 47 | test "error binary operator" { | ||
| 48 | const a = errBinaryOperatorG(true) catch 3; | ||
| 49 | const b = errBinaryOperatorG(false) catch 3; | ||
| 50 | try expect(a == 3); | ||
| 51 | try expect(b == 10); | ||
| 52 | } | ||
| 53 | fn errBinaryOperatorG(x: bool) anyerror!isize { | ||
| 54 | return if (x) error.ItBroke else @as(isize, 10); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "unwrap simple value from error" { | ||
| 58 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; | ||
| 59 | try expect(i == 13); | ||
| 60 | } | ||
| 61 | fn unwrapSimpleValueFromErrorDo() anyerror!isize { | ||
| 62 | return 13; | ||
| 63 | } | ||
| 64 | |||
| 65 | test "error return in assignment" { | ||
| 66 | doErrReturnInAssignment() catch unreachable; | ||
| 67 | } | ||
| 68 | |||
| 69 | fn doErrReturnInAssignment() anyerror!void { | ||
| 70 | var x: i32 = undefined; | ||
| 71 | x = try makeANonErr(); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn makeANonErr() anyerror!i32 { | ||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | test "error union type " { | ||
| 79 | try testErrorUnionType(); | ||
| 80 | comptime try testErrorUnionType(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn testErrorUnionType() !void { | ||
| 84 | const x: anyerror!i32 = 1234; | ||
| 85 | if (x) |value| try expect(value == 1234) else |_| unreachable; | ||
| 86 | try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); | ||
| 87 | try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet); | ||
| 88 | try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "error set type" { | ||
| 92 | try testErrorSetType(); | ||
| 93 | comptime try testErrorSetType(); | ||
| 94 | } | ||
| 95 | |||
| 96 | const MyErrSet = error{ | ||
| 97 | OutOfMemory, | ||
| 98 | FileNotFound, | ||
| 99 | }; | ||
| 100 | |||
| 101 | fn testErrorSetType() !void { | ||
| 102 | try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2); | ||
| 103 | |||
| 104 | const a: MyErrSet!i32 = 5678; | ||
| 105 | const b: MyErrSet!i32 = MyErrSet.OutOfMemory; | ||
| 106 | |||
| 107 | if (a) |value| try expect(value == 5678) else |err| switch (err) { | ||
| 108 | error.OutOfMemory => unreachable, | ||
| 109 | error.FileNotFound => unreachable, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | test "explicit error set cast" { | ||
| 114 | try testExplicitErrorSetCast(Set1.A); | ||
| 115 | comptime try testExplicitErrorSetCast(Set1.A); | ||
| 116 | } | ||
| 117 | |||
| 118 | const Set1 = error{ | ||
| 119 | A, | ||
| 120 | B, | ||
| 121 | }; | ||
| 122 | const Set2 = error{ | ||
| 123 | A, | ||
| 124 | C, | ||
| 125 | }; | ||
| 126 | |||
| 127 | fn testExplicitErrorSetCast(set1: Set1) !void { | ||
| 128 | var x = @errSetCast(Set2, set1); | ||
| 129 | var y = @errSetCast(Set1, x); | ||
| 130 | try expect(y == error.A); | ||
| 131 | } | ||
| 132 | |||
| 133 | test "comptime test error for empty error set" { | ||
| 134 | try testComptimeTestErrorEmptySet(1234); | ||
| 135 | comptime try testComptimeTestErrorEmptySet(1234); | ||
| 136 | } | ||
| 137 | |||
| 138 | const EmptyErrorSet = error{}; | ||
| 139 | |||
| 140 | fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void { | ||
| 141 | if (x) |v| try expect(v == 1234) else |err| @compileError("bad"); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "syntax: optional operator in front of error union operator" { | ||
| 145 | comptime { | ||
| 146 | try expect(?(anyerror!i32) == ?(anyerror!i32)); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | test "comptime err to int of error set with only 1 possible value" { | ||
| 151 | testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 152 | comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 153 | } | ||
| 154 | fn testErrToIntWithOnePossibleValue( | ||
| 155 | x: error{A}, | ||
| 156 | comptime value: u32, | ||
| 157 | ) void { | ||
| 158 | if (@errorToInt(x) != value) { | ||
| 159 | @compileError("bad"); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | test "empty error union" { | ||
| 164 | const x = error{} || error{}; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "error union peer type resolution" { | ||
| 168 | try testErrorUnionPeerTypeResolution(1); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn testErrorUnionPeerTypeResolution(x: i32) !void { | ||
| 172 | const y = switch (x) { | ||
| 173 | 1 => bar_1(), | ||
| 174 | 2 => baz_1(), | ||
| 175 | else => quux_1(), | ||
| 176 | }; | ||
| 177 | if (y) |_| { | ||
| 178 | @panic("expected error"); | ||
| 179 | } else |e| { | ||
| 180 | try expect(e == error.A); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | fn bar_1() anyerror { | ||
| 185 | return error.A; | ||
| 186 | } | ||
| 187 | |||
| 188 | fn baz_1() !i32 { | ||
| 189 | return error.B; | ||
| 190 | } | ||
| 191 | |||
| 192 | fn quux_1() !i32 { | ||
| 193 | return error.C; | ||
| 194 | } | ||
| 195 | |||
| 196 | test "error: fn returning empty error set can be passed as fn returning any error" { | ||
| 197 | entry(); | ||
| 198 | comptime entry(); | ||
| 199 | } | ||
| 200 | |||
| 201 | fn entry() void { | ||
| 202 | foo2(bar2); | ||
| 203 | } | ||
| 204 | |||
| 205 | fn foo2(f: fn () anyerror!void) void { | ||
| 206 | const x = f(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn bar2() (error{}!void) {} | ||
| 210 | |||
| 211 | test "error: Zero sized error set returned with value payload crash" { | ||
| 212 | _ = foo3(0) catch {}; | ||
| 213 | _ = comptime foo3(0) catch {}; | ||
| 214 | } | ||
| 215 | |||
| 216 | const Error = error{}; | ||
| 217 | fn foo3(b: usize) Error!usize { | ||
| 218 | return b; | ||
| 219 | } | ||
| 220 | |||
| 221 | test "error: Infer error set from literals" { | ||
| 222 | _ = nullLiteral("n") catch |err| handleErrors(err); | ||
| 223 | _ = floatLiteral("n") catch |err| handleErrors(err); | ||
| 224 | _ = intLiteral("n") catch |err| handleErrors(err); | ||
| 225 | _ = comptime nullLiteral("n") catch |err| handleErrors(err); | ||
| 226 | _ = comptime floatLiteral("n") catch |err| handleErrors(err); | ||
| 227 | _ = comptime intLiteral("n") catch |err| handleErrors(err); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn handleErrors(err: anytype) noreturn { | ||
| 231 | switch (err) { | ||
| 232 | error.T => {}, | ||
| 233 | } | ||
| 234 | |||
| 235 | unreachable; | ||
| 236 | } | ||
| 237 | |||
| 238 | fn nullLiteral(str: []const u8) !?i64 { | ||
| 239 | if (str[0] == 'n') return null; | ||
| 240 | |||
| 241 | return error.T; | ||
| 242 | } | ||
| 243 | |||
| 244 | fn floatLiteral(str: []const u8) !?f64 { | ||
| 245 | if (str[0] == 'n') return 1.0; | ||
| 246 | |||
| 247 | return error.T; | ||
| 248 | } | ||
| 249 | |||
| 250 | fn intLiteral(str: []const u8) !?i64 { | ||
| 251 | if (str[0] == 'n') return 1; | ||
| 252 | |||
| 253 | return error.T; | ||
| 254 | } | ||
| 255 | |||
| 256 | test "nested error union function call in optional unwrap" { | ||
| 257 | const S = struct { | ||
| 258 | const Foo = struct { | ||
| 259 | a: i32, | ||
| 260 | }; | ||
| 261 | |||
| 262 | fn errorable() !i32 { | ||
| 263 | var x: Foo = (try getFoo()) orelse return error.Other; | ||
| 264 | return x.a; | ||
| 265 | } | ||
| 266 | |||
| 267 | fn errorable2() !i32 { | ||
| 268 | var x: Foo = (try getFoo2()) orelse return error.Other; | ||
| 269 | return x.a; | ||
| 270 | } | ||
| 271 | |||
| 272 | fn errorable3() !i32 { | ||
| 273 | var x: Foo = (try getFoo3()) orelse return error.Other; | ||
| 274 | return x.a; | ||
| 275 | } | ||
| 276 | |||
| 277 | fn getFoo() anyerror!?Foo { | ||
| 278 | return Foo{ .a = 1234 }; | ||
| 279 | } | ||
| 280 | |||
| 281 | fn getFoo2() anyerror!?Foo { | ||
| 282 | return error.Failure; | ||
| 283 | } | ||
| 284 | |||
| 285 | fn getFoo3() anyerror!?Foo { | ||
| 286 | return null; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | try expect((try S.errorable()) == 1234); | ||
| 290 | try expectError(error.Failure, S.errorable2()); | ||
| 291 | try expectError(error.Other, S.errorable3()); | ||
| 292 | comptime { | ||
| 293 | try expect((try S.errorable()) == 1234); | ||
| 294 | try expectError(error.Failure, S.errorable2()); | ||
| 295 | try expectError(error.Other, S.errorable3()); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | test "widen cast integer payload of error union function call" { | ||
| 300 | const S = struct { | ||
| 301 | fn errorable() !u64 { | ||
| 302 | var x = @as(u64, try number()); | ||
| 303 | return x; | ||
| 304 | } | ||
| 305 | |||
| 306 | fn number() anyerror!u32 { | ||
| 307 | return 1234; | ||
| 308 | } | ||
| 309 | }; | ||
| 310 | try expect((try S.errorable()) == 1234); | ||
| 311 | } | ||
| 312 | |||
| 313 | test "return function call to error set from error union function" { | ||
| 314 | const S = struct { | ||
| 315 | fn errorable() anyerror!i32 { | ||
| 316 | return fail(); | ||
| 317 | } | ||
| 318 | |||
| 319 | fn fail() anyerror { | ||
| 320 | return error.Failure; | ||
| 321 | } | ||
| 322 | }; | ||
| 323 | try expectError(error.Failure, S.errorable()); | ||
| 324 | comptime try expectError(error.Failure, S.errorable()); | ||
| 325 | } | ||
| 326 | |||
| 327 | test "optional error set is the same size as error set" { | ||
| 328 | comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); | ||
| 329 | const S = struct { | ||
| 330 | fn returnsOptErrSet() ?anyerror { | ||
| 331 | return null; | ||
| 332 | } | ||
| 333 | }; | ||
| 334 | try expect(S.returnsOptErrSet() == null); | ||
| 335 | comptime try expect(S.returnsOptErrSet() == null); | ||
| 336 | } | ||
| 337 | |||
| 338 | test "debug info for optional error set" { | ||
| 339 | const SomeError = error{Hello}; | ||
| 340 | var a_local_variable: ?SomeError = null; | ||
| 341 | } | ||
| 342 | |||
| 343 | test "nested catch" { | ||
| 344 | const S = struct { | ||
| 345 | fn entry() !void { | ||
| 346 | try expectError(error.Bad, func()); | ||
| 347 | } | ||
| 348 | fn fail() anyerror!Foo { | ||
| 349 | return error.Wrong; | ||
| 350 | } | ||
| 351 | fn func() anyerror!Foo { | ||
| 352 | const x = fail() catch | ||
| 353 | fail() catch | ||
| 354 | return error.Bad; | ||
| 355 | unreachable; | ||
| 356 | } | ||
| 357 | const Foo = struct { | ||
| 358 | field: i32, | ||
| 359 | }; | ||
| 360 | }; | ||
| 361 | try S.entry(); | ||
| 362 | comptime try S.entry(); | ||
| 363 | } | ||
| 364 | |||
| 365 | test "implicit cast to optional to error union to return result loc" { | ||
| 366 | const S = struct { | ||
| 367 | fn entry() !void { | ||
| 368 | var x: Foo = undefined; | ||
| 369 | if (func(&x)) |opt| { | ||
| 370 | try expect(opt != null); | ||
| 371 | } else |_| @panic("expected non error"); | ||
| 372 | } | ||
| 373 | fn func(f: *Foo) anyerror!?*Foo { | ||
| 374 | return f; | ||
| 375 | } | ||
| 376 | const Foo = struct { | ||
| 377 | field: i32, | ||
| 378 | }; | ||
| 379 | }; | ||
| 380 | try S.entry(); | ||
| 381 | //comptime S.entry(); TODO | ||
| 382 | } | ||
| 383 | |||
| 384 | test "function pointer with return type that is error union with payload which is pointer of parent struct" { | ||
| 385 | const S = struct { | ||
| 386 | const Foo = struct { | ||
| 387 | fun: fn (a: i32) (anyerror!*Foo), | ||
| 388 | }; | ||
| 389 | |||
| 390 | const Err = error{UnspecifiedErr}; | ||
| 391 | |||
| 392 | fn bar(a: i32) anyerror!*Foo { | ||
| 393 | return Err.UnspecifiedErr; | ||
| 394 | } | ||
| 395 | |||
| 396 | fn doTheTest() !void { | ||
| 397 | var x = Foo{ .fun = bar }; | ||
| 398 | try expectError(error.UnspecifiedErr, x.fun(1)); | ||
| 399 | } | ||
| 400 | }; | ||
| 401 | try S.doTheTest(); | ||
| 402 | } | ||
| 403 | |||
| 404 | test "return result loc as peer result loc in inferred error set function" { | ||
| 405 | const S = struct { | ||
| 406 | fn doTheTest() !void { | ||
| 407 | if (foo(2)) |x| { | ||
| 408 | try expect(x.Two); | ||
| 409 | } else |e| switch (e) { | ||
| 410 | error.Whatever => @panic("fail"), | ||
| 411 | } | ||
| 412 | try expectError(error.Whatever, foo(99)); | ||
| 413 | } | ||
| 414 | const FormValue = union(enum) { | ||
| 415 | One: void, | ||
| 416 | Two: bool, | ||
| 417 | }; | ||
| 418 | |||
| 419 | fn foo(id: u64) !FormValue { | ||
| 420 | return switch (id) { | ||
| 421 | 2 => FormValue{ .Two = true }, | ||
| 422 | 1 => FormValue{ .One = {} }, | ||
| 423 | else => return error.Whatever, | ||
| 424 | }; | ||
| 425 | } | ||
| 426 | }; | ||
| 427 | try S.doTheTest(); | ||
| 428 | comptime try S.doTheTest(); | ||
| 429 | } | ||
| 430 | |||
| 431 | test "error payload type is correctly resolved" { | ||
| 432 | const MyIntWrapper = struct { | ||
| 433 | const Self = @This(); | ||
| 434 | |||
| 435 | x: i32, | ||
| 436 | |||
| 437 | pub fn create() anyerror!Self { | ||
| 438 | return Self{ .x = 42 }; | ||
| 439 | } | ||
| 440 | }; | ||
| 441 | |||
| 442 | try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create()); | ||
| 443 | } | ||
| 444 | |||
| 445 | test "error union comptime caching" { | ||
| 446 | const S = struct { | ||
| 447 | fn foo(comptime arg: anytype) void {} | ||
| 448 | }; | ||
| 449 | |||
| 450 | S.foo(@as(anyerror!void, {})); | ||
| 451 | S.foo(@as(anyerror!void, {})); | ||
| 452 | } | ||
test/behavior/eval.zig created+832| ... | @@ -0,0 +1,832 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | |||
| 5 | test "compile time recursion" { | ||
| 6 | try expect(some_data.len == 21); | ||
| 7 | } | ||
| 8 | var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; | ||
| 9 | fn fibonacci(x: i32) i32 { | ||
| 10 | if (x <= 1) return 1; | ||
| 11 | return fibonacci(x - 1) + fibonacci(x - 2); | ||
| 12 | } | ||
| 13 | |||
| 14 | fn unwrapAndAddOne(blah: ?i32) i32 { | ||
| 15 | return blah.? + 1; | ||
| 16 | } | ||
| 17 | const should_be_1235 = unwrapAndAddOne(1234); | ||
| 18 | test "static add one" { | ||
| 19 | try expect(should_be_1235 == 1235); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "inlined loop" { | ||
| 23 | comptime var i = 0; | ||
| 24 | comptime var sum = 0; | ||
| 25 | inline while (i <= 5) : (i += 1) | ||
| 26 | sum += i; | ||
| 27 | try expect(sum == 15); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn gimme1or2(comptime a: bool) i32 { | ||
| 31 | const x: i32 = 1; | ||
| 32 | const y: i32 = 2; | ||
| 33 | comptime var z: i32 = if (a) x else y; | ||
| 34 | return z; | ||
| 35 | } | ||
| 36 | test "inline variable gets result of const if" { | ||
| 37 | try expect(gimme1or2(true) == 1); | ||
| 38 | try expect(gimme1or2(false) == 2); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "static function evaluation" { | ||
| 42 | try expect(statically_added_number == 3); | ||
| 43 | } | ||
| 44 | const statically_added_number = staticAdd(1, 2); | ||
| 45 | fn staticAdd(a: i32, b: i32) i32 { | ||
| 46 | return a + b; | ||
| 47 | } | ||
| 48 | |||
| 49 | test "const expr eval on single expr blocks" { | ||
| 50 | try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 51 | comptime try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 52 | } | ||
| 53 | |||
| 54 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { | ||
| 55 | const literal = 3; | ||
| 56 | |||
| 57 | const result = if (b) b: { | ||
| 58 | break :b literal; | ||
| 59 | } else b: { | ||
| 60 | break :b x; | ||
| 61 | }; | ||
| 62 | |||
| 63 | return result; | ||
| 64 | } | ||
| 65 | |||
| 66 | test "statically initialized list" { | ||
| 67 | try expect(static_point_list[0].x == 1); | ||
| 68 | try expect(static_point_list[0].y == 2); | ||
| 69 | try expect(static_point_list[1].x == 3); | ||
| 70 | try expect(static_point_list[1].y == 4); | ||
| 71 | } | ||
| 72 | const Point = struct { | ||
| 73 | x: i32, | ||
| 74 | y: i32, | ||
| 75 | }; | ||
| 76 | const static_point_list = [_]Point{ | ||
| 77 | makePoint(1, 2), | ||
| 78 | makePoint(3, 4), | ||
| 79 | }; | ||
| 80 | fn makePoint(x: i32, y: i32) Point { | ||
| 81 | return Point{ | ||
| 82 | .x = x, | ||
| 83 | .y = y, | ||
| 84 | }; | ||
| 85 | } | ||
| 86 | |||
| 87 | test "static eval list init" { | ||
| 88 | try expect(static_vec3.data[2] == 1.0); | ||
| 89 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | ||
| 90 | } | ||
| 91 | const static_vec3 = vec3(0.0, 0.0, 1.0); | ||
| 92 | pub const Vec3 = struct { | ||
| 93 | data: [3]f32, | ||
| 94 | }; | ||
| 95 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | ||
| 96 | return Vec3{ | ||
| 97 | .data = [_]f32{ | ||
| 98 | x, | ||
| 99 | y, | ||
| 100 | z, | ||
| 101 | }, | ||
| 102 | }; | ||
| 103 | } | ||
| 104 | |||
| 105 | test "constant expressions" { | ||
| 106 | var array: [array_size]u8 = undefined; | ||
| 107 | try expect(@sizeOf(@TypeOf(array)) == 20); | ||
| 108 | } | ||
| 109 | const array_size: u8 = 20; | ||
| 110 | |||
| 111 | test "constant struct with negation" { | ||
| 112 | try expect(vertices[0].x == -0.6); | ||
| 113 | } | ||
| 114 | const Vertex = struct { | ||
| 115 | x: f32, | ||
| 116 | y: f32, | ||
| 117 | r: f32, | ||
| 118 | g: f32, | ||
| 119 | b: f32, | ||
| 120 | }; | ||
| 121 | const vertices = [_]Vertex{ | ||
| 122 | Vertex{ | ||
| 123 | .x = -0.6, | ||
| 124 | .y = -0.4, | ||
| 125 | .r = 1.0, | ||
| 126 | .g = 0.0, | ||
| 127 | .b = 0.0, | ||
| 128 | }, | ||
| 129 | Vertex{ | ||
| 130 | .x = 0.6, | ||
| 131 | .y = -0.4, | ||
| 132 | .r = 0.0, | ||
| 133 | .g = 1.0, | ||
| 134 | .b = 0.0, | ||
| 135 | }, | ||
| 136 | Vertex{ | ||
| 137 | .x = 0.0, | ||
| 138 | .y = 0.6, | ||
| 139 | .r = 0.0, | ||
| 140 | .g = 0.0, | ||
| 141 | .b = 1.0, | ||
| 142 | }, | ||
| 143 | }; | ||
| 144 | |||
| 145 | test "statically initialized struct" { | ||
| 146 | st_init_str_foo.x += 1; | ||
| 147 | try expect(st_init_str_foo.x == 14); | ||
| 148 | } | ||
| 149 | const StInitStrFoo = struct { | ||
| 150 | x: i32, | ||
| 151 | y: bool, | ||
| 152 | }; | ||
| 153 | var st_init_str_foo = StInitStrFoo{ | ||
| 154 | .x = 13, | ||
| 155 | .y = true, | ||
| 156 | }; | ||
| 157 | |||
| 158 | test "statically initalized array literal" { | ||
| 159 | const y: [4]u8 = st_init_arr_lit_x; | ||
| 160 | try expect(y[3] == 4); | ||
| 161 | } | ||
| 162 | const st_init_arr_lit_x = [_]u8{ | ||
| 163 | 1, | ||
| 164 | 2, | ||
| 165 | 3, | ||
| 166 | 4, | ||
| 167 | }; | ||
| 168 | |||
| 169 | test "const slice" { | ||
| 170 | comptime { | ||
| 171 | const a = "1234567890"; | ||
| 172 | try expect(a.len == 10); | ||
| 173 | const b = a[1..2]; | ||
| 174 | try expect(b.len == 1); | ||
| 175 | try expect(b[0] == '2'); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | test "try to trick eval with runtime if" { | ||
| 180 | try expect(testTryToTrickEvalWithRuntimeIf(true) == 10); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | ||
| 184 | comptime var i: usize = 0; | ||
| 185 | inline while (i < 10) : (i += 1) { | ||
| 186 | const result = if (b) false else true; | ||
| 187 | } | ||
| 188 | comptime { | ||
| 189 | return i; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { | ||
| 194 | var runtime = [1]i32{3}; | ||
| 195 | comptime var i: usize = 0; | ||
| 196 | inline while (i < 2) : (i += 1) { | ||
| 197 | const result = if (i == 0) [1]i32{2} else runtime; | ||
| 198 | } | ||
| 199 | comptime { | ||
| 200 | try expect(i == 2); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | fn max(comptime T: type, a: T, b: T) T { | ||
| 205 | if (T == bool) { | ||
| 206 | return a or b; | ||
| 207 | } else if (a > b) { | ||
| 208 | return a; | ||
| 209 | } else { | ||
| 210 | return b; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | fn letsTryToCompareBools(a: bool, b: bool) bool { | ||
| 214 | return max(bool, a, b); | ||
| 215 | } | ||
| 216 | test "inlined block and runtime block phi" { | ||
| 217 | try expect(letsTryToCompareBools(true, true)); | ||
| 218 | try expect(letsTryToCompareBools(true, false)); | ||
| 219 | try expect(letsTryToCompareBools(false, true)); | ||
| 220 | try expect(!letsTryToCompareBools(false, false)); | ||
| 221 | |||
| 222 | comptime { | ||
| 223 | try expect(letsTryToCompareBools(true, true)); | ||
| 224 | try expect(letsTryToCompareBools(true, false)); | ||
| 225 | try expect(letsTryToCompareBools(false, true)); | ||
| 226 | try expect(!letsTryToCompareBools(false, false)); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | const CmdFn = struct { | ||
| 231 | name: []const u8, | ||
| 232 | func: fn (i32) i32, | ||
| 233 | }; | ||
| 234 | |||
| 235 | const cmd_fns = [_]CmdFn{ | ||
| 236 | CmdFn{ | ||
| 237 | .name = "one", | ||
| 238 | .func = one, | ||
| 239 | }, | ||
| 240 | CmdFn{ | ||
| 241 | .name = "two", | ||
| 242 | .func = two, | ||
| 243 | }, | ||
| 244 | CmdFn{ | ||
| 245 | .name = "three", | ||
| 246 | .func = three, | ||
| 247 | }, | ||
| 248 | }; | ||
| 249 | fn one(value: i32) i32 { | ||
| 250 | return value + 1; | ||
| 251 | } | ||
| 252 | fn two(value: i32) i32 { | ||
| 253 | return value + 2; | ||
| 254 | } | ||
| 255 | fn three(value: i32) i32 { | ||
| 256 | return value + 3; | ||
| 257 | } | ||
| 258 | |||
| 259 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | ||
| 260 | var result: i32 = start_value; | ||
| 261 | comptime var i = 0; | ||
| 262 | inline while (i < cmd_fns.len) : (i += 1) { | ||
| 263 | if (cmd_fns[i].name[0] == prefix_char) { | ||
| 264 | result = cmd_fns[i].func(result); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | return result; | ||
| 268 | } | ||
| 269 | |||
| 270 | test "comptime iterate over fn ptr list" { | ||
| 271 | try expect(performFn('t', 1) == 6); | ||
| 272 | try expect(performFn('o', 0) == 1); | ||
| 273 | try expect(performFn('w', 99) == 99); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "eval @setRuntimeSafety at compile-time" { | ||
| 277 | const result = comptime fnWithSetRuntimeSafety(); | ||
| 278 | try expect(result == 1234); | ||
| 279 | } | ||
| 280 | |||
| 281 | fn fnWithSetRuntimeSafety() i32 { | ||
| 282 | @setRuntimeSafety(true); | ||
| 283 | return 1234; | ||
| 284 | } | ||
| 285 | |||
| 286 | test "eval @setFloatMode at compile-time" { | ||
| 287 | const result = comptime fnWithFloatMode(); | ||
| 288 | try expect(result == 1234.0); | ||
| 289 | } | ||
| 290 | |||
| 291 | fn fnWithFloatMode() f32 { | ||
| 292 | @setFloatMode(std.builtin.FloatMode.Strict); | ||
| 293 | return 1234.0; | ||
| 294 | } | ||
| 295 | |||
| 296 | const SimpleStruct = struct { | ||
| 297 | field: i32, | ||
| 298 | |||
| 299 | fn method(self: *const SimpleStruct) i32 { | ||
| 300 | return self.field + 3; | ||
| 301 | } | ||
| 302 | }; | ||
| 303 | |||
| 304 | var simple_struct = SimpleStruct{ .field = 1234 }; | ||
| 305 | |||
| 306 | const bound_fn = simple_struct.method; | ||
| 307 | |||
| 308 | test "call method on bound fn referring to var instance" { | ||
| 309 | try expect(bound_fn() == 1237); | ||
| 310 | } | ||
| 311 | |||
| 312 | test "ptr to local array argument at comptime" { | ||
| 313 | comptime { | ||
| 314 | var bytes: [10]u8 = undefined; | ||
| 315 | modifySomeBytes(bytes[0..]); | ||
| 316 | try expect(bytes[0] == 'a'); | ||
| 317 | try expect(bytes[9] == 'b'); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | fn modifySomeBytes(bytes: []u8) void { | ||
| 322 | bytes[0] = 'a'; | ||
| 323 | bytes[9] = 'b'; | ||
| 324 | } | ||
| 325 | |||
| 326 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | ||
| 327 | testCompTimeUIntComparisons(1234); | ||
| 328 | } | ||
| 329 | fn testCompTimeUIntComparisons(x: u32) void { | ||
| 330 | if (!(0 <= x)) { | ||
| 331 | @compileError("this condition should be comptime known"); | ||
| 332 | } | ||
| 333 | if (0 > x) { | ||
| 334 | @compileError("this condition should be comptime known"); | ||
| 335 | } | ||
| 336 | if (!(x >= 0)) { | ||
| 337 | @compileError("this condition should be comptime known"); | ||
| 338 | } | ||
| 339 | if (x < 0) { | ||
| 340 | @compileError("this condition should be comptime known"); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | test "const ptr to variable data changes at runtime" { | ||
| 345 | try expect(foo_ref.name[0] == 'a'); | ||
| 346 | foo_ref.name = "b"; | ||
| 347 | try expect(foo_ref.name[0] == 'b'); | ||
| 348 | } | ||
| 349 | |||
| 350 | const Foo = struct { | ||
| 351 | name: []const u8, | ||
| 352 | }; | ||
| 353 | |||
| 354 | var foo_contents = Foo{ .name = "a" }; | ||
| 355 | const foo_ref = &foo_contents; | ||
| 356 | |||
| 357 | test "create global array with for loop" { | ||
| 358 | try expect(global_array[5] == 5 * 5); | ||
| 359 | try expect(global_array[9] == 9 * 9); | ||
| 360 | } | ||
| 361 | |||
| 362 | const global_array = x: { | ||
| 363 | var result: [10]usize = undefined; | ||
| 364 | for (result) |*item, index| { | ||
| 365 | item.* = index * index; | ||
| 366 | } | ||
| 367 | break :x result; | ||
| 368 | }; | ||
| 369 | |||
| 370 | test "compile-time downcast when the bits fit" { | ||
| 371 | comptime { | ||
| 372 | const spartan_count: u16 = 255; | ||
| 373 | const byte = @intCast(u8, spartan_count); | ||
| 374 | try expect(byte == 255); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | const hi1 = "hi"; | ||
| 379 | const hi2 = hi1; | ||
| 380 | test "const global shares pointer with other same one" { | ||
| 381 | try assertEqualPtrs(&hi1[0], &hi2[0]); | ||
| 382 | comptime try expect(&hi1[0] == &hi2[0]); | ||
| 383 | } | ||
| 384 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { | ||
| 385 | try expect(ptr1 == ptr2); | ||
| 386 | } | ||
| 387 | |||
| 388 | test "@setEvalBranchQuota" { | ||
| 389 | comptime { | ||
| 390 | // 1001 for the loop and then 1 more for the expect fn call | ||
| 391 | @setEvalBranchQuota(1002); | ||
| 392 | var i = 0; | ||
| 393 | var sum = 0; | ||
| 394 | while (i < 1001) : (i += 1) { | ||
| 395 | sum += i; | ||
| 396 | } | ||
| 397 | try expect(sum == 500500); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | test "float literal at compile time not lossy" { | ||
| 402 | try expect(16777216.0 + 1.0 == 16777217.0); | ||
| 403 | try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); | ||
| 404 | } | ||
| 405 | |||
| 406 | test "f32 at compile time is lossy" { | ||
| 407 | try expect(@as(f32, 1 << 24) + 1 == 1 << 24); | ||
| 408 | } | ||
| 409 | |||
| 410 | test "f64 at compile time is lossy" { | ||
| 411 | try expect(@as(f64, 1 << 53) + 1 == 1 << 53); | ||
| 412 | } | ||
| 413 | |||
| 414 | test "f128 at compile time is lossy" { | ||
| 415 | try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | ||
| 416 | } | ||
| 417 | |||
| 418 | comptime { | ||
| 419 | try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192); | ||
| 420 | } | ||
| 421 | |||
| 422 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | ||
| 423 | return struct { | ||
| 424 | pub const Node = struct {}; | ||
| 425 | }; | ||
| 426 | } | ||
| 427 | |||
| 428 | test "string literal used as comptime slice is memoized" { | ||
| 429 | const a = "link"; | ||
| 430 | const b = "link"; | ||
| 431 | comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | ||
| 432 | comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | ||
| 433 | } | ||
| 434 | |||
| 435 | test "comptime slice of undefined pointer of length 0" { | ||
| 436 | const slice1 = @as([*]i32, undefined)[0..0]; | ||
| 437 | try expect(slice1.len == 0); | ||
| 438 | const slice2 = @as([*]i32, undefined)[100..100]; | ||
| 439 | try expect(slice2.len == 0); | ||
| 440 | } | ||
| 441 | |||
| 442 | fn copyWithPartialInline(s: []u32, b: []u8) void { | ||
| 443 | comptime var i: usize = 0; | ||
| 444 | inline while (i < 4) : (i += 1) { | ||
| 445 | s[i] = 0; | ||
| 446 | s[i] |= @as(u32, b[i * 4 + 0]) << 24; | ||
| 447 | s[i] |= @as(u32, b[i * 4 + 1]) << 16; | ||
| 448 | s[i] |= @as(u32, b[i * 4 + 2]) << 8; | ||
| 449 | s[i] |= @as(u32, b[i * 4 + 3]) << 0; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | test "binary math operator in partially inlined function" { | ||
| 454 | var s: [4]u32 = undefined; | ||
| 455 | var b: [16]u8 = undefined; | ||
| 456 | |||
| 457 | for (b) |*r, i| | ||
| 458 | r.* = @intCast(u8, i + 1); | ||
| 459 | |||
| 460 | copyWithPartialInline(s[0..], b[0..]); | ||
| 461 | try expect(s[0] == 0x1020304); | ||
| 462 | try expect(s[1] == 0x5060708); | ||
| 463 | try expect(s[2] == 0x90a0b0c); | ||
| 464 | try expect(s[3] == 0xd0e0f10); | ||
| 465 | } | ||
| 466 | |||
| 467 | test "comptime function with the same args is memoized" { | ||
| 468 | comptime { | ||
| 469 | try expect(MakeType(i32) == MakeType(i32)); | ||
| 470 | try expect(MakeType(i32) != MakeType(f64)); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | fn MakeType(comptime T: type) type { | ||
| 475 | return struct { | ||
| 476 | field: T, | ||
| 477 | }; | ||
| 478 | } | ||
| 479 | |||
| 480 | test "comptime function with mutable pointer is not memoized" { | ||
| 481 | comptime { | ||
| 482 | var x: i32 = 1; | ||
| 483 | const ptr = &x; | ||
| 484 | increment(ptr); | ||
| 485 | increment(ptr); | ||
| 486 | try expect(x == 3); | ||
| 487 | } | ||
| 488 | } | ||
| 489 | |||
| 490 | fn increment(value: *i32) void { | ||
| 491 | value.* += 1; | ||
| 492 | } | ||
| 493 | |||
| 494 | fn generateTable(comptime T: type) [1010]T { | ||
| 495 | var res: [1010]T = undefined; | ||
| 496 | var i: usize = 0; | ||
| 497 | while (i < 1010) : (i += 1) { | ||
| 498 | res[i] = @intCast(T, i); | ||
| 499 | } | ||
| 500 | return res; | ||
| 501 | } | ||
| 502 | |||
| 503 | fn doesAlotT(comptime T: type, value: usize) T { | ||
| 504 | @setEvalBranchQuota(5000); | ||
| 505 | const table = comptime blk: { | ||
| 506 | break :blk generateTable(T); | ||
| 507 | }; | ||
| 508 | return table[value]; | ||
| 509 | } | ||
| 510 | |||
| 511 | test "@setEvalBranchQuota at same scope as generic function call" { | ||
| 512 | try expect(doesAlotT(u32, 2) == 2); | ||
| 513 | } | ||
| 514 | |||
| 515 | test "comptime slice of slice preserves comptime var" { | ||
| 516 | comptime { | ||
| 517 | var buff: [10]u8 = undefined; | ||
| 518 | buff[0..][0..][0] = 1; | ||
| 519 | try expect(buff[0..][0..][0] == 1); | ||
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | test "comptime slice of pointer preserves comptime var" { | ||
| 524 | comptime { | ||
| 525 | var buff: [10]u8 = undefined; | ||
| 526 | var a = @ptrCast([*]u8, &buff); | ||
| 527 | a[0..1][0] = 1; | ||
| 528 | try expect(buff[0..][0..][0] == 1); | ||
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | const SingleFieldStruct = struct { | ||
| 533 | x: i32, | ||
| 534 | |||
| 535 | fn read_x(self: *const SingleFieldStruct) i32 { | ||
| 536 | return self.x; | ||
| 537 | } | ||
| 538 | }; | ||
| 539 | test "const ptr to comptime mutable data is not memoized" { | ||
| 540 | comptime { | ||
| 541 | var foo = SingleFieldStruct{ .x = 1 }; | ||
| 542 | try expect(foo.read_x() == 1); | ||
| 543 | foo.x = 2; | ||
| 544 | try expect(foo.read_x() == 2); | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | test "array concat of slices gives slice" { | ||
| 549 | comptime { | ||
| 550 | var a: []const u8 = "aoeu"; | ||
| 551 | var b: []const u8 = "asdf"; | ||
| 552 | const c = a ++ b; | ||
| 553 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | test "comptime shlWithOverflow" { | ||
| 558 | const ct_shifted: u64 = comptime amt: { | ||
| 559 | var amt = @as(u64, 0); | ||
| 560 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | ||
| 561 | break :amt amt; | ||
| 562 | }; | ||
| 563 | |||
| 564 | const rt_shifted: u64 = amt: { | ||
| 565 | var amt = @as(u64, 0); | ||
| 566 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | ||
| 567 | break :amt amt; | ||
| 568 | }; | ||
| 569 | |||
| 570 | try expect(ct_shifted == rt_shifted); | ||
| 571 | } | ||
| 572 | |||
| 573 | test "runtime 128 bit integer division" { | ||
| 574 | var a: u128 = 152313999999999991610955792383; | ||
| 575 | var b: u128 = 10000000000000000000; | ||
| 576 | var c = a / b; | ||
| 577 | try expect(c == 15231399999); | ||
| 578 | } | ||
| 579 | |||
| 580 | pub const Info = struct { | ||
| 581 | version: u8, | ||
| 582 | }; | ||
| 583 | |||
| 584 | pub const diamond_info = Info{ .version = 0 }; | ||
| 585 | |||
| 586 | test "comptime modification of const struct field" { | ||
| 587 | comptime { | ||
| 588 | var res = diamond_info; | ||
| 589 | res.version = 1; | ||
| 590 | try expect(diamond_info.version == 0); | ||
| 591 | try expect(res.version == 1); | ||
| 592 | } | ||
| 593 | } | ||
| 594 | |||
| 595 | test "pointer to type" { | ||
| 596 | comptime { | ||
| 597 | var T: type = i32; | ||
| 598 | try expect(T == i32); | ||
| 599 | var ptr = &T; | ||
| 600 | try expect(@TypeOf(ptr) == *type); | ||
| 601 | ptr.* = f32; | ||
| 602 | try expect(T == f32); | ||
| 603 | try expect(*T == *f32); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | test "slice of type" { | ||
| 608 | comptime { | ||
| 609 | var types_array = [_]type{ i32, f64, type }; | ||
| 610 | for (types_array) |T, i| { | ||
| 611 | switch (i) { | ||
| 612 | 0 => try expect(T == i32), | ||
| 613 | 1 => try expect(T == f64), | ||
| 614 | 2 => try expect(T == type), | ||
| 615 | else => unreachable, | ||
| 616 | } | ||
| 617 | } | ||
| 618 | for (types_array[0..]) |T, i| { | ||
| 619 | switch (i) { | ||
| 620 | 0 => try expect(T == i32), | ||
| 621 | 1 => try expect(T == f64), | ||
| 622 | 2 => try expect(T == type), | ||
| 623 | else => unreachable, | ||
| 624 | } | ||
| 625 | } | ||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | const Wrapper = struct { | ||
| 630 | T: type, | ||
| 631 | }; | ||
| 632 | |||
| 633 | fn wrap(comptime T: type) Wrapper { | ||
| 634 | return Wrapper{ .T = T }; | ||
| 635 | } | ||
| 636 | |||
| 637 | test "function which returns struct with type field causes implicit comptime" { | ||
| 638 | const ty = wrap(i32).T; | ||
| 639 | try expect(ty == i32); | ||
| 640 | } | ||
| 641 | |||
| 642 | test "call method with comptime pass-by-non-copying-value self parameter" { | ||
| 643 | const S = struct { | ||
| 644 | a: u8, | ||
| 645 | |||
| 646 | fn b(comptime s: @This()) u8 { | ||
| 647 | return s.a; | ||
| 648 | } | ||
| 649 | }; | ||
| 650 | |||
| 651 | const s = S{ .a = 2 }; | ||
| 652 | var b = s.b(); | ||
| 653 | try expect(b == 2); | ||
| 654 | } | ||
| 655 | |||
| 656 | test "@tagName of @typeInfo" { | ||
| 657 | const str = @tagName(@typeInfo(u8)); | ||
| 658 | try expect(std.mem.eql(u8, str, "Int")); | ||
| 659 | } | ||
| 660 | |||
| 661 | test "setting backward branch quota just before a generic fn call" { | ||
| 662 | @setEvalBranchQuota(1001); | ||
| 663 | loopNTimes(1001); | ||
| 664 | } | ||
| 665 | |||
| 666 | fn loopNTimes(comptime n: usize) void { | ||
| 667 | comptime var i = 0; | ||
| 668 | inline while (i < n) : (i += 1) {} | ||
| 669 | } | ||
| 670 | |||
| 671 | test "variable inside inline loop that has different types on different iterations" { | ||
| 672 | try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); | ||
| 673 | } | ||
| 674 | |||
| 675 | fn testVarInsideInlineLoop(args: anytype) !void { | ||
| 676 | comptime var i = 0; | ||
| 677 | inline while (i < args.len) : (i += 1) { | ||
| 678 | const x = args[i]; | ||
| 679 | if (i == 0) try expect(x); | ||
| 680 | if (i == 1) try expect(x == 42); | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | test "inline for with same type but different values" { | ||
| 685 | var res: usize = 0; | ||
| 686 | inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| { | ||
| 687 | var a: T = undefined; | ||
| 688 | res += a.len; | ||
| 689 | } | ||
| 690 | try expect(res == 5); | ||
| 691 | } | ||
| 692 | |||
| 693 | test "refer to the type of a generic function" { | ||
| 694 | const Func = fn (type) void; | ||
| 695 | const f: Func = doNothingWithType; | ||
| 696 | f(i32); | ||
| 697 | } | ||
| 698 | |||
| 699 | fn doNothingWithType(comptime T: type) void {} | ||
| 700 | |||
| 701 | test "zero extend from u0 to u1" { | ||
| 702 | var zero_u0: u0 = 0; | ||
| 703 | var zero_u1: u1 = zero_u0; | ||
| 704 | try expect(zero_u1 == 0); | ||
| 705 | } | ||
| 706 | |||
| 707 | test "bit shift a u1" { | ||
| 708 | var x: u1 = 1; | ||
| 709 | var y = x << 0; | ||
| 710 | try expect(y == 1); | ||
| 711 | } | ||
| 712 | |||
| 713 | test "comptime pointer cast array and then slice" { | ||
| 714 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | ||
| 715 | |||
| 716 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | ||
| 717 | const sliceA: []const u8 = ptrA[0..2]; | ||
| 718 | |||
| 719 | const ptrB: [*]const u8 = &array; | ||
| 720 | const sliceB: []const u8 = ptrB[0..2]; | ||
| 721 | |||
| 722 | try expect(sliceA[1] == 2); | ||
| 723 | try expect(sliceB[1] == 2); | ||
| 724 | } | ||
| 725 | |||
| 726 | test "slice bounds in comptime concatenation" { | ||
| 727 | const bs = comptime blk: { | ||
| 728 | const b = "........1........"; | ||
| 729 | break :blk b[8..9]; | ||
| 730 | }; | ||
| 731 | const str = "" ++ bs; | ||
| 732 | try expect(str.len == 1); | ||
| 733 | try expect(std.mem.eql(u8, str, "1")); | ||
| 734 | |||
| 735 | const str2 = bs ++ ""; | ||
| 736 | try expect(str2.len == 1); | ||
| 737 | try expect(std.mem.eql(u8, str2, "1")); | ||
| 738 | } | ||
| 739 | |||
| 740 | test "comptime bitwise operators" { | ||
| 741 | comptime { | ||
| 742 | try expect(3 & 1 == 1); | ||
| 743 | try expect(3 & -1 == 3); | ||
| 744 | try expect(-3 & -1 == -3); | ||
| 745 | try expect(3 | -1 == -1); | ||
| 746 | try expect(-3 | -1 == -1); | ||
| 747 | try expect(3 ^ -1 == -4); | ||
| 748 | try expect(-3 ^ -1 == 2); | ||
| 749 | try expect(~@as(i8, -1) == 0); | ||
| 750 | try expect(~@as(i128, -1) == 0); | ||
| 751 | try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | ||
| 752 | try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | ||
| 753 | try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | ||
| 758 | comptime { | ||
| 759 | try expect(*align(1:0:2) u16 == *align(1) u16); | ||
| 760 | try expect(*align(2:0:2) u16 == *u16); | ||
| 761 | } | ||
| 762 | } | ||
| 763 | |||
| 764 | test "array concatenation forces comptime" { | ||
| 765 | var a = oneItem(3) ++ oneItem(4); | ||
| 766 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); | ||
| 767 | } | ||
| 768 | |||
| 769 | test "array multiplication forces comptime" { | ||
| 770 | var a = oneItem(3) ** scalar(2); | ||
| 771 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); | ||
| 772 | } | ||
| 773 | |||
| 774 | fn oneItem(x: i32) [1]i32 { | ||
| 775 | return [_]i32{x}; | ||
| 776 | } | ||
| 777 | |||
| 778 | fn scalar(x: u32) u32 { | ||
| 779 | return x; | ||
| 780 | } | ||
| 781 | |||
| 782 | test "no undeclared identifier error in unanalyzed branches" { | ||
| 783 | if (false) { | ||
| 784 | lol_this_doesnt_exist = nonsense; | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | test "comptime assign int to optional int" { | ||
| 789 | comptime { | ||
| 790 | var x: ?i32 = null; | ||
| 791 | x = 2; | ||
| 792 | x.? *= 10; | ||
| 793 | try expectEqual(20, x.?); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | test "return 0 from function that has u0 return type" { | ||
| 798 | const S = struct { | ||
| 799 | fn foo_zero() u0 { | ||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | }; | ||
| 803 | comptime { | ||
| 804 | if (S.foo_zero() != 0) { | ||
| 805 | @compileError("test failed"); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | } | ||
| 809 | |||
| 810 | test "two comptime calls with array default initialized to undefined" { | ||
| 811 | const S = struct { | ||
| 812 | const CrossTarget = struct { | ||
| 813 | dynamic_linker: DynamicLinker = DynamicLinker{}, | ||
| 814 | |||
| 815 | pub fn parse() void { | ||
| 816 | var result: CrossTarget = .{}; | ||
| 817 | result.getCpuArch(); | ||
| 818 | } | ||
| 819 | |||
| 820 | pub fn getCpuArch(self: CrossTarget) void {} | ||
| 821 | }; | ||
| 822 | |||
| 823 | const DynamicLinker = struct { | ||
| 824 | buffer: [255]u8 = undefined, | ||
| 825 | }; | ||
| 826 | }; | ||
| 827 | |||
| 828 | comptime { | ||
| 829 | S.CrossTarget.parse(); | ||
| 830 | S.CrossTarget.parse(); | ||
| 831 | } | ||
| 832 | } | ||
test/behavior/field_parent_ptr.zig created+41| ... | @@ -0,0 +1,41 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@fieldParentPtr non-first field" { | ||
| 4 | try testParentFieldPtr(&foo.c); | ||
| 5 | comptime try testParentFieldPtr(&foo.c); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "@fieldParentPtr first field" { | ||
| 9 | try testParentFieldPtrFirst(&foo.a); | ||
| 10 | comptime try testParentFieldPtrFirst(&foo.a); | ||
| 11 | } | ||
| 12 | |||
| 13 | const Foo = struct { | ||
| 14 | a: bool, | ||
| 15 | b: f32, | ||
| 16 | c: i32, | ||
| 17 | d: i32, | ||
| 18 | }; | ||
| 19 | |||
| 20 | const foo = Foo{ | ||
| 21 | .a = true, | ||
| 22 | .b = 0.123, | ||
| 23 | .c = 1234, | ||
| 24 | .d = -10, | ||
| 25 | }; | ||
| 26 | |||
| 27 | fn testParentFieldPtr(c: *const i32) !void { | ||
| 28 | try expect(c == &foo.c); | ||
| 29 | |||
| 30 | const base = @fieldParentPtr(Foo, "c", c); | ||
| 31 | try expect(base == &foo); | ||
| 32 | try expect(&base.c == c); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn testParentFieldPtrFirst(a: *const bool) !void { | ||
| 36 | try expect(a == &foo.a); | ||
| 37 | |||
| 38 | const base = @fieldParentPtr(Foo, "a", a); | ||
| 39 | try expect(base == &foo); | ||
| 40 | try expect(&base.a == a); | ||
| 41 | } | ||
test/behavior/floatop.zig created+465| ... | @@ -0,0 +1,465 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const math = std.math; | ||
| 4 | const pi = std.math.pi; | ||
| 5 | const e = std.math.e; | ||
| 6 | const Vector = std.meta.Vector; | ||
| 7 | |||
| 8 | const epsilon = 0.000001; | ||
| 9 | |||
| 10 | test "@sqrt" { | ||
| 11 | comptime try testSqrt(); | ||
| 12 | try testSqrt(); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn testSqrt() !void { | ||
| 16 | { | ||
| 17 | var a: f16 = 4; | ||
| 18 | try expect(@sqrt(a) == 2); | ||
| 19 | } | ||
| 20 | { | ||
| 21 | var a: f32 = 9; | ||
| 22 | try expect(@sqrt(a) == 3); | ||
| 23 | var b: f32 = 1.1; | ||
| 24 | try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon)); | ||
| 25 | } | ||
| 26 | { | ||
| 27 | var a: f64 = 25; | ||
| 28 | try expect(@sqrt(a) == 5); | ||
| 29 | } | ||
| 30 | { | ||
| 31 | const a: comptime_float = 25.0; | ||
| 32 | try expect(@sqrt(a) == 5.0); | ||
| 33 | } | ||
| 34 | // TODO https://github.com/ziglang/zig/issues/4026 | ||
| 35 | //{ | ||
| 36 | // var a: f128 = 49; | ||
| 37 | //try expect(@sqrt(a) == 7); | ||
| 38 | //} | ||
| 39 | { | ||
| 40 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 41 | var result = @sqrt(v); | ||
| 42 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon)); | ||
| 43 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon)); | ||
| 44 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon)); | ||
| 45 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon)); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | test "more @sqrt f16 tests" { | ||
| 50 | // TODO these are not all passing at comptime | ||
| 51 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 52 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon)); | ||
| 53 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon)); | ||
| 54 | try expect(@sqrt(@as(f16, 4.0)) == 2.0); | ||
| 55 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon)); | ||
| 56 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon)); | ||
| 57 | try expect(@sqrt(@as(f16, 64.0)) == 8.0); | ||
| 58 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon)); | ||
| 59 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon)); | ||
| 60 | |||
| 61 | // special cases | ||
| 62 | try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16))))); | ||
| 63 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 64 | try expect(@sqrt(@as(f16, -0.0)) == -0.0); | ||
| 65 | try expect(math.isNan(@sqrt(@as(f16, -1.0)))); | ||
| 66 | try expect(math.isNan(@sqrt(@as(f16, math.nan(f16))))); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "@sin" { | ||
| 70 | comptime try testSin(); | ||
| 71 | try testSin(); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn testSin() !void { | ||
| 75 | // TODO test f128, and c_longdouble | ||
| 76 | // https://github.com/ziglang/zig/issues/4026 | ||
| 77 | { | ||
| 78 | var a: f16 = 0; | ||
| 79 | try expect(@sin(a) == 0); | ||
| 80 | } | ||
| 81 | { | ||
| 82 | var a: f32 = 0; | ||
| 83 | try expect(@sin(a) == 0); | ||
| 84 | } | ||
| 85 | { | ||
| 86 | var a: f64 = 0; | ||
| 87 | try expect(@sin(a) == 0); | ||
| 88 | } | ||
| 89 | { | ||
| 90 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 91 | var result = @sin(v); | ||
| 92 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon)); | ||
| 93 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon)); | ||
| 94 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon)); | ||
| 95 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon)); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | test "@cos" { | ||
| 100 | comptime try testCos(); | ||
| 101 | try testCos(); | ||
| 102 | } | ||
| 103 | |||
| 104 | fn testCos() !void { | ||
| 105 | // TODO test f128, and c_longdouble | ||
| 106 | // https://github.com/ziglang/zig/issues/4026 | ||
| 107 | { | ||
| 108 | var a: f16 = 0; | ||
| 109 | try expect(@cos(a) == 1); | ||
| 110 | } | ||
| 111 | { | ||
| 112 | var a: f32 = 0; | ||
| 113 | try expect(@cos(a) == 1); | ||
| 114 | } | ||
| 115 | { | ||
| 116 | var a: f64 = 0; | ||
| 117 | try expect(@cos(a) == 1); | ||
| 118 | } | ||
| 119 | { | ||
| 120 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 121 | var result = @cos(v); | ||
| 122 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon)); | ||
| 123 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon)); | ||
| 124 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon)); | ||
| 125 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon)); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | test "@exp" { | ||
| 130 | comptime try testExp(); | ||
| 131 | try testExp(); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn testExp() !void { | ||
| 135 | // TODO test f128, and c_longdouble | ||
| 136 | // https://github.com/ziglang/zig/issues/4026 | ||
| 137 | { | ||
| 138 | var a: f16 = 0; | ||
| 139 | try expect(@exp(a) == 1); | ||
| 140 | } | ||
| 141 | { | ||
| 142 | var a: f32 = 0; | ||
| 143 | try expect(@exp(a) == 1); | ||
| 144 | } | ||
| 145 | { | ||
| 146 | var a: f64 = 0; | ||
| 147 | try expect(@exp(a) == 1); | ||
| 148 | } | ||
| 149 | { | ||
| 150 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 151 | var result = @exp(v); | ||
| 152 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon)); | ||
| 153 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon)); | ||
| 154 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon)); | ||
| 155 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon)); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | test "@exp2" { | ||
| 160 | comptime try testExp2(); | ||
| 161 | try testExp2(); | ||
| 162 | } | ||
| 163 | |||
| 164 | fn testExp2() !void { | ||
| 165 | // TODO test f128, and c_longdouble | ||
| 166 | // https://github.com/ziglang/zig/issues/4026 | ||
| 167 | { | ||
| 168 | var a: f16 = 2; | ||
| 169 | try expect(@exp2(a) == 4); | ||
| 170 | } | ||
| 171 | { | ||
| 172 | var a: f32 = 2; | ||
| 173 | try expect(@exp2(a) == 4); | ||
| 174 | } | ||
| 175 | { | ||
| 176 | var a: f64 = 2; | ||
| 177 | try expect(@exp2(a) == 4); | ||
| 178 | } | ||
| 179 | { | ||
| 180 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 181 | var result = @exp2(v); | ||
| 182 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon)); | ||
| 183 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon)); | ||
| 184 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon)); | ||
| 185 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon)); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | test "@log" { | ||
| 190 | // Old musl (and glibc?), and our current math.ln implementation do not return 1 | ||
| 191 | // so also accept those values. | ||
| 192 | comptime try testLog(); | ||
| 193 | try testLog(); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn testLog() !void { | ||
| 197 | // TODO test f128, and c_longdouble | ||
| 198 | // https://github.com/ziglang/zig/issues/4026 | ||
| 199 | { | ||
| 200 | var a: f16 = e; | ||
| 201 | try expect(math.approxEqAbs(f16, @log(a), 1, epsilon)); | ||
| 202 | } | ||
| 203 | { | ||
| 204 | var a: f32 = e; | ||
| 205 | try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff))); | ||
| 206 | } | ||
| 207 | { | ||
| 208 | var a: f64 = e; | ||
| 209 | try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000))); | ||
| 210 | } | ||
| 211 | { | ||
| 212 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 213 | var result = @log(v); | ||
| 214 | try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon)); | ||
| 215 | try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon)); | ||
| 216 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon)); | ||
| 217 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon)); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | test "@log2" { | ||
| 222 | comptime try testLog2(); | ||
| 223 | try testLog2(); | ||
| 224 | } | ||
| 225 | |||
| 226 | fn testLog2() !void { | ||
| 227 | // TODO test f128, and c_longdouble | ||
| 228 | // https://github.com/ziglang/zig/issues/4026 | ||
| 229 | { | ||
| 230 | var a: f16 = 4; | ||
| 231 | try expect(@log2(a) == 2); | ||
| 232 | } | ||
| 233 | { | ||
| 234 | var a: f32 = 4; | ||
| 235 | try expect(@log2(a) == 2); | ||
| 236 | } | ||
| 237 | { | ||
| 238 | var a: f64 = 4; | ||
| 239 | try expect(@log2(a) == 2); | ||
| 240 | } | ||
| 241 | { | ||
| 242 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 243 | var result = @log2(v); | ||
| 244 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon)); | ||
| 245 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon)); | ||
| 246 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon)); | ||
| 247 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon)); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | test "@log10" { | ||
| 252 | comptime try testLog10(); | ||
| 253 | try testLog10(); | ||
| 254 | } | ||
| 255 | |||
| 256 | fn testLog10() !void { | ||
| 257 | // TODO test f128, and c_longdouble | ||
| 258 | // https://github.com/ziglang/zig/issues/4026 | ||
| 259 | { | ||
| 260 | var a: f16 = 100; | ||
| 261 | try expect(@log10(a) == 2); | ||
| 262 | } | ||
| 263 | { | ||
| 264 | var a: f32 = 100; | ||
| 265 | try expect(@log10(a) == 2); | ||
| 266 | } | ||
| 267 | { | ||
| 268 | var a: f64 = 1000; | ||
| 269 | try expect(@log10(a) == 3); | ||
| 270 | } | ||
| 271 | { | ||
| 272 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 273 | var result = @log10(v); | ||
| 274 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon)); | ||
| 275 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon)); | ||
| 276 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon)); | ||
| 277 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon)); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | test "@fabs" { | ||
| 282 | comptime try testFabs(); | ||
| 283 | try testFabs(); | ||
| 284 | } | ||
| 285 | |||
| 286 | fn testFabs() !void { | ||
| 287 | // TODO test f128, and c_longdouble | ||
| 288 | // https://github.com/ziglang/zig/issues/4026 | ||
| 289 | { | ||
| 290 | var a: f16 = -2.5; | ||
| 291 | var b: f16 = 2.5; | ||
| 292 | try expect(@fabs(a) == 2.5); | ||
| 293 | try expect(@fabs(b) == 2.5); | ||
| 294 | } | ||
| 295 | { | ||
| 296 | var a: f32 = -2.5; | ||
| 297 | var b: f32 = 2.5; | ||
| 298 | try expect(@fabs(a) == 2.5); | ||
| 299 | try expect(@fabs(b) == 2.5); | ||
| 300 | } | ||
| 301 | { | ||
| 302 | var a: f64 = -2.5; | ||
| 303 | var b: f64 = 2.5; | ||
| 304 | try expect(@fabs(a) == 2.5); | ||
| 305 | try expect(@fabs(b) == 2.5); | ||
| 306 | } | ||
| 307 | { | ||
| 308 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 309 | var result = @fabs(v); | ||
| 310 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon)); | ||
| 311 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon)); | ||
| 312 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon)); | ||
| 313 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon)); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | test "@floor" { | ||
| 318 | comptime try testFloor(); | ||
| 319 | try testFloor(); | ||
| 320 | } | ||
| 321 | |||
| 322 | fn testFloor() !void { | ||
| 323 | // TODO test f128, and c_longdouble | ||
| 324 | // https://github.com/ziglang/zig/issues/4026 | ||
| 325 | { | ||
| 326 | var a: f16 = 2.1; | ||
| 327 | try expect(@floor(a) == 2); | ||
| 328 | } | ||
| 329 | { | ||
| 330 | var a: f32 = 2.1; | ||
| 331 | try expect(@floor(a) == 2); | ||
| 332 | } | ||
| 333 | { | ||
| 334 | var a: f64 = 3.5; | ||
| 335 | try expect(@floor(a) == 3); | ||
| 336 | } | ||
| 337 | { | ||
| 338 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 339 | var result = @floor(v); | ||
| 340 | try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon)); | ||
| 341 | try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon)); | ||
| 342 | try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon)); | ||
| 343 | try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon)); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | test "@ceil" { | ||
| 348 | comptime try testCeil(); | ||
| 349 | try testCeil(); | ||
| 350 | } | ||
| 351 | |||
| 352 | fn testCeil() !void { | ||
| 353 | // TODO test f128, and c_longdouble | ||
| 354 | // https://github.com/ziglang/zig/issues/4026 | ||
| 355 | { | ||
| 356 | var a: f16 = 2.1; | ||
| 357 | try expect(@ceil(a) == 3); | ||
| 358 | } | ||
| 359 | { | ||
| 360 | var a: f32 = 2.1; | ||
| 361 | try expect(@ceil(a) == 3); | ||
| 362 | } | ||
| 363 | { | ||
| 364 | var a: f64 = 3.5; | ||
| 365 | try expect(@ceil(a) == 4); | ||
| 366 | } | ||
| 367 | { | ||
| 368 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 369 | var result = @ceil(v); | ||
| 370 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon)); | ||
| 371 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon)); | ||
| 372 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon)); | ||
| 373 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon)); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | test "@trunc" { | ||
| 378 | comptime try testTrunc(); | ||
| 379 | try testTrunc(); | ||
| 380 | } | ||
| 381 | |||
| 382 | fn testTrunc() !void { | ||
| 383 | // TODO test f128, and c_longdouble | ||
| 384 | // https://github.com/ziglang/zig/issues/4026 | ||
| 385 | { | ||
| 386 | var a: f16 = 2.1; | ||
| 387 | try expect(@trunc(a) == 2); | ||
| 388 | } | ||
| 389 | { | ||
| 390 | var a: f32 = 2.1; | ||
| 391 | try expect(@trunc(a) == 2); | ||
| 392 | } | ||
| 393 | { | ||
| 394 | var a: f64 = -3.5; | ||
| 395 | try expect(@trunc(a) == -3); | ||
| 396 | } | ||
| 397 | { | ||
| 398 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 399 | var result = @trunc(v); | ||
| 400 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon)); | ||
| 401 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon)); | ||
| 402 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon)); | ||
| 403 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon)); | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | test "floating point comparisons" { | ||
| 408 | try testFloatComparisons(); | ||
| 409 | comptime try testFloatComparisons(); | ||
| 410 | } | ||
| 411 | |||
| 412 | fn testFloatComparisons() !void { | ||
| 413 | inline for ([_]type{ f16, f32, f64, f128 }) |ty| { | ||
| 414 | // No decimal part | ||
| 415 | { | ||
| 416 | const x: ty = 1.0; | ||
| 417 | try expect(x == 1); | ||
| 418 | try expect(x != 0); | ||
| 419 | try expect(x > 0); | ||
| 420 | try expect(x < 2); | ||
| 421 | try expect(x >= 1); | ||
| 422 | try expect(x <= 1); | ||
| 423 | } | ||
| 424 | // Non-zero decimal part | ||
| 425 | { | ||
| 426 | const x: ty = 1.5; | ||
| 427 | try expect(x != 1); | ||
| 428 | try expect(x != 2); | ||
| 429 | try expect(x > 1); | ||
| 430 | try expect(x < 2); | ||
| 431 | try expect(x >= 1); | ||
| 432 | try expect(x <= 2); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | test "different sized float comparisons" { | ||
| 438 | try testDifferentSizedFloatComparisons(); | ||
| 439 | comptime try testDifferentSizedFloatComparisons(); | ||
| 440 | } | ||
| 441 | |||
| 442 | fn testDifferentSizedFloatComparisons() !void { | ||
| 443 | var a: f16 = 1; | ||
| 444 | var b: f64 = 2; | ||
| 445 | try expect(a < b); | ||
| 446 | } | ||
| 447 | |||
| 448 | // TODO This is waiting on library support for the Windows build (not sure why the other's don't need it) | ||
| 449 | //test "@nearbyint" { | ||
| 450 | // comptime testNearbyInt(); | ||
| 451 | // testNearbyInt(); | ||
| 452 | //} | ||
| 453 | |||
| 454 | //fn testNearbyInt() void { | ||
| 455 | // // TODO test f16, f128, and c_longdouble | ||
| 456 | // // https://github.com/ziglang/zig/issues/4026 | ||
| 457 | // { | ||
| 458 | // var a: f32 = 2.1; | ||
| 459 | // try expect(@nearbyint(a) == 2); | ||
| 460 | // } | ||
| 461 | // { | ||
| 462 | // var a: f64 = -3.75; | ||
| 463 | // try expect(@nearbyint(a) == -4); | ||
| 464 | // } | ||
| 465 | //} | ||
test/behavior/fn.zig created+287| ... | @@ -0,0 +1,287 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const testing = std.testing; | ||
| 4 | const expect = testing.expect; | ||
| 5 | const expectEqual = testing.expectEqual; | ||
| 6 | |||
| 7 | test "params" { | ||
| 8 | try expect(testParamsAdd(22, 11) == 33); | ||
| 9 | } | ||
| 10 | fn testParamsAdd(a: i32, b: i32) i32 { | ||
| 11 | return a + b; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "local variables" { | ||
| 15 | testLocVars(2); | ||
| 16 | } | ||
| 17 | fn testLocVars(b: i32) void { | ||
| 18 | const a: i32 = 1; | ||
| 19 | if (a + b != 3) unreachable; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "void parameters" { | ||
| 23 | try voidFun(1, void{}, 2, {}); | ||
| 24 | } | ||
| 25 | fn voidFun(a: i32, b: void, c: i32, d: void) !void { | ||
| 26 | const v = b; | ||
| 27 | const vv: void = if (a == 1) v else {}; | ||
| 28 | try expect(a + c == 3); | ||
| 29 | return vv; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "mutable local variables" { | ||
| 33 | var zero: i32 = 0; | ||
| 34 | try expect(zero == 0); | ||
| 35 | |||
| 36 | var i = @as(i32, 0); | ||
| 37 | while (i != 3) { | ||
| 38 | i += 1; | ||
| 39 | } | ||
| 40 | try expect(i == 3); | ||
| 41 | } | ||
| 42 | |||
| 43 | test "separate block scopes" { | ||
| 44 | { | ||
| 45 | const no_conflict: i32 = 5; | ||
| 46 | try expect(no_conflict == 5); | ||
| 47 | } | ||
| 48 | |||
| 49 | const c = x: { | ||
| 50 | const no_conflict = @as(i32, 10); | ||
| 51 | break :x no_conflict; | ||
| 52 | }; | ||
| 53 | try expect(c == 10); | ||
| 54 | } | ||
| 55 | |||
| 56 | test "call function with empty string" { | ||
| 57 | acceptsString(""); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn acceptsString(foo: []u8) void {} | ||
| 61 | |||
| 62 | fn @"weird function name"() i32 { | ||
| 63 | return 1234; | ||
| 64 | } | ||
| 65 | test "weird function name" { | ||
| 66 | try expect(@"weird function name"() == 1234); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "implicit cast function unreachable return" { | ||
| 70 | wantsFnWithVoid(fnWithUnreachable); | ||
| 71 | } | ||
| 72 | |||
| 73 | fn wantsFnWithVoid(f: fn () void) void {} | ||
| 74 | |||
| 75 | fn fnWithUnreachable() noreturn { | ||
| 76 | unreachable; | ||
| 77 | } | ||
| 78 | |||
| 79 | test "function pointers" { | ||
| 80 | const fns = [_]@TypeOf(fn1){ | ||
| 81 | fn1, | ||
| 82 | fn2, | ||
| 83 | fn3, | ||
| 84 | fn4, | ||
| 85 | }; | ||
| 86 | for (fns) |f, i| { | ||
| 87 | try expect(f() == @intCast(u32, i) + 5); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | fn fn1() u32 { | ||
| 91 | return 5; | ||
| 92 | } | ||
| 93 | fn fn2() u32 { | ||
| 94 | return 6; | ||
| 95 | } | ||
| 96 | fn fn3() u32 { | ||
| 97 | return 7; | ||
| 98 | } | ||
| 99 | fn fn4() u32 { | ||
| 100 | return 8; | ||
| 101 | } | ||
| 102 | |||
| 103 | test "number literal as an argument" { | ||
| 104 | try numberLiteralArg(3); | ||
| 105 | comptime try numberLiteralArg(3); | ||
| 106 | } | ||
| 107 | |||
| 108 | fn numberLiteralArg(a: anytype) !void { | ||
| 109 | try expect(a == 3); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "assign inline fn to const variable" { | ||
| 113 | const a = inlineFn; | ||
| 114 | a(); | ||
| 115 | } | ||
| 116 | |||
| 117 | fn inlineFn() callconv(.Inline) void {} | ||
| 118 | |||
| 119 | test "pass by non-copying value" { | ||
| 120 | try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | ||
| 121 | } | ||
| 122 | |||
| 123 | const Point = struct { | ||
| 124 | x: i32, | ||
| 125 | y: i32, | ||
| 126 | }; | ||
| 127 | |||
| 128 | fn addPointCoords(pt: Point) i32 { | ||
| 129 | return pt.x + pt.y; | ||
| 130 | } | ||
| 131 | |||
| 132 | test "pass by non-copying value through var arg" { | ||
| 133 | try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); | ||
| 134 | } | ||
| 135 | |||
| 136 | fn addPointCoordsVar(pt: anytype) !i32 { | ||
| 137 | comptime try expect(@TypeOf(pt) == Point); | ||
| 138 | return pt.x + pt.y; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "pass by non-copying value as method" { | ||
| 142 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 143 | try expect(pt.addPointCoords() == 3); | ||
| 144 | } | ||
| 145 | |||
| 146 | const Point2 = struct { | ||
| 147 | x: i32, | ||
| 148 | y: i32, | ||
| 149 | |||
| 150 | fn addPointCoords(self: Point2) i32 { | ||
| 151 | return self.x + self.y; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | |||
| 155 | test "pass by non-copying value as method, which is generic" { | ||
| 156 | var pt = Point3{ .x = 1, .y = 2 }; | ||
| 157 | try expect(pt.addPointCoords(i32) == 3); | ||
| 158 | } | ||
| 159 | |||
| 160 | const Point3 = struct { | ||
| 161 | x: i32, | ||
| 162 | y: i32, | ||
| 163 | |||
| 164 | fn addPointCoords(self: Point3, comptime T: type) i32 { | ||
| 165 | return self.x + self.y; | ||
| 166 | } | ||
| 167 | }; | ||
| 168 | |||
| 169 | test "pass by non-copying value as method, at comptime" { | ||
| 170 | comptime { | ||
| 171 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 172 | try expect(pt.addPointCoords() == 3); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | fn outer(y: u32) fn (u32) u32 { | ||
| 177 | const Y = @TypeOf(y); | ||
| 178 | const st = struct { | ||
| 179 | fn get(z: u32) u32 { | ||
| 180 | return z + @sizeOf(Y); | ||
| 181 | } | ||
| 182 | }; | ||
| 183 | return st.get; | ||
| 184 | } | ||
| 185 | |||
| 186 | test "return inner function which references comptime variable of outer function" { | ||
| 187 | var func = outer(10); | ||
| 188 | try expect(func(3) == 7); | ||
| 189 | } | ||
| 190 | |||
| 191 | test "extern struct with stdcallcc fn pointer" { | ||
| 192 | const S = extern struct { | ||
| 193 | ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32, | ||
| 194 | |||
| 195 | fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 { | ||
| 196 | return 1234; | ||
| 197 | } | ||
| 198 | }; | ||
| 199 | |||
| 200 | var s: S = undefined; | ||
| 201 | s.ptr = S.foo; | ||
| 202 | try expect(s.ptr() == 1234); | ||
| 203 | } | ||
| 204 | |||
| 205 | test "implicit cast fn call result to optional in field result" { | ||
| 206 | const S = struct { | ||
| 207 | fn entry() !void { | ||
| 208 | var x = Foo{ | ||
| 209 | .field = optionalPtr(), | ||
| 210 | }; | ||
| 211 | try expect(x.field.?.* == 999); | ||
| 212 | } | ||
| 213 | |||
| 214 | const glob: i32 = 999; | ||
| 215 | |||
| 216 | fn optionalPtr() *const i32 { | ||
| 217 | return &glob; | ||
| 218 | } | ||
| 219 | |||
| 220 | const Foo = struct { | ||
| 221 | field: ?*const i32, | ||
| 222 | }; | ||
| 223 | }; | ||
| 224 | try S.entry(); | ||
| 225 | comptime try S.entry(); | ||
| 226 | } | ||
| 227 | |||
| 228 | test "discard the result of a function that returns a struct" { | ||
| 229 | const S = struct { | ||
| 230 | fn entry() void { | ||
| 231 | _ = func(); | ||
| 232 | } | ||
| 233 | |||
| 234 | fn func() Foo { | ||
| 235 | return undefined; | ||
| 236 | } | ||
| 237 | |||
| 238 | const Foo = struct { | ||
| 239 | a: u64, | ||
| 240 | b: u64, | ||
| 241 | }; | ||
| 242 | }; | ||
| 243 | S.entry(); | ||
| 244 | comptime S.entry(); | ||
| 245 | } | ||
| 246 | |||
| 247 | test "function call with anon list literal" { | ||
| 248 | const S = struct { | ||
| 249 | fn doTheTest() !void { | ||
| 250 | try consumeVec(.{ 9, 8, 7 }); | ||
| 251 | } | ||
| 252 | |||
| 253 | fn consumeVec(vec: [3]f32) !void { | ||
| 254 | try expect(vec[0] == 9); | ||
| 255 | try expect(vec[1] == 8); | ||
| 256 | try expect(vec[2] == 7); | ||
| 257 | } | ||
| 258 | }; | ||
| 259 | try S.doTheTest(); | ||
| 260 | comptime try S.doTheTest(); | ||
| 261 | } | ||
| 262 | |||
| 263 | test "ability to give comptime types and non comptime types to same parameter" { | ||
| 264 | const S = struct { | ||
| 265 | fn doTheTest() !void { | ||
| 266 | var x: i32 = 1; | ||
| 267 | try expect(foo(x) == 10); | ||
| 268 | try expect(foo(i32) == 20); | ||
| 269 | } | ||
| 270 | |||
| 271 | fn foo(arg: anytype) i32 { | ||
| 272 | if (@typeInfo(@TypeOf(arg)) == .Type and arg == i32) return 20; | ||
| 273 | return 9 + arg; | ||
| 274 | } | ||
| 275 | }; | ||
| 276 | try S.doTheTest(); | ||
| 277 | comptime try S.doTheTest(); | ||
| 278 | } | ||
| 279 | |||
| 280 | test "function with inferred error set but returning no error" { | ||
| 281 | const S = struct { | ||
| 282 | fn foo() !void {} | ||
| 283 | }; | ||
| 284 | |||
| 285 | const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; | ||
| 286 | try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); | ||
| 287 | } | ||
test/behavior/fn_delegation.zig created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: u64 = 10, | ||
| 5 | |||
| 6 | fn one(self: Foo) u64 { | ||
| 7 | return self.a + 1; | ||
| 8 | } | ||
| 9 | |||
| 10 | const two = __two; | ||
| 11 | |||
| 12 | fn __two(self: Foo) u64 { | ||
| 13 | return self.a + 2; | ||
| 14 | } | ||
| 15 | |||
| 16 | const three = __three; | ||
| 17 | |||
| 18 | const four = custom(Foo, 4); | ||
| 19 | }; | ||
| 20 | |||
| 21 | fn __three(self: Foo) u64 { | ||
| 22 | return self.a + 3; | ||
| 23 | } | ||
| 24 | |||
| 25 | fn custom(comptime T: type, comptime num: u64) fn (T) u64 { | ||
| 26 | return struct { | ||
| 27 | fn function(self: T) u64 { | ||
| 28 | return self.a + num; | ||
| 29 | } | ||
| 30 | }.function; | ||
| 31 | } | ||
| 32 | |||
| 33 | test "fn delegation" { | ||
| 34 | const foo = Foo{}; | ||
| 35 | try expect(foo.one() == 11); | ||
| 36 | try expect(foo.two() == 12); | ||
| 37 | try expect(foo.three() == 13); | ||
| 38 | try expect(foo.four() == 14); | ||
| 39 | } | ||
test/behavior/fn_in_struct_in_comptime.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn get_foo() fn (*u8) usize { | ||
| 4 | comptime { | ||
| 5 | return struct { | ||
| 6 | fn func(ptr: *u8) usize { | ||
| 7 | var u = @ptrToInt(ptr); | ||
| 8 | return u; | ||
| 9 | } | ||
| 10 | }.func; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "define a function in an anonymous struct in comptime" { | ||
| 15 | const foo = get_foo(); | ||
| 16 | try expect(foo(@intToPtr(*u8, 12345)) == 12345); | ||
| 17 | } | ||
test/behavior/for.zig created+172| ... | @@ -0,0 +1,172 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const mem = std.mem; | ||
| 5 | |||
| 6 | test "continue in for loop" { | ||
| 7 | const array = [_]i32{ | ||
| 8 | 1, | ||
| 9 | 2, | ||
| 10 | 3, | ||
| 11 | 4, | ||
| 12 | 5, | ||
| 13 | }; | ||
| 14 | var sum: i32 = 0; | ||
| 15 | for (array) |x| { | ||
| 16 | sum += x; | ||
| 17 | if (x < 3) { | ||
| 18 | continue; | ||
| 19 | } | ||
| 20 | break; | ||
| 21 | } | ||
| 22 | if (sum != 6) unreachable; | ||
| 23 | } | ||
| 24 | |||
| 25 | test "for loop with pointer elem var" { | ||
| 26 | const source = "abcdefg"; | ||
| 27 | var target: [source.len]u8 = undefined; | ||
| 28 | mem.copy(u8, target[0..], source); | ||
| 29 | mangleString(target[0..]); | ||
| 30 | try expect(mem.eql(u8, &target, "bcdefgh")); | ||
| 31 | |||
| 32 | for (source) |*c, i| | ||
| 33 | try expect(@TypeOf(c) == *const u8); | ||
| 34 | for (target) |*c, i| | ||
| 35 | try expect(@TypeOf(c) == *u8); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn mangleString(s: []u8) void { | ||
| 39 | for (s) |*c| { | ||
| 40 | c.* += 1; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | test "basic for loop" { | ||
| 45 | const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | ||
| 46 | |||
| 47 | var buffer: [expected_result.len]u8 = undefined; | ||
| 48 | var buf_index: usize = 0; | ||
| 49 | |||
| 50 | const array = [_]u8{ 9, 8, 7, 6 }; | ||
| 51 | for (array) |item| { | ||
| 52 | buffer[buf_index] = item; | ||
| 53 | buf_index += 1; | ||
| 54 | } | ||
| 55 | for (array) |item, index| { | ||
| 56 | buffer[buf_index] = @intCast(u8, index); | ||
| 57 | buf_index += 1; | ||
| 58 | } | ||
| 59 | const array_ptr = &array; | ||
| 60 | for (array_ptr) |item| { | ||
| 61 | buffer[buf_index] = item; | ||
| 62 | buf_index += 1; | ||
| 63 | } | ||
| 64 | for (array_ptr) |item, index| { | ||
| 65 | buffer[buf_index] = @intCast(u8, index); | ||
| 66 | buf_index += 1; | ||
| 67 | } | ||
| 68 | const unknown_size: []const u8 = &array; | ||
| 69 | for (unknown_size) |item| { | ||
| 70 | buffer[buf_index] = item; | ||
| 71 | buf_index += 1; | ||
| 72 | } | ||
| 73 | for (unknown_size) |item, index| { | ||
| 74 | buffer[buf_index] = @intCast(u8, index); | ||
| 75 | buf_index += 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | try expect(mem.eql(u8, buffer[0..buf_index], &expected_result)); | ||
| 79 | } | ||
| 80 | |||
| 81 | test "break from outer for loop" { | ||
| 82 | try testBreakOuter(); | ||
| 83 | comptime try testBreakOuter(); | ||
| 84 | } | ||
| 85 | |||
| 86 | fn testBreakOuter() !void { | ||
| 87 | var array = "aoeu"; | ||
| 88 | var count: usize = 0; | ||
| 89 | outer: for (array) |_| { | ||
| 90 | for (array) |_| { | ||
| 91 | count += 1; | ||
| 92 | break :outer; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | try expect(count == 1); | ||
| 96 | } | ||
| 97 | |||
| 98 | test "continue outer for loop" { | ||
| 99 | try testContinueOuter(); | ||
| 100 | comptime try testContinueOuter(); | ||
| 101 | } | ||
| 102 | |||
| 103 | fn testContinueOuter() !void { | ||
| 104 | var array = "aoeu"; | ||
| 105 | var counter: usize = 0; | ||
| 106 | outer: for (array) |_| { | ||
| 107 | for (array) |_| { | ||
| 108 | counter += 1; | ||
| 109 | continue :outer; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | try expect(counter == array.len); | ||
| 113 | } | ||
| 114 | |||
| 115 | test "2 break statements and an else" { | ||
| 116 | const S = struct { | ||
| 117 | fn entry(t: bool, f: bool) !void { | ||
| 118 | var buf: [10]u8 = undefined; | ||
| 119 | var ok = false; | ||
| 120 | ok = for (buf) |item| { | ||
| 121 | if (f) break false; | ||
| 122 | if (t) break true; | ||
| 123 | } else false; | ||
| 124 | try expect(ok); | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | try S.entry(true, false); | ||
| 128 | comptime try S.entry(true, false); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "for with null and T peer types and inferred result location type" { | ||
| 132 | const S = struct { | ||
| 133 | fn doTheTest(slice: []const u8) !void { | ||
| 134 | if (for (slice) |item| { | ||
| 135 | if (item == 10) { | ||
| 136 | break item; | ||
| 137 | } | ||
| 138 | } else null) |v| { | ||
| 139 | @panic("fail"); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | try S.doTheTest(&[_]u8{ 1, 2 }); | ||
| 144 | comptime try S.doTheTest(&[_]u8{ 1, 2 }); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "for copies its payload" { | ||
| 148 | const S = struct { | ||
| 149 | fn doTheTest() !void { | ||
| 150 | var x = [_]usize{ 1, 2, 3 }; | ||
| 151 | for (x) |value, i| { | ||
| 152 | // Modify the original array | ||
| 153 | x[i] += 99; | ||
| 154 | try expectEqual(value, i + 1); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | try S.doTheTest(); | ||
| 159 | comptime try S.doTheTest(); | ||
| 160 | } | ||
| 161 | |||
| 162 | test "for on slice with allowzero ptr" { | ||
| 163 | const S = struct { | ||
| 164 | fn doTheTest(slice: []const u8) !void { | ||
| 165 | var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len]; | ||
| 166 | for (ptr) |x, i| try expect(x == i + 1); | ||
| 167 | for (ptr) |*x, i| try expect(x.* == i + 1); | ||
| 168 | } | ||
| 169 | }; | ||
| 170 | try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); | ||
| 171 | comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); | ||
| 172 | } | ||
test/behavior/generics.zig created+169| ... | @@ -0,0 +1,169 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "simple generic fn" { | ||
| 7 | try expect(max(i32, 3, -1) == 3); | ||
| 8 | try expect(max(f32, 0.123, 0.456) == 0.456); | ||
| 9 | try expect(add(2, 3) == 5); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn max(comptime T: type, a: T, b: T) T { | ||
| 13 | return if (a > b) a else b; | ||
| 14 | } | ||
| 15 | |||
| 16 | fn add(comptime a: i32, b: i32) i32 { | ||
| 17 | return (comptime a) + b; | ||
| 18 | } | ||
| 19 | |||
| 20 | const the_max = max(u32, 1234, 5678); | ||
| 21 | test "compile time generic eval" { | ||
| 22 | try expect(the_max == 5678); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn gimmeTheBigOne(a: u32, b: u32) u32 { | ||
| 26 | return max(u32, a, b); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn shouldCallSameInstance(a: u32, b: u32) u32 { | ||
| 30 | return max(u32, a, b); | ||
| 31 | } | ||
| 32 | |||
| 33 | fn sameButWithFloats(a: f64, b: f64) f64 { | ||
| 34 | return max(f64, a, b); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "fn with comptime args" { | ||
| 38 | try expect(gimmeTheBigOne(1234, 5678) == 5678); | ||
| 39 | try expect(shouldCallSameInstance(34, 12) == 34); | ||
| 40 | try expect(sameButWithFloats(0.43, 0.49) == 0.49); | ||
| 41 | } | ||
| 42 | |||
| 43 | test "var params" { | ||
| 44 | try expect(max_i32(12, 34) == 34); | ||
| 45 | try expect(max_f64(1.2, 3.4) == 3.4); | ||
| 46 | } | ||
| 47 | |||
| 48 | comptime { | ||
| 49 | try expect(max_i32(12, 34) == 34); | ||
| 50 | try expect(max_f64(1.2, 3.4) == 3.4); | ||
| 51 | } | ||
| 52 | |||
| 53 | fn max_var(a: anytype, b: anytype) @TypeOf(a + b) { | ||
| 54 | return if (a > b) a else b; | ||
| 55 | } | ||
| 56 | |||
| 57 | fn max_i32(a: i32, b: i32) i32 { | ||
| 58 | return max_var(a, b); | ||
| 59 | } | ||
| 60 | |||
| 61 | fn max_f64(a: f64, b: f64) f64 { | ||
| 62 | return max_var(a, b); | ||
| 63 | } | ||
| 64 | |||
| 65 | pub fn List(comptime T: type) type { | ||
| 66 | return SmallList(T, 8); | ||
| 67 | } | ||
| 68 | |||
| 69 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { | ||
| 70 | return struct { | ||
| 71 | items: []T, | ||
| 72 | length: usize, | ||
| 73 | prealloc_items: [STATIC_SIZE]T, | ||
| 74 | }; | ||
| 75 | } | ||
| 76 | |||
| 77 | test "function with return type type" { | ||
| 78 | var list: List(i32) = undefined; | ||
| 79 | var list2: List(i32) = undefined; | ||
| 80 | list.length = 10; | ||
| 81 | list2.length = 10; | ||
| 82 | try expect(list.prealloc_items.len == 8); | ||
| 83 | try expect(list2.prealloc_items.len == 8); | ||
| 84 | } | ||
| 85 | |||
| 86 | test "generic struct" { | ||
| 87 | var a1 = GenNode(i32){ | ||
| 88 | .value = 13, | ||
| 89 | .next = null, | ||
| 90 | }; | ||
| 91 | var b1 = GenNode(bool){ | ||
| 92 | .value = true, | ||
| 93 | .next = null, | ||
| 94 | }; | ||
| 95 | try expect(a1.value == 13); | ||
| 96 | try expect(a1.value == a1.getVal()); | ||
| 97 | try expect(b1.getVal()); | ||
| 98 | } | ||
| 99 | fn GenNode(comptime T: type) type { | ||
| 100 | return struct { | ||
| 101 | value: T, | ||
| 102 | next: ?*GenNode(T), | ||
| 103 | fn getVal(n: *const GenNode(T)) T { | ||
| 104 | return n.value; | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | } | ||
| 108 | |||
| 109 | test "const decls in struct" { | ||
| 110 | try expect(GenericDataThing(3).count_plus_one == 4); | ||
| 111 | } | ||
| 112 | fn GenericDataThing(comptime count: isize) type { | ||
| 113 | return struct { | ||
| 114 | const count_plus_one = count + 1; | ||
| 115 | }; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "use generic param in generic param" { | ||
| 119 | try expect(aGenericFn(i32, 3, 4) == 7); | ||
| 120 | } | ||
| 121 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { | ||
| 122 | return a + b; | ||
| 123 | } | ||
| 124 | |||
| 125 | test "generic fn with implicit cast" { | ||
| 126 | try expect(getFirstByte(u8, &[_]u8{13}) == 13); | ||
| 127 | try expect(getFirstByte(u16, &[_]u16{ | ||
| 128 | 0, | ||
| 129 | 13, | ||
| 130 | }) == 0); | ||
| 131 | } | ||
| 132 | fn getByte(ptr: ?*const u8) u8 { | ||
| 133 | return ptr.?.*; | ||
| 134 | } | ||
| 135 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 136 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 137 | } | ||
| 138 | |||
| 139 | const foos = [_]fn (anytype) bool{ | ||
| 140 | foo1, | ||
| 141 | foo2, | ||
| 142 | }; | ||
| 143 | |||
| 144 | fn foo1(arg: anytype) bool { | ||
| 145 | return arg; | ||
| 146 | } | ||
| 147 | fn foo2(arg: anytype) bool { | ||
| 148 | return !arg; | ||
| 149 | } | ||
| 150 | |||
| 151 | test "array of generic fns" { | ||
| 152 | try expect(foos[0](true)); | ||
| 153 | try expect(!foos[1](true)); | ||
| 154 | } | ||
| 155 | |||
| 156 | test "generic fn keeps non-generic parameter types" { | ||
| 157 | const A = 128; | ||
| 158 | |||
| 159 | const S = struct { | ||
| 160 | fn f(comptime T: type, s: []T) !void { | ||
| 161 | try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment); | ||
| 162 | } | ||
| 163 | }; | ||
| 164 | |||
| 165 | // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that | ||
| 166 | // `x` type not affect `s` parameter type. | ||
| 167 | var x: [16]u8 align(A) = undefined; | ||
| 168 | try S.f(u8, &x); | ||
| 169 | } | ||
test/behavior/hasdecl.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const Foo = @import("hasdecl/foo.zig"); | ||
| 5 | |||
| 6 | const Bar = struct { | ||
| 7 | nope: i32, | ||
| 8 | |||
| 9 | const hi = 1; | ||
| 10 | pub var blah = "xxx"; | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "@hasDecl" { | ||
| 14 | try expect(@hasDecl(Foo, "public_thing")); | ||
| 15 | try expect(!@hasDecl(Foo, "private_thing")); | ||
| 16 | try expect(!@hasDecl(Foo, "no_thing")); | ||
| 17 | |||
| 18 | try expect(@hasDecl(Bar, "hi")); | ||
| 19 | try expect(@hasDecl(Bar, "blah")); | ||
| 20 | try expect(!@hasDecl(Bar, "nope")); | ||
| 21 | } | ||
test/behavior/hasdecl/foo.zig created+2| ... | @@ -0,0 +1,2 @@ | ||
| 1 | pub const public_thing = 42; | ||
| 2 | const private_thing = 666; | ||
test/behavior/hasfield.zig created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | test "@hasField" { | ||
| 5 | const struc = struct { | ||
| 6 | a: i32, | ||
| 7 | b: []u8, | ||
| 8 | |||
| 9 | pub const nope = 1; | ||
| 10 | }; | ||
| 11 | try expect(@hasField(struc, "a") == true); | ||
| 12 | try expect(@hasField(struc, "b") == true); | ||
| 13 | try expect(@hasField(struc, "non-existant") == false); | ||
| 14 | try expect(@hasField(struc, "nope") == false); | ||
| 15 | |||
| 16 | const unin = union { | ||
| 17 | a: u64, | ||
| 18 | b: []u16, | ||
| 19 | |||
| 20 | pub const nope = 1; | ||
| 21 | }; | ||
| 22 | try expect(@hasField(unin, "a") == true); | ||
| 23 | try expect(@hasField(unin, "b") == true); | ||
| 24 | try expect(@hasField(unin, "non-existant") == false); | ||
| 25 | try expect(@hasField(unin, "nope") == false); | ||
| 26 | |||
| 27 | const enm = enum { | ||
| 28 | a, | ||
| 29 | b, | ||
| 30 | |||
| 31 | pub const nope = 1; | ||
| 32 | }; | ||
| 33 | try expect(@hasField(enm, "a") == true); | ||
| 34 | try expect(@hasField(enm, "b") == true); | ||
| 35 | try expect(@hasField(enm, "non-existant") == false); | ||
| 36 | try expect(@hasField(enm, "nope") == false); | ||
| 37 | } | ||
test/behavior/if.zig created+109| ... | @@ -0,0 +1,109 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | |||
| 5 | test "if statements" { | ||
| 6 | shouldBeEqual(1, 1); | ||
| 7 | firstEqlThird(2, 1, 2); | ||
| 8 | } | ||
| 9 | fn shouldBeEqual(a: i32, b: i32) void { | ||
| 10 | if (a != b) { | ||
| 11 | unreachable; | ||
| 12 | } else { | ||
| 13 | return; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | fn firstEqlThird(a: i32, b: i32, c: i32) void { | ||
| 17 | if (a == b) { | ||
| 18 | unreachable; | ||
| 19 | } else if (b == c) { | ||
| 20 | unreachable; | ||
| 21 | } else if (a == c) { | ||
| 22 | return; | ||
| 23 | } else { | ||
| 24 | unreachable; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "else if expression" { | ||
| 29 | try expect(elseIfExpressionF(1) == 1); | ||
| 30 | } | ||
| 31 | fn elseIfExpressionF(c: u8) u8 { | ||
| 32 | if (c == 0) { | ||
| 33 | return 0; | ||
| 34 | } else if (c == 1) { | ||
| 35 | return 1; | ||
| 36 | } else { | ||
| 37 | return @as(u8, 2); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // #2297 | ||
| 42 | var global_with_val: anyerror!u32 = 0; | ||
| 43 | var global_with_err: anyerror!u32 = error.SomeError; | ||
| 44 | |||
| 45 | test "unwrap mutable global var" { | ||
| 46 | if (global_with_val) |v| { | ||
| 47 | try expect(v == 0); | ||
| 48 | } else |e| { | ||
| 49 | unreachable; | ||
| 50 | } | ||
| 51 | if (global_with_err) |_| { | ||
| 52 | unreachable; | ||
| 53 | } else |e| { | ||
| 54 | try expect(e == error.SomeError); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | test "labeled break inside comptime if inside runtime if" { | ||
| 59 | var answer: i32 = 0; | ||
| 60 | var c = true; | ||
| 61 | if (c) { | ||
| 62 | answer = if (true) blk: { | ||
| 63 | break :blk @as(i32, 42); | ||
| 64 | }; | ||
| 65 | } | ||
| 66 | try expect(answer == 42); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "const result loc, runtime if cond, else unreachable" { | ||
| 70 | const Num = enum { | ||
| 71 | One, | ||
| 72 | Two, | ||
| 73 | }; | ||
| 74 | |||
| 75 | var t = true; | ||
| 76 | const x = if (t) Num.Two else unreachable; | ||
| 77 | try expect(x == .Two); | ||
| 78 | } | ||
| 79 | |||
| 80 | test "if prongs cast to expected type instead of peer type resolution" { | ||
| 81 | const S = struct { | ||
| 82 | fn doTheTest(f: bool) !void { | ||
| 83 | var x: i32 = 0; | ||
| 84 | x = if (f) 1 else 2; | ||
| 85 | try expect(x == 2); | ||
| 86 | |||
| 87 | var b = true; | ||
| 88 | const y: i32 = if (b) 1 else 2; | ||
| 89 | try expect(y == 1); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | try S.doTheTest(false); | ||
| 93 | comptime try S.doTheTest(false); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "while copies its payload" { | ||
| 97 | const S = struct { | ||
| 98 | fn doTheTest() !void { | ||
| 99 | var tmp: ?i32 = 10; | ||
| 100 | if (tmp) |value| { | ||
| 101 | // Modify the original variable | ||
| 102 | tmp = null; | ||
| 103 | try expectEqual(@as(i32, 10), value); | ||
| 104 | } else unreachable; | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | try S.doTheTest(); | ||
| 108 | comptime try S.doTheTest(); | ||
| 109 | } | ||
test/behavior/import.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const expectEqual = @import("std").testing.expectEqual; | ||
| 3 | const a_namespace = @import("import/a_namespace.zig"); | ||
| 4 | |||
| 5 | test "call fn via namespace lookup" { | ||
| 6 | try expectEqual(@as(i32, 1234), a_namespace.foo()); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "importing the same thing gives the same import" { | ||
| 10 | try expect(@import("std") == @import("std")); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "import in non-toplevel scope" { | ||
| 14 | const S = struct { | ||
| 15 | usingnamespace @import("import/a_namespace.zig"); | ||
| 16 | }; | ||
| 17 | try expectEqual(@as(i32, 1234), S.foo()); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "import empty file" { | ||
| 21 | const empty = @import("import/empty.zig"); | ||
| 22 | } | ||
test/behavior/import/a_namespace.zig created+3| ... | @@ -0,0 +1,3 @@ | ||
| 1 | pub fn foo() i32 { | ||
| 2 | return 1234; | ||
| 3 | } | ||
test/behavior/import/empty.zig createdtest/behavior/incomplete_struct_param_tld.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 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: 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{ .x = 13 }, | ||
| 27 | }, | ||
| 28 | }; | ||
| 29 | try expect(foo(a) == 13); | ||
| 30 | } | ||
test/behavior/inttoptr.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | test "casting random address to function pointer" { | ||
| 2 | randomAddressToFunction(); | ||
| 3 | comptime randomAddressToFunction(); | ||
| 4 | } | ||
| 5 | |||
| 6 | fn randomAddressToFunction() void { | ||
| 7 | var addr: usize = 0xdeadbeef; | ||
| 8 | var ptr = @intToPtr(fn () void, addr); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "mutate through ptr initialized with constant intToPtr value" { | ||
| 12 | forceCompilerAnalyzeBranchHardCodedPtrDereference(false); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { | ||
| 16 | const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); | ||
| 17 | if (x) { | ||
| 18 | hardCodedP.* = hardCodedP.* | 10; | ||
| 19 | } else { | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | } | ||
test/behavior/ir_block_deps.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn foo(id: u64) !i32 { | ||
| 4 | return switch (id) { | ||
| 5 | 1 => getErrInt(), | ||
| 6 | 2 => { | ||
| 7 | const size = try getErrInt(); | ||
| 8 | return try getErrInt(); | ||
| 9 | }, | ||
| 10 | else => error.ItBroke, | ||
| 11 | }; | ||
| 12 | } | ||
| 13 | |||
| 14 | fn getErrInt() anyerror!i32 { | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "ir block deps" { | ||
| 19 | try expect((foo(1) catch unreachable) == 0); | ||
| 20 | try expect((foo(2) catch unreachable) == 0); | ||
| 21 | } | ||
test/behavior/math.zig created+872| ... | @@ -0,0 +1,872 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 5 | const maxInt = std.math.maxInt; | ||
| 6 | const minInt = std.math.minInt; | ||
| 7 | const mem = std.mem; | ||
| 8 | |||
| 9 | test "division" { | ||
| 10 | try testDivision(); | ||
| 11 | comptime try testDivision(); | ||
| 12 | } | ||
| 13 | fn testDivision() !void { | ||
| 14 | try expect(div(u32, 13, 3) == 4); | ||
| 15 | try expect(div(f16, 1.0, 2.0) == 0.5); | ||
| 16 | try expect(div(f32, 1.0, 2.0) == 0.5); | ||
| 17 | |||
| 18 | try expect(divExact(u32, 55, 11) == 5); | ||
| 19 | try expect(divExact(i32, -55, 11) == -5); | ||
| 20 | try expect(divExact(f16, 55.0, 11.0) == 5.0); | ||
| 21 | try expect(divExact(f16, -55.0, 11.0) == -5.0); | ||
| 22 | try expect(divExact(f32, 55.0, 11.0) == 5.0); | ||
| 23 | try expect(divExact(f32, -55.0, 11.0) == -5.0); | ||
| 24 | |||
| 25 | try expect(divFloor(i32, 5, 3) == 1); | ||
| 26 | try expect(divFloor(i32, -5, 3) == -2); | ||
| 27 | try expect(divFloor(f16, 5.0, 3.0) == 1.0); | ||
| 28 | try expect(divFloor(f16, -5.0, 3.0) == -2.0); | ||
| 29 | try expect(divFloor(f32, 5.0, 3.0) == 1.0); | ||
| 30 | try expect(divFloor(f32, -5.0, 3.0) == -2.0); | ||
| 31 | try expect(divFloor(i32, -0x80000000, -2) == 0x40000000); | ||
| 32 | try expect(divFloor(i32, 0, -0x80000000) == 0); | ||
| 33 | try expect(divFloor(i32, -0x40000001, 0x40000000) == -2); | ||
| 34 | try expect(divFloor(i32, -0x80000000, 1) == -0x80000000); | ||
| 35 | try expect(divFloor(i32, 10, 12) == 0); | ||
| 36 | try expect(divFloor(i32, -14, 12) == -2); | ||
| 37 | try expect(divFloor(i32, -2, 12) == -1); | ||
| 38 | |||
| 39 | try expect(divTrunc(i32, 5, 3) == 1); | ||
| 40 | try expect(divTrunc(i32, -5, 3) == -1); | ||
| 41 | try expect(divTrunc(f16, 5.0, 3.0) == 1.0); | ||
| 42 | try expect(divTrunc(f16, -5.0, 3.0) == -1.0); | ||
| 43 | try expect(divTrunc(f32, 5.0, 3.0) == 1.0); | ||
| 44 | try expect(divTrunc(f32, -5.0, 3.0) == -1.0); | ||
| 45 | try expect(divTrunc(f64, 5.0, 3.0) == 1.0); | ||
| 46 | try expect(divTrunc(f64, -5.0, 3.0) == -1.0); | ||
| 47 | try expect(divTrunc(i32, 10, 12) == 0); | ||
| 48 | try expect(divTrunc(i32, -14, 12) == -1); | ||
| 49 | try expect(divTrunc(i32, -2, 12) == 0); | ||
| 50 | |||
| 51 | try expect(mod(i32, 10, 12) == 10); | ||
| 52 | try expect(mod(i32, -14, 12) == 10); | ||
| 53 | try expect(mod(i32, -2, 12) == 10); | ||
| 54 | |||
| 55 | comptime { | ||
| 56 | try expect( | ||
| 57 | 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, | ||
| 58 | ); | ||
| 59 | try expect( | ||
| 60 | @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, | ||
| 61 | ); | ||
| 62 | try expect( | ||
| 63 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, | ||
| 64 | ); | ||
| 65 | try expect( | ||
| 66 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | ||
| 67 | ); | ||
| 68 | try expect( | ||
| 69 | @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, | ||
| 70 | ); | ||
| 71 | try expect( | ||
| 72 | @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, | ||
| 73 | ); | ||
| 74 | try expect( | ||
| 75 | 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, | ||
| 76 | ); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | fn div(comptime T: type, a: T, b: T) T { | ||
| 80 | return a / b; | ||
| 81 | } | ||
| 82 | fn divExact(comptime T: type, a: T, b: T) T { | ||
| 83 | return @divExact(a, b); | ||
| 84 | } | ||
| 85 | fn divFloor(comptime T: type, a: T, b: T) T { | ||
| 86 | return @divFloor(a, b); | ||
| 87 | } | ||
| 88 | fn divTrunc(comptime T: type, a: T, b: T) T { | ||
| 89 | return @divTrunc(a, b); | ||
| 90 | } | ||
| 91 | fn mod(comptime T: type, a: T, b: T) T { | ||
| 92 | return @mod(a, b); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "@addWithOverflow" { | ||
| 96 | var result: u8 = undefined; | ||
| 97 | try expect(@addWithOverflow(u8, 250, 100, &result)); | ||
| 98 | try expect(!@addWithOverflow(u8, 100, 150, &result)); | ||
| 99 | try expect(result == 250); | ||
| 100 | } | ||
| 101 | |||
| 102 | // TODO test mulWithOverflow | ||
| 103 | // TODO test subWithOverflow | ||
| 104 | |||
| 105 | test "@shlWithOverflow" { | ||
| 106 | var result: u16 = undefined; | ||
| 107 | try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | ||
| 108 | try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | ||
| 109 | try expect(result == 0b1011111111111100); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "@*WithOverflow with u0 values" { | ||
| 113 | var result: u0 = undefined; | ||
| 114 | try expect(!@addWithOverflow(u0, 0, 0, &result)); | ||
| 115 | try expect(!@subWithOverflow(u0, 0, 0, &result)); | ||
| 116 | try expect(!@mulWithOverflow(u0, 0, 0, &result)); | ||
| 117 | try expect(!@shlWithOverflow(u0, 0, 0, &result)); | ||
| 118 | } | ||
| 119 | |||
| 120 | test "@clz" { | ||
| 121 | try testClz(); | ||
| 122 | comptime try testClz(); | ||
| 123 | } | ||
| 124 | |||
| 125 | fn testClz() !void { | ||
| 126 | try expect(clz(u8, 0b10001010) == 0); | ||
| 127 | try expect(clz(u8, 0b00001010) == 4); | ||
| 128 | try expect(clz(u8, 0b00011010) == 3); | ||
| 129 | try expect(clz(u8, 0b00000000) == 8); | ||
| 130 | try expect(clz(u128, 0xffffffffffffffff) == 64); | ||
| 131 | try expect(clz(u128, 0x10000000000000000) == 63); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn clz(comptime T: type, x: T) usize { | ||
| 135 | return @clz(T, x); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "@ctz" { | ||
| 139 | try testCtz(); | ||
| 140 | comptime try testCtz(); | ||
| 141 | } | ||
| 142 | |||
| 143 | fn testCtz() !void { | ||
| 144 | try expect(ctz(u8, 0b10100000) == 5); | ||
| 145 | try expect(ctz(u8, 0b10001010) == 1); | ||
| 146 | try expect(ctz(u8, 0b00000000) == 8); | ||
| 147 | try expect(ctz(u16, 0b00000000) == 16); | ||
| 148 | } | ||
| 149 | |||
| 150 | fn ctz(comptime T: type, x: T) usize { | ||
| 151 | return @ctz(T, x); | ||
| 152 | } | ||
| 153 | |||
| 154 | test "assignment operators" { | ||
| 155 | var i: u32 = 0; | ||
| 156 | i += 5; | ||
| 157 | try expect(i == 5); | ||
| 158 | i -= 2; | ||
| 159 | try expect(i == 3); | ||
| 160 | i *= 20; | ||
| 161 | try expect(i == 60); | ||
| 162 | i /= 3; | ||
| 163 | try expect(i == 20); | ||
| 164 | i %= 11; | ||
| 165 | try expect(i == 9); | ||
| 166 | i <<= 1; | ||
| 167 | try expect(i == 18); | ||
| 168 | i >>= 2; | ||
| 169 | try expect(i == 4); | ||
| 170 | i = 6; | ||
| 171 | i &= 5; | ||
| 172 | try expect(i == 4); | ||
| 173 | i ^= 6; | ||
| 174 | try expect(i == 2); | ||
| 175 | i = 6; | ||
| 176 | i |= 3; | ||
| 177 | try expect(i == 7); | ||
| 178 | } | ||
| 179 | |||
| 180 | test "three expr in a row" { | ||
| 181 | try testThreeExprInARow(false, true); | ||
| 182 | comptime try testThreeExprInARow(false, true); | ||
| 183 | } | ||
| 184 | fn testThreeExprInARow(f: bool, t: bool) !void { | ||
| 185 | try assertFalse(f or f or f); | ||
| 186 | try assertFalse(t and t and f); | ||
| 187 | try assertFalse(1 | 2 | 4 != 7); | ||
| 188 | try assertFalse(3 ^ 6 ^ 8 != 13); | ||
| 189 | try assertFalse(7 & 14 & 28 != 4); | ||
| 190 | try assertFalse(9 << 1 << 2 != 9 << 3); | ||
| 191 | try assertFalse(90 >> 1 >> 2 != 90 >> 3); | ||
| 192 | try assertFalse(100 - 1 + 1000 != 1099); | ||
| 193 | try assertFalse(5 * 4 / 2 % 3 != 1); | ||
| 194 | try assertFalse(@as(i32, @as(i32, 5)) != 5); | ||
| 195 | try assertFalse(!!false); | ||
| 196 | try assertFalse(@as(i32, 7) != --(@as(i32, 7))); | ||
| 197 | } | ||
| 198 | fn assertFalse(b: bool) !void { | ||
| 199 | try expect(!b); | ||
| 200 | } | ||
| 201 | |||
| 202 | test "const number literal" { | ||
| 203 | const one = 1; | ||
| 204 | const eleven = ten + one; | ||
| 205 | |||
| 206 | try expect(eleven == 11); | ||
| 207 | } | ||
| 208 | const ten = 10; | ||
| 209 | |||
| 210 | test "unsigned wrapping" { | ||
| 211 | try testUnsignedWrappingEval(maxInt(u32)); | ||
| 212 | comptime try testUnsignedWrappingEval(maxInt(u32)); | ||
| 213 | } | ||
| 214 | fn testUnsignedWrappingEval(x: u32) !void { | ||
| 215 | const zero = x +% 1; | ||
| 216 | try expect(zero == 0); | ||
| 217 | const orig = zero -% 1; | ||
| 218 | try expect(orig == maxInt(u32)); | ||
| 219 | } | ||
| 220 | |||
| 221 | test "signed wrapping" { | ||
| 222 | try testSignedWrappingEval(maxInt(i32)); | ||
| 223 | comptime try testSignedWrappingEval(maxInt(i32)); | ||
| 224 | } | ||
| 225 | fn testSignedWrappingEval(x: i32) !void { | ||
| 226 | const min_val = x +% 1; | ||
| 227 | try expect(min_val == minInt(i32)); | ||
| 228 | const max_val = min_val -% 1; | ||
| 229 | try expect(max_val == maxInt(i32)); | ||
| 230 | } | ||
| 231 | |||
| 232 | test "signed negation wrapping" { | ||
| 233 | try testSignedNegationWrappingEval(minInt(i16)); | ||
| 234 | comptime try testSignedNegationWrappingEval(minInt(i16)); | ||
| 235 | } | ||
| 236 | fn testSignedNegationWrappingEval(x: i16) !void { | ||
| 237 | try expect(x == -32768); | ||
| 238 | const neg = -%x; | ||
| 239 | try expect(neg == -32768); | ||
| 240 | } | ||
| 241 | |||
| 242 | test "unsigned negation wrapping" { | ||
| 243 | try testUnsignedNegationWrappingEval(1); | ||
| 244 | comptime try testUnsignedNegationWrappingEval(1); | ||
| 245 | } | ||
| 246 | fn testUnsignedNegationWrappingEval(x: u16) !void { | ||
| 247 | try expect(x == 1); | ||
| 248 | const neg = -%x; | ||
| 249 | try expect(neg == maxInt(u16)); | ||
| 250 | } | ||
| 251 | |||
| 252 | test "unsigned 64-bit division" { | ||
| 253 | try test_u64_div(); | ||
| 254 | comptime try test_u64_div(); | ||
| 255 | } | ||
| 256 | fn test_u64_div() !void { | ||
| 257 | const result = divWithResult(1152921504606846976, 34359738365); | ||
| 258 | try expect(result.quotient == 33554432); | ||
| 259 | try expect(result.remainder == 100663296); | ||
| 260 | } | ||
| 261 | fn divWithResult(a: u64, b: u64) DivResult { | ||
| 262 | return DivResult{ | ||
| 263 | .quotient = a / b, | ||
| 264 | .remainder = a % b, | ||
| 265 | }; | ||
| 266 | } | ||
| 267 | const DivResult = struct { | ||
| 268 | quotient: u64, | ||
| 269 | remainder: u64, | ||
| 270 | }; | ||
| 271 | |||
| 272 | test "binary not" { | ||
| 273 | try expect(comptime x: { | ||
| 274 | break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101; | ||
| 275 | }); | ||
| 276 | try expect(comptime x: { | ||
| 277 | break :x ~@as(u64, 2147483647) == 18446744071562067968; | ||
| 278 | }); | ||
| 279 | try testBinaryNot(0b1010101010101010); | ||
| 280 | } | ||
| 281 | |||
| 282 | fn testBinaryNot(x: u16) !void { | ||
| 283 | try expect(~x == 0b0101010101010101); | ||
| 284 | } | ||
| 285 | |||
| 286 | test "small int addition" { | ||
| 287 | var x: u2 = 0; | ||
| 288 | try expect(x == 0); | ||
| 289 | |||
| 290 | x += 1; | ||
| 291 | try expect(x == 1); | ||
| 292 | |||
| 293 | x += 1; | ||
| 294 | try expect(x == 2); | ||
| 295 | |||
| 296 | x += 1; | ||
| 297 | try expect(x == 3); | ||
| 298 | |||
| 299 | var result: @TypeOf(x) = 3; | ||
| 300 | try expect(@addWithOverflow(@TypeOf(x), x, 1, &result)); | ||
| 301 | |||
| 302 | try expect(result == 0); | ||
| 303 | } | ||
| 304 | |||
| 305 | test "float equality" { | ||
| 306 | const x: f64 = 0.012; | ||
| 307 | const y: f64 = x + 1.0; | ||
| 308 | |||
| 309 | try testFloatEqualityImpl(x, y); | ||
| 310 | comptime try testFloatEqualityImpl(x, y); | ||
| 311 | } | ||
| 312 | |||
| 313 | fn testFloatEqualityImpl(x: f64, y: f64) !void { | ||
| 314 | const y2 = x + 1.0; | ||
| 315 | try expect(y == y2); | ||
| 316 | } | ||
| 317 | |||
| 318 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { | ||
| 319 | try expect(5 / 3 == 1); | ||
| 320 | try expect(-5 / -3 == 1); | ||
| 321 | try expect(-6 / 3 == -2); | ||
| 322 | |||
| 323 | try expect(5 % 3 == 2); | ||
| 324 | try expect(-6 % 3 == 0); | ||
| 325 | } | ||
| 326 | |||
| 327 | test "hex float literal parsing" { | ||
| 328 | comptime try expect(0x1.0 == 1.0); | ||
| 329 | } | ||
| 330 | |||
| 331 | test "quad hex float literal parsing in range" { | ||
| 332 | const a = 0x1.af23456789bbaaab347645365cdep+5; | ||
| 333 | const b = 0x1.dedafcff354b6ae9758763545432p-9; | ||
| 334 | const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; | ||
| 335 | const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; | ||
| 336 | } | ||
| 337 | |||
| 338 | test "quad hex float literal parsing accurate" { | ||
| 339 | const a: f128 = 0x1.1111222233334444555566667777p+0; | ||
| 340 | |||
| 341 | // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. | ||
| 342 | const expected: u128 = 0x3fff1111222233334444555566667777; | ||
| 343 | try expect(@bitCast(u128, a) == expected); | ||
| 344 | |||
| 345 | // non-normalized | ||
| 346 | const b: f128 = 0x11.111222233334444555566667777p-4; | ||
| 347 | try expect(@bitCast(u128, b) == expected); | ||
| 348 | |||
| 349 | const S = struct { | ||
| 350 | fn doTheTest() !void { | ||
| 351 | { | ||
| 352 | var f: f128 = 0x1.2eab345678439abcdefea56782346p+5; | ||
| 353 | try expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234); | ||
| 354 | } | ||
| 355 | { | ||
| 356 | var f: f128 = 0x1.edcb34a235253948765432134674fp-1; | ||
| 357 | try expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674); | ||
| 358 | } | ||
| 359 | { | ||
| 360 | var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50; | ||
| 361 | try expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff50); | ||
| 362 | } | ||
| 363 | { | ||
| 364 | var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9; | ||
| 365 | try expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214568); | ||
| 366 | } | ||
| 367 | const exp2ft = [_]f64{ | ||
| 368 | 0x1.6a09e667f3bcdp-1, | ||
| 369 | 0x1.7a11473eb0187p-1, | ||
| 370 | 0x1.8ace5422aa0dbp-1, | ||
| 371 | 0x1.9c49182a3f090p-1, | ||
| 372 | 0x1.ae89f995ad3adp-1, | ||
| 373 | 0x1.c199bdd85529cp-1, | ||
| 374 | 0x1.d5818dcfba487p-1, | ||
| 375 | 0x1.ea4afa2a490dap-1, | ||
| 376 | 0x1.0000000000000p+0, | ||
| 377 | 0x1.0b5586cf9890fp+0, | ||
| 378 | 0x1.172b83c7d517bp+0, | ||
| 379 | 0x1.2387a6e756238p+0, | ||
| 380 | 0x1.306fe0a31b715p+0, | ||
| 381 | 0x1.3dea64c123422p+0, | ||
| 382 | 0x1.4bfdad5362a27p+0, | ||
| 383 | 0x1.5ab07dd485429p+0, | ||
| 384 | 0x1.8p23, | ||
| 385 | 0x1.62e430p-1, | ||
| 386 | 0x1.ebfbe0p-3, | ||
| 387 | 0x1.c6b348p-5, | ||
| 388 | 0x1.3b2c9cp-7, | ||
| 389 | 0x1.0p127, | ||
| 390 | -0x1.0p-149, | ||
| 391 | }; | ||
| 392 | |||
| 393 | const answers = [_]u64{ | ||
| 394 | 0x3fe6a09e667f3bcd, | ||
| 395 | 0x3fe7a11473eb0187, | ||
| 396 | 0x3fe8ace5422aa0db, | ||
| 397 | 0x3fe9c49182a3f090, | ||
| 398 | 0x3feae89f995ad3ad, | ||
| 399 | 0x3fec199bdd85529c, | ||
| 400 | 0x3fed5818dcfba487, | ||
| 401 | 0x3feea4afa2a490da, | ||
| 402 | 0x3ff0000000000000, | ||
| 403 | 0x3ff0b5586cf9890f, | ||
| 404 | 0x3ff172b83c7d517b, | ||
| 405 | 0x3ff2387a6e756238, | ||
| 406 | 0x3ff306fe0a31b715, | ||
| 407 | 0x3ff3dea64c123422, | ||
| 408 | 0x3ff4bfdad5362a27, | ||
| 409 | 0x3ff5ab07dd485429, | ||
| 410 | 0x4168000000000000, | ||
| 411 | 0x3fe62e4300000000, | ||
| 412 | 0x3fcebfbe00000000, | ||
| 413 | 0x3fac6b3480000000, | ||
| 414 | 0x3f83b2c9c0000000, | ||
| 415 | 0x47e0000000000000, | ||
| 416 | 0xb6a0000000000000, | ||
| 417 | }; | ||
| 418 | |||
| 419 | for (exp2ft) |x, i| { | ||
| 420 | try expect(@bitCast(u64, x) == answers[i]); | ||
| 421 | } | ||
| 422 | } | ||
| 423 | }; | ||
| 424 | try S.doTheTest(); | ||
| 425 | comptime try S.doTheTest(); | ||
| 426 | } | ||
| 427 | |||
| 428 | test "underscore separator parsing" { | ||
| 429 | try expect(0_0_0_0 == 0); | ||
| 430 | try expect(1_234_567 == 1234567); | ||
| 431 | try expect(001_234_567 == 1234567); | ||
| 432 | try expect(0_0_1_2_3_4_5_6_7 == 1234567); | ||
| 433 | |||
| 434 | try expect(0b0_0_0_0 == 0); | ||
| 435 | try expect(0b1010_1010 == 0b10101010); | ||
| 436 | try expect(0b0000_1010_1010 == 0b10101010); | ||
| 437 | try expect(0b1_0_1_0_1_0_1_0 == 0b10101010); | ||
| 438 | |||
| 439 | try expect(0o0_0_0_0 == 0); | ||
| 440 | try expect(0o1010_1010 == 0o10101010); | ||
| 441 | try expect(0o0000_1010_1010 == 0o10101010); | ||
| 442 | try expect(0o1_0_1_0_1_0_1_0 == 0o10101010); | ||
| 443 | |||
| 444 | try expect(0x0_0_0_0 == 0); | ||
| 445 | try expect(0x1010_1010 == 0x10101010); | ||
| 446 | try expect(0x0000_1010_1010 == 0x10101010); | ||
| 447 | try expect(0x1_0_1_0_1_0_1_0 == 0x10101010); | ||
| 448 | |||
| 449 | try expect(123_456.789_000e1_0 == 123456.789000e10); | ||
| 450 | try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10); | ||
| 451 | |||
| 452 | try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10); | ||
| 453 | try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10); | ||
| 454 | } | ||
| 455 | |||
| 456 | test "hex float literal within range" { | ||
| 457 | const a = 0x1.0p16383; | ||
| 458 | const b = 0x0.1p16387; | ||
| 459 | const c = 0x1.0p-16382; | ||
| 460 | } | ||
| 461 | |||
| 462 | test "truncating shift left" { | ||
| 463 | try testShlTrunc(maxInt(u16)); | ||
| 464 | comptime try testShlTrunc(maxInt(u16)); | ||
| 465 | } | ||
| 466 | fn testShlTrunc(x: u16) !void { | ||
| 467 | const shifted = x << 1; | ||
| 468 | try expect(shifted == 65534); | ||
| 469 | } | ||
| 470 | |||
| 471 | test "truncating shift right" { | ||
| 472 | try testShrTrunc(maxInt(u16)); | ||
| 473 | comptime try testShrTrunc(maxInt(u16)); | ||
| 474 | } | ||
| 475 | fn testShrTrunc(x: u16) !void { | ||
| 476 | const shifted = x >> 1; | ||
| 477 | try expect(shifted == 32767); | ||
| 478 | } | ||
| 479 | |||
| 480 | test "exact shift left" { | ||
| 481 | try testShlExact(0b00110101); | ||
| 482 | comptime try testShlExact(0b00110101); | ||
| 483 | } | ||
| 484 | fn testShlExact(x: u8) !void { | ||
| 485 | const shifted = @shlExact(x, 2); | ||
| 486 | try expect(shifted == 0b11010100); | ||
| 487 | } | ||
| 488 | |||
| 489 | test "exact shift right" { | ||
| 490 | try testShrExact(0b10110100); | ||
| 491 | comptime try testShrExact(0b10110100); | ||
| 492 | } | ||
| 493 | fn testShrExact(x: u8) !void { | ||
| 494 | const shifted = @shrExact(x, 2); | ||
| 495 | try expect(shifted == 0b00101101); | ||
| 496 | } | ||
| 497 | |||
| 498 | test "shift left/right on u0 operand" { | ||
| 499 | const S = struct { | ||
| 500 | fn doTheTest() !void { | ||
| 501 | var x: u0 = 0; | ||
| 502 | var y: u0 = 0; | ||
| 503 | try expectEqual(@as(u0, 0), x << 0); | ||
| 504 | try expectEqual(@as(u0, 0), x >> 0); | ||
| 505 | try expectEqual(@as(u0, 0), x << y); | ||
| 506 | try expectEqual(@as(u0, 0), x >> y); | ||
| 507 | try expectEqual(@as(u0, 0), @shlExact(x, 0)); | ||
| 508 | try expectEqual(@as(u0, 0), @shrExact(x, 0)); | ||
| 509 | try expectEqual(@as(u0, 0), @shlExact(x, y)); | ||
| 510 | try expectEqual(@as(u0, 0), @shrExact(x, y)); | ||
| 511 | } | ||
| 512 | }; | ||
| 513 | try S.doTheTest(); | ||
| 514 | comptime try S.doTheTest(); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "comptime_int addition" { | ||
| 518 | comptime { | ||
| 519 | try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | ||
| 520 | try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | test "comptime_int multiplication" { | ||
| 525 | comptime { | ||
| 526 | try expect( | ||
| 527 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | ||
| 528 | ); | ||
| 529 | try expect( | ||
| 530 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | ||
| 531 | ); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | test "comptime_int shifting" { | ||
| 536 | comptime { | ||
| 537 | try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000); | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | test "comptime_int multi-limb shift and mask" { | ||
| 542 | comptime { | ||
| 543 | var a = 0xefffffffa0000001eeeeeeefaaaaaaab; | ||
| 544 | |||
| 545 | try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab); | ||
| 546 | a >>= 32; | ||
| 547 | try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef); | ||
| 548 | a >>= 32; | ||
| 549 | try expect(@as(u32, a & 0xffffffff) == 0xa0000001); | ||
| 550 | a >>= 32; | ||
| 551 | try expect(@as(u32, a & 0xffffffff) == 0xefffffff); | ||
| 552 | a >>= 32; | ||
| 553 | |||
| 554 | try expect(a == 0); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | test "comptime_int multi-limb partial shift right" { | ||
| 559 | comptime { | ||
| 560 | var a = 0x1ffffffffeeeeeeee; | ||
| 561 | a >>= 16; | ||
| 562 | try expect(a == 0x1ffffffffeeee); | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | test "xor" { | ||
| 567 | try test_xor(); | ||
| 568 | comptime try test_xor(); | ||
| 569 | } | ||
| 570 | |||
| 571 | fn test_xor() !void { | ||
| 572 | try expect(0xFF ^ 0x00 == 0xFF); | ||
| 573 | try expect(0xF0 ^ 0x0F == 0xFF); | ||
| 574 | try expect(0xFF ^ 0xF0 == 0x0F); | ||
| 575 | try expect(0xFF ^ 0x0F == 0xF0); | ||
| 576 | try expect(0xFF ^ 0xFF == 0x00); | ||
| 577 | } | ||
| 578 | |||
| 579 | test "comptime_int xor" { | ||
| 580 | comptime { | ||
| 581 | try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 582 | try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 583 | try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); | ||
| 584 | try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); | ||
| 585 | try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); | ||
| 586 | try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 587 | try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); | ||
| 588 | try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | test "f128" { | ||
| 593 | try test_f128(); | ||
| 594 | comptime try test_f128(); | ||
| 595 | } | ||
| 596 | |||
| 597 | fn make_f128(x: f128) f128 { | ||
| 598 | return x; | ||
| 599 | } | ||
| 600 | |||
| 601 | fn test_f128() !void { | ||
| 602 | try expect(@sizeOf(f128) == 16); | ||
| 603 | try expect(make_f128(1.0) == 1.0); | ||
| 604 | try expect(make_f128(1.0) != 1.1); | ||
| 605 | try expect(make_f128(1.0) > 0.9); | ||
| 606 | try expect(make_f128(1.0) >= 0.9); | ||
| 607 | try expect(make_f128(1.0) >= 1.0); | ||
| 608 | try should_not_be_zero(1.0); | ||
| 609 | } | ||
| 610 | |||
| 611 | fn should_not_be_zero(x: f128) !void { | ||
| 612 | try expect(x != 0.0); | ||
| 613 | } | ||
| 614 | |||
| 615 | test "comptime float rem int" { | ||
| 616 | comptime { | ||
| 617 | var x = @as(f32, 1) % 2; | ||
| 618 | try expect(x == 1.0); | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | test "remainder division" { | ||
| 623 | comptime try remdiv(f16); | ||
| 624 | comptime try remdiv(f32); | ||
| 625 | comptime try remdiv(f64); | ||
| 626 | comptime try remdiv(f128); | ||
| 627 | try remdiv(f16); | ||
| 628 | try remdiv(f64); | ||
| 629 | try remdiv(f128); | ||
| 630 | } | ||
| 631 | |||
| 632 | fn remdiv(comptime T: type) !void { | ||
| 633 | try expect(@as(T, 1) == @as(T, 1) % @as(T, 2)); | ||
| 634 | try expect(@as(T, 1) == @as(T, 7) % @as(T, 3)); | ||
| 635 | } | ||
| 636 | |||
| 637 | test "@sqrt" { | ||
| 638 | try testSqrt(f64, 12.0); | ||
| 639 | comptime try testSqrt(f64, 12.0); | ||
| 640 | try testSqrt(f32, 13.0); | ||
| 641 | comptime try testSqrt(f32, 13.0); | ||
| 642 | try testSqrt(f16, 13.0); | ||
| 643 | comptime try testSqrt(f16, 13.0); | ||
| 644 | |||
| 645 | const x = 14.0; | ||
| 646 | const y = x * x; | ||
| 647 | const z = @sqrt(y); | ||
| 648 | comptime try expect(z == x); | ||
| 649 | } | ||
| 650 | |||
| 651 | fn testSqrt(comptime T: type, x: T) !void { | ||
| 652 | try expect(@sqrt(x * x) == x); | ||
| 653 | } | ||
| 654 | |||
| 655 | test "@fabs" { | ||
| 656 | try testFabs(f128, 12.0); | ||
| 657 | comptime try testFabs(f128, 12.0); | ||
| 658 | try testFabs(f64, 12.0); | ||
| 659 | comptime try testFabs(f64, 12.0); | ||
| 660 | try testFabs(f32, 12.0); | ||
| 661 | comptime try testFabs(f32, 12.0); | ||
| 662 | try testFabs(f16, 12.0); | ||
| 663 | comptime try testFabs(f16, 12.0); | ||
| 664 | |||
| 665 | const x = 14.0; | ||
| 666 | const y = -x; | ||
| 667 | const z = @fabs(y); | ||
| 668 | comptime try expectEqual(x, z); | ||
| 669 | } | ||
| 670 | |||
| 671 | fn testFabs(comptime T: type, x: T) !void { | ||
| 672 | const y = -x; | ||
| 673 | const z = @fabs(y); | ||
| 674 | try expectEqual(x, z); | ||
| 675 | } | ||
| 676 | |||
| 677 | test "@floor" { | ||
| 678 | // FIXME: Generates a floorl function call | ||
| 679 | // testFloor(f128, 12.0); | ||
| 680 | comptime try testFloor(f128, 12.0); | ||
| 681 | try testFloor(f64, 12.0); | ||
| 682 | comptime try testFloor(f64, 12.0); | ||
| 683 | try testFloor(f32, 12.0); | ||
| 684 | comptime try testFloor(f32, 12.0); | ||
| 685 | try testFloor(f16, 12.0); | ||
| 686 | comptime try testFloor(f16, 12.0); | ||
| 687 | |||
| 688 | const x = 14.0; | ||
| 689 | const y = x + 0.7; | ||
| 690 | const z = @floor(y); | ||
| 691 | comptime try expectEqual(x, z); | ||
| 692 | } | ||
| 693 | |||
| 694 | fn testFloor(comptime T: type, x: T) !void { | ||
| 695 | const y = x + 0.6; | ||
| 696 | const z = @floor(y); | ||
| 697 | try expectEqual(x, z); | ||
| 698 | } | ||
| 699 | |||
| 700 | test "@ceil" { | ||
| 701 | // FIXME: Generates a ceill function call | ||
| 702 | //testCeil(f128, 12.0); | ||
| 703 | comptime try testCeil(f128, 12.0); | ||
| 704 | try testCeil(f64, 12.0); | ||
| 705 | comptime try testCeil(f64, 12.0); | ||
| 706 | try testCeil(f32, 12.0); | ||
| 707 | comptime try testCeil(f32, 12.0); | ||
| 708 | try testCeil(f16, 12.0); | ||
| 709 | comptime try testCeil(f16, 12.0); | ||
| 710 | |||
| 711 | const x = 14.0; | ||
| 712 | const y = x - 0.7; | ||
| 713 | const z = @ceil(y); | ||
| 714 | comptime try expectEqual(x, z); | ||
| 715 | } | ||
| 716 | |||
| 717 | fn testCeil(comptime T: type, x: T) !void { | ||
| 718 | const y = x - 0.8; | ||
| 719 | const z = @ceil(y); | ||
| 720 | try expectEqual(x, z); | ||
| 721 | } | ||
| 722 | |||
| 723 | test "@trunc" { | ||
| 724 | // FIXME: Generates a truncl function call | ||
| 725 | //testTrunc(f128, 12.0); | ||
| 726 | comptime try testTrunc(f128, 12.0); | ||
| 727 | try testTrunc(f64, 12.0); | ||
| 728 | comptime try testTrunc(f64, 12.0); | ||
| 729 | try testTrunc(f32, 12.0); | ||
| 730 | comptime try testTrunc(f32, 12.0); | ||
| 731 | try testTrunc(f16, 12.0); | ||
| 732 | comptime try testTrunc(f16, 12.0); | ||
| 733 | |||
| 734 | const x = 14.0; | ||
| 735 | const y = x + 0.7; | ||
| 736 | const z = @trunc(y); | ||
| 737 | comptime try expectEqual(x, z); | ||
| 738 | } | ||
| 739 | |||
| 740 | fn testTrunc(comptime T: type, x: T) !void { | ||
| 741 | { | ||
| 742 | const y = x + 0.8; | ||
| 743 | const z = @trunc(y); | ||
| 744 | try expectEqual(x, z); | ||
| 745 | } | ||
| 746 | |||
| 747 | { | ||
| 748 | const y = -x - 0.8; | ||
| 749 | const z = @trunc(y); | ||
| 750 | try expectEqual(-x, z); | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | test "@round" { | ||
| 755 | // FIXME: Generates a roundl function call | ||
| 756 | //testRound(f128, 12.0); | ||
| 757 | comptime try testRound(f128, 12.0); | ||
| 758 | try testRound(f64, 12.0); | ||
| 759 | comptime try testRound(f64, 12.0); | ||
| 760 | try testRound(f32, 12.0); | ||
| 761 | comptime try testRound(f32, 12.0); | ||
| 762 | try testRound(f16, 12.0); | ||
| 763 | comptime try testRound(f16, 12.0); | ||
| 764 | |||
| 765 | const x = 14.0; | ||
| 766 | const y = x + 0.4; | ||
| 767 | const z = @round(y); | ||
| 768 | comptime try expectEqual(x, z); | ||
| 769 | } | ||
| 770 | |||
| 771 | fn testRound(comptime T: type, x: T) !void { | ||
| 772 | const y = x - 0.5; | ||
| 773 | const z = @round(y); | ||
| 774 | try expectEqual(x, z); | ||
| 775 | } | ||
| 776 | |||
| 777 | test "comptime_int param and return" { | ||
| 778 | const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); | ||
| 779 | try expect(a == 137114567242441932203689521744947848950); | ||
| 780 | |||
| 781 | const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); | ||
| 782 | try expect(b == 985095453608931032642182098849559179469148836107390954364380); | ||
| 783 | } | ||
| 784 | |||
| 785 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | ||
| 786 | return a + b; | ||
| 787 | } | ||
| 788 | |||
| 789 | test "vector integer addition" { | ||
| 790 | const S = struct { | ||
| 791 | fn doTheTest() !void { | ||
| 792 | var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; | ||
| 793 | var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; | ||
| 794 | var result = a + b; | ||
| 795 | var result_array: [4]i32 = result; | ||
| 796 | const expected = [_]i32{ 6, 8, 10, 12 }; | ||
| 797 | try expectEqualSlices(i32, &expected, &result_array); | ||
| 798 | } | ||
| 799 | }; | ||
| 800 | try S.doTheTest(); | ||
| 801 | comptime try S.doTheTest(); | ||
| 802 | } | ||
| 803 | |||
| 804 | test "NaN comparison" { | ||
| 805 | try testNanEqNan(f16); | ||
| 806 | try testNanEqNan(f32); | ||
| 807 | try testNanEqNan(f64); | ||
| 808 | try testNanEqNan(f128); | ||
| 809 | comptime try testNanEqNan(f16); | ||
| 810 | comptime try testNanEqNan(f32); | ||
| 811 | comptime try testNanEqNan(f64); | ||
| 812 | comptime try testNanEqNan(f128); | ||
| 813 | } | ||
| 814 | |||
| 815 | fn testNanEqNan(comptime F: type) !void { | ||
| 816 | var nan1 = std.math.nan(F); | ||
| 817 | var nan2 = std.math.nan(F); | ||
| 818 | try expect(nan1 != nan2); | ||
| 819 | try expect(!(nan1 == nan2)); | ||
| 820 | try expect(!(nan1 > nan2)); | ||
| 821 | try expect(!(nan1 >= nan2)); | ||
| 822 | try expect(!(nan1 < nan2)); | ||
| 823 | try expect(!(nan1 <= nan2)); | ||
| 824 | } | ||
| 825 | |||
| 826 | test "128-bit multiplication" { | ||
| 827 | var a: i128 = 3; | ||
| 828 | var b: i128 = 2; | ||
| 829 | var c = a * b; | ||
| 830 | try expect(c == 6); | ||
| 831 | } | ||
| 832 | |||
| 833 | test "vector comparison" { | ||
| 834 | const S = struct { | ||
| 835 | fn doTheTest() !void { | ||
| 836 | var a: std.meta.Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 }; | ||
| 837 | var b: std.meta.Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 }; | ||
| 838 | try expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false })); | ||
| 839 | try expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false })); | ||
| 840 | try expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false })); | ||
| 841 | try expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true })); | ||
| 842 | try expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true })); | ||
| 843 | try expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true })); | ||
| 844 | } | ||
| 845 | }; | ||
| 846 | try S.doTheTest(); | ||
| 847 | comptime try S.doTheTest(); | ||
| 848 | } | ||
| 849 | |||
| 850 | test "compare undefined literal with comptime_int" { | ||
| 851 | var x = undefined == 1; | ||
| 852 | // x is now undefined with type bool | ||
| 853 | x = true; | ||
| 854 | try expect(x); | ||
| 855 | } | ||
| 856 | |||
| 857 | test "signed zeros are represented properly" { | ||
| 858 | const S = struct { | ||
| 859 | fn doTheTest() !void { | ||
| 860 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | ||
| 861 | const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | ||
| 862 | var as_fp_val = -@as(T, 0.0); | ||
| 863 | var as_uint_val = @bitCast(ST, as_fp_val); | ||
| 864 | // Ensure the sign bit is set. | ||
| 865 | try expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1); | ||
| 866 | } | ||
| 867 | } | ||
| 868 | }; | ||
| 869 | |||
| 870 | try S.doTheTest(); | ||
| 871 | comptime try S.doTheTest(); | ||
| 872 | } | ||
test/behavior/merge_error_sets.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const A = error{ | ||
| 2 | FileNotFound, | ||
| 3 | NotDir, | ||
| 4 | }; | ||
| 5 | const B = error{OutOfMemory}; | ||
| 6 | |||
| 7 | const C = A || B; | ||
| 8 | |||
| 9 | fn foo() C!void { | ||
| 10 | return error.NotDir; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "merge error sets" { | ||
| 14 | if (foo()) { | ||
| 15 | @panic("unexpected"); | ||
| 16 | } else |err| switch (err) { | ||
| 17 | error.OutOfMemory => @panic("unexpected"), | ||
| 18 | error.FileNotFound => @panic("unexpected"), | ||
| 19 | error.NotDir => {}, | ||
| 20 | } | ||
| 21 | } | ||
test/behavior/misc.zig created+761| ... | @@ -0,0 +1,761 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const mem = std.mem; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | |||
| 7 | // normal comment | ||
| 8 | |||
| 9 | /// this is a documentation comment | ||
| 10 | /// doc comment line 2 | ||
| 11 | fn emptyFunctionWithComments() void {} | ||
| 12 | |||
| 13 | test "empty function with comments" { | ||
| 14 | emptyFunctionWithComments(); | ||
| 15 | } | ||
| 16 | |||
| 17 | comptime { | ||
| 18 | @export(disabledExternFn, .{ .name = "disabledExternFn", .linkage = .Internal }); | ||
| 19 | } | ||
| 20 | |||
| 21 | fn disabledExternFn() callconv(.C) void {} | ||
| 22 | |||
| 23 | test "call disabled extern fn" { | ||
| 24 | disabledExternFn(); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "short circuit" { | ||
| 28 | try testShortCircuit(false, true); | ||
| 29 | comptime try testShortCircuit(false, true); | ||
| 30 | } | ||
| 31 | |||
| 32 | fn testShortCircuit(f: bool, t: bool) !void { | ||
| 33 | var hit_1 = f; | ||
| 34 | var hit_2 = f; | ||
| 35 | var hit_3 = f; | ||
| 36 | var hit_4 = f; | ||
| 37 | |||
| 38 | if (t or x: { | ||
| 39 | try expect(f); | ||
| 40 | break :x f; | ||
| 41 | }) { | ||
| 42 | hit_1 = t; | ||
| 43 | } | ||
| 44 | if (f or x: { | ||
| 45 | hit_2 = t; | ||
| 46 | break :x f; | ||
| 47 | }) { | ||
| 48 | try expect(f); | ||
| 49 | } | ||
| 50 | |||
| 51 | if (t and x: { | ||
| 52 | hit_3 = t; | ||
| 53 | break :x f; | ||
| 54 | }) { | ||
| 55 | try expect(f); | ||
| 56 | } | ||
| 57 | if (f and x: { | ||
| 58 | try expect(f); | ||
| 59 | break :x f; | ||
| 60 | }) { | ||
| 61 | try expect(f); | ||
| 62 | } else { | ||
| 63 | hit_4 = t; | ||
| 64 | } | ||
| 65 | try expect(hit_1); | ||
| 66 | try expect(hit_2); | ||
| 67 | try expect(hit_3); | ||
| 68 | try expect(hit_4); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "truncate" { | ||
| 72 | try expect(testTruncate(0x10fd) == 0xfd); | ||
| 73 | } | ||
| 74 | fn testTruncate(x: u32) u8 { | ||
| 75 | return @truncate(u8, x); | ||
| 76 | } | ||
| 77 | |||
| 78 | fn first4KeysOfHomeRow() []const u8 { | ||
| 79 | return "aoeu"; | ||
| 80 | } | ||
| 81 | |||
| 82 | test "return string from function" { | ||
| 83 | try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 84 | } | ||
| 85 | |||
| 86 | const g1: i32 = 1233 + 1; | ||
| 87 | var g2: i32 = 0; | ||
| 88 | |||
| 89 | test "global variables" { | ||
| 90 | try expect(g2 == 0); | ||
| 91 | g2 = g1; | ||
| 92 | try expect(g2 == 1234); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "memcpy and memset intrinsics" { | ||
| 96 | var foo: [20]u8 = undefined; | ||
| 97 | var bar: [20]u8 = undefined; | ||
| 98 | |||
| 99 | @memset(&foo, 'A', foo.len); | ||
| 100 | @memcpy(&bar, &foo, bar.len); | ||
| 101 | |||
| 102 | if (bar[11] != 'A') unreachable; | ||
| 103 | } | ||
| 104 | |||
| 105 | test "builtin static eval" { | ||
| 106 | const x: i32 = comptime x: { | ||
| 107 | break :x 1 + 2 + 3; | ||
| 108 | }; | ||
| 109 | try expect(x == comptime 6); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "slicing" { | ||
| 113 | var array: [20]i32 = undefined; | ||
| 114 | |||
| 115 | array[5] = 1234; | ||
| 116 | |||
| 117 | var slice = array[5..10]; | ||
| 118 | |||
| 119 | if (slice.len != 5) unreachable; | ||
| 120 | |||
| 121 | const ptr = &slice[0]; | ||
| 122 | if (ptr.* != 1234) unreachable; | ||
| 123 | |||
| 124 | var slice_rest = array[10..]; | ||
| 125 | if (slice_rest.len != 10) unreachable; | ||
| 126 | } | ||
| 127 | |||
| 128 | test "constant equal function pointers" { | ||
| 129 | const alias = emptyFn; | ||
| 130 | try expect(comptime x: { | ||
| 131 | break :x emptyFn == alias; | ||
| 132 | }); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn emptyFn() void {} | ||
| 136 | |||
| 137 | test "hex escape" { | ||
| 138 | try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "string concatenation" { | ||
| 142 | try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); | ||
| 143 | } | ||
| 144 | |||
| 145 | test "array mult operator" { | ||
| 146 | try expect(mem.eql(u8, "ab" ** 5, "ababababab")); | ||
| 147 | } | ||
| 148 | |||
| 149 | test "string escapes" { | ||
| 150 | try expect(mem.eql(u8, "\"", "\x22")); | ||
| 151 | try expect(mem.eql(u8, "\'", "\x27")); | ||
| 152 | try expect(mem.eql(u8, "\n", "\x0a")); | ||
| 153 | try expect(mem.eql(u8, "\r", "\x0d")); | ||
| 154 | try expect(mem.eql(u8, "\t", "\x09")); | ||
| 155 | try expect(mem.eql(u8, "\\", "\x5c")); | ||
| 156 | try expect(mem.eql(u8, "\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01")); | ||
| 157 | } | ||
| 158 | |||
| 159 | test "multiline string" { | ||
| 160 | const s1 = | ||
| 161 | \\one | ||
| 162 | \\two) | ||
| 163 | \\three | ||
| 164 | ; | ||
| 165 | const s2 = "one\ntwo)\nthree"; | ||
| 166 | try expect(mem.eql(u8, s1, s2)); | ||
| 167 | } | ||
| 168 | |||
| 169 | test "multiline string comments at start" { | ||
| 170 | const s1 = | ||
| 171 | //\\one | ||
| 172 | \\two) | ||
| 173 | \\three | ||
| 174 | ; | ||
| 175 | const s2 = "two)\nthree"; | ||
| 176 | try expect(mem.eql(u8, s1, s2)); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "multiline string comments at end" { | ||
| 180 | const s1 = | ||
| 181 | \\one | ||
| 182 | \\two) | ||
| 183 | //\\three | ||
| 184 | ; | ||
| 185 | const s2 = "one\ntwo)"; | ||
| 186 | try expect(mem.eql(u8, s1, s2)); | ||
| 187 | } | ||
| 188 | |||
| 189 | test "multiline string comments in middle" { | ||
| 190 | const s1 = | ||
| 191 | \\one | ||
| 192 | //\\two) | ||
| 193 | \\three | ||
| 194 | ; | ||
| 195 | const s2 = "one\nthree"; | ||
| 196 | try expect(mem.eql(u8, s1, s2)); | ||
| 197 | } | ||
| 198 | |||
| 199 | test "multiline string comments at multiple places" { | ||
| 200 | const s1 = | ||
| 201 | \\one | ||
| 202 | //\\two | ||
| 203 | \\three | ||
| 204 | //\\four | ||
| 205 | \\five | ||
| 206 | ; | ||
| 207 | const s2 = "one\nthree\nfive"; | ||
| 208 | try expect(mem.eql(u8, s1, s2)); | ||
| 209 | } | ||
| 210 | |||
| 211 | test "multiline C string" { | ||
| 212 | const s1 = | ||
| 213 | \\one | ||
| 214 | \\two) | ||
| 215 | \\three | ||
| 216 | ; | ||
| 217 | const s2 = "one\ntwo)\nthree"; | ||
| 218 | try expect(std.cstr.cmp(s1, s2) == 0); | ||
| 219 | } | ||
| 220 | |||
| 221 | test "type equality" { | ||
| 222 | try expect(*const u8 != *u8); | ||
| 223 | } | ||
| 224 | |||
| 225 | const global_a: i32 = 1234; | ||
| 226 | const global_b: *const i32 = &global_a; | ||
| 227 | const global_c: *const f32 = @ptrCast(*const f32, global_b); | ||
| 228 | test "compile time global reinterpret" { | ||
| 229 | const d = @ptrCast(*const i32, global_c); | ||
| 230 | try expect(d.* == 1234); | ||
| 231 | } | ||
| 232 | |||
| 233 | test "explicit cast maybe pointers" { | ||
| 234 | const a: ?*i32 = undefined; | ||
| 235 | const b: ?*f32 = @ptrCast(?*f32, a); | ||
| 236 | } | ||
| 237 | |||
| 238 | test "generic malloc free" { | ||
| 239 | const a = memAlloc(u8, 10) catch unreachable; | ||
| 240 | memFree(u8, a); | ||
| 241 | } | ||
| 242 | var some_mem: [100]u8 = undefined; | ||
| 243 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | ||
| 244 | return @ptrCast([*]T, &some_mem[0])[0..n]; | ||
| 245 | } | ||
| 246 | fn memFree(comptime T: type, memory: []T) void {} | ||
| 247 | |||
| 248 | test "cast undefined" { | ||
| 249 | const array: [100]u8 = undefined; | ||
| 250 | const slice = @as([]const u8, &array); | ||
| 251 | testCastUndefined(slice); | ||
| 252 | } | ||
| 253 | fn testCastUndefined(x: []const u8) void {} | ||
| 254 | |||
| 255 | test "cast small unsigned to larger signed" { | ||
| 256 | try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200)); | ||
| 257 | try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999)); | ||
| 258 | } | ||
| 259 | fn castSmallUnsignedToLargerSigned1(x: u8) i16 { | ||
| 260 | return x; | ||
| 261 | } | ||
| 262 | fn castSmallUnsignedToLargerSigned2(x: u16) i64 { | ||
| 263 | return x; | ||
| 264 | } | ||
| 265 | |||
| 266 | test "implicit cast after unreachable" { | ||
| 267 | try expect(outer() == 1234); | ||
| 268 | } | ||
| 269 | fn inner() i32 { | ||
| 270 | return 1234; | ||
| 271 | } | ||
| 272 | fn outer() i64 { | ||
| 273 | return inner(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "pointer dereferencing" { | ||
| 277 | var x = @as(i32, 3); | ||
| 278 | const y = &x; | ||
| 279 | |||
| 280 | y.* += 1; | ||
| 281 | |||
| 282 | try expect(x == 4); | ||
| 283 | try expect(y.* == 4); | ||
| 284 | } | ||
| 285 | |||
| 286 | test "call result of if else expression" { | ||
| 287 | try expect(mem.eql(u8, f2(true), "a")); | ||
| 288 | try expect(mem.eql(u8, f2(false), "b")); | ||
| 289 | } | ||
| 290 | fn f2(x: bool) []const u8 { | ||
| 291 | return (if (x) fA else fB)(); | ||
| 292 | } | ||
| 293 | fn fA() []const u8 { | ||
| 294 | return "a"; | ||
| 295 | } | ||
| 296 | fn fB() []const u8 { | ||
| 297 | return "b"; | ||
| 298 | } | ||
| 299 | |||
| 300 | test "const expression eval handling of variables" { | ||
| 301 | var x = true; | ||
| 302 | while (x) { | ||
| 303 | x = false; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | test "constant enum initialization with differing sizes" { | ||
| 308 | try test3_1(test3_foo); | ||
| 309 | try test3_2(test3_bar); | ||
| 310 | } | ||
| 311 | const Test3Foo = union(enum) { | ||
| 312 | One: void, | ||
| 313 | Two: f32, | ||
| 314 | Three: Test3Point, | ||
| 315 | }; | ||
| 316 | const Test3Point = struct { | ||
| 317 | x: i32, | ||
| 318 | y: i32, | ||
| 319 | }; | ||
| 320 | const test3_foo = Test3Foo{ | ||
| 321 | .Three = Test3Point{ | ||
| 322 | .x = 3, | ||
| 323 | .y = 4, | ||
| 324 | }, | ||
| 325 | }; | ||
| 326 | const test3_bar = Test3Foo{ .Two = 13 }; | ||
| 327 | fn test3_1(f: Test3Foo) !void { | ||
| 328 | switch (f) { | ||
| 329 | Test3Foo.Three => |pt| { | ||
| 330 | try expect(pt.x == 3); | ||
| 331 | try expect(pt.y == 4); | ||
| 332 | }, | ||
| 333 | else => unreachable, | ||
| 334 | } | ||
| 335 | } | ||
| 336 | fn test3_2(f: Test3Foo) !void { | ||
| 337 | switch (f) { | ||
| 338 | Test3Foo.Two => |x| { | ||
| 339 | try expect(x == 13); | ||
| 340 | }, | ||
| 341 | else => unreachable, | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | test "character literals" { | ||
| 346 | try expect('\'' == single_quote); | ||
| 347 | } | ||
| 348 | const single_quote = '\''; | ||
| 349 | |||
| 350 | test "take address of parameter" { | ||
| 351 | try testTakeAddressOfParameter(12.34); | ||
| 352 | } | ||
| 353 | fn testTakeAddressOfParameter(f: f32) !void { | ||
| 354 | const f_ptr = &f; | ||
| 355 | try expect(f_ptr.* == 12.34); | ||
| 356 | } | ||
| 357 | |||
| 358 | test "pointer comparison" { | ||
| 359 | const a = @as([]const u8, "a"); | ||
| 360 | const b = &a; | ||
| 361 | try expect(ptrEql(b, b)); | ||
| 362 | } | ||
| 363 | fn ptrEql(a: *const []const u8, b: *const []const u8) bool { | ||
| 364 | return a == b; | ||
| 365 | } | ||
| 366 | |||
| 367 | test "string concatenation" { | ||
| 368 | const a = "OK" ++ " IT " ++ "WORKED"; | ||
| 369 | const b = "OK IT WORKED"; | ||
| 370 | |||
| 371 | comptime try expect(@TypeOf(a) == *const [12:0]u8); | ||
| 372 | comptime try expect(@TypeOf(b) == *const [12:0]u8); | ||
| 373 | |||
| 374 | const len = mem.len(b); | ||
| 375 | const len_with_null = len + 1; | ||
| 376 | { | ||
| 377 | var i: u32 = 0; | ||
| 378 | while (i < len_with_null) : (i += 1) { | ||
| 379 | try expect(a[i] == b[i]); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | try expect(a[len] == 0); | ||
| 383 | try expect(b[len] == 0); | ||
| 384 | } | ||
| 385 | |||
| 386 | test "pointer to void return type" { | ||
| 387 | testPointerToVoidReturnType() catch unreachable; | ||
| 388 | } | ||
| 389 | fn testPointerToVoidReturnType() anyerror!void { | ||
| 390 | const a = testPointerToVoidReturnType2(); | ||
| 391 | return a.*; | ||
| 392 | } | ||
| 393 | const test_pointer_to_void_return_type_x = void{}; | ||
| 394 | fn testPointerToVoidReturnType2() *const void { | ||
| 395 | return &test_pointer_to_void_return_type_x; | ||
| 396 | } | ||
| 397 | |||
| 398 | test "non const ptr to aliased type" { | ||
| 399 | const int = i32; | ||
| 400 | try expect(?*int == ?*i32); | ||
| 401 | } | ||
| 402 | |||
| 403 | test "array 2D const double ptr" { | ||
| 404 | const rect_2d_vertexes = [_][1]f32{ | ||
| 405 | [_]f32{1.0}, | ||
| 406 | [_]f32{2.0}, | ||
| 407 | }; | ||
| 408 | try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); | ||
| 409 | } | ||
| 410 | |||
| 411 | fn testArray2DConstDoublePtr(ptr: *const f32) !void { | ||
| 412 | const ptr2 = @ptrCast([*]const f32, ptr); | ||
| 413 | try expect(ptr2[0] == 1.0); | ||
| 414 | try expect(ptr2[1] == 2.0); | ||
| 415 | } | ||
| 416 | |||
| 417 | const AStruct = struct { | ||
| 418 | x: i32, | ||
| 419 | }; | ||
| 420 | const AnEnum = enum { | ||
| 421 | One, | ||
| 422 | Two, | ||
| 423 | }; | ||
| 424 | const AUnionEnum = union(enum) { | ||
| 425 | One: i32, | ||
| 426 | Two: void, | ||
| 427 | }; | ||
| 428 | const AUnion = union { | ||
| 429 | One: void, | ||
| 430 | Two: void, | ||
| 431 | }; | ||
| 432 | |||
| 433 | test "@typeName" { | ||
| 434 | const Struct = struct {}; | ||
| 435 | const Union = union { | ||
| 436 | unused: u8, | ||
| 437 | }; | ||
| 438 | const Enum = enum { | ||
| 439 | Unused, | ||
| 440 | }; | ||
| 441 | comptime { | ||
| 442 | try expect(mem.eql(u8, @typeName(i64), "i64")); | ||
| 443 | try expect(mem.eql(u8, @typeName(*usize), "*usize")); | ||
| 444 | // https://github.com/ziglang/zig/issues/675 | ||
| 445 | try expect(mem.eql(u8, "behavior.misc.TypeFromFn(u8)", @typeName(TypeFromFn(u8)))); | ||
| 446 | try expect(mem.eql(u8, @typeName(Struct), "Struct")); | ||
| 447 | try expect(mem.eql(u8, @typeName(Union), "Union")); | ||
| 448 | try expect(mem.eql(u8, @typeName(Enum), "Enum")); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | fn TypeFromFn(comptime T: type) type { | ||
| 453 | return struct {}; | ||
| 454 | } | ||
| 455 | |||
| 456 | test "double implicit cast in same expression" { | ||
| 457 | var x = @as(i32, @as(u16, nine())); | ||
| 458 | try expect(x == 9); | ||
| 459 | } | ||
| 460 | fn nine() u8 { | ||
| 461 | return 9; | ||
| 462 | } | ||
| 463 | |||
| 464 | test "global variable initialized to global variable array element" { | ||
| 465 | try expect(global_ptr == &gdt[0]); | ||
| 466 | } | ||
| 467 | const GDTEntry = struct { | ||
| 468 | field: i32, | ||
| 469 | }; | ||
| 470 | var gdt = [_]GDTEntry{ | ||
| 471 | GDTEntry{ .field = 1 }, | ||
| 472 | GDTEntry{ .field = 2 }, | ||
| 473 | }; | ||
| 474 | var global_ptr = &gdt[0]; | ||
| 475 | |||
| 476 | // can't really run this test but we can make sure it has no compile error | ||
| 477 | // and generates code | ||
| 478 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 479 | export fn writeToVRam() void { | ||
| 480 | vram[0] = 'X'; | ||
| 481 | } | ||
| 482 | |||
| 483 | const OpaqueA = opaque {}; | ||
| 484 | const OpaqueB = opaque {}; | ||
| 485 | test "opaque types" { | ||
| 486 | try expect(*OpaqueA != *OpaqueB); | ||
| 487 | try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); | ||
| 488 | try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | ||
| 489 | } | ||
| 490 | |||
| 491 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 492 | var x: i32 = 1234; | ||
| 493 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 494 | } | ||
| 495 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 496 | var a = ptr; | ||
| 497 | return a; | ||
| 498 | } | ||
| 499 | |||
| 500 | test "comptime if inside runtime while which unconditionally breaks" { | ||
| 501 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 502 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 503 | } | ||
| 504 | fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { | ||
| 505 | while (cond) { | ||
| 506 | if (false) {} | ||
| 507 | break; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | test "implicit comptime while" { | ||
| 512 | while (false) { | ||
| 513 | @compileError("bad"); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | fn fnThatClosesOverLocalConst() type { | ||
| 518 | const c = 1; | ||
| 519 | return struct { | ||
| 520 | fn g() i32 { | ||
| 521 | return c; | ||
| 522 | } | ||
| 523 | }; | ||
| 524 | } | ||
| 525 | |||
| 526 | test "function closes over local const" { | ||
| 527 | const x = fnThatClosesOverLocalConst().g(); | ||
| 528 | try expect(x == 1); | ||
| 529 | } | ||
| 530 | |||
| 531 | test "cold function" { | ||
| 532 | thisIsAColdFn(); | ||
| 533 | comptime thisIsAColdFn(); | ||
| 534 | } | ||
| 535 | |||
| 536 | fn thisIsAColdFn() void { | ||
| 537 | @setCold(true); | ||
| 538 | } | ||
| 539 | |||
| 540 | const PackedStruct = packed struct { | ||
| 541 | a: u8, | ||
| 542 | b: u8, | ||
| 543 | }; | ||
| 544 | const PackedUnion = packed union { | ||
| 545 | a: u8, | ||
| 546 | b: u32, | ||
| 547 | }; | ||
| 548 | const PackedEnum = packed enum { | ||
| 549 | A, | ||
| 550 | B, | ||
| 551 | }; | ||
| 552 | |||
| 553 | test "packed struct, enum, union parameters in extern function" { | ||
| 554 | testPackedStuff(&(PackedStruct{ | ||
| 555 | .a = 1, | ||
| 556 | .b = 2, | ||
| 557 | }), &(PackedUnion{ .a = 1 }), PackedEnum.A); | ||
| 558 | } | ||
| 559 | |||
| 560 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} | ||
| 561 | |||
| 562 | test "slicing zero length array" { | ||
| 563 | const s1 = ""[0..]; | ||
| 564 | const s2 = ([_]u32{})[0..]; | ||
| 565 | try expect(s1.len == 0); | ||
| 566 | try expect(s2.len == 0); | ||
| 567 | try expect(mem.eql(u8, s1, "")); | ||
| 568 | try expect(mem.eql(u32, s2, &[_]u32{})); | ||
| 569 | } | ||
| 570 | |||
| 571 | const addr1 = @ptrCast(*const u8, emptyFn); | ||
| 572 | test "comptime cast fn to ptr" { | ||
| 573 | const addr2 = @ptrCast(*const u8, emptyFn); | ||
| 574 | comptime try expect(addr1 == addr2); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "equality compare fn ptrs" { | ||
| 578 | var a = emptyFn; | ||
| 579 | try expect(a == a); | ||
| 580 | } | ||
| 581 | |||
| 582 | test "self reference through fn ptr field" { | ||
| 583 | const S = struct { | ||
| 584 | const A = struct { | ||
| 585 | f: fn (A) u8, | ||
| 586 | }; | ||
| 587 | |||
| 588 | fn foo(a: A) u8 { | ||
| 589 | return 12; | ||
| 590 | } | ||
| 591 | }; | ||
| 592 | var a: S.A = undefined; | ||
| 593 | a.f = S.foo; | ||
| 594 | try expect(a.f(a) == 12); | ||
| 595 | } | ||
| 596 | |||
| 597 | test "volatile load and store" { | ||
| 598 | var number: i32 = 1234; | ||
| 599 | const ptr = @as(*volatile i32, &number); | ||
| 600 | ptr.* += 1; | ||
| 601 | try expect(ptr.* == 1235); | ||
| 602 | } | ||
| 603 | |||
| 604 | test "slice string literal has correct type" { | ||
| 605 | comptime { | ||
| 606 | try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); | ||
| 607 | const array = [_]i32{ 1, 2, 3, 4 }; | ||
| 608 | try expect(@TypeOf(array[0..]) == *const [4]i32); | ||
| 609 | } | ||
| 610 | var runtime_zero: usize = 0; | ||
| 611 | comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); | ||
| 612 | const array = [_]i32{ 1, 2, 3, 4 }; | ||
| 613 | comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); | ||
| 614 | } | ||
| 615 | |||
| 616 | test "struct inside function" { | ||
| 617 | try testStructInFn(); | ||
| 618 | comptime try testStructInFn(); | ||
| 619 | } | ||
| 620 | |||
| 621 | fn testStructInFn() !void { | ||
| 622 | const BlockKind = u32; | ||
| 623 | |||
| 624 | const Block = struct { | ||
| 625 | kind: BlockKind, | ||
| 626 | }; | ||
| 627 | |||
| 628 | var block = Block{ .kind = 1234 }; | ||
| 629 | |||
| 630 | block.kind += 1; | ||
| 631 | |||
| 632 | try expect(block.kind == 1235); | ||
| 633 | } | ||
| 634 | |||
| 635 | test "fn call returning scalar optional in equality expression" { | ||
| 636 | try expect(getNull() == null); | ||
| 637 | } | ||
| 638 | |||
| 639 | fn getNull() ?*i32 { | ||
| 640 | return null; | ||
| 641 | } | ||
| 642 | |||
| 643 | test "thread local variable" { | ||
| 644 | const S = struct { | ||
| 645 | threadlocal var t: i32 = 1234; | ||
| 646 | }; | ||
| 647 | S.t += 1; | ||
| 648 | try expect(S.t == 1235); | ||
| 649 | } | ||
| 650 | |||
| 651 | test "unicode escape in character literal" { | ||
| 652 | var a: u24 = '\u{01f4a9}'; | ||
| 653 | try expect(a == 128169); | ||
| 654 | } | ||
| 655 | |||
| 656 | test "unicode character in character literal" { | ||
| 657 | try expect('💩' == 128169); | ||
| 658 | } | ||
| 659 | |||
| 660 | test "result location zero sized array inside struct field implicit cast to slice" { | ||
| 661 | const E = struct { | ||
| 662 | entries: []u32, | ||
| 663 | }; | ||
| 664 | var foo = E{ .entries = &[_]u32{} }; | ||
| 665 | try expect(foo.entries.len == 0); | ||
| 666 | } | ||
| 667 | |||
| 668 | var global_foo: *i32 = undefined; | ||
| 669 | |||
| 670 | test "global variable assignment with optional unwrapping with var initialized to undefined" { | ||
| 671 | const S = struct { | ||
| 672 | var data: i32 = 1234; | ||
| 673 | fn foo() ?*i32 { | ||
| 674 | return &data; | ||
| 675 | } | ||
| 676 | }; | ||
| 677 | global_foo = S.foo() orelse { | ||
| 678 | @panic("bad"); | ||
| 679 | }; | ||
| 680 | try expect(global_foo.* == 1234); | ||
| 681 | } | ||
| 682 | |||
| 683 | test "peer result location with typed parent, runtime condition, comptime prongs" { | ||
| 684 | const S = struct { | ||
| 685 | fn doTheTest(arg: i32) i32 { | ||
| 686 | const st = Structy{ | ||
| 687 | .bleh = if (arg == 1) 1 else 1, | ||
| 688 | }; | ||
| 689 | |||
| 690 | if (st.bleh == 1) | ||
| 691 | return 1234; | ||
| 692 | return 0; | ||
| 693 | } | ||
| 694 | |||
| 695 | const Structy = struct { | ||
| 696 | bleh: i32, | ||
| 697 | }; | ||
| 698 | }; | ||
| 699 | try expect(S.doTheTest(0) == 1234); | ||
| 700 | try expect(S.doTheTest(1) == 1234); | ||
| 701 | } | ||
| 702 | |||
| 703 | test "nested optional field in struct" { | ||
| 704 | const S2 = struct { | ||
| 705 | y: u8, | ||
| 706 | }; | ||
| 707 | const S1 = struct { | ||
| 708 | x: ?S2, | ||
| 709 | }; | ||
| 710 | var s = S1{ | ||
| 711 | .x = S2{ .y = 127 }, | ||
| 712 | }; | ||
| 713 | try expect(s.x.?.y == 127); | ||
| 714 | } | ||
| 715 | |||
| 716 | fn maybe(x: bool) anyerror!?u32 { | ||
| 717 | return switch (x) { | ||
| 718 | true => @as(u32, 42), | ||
| 719 | else => null, | ||
| 720 | }; | ||
| 721 | } | ||
| 722 | |||
| 723 | test "result location is optional inside error union" { | ||
| 724 | const x = maybe(true) catch unreachable; | ||
| 725 | try expect(x.? == 42); | ||
| 726 | } | ||
| 727 | |||
| 728 | threadlocal var buffer: [11]u8 = undefined; | ||
| 729 | |||
| 730 | test "pointer to thread local array" { | ||
| 731 | const s = "Hello world"; | ||
| 732 | std.mem.copy(u8, buffer[0..], s); | ||
| 733 | try std.testing.expectEqualSlices(u8, buffer[0..], s); | ||
| 734 | } | ||
| 735 | |||
| 736 | test "auto created variables have correct alignment" { | ||
| 737 | const S = struct { | ||
| 738 | fn foo(str: [*]const u8) u32 { | ||
| 739 | for (@ptrCast([*]align(1) const u32, str)[0..1]) |v| { | ||
| 740 | return v; | ||
| 741 | } | ||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | }; | ||
| 745 | try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); | ||
| 746 | comptime try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); | ||
| 747 | } | ||
| 748 | |||
| 749 | extern var opaque_extern_var: opaque {}; | ||
| 750 | var var_to_export: u32 = 42; | ||
| 751 | test "extern variable with non-pointer opaque type" { | ||
| 752 | @export(var_to_export, .{ .name = "opaque_extern_var" }); | ||
| 753 | try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42); | ||
| 754 | } | ||
| 755 | |||
| 756 | test "lazy typeInfo value as generic parameter" { | ||
| 757 | const S = struct { | ||
| 758 | fn foo(args: anytype) void {} | ||
| 759 | }; | ||
| 760 | S.foo(@typeInfo(@TypeOf(.{}))); | ||
| 761 | } | ||
test/behavior/muladd.zig created+34| ... | @@ -0,0 +1,34 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@mulAdd" { | ||
| 4 | comptime try testMulAdd(); | ||
| 5 | try testMulAdd(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testMulAdd() !void { | ||
| 9 | { | ||
| 10 | var a: f16 = 5.5; | ||
| 11 | var b: f16 = 2.5; | ||
| 12 | var c: f16 = 6.25; | ||
| 13 | try expect(@mulAdd(f16, a, b, c) == 20); | ||
| 14 | } | ||
| 15 | { | ||
| 16 | var a: f32 = 5.5; | ||
| 17 | var b: f32 = 2.5; | ||
| 18 | var c: f32 = 6.25; | ||
| 19 | try expect(@mulAdd(f32, a, b, c) == 20); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var a: f64 = 5.5; | ||
| 23 | var b: f64 = 2.5; | ||
| 24 | var c: f64 = 6.25; | ||
| 25 | try expect(@mulAdd(f64, a, b, c) == 20); | ||
| 26 | } | ||
| 27 | // Awaits implementation in libm.zig | ||
| 28 | //{ | ||
| 29 | // var a: f16 = 5.5; | ||
| 30 | // var b: f128 = 2.5; | ||
| 31 | // var c: f128 = 6.25; | ||
| 32 | //try expect(@mulAdd(f128, a, b, c) == 20); | ||
| 33 | //} | ||
| 34 | } | ||
test/behavior/namespace_depends_on_compile_var.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "namespace depends on compile var" { | ||
| 5 | if (some_namespace.a_bool) { | ||
| 6 | try expect(some_namespace.a_bool); | ||
| 7 | } else { | ||
| 8 | try expect(!some_namespace.a_bool); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | const some_namespace = switch (std.builtin.os.tag) { | ||
| 12 | .linux => @import("namespace_depends_on_compile_var/a.zig"), | ||
| 13 | else => @import("namespace_depends_on_compile_var/b.zig"), | ||
| 14 | }; | ||
test/behavior/namespace_depends_on_compile_var/a.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const a_bool = true; | ||
test/behavior/namespace_depends_on_compile_var/b.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const a_bool = false; | ||
test/behavior/null.zig created+162| ... | @@ -0,0 +1,162 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "optional type" { | ||
| 4 | const x: ?bool = true; | ||
| 5 | |||
| 6 | if (x) |y| { | ||
| 7 | if (y) { | ||
| 8 | // OK | ||
| 9 | } else { | ||
| 10 | unreachable; | ||
| 11 | } | ||
| 12 | } else { | ||
| 13 | unreachable; | ||
| 14 | } | ||
| 15 | |||
| 16 | const next_x: ?i32 = null; | ||
| 17 | |||
| 18 | const z = next_x orelse 1234; | ||
| 19 | |||
| 20 | try expect(z == 1234); | ||
| 21 | |||
| 22 | const final_x: ?i32 = 13; | ||
| 23 | |||
| 24 | const num = final_x orelse unreachable; | ||
| 25 | |||
| 26 | try expect(num == 13); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "test maybe object and get a pointer to the inner value" { | ||
| 30 | var maybe_bool: ?bool = true; | ||
| 31 | |||
| 32 | if (maybe_bool) |*b| { | ||
| 33 | b.* = false; | ||
| 34 | } | ||
| 35 | |||
| 36 | try expect(maybe_bool.? == false); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "rhs maybe unwrap return" { | ||
| 40 | const x: ?bool = true; | ||
| 41 | const y = x orelse return; | ||
| 42 | } | ||
| 43 | |||
| 44 | test "maybe return" { | ||
| 45 | try maybeReturnImpl(); | ||
| 46 | comptime try maybeReturnImpl(); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn maybeReturnImpl() !void { | ||
| 50 | try expect(foo(1235).?); | ||
| 51 | if (foo(null) != null) unreachable; | ||
| 52 | try expect(!foo(1234).?); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn foo(x: ?i32) ?bool { | ||
| 56 | const value = x orelse return null; | ||
| 57 | return value > 1234; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "if var maybe pointer" { | ||
| 61 | try expect(shouldBeAPlus1(Particle{ | ||
| 62 | .a = 14, | ||
| 63 | .b = 1, | ||
| 64 | .c = 1, | ||
| 65 | .d = 1, | ||
| 66 | }) == 15); | ||
| 67 | } | ||
| 68 | fn shouldBeAPlus1(p: Particle) u64 { | ||
| 69 | var maybe_particle: ?Particle = p; | ||
| 70 | if (maybe_particle) |*particle| { | ||
| 71 | particle.a += 1; | ||
| 72 | } | ||
| 73 | if (maybe_particle) |particle| { | ||
| 74 | return particle.a; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | const Particle = struct { | ||
| 79 | a: u64, | ||
| 80 | b: u64, | ||
| 81 | c: u64, | ||
| 82 | d: u64, | ||
| 83 | }; | ||
| 84 | |||
| 85 | test "null literal outside function" { | ||
| 86 | const is_null = here_is_a_null_literal.context == null; | ||
| 87 | try expect(is_null); | ||
| 88 | |||
| 89 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 90 | try expect(!is_non_null); | ||
| 91 | } | ||
| 92 | const SillyStruct = struct { | ||
| 93 | context: ?i32, | ||
| 94 | }; | ||
| 95 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 96 | |||
| 97 | test "test null runtime" { | ||
| 98 | try testTestNullRuntime(null); | ||
| 99 | } | ||
| 100 | fn testTestNullRuntime(x: ?i32) !void { | ||
| 101 | try expect(x == null); | ||
| 102 | try expect(!(x != null)); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "optional void" { | ||
| 106 | try optionalVoidImpl(); | ||
| 107 | comptime try optionalVoidImpl(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn optionalVoidImpl() !void { | ||
| 111 | try expect(bar(null) == null); | ||
| 112 | try expect(bar({}) != null); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn bar(x: ?void) ?void { | ||
| 116 | if (x) |_| { | ||
| 117 | return {}; | ||
| 118 | } else { | ||
| 119 | return null; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | const StructWithOptional = struct { | ||
| 124 | field: ?i32, | ||
| 125 | }; | ||
| 126 | |||
| 127 | var struct_with_optional: StructWithOptional = undefined; | ||
| 128 | |||
| 129 | test "unwrap optional which is field of global var" { | ||
| 130 | struct_with_optional.field = null; | ||
| 131 | if (struct_with_optional.field) |payload| { | ||
| 132 | unreachable; | ||
| 133 | } | ||
| 134 | struct_with_optional.field = 1234; | ||
| 135 | if (struct_with_optional.field) |payload| { | ||
| 136 | try expect(payload == 1234); | ||
| 137 | } else { | ||
| 138 | unreachable; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | test "null with default unwrap" { | ||
| 143 | const x: i32 = null orelse 1; | ||
| 144 | try expect(x == 1); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "optional types" { | ||
| 148 | comptime { | ||
| 149 | const opt_type_struct = StructWithOptionalType{ .t = u8 }; | ||
| 150 | try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | const StructWithOptionalType = struct { | ||
| 155 | t: ?type, | ||
| 156 | }; | ||
| 157 | |||
| 158 | test "optional pointer to 0 bit type null value at runtime" { | ||
| 159 | const EmptyStruct = struct {}; | ||
| 160 | var x: ?*EmptyStruct = null; | ||
| 161 | try expect(x == null); | ||
| 162 | } | ||
test/behavior/optional.zig created+269| ... | @@ -0,0 +1,269 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | pub const EmptyStruct = struct {}; | ||
| 7 | |||
| 8 | test "optional pointer to size zero struct" { | ||
| 9 | var e = EmptyStruct{}; | ||
| 10 | var o: ?*EmptyStruct = &e; | ||
| 11 | try expect(o != null); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "equality compare nullable pointers" { | ||
| 15 | try testNullPtrsEql(); | ||
| 16 | comptime try testNullPtrsEql(); | ||
| 17 | } | ||
| 18 | |||
| 19 | fn testNullPtrsEql() !void { | ||
| 20 | var number: i32 = 1234; | ||
| 21 | |||
| 22 | var x: ?*i32 = null; | ||
| 23 | var y: ?*i32 = null; | ||
| 24 | try expect(x == y); | ||
| 25 | y = &number; | ||
| 26 | try expect(x != y); | ||
| 27 | try expect(x != &number); | ||
| 28 | try expect(&number != x); | ||
| 29 | x = &number; | ||
| 30 | try expect(x == y); | ||
| 31 | try expect(x == &number); | ||
| 32 | try expect(&number == x); | ||
| 33 | } | ||
| 34 | |||
| 35 | test "address of unwrap optional" { | ||
| 36 | const S = struct { | ||
| 37 | const Foo = struct { | ||
| 38 | a: i32, | ||
| 39 | }; | ||
| 40 | |||
| 41 | var global: ?Foo = null; | ||
| 42 | |||
| 43 | pub fn getFoo() anyerror!*Foo { | ||
| 44 | return &global.?; | ||
| 45 | } | ||
| 46 | }; | ||
| 47 | S.global = S.Foo{ .a = 1234 }; | ||
| 48 | const foo = S.getFoo() catch unreachable; | ||
| 49 | try expect(foo.a == 1234); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "equality compare optional with non-optional" { | ||
| 53 | try test_cmp_optional_non_optional(); | ||
| 54 | comptime try test_cmp_optional_non_optional(); | ||
| 55 | } | ||
| 56 | |||
| 57 | fn test_cmp_optional_non_optional() !void { | ||
| 58 | var ten: i32 = 10; | ||
| 59 | var opt_ten: ?i32 = 10; | ||
| 60 | var five: i32 = 5; | ||
| 61 | var int_n: ?i32 = null; | ||
| 62 | |||
| 63 | try expect(int_n != ten); | ||
| 64 | try expect(opt_ten == ten); | ||
| 65 | try expect(opt_ten != five); | ||
| 66 | |||
| 67 | // test evaluation is always lexical | ||
| 68 | // ensure that the optional isn't always computed before the non-optional | ||
| 69 | var mutable_state: i32 = 0; | ||
| 70 | _ = blk1: { | ||
| 71 | mutable_state += 1; | ||
| 72 | break :blk1 @as(?f64, 10.0); | ||
| 73 | } != blk2: { | ||
| 74 | try expect(mutable_state == 1); | ||
| 75 | break :blk2 @as(f64, 5.0); | ||
| 76 | }; | ||
| 77 | _ = blk1: { | ||
| 78 | mutable_state += 1; | ||
| 79 | break :blk1 @as(f64, 10.0); | ||
| 80 | } != blk2: { | ||
| 81 | try expect(mutable_state == 2); | ||
| 82 | break :blk2 @as(?f64, 5.0); | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 86 | test "passing an optional integer as a parameter" { | ||
| 87 | const S = struct { | ||
| 88 | fn entry() bool { | ||
| 89 | var x: i32 = 1234; | ||
| 90 | return foo(x); | ||
| 91 | } | ||
| 92 | |||
| 93 | fn foo(x: ?i32) bool { | ||
| 94 | return x.? == 1234; | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | try expect(S.entry()); | ||
| 98 | comptime try expect(S.entry()); | ||
| 99 | } | ||
| 100 | |||
| 101 | test "unwrap function call with optional pointer return value" { | ||
| 102 | const S = struct { | ||
| 103 | fn entry() !void { | ||
| 104 | try expect(foo().?.* == 1234); | ||
| 105 | try expect(bar() == null); | ||
| 106 | } | ||
| 107 | const global: i32 = 1234; | ||
| 108 | fn foo() ?*const i32 { | ||
| 109 | return &global; | ||
| 110 | } | ||
| 111 | fn bar() ?*i32 { | ||
| 112 | return null; | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | try S.entry(); | ||
| 116 | comptime try S.entry(); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "nested orelse" { | ||
| 120 | const S = struct { | ||
| 121 | fn entry() !void { | ||
| 122 | try expect(func() == null); | ||
| 123 | } | ||
| 124 | fn maybe() ?Foo { | ||
| 125 | return null; | ||
| 126 | } | ||
| 127 | fn func() ?Foo { | ||
| 128 | const x = maybe() orelse | ||
| 129 | maybe() orelse | ||
| 130 | return null; | ||
| 131 | unreachable; | ||
| 132 | } | ||
| 133 | const Foo = struct { | ||
| 134 | field: i32, | ||
| 135 | }; | ||
| 136 | }; | ||
| 137 | try S.entry(); | ||
| 138 | comptime try S.entry(); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "self-referential struct through a slice of optional" { | ||
| 142 | const S = struct { | ||
| 143 | const Node = struct { | ||
| 144 | children: []?Node, | ||
| 145 | data: ?u8, | ||
| 146 | |||
| 147 | fn new() Node { | ||
| 148 | return Node{ | ||
| 149 | .children = undefined, | ||
| 150 | .data = null, | ||
| 151 | }; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | }; | ||
| 155 | |||
| 156 | var n = S.Node.new(); | ||
| 157 | try expect(n.data == null); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "assigning to an unwrapped optional field in an inline loop" { | ||
| 161 | comptime var maybe_pos_arg: ?comptime_int = null; | ||
| 162 | inline for ("ab") |x| { | ||
| 163 | maybe_pos_arg = 0; | ||
| 164 | if (maybe_pos_arg.? != 0) { | ||
| 165 | @compileError("bad"); | ||
| 166 | } | ||
| 167 | maybe_pos_arg.? = 10; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | test "coerce an anon struct literal to optional struct" { | ||
| 172 | const S = struct { | ||
| 173 | const Struct = struct { | ||
| 174 | field: u32, | ||
| 175 | }; | ||
| 176 | fn doTheTest() !void { | ||
| 177 | var maybe_dims: ?Struct = null; | ||
| 178 | maybe_dims = .{ .field = 1 }; | ||
| 179 | try expect(maybe_dims.?.field == 1); | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | try S.doTheTest(); | ||
| 183 | comptime try S.doTheTest(); | ||
| 184 | } | ||
| 185 | |||
| 186 | test "optional with void type" { | ||
| 187 | const Foo = struct { | ||
| 188 | x: ?void, | ||
| 189 | }; | ||
| 190 | var x = Foo{ .x = null }; | ||
| 191 | try expect(x.x == null); | ||
| 192 | } | ||
| 193 | |||
| 194 | test "0-bit child type coerced to optional return ptr result location" { | ||
| 195 | const S = struct { | ||
| 196 | fn doTheTest() !void { | ||
| 197 | var y = Foo{}; | ||
| 198 | var z = y.thing(); | ||
| 199 | try expect(z != null); | ||
| 200 | } | ||
| 201 | |||
| 202 | const Foo = struct { | ||
| 203 | pub const Bar = struct { | ||
| 204 | field: *Foo, | ||
| 205 | }; | ||
| 206 | |||
| 207 | pub fn thing(self: *Foo) ?Bar { | ||
| 208 | return Bar{ .field = self }; | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | }; | ||
| 212 | try S.doTheTest(); | ||
| 213 | comptime try S.doTheTest(); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "0-bit child type coerced to optional" { | ||
| 217 | const S = struct { | ||
| 218 | fn doTheTest() !void { | ||
| 219 | var it: Foo = .{ | ||
| 220 | .list = undefined, | ||
| 221 | }; | ||
| 222 | try expect(it.foo() != null); | ||
| 223 | } | ||
| 224 | |||
| 225 | const Empty = struct {}; | ||
| 226 | const Foo = struct { | ||
| 227 | list: [10]Empty, | ||
| 228 | |||
| 229 | fn foo(self: *Foo) ?*Empty { | ||
| 230 | const data = &self.list[0]; | ||
| 231 | return data; | ||
| 232 | } | ||
| 233 | }; | ||
| 234 | }; | ||
| 235 | try S.doTheTest(); | ||
| 236 | comptime try S.doTheTest(); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "array of optional unaligned types" { | ||
| 240 | const Enum = enum { one, two, three }; | ||
| 241 | |||
| 242 | const SomeUnion = union(enum) { | ||
| 243 | Num: Enum, | ||
| 244 | Other: u32, | ||
| 245 | }; | ||
| 246 | |||
| 247 | const values = [_]?SomeUnion{ | ||
| 248 | SomeUnion{ .Num = .one }, | ||
| 249 | SomeUnion{ .Num = .two }, | ||
| 250 | SomeUnion{ .Num = .three }, | ||
| 251 | SomeUnion{ .Num = .one }, | ||
| 252 | SomeUnion{ .Num = .two }, | ||
| 253 | SomeUnion{ .Num = .three }, | ||
| 254 | }; | ||
| 255 | |||
| 256 | // The index must be a runtime value | ||
| 257 | var i: usize = 0; | ||
| 258 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 259 | i += 1; | ||
| 260 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 261 | i += 1; | ||
| 262 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 263 | i += 1; | ||
| 264 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 265 | i += 1; | ||
| 266 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 267 | i += 1; | ||
| 268 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 269 | } | ||
test/behavior/pointers.zig created+339| ... | @@ -0,0 +1,339 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectError = testing.expectError; | ||
| 5 | |||
| 6 | test "dereference pointer" { | ||
| 7 | comptime try testDerefPtr(); | ||
| 8 | try testDerefPtr(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testDerefPtr() !void { | ||
| 12 | var x: i32 = 1234; | ||
| 13 | var y = &x; | ||
| 14 | y.* += 1; | ||
| 15 | try expect(x == 1235); | ||
| 16 | } | ||
| 17 | |||
| 18 | const Foo1 = struct { | ||
| 19 | x: void, | ||
| 20 | }; | ||
| 21 | |||
| 22 | test "dereference pointer again" { | ||
| 23 | try testDerefPtrOneVal(); | ||
| 24 | comptime try testDerefPtrOneVal(); | ||
| 25 | } | ||
| 26 | |||
| 27 | fn testDerefPtrOneVal() !void { | ||
| 28 | // Foo1 satisfies the OnePossibleValueYes criteria | ||
| 29 | const x = &Foo1{ .x = {} }; | ||
| 30 | const y = x.*; | ||
| 31 | try expect(@TypeOf(y.x) == void); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "pointer arithmetic" { | ||
| 35 | var ptr: [*]const u8 = "abcd"; | ||
| 36 | |||
| 37 | try expect(ptr[0] == 'a'); | ||
| 38 | ptr += 1; | ||
| 39 | try expect(ptr[0] == 'b'); | ||
| 40 | ptr += 1; | ||
| 41 | try expect(ptr[0] == 'c'); | ||
| 42 | ptr += 1; | ||
| 43 | try expect(ptr[0] == 'd'); | ||
| 44 | ptr += 1; | ||
| 45 | try expect(ptr[0] == 0); | ||
| 46 | ptr -= 1; | ||
| 47 | try expect(ptr[0] == 'd'); | ||
| 48 | ptr -= 1; | ||
| 49 | try expect(ptr[0] == 'c'); | ||
| 50 | ptr -= 1; | ||
| 51 | try expect(ptr[0] == 'b'); | ||
| 52 | ptr -= 1; | ||
| 53 | try expect(ptr[0] == 'a'); | ||
| 54 | } | ||
| 55 | |||
| 56 | test "double pointer parsing" { | ||
| 57 | comptime try expect(PtrOf(PtrOf(i32)) == **i32); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn PtrOf(comptime T: type) type { | ||
| 61 | return *T; | ||
| 62 | } | ||
| 63 | |||
| 64 | test "assigning integer to C pointer" { | ||
| 65 | var x: i32 = 0; | ||
| 66 | var ptr: [*c]u8 = 0; | ||
| 67 | var ptr2: [*c]u8 = x; | ||
| 68 | } | ||
| 69 | |||
| 70 | test "implicit cast single item pointer to C pointer and back" { | ||
| 71 | var y: u8 = 11; | ||
| 72 | var x: [*c]u8 = &y; | ||
| 73 | var z: *u8 = x; | ||
| 74 | z.* += 1; | ||
| 75 | try expect(y == 12); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "C pointer comparison and arithmetic" { | ||
| 79 | const S = struct { | ||
| 80 | fn doTheTest() !void { | ||
| 81 | var one: usize = 1; | ||
| 82 | var ptr1: [*c]u32 = 0; | ||
| 83 | var ptr2 = ptr1 + 10; | ||
| 84 | try expect(ptr1 == 0); | ||
| 85 | try expect(ptr1 >= 0); | ||
| 86 | try expect(ptr1 <= 0); | ||
| 87 | // expect(ptr1 < 1); | ||
| 88 | // expect(ptr1 < one); | ||
| 89 | // expect(1 > ptr1); | ||
| 90 | // expect(one > ptr1); | ||
| 91 | try expect(ptr1 < ptr2); | ||
| 92 | try expect(ptr2 > ptr1); | ||
| 93 | try expect(ptr2 >= 40); | ||
| 94 | try expect(ptr2 == 40); | ||
| 95 | try expect(ptr2 <= 40); | ||
| 96 | ptr2 -= 10; | ||
| 97 | try expect(ptr1 == ptr2); | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | try S.doTheTest(); | ||
| 101 | comptime try S.doTheTest(); | ||
| 102 | } | ||
| 103 | |||
| 104 | test "peer type resolution with C pointers" { | ||
| 105 | var ptr_one: *u8 = undefined; | ||
| 106 | var ptr_many: [*]u8 = undefined; | ||
| 107 | var ptr_c: [*c]u8 = undefined; | ||
| 108 | var t = true; | ||
| 109 | var x1 = if (t) ptr_one else ptr_c; | ||
| 110 | var x2 = if (t) ptr_many else ptr_c; | ||
| 111 | var x3 = if (t) ptr_c else ptr_one; | ||
| 112 | var x4 = if (t) ptr_c else ptr_many; | ||
| 113 | try expect(@TypeOf(x1) == [*c]u8); | ||
| 114 | try expect(@TypeOf(x2) == [*c]u8); | ||
| 115 | try expect(@TypeOf(x3) == [*c]u8); | ||
| 116 | try expect(@TypeOf(x4) == [*c]u8); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "implicit casting between C pointer and optional non-C pointer" { | ||
| 120 | var slice: []const u8 = "aoeu"; | ||
| 121 | const opt_many_ptr: ?[*]const u8 = slice.ptr; | ||
| 122 | var ptr_opt_many_ptr = &opt_many_ptr; | ||
| 123 | var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; | ||
| 124 | try expect(c_ptr.*.* == 'a'); | ||
| 125 | ptr_opt_many_ptr = c_ptr; | ||
| 126 | try expect(ptr_opt_many_ptr.*.?[1] == 'o'); | ||
| 127 | } | ||
| 128 | |||
| 129 | test "implicit cast error unions with non-optional to optional pointer" { | ||
| 130 | const S = struct { | ||
| 131 | fn doTheTest() !void { | ||
| 132 | try expectError(error.Fail, foo()); | ||
| 133 | } | ||
| 134 | fn foo() anyerror!?*u8 { | ||
| 135 | return bar() orelse error.Fail; | ||
| 136 | } | ||
| 137 | fn bar() ?*u8 { | ||
| 138 | return null; | ||
| 139 | } | ||
| 140 | }; | ||
| 141 | try S.doTheTest(); | ||
| 142 | comptime try S.doTheTest(); | ||
| 143 | } | ||
| 144 | |||
| 145 | test "initialize const optional C pointer to null" { | ||
| 146 | const a: ?[*c]i32 = null; | ||
| 147 | try expect(a == null); | ||
| 148 | comptime try expect(a == null); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "compare equality of optional and non-optional pointer" { | ||
| 152 | const a = @intToPtr(*const usize, 0x12345678); | ||
| 153 | const b = @intToPtr(?*usize, 0x12345678); | ||
| 154 | try expect(a == b); | ||
| 155 | try expect(b == a); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "allowzero pointer and slice" { | ||
| 159 | var ptr = @intToPtr([*]allowzero i32, 0); | ||
| 160 | var opt_ptr: ?[*]allowzero i32 = ptr; | ||
| 161 | try expect(opt_ptr != null); | ||
| 162 | try expect(@ptrToInt(ptr) == 0); | ||
| 163 | var runtime_zero: usize = 0; | ||
| 164 | var slice = ptr[runtime_zero..10]; | ||
| 165 | comptime try expect(@TypeOf(slice) == []allowzero i32); | ||
| 166 | try expect(@ptrToInt(&slice[5]) == 20); | ||
| 167 | |||
| 168 | comptime try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); | ||
| 169 | comptime try expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "assign null directly to C pointer and test null equality" { | ||
| 173 | var x: [*c]i32 = null; | ||
| 174 | try expect(x == null); | ||
| 175 | try expect(null == x); | ||
| 176 | try expect(!(x != null)); | ||
| 177 | try expect(!(null != x)); | ||
| 178 | if (x) |same_x| { | ||
| 179 | @panic("fail"); | ||
| 180 | } | ||
| 181 | var otherx: i32 = undefined; | ||
| 182 | try expect((x orelse &otherx) == &otherx); | ||
| 183 | |||
| 184 | const y: [*c]i32 = null; | ||
| 185 | comptime try expect(y == null); | ||
| 186 | comptime try expect(null == y); | ||
| 187 | comptime try expect(!(y != null)); | ||
| 188 | comptime try expect(!(null != y)); | ||
| 189 | if (y) |same_y| @panic("fail"); | ||
| 190 | const othery: i32 = undefined; | ||
| 191 | comptime try expect((y orelse &othery) == &othery); | ||
| 192 | |||
| 193 | var n: i32 = 1234; | ||
| 194 | var x1: [*c]i32 = &n; | ||
| 195 | try expect(!(x1 == null)); | ||
| 196 | try expect(!(null == x1)); | ||
| 197 | try expect(x1 != null); | ||
| 198 | try expect(null != x1); | ||
| 199 | try expect(x1.?.* == 1234); | ||
| 200 | if (x1) |same_x1| { | ||
| 201 | try expect(same_x1.* == 1234); | ||
| 202 | } else { | ||
| 203 | @panic("fail"); | ||
| 204 | } | ||
| 205 | try expect((x1 orelse &otherx) == x1); | ||
| 206 | |||
| 207 | const nc: i32 = 1234; | ||
| 208 | const y1: [*c]const i32 = &nc; | ||
| 209 | comptime try expect(!(y1 == null)); | ||
| 210 | comptime try expect(!(null == y1)); | ||
| 211 | comptime try expect(y1 != null); | ||
| 212 | comptime try expect(null != y1); | ||
| 213 | comptime try expect(y1.?.* == 1234); | ||
| 214 | if (y1) |same_y1| { | ||
| 215 | try expect(same_y1.* == 1234); | ||
| 216 | } else { | ||
| 217 | @compileError("fail"); | ||
| 218 | } | ||
| 219 | comptime try expect((y1 orelse &othery) == y1); | ||
| 220 | } | ||
| 221 | |||
| 222 | test "null terminated pointer" { | ||
| 223 | const S = struct { | ||
| 224 | fn doTheTest() !void { | ||
| 225 | var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' }; | ||
| 226 | var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero); | ||
| 227 | var no_zero_ptr: [*]const u8 = zero_ptr; | ||
| 228 | var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr); | ||
| 229 | try expect(std.mem.eql(u8, std.mem.spanZ(zero_ptr_again), "hello")); | ||
| 230 | } | ||
| 231 | }; | ||
| 232 | try S.doTheTest(); | ||
| 233 | comptime try S.doTheTest(); | ||
| 234 | } | ||
| 235 | |||
| 236 | test "allow any sentinel" { | ||
| 237 | const S = struct { | ||
| 238 | fn doTheTest() !void { | ||
| 239 | var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 }; | ||
| 240 | var ptr: [*:std.math.minInt(i32)]i32 = &array; | ||
| 241 | try expect(ptr[4] == std.math.minInt(i32)); | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | try S.doTheTest(); | ||
| 245 | comptime try S.doTheTest(); | ||
| 246 | } | ||
| 247 | |||
| 248 | test "pointer sentinel with enums" { | ||
| 249 | const S = struct { | ||
| 250 | const Number = enum { | ||
| 251 | one, | ||
| 252 | two, | ||
| 253 | sentinel, | ||
| 254 | }; | ||
| 255 | |||
| 256 | fn doTheTest() !void { | ||
| 257 | var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one }; | ||
| 258 | try expect(ptr[4] == .sentinel); // TODO this should be comptime try expect, see #3731 | ||
| 259 | } | ||
| 260 | }; | ||
| 261 | try S.doTheTest(); | ||
| 262 | comptime try S.doTheTest(); | ||
| 263 | } | ||
| 264 | |||
| 265 | test "pointer sentinel with optional element" { | ||
| 266 | const S = struct { | ||
| 267 | fn doTheTest() !void { | ||
| 268 | var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 }; | ||
| 269 | try expect(ptr[4] == null); // TODO this should be comptime try expect, see #3731 | ||
| 270 | } | ||
| 271 | }; | ||
| 272 | try S.doTheTest(); | ||
| 273 | comptime try S.doTheTest(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "pointer sentinel with +inf" { | ||
| 277 | const S = struct { | ||
| 278 | fn doTheTest() !void { | ||
| 279 | const inf = std.math.inf_f32; | ||
| 280 | var ptr: [*:inf]const f32 = &[_:inf]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 281 | try expect(ptr[4] == inf); // TODO this should be comptime try expect, see #3731 | ||
| 282 | } | ||
| 283 | }; | ||
| 284 | try S.doTheTest(); | ||
| 285 | comptime try S.doTheTest(); | ||
| 286 | } | ||
| 287 | |||
| 288 | test "pointer to array at fixed address" { | ||
| 289 | const array = @intToPtr(*volatile [1]u32, 0x10); | ||
| 290 | // Silly check just to reference `array` | ||
| 291 | try expect(@ptrToInt(&array[0]) == 0x10); | ||
| 292 | } | ||
| 293 | |||
| 294 | test "pointer arithmetic affects the alignment" { | ||
| 295 | { | ||
| 296 | var ptr: [*]align(8) u32 = undefined; | ||
| 297 | var x: usize = 1; | ||
| 298 | |||
| 299 | try expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8); | ||
| 300 | const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4 | ||
| 301 | try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4); | ||
| 302 | const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8 | ||
| 303 | try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8); | ||
| 304 | const ptr3 = ptr + 0; // no-op | ||
| 305 | try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); | ||
| 306 | const ptr4 = ptr + x; // runtime-known addend | ||
| 307 | try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); | ||
| 308 | } | ||
| 309 | { | ||
| 310 | var ptr: [*]align(8) [3]u8 = undefined; | ||
| 311 | var x: usize = 1; | ||
| 312 | |||
| 313 | const ptr1 = ptr + 17; // 3 * 17 = 51 | ||
| 314 | try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1); | ||
| 315 | const ptr2 = ptr + x; // runtime-known addend | ||
| 316 | try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1); | ||
| 317 | const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8 | ||
| 318 | try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); | ||
| 319 | const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4 | ||
| 320 | try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | test "@ptrToInt on null optional at comptime" { | ||
| 325 | { | ||
| 326 | const pointer = @intToPtr(?*u8, 0x000); | ||
| 327 | const x = @ptrToInt(pointer); | ||
| 328 | comptime try expect(0 == @ptrToInt(pointer)); | ||
| 329 | } | ||
| 330 | { | ||
| 331 | const pointer = @intToPtr(?*u8, 0xf00); | ||
| 332 | comptime try expect(0xf00 == @ptrToInt(pointer)); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | test "indexing array with sentinel returns correct type" { | ||
| 337 | var s: [:0]const u8 = "abc"; | ||
| 338 | try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0]))); | ||
| 339 | } | ||
test/behavior/popcount.zig created+43| ... | @@ -0,0 +1,43 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@popCount" { | ||
| 4 | comptime try testPopCount(); | ||
| 5 | try testPopCount(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testPopCount() !void { | ||
| 9 | { | ||
| 10 | var x: u32 = 0xffffffff; | ||
| 11 | try expect(@popCount(u32, x) == 32); | ||
| 12 | } | ||
| 13 | { | ||
| 14 | var x: u5 = 0x1f; | ||
| 15 | try expect(@popCount(u5, x) == 5); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var x: u32 = 0xaa; | ||
| 19 | try expect(@popCount(u32, x) == 4); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var x: u32 = 0xaaaaaaaa; | ||
| 23 | try expect(@popCount(u32, x) == 16); | ||
| 24 | } | ||
| 25 | { | ||
| 26 | var x: u32 = 0xaaaaaaaa; | ||
| 27 | try expect(@popCount(u32, x) == 16); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | var x: i16 = -1; | ||
| 31 | try expect(@popCount(i16, x) == 16); | ||
| 32 | } | ||
| 33 | { | ||
| 34 | var x: i8 = -120; | ||
| 35 | try expect(@popCount(i8, x) == 2); | ||
| 36 | } | ||
| 37 | comptime { | ||
| 38 | try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2); | ||
| 39 | } | ||
| 40 | comptime { | ||
| 41 | try expect(@popCount(i128, 0b11111111000110001100010000100001000011000011100101010001) == 24); | ||
| 42 | } | ||
| 43 | } | ||
test/behavior/ptrcast.zig created+73| ... | @@ -0,0 +1,73 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 5 | |||
| 6 | test "reinterpret bytes as integer with nonzero offset" { | ||
| 7 | try testReinterpretBytesAsInteger(); | ||
| 8 | comptime try testReinterpretBytesAsInteger(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testReinterpretBytesAsInteger() !void { | ||
| 12 | const bytes = "\x12\x34\x56\x78\xab"; | ||
| 13 | const expected = switch (native_endian) { | ||
| 14 | .Little => 0xab785634, | ||
| 15 | .Big => 0x345678ab, | ||
| 16 | }; | ||
| 17 | try expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "reinterpret bytes of an array into an extern struct" { | ||
| 21 | try testReinterpretBytesAsExternStruct(); | ||
| 22 | comptime try testReinterpretBytesAsExternStruct(); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn testReinterpretBytesAsExternStruct() !void { | ||
| 26 | var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 }; | ||
| 27 | |||
| 28 | const S = extern struct { | ||
| 29 | a: u8, | ||
| 30 | b: u16, | ||
| 31 | c: u8, | ||
| 32 | }; | ||
| 33 | |||
| 34 | var ptr = @ptrCast(*const S, &bytes); | ||
| 35 | var val = ptr.c; | ||
| 36 | try expect(val == 5); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "reinterpret struct field at comptime" { | ||
| 40 | const numNative = comptime Bytes.init(0x12345678); | ||
| 41 | if (native_endian != .Little) { | ||
| 42 | try expect(std.mem.eql(u8, &[_]u8{ 0x12, 0x34, 0x56, 0x78 }, &numNative.bytes)); | ||
| 43 | } else { | ||
| 44 | try expect(std.mem.eql(u8, &[_]u8{ 0x78, 0x56, 0x34, 0x12 }, &numNative.bytes)); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | const Bytes = struct { | ||
| 49 | bytes: [4]u8, | ||
| 50 | |||
| 51 | pub fn init(v: u32) Bytes { | ||
| 52 | var res: Bytes = undefined; | ||
| 53 | @ptrCast(*align(1) u32, &res.bytes).* = v; | ||
| 54 | |||
| 55 | return res; | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | |||
| 59 | test "comptime ptrcast keeps larger alignment" { | ||
| 60 | comptime { | ||
| 61 | const a: u32 = 1234; | ||
| 62 | const p = @ptrCast([*]const u8, &a); | ||
| 63 | try expect(@TypeOf(p) == [*]align(@alignOf(u32)) const u8); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | test "implicit optional pointer to optional c_void pointer" { | ||
| 68 | var buf: [4]u8 = "aoeu".*; | ||
| 69 | var x: ?[*]u8 = &buf; | ||
| 70 | var y: ?*c_void = x; | ||
| 71 | var z = @ptrCast(*[4]u8, y); | ||
| 72 | try expect(std.mem.eql(u8, z, "aoeu")); | ||
| 73 | } | ||
test/behavior/pub_enum.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | const other = @import("pub_enum/other.zig"); | ||
| 2 | const expect = @import("std").testing.expect; | ||
| 3 | |||
| 4 | test "pub enum" { | ||
| 5 | try pubEnumTest(other.APubEnum.Two); | ||
| 6 | } | ||
| 7 | fn pubEnumTest(foo: other.APubEnum) !void { | ||
| 8 | try expect(foo == other.APubEnum.Two); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "cast with imported symbol" { | ||
| 12 | try expect(@as(other.size_t, 42) == 42); | ||
| 13 | } | ||
test/behavior/pub_enum/other.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | pub const APubEnum = enum { | ||
| 2 | One, | ||
| 3 | Two, | ||
| 4 | Three, | ||
| 5 | }; | ||
| 6 | pub const size_t = u64; | ||
test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | var ok: bool = false; | ||
| 5 | test "reference a variable in an if after an if in the 2nd switch prong" { | ||
| 6 | try foo(true, Num.Two, false, "aoeu"); | ||
| 7 | try expect(!ok); | ||
| 8 | try foo(false, Num.One, false, "aoeu"); | ||
| 9 | try expect(!ok); | ||
| 10 | try foo(true, Num.One, false, "aoeu"); | ||
| 11 | try expect(ok); | ||
| 12 | } | ||
| 13 | |||
| 14 | const Num = enum { | ||
| 15 | One, | ||
| 16 | Two, | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(c: bool, k: Num, c2: bool, b: []const u8) !void { | ||
| 20 | switch (k) { | ||
| 21 | Num.Two => {}, | ||
| 22 | Num.One => { | ||
| 23 | if (c) { | ||
| 24 | const output_path = b; | ||
| 25 | |||
| 26 | if (c2) {} | ||
| 27 | |||
| 28 | try a(output_path); | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn a(x: []const u8) !void { | ||
| 35 | try expect(mem.eql(u8, x, "aoeu")); | ||
| 36 | ok = true; | ||
| 37 | } | ||
test/behavior/reflection.zig created+55| ... | @@ -0,0 +1,55 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const reflection = @This(); | ||
| 4 | |||
| 5 | test "reflection: function return type, var args, and param types" { | ||
| 6 | comptime { | ||
| 7 | const info = @typeInfo(@TypeOf(dummy)).Fn; | ||
| 8 | try expect(info.return_type.? == i32); | ||
| 9 | try expect(!info.is_var_args); | ||
| 10 | try expect(info.args.len == 3); | ||
| 11 | try expect(info.args[0].arg_type.? == bool); | ||
| 12 | try expect(info.args[1].arg_type.? == i32); | ||
| 13 | try expect(info.args[2].arg_type.? == f32); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | fn dummy(a: bool, b: i32, c: f32) i32 { | ||
| 18 | return 1234; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "reflection: @field" { | ||
| 22 | var f = Foo{ | ||
| 23 | .one = 42, | ||
| 24 | .two = true, | ||
| 25 | .three = void{}, | ||
| 26 | }; | ||
| 27 | |||
| 28 | try expect(f.one == f.one); | ||
| 29 | try expect(@field(f, "o" ++ "ne") == f.one); | ||
| 30 | try expect(@field(f, "t" ++ "wo") == f.two); | ||
| 31 | try expect(@field(f, "th" ++ "ree") == f.three); | ||
| 32 | try expect(@field(Foo, "const" ++ "ant") == Foo.constant); | ||
| 33 | try expect(@field(Bar, "O" ++ "ne") == Bar.One); | ||
| 34 | try expect(@field(Bar, "T" ++ "wo") == Bar.Two); | ||
| 35 | try expect(@field(Bar, "Th" ++ "ree") == Bar.Three); | ||
| 36 | try expect(@field(Bar, "F" ++ "our") == Bar.Four); | ||
| 37 | try expect(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); | ||
| 38 | @field(f, "o" ++ "ne") = 4; | ||
| 39 | try expect(f.one == 4); | ||
| 40 | } | ||
| 41 | |||
| 42 | const Foo = struct { | ||
| 43 | const constant = 52; | ||
| 44 | |||
| 45 | one: i32, | ||
| 46 | two: bool, | ||
| 47 | three: void, | ||
| 48 | }; | ||
| 49 | |||
| 50 | const Bar = union(enum) { | ||
| 51 | One: void, | ||
| 52 | Two: i32, | ||
| 53 | Three: bool, | ||
| 54 | Four: f64, | ||
| 55 | }; | ||
test/behavior/shuffle.zig created+63| ... | @@ -0,0 +1,63 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const Vector = std.meta.Vector; | ||
| 6 | |||
| 7 | test "@shuffle" { | ||
| 8 | // TODO investigate why this fails when cross-compiling to wasm. | ||
| 9 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 10 | |||
| 11 | const S = struct { | ||
| 12 | fn doTheTest() !void { | ||
| 13 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 14 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 15 | const mask: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }; | ||
| 16 | var res = @shuffle(i32, v, x, mask); | ||
| 17 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); | ||
| 18 | |||
| 19 | // Implicit cast from array (of mask) | ||
| 20 | res = @shuffle(i32, v, x, [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }); | ||
| 21 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); | ||
| 22 | |||
| 23 | // Undefined | ||
| 24 | const mask2: Vector(4, i32) = [4]i32{ 3, 1, 2, 0 }; | ||
| 25 | res = @shuffle(i32, v, undefined, mask2); | ||
| 26 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 40, -2, 30, 2147483647 })); | ||
| 27 | |||
| 28 | // Upcasting of b | ||
| 29 | var v2: Vector(2, i32) = [2]i32{ 2147483647, undefined }; | ||
| 30 | const mask3: Vector(4, i32) = [4]i32{ ~@as(i32, 0), 2, ~@as(i32, 0), 3 }; | ||
| 31 | res = @shuffle(i32, x, v2, mask3); | ||
| 32 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 2147483647, 4 })); | ||
| 33 | |||
| 34 | // Upcasting of a | ||
| 35 | var v3: Vector(2, i32) = [2]i32{ 2147483647, -2 }; | ||
| 36 | const mask4: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 1, ~@as(i32, 3) }; | ||
| 37 | res = @shuffle(i32, v3, x, mask4); | ||
| 38 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, -2, 4 })); | ||
| 39 | |||
| 40 | // bool | ||
| 41 | // https://github.com/ziglang/zig/issues/3317 | ||
| 42 | if (builtin.target.cpu.arch != .mipsel and builtin.target.cpu.arch != .mips) { | ||
| 43 | var x2: Vector(4, bool) = [4]bool{ false, true, false, true }; | ||
| 44 | var v4: Vector(2, bool) = [2]bool{ true, false }; | ||
| 45 | const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; | ||
| 46 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 47 | try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false })); | ||
| 48 | } | ||
| 49 | |||
| 50 | // TODO re-enable when LLVM codegen is fixed | ||
| 51 | // https://github.com/ziglang/zig/issues/3246 | ||
| 52 | if (false) { | ||
| 53 | var x2: Vector(3, bool) = [3]bool{ false, true, false }; | ||
| 54 | var v4: Vector(2, bool) = [2]bool{ true, false }; | ||
| 55 | const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; | ||
| 56 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 57 | try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false })); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | }; | ||
| 61 | try S.doTheTest(); | ||
| 62 | comptime try S.doTheTest(); | ||
| 63 | } | ||
test/behavior/sizeof_and_typeof.zig created+264| ... | @@ -0,0 +1,264 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | |||
| 6 | test "@sizeOf and @TypeOf" { | ||
| 7 | const y: @TypeOf(x) = 120; | ||
| 8 | try expect(@sizeOf(@TypeOf(y)) == 2); | ||
| 9 | } | ||
| 10 | const x: u16 = 13; | ||
| 11 | const z: @TypeOf(x) = 19; | ||
| 12 | |||
| 13 | const A = struct { | ||
| 14 | a: u8, | ||
| 15 | b: u32, | ||
| 16 | c: u8, | ||
| 17 | d: u3, | ||
| 18 | e: u5, | ||
| 19 | f: u16, | ||
| 20 | g: u16, | ||
| 21 | h: u9, | ||
| 22 | i: u7, | ||
| 23 | }; | ||
| 24 | |||
| 25 | const P = packed struct { | ||
| 26 | a: u8, | ||
| 27 | b: u32, | ||
| 28 | c: u8, | ||
| 29 | d: u3, | ||
| 30 | e: u5, | ||
| 31 | f: u16, | ||
| 32 | g: u16, | ||
| 33 | h: u9, | ||
| 34 | i: u7, | ||
| 35 | }; | ||
| 36 | |||
| 37 | test "@byteOffsetOf" { | ||
| 38 | // Packed structs have fixed memory layout | ||
| 39 | try expect(@byteOffsetOf(P, "a") == 0); | ||
| 40 | try expect(@byteOffsetOf(P, "b") == 1); | ||
| 41 | try expect(@byteOffsetOf(P, "c") == 5); | ||
| 42 | try expect(@byteOffsetOf(P, "d") == 6); | ||
| 43 | try expect(@byteOffsetOf(P, "e") == 6); | ||
| 44 | try expect(@byteOffsetOf(P, "f") == 7); | ||
| 45 | try expect(@byteOffsetOf(P, "g") == 9); | ||
| 46 | try expect(@byteOffsetOf(P, "h") == 11); | ||
| 47 | try expect(@byteOffsetOf(P, "i") == 12); | ||
| 48 | |||
| 49 | // Normal struct fields can be moved/padded | ||
| 50 | var a: A = undefined; | ||
| 51 | try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); | ||
| 52 | try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); | ||
| 53 | try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); | ||
| 54 | try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); | ||
| 55 | try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); | ||
| 56 | try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); | ||
| 57 | try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); | ||
| 58 | try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @byteOffsetOf(A, "h")); | ||
| 59 | try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @byteOffsetOf(A, "i")); | ||
| 60 | } | ||
| 61 | |||
| 62 | test "@byteOffsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" { | ||
| 63 | const p3a_len = 3; | ||
| 64 | const P3 = packed struct { | ||
| 65 | a: [p3a_len]u8, | ||
| 66 | b: usize, | ||
| 67 | }; | ||
| 68 | try std.testing.expectEqual(0, @byteOffsetOf(P3, "a")); | ||
| 69 | try std.testing.expectEqual(p3a_len, @byteOffsetOf(P3, "b")); | ||
| 70 | |||
| 71 | const p5a_len = 5; | ||
| 72 | const P5 = packed struct { | ||
| 73 | a: [p5a_len]u8, | ||
| 74 | b: usize, | ||
| 75 | }; | ||
| 76 | try std.testing.expectEqual(0, @byteOffsetOf(P5, "a")); | ||
| 77 | try std.testing.expectEqual(p5a_len, @byteOffsetOf(P5, "b")); | ||
| 78 | |||
| 79 | const p6a_len = 6; | ||
| 80 | const P6 = packed struct { | ||
| 81 | a: [p6a_len]u8, | ||
| 82 | b: usize, | ||
| 83 | }; | ||
| 84 | try std.testing.expectEqual(0, @byteOffsetOf(P6, "a")); | ||
| 85 | try std.testing.expectEqual(p6a_len, @byteOffsetOf(P6, "b")); | ||
| 86 | |||
| 87 | const p7a_len = 7; | ||
| 88 | const P7 = packed struct { | ||
| 89 | a: [p7a_len]u8, | ||
| 90 | b: usize, | ||
| 91 | }; | ||
| 92 | try std.testing.expectEqual(0, @byteOffsetOf(P7, "a")); | ||
| 93 | try std.testing.expectEqual(p7a_len, @byteOffsetOf(P7, "b")); | ||
| 94 | |||
| 95 | const p9a_len = 9; | ||
| 96 | const P9 = packed struct { | ||
| 97 | a: [p9a_len]u8, | ||
| 98 | b: usize, | ||
| 99 | }; | ||
| 100 | try std.testing.expectEqual(0, @byteOffsetOf(P9, "a")); | ||
| 101 | try std.testing.expectEqual(p9a_len, @byteOffsetOf(P9, "b")); | ||
| 102 | |||
| 103 | // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases | ||
| 104 | } | ||
| 105 | |||
| 106 | test "@bitOffsetOf" { | ||
| 107 | // Packed structs have fixed memory layout | ||
| 108 | try expect(@bitOffsetOf(P, "a") == 0); | ||
| 109 | try expect(@bitOffsetOf(P, "b") == 8); | ||
| 110 | try expect(@bitOffsetOf(P, "c") == 40); | ||
| 111 | try expect(@bitOffsetOf(P, "d") == 48); | ||
| 112 | try expect(@bitOffsetOf(P, "e") == 51); | ||
| 113 | try expect(@bitOffsetOf(P, "f") == 56); | ||
| 114 | try expect(@bitOffsetOf(P, "g") == 72); | ||
| 115 | |||
| 116 | try expect(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 117 | try expect(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 118 | try expect(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 119 | try expect(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 120 | try expect(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 121 | try expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 122 | try expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 123 | } | ||
| 124 | |||
| 125 | test "@sizeOf on compile-time types" { | ||
| 126 | try expect(@sizeOf(comptime_int) == 0); | ||
| 127 | try expect(@sizeOf(comptime_float) == 0); | ||
| 128 | try expect(@sizeOf(@TypeOf(.hi)) == 0); | ||
| 129 | try expect(@sizeOf(@TypeOf(type)) == 0); | ||
| 130 | } | ||
| 131 | |||
| 132 | test "@sizeOf(T) == 0 doesn't force resolving struct size" { | ||
| 133 | const S = struct { | ||
| 134 | const Foo = struct { | ||
| 135 | y: if (@sizeOf(Foo) == 0) u64 else u32, | ||
| 136 | }; | ||
| 137 | const Bar = struct { | ||
| 138 | x: i32, | ||
| 139 | y: if (0 == @sizeOf(Bar)) u64 else u32, | ||
| 140 | }; | ||
| 141 | }; | ||
| 142 | |||
| 143 | try expect(@sizeOf(S.Foo) == 4); | ||
| 144 | try expect(@sizeOf(S.Bar) == 8); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "@TypeOf() has no runtime side effects" { | ||
| 148 | const S = struct { | ||
| 149 | fn foo(comptime T: type, ptr: *T) T { | ||
| 150 | ptr.* += 1; | ||
| 151 | return ptr.*; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | var data: i32 = 0; | ||
| 155 | const T = @TypeOf(S.foo(i32, &data)); | ||
| 156 | comptime try expect(T == i32); | ||
| 157 | try expect(data == 0); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "@TypeOf() with multiple arguments" { | ||
| 161 | { | ||
| 162 | var var_1: u32 = undefined; | ||
| 163 | var var_2: u8 = undefined; | ||
| 164 | var var_3: u64 = undefined; | ||
| 165 | comptime try expect(@TypeOf(var_1, var_2, var_3) == u64); | ||
| 166 | } | ||
| 167 | { | ||
| 168 | var var_1: f16 = undefined; | ||
| 169 | var var_2: f32 = undefined; | ||
| 170 | var var_3: f64 = undefined; | ||
| 171 | comptime try expect(@TypeOf(var_1, var_2, var_3) == f64); | ||
| 172 | } | ||
| 173 | { | ||
| 174 | var var_1: u16 = undefined; | ||
| 175 | comptime try expect(@TypeOf(var_1, 0xffff) == u16); | ||
| 176 | } | ||
| 177 | { | ||
| 178 | var var_1: f32 = undefined; | ||
| 179 | comptime try expect(@TypeOf(var_1, 3.1415) == f32); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | test "branching logic inside @TypeOf" { | ||
| 184 | const S = struct { | ||
| 185 | var data: i32 = 0; | ||
| 186 | fn foo() anyerror!i32 { | ||
| 187 | data += 1; | ||
| 188 | return undefined; | ||
| 189 | } | ||
| 190 | }; | ||
| 191 | const T = @TypeOf(S.foo() catch undefined); | ||
| 192 | comptime try expect(T == i32); | ||
| 193 | try expect(S.data == 0); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn fn1(alpha: bool) void { | ||
| 197 | const n: usize = 7; | ||
| 198 | const v = if (alpha) n else @sizeOf(usize); | ||
| 199 | } | ||
| 200 | |||
| 201 | test "lazy @sizeOf result is checked for definedness" { | ||
| 202 | const f = fn1; | ||
| 203 | } | ||
| 204 | |||
| 205 | test "@bitSizeOf" { | ||
| 206 | try expect(@bitSizeOf(u2) == 2); | ||
| 207 | try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); | ||
| 208 | try expect(@bitSizeOf(struct { | ||
| 209 | a: u2, | ||
| 210 | }) == 8); | ||
| 211 | try expect(@bitSizeOf(packed struct { | ||
| 212 | a: u2, | ||
| 213 | }) == 2); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "@sizeOf comparison against zero" { | ||
| 217 | const S0 = struct { | ||
| 218 | f: *@This(), | ||
| 219 | }; | ||
| 220 | const U0 = union { | ||
| 221 | f: *@This(), | ||
| 222 | }; | ||
| 223 | const S1 = struct { | ||
| 224 | fn H(comptime T: type) type { | ||
| 225 | return struct { | ||
| 226 | x: T, | ||
| 227 | }; | ||
| 228 | } | ||
| 229 | f0: H(*@This()), | ||
| 230 | f1: H(**@This()), | ||
| 231 | f2: H(***@This()), | ||
| 232 | }; | ||
| 233 | const U1 = union { | ||
| 234 | fn H(comptime T: type) type { | ||
| 235 | return struct { | ||
| 236 | x: T, | ||
| 237 | }; | ||
| 238 | } | ||
| 239 | f0: H(*@This()), | ||
| 240 | f1: H(**@This()), | ||
| 241 | f2: H(***@This()), | ||
| 242 | }; | ||
| 243 | const S = struct { | ||
| 244 | fn doTheTest(comptime T: type, comptime result: bool) !void { | ||
| 245 | try expectEqual(result, @sizeOf(T) > 0); | ||
| 246 | } | ||
| 247 | }; | ||
| 248 | // Zero-sized type | ||
| 249 | try S.doTheTest(u0, false); | ||
| 250 | try S.doTheTest(*u0, false); | ||
| 251 | // Non byte-sized type | ||
| 252 | try S.doTheTest(u1, true); | ||
| 253 | try S.doTheTest(*u1, true); | ||
| 254 | // Regular type | ||
| 255 | try S.doTheTest(u8, true); | ||
| 256 | try S.doTheTest(*u8, true); | ||
| 257 | try S.doTheTest(f32, true); | ||
| 258 | try S.doTheTest(*f32, true); | ||
| 259 | // Container with ptr pointing to themselves | ||
| 260 | try S.doTheTest(S0, true); | ||
| 261 | try S.doTheTest(U0, true); | ||
| 262 | try S.doTheTest(S1, true); | ||
| 263 | try S.doTheTest(U1, true); | ||
| 264 | } | ||
test/behavior/slice.zig created+337| ... | @@ -0,0 +1,337 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | ||
| 8 | const y = x[0x100..]; | ||
| 9 | test "compile time slice of pointer to hard coded address" { | ||
| 10 | try expect(@ptrToInt(x) == 0x1000); | ||
| 11 | try expect(x.len == 0x500); | ||
| 12 | |||
| 13 | try expect(@ptrToInt(y) == 0x1100); | ||
| 14 | try expect(y.len == 0x400); | ||
| 15 | } | ||
| 16 | |||
| 17 | test "runtime safety lets us slice from len..len" { | ||
| 18 | var an_array = [_]u8{ | ||
| 19 | 1, | ||
| 20 | 2, | ||
| 21 | 3, | ||
| 22 | }; | ||
| 23 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | ||
| 27 | return a_slice[start..end]; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "implicitly cast array of size 0 to slice" { | ||
| 31 | var msg = [_]u8{}; | ||
| 32 | try assertLenIsZero(&msg); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn assertLenIsZero(msg: []const u8) !void { | ||
| 36 | try expect(msg.len == 0); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "C pointer" { | ||
| 40 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | ||
| 41 | var len: u32 = 10; | ||
| 42 | var slice = buf[0..len]; | ||
| 43 | try expectEqualSlices(u8, "kjdhfkjdhf", slice); | ||
| 44 | } | ||
| 45 | |||
| 46 | test "C pointer slice access" { | ||
| 47 | var buf: [10]u32 = [1]u32{42} ** 10; | ||
| 48 | const c_ptr = @ptrCast([*c]const u32, &buf); | ||
| 49 | |||
| 50 | var runtime_zero: usize = 0; | ||
| 51 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | ||
| 52 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | ||
| 53 | |||
| 54 | for (c_ptr[0..5]) |*cl| { | ||
| 55 | try expectEqual(@as(u32, 42), cl.*); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | fn sliceSum(comptime q: []const u8) i32 { | ||
| 60 | comptime var result = 0; | ||
| 61 | inline for (q) |item| { | ||
| 62 | result += item; | ||
| 63 | } | ||
| 64 | return result; | ||
| 65 | } | ||
| 66 | |||
| 67 | test "comptime slices are disambiguated" { | ||
| 68 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | ||
| 69 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | ||
| 70 | } | ||
| 71 | |||
| 72 | test "slice type with custom alignment" { | ||
| 73 | const LazilyResolvedType = struct { | ||
| 74 | anything: i32, | ||
| 75 | }; | ||
| 76 | var slice: []align(32) LazilyResolvedType = undefined; | ||
| 77 | var array: [10]LazilyResolvedType align(32) = undefined; | ||
| 78 | slice = &array; | ||
| 79 | slice[1].anything = 42; | ||
| 80 | try expect(array[1].anything == 42); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "access len index of sentinel-terminated slice" { | ||
| 84 | const S = struct { | ||
| 85 | fn doTheTest() !void { | ||
| 86 | var slice: [:0]const u8 = "hello"; | ||
| 87 | |||
| 88 | try expect(slice.len == 5); | ||
| 89 | try expect(slice[5] == 0); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | try S.doTheTest(); | ||
| 93 | comptime try S.doTheTest(); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "obtaining a null terminated slice" { | ||
| 97 | // here we have a normal array | ||
| 98 | var buf: [50]u8 = undefined; | ||
| 99 | |||
| 100 | buf[0] = 'a'; | ||
| 101 | buf[1] = 'b'; | ||
| 102 | buf[2] = 'c'; | ||
| 103 | buf[3] = 0; | ||
| 104 | |||
| 105 | // now we obtain a null terminated slice: | ||
| 106 | const ptr = buf[0..3 :0]; | ||
| 107 | |||
| 108 | var runtime_len: usize = 3; | ||
| 109 | const ptr2 = buf[0..runtime_len :0]; | ||
| 110 | // ptr2 is a null-terminated slice | ||
| 111 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | ||
| 112 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | ||
| 113 | var runtime_zero: usize = 0; | ||
| 114 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "empty array to slice" { | ||
| 118 | const S = struct { | ||
| 119 | fn doTheTest() !void { | ||
| 120 | const empty: []align(16) u8 = &[_]u8{}; | ||
| 121 | const align_1: []align(1) u8 = empty; | ||
| 122 | const align_4: []align(4) u8 = empty; | ||
| 123 | const align_16: []align(16) u8 = empty; | ||
| 124 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | ||
| 125 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | ||
| 126 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | |||
| 130 | try S.doTheTest(); | ||
| 131 | comptime try S.doTheTest(); | ||
| 132 | } | ||
| 133 | |||
| 134 | test "@ptrCast slice to pointer" { | ||
| 135 | const S = struct { | ||
| 136 | fn doTheTest() !void { | ||
| 137 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
| 138 | var slice: []u8 = &array; | ||
| 139 | var ptr = @ptrCast(*u16, slice); | ||
| 140 | try expect(ptr.* == 65535); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | |||
| 144 | try S.doTheTest(); | ||
| 145 | comptime try S.doTheTest(); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "slice syntax resulting in pointer-to-array" { | ||
| 149 | const S = struct { | ||
| 150 | fn doTheTest() !void { | ||
| 151 | try testArray(); | ||
| 152 | try testArrayZ(); | ||
| 153 | try testArray0(); | ||
| 154 | try testArrayAlign(); | ||
| 155 | try testPointer(); | ||
| 156 | try testPointerZ(); | ||
| 157 | try testPointer0(); | ||
| 158 | try testPointerAlign(); | ||
| 159 | try testSlice(); | ||
| 160 | try testSliceZ(); | ||
| 161 | try testSlice0(); | ||
| 162 | try testSliceOpt(); | ||
| 163 | try testSliceAlign(); | ||
| 164 | } | ||
| 165 | |||
| 166 | fn testArray() !void { | ||
| 167 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 168 | var slice = array[1..3]; | ||
| 169 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 170 | try expect(slice[0] == 2); | ||
| 171 | try expect(slice[1] == 3); | ||
| 172 | } | ||
| 173 | |||
| 174 | fn testArrayZ() !void { | ||
| 175 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 176 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | ||
| 177 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | ||
| 178 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | ||
| 179 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | ||
| 180 | } | ||
| 181 | |||
| 182 | fn testArray0() !void { | ||
| 183 | { | ||
| 184 | var array = [0]u8{}; | ||
| 185 | var slice = array[0..0]; | ||
| 186 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 187 | } | ||
| 188 | { | ||
| 189 | var array = [0:0]u8{}; | ||
| 190 | var slice = array[0..0]; | ||
| 191 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | ||
| 192 | try expect(slice[0] == 0); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | fn testArrayAlign() !void { | ||
| 197 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 198 | var slice = array[4..5]; | ||
| 199 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 200 | try expect(slice[0] == 5); | ||
| 201 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | ||
| 202 | } | ||
| 203 | |||
| 204 | fn testPointer() !void { | ||
| 205 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 206 | var pointer: [*]u8 = &array; | ||
| 207 | var slice = pointer[1..3]; | ||
| 208 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 209 | try expect(slice[0] == 2); | ||
| 210 | try expect(slice[1] == 3); | ||
| 211 | } | ||
| 212 | |||
| 213 | fn testPointerZ() !void { | ||
| 214 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 215 | var pointer: [*:0]u8 = &array; | ||
| 216 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | ||
| 217 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | ||
| 218 | } | ||
| 219 | |||
| 220 | fn testPointer0() !void { | ||
| 221 | var pointer: [*]const u0 = &[1]u0{0}; | ||
| 222 | var slice = pointer[0..1]; | ||
| 223 | comptime try expect(@TypeOf(slice) == *const [1]u0); | ||
| 224 | try expect(slice[0] == 0); | ||
| 225 | } | ||
| 226 | |||
| 227 | fn testPointerAlign() !void { | ||
| 228 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 229 | var pointer: [*]align(4) u8 = &array; | ||
| 230 | var slice = pointer[4..5]; | ||
| 231 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 232 | try expect(slice[0] == 5); | ||
| 233 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | ||
| 234 | } | ||
| 235 | |||
| 236 | fn testSlice() !void { | ||
| 237 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 238 | var src_slice: []u8 = &array; | ||
| 239 | var slice = src_slice[1..3]; | ||
| 240 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 241 | try expect(slice[0] == 2); | ||
| 242 | try expect(slice[1] == 3); | ||
| 243 | } | ||
| 244 | |||
| 245 | fn testSliceZ() !void { | ||
| 246 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 247 | var slice: [:0]u8 = &array; | ||
| 248 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | ||
| 249 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | ||
| 250 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | ||
| 251 | } | ||
| 252 | |||
| 253 | fn testSliceOpt() !void { | ||
| 254 | var array: [2]u8 = [2]u8{ 1, 2 }; | ||
| 255 | var slice: ?[]u8 = &array; | ||
| 256 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | ||
| 257 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | ||
| 258 | } | ||
| 259 | |||
| 260 | fn testSlice0() !void { | ||
| 261 | { | ||
| 262 | var array = [0]u8{}; | ||
| 263 | var src_slice: []u8 = &array; | ||
| 264 | var slice = src_slice[0..0]; | ||
| 265 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 266 | } | ||
| 267 | { | ||
| 268 | var array = [0:0]u8{}; | ||
| 269 | var src_slice: [:0]u8 = &array; | ||
| 270 | var slice = src_slice[0..0]; | ||
| 271 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | fn testSliceAlign() !void { | ||
| 276 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 277 | var src_slice: []align(4) u8 = &array; | ||
| 278 | var slice = src_slice[4..5]; | ||
| 279 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 280 | try expect(slice[0] == 5); | ||
| 281 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | ||
| 282 | } | ||
| 283 | |||
| 284 | fn testConcatStrLiterals() !void { | ||
| 285 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | ||
| 286 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | |||
| 290 | try S.doTheTest(); | ||
| 291 | comptime try S.doTheTest(); | ||
| 292 | } | ||
| 293 | |||
| 294 | test "slice of hardcoded address to pointer" { | ||
| 295 | const S = struct { | ||
| 296 | fn doTheTest() !void { | ||
| 297 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | ||
| 298 | comptime try expect(@TypeOf(pointer) == *[2]u8); | ||
| 299 | const slice: []const u8 = pointer; | ||
| 300 | try expect(@ptrToInt(slice.ptr) == 4); | ||
| 301 | try expect(slice.len == 2); | ||
| 302 | } | ||
| 303 | }; | ||
| 304 | |||
| 305 | try S.doTheTest(); | ||
| 306 | } | ||
| 307 | |||
| 308 | test "type coercion of pointer to anon struct literal to pointer to slice" { | ||
| 309 | const S = struct { | ||
| 310 | const U = union { | ||
| 311 | a: u32, | ||
| 312 | b: bool, | ||
| 313 | c: []const u8, | ||
| 314 | }; | ||
| 315 | |||
| 316 | fn doTheTest() !void { | ||
| 317 | var x1: u8 = 42; | ||
| 318 | const t1 = &.{ x1, 56, 54 }; | ||
| 319 | var slice1: []const u8 = t1; | ||
| 320 | try expect(slice1.len == 3); | ||
| 321 | try expect(slice1[0] == 42); | ||
| 322 | try expect(slice1[1] == 56); | ||
| 323 | try expect(slice1[2] == 54); | ||
| 324 | |||
| 325 | var x2: []const u8 = "hello"; | ||
| 326 | const t2 = &.{ x2, ", ", "world!" }; | ||
| 327 | // @compileLog(@TypeOf(t2)); | ||
| 328 | var slice2: []const []const u8 = t2; | ||
| 329 | try expect(slice2.len == 3); | ||
| 330 | try expect(mem.eql(u8, slice2[0], "hello")); | ||
| 331 | try expect(mem.eql(u8, slice2[1], ", ")); | ||
| 332 | try expect(mem.eql(u8, slice2[2], "world!")); | ||
| 333 | } | ||
| 334 | }; | ||
| 335 | // try S.doTheTest(); | ||
| 336 | comptime try S.doTheTest(); | ||
| 337 | } | ||
test/behavior/slice_sentinel_comptime.zig created+199| ... | @@ -0,0 +1,199 @@ | ||
| 1 | test "comptime slice-sentinel in bounds (unterminated)" { | ||
| 2 | // array | ||
| 3 | comptime { | ||
| 4 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 5 | const slice = target[0..3 :'d']; | ||
| 6 | } | ||
| 7 | |||
| 8 | // ptr_array | ||
| 9 | comptime { | ||
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 11 | var target = &buf; | ||
| 12 | const slice = target[0..3 :'d']; | ||
| 13 | } | ||
| 14 | |||
| 15 | // vector_ConstPtrSpecialBaseArray | ||
| 16 | comptime { | ||
| 17 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 18 | var target: [*]u8 = &buf; | ||
| 19 | const slice = target[0..3 :'d']; | ||
| 20 | } | ||
| 21 | |||
| 22 | // vector_ConstPtrSpecialRef | ||
| 23 | comptime { | ||
| 24 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 25 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 26 | const slice = target[0..3 :'d']; | ||
| 27 | } | ||
| 28 | |||
| 29 | // cvector_ConstPtrSpecialBaseArray | ||
| 30 | comptime { | ||
| 31 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 32 | var target: [*c]u8 = &buf; | ||
| 33 | const slice = target[0..3 :'d']; | ||
| 34 | } | ||
| 35 | |||
| 36 | // cvector_ConstPtrSpecialRef | ||
| 37 | comptime { | ||
| 38 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 39 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 40 | const slice = target[0..3 :'d']; | ||
| 41 | } | ||
| 42 | |||
| 43 | // slice | ||
| 44 | comptime { | ||
| 45 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 46 | var target: []u8 = &buf; | ||
| 47 | const slice = target[0..3 :'d']; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | test "comptime slice-sentinel in bounds (end,unterminated)" { | ||
| 52 | // array | ||
| 53 | comptime { | ||
| 54 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 55 | const slice = target[0..13 :0xff]; | ||
| 56 | } | ||
| 57 | |||
| 58 | // ptr_array | ||
| 59 | comptime { | ||
| 60 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 61 | var target = &buf; | ||
| 62 | const slice = target[0..13 :0xff]; | ||
| 63 | } | ||
| 64 | |||
| 65 | // vector_ConstPtrSpecialBaseArray | ||
| 66 | comptime { | ||
| 67 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 68 | var target: [*]u8 = &buf; | ||
| 69 | const slice = target[0..13 :0xff]; | ||
| 70 | } | ||
| 71 | |||
| 72 | // vector_ConstPtrSpecialRef | ||
| 73 | comptime { | ||
| 74 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 75 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 76 | const slice = target[0..13 :0xff]; | ||
| 77 | } | ||
| 78 | |||
| 79 | // cvector_ConstPtrSpecialBaseArray | ||
| 80 | comptime { | ||
| 81 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 82 | var target: [*c]u8 = &buf; | ||
| 83 | const slice = target[0..13 :0xff]; | ||
| 84 | } | ||
| 85 | |||
| 86 | // cvector_ConstPtrSpecialRef | ||
| 87 | comptime { | ||
| 88 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 89 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 90 | const slice = target[0..13 :0xff]; | ||
| 91 | } | ||
| 92 | |||
| 93 | // slice | ||
| 94 | comptime { | ||
| 95 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 96 | var target: []u8 = &buf; | ||
| 97 | const slice = target[0..13 :0xff]; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | test "comptime slice-sentinel in bounds (terminated)" { | ||
| 102 | // array | ||
| 103 | comptime { | ||
| 104 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 105 | const slice = target[0..3 :'d']; | ||
| 106 | } | ||
| 107 | |||
| 108 | // ptr_array | ||
| 109 | comptime { | ||
| 110 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 111 | var target = &buf; | ||
| 112 | const slice = target[0..3 :'d']; | ||
| 113 | } | ||
| 114 | |||
| 115 | // vector_ConstPtrSpecialBaseArray | ||
| 116 | comptime { | ||
| 117 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 118 | var target: [*]u8 = &buf; | ||
| 119 | const slice = target[0..3 :'d']; | ||
| 120 | } | ||
| 121 | |||
| 122 | // vector_ConstPtrSpecialRef | ||
| 123 | comptime { | ||
| 124 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 125 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 126 | const slice = target[0..3 :'d']; | ||
| 127 | } | ||
| 128 | |||
| 129 | // cvector_ConstPtrSpecialBaseArray | ||
| 130 | comptime { | ||
| 131 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 132 | var target: [*c]u8 = &buf; | ||
| 133 | const slice = target[0..3 :'d']; | ||
| 134 | } | ||
| 135 | |||
| 136 | // cvector_ConstPtrSpecialRef | ||
| 137 | comptime { | ||
| 138 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 139 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 140 | const slice = target[0..3 :'d']; | ||
| 141 | } | ||
| 142 | |||
| 143 | // slice | ||
| 144 | comptime { | ||
| 145 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 146 | var target: []u8 = &buf; | ||
| 147 | const slice = target[0..3 :'d']; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | test "comptime slice-sentinel in bounds (on target sentinel)" { | ||
| 152 | // array | ||
| 153 | comptime { | ||
| 154 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 155 | const slice = target[0..14 :0]; | ||
| 156 | } | ||
| 157 | |||
| 158 | // ptr_array | ||
| 159 | comptime { | ||
| 160 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 161 | var target = &buf; | ||
| 162 | const slice = target[0..14 :0]; | ||
| 163 | } | ||
| 164 | |||
| 165 | // vector_ConstPtrSpecialBaseArray | ||
| 166 | comptime { | ||
| 167 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 168 | var target: [*]u8 = &buf; | ||
| 169 | const slice = target[0..14 :0]; | ||
| 170 | } | ||
| 171 | |||
| 172 | // vector_ConstPtrSpecialRef | ||
| 173 | comptime { | ||
| 174 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 175 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 176 | const slice = target[0..14 :0]; | ||
| 177 | } | ||
| 178 | |||
| 179 | // cvector_ConstPtrSpecialBaseArray | ||
| 180 | comptime { | ||
| 181 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 182 | var target: [*c]u8 = &buf; | ||
| 183 | const slice = target[0..14 :0]; | ||
| 184 | } | ||
| 185 | |||
| 186 | // cvector_ConstPtrSpecialRef | ||
| 187 | comptime { | ||
| 188 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 189 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 190 | const slice = target[0..14 :0]; | ||
| 191 | } | ||
| 192 | |||
| 193 | // slice | ||
| 194 | comptime { | ||
| 195 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 196 | var target: []u8 = &buf; | ||
| 197 | const slice = target[0..14 :0]; | ||
| 198 | } | ||
| 199 | } | ||
test/behavior/src.zig created+17| ... | @@ -0,0 +1,17 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "@src" { | ||
| 5 | try doTheTest(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn doTheTest() !void { | ||
| 9 | const src = @src(); | ||
| 10 | |||
| 11 | try expect(src.line == 9); | ||
| 12 | try expect(src.column == 17); | ||
| 13 | try expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); | ||
| 14 | try expect(std.mem.endsWith(u8, src.file, "src.zig")); | ||
| 15 | try expect(src.fn_name[src.fn_name.len] == 0); | ||
| 16 | try expect(src.file[src.file.len] == 0); | ||
| 17 | } | ||
test/behavior/struct.zig created+946| ... | @@ -0,0 +1,946 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const expectEqual = std.testing.expectEqual; | ||
| 6 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 7 | const maxInt = std.math.maxInt; | ||
| 8 | const StructWithNoFields = struct { | ||
| 9 | fn add(a: i32, b: i32) i32 { | ||
| 10 | return a + b; | ||
| 11 | } | ||
| 12 | }; | ||
| 13 | const empty_global_instance = StructWithNoFields{}; | ||
| 14 | |||
| 15 | top_level_field: i32, | ||
| 16 | |||
| 17 | test "top level fields" { | ||
| 18 | var instance = @This(){ | ||
| 19 | .top_level_field = 1234, | ||
| 20 | }; | ||
| 21 | instance.top_level_field += 1; | ||
| 22 | try expectEqual(@as(i32, 1235), instance.top_level_field); | ||
| 23 | } | ||
| 24 | |||
| 25 | test "call struct static method" { | ||
| 26 | const result = StructWithNoFields.add(3, 4); | ||
| 27 | try expect(result == 7); | ||
| 28 | } | ||
| 29 | |||
| 30 | test "return empty struct instance" { | ||
| 31 | _ = returnEmptyStructInstance(); | ||
| 32 | } | ||
| 33 | fn returnEmptyStructInstance() StructWithNoFields { | ||
| 34 | return empty_global_instance; | ||
| 35 | } | ||
| 36 | |||
| 37 | const should_be_11 = StructWithNoFields.add(5, 6); | ||
| 38 | |||
| 39 | test "invoke static method in global scope" { | ||
| 40 | try expect(should_be_11 == 11); | ||
| 41 | } | ||
| 42 | |||
| 43 | test "void struct fields" { | ||
| 44 | const foo = VoidStructFieldsFoo{ | ||
| 45 | .a = void{}, | ||
| 46 | .b = 1, | ||
| 47 | .c = void{}, | ||
| 48 | }; | ||
| 49 | try expect(foo.b == 1); | ||
| 50 | try expect(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 51 | } | ||
| 52 | const VoidStructFieldsFoo = struct { | ||
| 53 | a: void, | ||
| 54 | b: i32, | ||
| 55 | c: void, | ||
| 56 | }; | ||
| 57 | |||
| 58 | test "structs" { | ||
| 59 | var foo: StructFoo = undefined; | ||
| 60 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 61 | foo.a += 1; | ||
| 62 | foo.b = foo.a == 1; | ||
| 63 | try testFoo(foo); | ||
| 64 | testMutation(&foo); | ||
| 65 | try expect(foo.c == 100); | ||
| 66 | } | ||
| 67 | const StructFoo = struct { | ||
| 68 | a: i32, | ||
| 69 | b: bool, | ||
| 70 | c: f32, | ||
| 71 | }; | ||
| 72 | fn testFoo(foo: StructFoo) !void { | ||
| 73 | try expect(foo.b); | ||
| 74 | } | ||
| 75 | fn testMutation(foo: *StructFoo) void { | ||
| 76 | foo.c = 100; | ||
| 77 | } | ||
| 78 | |||
| 79 | const Node = struct { | ||
| 80 | val: Val, | ||
| 81 | next: *Node, | ||
| 82 | }; | ||
| 83 | |||
| 84 | const Val = struct { | ||
| 85 | x: i32, | ||
| 86 | }; | ||
| 87 | |||
| 88 | test "struct point to self" { | ||
| 89 | var root: Node = undefined; | ||
| 90 | root.val.x = 1; | ||
| 91 | |||
| 92 | var node: Node = undefined; | ||
| 93 | node.next = &root; | ||
| 94 | node.val.x = 2; | ||
| 95 | |||
| 96 | root.next = &node; | ||
| 97 | |||
| 98 | try expect(node.next.next.next.val.x == 1); | ||
| 99 | } | ||
| 100 | |||
| 101 | test "struct byval assign" { | ||
| 102 | var foo1: StructFoo = undefined; | ||
| 103 | var foo2: StructFoo = undefined; | ||
| 104 | |||
| 105 | foo1.a = 1234; | ||
| 106 | foo2.a = 0; | ||
| 107 | try expect(foo2.a == 0); | ||
| 108 | foo2 = foo1; | ||
| 109 | try expect(foo2.a == 1234); | ||
| 110 | } | ||
| 111 | |||
| 112 | fn structInitializer() void { | ||
| 113 | const val = Val{ .x = 42 }; | ||
| 114 | try expect(val.x == 42); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "fn call of struct field" { | ||
| 118 | const Foo = struct { | ||
| 119 | ptr: fn () i32, | ||
| 120 | }; | ||
| 121 | const S = struct { | ||
| 122 | fn aFunc() i32 { | ||
| 123 | return 13; | ||
| 124 | } | ||
| 125 | |||
| 126 | fn callStructField(foo: Foo) i32 { | ||
| 127 | return foo.ptr(); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | |||
| 131 | try expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13); | ||
| 132 | } | ||
| 133 | |||
| 134 | test "store member function in variable" { | ||
| 135 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 136 | const memberFn = MemberFnTestFoo.member; | ||
| 137 | const result = memberFn(instance); | ||
| 138 | try expect(result == 1234); | ||
| 139 | } | ||
| 140 | const MemberFnTestFoo = struct { | ||
| 141 | x: i32, | ||
| 142 | fn member(foo: MemberFnTestFoo) i32 { | ||
| 143 | return foo.x; | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | |||
| 147 | test "call member function directly" { | ||
| 148 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 149 | const result = MemberFnTestFoo.member(instance); | ||
| 150 | try expect(result == 1234); | ||
| 151 | } | ||
| 152 | |||
| 153 | test "member functions" { | ||
| 154 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 155 | try expect(r.getSeed() == 1234); | ||
| 156 | } | ||
| 157 | const MemberFnRand = struct { | ||
| 158 | seed: u32, | ||
| 159 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 160 | return r.seed; | ||
| 161 | } | ||
| 162 | }; | ||
| 163 | |||
| 164 | test "return struct byval from function" { | ||
| 165 | const bar = makeBar(1234, 5678); | ||
| 166 | try expect(bar.y == 5678); | ||
| 167 | } | ||
| 168 | const Bar = struct { | ||
| 169 | x: i32, | ||
| 170 | y: i32, | ||
| 171 | }; | ||
| 172 | fn makeBar(x: i32, y: i32) Bar { | ||
| 173 | return Bar{ | ||
| 174 | .x = x, | ||
| 175 | .y = y, | ||
| 176 | }; | ||
| 177 | } | ||
| 178 | |||
| 179 | test "empty struct method call" { | ||
| 180 | const es = EmptyStruct{}; | ||
| 181 | try expect(es.method() == 1234); | ||
| 182 | } | ||
| 183 | const EmptyStruct = struct { | ||
| 184 | fn method(es: *const EmptyStruct) i32 { | ||
| 185 | return 1234; | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | |||
| 189 | test "return empty struct from fn" { | ||
| 190 | _ = testReturnEmptyStructFromFn(); | ||
| 191 | } | ||
| 192 | const EmptyStruct2 = struct {}; | ||
| 193 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 194 | return EmptyStruct2{}; | ||
| 195 | } | ||
| 196 | |||
| 197 | test "pass slice of empty struct to fn" { | ||
| 198 | try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1); | ||
| 199 | } | ||
| 200 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { | ||
| 201 | return slice.len; | ||
| 202 | } | ||
| 203 | |||
| 204 | const APackedStruct = packed struct { | ||
| 205 | x: u8, | ||
| 206 | y: u8, | ||
| 207 | }; | ||
| 208 | |||
| 209 | test "packed struct" { | ||
| 210 | var foo = APackedStruct{ | ||
| 211 | .x = 1, | ||
| 212 | .y = 2, | ||
| 213 | }; | ||
| 214 | foo.y += 1; | ||
| 215 | const four = foo.x + foo.y; | ||
| 216 | try expect(four == 4); | ||
| 217 | } | ||
| 218 | |||
| 219 | const BitField1 = packed struct { | ||
| 220 | a: u3, | ||
| 221 | b: u3, | ||
| 222 | c: u2, | ||
| 223 | }; | ||
| 224 | |||
| 225 | const bit_field_1 = BitField1{ | ||
| 226 | .a = 1, | ||
| 227 | .b = 2, | ||
| 228 | .c = 3, | ||
| 229 | }; | ||
| 230 | |||
| 231 | test "bit field access" { | ||
| 232 | var data = bit_field_1; | ||
| 233 | try expect(getA(&data) == 1); | ||
| 234 | try expect(getB(&data) == 2); | ||
| 235 | try expect(getC(&data) == 3); | ||
| 236 | comptime try expect(@sizeOf(BitField1) == 1); | ||
| 237 | |||
| 238 | data.b += 1; | ||
| 239 | try expect(data.b == 3); | ||
| 240 | |||
| 241 | data.a += 1; | ||
| 242 | try expect(data.a == 2); | ||
| 243 | try expect(data.b == 3); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn getA(data: *const BitField1) u3 { | ||
| 247 | return data.a; | ||
| 248 | } | ||
| 249 | |||
| 250 | fn getB(data: *const BitField1) u3 { | ||
| 251 | return data.b; | ||
| 252 | } | ||
| 253 | |||
| 254 | fn getC(data: *const BitField1) u2 { | ||
| 255 | return data.c; | ||
| 256 | } | ||
| 257 | |||
| 258 | const Foo24Bits = packed struct { | ||
| 259 | field: u24, | ||
| 260 | }; | ||
| 261 | const Foo96Bits = packed struct { | ||
| 262 | a: u24, | ||
| 263 | b: u24, | ||
| 264 | c: u24, | ||
| 265 | d: u24, | ||
| 266 | }; | ||
| 267 | |||
| 268 | test "packed struct 24bits" { | ||
| 269 | comptime { | ||
| 270 | try expect(@sizeOf(Foo24Bits) == 4); | ||
| 271 | if (@sizeOf(usize) == 4) { | ||
| 272 | try expect(@sizeOf(Foo96Bits) == 12); | ||
| 273 | } else { | ||
| 274 | try expect(@sizeOf(Foo96Bits) == 16); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | var value = Foo96Bits{ | ||
| 279 | .a = 0, | ||
| 280 | .b = 0, | ||
| 281 | .c = 0, | ||
| 282 | .d = 0, | ||
| 283 | }; | ||
| 284 | value.a += 1; | ||
| 285 | try expect(value.a == 1); | ||
| 286 | try expect(value.b == 0); | ||
| 287 | try expect(value.c == 0); | ||
| 288 | try expect(value.d == 0); | ||
| 289 | |||
| 290 | value.b += 1; | ||
| 291 | try expect(value.a == 1); | ||
| 292 | try expect(value.b == 1); | ||
| 293 | try expect(value.c == 0); | ||
| 294 | try expect(value.d == 0); | ||
| 295 | |||
| 296 | value.c += 1; | ||
| 297 | try expect(value.a == 1); | ||
| 298 | try expect(value.b == 1); | ||
| 299 | try expect(value.c == 1); | ||
| 300 | try expect(value.d == 0); | ||
| 301 | |||
| 302 | value.d += 1; | ||
| 303 | try expect(value.a == 1); | ||
| 304 | try expect(value.b == 1); | ||
| 305 | try expect(value.c == 1); | ||
| 306 | try expect(value.d == 1); | ||
| 307 | } | ||
| 308 | |||
| 309 | const Foo32Bits = packed struct { | ||
| 310 | field: u24, | ||
| 311 | pad: u8, | ||
| 312 | }; | ||
| 313 | |||
| 314 | const FooArray24Bits = packed struct { | ||
| 315 | a: u16, | ||
| 316 | b: [2]Foo32Bits, | ||
| 317 | c: u16, | ||
| 318 | }; | ||
| 319 | |||
| 320 | // TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512 | ||
| 321 | test "packed array 24bits" { | ||
| 322 | comptime { | ||
| 323 | try expect(@sizeOf([9]Foo32Bits) == 9 * 4); | ||
| 324 | try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2); | ||
| 325 | } | ||
| 326 | |||
| 327 | var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1); | ||
| 328 | bytes[bytes.len - 1] = 0xaa; | ||
| 329 | const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; | ||
| 330 | try expect(ptr.a == 0); | ||
| 331 | try expect(ptr.b[0].field == 0); | ||
| 332 | try expect(ptr.b[1].field == 0); | ||
| 333 | try expect(ptr.c == 0); | ||
| 334 | |||
| 335 | ptr.a = maxInt(u16); | ||
| 336 | try expect(ptr.a == maxInt(u16)); | ||
| 337 | try expect(ptr.b[0].field == 0); | ||
| 338 | try expect(ptr.b[1].field == 0); | ||
| 339 | try expect(ptr.c == 0); | ||
| 340 | |||
| 341 | ptr.b[0].field = maxInt(u24); | ||
| 342 | try expect(ptr.a == maxInt(u16)); | ||
| 343 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 344 | try expect(ptr.b[1].field == 0); | ||
| 345 | try expect(ptr.c == 0); | ||
| 346 | |||
| 347 | ptr.b[1].field = maxInt(u24); | ||
| 348 | try expect(ptr.a == maxInt(u16)); | ||
| 349 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 350 | try expect(ptr.b[1].field == maxInt(u24)); | ||
| 351 | try expect(ptr.c == 0); | ||
| 352 | |||
| 353 | ptr.c = maxInt(u16); | ||
| 354 | try expect(ptr.a == maxInt(u16)); | ||
| 355 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 356 | try expect(ptr.b[1].field == maxInt(u24)); | ||
| 357 | try expect(ptr.c == maxInt(u16)); | ||
| 358 | |||
| 359 | try expect(bytes[bytes.len - 1] == 0xaa); | ||
| 360 | } | ||
| 361 | |||
| 362 | const FooStructAligned = packed struct { | ||
| 363 | a: u8, | ||
| 364 | b: u8, | ||
| 365 | }; | ||
| 366 | |||
| 367 | const FooArrayOfAligned = packed struct { | ||
| 368 | a: [2]FooStructAligned, | ||
| 369 | }; | ||
| 370 | |||
| 371 | test "aligned array of packed struct" { | ||
| 372 | comptime { | ||
| 373 | try expect(@sizeOf(FooStructAligned) == 2); | ||
| 374 | try expect(@sizeOf(FooArrayOfAligned) == 2 * 2); | ||
| 375 | } | ||
| 376 | |||
| 377 | var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned); | ||
| 378 | const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0]; | ||
| 379 | |||
| 380 | try expect(ptr.a[0].a == 0xbb); | ||
| 381 | try expect(ptr.a[0].b == 0xbb); | ||
| 382 | try expect(ptr.a[1].a == 0xbb); | ||
| 383 | try expect(ptr.a[1].b == 0xbb); | ||
| 384 | } | ||
| 385 | |||
| 386 | test "runtime struct initialization of bitfield" { | ||
| 387 | const s1 = Nibbles{ | ||
| 388 | .x = x1, | ||
| 389 | .y = x1, | ||
| 390 | }; | ||
| 391 | const s2 = Nibbles{ | ||
| 392 | .x = @intCast(u4, x2), | ||
| 393 | .y = @intCast(u4, x2), | ||
| 394 | }; | ||
| 395 | |||
| 396 | try expect(s1.x == x1); | ||
| 397 | try expect(s1.y == x1); | ||
| 398 | try expect(s2.x == @intCast(u4, x2)); | ||
| 399 | try expect(s2.y == @intCast(u4, x2)); | ||
| 400 | } | ||
| 401 | |||
| 402 | var x1 = @as(u4, 1); | ||
| 403 | var x2 = @as(u8, 2); | ||
| 404 | |||
| 405 | const Nibbles = packed struct { | ||
| 406 | x: u4, | ||
| 407 | y: u4, | ||
| 408 | }; | ||
| 409 | |||
| 410 | const Bitfields = packed struct { | ||
| 411 | f1: u16, | ||
| 412 | f2: u16, | ||
| 413 | f3: u8, | ||
| 414 | f4: u8, | ||
| 415 | f5: u4, | ||
| 416 | f6: u4, | ||
| 417 | f7: u8, | ||
| 418 | }; | ||
| 419 | |||
| 420 | test "native bit field understands endianness" { | ||
| 421 | var all: u64 = if (native_endian != .Little) | ||
| 422 | 0x1111222233445677 | ||
| 423 | else | ||
| 424 | 0x7765443322221111; | ||
| 425 | var bytes: [8]u8 = undefined; | ||
| 426 | @memcpy(&bytes, @ptrCast([*]u8, &all), 8); | ||
| 427 | var bitfields = @ptrCast(*Bitfields, &bytes).*; | ||
| 428 | |||
| 429 | try expect(bitfields.f1 == 0x1111); | ||
| 430 | try expect(bitfields.f2 == 0x2222); | ||
| 431 | try expect(bitfields.f3 == 0x33); | ||
| 432 | try expect(bitfields.f4 == 0x44); | ||
| 433 | try expect(bitfields.f5 == 0x5); | ||
| 434 | try expect(bitfields.f6 == 0x6); | ||
| 435 | try expect(bitfields.f7 == 0x77); | ||
| 436 | } | ||
| 437 | |||
| 438 | test "align 1 field before self referential align 8 field as slice return type" { | ||
| 439 | const result = alloc(Expr); | ||
| 440 | try expect(result.len == 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | const Expr = union(enum) { | ||
| 444 | Literal: u8, | ||
| 445 | Question: *Expr, | ||
| 446 | }; | ||
| 447 | |||
| 448 | fn alloc(comptime T: type) []T { | ||
| 449 | return &[_]T{}; | ||
| 450 | } | ||
| 451 | |||
| 452 | test "call method with mutable reference to struct with no fields" { | ||
| 453 | const S = struct { | ||
| 454 | fn doC(s: *const @This()) bool { | ||
| 455 | return true; | ||
| 456 | } | ||
| 457 | fn do(s: *@This()) bool { | ||
| 458 | return true; | ||
| 459 | } | ||
| 460 | }; | ||
| 461 | |||
| 462 | var s = S{}; | ||
| 463 | try expect(S.doC(&s)); | ||
| 464 | try expect(s.doC()); | ||
| 465 | try expect(S.do(&s)); | ||
| 466 | try expect(s.do()); | ||
| 467 | } | ||
| 468 | |||
| 469 | test "implicit cast packed struct field to const ptr" { | ||
| 470 | const LevelUpMove = packed struct { | ||
| 471 | move_id: u9, | ||
| 472 | level: u7, | ||
| 473 | |||
| 474 | fn toInt(value: u7) u7 { | ||
| 475 | return value; | ||
| 476 | } | ||
| 477 | }; | ||
| 478 | |||
| 479 | var lup: LevelUpMove = undefined; | ||
| 480 | lup.level = 12; | ||
| 481 | const res = LevelUpMove.toInt(lup.level); | ||
| 482 | try expect(res == 12); | ||
| 483 | } | ||
| 484 | |||
| 485 | test "pointer to packed struct member in a stack variable" { | ||
| 486 | const S = packed struct { | ||
| 487 | a: u2, | ||
| 488 | b: u2, | ||
| 489 | }; | ||
| 490 | |||
| 491 | var s = S{ .a = 2, .b = 0 }; | ||
| 492 | var b_ptr = &s.b; | ||
| 493 | try expect(s.b == 0); | ||
| 494 | b_ptr.* = 2; | ||
| 495 | try expect(s.b == 2); | ||
| 496 | } | ||
| 497 | |||
| 498 | test "non-byte-aligned array inside packed struct" { | ||
| 499 | const Foo = packed struct { | ||
| 500 | a: bool, | ||
| 501 | b: [0x16]u8, | ||
| 502 | }; | ||
| 503 | const S = struct { | ||
| 504 | fn bar(slice: []const u8) !void { | ||
| 505 | try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu"); | ||
| 506 | } | ||
| 507 | fn doTheTest() !void { | ||
| 508 | var foo = Foo{ | ||
| 509 | .a = true, | ||
| 510 | .b = "abcdefghijklmnopqurstu".*, | ||
| 511 | }; | ||
| 512 | const value = foo.b; | ||
| 513 | try bar(&value); | ||
| 514 | } | ||
| 515 | }; | ||
| 516 | try S.doTheTest(); | ||
| 517 | comptime try S.doTheTest(); | ||
| 518 | } | ||
| 519 | |||
| 520 | test "packed struct with u0 field access" { | ||
| 521 | const S = packed struct { | ||
| 522 | f0: u0, | ||
| 523 | }; | ||
| 524 | var s = S{ .f0 = 0 }; | ||
| 525 | comptime try expect(s.f0 == 0); | ||
| 526 | } | ||
| 527 | |||
| 528 | const S0 = struct { | ||
| 529 | bar: S1, | ||
| 530 | |||
| 531 | pub const S1 = struct { | ||
| 532 | value: u8, | ||
| 533 | }; | ||
| 534 | |||
| 535 | fn init() @This() { | ||
| 536 | return S0{ .bar = S1{ .value = 123 } }; | ||
| 537 | } | ||
| 538 | }; | ||
| 539 | |||
| 540 | var g_foo: S0 = S0.init(); | ||
| 541 | |||
| 542 | test "access to global struct fields" { | ||
| 543 | g_foo.bar.value = 42; | ||
| 544 | try expect(g_foo.bar.value == 42); | ||
| 545 | } | ||
| 546 | |||
| 547 | test "packed struct with fp fields" { | ||
| 548 | const S = packed struct { | ||
| 549 | data: [3]f32, | ||
| 550 | |||
| 551 | pub fn frob(self: *@This()) void { | ||
| 552 | self.data[0] += self.data[1] + self.data[2]; | ||
| 553 | self.data[1] += self.data[0] + self.data[2]; | ||
| 554 | self.data[2] += self.data[0] + self.data[1]; | ||
| 555 | } | ||
| 556 | }; | ||
| 557 | |||
| 558 | var s: S = undefined; | ||
| 559 | s.data[0] = 1.0; | ||
| 560 | s.data[1] = 2.0; | ||
| 561 | s.data[2] = 3.0; | ||
| 562 | s.frob(); | ||
| 563 | try expectEqual(@as(f32, 6.0), s.data[0]); | ||
| 564 | try expectEqual(@as(f32, 11.0), s.data[1]); | ||
| 565 | try expectEqual(@as(f32, 20.0), s.data[2]); | ||
| 566 | } | ||
| 567 | |||
| 568 | test "use within struct scope" { | ||
| 569 | const S = struct { | ||
| 570 | usingnamespace struct { | ||
| 571 | pub fn inner() i32 { | ||
| 572 | return 42; | ||
| 573 | } | ||
| 574 | }; | ||
| 575 | }; | ||
| 576 | try expectEqual(@as(i32, 42), S.inner()); | ||
| 577 | } | ||
| 578 | |||
| 579 | test "default struct initialization fields" { | ||
| 580 | const S = struct { | ||
| 581 | a: i32 = 1234, | ||
| 582 | b: i32, | ||
| 583 | }; | ||
| 584 | const x = S{ | ||
| 585 | .b = 5, | ||
| 586 | }; | ||
| 587 | if (x.a + x.b != 1239) { | ||
| 588 | @compileError("it should be comptime known"); | ||
| 589 | } | ||
| 590 | var five: i32 = 5; | ||
| 591 | const y = S{ | ||
| 592 | .b = five, | ||
| 593 | }; | ||
| 594 | try expectEqual(1239, x.a + x.b); | ||
| 595 | } | ||
| 596 | |||
| 597 | test "fn with C calling convention returns struct by value" { | ||
| 598 | const S = struct { | ||
| 599 | fn entry() !void { | ||
| 600 | var x = makeBar(10); | ||
| 601 | try expectEqual(@as(i32, 10), x.handle); | ||
| 602 | } | ||
| 603 | |||
| 604 | const ExternBar = extern struct { | ||
| 605 | handle: i32, | ||
| 606 | }; | ||
| 607 | |||
| 608 | fn makeBar(t: i32) callconv(.C) ExternBar { | ||
| 609 | return ExternBar{ | ||
| 610 | .handle = t, | ||
| 611 | }; | ||
| 612 | } | ||
| 613 | }; | ||
| 614 | try S.entry(); | ||
| 615 | comptime try S.entry(); | ||
| 616 | } | ||
| 617 | |||
| 618 | test "for loop over pointers to struct, getting field from struct pointer" { | ||
| 619 | const S = struct { | ||
| 620 | const Foo = struct { | ||
| 621 | name: []const u8, | ||
| 622 | }; | ||
| 623 | |||
| 624 | var ok = true; | ||
| 625 | |||
| 626 | fn eql(a: []const u8) bool { | ||
| 627 | return true; | ||
| 628 | } | ||
| 629 | |||
| 630 | const ArrayList = struct { | ||
| 631 | fn toSlice(self: *ArrayList) []*Foo { | ||
| 632 | return @as([*]*Foo, undefined)[0..0]; | ||
| 633 | } | ||
| 634 | }; | ||
| 635 | |||
| 636 | fn doTheTest() !void { | ||
| 637 | var objects: ArrayList = undefined; | ||
| 638 | |||
| 639 | for (objects.toSlice()) |obj| { | ||
| 640 | if (eql(obj.name)) { | ||
| 641 | ok = false; | ||
| 642 | } | ||
| 643 | } | ||
| 644 | |||
| 645 | try expect(ok); | ||
| 646 | } | ||
| 647 | }; | ||
| 648 | try S.doTheTest(); | ||
| 649 | } | ||
| 650 | |||
| 651 | test "zero-bit field in packed struct" { | ||
| 652 | const S = packed struct { | ||
| 653 | x: u10, | ||
| 654 | y: void, | ||
| 655 | }; | ||
| 656 | var x: S = undefined; | ||
| 657 | } | ||
| 658 | |||
| 659 | test "struct field init with catch" { | ||
| 660 | const S = struct { | ||
| 661 | fn doTheTest() !void { | ||
| 662 | var x: anyerror!isize = 1; | ||
| 663 | var req = Foo{ | ||
| 664 | .field = x catch undefined, | ||
| 665 | }; | ||
| 666 | try expect(req.field == 1); | ||
| 667 | } | ||
| 668 | |||
| 669 | pub const Foo = extern struct { | ||
| 670 | field: isize, | ||
| 671 | }; | ||
| 672 | }; | ||
| 673 | try S.doTheTest(); | ||
| 674 | comptime try S.doTheTest(); | ||
| 675 | } | ||
| 676 | |||
| 677 | test "packed struct with non-ABI-aligned field" { | ||
| 678 | const S = packed struct { | ||
| 679 | x: u9, | ||
| 680 | y: u183, | ||
| 681 | }; | ||
| 682 | var s: S = undefined; | ||
| 683 | s.x = 1; | ||
| 684 | s.y = 42; | ||
| 685 | try expect(s.x == 1); | ||
| 686 | try expect(s.y == 42); | ||
| 687 | } | ||
| 688 | |||
| 689 | test "non-packed struct with u128 entry in union" { | ||
| 690 | const U = union(enum) { | ||
| 691 | Num: u128, | ||
| 692 | Void, | ||
| 693 | }; | ||
| 694 | |||
| 695 | const S = struct { | ||
| 696 | f1: U, | ||
| 697 | f2: U, | ||
| 698 | }; | ||
| 699 | |||
| 700 | var sx: S = undefined; | ||
| 701 | var s = &sx; | ||
| 702 | try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @byteOffsetOf(S, "f2")); | ||
| 703 | var v2 = U{ .Num = 123 }; | ||
| 704 | s.f2 = v2; | ||
| 705 | try std.testing.expect(s.f2.Num == 123); | ||
| 706 | } | ||
| 707 | |||
| 708 | test "packed struct field passed to generic function" { | ||
| 709 | const S = struct { | ||
| 710 | const P = packed struct { | ||
| 711 | b: u5, | ||
| 712 | g: u5, | ||
| 713 | r: u5, | ||
| 714 | a: u1, | ||
| 715 | }; | ||
| 716 | |||
| 717 | fn genericReadPackedField(ptr: anytype) u5 { | ||
| 718 | return ptr.*; | ||
| 719 | } | ||
| 720 | }; | ||
| 721 | |||
| 722 | var p: S.P = undefined; | ||
| 723 | p.b = 29; | ||
| 724 | var loaded = S.genericReadPackedField(&p.b); | ||
| 725 | try expect(loaded == 29); | ||
| 726 | } | ||
| 727 | |||
| 728 | test "anonymous struct literal syntax" { | ||
| 729 | const S = struct { | ||
| 730 | const Point = struct { | ||
| 731 | x: i32, | ||
| 732 | y: i32, | ||
| 733 | }; | ||
| 734 | |||
| 735 | fn doTheTest() !void { | ||
| 736 | var p: Point = .{ | ||
| 737 | .x = 1, | ||
| 738 | .y = 2, | ||
| 739 | }; | ||
| 740 | try expect(p.x == 1); | ||
| 741 | try expect(p.y == 2); | ||
| 742 | } | ||
| 743 | }; | ||
| 744 | try S.doTheTest(); | ||
| 745 | comptime try S.doTheTest(); | ||
| 746 | } | ||
| 747 | |||
| 748 | test "fully anonymous struct" { | ||
| 749 | const S = struct { | ||
| 750 | fn doTheTest() !void { | ||
| 751 | try dump(.{ | ||
| 752 | .int = @as(u32, 1234), | ||
| 753 | .float = @as(f64, 12.34), | ||
| 754 | .b = true, | ||
| 755 | .s = "hi", | ||
| 756 | }); | ||
| 757 | } | ||
| 758 | fn dump(args: anytype) !void { | ||
| 759 | try expect(args.int == 1234); | ||
| 760 | try expect(args.float == 12.34); | ||
| 761 | try expect(args.b); | ||
| 762 | try expect(args.s[0] == 'h'); | ||
| 763 | try expect(args.s[1] == 'i'); | ||
| 764 | } | ||
| 765 | }; | ||
| 766 | try S.doTheTest(); | ||
| 767 | comptime try S.doTheTest(); | ||
| 768 | } | ||
| 769 | |||
| 770 | test "fully anonymous list literal" { | ||
| 771 | const S = struct { | ||
| 772 | fn doTheTest() !void { | ||
| 773 | try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); | ||
| 774 | } | ||
| 775 | fn dump(args: anytype) !void { | ||
| 776 | try expect(args.@"0" == 1234); | ||
| 777 | try expect(args.@"1" == 12.34); | ||
| 778 | try expect(args.@"2"); | ||
| 779 | try expect(args.@"3"[0] == 'h'); | ||
| 780 | try expect(args.@"3"[1] == 'i'); | ||
| 781 | } | ||
| 782 | }; | ||
| 783 | try S.doTheTest(); | ||
| 784 | comptime try S.doTheTest(); | ||
| 785 | } | ||
| 786 | |||
| 787 | test "anonymous struct literal assigned to variable" { | ||
| 788 | var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; | ||
| 789 | try expect(vec.@"0" == 22); | ||
| 790 | try expect(vec.@"1" == 55); | ||
| 791 | try expect(vec.@"2" == 99); | ||
| 792 | } | ||
| 793 | |||
| 794 | test "struct with var field" { | ||
| 795 | const Point = struct { | ||
| 796 | x: anytype, | ||
| 797 | y: anytype, | ||
| 798 | }; | ||
| 799 | const pt = Point{ | ||
| 800 | .x = 1, | ||
| 801 | .y = 2, | ||
| 802 | }; | ||
| 803 | try expect(pt.x == 1); | ||
| 804 | try expect(pt.y == 2); | ||
| 805 | } | ||
| 806 | |||
| 807 | test "comptime struct field" { | ||
| 808 | const T = struct { | ||
| 809 | a: i32, | ||
| 810 | comptime b: i32 = 1234, | ||
| 811 | }; | ||
| 812 | |||
| 813 | var foo: T = undefined; | ||
| 814 | comptime try expect(foo.b == 1234); | ||
| 815 | } | ||
| 816 | |||
| 817 | test "anon struct literal field value initialized with fn call" { | ||
| 818 | const S = struct { | ||
| 819 | fn doTheTest() !void { | ||
| 820 | var x = .{foo()}; | ||
| 821 | try expectEqualSlices(u8, x[0], "hi"); | ||
| 822 | } | ||
| 823 | fn foo() []const u8 { | ||
| 824 | return "hi"; | ||
| 825 | } | ||
| 826 | }; | ||
| 827 | try S.doTheTest(); | ||
| 828 | comptime try S.doTheTest(); | ||
| 829 | } | ||
| 830 | |||
| 831 | test "self-referencing struct via array member" { | ||
| 832 | const T = struct { | ||
| 833 | children: [1]*@This(), | ||
| 834 | }; | ||
| 835 | var x: T = undefined; | ||
| 836 | x = T{ .children = .{&x} }; | ||
| 837 | try expect(x.children[0] == &x); | ||
| 838 | } | ||
| 839 | |||
| 840 | test "struct with union field" { | ||
| 841 | const Value = struct { | ||
| 842 | ref: u32 = 2, | ||
| 843 | kind: union(enum) { | ||
| 844 | None: usize, | ||
| 845 | Bool: bool, | ||
| 846 | }, | ||
| 847 | }; | ||
| 848 | |||
| 849 | var True = Value{ | ||
| 850 | .kind = .{ .Bool = true }, | ||
| 851 | }; | ||
| 852 | try expectEqual(@as(u32, 2), True.ref); | ||
| 853 | try expectEqual(true, True.kind.Bool); | ||
| 854 | } | ||
| 855 | |||
| 856 | test "type coercion of anon struct literal to struct" { | ||
| 857 | const S = struct { | ||
| 858 | const S2 = struct { | ||
| 859 | A: u32, | ||
| 860 | B: []const u8, | ||
| 861 | C: void, | ||
| 862 | D: Foo = .{}, | ||
| 863 | }; | ||
| 864 | |||
| 865 | const Foo = struct { | ||
| 866 | field: i32 = 1234, | ||
| 867 | }; | ||
| 868 | |||
| 869 | fn doTheTest() !void { | ||
| 870 | var y: u32 = 42; | ||
| 871 | const t0 = .{ .A = 123, .B = "foo", .C = {} }; | ||
| 872 | const t1 = .{ .A = y, .B = "foo", .C = {} }; | ||
| 873 | const y0: S2 = t0; | ||
| 874 | var y1: S2 = t1; | ||
| 875 | try expect(y0.A == 123); | ||
| 876 | try expect(std.mem.eql(u8, y0.B, "foo")); | ||
| 877 | try expect(y0.C == {}); | ||
| 878 | try expect(y0.D.field == 1234); | ||
| 879 | try expect(y1.A == y); | ||
| 880 | try expect(std.mem.eql(u8, y1.B, "foo")); | ||
| 881 | try expect(y1.C == {}); | ||
| 882 | try expect(y1.D.field == 1234); | ||
| 883 | } | ||
| 884 | }; | ||
| 885 | try S.doTheTest(); | ||
| 886 | comptime try S.doTheTest(); | ||
| 887 | } | ||
| 888 | |||
| 889 | test "type coercion of pointer to anon struct literal to pointer to struct" { | ||
| 890 | const S = struct { | ||
| 891 | const S2 = struct { | ||
| 892 | A: u32, | ||
| 893 | B: []const u8, | ||
| 894 | C: void, | ||
| 895 | D: Foo = .{}, | ||
| 896 | }; | ||
| 897 | |||
| 898 | const Foo = struct { | ||
| 899 | field: i32 = 1234, | ||
| 900 | }; | ||
| 901 | |||
| 902 | fn doTheTest() !void { | ||
| 903 | var y: u32 = 42; | ||
| 904 | const t0 = &.{ .A = 123, .B = "foo", .C = {} }; | ||
| 905 | const t1 = &.{ .A = y, .B = "foo", .C = {} }; | ||
| 906 | const y0: *const S2 = t0; | ||
| 907 | var y1: *const S2 = t1; | ||
| 908 | try expect(y0.A == 123); | ||
| 909 | try expect(std.mem.eql(u8, y0.B, "foo")); | ||
| 910 | try expect(y0.C == {}); | ||
| 911 | try expect(y0.D.field == 1234); | ||
| 912 | try expect(y1.A == y); | ||
| 913 | try expect(std.mem.eql(u8, y1.B, "foo")); | ||
| 914 | try expect(y1.C == {}); | ||
| 915 | try expect(y1.D.field == 1234); | ||
| 916 | } | ||
| 917 | }; | ||
| 918 | try S.doTheTest(); | ||
| 919 | comptime try S.doTheTest(); | ||
| 920 | } | ||
| 921 | |||
| 922 | test "packed struct with undefined initializers" { | ||
| 923 | const S = struct { | ||
| 924 | const P = packed struct { | ||
| 925 | a: u3, | ||
| 926 | _a: u3 = undefined, | ||
| 927 | b: u3, | ||
| 928 | _b: u3 = undefined, | ||
| 929 | c: u3, | ||
| 930 | _c: u3 = undefined, | ||
| 931 | }; | ||
| 932 | |||
| 933 | fn doTheTest() !void { | ||
| 934 | var p: P = undefined; | ||
| 935 | p = P{ .a = 2, .b = 4, .c = 6 }; | ||
| 936 | // Make sure the compiler doesn't touch the unprefixed fields. | ||
| 937 | // Use expect since i386-linux doesn't like expectEqual | ||
| 938 | try expect(p.a == 2); | ||
| 939 | try expect(p.b == 4); | ||
| 940 | try expect(p.c == 6); | ||
| 941 | } | ||
| 942 | }; | ||
| 943 | |||
| 944 | try S.doTheTest(); | ||
| 945 | comptime try S.doTheTest(); | ||
| 946 | } | ||
test/behavior/struct_contains_null_ptr_itself.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "struct contains null pointer which contains original struct" { | ||
| 5 | var x: ?*NodeLineComment = null; | ||
| 6 | try expect(x == null); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub const Node = struct { | ||
| 10 | id: Id, | ||
| 11 | comment: ?*NodeLineComment, | ||
| 12 | |||
| 13 | pub const Id = enum { | ||
| 14 | Root, | ||
| 15 | LineComment, | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub const NodeLineComment = struct { | ||
| 20 | base: Node, | ||
| 21 | }; | ||
test/behavior/struct_contains_slice_of_itself.zig created+85| ... | @@ -0,0 +1,85 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Node = struct { | ||
| 4 | payload: i32, | ||
| 5 | children: []Node, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const NodeAligned = struct { | ||
| 9 | payload: i32, | ||
| 10 | children: []align(@alignOf(NodeAligned)) NodeAligned, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "struct contains slice of itself" { | ||
| 14 | var other_nodes = [_]Node{ | ||
| 15 | Node{ | ||
| 16 | .payload = 31, | ||
| 17 | .children = &[_]Node{}, | ||
| 18 | }, | ||
| 19 | Node{ | ||
| 20 | .payload = 32, | ||
| 21 | .children = &[_]Node{}, | ||
| 22 | }, | ||
| 23 | }; | ||
| 24 | var nodes = [_]Node{ | ||
| 25 | Node{ | ||
| 26 | .payload = 1, | ||
| 27 | .children = &[_]Node{}, | ||
| 28 | }, | ||
| 29 | Node{ | ||
| 30 | .payload = 2, | ||
| 31 | .children = &[_]Node{}, | ||
| 32 | }, | ||
| 33 | Node{ | ||
| 34 | .payload = 3, | ||
| 35 | .children = other_nodes[0..], | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | const root = Node{ | ||
| 39 | .payload = 1234, | ||
| 40 | .children = nodes[0..], | ||
| 41 | }; | ||
| 42 | try expect(root.payload == 1234); | ||
| 43 | try expect(root.children[0].payload == 1); | ||
| 44 | try expect(root.children[1].payload == 2); | ||
| 45 | try expect(root.children[2].payload == 3); | ||
| 46 | try expect(root.children[2].children[0].payload == 31); | ||
| 47 | try expect(root.children[2].children[1].payload == 32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "struct contains aligned slice of itself" { | ||
| 51 | var other_nodes = [_]NodeAligned{ | ||
| 52 | NodeAligned{ | ||
| 53 | .payload = 31, | ||
| 54 | .children = &[_]NodeAligned{}, | ||
| 55 | }, | ||
| 56 | NodeAligned{ | ||
| 57 | .payload = 32, | ||
| 58 | .children = &[_]NodeAligned{}, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | var nodes = [_]NodeAligned{ | ||
| 62 | NodeAligned{ | ||
| 63 | .payload = 1, | ||
| 64 | .children = &[_]NodeAligned{}, | ||
| 65 | }, | ||
| 66 | NodeAligned{ | ||
| 67 | .payload = 2, | ||
| 68 | .children = &[_]NodeAligned{}, | ||
| 69 | }, | ||
| 70 | NodeAligned{ | ||
| 71 | .payload = 3, | ||
| 72 | .children = other_nodes[0..], | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | const root = NodeAligned{ | ||
| 76 | .payload = 1234, | ||
| 77 | .children = nodes[0..], | ||
| 78 | }; | ||
| 79 | try expect(root.payload == 1234); | ||
| 80 | try expect(root.children[0].payload == 1); | ||
| 81 | try expect(root.children[1].payload == 2); | ||
| 82 | try expect(root.children[2].payload == 3); | ||
| 83 | try expect(root.children[2].children[0].payload == 31); | ||
| 84 | try expect(root.children[2].children[1].payload == 32); | ||
| 85 | } | ||
test/behavior/switch.zig created+537| ... | @@ -0,0 +1,537 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectError = std.testing.expectError; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | |||
| 6 | test "switch with numbers" { | ||
| 7 | try testSwitchWithNumbers(13); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testSwitchWithNumbers(x: u32) !void { | ||
| 11 | const result = switch (x) { | ||
| 12 | 1, 2, 3, 4...8 => false, | ||
| 13 | 13 => true, | ||
| 14 | else => false, | ||
| 15 | }; | ||
| 16 | try expect(result); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "switch with all ranges" { | ||
| 20 | try expect(testSwitchWithAllRanges(50, 3) == 1); | ||
| 21 | try expect(testSwitchWithAllRanges(101, 0) == 2); | ||
| 22 | try expect(testSwitchWithAllRanges(300, 5) == 3); | ||
| 23 | try expect(testSwitchWithAllRanges(301, 6) == 6); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 27 | return switch (x) { | ||
| 28 | 0...100 => 1, | ||
| 29 | 101...200 => 2, | ||
| 30 | 201...300 => 3, | ||
| 31 | else => y, | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | test "implicit comptime switch" { | ||
| 36 | const x = 3 + 4; | ||
| 37 | const result = switch (x) { | ||
| 38 | 3 => 10, | ||
| 39 | 4 => 11, | ||
| 40 | 5, 6 => 12, | ||
| 41 | 7, 8 => 13, | ||
| 42 | else => 14, | ||
| 43 | }; | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | try expect(result + 1 == 14); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | test "switch on enum" { | ||
| 51 | const fruit = Fruit.Orange; | ||
| 52 | nonConstSwitchOnEnum(fruit); | ||
| 53 | } | ||
| 54 | const Fruit = enum { | ||
| 55 | Apple, | ||
| 56 | Orange, | ||
| 57 | Banana, | ||
| 58 | }; | ||
| 59 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 60 | switch (fruit) { | ||
| 61 | Fruit.Apple => unreachable, | ||
| 62 | Fruit.Orange => {}, | ||
| 63 | Fruit.Banana => unreachable, | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | test "switch statement" { | ||
| 68 | try nonConstSwitch(SwitchStatmentFoo.C); | ||
| 69 | } | ||
| 70 | fn nonConstSwitch(foo: SwitchStatmentFoo) !void { | ||
| 71 | const val = switch (foo) { | ||
| 72 | SwitchStatmentFoo.A => @as(i32, 1), | ||
| 73 | SwitchStatmentFoo.B => 2, | ||
| 74 | SwitchStatmentFoo.C => 3, | ||
| 75 | SwitchStatmentFoo.D => 4, | ||
| 76 | }; | ||
| 77 | try expect(val == 3); | ||
| 78 | } | ||
| 79 | const SwitchStatmentFoo = enum { | ||
| 80 | A, | ||
| 81 | B, | ||
| 82 | C, | ||
| 83 | D, | ||
| 84 | }; | ||
| 85 | |||
| 86 | test "switch prong with variable" { | ||
| 87 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | ||
| 88 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | ||
| 89 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); | ||
| 90 | } | ||
| 91 | const SwitchProngWithVarEnum = union(enum) { | ||
| 92 | One: i32, | ||
| 93 | Two: f32, | ||
| 94 | Meh: void, | ||
| 95 | }; | ||
| 96 | fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { | ||
| 97 | switch (a) { | ||
| 98 | SwitchProngWithVarEnum.One => |x| { | ||
| 99 | try expect(x == 13); | ||
| 100 | }, | ||
| 101 | SwitchProngWithVarEnum.Two => |x| { | ||
| 102 | try expect(x == 13.0); | ||
| 103 | }, | ||
| 104 | SwitchProngWithVarEnum.Meh => |x| { | ||
| 105 | const v: void = x; | ||
| 106 | }, | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | test "switch on enum using pointer capture" { | ||
| 111 | try testSwitchEnumPtrCapture(); | ||
| 112 | comptime try testSwitchEnumPtrCapture(); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn testSwitchEnumPtrCapture() !void { | ||
| 116 | var value = SwitchProngWithVarEnum{ .One = 1234 }; | ||
| 117 | switch (value) { | ||
| 118 | SwitchProngWithVarEnum.One => |*x| x.* += 1, | ||
| 119 | else => unreachable, | ||
| 120 | } | ||
| 121 | switch (value) { | ||
| 122 | SwitchProngWithVarEnum.One => |x| try expect(x == 1235), | ||
| 123 | else => unreachable, | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | test "switch with multiple expressions" { | ||
| 128 | const x = switch (returnsFive()) { | ||
| 129 | 1, 2, 3 => 1, | ||
| 130 | 4, 5, 6 => 2, | ||
| 131 | else => @as(i32, 3), | ||
| 132 | }; | ||
| 133 | try expect(x == 2); | ||
| 134 | } | ||
| 135 | fn returnsFive() i32 { | ||
| 136 | return 5; | ||
| 137 | } | ||
| 138 | |||
| 139 | const Number = union(enum) { | ||
| 140 | One: u64, | ||
| 141 | Two: u8, | ||
| 142 | Three: f32, | ||
| 143 | }; | ||
| 144 | |||
| 145 | const number = Number{ .Three = 1.23 }; | ||
| 146 | |||
| 147 | fn returnsFalse() bool { | ||
| 148 | switch (number) { | ||
| 149 | Number.One => |x| return x > 1234, | ||
| 150 | Number.Two => |x| return x == 'a', | ||
| 151 | Number.Three => |x| return x > 12.34, | ||
| 152 | } | ||
| 153 | } | ||
| 154 | test "switch on const enum with var" { | ||
| 155 | try expect(!returnsFalse()); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "switch on type" { | ||
| 159 | try expect(trueIfBoolFalseOtherwise(bool)); | ||
| 160 | try expect(!trueIfBoolFalseOtherwise(i32)); | ||
| 161 | } | ||
| 162 | |||
| 163 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 164 | return switch (T) { | ||
| 165 | bool => true, | ||
| 166 | else => false, | ||
| 167 | }; | ||
| 168 | } | ||
| 169 | |||
| 170 | test "switch handles all cases of number" { | ||
| 171 | try testSwitchHandleAllCases(); | ||
| 172 | comptime try testSwitchHandleAllCases(); | ||
| 173 | } | ||
| 174 | |||
| 175 | fn testSwitchHandleAllCases() !void { | ||
| 176 | try expect(testSwitchHandleAllCasesExhaustive(0) == 3); | ||
| 177 | try expect(testSwitchHandleAllCasesExhaustive(1) == 2); | ||
| 178 | try expect(testSwitchHandleAllCasesExhaustive(2) == 1); | ||
| 179 | try expect(testSwitchHandleAllCasesExhaustive(3) == 0); | ||
| 180 | |||
| 181 | try expect(testSwitchHandleAllCasesRange(100) == 0); | ||
| 182 | try expect(testSwitchHandleAllCasesRange(200) == 1); | ||
| 183 | try expect(testSwitchHandleAllCasesRange(201) == 2); | ||
| 184 | try expect(testSwitchHandleAllCasesRange(202) == 4); | ||
| 185 | try expect(testSwitchHandleAllCasesRange(230) == 3); | ||
| 186 | } | ||
| 187 | |||
| 188 | fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { | ||
| 189 | return switch (x) { | ||
| 190 | 0 => @as(u2, 3), | ||
| 191 | 1 => 2, | ||
| 192 | 2 => 1, | ||
| 193 | 3 => 0, | ||
| 194 | }; | ||
| 195 | } | ||
| 196 | |||
| 197 | fn testSwitchHandleAllCasesRange(x: u8) u8 { | ||
| 198 | return switch (x) { | ||
| 199 | 0...100 => @as(u8, 0), | ||
| 200 | 101...200 => 1, | ||
| 201 | 201, 203 => 2, | ||
| 202 | 202 => 4, | ||
| 203 | 204...255 => 3, | ||
| 204 | }; | ||
| 205 | } | ||
| 206 | |||
| 207 | test "switch all prongs unreachable" { | ||
| 208 | try testAllProngsUnreachable(); | ||
| 209 | comptime try testAllProngsUnreachable(); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn testAllProngsUnreachable() !void { | ||
| 213 | try expect(switchWithUnreachable(1) == 2); | ||
| 214 | try expect(switchWithUnreachable(2) == 10); | ||
| 215 | } | ||
| 216 | |||
| 217 | fn switchWithUnreachable(x: i32) i32 { | ||
| 218 | while (true) { | ||
| 219 | switch (x) { | ||
| 220 | 1 => return 2, | ||
| 221 | 2 => break, | ||
| 222 | else => continue, | ||
| 223 | } | ||
| 224 | } | ||
| 225 | return 10; | ||
| 226 | } | ||
| 227 | |||
| 228 | fn return_a_number() anyerror!i32 { | ||
| 229 | return 1; | ||
| 230 | } | ||
| 231 | |||
| 232 | test "capture value of switch with all unreachable prongs" { | ||
| 233 | const x = return_a_number() catch |err| switch (err) { | ||
| 234 | else => unreachable, | ||
| 235 | }; | ||
| 236 | try expect(x == 1); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "switching on booleans" { | ||
| 240 | try testSwitchOnBools(); | ||
| 241 | comptime try testSwitchOnBools(); | ||
| 242 | } | ||
| 243 | |||
| 244 | fn testSwitchOnBools() !void { | ||
| 245 | try expect(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 246 | try expect(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 247 | |||
| 248 | try expect(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 249 | try expect(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 250 | |||
| 251 | try expect(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 252 | try expect(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 256 | return switch (x) { | ||
| 257 | true => false, | ||
| 258 | false => true, | ||
| 259 | }; | ||
| 260 | } | ||
| 261 | |||
| 262 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 263 | return switch (x) { | ||
| 264 | true => false, | ||
| 265 | else => true, | ||
| 266 | }; | ||
| 267 | } | ||
| 268 | |||
| 269 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 270 | return switch (x) { | ||
| 271 | false => true, | ||
| 272 | else => false, | ||
| 273 | }; | ||
| 274 | } | ||
| 275 | |||
| 276 | test "u0" { | ||
| 277 | var val: u0 = 0; | ||
| 278 | switch (val) { | ||
| 279 | 0 => try expect(val == 0), | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | test "undefined.u0" { | ||
| 284 | var val: u0 = undefined; | ||
| 285 | switch (val) { | ||
| 286 | 0 => try expect(val == 0), | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | test "anon enum literal used in switch on union enum" { | ||
| 291 | const Foo = union(enum) { | ||
| 292 | a: i32, | ||
| 293 | }; | ||
| 294 | |||
| 295 | var foo = Foo{ .a = 1234 }; | ||
| 296 | switch (foo) { | ||
| 297 | .a => |x| { | ||
| 298 | try expect(x == 1234); | ||
| 299 | }, | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | test "else prong of switch on error set excludes other cases" { | ||
| 304 | const S = struct { | ||
| 305 | fn doTheTest() !void { | ||
| 306 | try expectError(error.C, bar()); | ||
| 307 | } | ||
| 308 | const E = error{ | ||
| 309 | A, | ||
| 310 | B, | ||
| 311 | } || E2; | ||
| 312 | |||
| 313 | const E2 = error{ | ||
| 314 | C, | ||
| 315 | D, | ||
| 316 | }; | ||
| 317 | |||
| 318 | fn foo() E!void { | ||
| 319 | return error.C; | ||
| 320 | } | ||
| 321 | |||
| 322 | fn bar() E2!void { | ||
| 323 | foo() catch |err| switch (err) { | ||
| 324 | error.A, error.B => {}, | ||
| 325 | else => |e| return e, | ||
| 326 | }; | ||
| 327 | } | ||
| 328 | }; | ||
| 329 | try S.doTheTest(); | ||
| 330 | comptime try S.doTheTest(); | ||
| 331 | } | ||
| 332 | |||
| 333 | test "switch prongs with error set cases make a new error set type for capture value" { | ||
| 334 | const S = struct { | ||
| 335 | fn doTheTest() !void { | ||
| 336 | try expectError(error.B, bar()); | ||
| 337 | } | ||
| 338 | const E = E1 || E2; | ||
| 339 | |||
| 340 | const E1 = error{ | ||
| 341 | A, | ||
| 342 | B, | ||
| 343 | }; | ||
| 344 | |||
| 345 | const E2 = error{ | ||
| 346 | C, | ||
| 347 | D, | ||
| 348 | }; | ||
| 349 | |||
| 350 | fn foo() E!void { | ||
| 351 | return error.B; | ||
| 352 | } | ||
| 353 | |||
| 354 | fn bar() E1!void { | ||
| 355 | foo() catch |err| switch (err) { | ||
| 356 | error.A, error.B => |e| return e, | ||
| 357 | else => {}, | ||
| 358 | }; | ||
| 359 | } | ||
| 360 | }; | ||
| 361 | try S.doTheTest(); | ||
| 362 | comptime try S.doTheTest(); | ||
| 363 | } | ||
| 364 | |||
| 365 | test "return result loc and then switch with range implicit casted to error union" { | ||
| 366 | const S = struct { | ||
| 367 | fn doTheTest() !void { | ||
| 368 | try expect((func(0xb) catch unreachable) == 0xb); | ||
| 369 | } | ||
| 370 | fn func(d: u8) anyerror!u8 { | ||
| 371 | return switch (d) { | ||
| 372 | 0xa...0xf => d, | ||
| 373 | else => unreachable, | ||
| 374 | }; | ||
| 375 | } | ||
| 376 | }; | ||
| 377 | try S.doTheTest(); | ||
| 378 | comptime try S.doTheTest(); | ||
| 379 | } | ||
| 380 | |||
| 381 | test "switch with null and T peer types and inferred result location type" { | ||
| 382 | const S = struct { | ||
| 383 | fn doTheTest(c: u8) !void { | ||
| 384 | if (switch (c) { | ||
| 385 | 0 => true, | ||
| 386 | else => null, | ||
| 387 | }) |v| { | ||
| 388 | @panic("fail"); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | }; | ||
| 392 | try S.doTheTest(1); | ||
| 393 | comptime try S.doTheTest(1); | ||
| 394 | } | ||
| 395 | |||
| 396 | test "switch prongs with cases with identical payload types" { | ||
| 397 | const Union = union(enum) { | ||
| 398 | A: usize, | ||
| 399 | B: isize, | ||
| 400 | C: usize, | ||
| 401 | }; | ||
| 402 | const S = struct { | ||
| 403 | fn doTheTest() !void { | ||
| 404 | try doTheSwitch1(Union{ .A = 8 }); | ||
| 405 | try doTheSwitch2(Union{ .B = -8 }); | ||
| 406 | } | ||
| 407 | fn doTheSwitch1(u: Union) !void { | ||
| 408 | switch (u) { | ||
| 409 | .A, .C => |e| { | ||
| 410 | try expect(@TypeOf(e) == usize); | ||
| 411 | try expect(e == 8); | ||
| 412 | }, | ||
| 413 | .B => |e| @panic("fail"), | ||
| 414 | } | ||
| 415 | } | ||
| 416 | fn doTheSwitch2(u: Union) !void { | ||
| 417 | switch (u) { | ||
| 418 | .A, .C => |e| @panic("fail"), | ||
| 419 | .B => |e| { | ||
| 420 | try expect(@TypeOf(e) == isize); | ||
| 421 | try expect(e == -8); | ||
| 422 | }, | ||
| 423 | } | ||
| 424 | } | ||
| 425 | }; | ||
| 426 | try S.doTheTest(); | ||
| 427 | comptime try S.doTheTest(); | ||
| 428 | } | ||
| 429 | |||
| 430 | test "switch with disjoint range" { | ||
| 431 | var q: u8 = 0; | ||
| 432 | switch (q) { | ||
| 433 | 0...125 => {}, | ||
| 434 | 127...255 => {}, | ||
| 435 | 126...126 => {}, | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | test "switch variable for range and multiple prongs" { | ||
| 440 | const S = struct { | ||
| 441 | fn doTheTest() !void { | ||
| 442 | var u: u8 = 16; | ||
| 443 | try doTheSwitch(u); | ||
| 444 | comptime try doTheSwitch(u); | ||
| 445 | var v: u8 = 42; | ||
| 446 | try doTheSwitch(v); | ||
| 447 | comptime try doTheSwitch(v); | ||
| 448 | } | ||
| 449 | fn doTheSwitch(q: u8) !void { | ||
| 450 | switch (q) { | ||
| 451 | 0...40 => |x| try expect(x == 16), | ||
| 452 | 41, 42, 43 => |x| try expect(x == 42), | ||
| 453 | else => try expect(false), | ||
| 454 | } | ||
| 455 | } | ||
| 456 | }; | ||
| 457 | } | ||
| 458 | |||
| 459 | var state: u32 = 0; | ||
| 460 | fn poll() void { | ||
| 461 | switch (state) { | ||
| 462 | 0 => { | ||
| 463 | state = 1; | ||
| 464 | }, | ||
| 465 | else => { | ||
| 466 | state += 1; | ||
| 467 | }, | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | test "switch on global mutable var isn't constant-folded" { | ||
| 472 | while (state < 2) { | ||
| 473 | poll(); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | test "switch on pointer type" { | ||
| 478 | const S = struct { | ||
| 479 | const X = struct { | ||
| 480 | field: u32, | ||
| 481 | }; | ||
| 482 | |||
| 483 | const P1 = @intToPtr(*X, 0x400); | ||
| 484 | const P2 = @intToPtr(*X, 0x800); | ||
| 485 | const P3 = @intToPtr(*X, 0xC00); | ||
| 486 | |||
| 487 | fn doTheTest(arg: *X) i32 { | ||
| 488 | switch (arg) { | ||
| 489 | P1 => return 1, | ||
| 490 | P2 => return 2, | ||
| 491 | else => return 3, | ||
| 492 | } | ||
| 493 | } | ||
| 494 | }; | ||
| 495 | |||
| 496 | try expect(1 == S.doTheTest(S.P1)); | ||
| 497 | try expect(2 == S.doTheTest(S.P2)); | ||
| 498 | try expect(3 == S.doTheTest(S.P3)); | ||
| 499 | comptime try expect(1 == S.doTheTest(S.P1)); | ||
| 500 | comptime try expect(2 == S.doTheTest(S.P2)); | ||
| 501 | comptime try expect(3 == S.doTheTest(S.P3)); | ||
| 502 | } | ||
| 503 | |||
| 504 | test "switch on error set with single else" { | ||
| 505 | const S = struct { | ||
| 506 | fn doTheTest() !void { | ||
| 507 | var some: error{Foo} = error.Foo; | ||
| 508 | try expect(switch (some) { | ||
| 509 | else => |a| true, | ||
| 510 | }); | ||
| 511 | } | ||
| 512 | }; | ||
| 513 | |||
| 514 | try S.doTheTest(); | ||
| 515 | comptime try S.doTheTest(); | ||
| 516 | } | ||
| 517 | |||
| 518 | test "while copies its payload" { | ||
| 519 | const S = struct { | ||
| 520 | fn doTheTest() !void { | ||
| 521 | var tmp: union(enum) { | ||
| 522 | A: u8, | ||
| 523 | B: u32, | ||
| 524 | } = .{ .A = 42 }; | ||
| 525 | switch (tmp) { | ||
| 526 | .A => |value| { | ||
| 527 | // Modify the original union | ||
| 528 | tmp = .{ .B = 0x10101010 }; | ||
| 529 | try expectEqual(@as(u8, 42), value); | ||
| 530 | }, | ||
| 531 | else => unreachable, | ||
| 532 | } | ||
| 533 | } | ||
| 534 | }; | ||
| 535 | try S.doTheTest(); | ||
| 536 | comptime try S.doTheTest(); | ||
| 537 | } | ||
test/behavior/switch_prong_err_enum.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | var read_count: u64 = 0; | ||
| 4 | |||
| 5 | fn readOnce() anyerror!u64 { | ||
| 6 | read_count += 1; | ||
| 7 | return read_count; | ||
| 8 | } | ||
| 9 | |||
| 10 | const FormValue = union(enum) { | ||
| 11 | Address: u64, | ||
| 12 | Other: bool, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn doThing(form_id: u64) anyerror!FormValue { | ||
| 16 | return switch (form_id) { | ||
| 17 | 17 => FormValue{ .Address = try readOnce() }, | ||
| 18 | else => error.InvalidDebugInfo, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "switch prong returns error enum" { | ||
| 23 | switch (doThing(17) catch unreachable) { | ||
| 24 | FormValue.Address => |payload| { | ||
| 25 | try expect(payload == 1); | ||
| 26 | }, | ||
| 27 | else => unreachable, | ||
| 28 | } | ||
| 29 | try expect(read_count == 1); | ||
| 30 | } | ||
test/behavior/switch_prong_implicit_cast.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const FormValue = union(enum) { | ||
| 4 | One: void, | ||
| 5 | Two: bool, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn foo(id: u64) !FormValue { | ||
| 9 | return switch (id) { | ||
| 10 | 2 => FormValue{ .Two = true }, | ||
| 11 | 1 => FormValue{ .One = {} }, | ||
| 12 | else => return error.Whatever, | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch prong implicit cast" { | ||
| 17 | const result = switch (foo(2) catch unreachable) { | ||
| 18 | FormValue.One => false, | ||
| 19 | FormValue.Two => |x| x, | ||
| 20 | }; | ||
| 21 | try expect(result); | ||
| 22 | } | ||
test/behavior/syntax.zig created+68| ... | @@ -0,0 +1,68 @@ | ||
| 1 | // Test trailing comma syntax | ||
| 2 | // zig fmt: off | ||
| 3 | |||
| 4 | extern var a: c_int; | ||
| 5 | extern "c" var b: c_int; | ||
| 6 | export var c: c_int = 0; | ||
| 7 | threadlocal var d: c_int; | ||
| 8 | extern threadlocal var e: c_int; | ||
| 9 | extern "c" threadlocal var f: c_int; | ||
| 10 | export threadlocal var g: c_int = 0; | ||
| 11 | |||
| 12 | const struct_trailing_comma = struct { x: i32, y: i32, }; | ||
| 13 | const struct_no_comma = struct { x: i32, y: i32 }; | ||
| 14 | const struct_fn_no_comma = struct { fn m() void {} y: i32 }; | ||
| 15 | |||
| 16 | const enum_no_comma = enum { A, B }; | ||
| 17 | |||
| 18 | fn container_init() void { | ||
| 19 | const S = struct { x: i32, y: i32 }; | ||
| 20 | _ = S { .x = 1, .y = 2 }; | ||
| 21 | _ = S { .x = 1, .y = 2, }; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn type_expr_return1() if (true) A {} | ||
| 25 | fn type_expr_return2() for (true) |_| A {} | ||
| 26 | fn type_expr_return3() while (true) A {} | ||
| 27 | fn type_expr_return4() comptime A {} | ||
| 28 | |||
| 29 | fn switch_cases(x: i32) void { | ||
| 30 | switch (x) { | ||
| 31 | 1,2,3 => {}, | ||
| 32 | 4,5, => {}, | ||
| 33 | 6...8, => {}, | ||
| 34 | else => {}, | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | fn switch_prongs(x: i32) void { | ||
| 39 | switch (x) { | ||
| 40 | 0 => {}, | ||
| 41 | else => {}, | ||
| 42 | } | ||
| 43 | switch (x) { | ||
| 44 | 0 => {}, | ||
| 45 | else => {} | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | const fn_no_comma = fn(i32, i32)void; | ||
| 50 | const fn_trailing_comma = fn(i32, i32,)void; | ||
| 51 | |||
| 52 | fn fn_calls() void { | ||
| 53 | fn add(x: i32, y: i32,) i32 { x + y }; | ||
| 54 | _ = add(1, 2); | ||
| 55 | _ = add(1, 2,); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn asm_lists() void { | ||
| 59 | if (false) { // Build AST but don't analyze | ||
| 60 | asm ("not real assembly" | ||
| 61 | :[a] "x" (x),); | ||
| 62 | asm ("not real assembly" | ||
| 63 | :[a] "x" (->i32),:[a] "x" (1),); | ||
| 64 | asm ("still not real assembly" | ||
| 65 | :::"a","b",); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
test/behavior/this.zig created+34| ... | @@ -0,0 +1,34 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const module = @This(); | ||
| 4 | |||
| 5 | fn Point(comptime T: type) type { | ||
| 6 | return struct { | ||
| 7 | const Self = @This(); | ||
| 8 | x: T, | ||
| 9 | y: T, | ||
| 10 | |||
| 11 | fn addOne(self: *Self) void { | ||
| 12 | self.x += 1; | ||
| 13 | self.y += 1; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn add(x: i32, y: i32) i32 { | ||
| 19 | return x + y; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "this refer to module call private fn" { | ||
| 23 | try expect(module.add(1, 2) == 3); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "this refer to container" { | ||
| 27 | var pt = Point(i32){ | ||
| 28 | .x = 12, | ||
| 29 | .y = 34, | ||
| 30 | }; | ||
| 31 | pt.addOne(); | ||
| 32 | try expect(pt.x == 13); | ||
| 33 | try expect(pt.y == 35); | ||
| 34 | } | ||
test/behavior/translate_c_macros.h created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | // initializer list expression | ||
| 2 | typedef struct Color { | ||
| 3 | unsigned char r; | ||
| 4 | unsigned char g; | ||
| 5 | unsigned char b; | ||
| 6 | unsigned char a; | ||
| 7 | } Color; | ||
| 8 | #define CLITERAL(type) (type) | ||
| 9 | #define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray | ||
| 10 | |||
| 11 | #define MY_SIZEOF(x) ((int)sizeof(x)) | ||
| 12 | #define MY_SIZEOF2(x) ((int)sizeof x) | ||
| 13 | |||
| 14 | struct Foo { | ||
| 15 | int a; | ||
| 16 | }; | ||
| 17 | |||
| 18 | #define SIZE_OF_FOO sizeof(struct Foo) | ||
test/behavior/translate_c_macros.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const expectEqual = @import("std").testing.expectEqual; | ||
| 3 | |||
| 4 | const h = @cImport(@cInclude("behavior/translate_c_macros.h")); | ||
| 5 | |||
| 6 | test "initializer list expression" { | ||
| 7 | try expectEqual(h.Color{ | ||
| 8 | .r = 200, | ||
| 9 | .g = 200, | ||
| 10 | .b = 200, | ||
| 11 | .a = 255, | ||
| 12 | }, h.LIGHTGRAY); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "sizeof in macros" { | ||
| 16 | try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32)); | ||
| 17 | try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32)); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "reference to a struct type" { | ||
| 21 | try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); | ||
| 22 | } | ||
test/behavior/truncate.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "truncate u0 to larger integer allowed and has comptime known result" { | ||
| 5 | var x: u0 = 0; | ||
| 6 | const y = @truncate(u8, x); | ||
| 7 | comptime try expect(y == 0); | ||
| 8 | } | ||
| 9 | |||
| 10 | test "truncate.u0.literal" { | ||
| 11 | var z = @truncate(u0, 0); | ||
| 12 | try expect(z == 0); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "truncate.u0.const" { | ||
| 16 | const c0: usize = 0; | ||
| 17 | var z = @truncate(u0, c0); | ||
| 18 | try expect(z == 0); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "truncate.u0.var" { | ||
| 22 | var d: u8 = 2; | ||
| 23 | var z = @truncate(u0, d); | ||
| 24 | try expect(z == 0); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "truncate sign mismatch but comptime known so it works anyway" { | ||
| 28 | const x: u32 = 10; | ||
| 29 | var result = @truncate(i8, x); | ||
| 30 | try expect(result == 10); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "truncate on comptime integer" { | ||
| 34 | var x = @truncate(u16, 9999); | ||
| 35 | try expect(x == 9999); | ||
| 36 | } | ||
test/behavior/try.zig created+43| ... | @@ -0,0 +1,43 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "try on error union" { | ||
| 4 | try tryOnErrorUnionImpl(); | ||
| 5 | comptime try tryOnErrorUnionImpl(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn tryOnErrorUnionImpl() !void { | ||
| 9 | const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { | ||
| 10 | error.ItBroke, error.NoMem => 1, | ||
| 11 | error.CrappedOut => @as(i32, 2), | ||
| 12 | else => unreachable, | ||
| 13 | }; | ||
| 14 | try expect(x == 11); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn returnsTen() anyerror!i32 { | ||
| 18 | return 10; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "try without vars" { | ||
| 22 | const result1 = if (failIfTrue(true)) 1 else |_| @as(i32, 2); | ||
| 23 | try expect(result1 == 2); | ||
| 24 | |||
| 25 | const result2 = if (failIfTrue(false)) 1 else |_| @as(i32, 2); | ||
| 26 | try expect(result2 == 1); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn failIfTrue(ok: bool) anyerror!void { | ||
| 30 | if (ok) { | ||
| 31 | return error.ItBroke; | ||
| 32 | } else { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "try then not executed with assignment" { | ||
| 38 | if (failIfTrue(true)) { | ||
| 39 | unreachable; | ||
| 40 | } else |err| { | ||
| 41 | try expect(err == error.ItBroke); | ||
| 42 | } | ||
| 43 | } | ||
test/behavior/tuple.zig created+113| ... | @@ -0,0 +1,113 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "tuple concatenation" { | ||
| 7 | const S = struct { | ||
| 8 | fn doTheTest() !void { | ||
| 9 | var a: i32 = 1; | ||
| 10 | var b: i32 = 2; | ||
| 11 | var x = .{a}; | ||
| 12 | var y = .{b}; | ||
| 13 | var c = x ++ y; | ||
| 14 | try expectEqual(@as(i32, 1), c[0]); | ||
| 15 | try expectEqual(@as(i32, 2), c[1]); | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | try S.doTheTest(); | ||
| 19 | comptime try S.doTheTest(); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "tuple multiplication" { | ||
| 23 | const S = struct { | ||
| 24 | fn doTheTest() !void { | ||
| 25 | { | ||
| 26 | const t = .{} ** 4; | ||
| 27 | try expectEqual(0, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | const t = .{'a'} ** 4; | ||
| 31 | try expectEqual(4, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 32 | inline for (t) |x| try expectEqual('a', x); | ||
| 33 | } | ||
| 34 | { | ||
| 35 | const t = .{ 1, 2, 3 } ** 4; | ||
| 36 | try expectEqual(12, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 37 | inline for (t) |x, i| try expectEqual(1 + i % 3, x); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | try S.doTheTest(); | ||
| 42 | comptime try S.doTheTest(); | ||
| 43 | |||
| 44 | const T = struct { | ||
| 45 | fn consume_tuple(tuple: anytype, len: usize) !void { | ||
| 46 | try expect(tuple.len == len); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn doTheTest() !void { | ||
| 50 | const t1 = .{}; | ||
| 51 | |||
| 52 | var rt_var: u8 = 42; | ||
| 53 | const t2 = .{rt_var} ++ .{}; | ||
| 54 | |||
| 55 | try expect(t2.len == 1); | ||
| 56 | try expect(t2.@"0" == rt_var); | ||
| 57 | try expect(t2.@"0" == 42); | ||
| 58 | try expect(&t2.@"0" != &rt_var); | ||
| 59 | |||
| 60 | try consume_tuple(t1 ++ t1, 0); | ||
| 61 | try consume_tuple(.{} ++ .{}, 0); | ||
| 62 | try consume_tuple(.{0} ++ .{}, 1); | ||
| 63 | try consume_tuple(.{0} ++ .{1}, 2); | ||
| 64 | try consume_tuple(.{ 0, 1, 2 } ++ .{ u8, 1, noreturn }, 6); | ||
| 65 | try consume_tuple(t2 ++ t1, 1); | ||
| 66 | try consume_tuple(t1 ++ t2, 1); | ||
| 67 | try consume_tuple(t2 ++ t2, 2); | ||
| 68 | try consume_tuple(.{rt_var} ++ .{}, 1); | ||
| 69 | try consume_tuple(.{rt_var} ++ t1, 1); | ||
| 70 | try consume_tuple(.{} ++ .{rt_var}, 1); | ||
| 71 | try consume_tuple(t2 ++ .{void}, 2); | ||
| 72 | try consume_tuple(t2 ++ .{0}, 2); | ||
| 73 | try consume_tuple(.{0} ++ t2, 2); | ||
| 74 | try consume_tuple(.{void} ++ t2, 2); | ||
| 75 | try consume_tuple(.{u8} ++ .{rt_var} ++ .{true}, 3); | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | try T.doTheTest(); | ||
| 80 | comptime try T.doTheTest(); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "pass tuple to comptime var parameter" { | ||
| 84 | const S = struct { | ||
| 85 | fn Foo(comptime args: anytype) !void { | ||
| 86 | try expect(args[0] == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn doTheTest() !void { | ||
| 90 | try Foo(.{1}); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | try S.doTheTest(); | ||
| 94 | comptime try S.doTheTest(); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "tuple initializer for var" { | ||
| 98 | const S = struct { | ||
| 99 | fn doTheTest() void { | ||
| 100 | const Bytes = struct { | ||
| 101 | id: usize, | ||
| 102 | }; | ||
| 103 | |||
| 104 | var tmp = .{ | ||
| 105 | .id = @as(usize, 2), | ||
| 106 | .name = Bytes{ .id = 20 }, | ||
| 107 | }; | ||
| 108 | } | ||
| 109 | }; | ||
| 110 | |||
| 111 | S.doTheTest(); | ||
| 112 | comptime S.doTheTest(); | ||
| 113 | } | ||
test/behavior/type.zig created+453| ... | @@ -0,0 +1,453 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const TypeInfo = std.builtin.TypeInfo; | ||
| 4 | const testing = std.testing; | ||
| 5 | |||
| 6 | fn testTypes(comptime types: []const type) !void { | ||
| 7 | inline for (types) |testType| { | ||
| 8 | try testing.expect(testType == @Type(@typeInfo(testType))); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | test "Type.MetaType" { | ||
| 13 | try testing.expect(type == @Type(TypeInfo{ .Type = undefined })); | ||
| 14 | try testTypes(&[_]type{type}); | ||
| 15 | } | ||
| 16 | |||
| 17 | test "Type.Void" { | ||
| 18 | try testing.expect(void == @Type(TypeInfo{ .Void = undefined })); | ||
| 19 | try testTypes(&[_]type{void}); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "Type.Bool" { | ||
| 23 | try testing.expect(bool == @Type(TypeInfo{ .Bool = undefined })); | ||
| 24 | try testTypes(&[_]type{bool}); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "Type.NoReturn" { | ||
| 28 | try testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined })); | ||
| 29 | try testTypes(&[_]type{noreturn}); | ||
| 30 | } | ||
| 31 | |||
| 32 | test "Type.Int" { | ||
| 33 | try testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 1 } })); | ||
| 34 | try testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 1 } })); | ||
| 35 | try testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 8 } })); | ||
| 36 | try testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 8 } })); | ||
| 37 | try testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 64 } })); | ||
| 38 | try testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 64 } })); | ||
| 39 | try testTypes(&[_]type{ u8, u32, i64 }); | ||
| 40 | } | ||
| 41 | |||
| 42 | test "Type.Float" { | ||
| 43 | try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } })); | ||
| 44 | try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } })); | ||
| 45 | try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } })); | ||
| 46 | try testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } })); | ||
| 47 | try testTypes(&[_]type{ f16, f32, f64, f128 }); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "Type.Pointer" { | ||
| 51 | try testTypes(&[_]type{ | ||
| 52 | // One Value Pointer Types | ||
| 53 | *u8, *const u8, | ||
| 54 | *volatile u8, *const volatile u8, | ||
| 55 | *align(4) u8, *align(4) const u8, | ||
| 56 | *align(4) volatile u8, *align(4) const volatile u8, | ||
| 57 | *align(8) u8, *align(8) const u8, | ||
| 58 | *align(8) volatile u8, *align(8) const volatile u8, | ||
| 59 | *allowzero u8, *allowzero const u8, | ||
| 60 | *allowzero volatile u8, *allowzero const volatile u8, | ||
| 61 | *allowzero align(4) u8, *allowzero align(4) const u8, | ||
| 62 | *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, | ||
| 63 | // Many Values Pointer Types | ||
| 64 | [*]u8, [*]const u8, | ||
| 65 | [*]volatile u8, [*]const volatile u8, | ||
| 66 | [*]align(4) u8, [*]align(4) const u8, | ||
| 67 | [*]align(4) volatile u8, [*]align(4) const volatile u8, | ||
| 68 | [*]align(8) u8, [*]align(8) const u8, | ||
| 69 | [*]align(8) volatile u8, [*]align(8) const volatile u8, | ||
| 70 | [*]allowzero u8, [*]allowzero const u8, | ||
| 71 | [*]allowzero volatile u8, [*]allowzero const volatile u8, | ||
| 72 | [*]allowzero align(4) u8, [*]allowzero align(4) const u8, | ||
| 73 | [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, | ||
| 74 | // Slice Types | ||
| 75 | []u8, []const u8, | ||
| 76 | []volatile u8, []const volatile u8, | ||
| 77 | []align(4) u8, []align(4) const u8, | ||
| 78 | []align(4) volatile u8, []align(4) const volatile u8, | ||
| 79 | []align(8) u8, []align(8) const u8, | ||
| 80 | []align(8) volatile u8, []align(8) const volatile u8, | ||
| 81 | []allowzero u8, []allowzero const u8, | ||
| 82 | []allowzero volatile u8, []allowzero const volatile u8, | ||
| 83 | []allowzero align(4) u8, []allowzero align(4) const u8, | ||
| 84 | []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, | ||
| 85 | // C Pointer Types | ||
| 86 | [*c]u8, [*c]const u8, | ||
| 87 | [*c]volatile u8, [*c]const volatile u8, | ||
| 88 | [*c]align(4) u8, [*c]align(4) const u8, | ||
| 89 | [*c]align(4) volatile u8, [*c]align(4) const volatile u8, | ||
| 90 | [*c]align(8) u8, [*c]align(8) const u8, | ||
| 91 | [*c]align(8) volatile u8, [*c]align(8) const volatile u8, | ||
| 92 | }); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "Type.Array" { | ||
| 96 | try testing.expect([123]u8 == @Type(TypeInfo{ | ||
| 97 | .Array = TypeInfo.Array{ | ||
| 98 | .len = 123, | ||
| 99 | .child = u8, | ||
| 100 | .sentinel = null, | ||
| 101 | }, | ||
| 102 | })); | ||
| 103 | try testing.expect([2]u32 == @Type(TypeInfo{ | ||
| 104 | .Array = TypeInfo.Array{ | ||
| 105 | .len = 2, | ||
| 106 | .child = u32, | ||
| 107 | .sentinel = null, | ||
| 108 | }, | ||
| 109 | })); | ||
| 110 | try testing.expect([2:0]u32 == @Type(TypeInfo{ | ||
| 111 | .Array = TypeInfo.Array{ | ||
| 112 | .len = 2, | ||
| 113 | .child = u32, | ||
| 114 | .sentinel = 0, | ||
| 115 | }, | ||
| 116 | })); | ||
| 117 | try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool }); | ||
| 118 | } | ||
| 119 | |||
| 120 | test "Type.ComptimeFloat" { | ||
| 121 | try testTypes(&[_]type{comptime_float}); | ||
| 122 | } | ||
| 123 | test "Type.ComptimeInt" { | ||
| 124 | try testTypes(&[_]type{comptime_int}); | ||
| 125 | } | ||
| 126 | test "Type.Undefined" { | ||
| 127 | try testTypes(&[_]type{@TypeOf(undefined)}); | ||
| 128 | } | ||
| 129 | test "Type.Null" { | ||
| 130 | try testTypes(&[_]type{@TypeOf(null)}); | ||
| 131 | } | ||
| 132 | test "@Type create slice with null sentinel" { | ||
| 133 | const Slice = @Type(TypeInfo{ | ||
| 134 | .Pointer = .{ | ||
| 135 | .size = .Slice, | ||
| 136 | .is_const = true, | ||
| 137 | .is_volatile = false, | ||
| 138 | .is_allowzero = false, | ||
| 139 | .alignment = 8, | ||
| 140 | .child = *i32, | ||
| 141 | .sentinel = null, | ||
| 142 | }, | ||
| 143 | }); | ||
| 144 | try testing.expect(Slice == []align(8) const *i32); | ||
| 145 | } | ||
| 146 | test "@Type picks up the sentinel value from TypeInfo" { | ||
| 147 | try testTypes(&[_]type{ | ||
| 148 | [11:0]u8, [4:10]u8, | ||
| 149 | [*:0]u8, [*:0]const u8, | ||
| 150 | [*:0]volatile u8, [*:0]const volatile u8, | ||
| 151 | [*:0]align(4) u8, [*:0]align(4) const u8, | ||
| 152 | [*:0]align(4) volatile u8, [*:0]align(4) const volatile u8, | ||
| 153 | [*:0]align(8) u8, [*:0]align(8) const u8, | ||
| 154 | [*:0]align(8) volatile u8, [*:0]align(8) const volatile u8, | ||
| 155 | [*:0]allowzero u8, [*:0]allowzero const u8, | ||
| 156 | [*:0]allowzero volatile u8, [*:0]allowzero const volatile u8, | ||
| 157 | [*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8, | ||
| 158 | [*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8, | ||
| 159 | [*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8, | ||
| 160 | [:0]u8, [:0]const u8, | ||
| 161 | [:0]volatile u8, [:0]const volatile u8, | ||
| 162 | [:0]align(4) u8, [:0]align(4) const u8, | ||
| 163 | [:0]align(4) volatile u8, [:0]align(4) const volatile u8, | ||
| 164 | [:0]align(8) u8, [:0]align(8) const u8, | ||
| 165 | [:0]align(8) volatile u8, [:0]align(8) const volatile u8, | ||
| 166 | [:0]allowzero u8, [:0]allowzero const u8, | ||
| 167 | [:0]allowzero volatile u8, [:0]allowzero const volatile u8, | ||
| 168 | [:0]allowzero align(4) u8, [:0]allowzero align(4) const u8, | ||
| 169 | [:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8, | ||
| 170 | [:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8, | ||
| 171 | }); | ||
| 172 | } | ||
| 173 | |||
| 174 | test "Type.Optional" { | ||
| 175 | try testTypes(&[_]type{ | ||
| 176 | ?u8, | ||
| 177 | ?*u8, | ||
| 178 | ?[]u8, | ||
| 179 | ?[*]u8, | ||
| 180 | ?[*c]u8, | ||
| 181 | }); | ||
| 182 | } | ||
| 183 | |||
| 184 | test "Type.ErrorUnion" { | ||
| 185 | try testTypes(&[_]type{ | ||
| 186 | error{}!void, | ||
| 187 | error{Error}!void, | ||
| 188 | }); | ||
| 189 | } | ||
| 190 | |||
| 191 | test "Type.Opaque" { | ||
| 192 | const Opaque = @Type(.{ | ||
| 193 | .Opaque = .{ | ||
| 194 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 195 | }, | ||
| 196 | }); | ||
| 197 | try testing.expect(Opaque != opaque {}); | ||
| 198 | try testing.expectEqualSlices( | ||
| 199 | TypeInfo.Declaration, | ||
| 200 | &[_]TypeInfo.Declaration{}, | ||
| 201 | @typeInfo(Opaque).Opaque.decls, | ||
| 202 | ); | ||
| 203 | } | ||
| 204 | |||
| 205 | test "Type.Vector" { | ||
| 206 | try testTypes(&[_]type{ | ||
| 207 | @Vector(0, u8), | ||
| 208 | @Vector(4, u8), | ||
| 209 | @Vector(8, *u8), | ||
| 210 | std.meta.Vector(0, u8), | ||
| 211 | std.meta.Vector(4, u8), | ||
| 212 | std.meta.Vector(8, *u8), | ||
| 213 | }); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "Type.AnyFrame" { | ||
| 217 | try testTypes(&[_]type{ | ||
| 218 | anyframe, | ||
| 219 | anyframe->u8, | ||
| 220 | anyframe->anyframe->u8, | ||
| 221 | }); | ||
| 222 | } | ||
| 223 | |||
| 224 | test "Type.EnumLiteral" { | ||
| 225 | try testTypes(&[_]type{ | ||
| 226 | @TypeOf(.Dummy), | ||
| 227 | }); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn add(a: i32, b: i32) i32 { | ||
| 231 | return a + b; | ||
| 232 | } | ||
| 233 | |||
| 234 | test "Type.Frame" { | ||
| 235 | try testTypes(&[_]type{ | ||
| 236 | @Frame(add), | ||
| 237 | }); | ||
| 238 | } | ||
| 239 | |||
| 240 | test "Type.ErrorSet" { | ||
| 241 | // error sets don't compare equal so just check if they compile | ||
| 242 | _ = @Type(@typeInfo(error{})); | ||
| 243 | _ = @Type(@typeInfo(error{A})); | ||
| 244 | _ = @Type(@typeInfo(error{ A, B, C })); | ||
| 245 | } | ||
| 246 | |||
| 247 | test "Type.Struct" { | ||
| 248 | const A = @Type(@typeInfo(struct { x: u8, y: u32 })); | ||
| 249 | const infoA = @typeInfo(A).Struct; | ||
| 250 | try testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout); | ||
| 251 | try testing.expectEqualSlices(u8, "x", infoA.fields[0].name); | ||
| 252 | try testing.expectEqual(u8, infoA.fields[0].field_type); | ||
| 253 | try testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value); | ||
| 254 | try testing.expectEqualSlices(u8, "y", infoA.fields[1].name); | ||
| 255 | try testing.expectEqual(u32, infoA.fields[1].field_type); | ||
| 256 | try testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value); | ||
| 257 | try testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls); | ||
| 258 | try testing.expectEqual(@as(bool, false), infoA.is_tuple); | ||
| 259 | |||
| 260 | var a = A{ .x = 0, .y = 1 }; | ||
| 261 | try testing.expectEqual(@as(u8, 0), a.x); | ||
| 262 | try testing.expectEqual(@as(u32, 1), a.y); | ||
| 263 | a.y += 1; | ||
| 264 | try testing.expectEqual(@as(u32, 2), a.y); | ||
| 265 | |||
| 266 | const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 })); | ||
| 267 | const infoB = @typeInfo(B).Struct; | ||
| 268 | try testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout); | ||
| 269 | try testing.expectEqualSlices(u8, "x", infoB.fields[0].name); | ||
| 270 | try testing.expectEqual(u8, infoB.fields[0].field_type); | ||
| 271 | try testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value); | ||
| 272 | try testing.expectEqualSlices(u8, "y", infoB.fields[1].name); | ||
| 273 | try testing.expectEqual(u32, infoB.fields[1].field_type); | ||
| 274 | try testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value); | ||
| 275 | try testing.expectEqual(@as(usize, 0), infoB.decls.len); | ||
| 276 | try testing.expectEqual(@as(bool, false), infoB.is_tuple); | ||
| 277 | |||
| 278 | const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 })); | ||
| 279 | const infoC = @typeInfo(C).Struct; | ||
| 280 | try testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout); | ||
| 281 | try testing.expectEqualSlices(u8, "x", infoC.fields[0].name); | ||
| 282 | try testing.expectEqual(u8, infoC.fields[0].field_type); | ||
| 283 | try testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value); | ||
| 284 | try testing.expectEqualSlices(u8, "y", infoC.fields[1].name); | ||
| 285 | try testing.expectEqual(u32, infoC.fields[1].field_type); | ||
| 286 | try testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value); | ||
| 287 | try testing.expectEqual(@as(usize, 0), infoC.decls.len); | ||
| 288 | try testing.expectEqual(@as(bool, false), infoC.is_tuple); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "Type.Enum" { | ||
| 292 | const Foo = @Type(.{ | ||
| 293 | .Enum = .{ | ||
| 294 | .layout = .Auto, | ||
| 295 | .tag_type = u8, | ||
| 296 | .fields = &[_]TypeInfo.EnumField{ | ||
| 297 | .{ .name = "a", .value = 1 }, | ||
| 298 | .{ .name = "b", .value = 5 }, | ||
| 299 | }, | ||
| 300 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 301 | .is_exhaustive = true, | ||
| 302 | }, | ||
| 303 | }); | ||
| 304 | try testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive); | ||
| 305 | try testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a)); | ||
| 306 | try testing.expectEqual(@as(u8, 5), @enumToInt(Foo.b)); | ||
| 307 | const Bar = @Type(.{ | ||
| 308 | .Enum = .{ | ||
| 309 | .layout = .Extern, | ||
| 310 | .tag_type = u32, | ||
| 311 | .fields = &[_]TypeInfo.EnumField{ | ||
| 312 | .{ .name = "a", .value = 1 }, | ||
| 313 | .{ .name = "b", .value = 5 }, | ||
| 314 | }, | ||
| 315 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 316 | .is_exhaustive = false, | ||
| 317 | }, | ||
| 318 | }); | ||
| 319 | try testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive); | ||
| 320 | try testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a)); | ||
| 321 | try testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); | ||
| 322 | try testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); | ||
| 323 | } | ||
| 324 | |||
| 325 | test "Type.Union" { | ||
| 326 | const Untagged = @Type(.{ | ||
| 327 | .Union = .{ | ||
| 328 | .layout = .Auto, | ||
| 329 | .tag_type = null, | ||
| 330 | .fields = &[_]TypeInfo.UnionField{ | ||
| 331 | .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) }, | ||
| 332 | .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) }, | ||
| 333 | }, | ||
| 334 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 335 | }, | ||
| 336 | }); | ||
| 337 | var untagged = Untagged{ .int = 1 }; | ||
| 338 | untagged.float = 2.0; | ||
| 339 | untagged.int = 3; | ||
| 340 | try testing.expectEqual(@as(i32, 3), untagged.int); | ||
| 341 | |||
| 342 | const PackedUntagged = @Type(.{ | ||
| 343 | .Union = .{ | ||
| 344 | .layout = .Packed, | ||
| 345 | .tag_type = null, | ||
| 346 | .fields = &[_]TypeInfo.UnionField{ | ||
| 347 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | ||
| 348 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 349 | }, | ||
| 350 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 351 | }, | ||
| 352 | }); | ||
| 353 | var packed_untagged = PackedUntagged{ .signed = -1 }; | ||
| 354 | try testing.expectEqual(@as(i32, -1), packed_untagged.signed); | ||
| 355 | try testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned); | ||
| 356 | |||
| 357 | const Tag = @Type(.{ | ||
| 358 | .Enum = .{ | ||
| 359 | .layout = .Auto, | ||
| 360 | .tag_type = u1, | ||
| 361 | .fields = &[_]TypeInfo.EnumField{ | ||
| 362 | .{ .name = "signed", .value = 0 }, | ||
| 363 | .{ .name = "unsigned", .value = 1 }, | ||
| 364 | }, | ||
| 365 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 366 | .is_exhaustive = true, | ||
| 367 | }, | ||
| 368 | }); | ||
| 369 | const Tagged = @Type(.{ | ||
| 370 | .Union = .{ | ||
| 371 | .layout = .Auto, | ||
| 372 | .tag_type = Tag, | ||
| 373 | .fields = &[_]TypeInfo.UnionField{ | ||
| 374 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | ||
| 375 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 376 | }, | ||
| 377 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 378 | }, | ||
| 379 | }); | ||
| 380 | var tagged = Tagged{ .signed = -1 }; | ||
| 381 | try testing.expectEqual(Tag.signed, tagged); | ||
| 382 | tagged = .{ .unsigned = 1 }; | ||
| 383 | try testing.expectEqual(Tag.unsigned, tagged); | ||
| 384 | } | ||
| 385 | |||
| 386 | test "Type.Union from Type.Enum" { | ||
| 387 | const Tag = @Type(.{ | ||
| 388 | .Enum = .{ | ||
| 389 | .layout = .Auto, | ||
| 390 | .tag_type = u0, | ||
| 391 | .fields = &[_]TypeInfo.EnumField{ | ||
| 392 | .{ .name = "working_as_expected", .value = 0 }, | ||
| 393 | }, | ||
| 394 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 395 | .is_exhaustive = true, | ||
| 396 | }, | ||
| 397 | }); | ||
| 398 | const T = @Type(.{ | ||
| 399 | .Union = .{ | ||
| 400 | .layout = .Auto, | ||
| 401 | .tag_type = Tag, | ||
| 402 | .fields = &[_]TypeInfo.UnionField{ | ||
| 403 | .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 404 | }, | ||
| 405 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 406 | }, | ||
| 407 | }); | ||
| 408 | _ = T; | ||
| 409 | _ = @typeInfo(T).Union; | ||
| 410 | } | ||
| 411 | |||
| 412 | test "Type.Union from regular enum" { | ||
| 413 | const E = enum { working_as_expected = 0 }; | ||
| 414 | const T = @Type(.{ | ||
| 415 | .Union = .{ | ||
| 416 | .layout = .Auto, | ||
| 417 | .tag_type = E, | ||
| 418 | .fields = &[_]TypeInfo.UnionField{ | ||
| 419 | .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 420 | }, | ||
| 421 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 422 | }, | ||
| 423 | }); | ||
| 424 | _ = T; | ||
| 425 | _ = @typeInfo(T).Union; | ||
| 426 | } | ||
| 427 | |||
| 428 | test "Type.Fn" { | ||
| 429 | // wasm doesn't support align attributes on functions | ||
| 430 | if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest; | ||
| 431 | |||
| 432 | const foo = struct { | ||
| 433 | fn func(a: usize, b: bool) align(4) callconv(.C) usize { | ||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | }.func; | ||
| 437 | const Foo = @Type(@typeInfo(@TypeOf(foo))); | ||
| 438 | const foo_2: Foo = foo; | ||
| 439 | } | ||
| 440 | |||
| 441 | test "Type.BoundFn" { | ||
| 442 | // wasm doesn't support align attributes on functions | ||
| 443 | if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest; | ||
| 444 | |||
| 445 | const TestStruct = packed struct { | ||
| 446 | pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {} | ||
| 447 | }; | ||
| 448 | const test_instance: TestStruct = undefined; | ||
| 449 | try testing.expect(std.meta.eql( | ||
| 450 | @typeName(@TypeOf(test_instance.foo)), | ||
| 451 | @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))), | ||
| 452 | )); | ||
| 453 | } | ||
test/behavior/type_info.zig created+484| ... | @@ -0,0 +1,484 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | const TypeInfo = std.builtin.TypeInfo; | ||
| 6 | const TypeId = std.builtin.TypeId; | ||
| 7 | |||
| 8 | const expect = std.testing.expect; | ||
| 9 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 10 | |||
| 11 | test "type info: tag type, void info" { | ||
| 12 | try testBasic(); | ||
| 13 | comptime try testBasic(); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn testBasic() !void { | ||
| 17 | try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId); | ||
| 18 | const void_info = @typeInfo(void); | ||
| 19 | try expect(void_info == TypeId.Void); | ||
| 20 | try expect(void_info.Void == {}); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "type info: integer, floating point type info" { | ||
| 24 | try testIntFloat(); | ||
| 25 | comptime try testIntFloat(); | ||
| 26 | } | ||
| 27 | |||
| 28 | fn testIntFloat() !void { | ||
| 29 | const u8_info = @typeInfo(u8); | ||
| 30 | try expect(u8_info == .Int); | ||
| 31 | try expect(u8_info.Int.signedness == .unsigned); | ||
| 32 | try expect(u8_info.Int.bits == 8); | ||
| 33 | |||
| 34 | const f64_info = @typeInfo(f64); | ||
| 35 | try expect(f64_info == .Float); | ||
| 36 | try expect(f64_info.Float.bits == 64); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "type info: pointer type info" { | ||
| 40 | try testPointer(); | ||
| 41 | comptime try testPointer(); | ||
| 42 | } | ||
| 43 | |||
| 44 | fn testPointer() !void { | ||
| 45 | const u32_ptr_info = @typeInfo(*u32); | ||
| 46 | try expect(u32_ptr_info == .Pointer); | ||
| 47 | try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); | ||
| 48 | try expect(u32_ptr_info.Pointer.is_const == false); | ||
| 49 | try expect(u32_ptr_info.Pointer.is_volatile == false); | ||
| 50 | try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32)); | ||
| 51 | try expect(u32_ptr_info.Pointer.child == u32); | ||
| 52 | try expect(u32_ptr_info.Pointer.sentinel == null); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "type info: unknown length pointer type info" { | ||
| 56 | try testUnknownLenPtr(); | ||
| 57 | comptime try testUnknownLenPtr(); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn testUnknownLenPtr() !void { | ||
| 61 | const u32_ptr_info = @typeInfo([*]const volatile f64); | ||
| 62 | try expect(u32_ptr_info == .Pointer); | ||
| 63 | try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); | ||
| 64 | try expect(u32_ptr_info.Pointer.is_const == true); | ||
| 65 | try expect(u32_ptr_info.Pointer.is_volatile == true); | ||
| 66 | try expect(u32_ptr_info.Pointer.sentinel == null); | ||
| 67 | try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64)); | ||
| 68 | try expect(u32_ptr_info.Pointer.child == f64); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "type info: null terminated pointer type info" { | ||
| 72 | try testNullTerminatedPtr(); | ||
| 73 | comptime try testNullTerminatedPtr(); | ||
| 74 | } | ||
| 75 | |||
| 76 | fn testNullTerminatedPtr() !void { | ||
| 77 | const ptr_info = @typeInfo([*:0]u8); | ||
| 78 | try expect(ptr_info == .Pointer); | ||
| 79 | try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); | ||
| 80 | try expect(ptr_info.Pointer.is_const == false); | ||
| 81 | try expect(ptr_info.Pointer.is_volatile == false); | ||
| 82 | try expect(ptr_info.Pointer.sentinel.? == 0); | ||
| 83 | |||
| 84 | try expect(@typeInfo([:0]u8).Pointer.sentinel != null); | ||
| 85 | } | ||
| 86 | |||
| 87 | test "type info: C pointer type info" { | ||
| 88 | try testCPtr(); | ||
| 89 | comptime try testCPtr(); | ||
| 90 | } | ||
| 91 | |||
| 92 | fn testCPtr() !void { | ||
| 93 | const ptr_info = @typeInfo([*c]align(4) const i8); | ||
| 94 | try expect(ptr_info == .Pointer); | ||
| 95 | try expect(ptr_info.Pointer.size == .C); | ||
| 96 | try expect(ptr_info.Pointer.is_const); | ||
| 97 | try expect(!ptr_info.Pointer.is_volatile); | ||
| 98 | try expect(ptr_info.Pointer.alignment == 4); | ||
| 99 | try expect(ptr_info.Pointer.child == i8); | ||
| 100 | } | ||
| 101 | |||
| 102 | test "type info: slice type info" { | ||
| 103 | try testSlice(); | ||
| 104 | comptime try testSlice(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn testSlice() !void { | ||
| 108 | const u32_slice_info = @typeInfo([]u32); | ||
| 109 | try expect(u32_slice_info == .Pointer); | ||
| 110 | try expect(u32_slice_info.Pointer.size == .Slice); | ||
| 111 | try expect(u32_slice_info.Pointer.is_const == false); | ||
| 112 | try expect(u32_slice_info.Pointer.is_volatile == false); | ||
| 113 | try expect(u32_slice_info.Pointer.alignment == 4); | ||
| 114 | try expect(u32_slice_info.Pointer.child == u32); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "type info: array type info" { | ||
| 118 | try testArray(); | ||
| 119 | comptime try testArray(); | ||
| 120 | } | ||
| 121 | |||
| 122 | fn testArray() !void { | ||
| 123 | { | ||
| 124 | const info = @typeInfo([42]u8); | ||
| 125 | try expect(info == .Array); | ||
| 126 | try expect(info.Array.len == 42); | ||
| 127 | try expect(info.Array.child == u8); | ||
| 128 | try expect(info.Array.sentinel == null); | ||
| 129 | } | ||
| 130 | |||
| 131 | { | ||
| 132 | const info = @typeInfo([10:0]u8); | ||
| 133 | try expect(info.Array.len == 10); | ||
| 134 | try expect(info.Array.child == u8); | ||
| 135 | try expect(info.Array.sentinel.? == @as(u8, 0)); | ||
| 136 | try expect(@sizeOf([10:0]u8) == info.Array.len + 1); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | test "type info: optional type info" { | ||
| 141 | try testOptional(); | ||
| 142 | comptime try testOptional(); | ||
| 143 | } | ||
| 144 | |||
| 145 | fn testOptional() !void { | ||
| 146 | const null_info = @typeInfo(?void); | ||
| 147 | try expect(null_info == .Optional); | ||
| 148 | try expect(null_info.Optional.child == void); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "type info: error set, error union info" { | ||
| 152 | try testErrorSet(); | ||
| 153 | comptime try testErrorSet(); | ||
| 154 | } | ||
| 155 | |||
| 156 | fn testErrorSet() !void { | ||
| 157 | const TestErrorSet = error{ | ||
| 158 | First, | ||
| 159 | Second, | ||
| 160 | Third, | ||
| 161 | }; | ||
| 162 | |||
| 163 | const error_set_info = @typeInfo(TestErrorSet); | ||
| 164 | try expect(error_set_info == .ErrorSet); | ||
| 165 | try expect(error_set_info.ErrorSet.?.len == 3); | ||
| 166 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First")); | ||
| 167 | |||
| 168 | const error_union_info = @typeInfo(TestErrorSet!usize); | ||
| 169 | try expect(error_union_info == .ErrorUnion); | ||
| 170 | try expect(error_union_info.ErrorUnion.error_set == TestErrorSet); | ||
| 171 | try expect(error_union_info.ErrorUnion.payload == usize); | ||
| 172 | |||
| 173 | const global_info = @typeInfo(anyerror); | ||
| 174 | try expect(global_info == .ErrorSet); | ||
| 175 | try expect(global_info.ErrorSet == null); | ||
| 176 | } | ||
| 177 | |||
| 178 | test "type info: enum info" { | ||
| 179 | try testEnum(); | ||
| 180 | comptime try testEnum(); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn testEnum() !void { | ||
| 184 | const Os = enum { | ||
| 185 | Windows, | ||
| 186 | Macos, | ||
| 187 | Linux, | ||
| 188 | FreeBSD, | ||
| 189 | }; | ||
| 190 | |||
| 191 | const os_info = @typeInfo(Os); | ||
| 192 | try expect(os_info == .Enum); | ||
| 193 | try expect(os_info.Enum.layout == .Auto); | ||
| 194 | try expect(os_info.Enum.fields.len == 4); | ||
| 195 | try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); | ||
| 196 | try expect(os_info.Enum.fields[3].value == 3); | ||
| 197 | try expect(os_info.Enum.tag_type == u2); | ||
| 198 | try expect(os_info.Enum.decls.len == 0); | ||
| 199 | } | ||
| 200 | |||
| 201 | test "type info: union info" { | ||
| 202 | try testUnion(); | ||
| 203 | comptime try testUnion(); | ||
| 204 | } | ||
| 205 | |||
| 206 | fn testUnion() !void { | ||
| 207 | const typeinfo_info = @typeInfo(TypeInfo); | ||
| 208 | try expect(typeinfo_info == .Union); | ||
| 209 | try expect(typeinfo_info.Union.layout == .Auto); | ||
| 210 | try expect(typeinfo_info.Union.tag_type.? == TypeId); | ||
| 211 | try expect(typeinfo_info.Union.fields.len == 25); | ||
| 212 | try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); | ||
| 213 | try expect(typeinfo_info.Union.decls.len == 22); | ||
| 214 | |||
| 215 | const TestNoTagUnion = union { | ||
| 216 | Foo: void, | ||
| 217 | Bar: u32, | ||
| 218 | }; | ||
| 219 | |||
| 220 | const notag_union_info = @typeInfo(TestNoTagUnion); | ||
| 221 | try expect(notag_union_info == .Union); | ||
| 222 | try expect(notag_union_info.Union.tag_type == null); | ||
| 223 | try expect(notag_union_info.Union.layout == .Auto); | ||
| 224 | try expect(notag_union_info.Union.fields.len == 2); | ||
| 225 | try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void)); | ||
| 226 | try expect(notag_union_info.Union.fields[1].field_type == u32); | ||
| 227 | try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32)); | ||
| 228 | |||
| 229 | const TestExternUnion = extern union { | ||
| 230 | foo: *c_void, | ||
| 231 | }; | ||
| 232 | |||
| 233 | const extern_union_info = @typeInfo(TestExternUnion); | ||
| 234 | try expect(extern_union_info.Union.layout == .Extern); | ||
| 235 | try expect(extern_union_info.Union.tag_type == null); | ||
| 236 | try expect(extern_union_info.Union.fields[0].field_type == *c_void); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "type info: struct info" { | ||
| 240 | try testStruct(); | ||
| 241 | comptime try testStruct(); | ||
| 242 | } | ||
| 243 | |||
| 244 | fn testStruct() !void { | ||
| 245 | const unpacked_struct_info = @typeInfo(TestUnpackedStruct); | ||
| 246 | try expect(unpacked_struct_info.Struct.is_tuple == false); | ||
| 247 | try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32)); | ||
| 248 | try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4); | ||
| 249 | try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?); | ||
| 250 | |||
| 251 | const struct_info = @typeInfo(TestStruct); | ||
| 252 | try expect(struct_info == .Struct); | ||
| 253 | try expect(struct_info.Struct.is_tuple == false); | ||
| 254 | try expect(struct_info.Struct.layout == .Packed); | ||
| 255 | try expect(struct_info.Struct.fields.len == 4); | ||
| 256 | try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize)); | ||
| 257 | try expect(struct_info.Struct.fields[2].field_type == *TestStruct); | ||
| 258 | try expect(struct_info.Struct.fields[2].default_value == null); | ||
| 259 | try expect(struct_info.Struct.fields[3].default_value.? == 4); | ||
| 260 | try expect(struct_info.Struct.fields[3].alignment == 1); | ||
| 261 | try expect(struct_info.Struct.decls.len == 2); | ||
| 262 | try expect(struct_info.Struct.decls[0].is_pub); | ||
| 263 | try expect(!struct_info.Struct.decls[0].data.Fn.is_extern); | ||
| 264 | try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null); | ||
| 265 | try expect(struct_info.Struct.decls[0].data.Fn.return_type == void); | ||
| 266 | try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void); | ||
| 267 | } | ||
| 268 | |||
| 269 | const TestUnpackedStruct = struct { | ||
| 270 | fieldA: u32 = 4, | ||
| 271 | fieldB: *const [6:0]u8 = "foobar", | ||
| 272 | }; | ||
| 273 | |||
| 274 | const TestStruct = packed struct { | ||
| 275 | fieldA: usize align(2 * @alignOf(usize)), | ||
| 276 | fieldB: void, | ||
| 277 | fieldC: *Self, | ||
| 278 | fieldD: u32 = 4, | ||
| 279 | |||
| 280 | pub fn foo(self: *const Self) void {} | ||
| 281 | const Self = @This(); | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "type info: opaque info" { | ||
| 285 | try testOpaque(); | ||
| 286 | comptime try testOpaque(); | ||
| 287 | } | ||
| 288 | |||
| 289 | fn testOpaque() !void { | ||
| 290 | const Foo = opaque { | ||
| 291 | const A = 1; | ||
| 292 | fn b() void {} | ||
| 293 | }; | ||
| 294 | |||
| 295 | const foo_info = @typeInfo(Foo); | ||
| 296 | try expect(foo_info.Opaque.decls.len == 2); | ||
| 297 | } | ||
| 298 | |||
| 299 | test "type info: function type info" { | ||
| 300 | // wasm doesn't support align attributes on functions | ||
| 301 | if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest; | ||
| 302 | try testFunction(); | ||
| 303 | comptime try testFunction(); | ||
| 304 | } | ||
| 305 | |||
| 306 | fn testFunction() !void { | ||
| 307 | const fn_info = @typeInfo(@TypeOf(foo)); | ||
| 308 | try expect(fn_info == .Fn); | ||
| 309 | try expect(fn_info.Fn.alignment > 0); | ||
| 310 | try expect(fn_info.Fn.calling_convention == .C); | ||
| 311 | try expect(!fn_info.Fn.is_generic); | ||
| 312 | try expect(fn_info.Fn.args.len == 2); | ||
| 313 | try expect(fn_info.Fn.is_var_args); | ||
| 314 | try expect(fn_info.Fn.return_type.? == usize); | ||
| 315 | const fn_aligned_info = @typeInfo(@TypeOf(fooAligned)); | ||
| 316 | try expect(fn_aligned_info.Fn.alignment == 4); | ||
| 317 | |||
| 318 | const test_instance: TestStruct = undefined; | ||
| 319 | const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo)); | ||
| 320 | try expect(bound_fn_info == .BoundFn); | ||
| 321 | try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); | ||
| 322 | } | ||
| 323 | |||
| 324 | extern fn foo(a: usize, b: bool, ...) callconv(.C) usize; | ||
| 325 | extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize; | ||
| 326 | |||
| 327 | test "typeInfo with comptime parameter in struct fn def" { | ||
| 328 | const S = struct { | ||
| 329 | pub fn func(comptime x: f32) void {} | ||
| 330 | }; | ||
| 331 | comptime var info = @typeInfo(S); | ||
| 332 | } | ||
| 333 | |||
| 334 | test "type info: vectors" { | ||
| 335 | try testVector(); | ||
| 336 | comptime try testVector(); | ||
| 337 | } | ||
| 338 | |||
| 339 | fn testVector() !void { | ||
| 340 | const vec_info = @typeInfo(std.meta.Vector(4, i32)); | ||
| 341 | try expect(vec_info == .Vector); | ||
| 342 | try expect(vec_info.Vector.len == 4); | ||
| 343 | try expect(vec_info.Vector.child == i32); | ||
| 344 | } | ||
| 345 | |||
| 346 | test "type info: anyframe and anyframe->T" { | ||
| 347 | try testAnyFrame(); | ||
| 348 | comptime try testAnyFrame(); | ||
| 349 | } | ||
| 350 | |||
| 351 | fn testAnyFrame() !void { | ||
| 352 | { | ||
| 353 | const anyframe_info = @typeInfo(anyframe->i32); | ||
| 354 | try expect(anyframe_info == .AnyFrame); | ||
| 355 | try expect(anyframe_info.AnyFrame.child.? == i32); | ||
| 356 | } | ||
| 357 | |||
| 358 | { | ||
| 359 | const anyframe_info = @typeInfo(anyframe); | ||
| 360 | try expect(anyframe_info == .AnyFrame); | ||
| 361 | try expect(anyframe_info.AnyFrame.child == null); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | test "type info: pass to function" { | ||
| 366 | _ = passTypeInfo(@typeInfo(void)); | ||
| 367 | _ = comptime passTypeInfo(@typeInfo(void)); | ||
| 368 | } | ||
| 369 | |||
| 370 | fn passTypeInfo(comptime info: TypeInfo) type { | ||
| 371 | return void; | ||
| 372 | } | ||
| 373 | |||
| 374 | test "type info: TypeId -> TypeInfo impl cast" { | ||
| 375 | _ = passTypeInfo(TypeId.Void); | ||
| 376 | _ = comptime passTypeInfo(TypeId.Void); | ||
| 377 | } | ||
| 378 | |||
| 379 | test "type info: extern fns with and without lib names" { | ||
| 380 | const S = struct { | ||
| 381 | extern fn bar1() void; | ||
| 382 | extern "cool" fn bar2() void; | ||
| 383 | }; | ||
| 384 | const info = @typeInfo(S); | ||
| 385 | comptime { | ||
| 386 | for (info.Struct.decls) |decl| { | ||
| 387 | if (std.mem.eql(u8, decl.name, "bar1")) { | ||
| 388 | try expect(decl.data.Fn.lib_name == null); | ||
| 389 | } else { | ||
| 390 | try expectEqualStrings("cool", decl.data.Fn.lib_name.?); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | test "data field is a compile-time value" { | ||
| 397 | const S = struct { | ||
| 398 | const Bar = @as(isize, -1); | ||
| 399 | }; | ||
| 400 | comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize); | ||
| 401 | } | ||
| 402 | |||
| 403 | test "sentinel of opaque pointer type" { | ||
| 404 | const c_void_info = @typeInfo(*c_void); | ||
| 405 | try expect(c_void_info.Pointer.sentinel == null); | ||
| 406 | } | ||
| 407 | |||
| 408 | test "@typeInfo does not force declarations into existence" { | ||
| 409 | const S = struct { | ||
| 410 | x: i32, | ||
| 411 | |||
| 412 | fn doNotReferenceMe() void { | ||
| 413 | @compileError("test failed"); | ||
| 414 | } | ||
| 415 | }; | ||
| 416 | comptime try expect(@typeInfo(S).Struct.fields.len == 1); | ||
| 417 | } | ||
| 418 | |||
| 419 | test "defaut value for a var-typed field" { | ||
| 420 | const S = struct { x: anytype }; | ||
| 421 | try expect(@typeInfo(S).Struct.fields[0].default_value == null); | ||
| 422 | } | ||
| 423 | |||
| 424 | fn add(a: i32, b: i32) i32 { | ||
| 425 | return a + b; | ||
| 426 | } | ||
| 427 | |||
| 428 | test "type info for async frames" { | ||
| 429 | switch (@typeInfo(@Frame(add))) { | ||
| 430 | .Frame => |frame| { | ||
| 431 | try expect(frame.function == add); | ||
| 432 | }, | ||
| 433 | else => unreachable, | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | test "type info: value is correctly copied" { | ||
| 438 | comptime { | ||
| 439 | var ptrInfo = @typeInfo([]u32); | ||
| 440 | ptrInfo.Pointer.size = .One; | ||
| 441 | try expect(@typeInfo([]u32).Pointer.size == .Slice); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | test "Declarations are returned in declaration order" { | ||
| 446 | const S = struct { | ||
| 447 | const a = 1; | ||
| 448 | const b = 2; | ||
| 449 | const c = 3; | ||
| 450 | const d = 4; | ||
| 451 | const e = 5; | ||
| 452 | }; | ||
| 453 | const d = @typeInfo(S).Struct.decls; | ||
| 454 | try expect(std.mem.eql(u8, d[0].name, "a")); | ||
| 455 | try expect(std.mem.eql(u8, d[1].name, "b")); | ||
| 456 | try expect(std.mem.eql(u8, d[2].name, "c")); | ||
| 457 | try expect(std.mem.eql(u8, d[3].name, "d")); | ||
| 458 | try expect(std.mem.eql(u8, d[4].name, "e")); | ||
| 459 | } | ||
| 460 | |||
| 461 | test "Struct.is_tuple" { | ||
| 462 | try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple); | ||
| 463 | try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple); | ||
| 464 | } | ||
| 465 | |||
| 466 | test "StructField.is_comptime" { | ||
| 467 | const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct; | ||
| 468 | try expect(!info.fields[0].is_comptime); | ||
| 469 | try expect(info.fields[1].is_comptime); | ||
| 470 | } | ||
| 471 | |||
| 472 | test "typeInfo resolves usingnamespace declarations" { | ||
| 473 | const A = struct { | ||
| 474 | pub const f1 = 42; | ||
| 475 | }; | ||
| 476 | |||
| 477 | const B = struct { | ||
| 478 | const f0 = 42; | ||
| 479 | usingnamespace A; | ||
| 480 | }; | ||
| 481 | |||
| 482 | try expect(@typeInfo(B).Struct.decls.len == 2); | ||
| 483 | //a | ||
| 484 | } | ||
test/behavior/typename.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | |||
| 5 | test "slice" { | ||
| 6 | try expectEqualSlices(u8, "[]u8", @typeName([]u8)); | ||
| 7 | } | ||
test/behavior/undefined.zig created+69| ... | @@ -0,0 +1,69 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | fn initStaticArray() [10]i32 { | ||
| 6 | var array: [10]i32 = undefined; | ||
| 7 | array[0] = 1; | ||
| 8 | array[4] = 2; | ||
| 9 | array[7] = 3; | ||
| 10 | array[9] = 4; | ||
| 11 | return array; | ||
| 12 | } | ||
| 13 | const static_array = initStaticArray(); | ||
| 14 | test "init static array to undefined" { | ||
| 15 | try expect(static_array[0] == 1); | ||
| 16 | try expect(static_array[4] == 2); | ||
| 17 | try expect(static_array[7] == 3); | ||
| 18 | try expect(static_array[9] == 4); | ||
| 19 | |||
| 20 | comptime { | ||
| 21 | try expect(static_array[0] == 1); | ||
| 22 | try expect(static_array[4] == 2); | ||
| 23 | try expect(static_array[7] == 3); | ||
| 24 | try expect(static_array[9] == 4); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | const Foo = struct { | ||
| 29 | x: i32, | ||
| 30 | |||
| 31 | fn setFooXMethod(foo: *Foo) void { | ||
| 32 | foo.x = 3; | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | fn setFooX(foo: *Foo) void { | ||
| 37 | foo.x = 2; | ||
| 38 | } | ||
| 39 | |||
| 40 | test "assign undefined to struct" { | ||
| 41 | comptime { | ||
| 42 | var foo: Foo = undefined; | ||
| 43 | setFooX(&foo); | ||
| 44 | try expect(foo.x == 2); | ||
| 45 | } | ||
| 46 | { | ||
| 47 | var foo: Foo = undefined; | ||
| 48 | setFooX(&foo); | ||
| 49 | try expect(foo.x == 2); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | test "assign undefined to struct with method" { | ||
| 54 | comptime { | ||
| 55 | var foo: Foo = undefined; | ||
| 56 | foo.setFooXMethod(); | ||
| 57 | try expect(foo.x == 3); | ||
| 58 | } | ||
| 59 | { | ||
| 60 | var foo: Foo = undefined; | ||
| 61 | foo.setFooXMethod(); | ||
| 62 | try expect(foo.x == 3); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | test "type name of undefined" { | ||
| 67 | const x = undefined; | ||
| 68 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)")); | ||
| 69 | } | ||
test/behavior/underscore.zig created+28| ... | @@ -0,0 +1,28 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "ignore lval with underscore" { | ||
| 5 | _ = false; | ||
| 6 | } | ||
| 7 | |||
| 8 | test "ignore lval with underscore (for loop)" { | ||
| 9 | for ([_]void{}) |_, i| { | ||
| 10 | for ([_]void{}) |_, j| { | ||
| 11 | break; | ||
| 12 | } | ||
| 13 | break; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | test "ignore lval with underscore (while loop)" { | ||
| 18 | while (optionalReturnError()) |_| { | ||
| 19 | while (optionalReturnError()) |_| { | ||
| 20 | break; | ||
| 21 | } else |_| {} | ||
| 22 | break; | ||
| 23 | } else |_| {} | ||
| 24 | } | ||
| 25 | |||
| 26 | fn optionalReturnError() !?u32 { | ||
| 27 | return error.optionalReturnError; | ||
| 28 | } | ||
test/behavior/union.zig created+806| ... | @@ -0,0 +1,806 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const Tag = std.meta.Tag; | ||
| 5 | |||
| 6 | const Value = union(enum) { | ||
| 7 | Int: u64, | ||
| 8 | Array: [9]u8, | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Agg = struct { | ||
| 12 | val1: Value, | ||
| 13 | val2: Value, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const v1 = Value{ .Int = 1234 }; | ||
| 17 | const v2 = Value{ .Array = [_]u8{3} ** 9 }; | ||
| 18 | |||
| 19 | const err = @as(anyerror!Agg, Agg{ | ||
| 20 | .val1 = v1, | ||
| 21 | .val2 = v2, | ||
| 22 | }); | ||
| 23 | |||
| 24 | const array = [_]Value{ | ||
| 25 | v1, | ||
| 26 | v2, | ||
| 27 | v1, | ||
| 28 | v2, | ||
| 29 | }; | ||
| 30 | |||
| 31 | test "unions embedded in aggregate types" { | ||
| 32 | switch (array[1]) { | ||
| 33 | Value.Array => |arr| try expect(arr[4] == 3), | ||
| 34 | else => unreachable, | ||
| 35 | } | ||
| 36 | switch ((err catch unreachable).val1) { | ||
| 37 | Value.Int => |x| try expect(x == 1234), | ||
| 38 | else => unreachable, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | const Foo = union { | ||
| 43 | float: f64, | ||
| 44 | int: i32, | ||
| 45 | }; | ||
| 46 | |||
| 47 | test "basic unions" { | ||
| 48 | var foo = Foo{ .int = 1 }; | ||
| 49 | try expect(foo.int == 1); | ||
| 50 | foo = Foo{ .float = 12.34 }; | ||
| 51 | try expect(foo.float == 12.34); | ||
| 52 | } | ||
| 53 | |||
| 54 | test "comptime union field access" { | ||
| 55 | comptime { | ||
| 56 | var foo = Foo{ .int = 0 }; | ||
| 57 | try expect(foo.int == 0); | ||
| 58 | |||
| 59 | foo = Foo{ .float = 42.42 }; | ||
| 60 | try expect(foo.float == 42.42); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | test "init union with runtime value" { | ||
| 65 | var foo: Foo = undefined; | ||
| 66 | |||
| 67 | setFloat(&foo, 12.34); | ||
| 68 | try expect(foo.float == 12.34); | ||
| 69 | |||
| 70 | setInt(&foo, 42); | ||
| 71 | try expect(foo.int == 42); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn setFloat(foo: *Foo, x: f64) void { | ||
| 75 | foo.* = Foo{ .float = x }; | ||
| 76 | } | ||
| 77 | |||
| 78 | fn setInt(foo: *Foo, x: i32) void { | ||
| 79 | foo.* = Foo{ .int = x }; | ||
| 80 | } | ||
| 81 | |||
| 82 | const FooExtern = extern union { | ||
| 83 | float: f64, | ||
| 84 | int: i32, | ||
| 85 | }; | ||
| 86 | |||
| 87 | test "basic extern unions" { | ||
| 88 | var foo = FooExtern{ .int = 1 }; | ||
| 89 | try expect(foo.int == 1); | ||
| 90 | foo.float = 12.34; | ||
| 91 | try expect(foo.float == 12.34); | ||
| 92 | } | ||
| 93 | |||
| 94 | const Letter = enum { | ||
| 95 | A, | ||
| 96 | B, | ||
| 97 | C, | ||
| 98 | }; | ||
| 99 | const Payload = union(Letter) { | ||
| 100 | A: i32, | ||
| 101 | B: f64, | ||
| 102 | C: bool, | ||
| 103 | }; | ||
| 104 | |||
| 105 | test "union with specified enum tag" { | ||
| 106 | try doTest(); | ||
| 107 | comptime try doTest(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn doTest() !void { | ||
| 111 | try expect((try bar(Payload{ .A = 1234 })) == -10); | ||
| 112 | } | ||
| 113 | |||
| 114 | fn bar(value: Payload) !i32 { | ||
| 115 | try expect(@as(Letter, value) == Letter.A); | ||
| 116 | return switch (value) { | ||
| 117 | Payload.A => |x| return x - 1244, | ||
| 118 | Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21, | ||
| 119 | Payload.C => |x| if (x) @as(i32, 30) else 31, | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | |||
| 123 | const MultipleChoice = union(enum(u32)) { | ||
| 124 | A = 20, | ||
| 125 | B = 40, | ||
| 126 | C = 60, | ||
| 127 | D = 1000, | ||
| 128 | }; | ||
| 129 | test "simple union(enum(u32))" { | ||
| 130 | var x = MultipleChoice.C; | ||
| 131 | try expect(x == MultipleChoice.C); | ||
| 132 | try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60); | ||
| 133 | } | ||
| 134 | |||
| 135 | const MultipleChoice2 = union(enum(u32)) { | ||
| 136 | Unspecified1: i32, | ||
| 137 | A: f32 = 20, | ||
| 138 | Unspecified2: void, | ||
| 139 | B: bool = 40, | ||
| 140 | Unspecified3: i32, | ||
| 141 | C: i8 = 60, | ||
| 142 | Unspecified4: void, | ||
| 143 | D: void = 1000, | ||
| 144 | Unspecified5: i32, | ||
| 145 | }; | ||
| 146 | |||
| 147 | test "union(enum(u32)) with specified and unspecified tag values" { | ||
| 148 | comptime try expect(Tag(Tag(MultipleChoice2)) == u32); | ||
| 149 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 150 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 151 | } | ||
| 152 | |||
| 153 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { | ||
| 154 | try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60); | ||
| 155 | try expect(1123 == switch (x) { | ||
| 156 | MultipleChoice2.A => 1, | ||
| 157 | MultipleChoice2.B => 2, | ||
| 158 | MultipleChoice2.C => |v| @as(i32, 1000) + v, | ||
| 159 | MultipleChoice2.D => 4, | ||
| 160 | MultipleChoice2.Unspecified1 => 5, | ||
| 161 | MultipleChoice2.Unspecified2 => 6, | ||
| 162 | MultipleChoice2.Unspecified3 => 7, | ||
| 163 | MultipleChoice2.Unspecified4 => 8, | ||
| 164 | MultipleChoice2.Unspecified5 => 9, | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | |||
| 168 | const ExternPtrOrInt = extern union { | ||
| 169 | ptr: *u8, | ||
| 170 | int: u64, | ||
| 171 | }; | ||
| 172 | test "extern union size" { | ||
| 173 | comptime try expect(@sizeOf(ExternPtrOrInt) == 8); | ||
| 174 | } | ||
| 175 | |||
| 176 | const PackedPtrOrInt = packed union { | ||
| 177 | ptr: *u8, | ||
| 178 | int: u64, | ||
| 179 | }; | ||
| 180 | test "extern union size" { | ||
| 181 | comptime try expect(@sizeOf(PackedPtrOrInt) == 8); | ||
| 182 | } | ||
| 183 | |||
| 184 | const ZeroBits = union { | ||
| 185 | OnlyField: void, | ||
| 186 | }; | ||
| 187 | test "union with only 1 field which is void should be zero bits" { | ||
| 188 | comptime try expect(@sizeOf(ZeroBits) == 0); | ||
| 189 | } | ||
| 190 | |||
| 191 | const TheTag = enum { | ||
| 192 | A, | ||
| 193 | B, | ||
| 194 | C, | ||
| 195 | }; | ||
| 196 | const TheUnion = union(TheTag) { | ||
| 197 | A: i32, | ||
| 198 | B: i32, | ||
| 199 | C: i32, | ||
| 200 | }; | ||
| 201 | test "union field access gives the enum values" { | ||
| 202 | try expect(TheUnion.A == TheTag.A); | ||
| 203 | try expect(TheUnion.B == TheTag.B); | ||
| 204 | try expect(TheUnion.C == TheTag.C); | ||
| 205 | } | ||
| 206 | |||
| 207 | test "cast union to tag type of union" { | ||
| 208 | try testCastUnionToTag(TheUnion{ .B = 1234 }); | ||
| 209 | comptime try testCastUnionToTag(TheUnion{ .B = 1234 }); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn testCastUnionToTag(x: TheUnion) !void { | ||
| 213 | try expect(@as(TheTag, x) == TheTag.B); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "cast tag type of union to union" { | ||
| 217 | var x: Value2 = Letter2.B; | ||
| 218 | try expect(@as(Letter2, x) == Letter2.B); | ||
| 219 | } | ||
| 220 | const Letter2 = enum { | ||
| 221 | A, | ||
| 222 | B, | ||
| 223 | C, | ||
| 224 | }; | ||
| 225 | const Value2 = union(Letter2) { | ||
| 226 | A: i32, | ||
| 227 | B, | ||
| 228 | C, | ||
| 229 | }; | ||
| 230 | |||
| 231 | test "implicit cast union to its tag type" { | ||
| 232 | var x: Value2 = Letter2.B; | ||
| 233 | try expect(x == Letter2.B); | ||
| 234 | try giveMeLetterB(x); | ||
| 235 | } | ||
| 236 | fn giveMeLetterB(x: Letter2) !void { | ||
| 237 | try expect(x == Value2.B); | ||
| 238 | } | ||
| 239 | |||
| 240 | pub const PackThis = union(enum) { | ||
| 241 | Invalid: bool, | ||
| 242 | StringLiteral: u2, | ||
| 243 | }; | ||
| 244 | |||
| 245 | test "constant packed union" { | ||
| 246 | try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); | ||
| 247 | } | ||
| 248 | |||
| 249 | fn testConstPackedUnion(expected_tokens: []const PackThis) !void { | ||
| 250 | try expect(expected_tokens[0].StringLiteral == 1); | ||
| 251 | } | ||
| 252 | |||
| 253 | test "switch on union with only 1 field" { | ||
| 254 | var r: PartialInst = undefined; | ||
| 255 | r = PartialInst.Compiled; | ||
| 256 | switch (r) { | ||
| 257 | PartialInst.Compiled => { | ||
| 258 | var z: PartialInstWithPayload = undefined; | ||
| 259 | z = PartialInstWithPayload{ .Compiled = 1234 }; | ||
| 260 | switch (z) { | ||
| 261 | PartialInstWithPayload.Compiled => |x| { | ||
| 262 | try expect(x == 1234); | ||
| 263 | return; | ||
| 264 | }, | ||
| 265 | } | ||
| 266 | }, | ||
| 267 | } | ||
| 268 | unreachable; | ||
| 269 | } | ||
| 270 | |||
| 271 | const PartialInst = union(enum) { | ||
| 272 | Compiled, | ||
| 273 | }; | ||
| 274 | |||
| 275 | const PartialInstWithPayload = union(enum) { | ||
| 276 | Compiled: i32, | ||
| 277 | }; | ||
| 278 | |||
| 279 | test "access a member of tagged union with conflicting enum tag name" { | ||
| 280 | const Bar = union(enum) { | ||
| 281 | A: A, | ||
| 282 | B: B, | ||
| 283 | |||
| 284 | const A = u8; | ||
| 285 | const B = void; | ||
| 286 | }; | ||
| 287 | |||
| 288 | comptime try expect(Bar.A == u8); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "tagged union initialization with runtime void" { | ||
| 292 | try expect(testTaggedUnionInit({})); | ||
| 293 | } | ||
| 294 | |||
| 295 | const TaggedUnionWithAVoid = union(enum) { | ||
| 296 | A, | ||
| 297 | B: i32, | ||
| 298 | }; | ||
| 299 | |||
| 300 | fn testTaggedUnionInit(x: anytype) bool { | ||
| 301 | const y = TaggedUnionWithAVoid{ .A = x }; | ||
| 302 | return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A; | ||
| 303 | } | ||
| 304 | |||
| 305 | pub const UnionEnumNoPayloads = union(enum) { | ||
| 306 | A, | ||
| 307 | B, | ||
| 308 | }; | ||
| 309 | |||
| 310 | test "tagged union with no payloads" { | ||
| 311 | const a = UnionEnumNoPayloads{ .B = {} }; | ||
| 312 | switch (a) { | ||
| 313 | Tag(UnionEnumNoPayloads).A => @panic("wrong"), | ||
| 314 | Tag(UnionEnumNoPayloads).B => {}, | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | test "union with only 1 field casted to its enum type" { | ||
| 319 | const Literal = union(enum) { | ||
| 320 | Number: f64, | ||
| 321 | Bool: bool, | ||
| 322 | }; | ||
| 323 | |||
| 324 | const Expr = union(enum) { | ||
| 325 | Literal: Literal, | ||
| 326 | }; | ||
| 327 | |||
| 328 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 329 | const ExprTag = Tag(Expr); | ||
| 330 | comptime try expect(Tag(ExprTag) == u0); | ||
| 331 | var t = @as(ExprTag, e); | ||
| 332 | try expect(t == Expr.Literal); | ||
| 333 | } | ||
| 334 | |||
| 335 | test "union with only 1 field casted to its enum type which has enum value specified" { | ||
| 336 | const Literal = union(enum) { | ||
| 337 | Number: f64, | ||
| 338 | Bool: bool, | ||
| 339 | }; | ||
| 340 | |||
| 341 | const ExprTag = enum(comptime_int) { | ||
| 342 | Literal = 33, | ||
| 343 | }; | ||
| 344 | |||
| 345 | const Expr = union(ExprTag) { | ||
| 346 | Literal: Literal, | ||
| 347 | }; | ||
| 348 | |||
| 349 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 350 | comptime try expect(Tag(ExprTag) == comptime_int); | ||
| 351 | var t = @as(ExprTag, e); | ||
| 352 | try expect(t == Expr.Literal); | ||
| 353 | try expect(@enumToInt(t) == 33); | ||
| 354 | comptime try expect(@enumToInt(t) == 33); | ||
| 355 | } | ||
| 356 | |||
| 357 | test "@enumToInt works on unions" { | ||
| 358 | const Bar = union(enum) { | ||
| 359 | A: bool, | ||
| 360 | B: u8, | ||
| 361 | C, | ||
| 362 | }; | ||
| 363 | |||
| 364 | const a = Bar{ .A = true }; | ||
| 365 | var b = Bar{ .B = undefined }; | ||
| 366 | var c = Bar.C; | ||
| 367 | try expect(@enumToInt(a) == 0); | ||
| 368 | try expect(@enumToInt(b) == 1); | ||
| 369 | try expect(@enumToInt(c) == 2); | ||
| 370 | } | ||
| 371 | |||
| 372 | const Attribute = union(enum) { | ||
| 373 | A: bool, | ||
| 374 | B: u8, | ||
| 375 | }; | ||
| 376 | |||
| 377 | fn setAttribute(attr: Attribute) void {} | ||
| 378 | |||
| 379 | fn Setter(attr: Attribute) type { | ||
| 380 | return struct { | ||
| 381 | fn set() void { | ||
| 382 | setAttribute(attr); | ||
| 383 | } | ||
| 384 | }; | ||
| 385 | } | ||
| 386 | |||
| 387 | test "comptime union field value equality" { | ||
| 388 | const a0 = Setter(Attribute{ .A = false }); | ||
| 389 | const a1 = Setter(Attribute{ .A = true }); | ||
| 390 | const a2 = Setter(Attribute{ .A = false }); | ||
| 391 | |||
| 392 | const b0 = Setter(Attribute{ .B = 5 }); | ||
| 393 | const b1 = Setter(Attribute{ .B = 9 }); | ||
| 394 | const b2 = Setter(Attribute{ .B = 5 }); | ||
| 395 | |||
| 396 | try expect(a0 == a0); | ||
| 397 | try expect(a1 == a1); | ||
| 398 | try expect(a0 == a2); | ||
| 399 | |||
| 400 | try expect(b0 == b0); | ||
| 401 | try expect(b1 == b1); | ||
| 402 | try expect(b0 == b2); | ||
| 403 | |||
| 404 | try expect(a0 != b0); | ||
| 405 | try expect(a0 != a1); | ||
| 406 | try expect(b0 != b1); | ||
| 407 | } | ||
| 408 | |||
| 409 | test "return union init with void payload" { | ||
| 410 | const S = struct { | ||
| 411 | fn entry() !void { | ||
| 412 | try expect(func().state == State.one); | ||
| 413 | } | ||
| 414 | const Outer = union(enum) { | ||
| 415 | state: State, | ||
| 416 | }; | ||
| 417 | const State = union(enum) { | ||
| 418 | one: void, | ||
| 419 | two: u32, | ||
| 420 | }; | ||
| 421 | fn func() Outer { | ||
| 422 | return Outer{ .state = State{ .one = {} } }; | ||
| 423 | } | ||
| 424 | }; | ||
| 425 | try S.entry(); | ||
| 426 | comptime try S.entry(); | ||
| 427 | } | ||
| 428 | |||
| 429 | test "@unionInit can modify a union type" { | ||
| 430 | const UnionInitEnum = union(enum) { | ||
| 431 | Boolean: bool, | ||
| 432 | Byte: u8, | ||
| 433 | }; | ||
| 434 | |||
| 435 | var value: UnionInitEnum = undefined; | ||
| 436 | |||
| 437 | value = @unionInit(UnionInitEnum, "Boolean", true); | ||
| 438 | try expect(value.Boolean == true); | ||
| 439 | value.Boolean = false; | ||
| 440 | try expect(value.Boolean == false); | ||
| 441 | |||
| 442 | value = @unionInit(UnionInitEnum, "Byte", 2); | ||
| 443 | try expect(value.Byte == 2); | ||
| 444 | value.Byte = 3; | ||
| 445 | try expect(value.Byte == 3); | ||
| 446 | } | ||
| 447 | |||
| 448 | test "@unionInit can modify a pointer value" { | ||
| 449 | const UnionInitEnum = union(enum) { | ||
| 450 | Boolean: bool, | ||
| 451 | Byte: u8, | ||
| 452 | }; | ||
| 453 | |||
| 454 | var value: UnionInitEnum = undefined; | ||
| 455 | var value_ptr = &value; | ||
| 456 | |||
| 457 | value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true); | ||
| 458 | try expect(value.Boolean == true); | ||
| 459 | |||
| 460 | value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2); | ||
| 461 | try expect(value.Byte == 2); | ||
| 462 | } | ||
| 463 | |||
| 464 | test "union no tag with struct member" { | ||
| 465 | const Struct = struct {}; | ||
| 466 | const Union = union { | ||
| 467 | s: Struct, | ||
| 468 | pub fn foo(self: *@This()) void {} | ||
| 469 | }; | ||
| 470 | var u = Union{ .s = Struct{} }; | ||
| 471 | u.foo(); | ||
| 472 | } | ||
| 473 | |||
| 474 | fn testComparison() !void { | ||
| 475 | var x = Payload{ .A = 42 }; | ||
| 476 | try expect(x == .A); | ||
| 477 | try expect(x != .B); | ||
| 478 | try expect(x != .C); | ||
| 479 | try expect((x == .B) == false); | ||
| 480 | try expect((x == .C) == false); | ||
| 481 | try expect((x != .A) == false); | ||
| 482 | } | ||
| 483 | |||
| 484 | test "comparison between union and enum literal" { | ||
| 485 | try testComparison(); | ||
| 486 | comptime try testComparison(); | ||
| 487 | } | ||
| 488 | |||
| 489 | test "packed union generates correctly aligned LLVM type" { | ||
| 490 | const U = packed union { | ||
| 491 | f1: fn () error{TestUnexpectedResult}!void, | ||
| 492 | f2: u32, | ||
| 493 | }; | ||
| 494 | var foo = [_]U{ | ||
| 495 | U{ .f1 = doTest }, | ||
| 496 | U{ .f2 = 0 }, | ||
| 497 | }; | ||
| 498 | try foo[0].f1(); | ||
| 499 | } | ||
| 500 | |||
| 501 | test "union with one member defaults to u0 tag type" { | ||
| 502 | const U0 = union(enum) { | ||
| 503 | X: u32, | ||
| 504 | }; | ||
| 505 | comptime try expect(Tag(Tag(U0)) == u0); | ||
| 506 | } | ||
| 507 | |||
| 508 | test "union with comptime_int tag" { | ||
| 509 | const Union = union(enum(comptime_int)) { | ||
| 510 | X: u32, | ||
| 511 | Y: u16, | ||
| 512 | Z: u8, | ||
| 513 | }; | ||
| 514 | comptime try expect(Tag(Tag(Union)) == comptime_int); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "extern union doesn't trigger field check at comptime" { | ||
| 518 | const U = extern union { | ||
| 519 | x: u32, | ||
| 520 | y: u8, | ||
| 521 | }; | ||
| 522 | |||
| 523 | const x = U{ .x = 0x55AAAA55 }; | ||
| 524 | comptime try expect(x.y == 0x55); | ||
| 525 | } | ||
| 526 | |||
| 527 | const Foo1 = union(enum) { | ||
| 528 | f: struct { | ||
| 529 | x: usize, | ||
| 530 | }, | ||
| 531 | }; | ||
| 532 | var glbl: Foo1 = undefined; | ||
| 533 | |||
| 534 | test "global union with single field is correctly initialized" { | ||
| 535 | glbl = Foo1{ | ||
| 536 | .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 }, | ||
| 537 | }; | ||
| 538 | try expect(glbl.f.x == 123); | ||
| 539 | } | ||
| 540 | |||
| 541 | pub const FooUnion = union(enum) { | ||
| 542 | U0: usize, | ||
| 543 | U1: u8, | ||
| 544 | }; | ||
| 545 | |||
| 546 | var glbl_array: [2]FooUnion = undefined; | ||
| 547 | |||
| 548 | test "initialize global array of union" { | ||
| 549 | glbl_array[1] = FooUnion{ .U1 = 2 }; | ||
| 550 | glbl_array[0] = FooUnion{ .U0 = 1 }; | ||
| 551 | try expect(glbl_array[0].U0 == 1); | ||
| 552 | try expect(glbl_array[1].U1 == 2); | ||
| 553 | } | ||
| 554 | |||
| 555 | test "anonymous union literal syntax" { | ||
| 556 | const S = struct { | ||
| 557 | const Number = union { | ||
| 558 | int: i32, | ||
| 559 | float: f64, | ||
| 560 | }; | ||
| 561 | |||
| 562 | fn doTheTest() !void { | ||
| 563 | var i: Number = .{ .int = 42 }; | ||
| 564 | var f = makeNumber(); | ||
| 565 | try expect(i.int == 42); | ||
| 566 | try expect(f.float == 12.34); | ||
| 567 | } | ||
| 568 | |||
| 569 | fn makeNumber() Number { | ||
| 570 | return .{ .float = 12.34 }; | ||
| 571 | } | ||
| 572 | }; | ||
| 573 | try S.doTheTest(); | ||
| 574 | comptime try S.doTheTest(); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "update the tag value for zero-sized unions" { | ||
| 578 | const S = union(enum) { | ||
| 579 | U0: void, | ||
| 580 | U1: void, | ||
| 581 | }; | ||
| 582 | var x = S{ .U0 = {} }; | ||
| 583 | try expect(x == .U0); | ||
| 584 | x = S{ .U1 = {} }; | ||
| 585 | try expect(x == .U1); | ||
| 586 | } | ||
| 587 | |||
| 588 | test "function call result coerces from tagged union to the tag" { | ||
| 589 | const S = struct { | ||
| 590 | const Arch = union(enum) { | ||
| 591 | One, | ||
| 592 | Two: usize, | ||
| 593 | }; | ||
| 594 | |||
| 595 | const ArchTag = Tag(Arch); | ||
| 596 | |||
| 597 | fn doTheTest() !void { | ||
| 598 | var x: ArchTag = getArch1(); | ||
| 599 | try expect(x == .One); | ||
| 600 | |||
| 601 | var y: ArchTag = getArch2(); | ||
| 602 | try expect(y == .Two); | ||
| 603 | } | ||
| 604 | |||
| 605 | pub fn getArch1() Arch { | ||
| 606 | return .One; | ||
| 607 | } | ||
| 608 | |||
| 609 | pub fn getArch2() Arch { | ||
| 610 | return .{ .Two = 99 }; | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | try S.doTheTest(); | ||
| 614 | comptime try S.doTheTest(); | ||
| 615 | } | ||
| 616 | |||
| 617 | test "0-sized extern union definition" { | ||
| 618 | const U = extern union { | ||
| 619 | a: void, | ||
| 620 | const f = 1; | ||
| 621 | }; | ||
| 622 | |||
| 623 | try expect(U.f == 1); | ||
| 624 | } | ||
| 625 | |||
| 626 | test "union initializer generates padding only if needed" { | ||
| 627 | const U = union(enum) { | ||
| 628 | A: u24, | ||
| 629 | }; | ||
| 630 | |||
| 631 | var v = U{ .A = 532 }; | ||
| 632 | try expect(v.A == 532); | ||
| 633 | } | ||
| 634 | |||
| 635 | test "runtime tag name with single field" { | ||
| 636 | const U = union(enum) { | ||
| 637 | A: i32, | ||
| 638 | }; | ||
| 639 | |||
| 640 | var v = U{ .A = 42 }; | ||
| 641 | try expect(std.mem.eql(u8, @tagName(v), "A")); | ||
| 642 | } | ||
| 643 | |||
| 644 | test "cast from anonymous struct to union" { | ||
| 645 | const S = struct { | ||
| 646 | const U = union(enum) { | ||
| 647 | A: u32, | ||
| 648 | B: []const u8, | ||
| 649 | C: void, | ||
| 650 | }; | ||
| 651 | fn doTheTest() !void { | ||
| 652 | var y: u32 = 42; | ||
| 653 | const t0 = .{ .A = 123 }; | ||
| 654 | const t1 = .{ .B = "foo" }; | ||
| 655 | const t2 = .{ .C = {} }; | ||
| 656 | const t3 = .{ .A = y }; | ||
| 657 | const x0: U = t0; | ||
| 658 | var x1: U = t1; | ||
| 659 | const x2: U = t2; | ||
| 660 | var x3: U = t3; | ||
| 661 | try expect(x0.A == 123); | ||
| 662 | try expect(std.mem.eql(u8, x1.B, "foo")); | ||
| 663 | try expect(x2 == .C); | ||
| 664 | try expect(x3.A == y); | ||
| 665 | } | ||
| 666 | }; | ||
| 667 | try S.doTheTest(); | ||
| 668 | comptime try S.doTheTest(); | ||
| 669 | } | ||
| 670 | |||
| 671 | test "cast from pointer to anonymous struct to pointer to union" { | ||
| 672 | const S = struct { | ||
| 673 | const U = union(enum) { | ||
| 674 | A: u32, | ||
| 675 | B: []const u8, | ||
| 676 | C: void, | ||
| 677 | }; | ||
| 678 | fn doTheTest() !void { | ||
| 679 | var y: u32 = 42; | ||
| 680 | const t0 = &.{ .A = 123 }; | ||
| 681 | const t1 = &.{ .B = "foo" }; | ||
| 682 | const t2 = &.{ .C = {} }; | ||
| 683 | const t3 = &.{ .A = y }; | ||
| 684 | const x0: *const U = t0; | ||
| 685 | var x1: *const U = t1; | ||
| 686 | const x2: *const U = t2; | ||
| 687 | var x3: *const U = t3; | ||
| 688 | try expect(x0.A == 123); | ||
| 689 | try expect(std.mem.eql(u8, x1.B, "foo")); | ||
| 690 | try expect(x2.* == .C); | ||
| 691 | try expect(x3.A == y); | ||
| 692 | } | ||
| 693 | }; | ||
| 694 | try S.doTheTest(); | ||
| 695 | comptime try S.doTheTest(); | ||
| 696 | } | ||
| 697 | |||
| 698 | test "method call on an empty union" { | ||
| 699 | const S = struct { | ||
| 700 | const MyUnion = union(MyUnionTag) { | ||
| 701 | pub const MyUnionTag = enum { X1, X2 }; | ||
| 702 | X1: [0]u8, | ||
| 703 | X2: [0]u8, | ||
| 704 | |||
| 705 | pub fn useIt(self: *@This()) bool { | ||
| 706 | return true; | ||
| 707 | } | ||
| 708 | }; | ||
| 709 | |||
| 710 | fn doTheTest() !void { | ||
| 711 | var u = MyUnion{ .X1 = [0]u8{} }; | ||
| 712 | try expect(u.useIt()); | ||
| 713 | } | ||
| 714 | }; | ||
| 715 | try S.doTheTest(); | ||
| 716 | comptime try S.doTheTest(); | ||
| 717 | } | ||
| 718 | |||
| 719 | test "switching on non exhaustive union" { | ||
| 720 | const S = struct { | ||
| 721 | const E = enum(u8) { | ||
| 722 | a, | ||
| 723 | b, | ||
| 724 | _, | ||
| 725 | }; | ||
| 726 | const U = union(E) { | ||
| 727 | a: i32, | ||
| 728 | b: u32, | ||
| 729 | }; | ||
| 730 | fn doTheTest() !void { | ||
| 731 | var a = U{ .a = 2 }; | ||
| 732 | switch (a) { | ||
| 733 | .a => |val| try expect(val == 2), | ||
| 734 | .b => unreachable, | ||
| 735 | } | ||
| 736 | } | ||
| 737 | }; | ||
| 738 | try S.doTheTest(); | ||
| 739 | comptime try S.doTheTest(); | ||
| 740 | } | ||
| 741 | |||
| 742 | test "containers with single-field enums" { | ||
| 743 | const S = struct { | ||
| 744 | const A = union(enum) { f1 }; | ||
| 745 | const B = union(enum) { f1: void }; | ||
| 746 | const C = struct { a: A }; | ||
| 747 | const D = struct { a: B }; | ||
| 748 | |||
| 749 | fn doTheTest() !void { | ||
| 750 | var array1 = [1]A{A{ .f1 = {} }}; | ||
| 751 | var array2 = [1]B{B{ .f1 = {} }}; | ||
| 752 | try expect(array1[0] == .f1); | ||
| 753 | try expect(array2[0] == .f1); | ||
| 754 | |||
| 755 | var struct1 = C{ .a = A{ .f1 = {} } }; | ||
| 756 | var struct2 = D{ .a = B{ .f1 = {} } }; | ||
| 757 | try expect(struct1.a == .f1); | ||
| 758 | try expect(struct2.a == .f1); | ||
| 759 | } | ||
| 760 | }; | ||
| 761 | |||
| 762 | try S.doTheTest(); | ||
| 763 | comptime try S.doTheTest(); | ||
| 764 | } | ||
| 765 | |||
| 766 | test "@unionInit on union w/ tag but no fields" { | ||
| 767 | const S = struct { | ||
| 768 | const Type = enum(u8) { no_op = 105 }; | ||
| 769 | |||
| 770 | const Data = union(Type) { | ||
| 771 | no_op: void, | ||
| 772 | |||
| 773 | pub fn decode(buf: []const u8) Data { | ||
| 774 | return @unionInit(Data, "no_op", {}); | ||
| 775 | } | ||
| 776 | }; | ||
| 777 | |||
| 778 | comptime { | ||
| 779 | try expect(@sizeOf(Data) != 0); | ||
| 780 | } | ||
| 781 | |||
| 782 | fn doTheTest() !void { | ||
| 783 | var data: Data = .{ .no_op = .{} }; | ||
| 784 | var o = Data.decode(&[_]u8{}); | ||
| 785 | try expectEqual(Type.no_op, o); | ||
| 786 | } | ||
| 787 | }; | ||
| 788 | |||
| 789 | try S.doTheTest(); | ||
| 790 | comptime try S.doTheTest(); | ||
| 791 | } | ||
| 792 | |||
| 793 | test "union enum type gets a separate scope" { | ||
| 794 | const S = struct { | ||
| 795 | const U = union(enum) { | ||
| 796 | a: u8, | ||
| 797 | const foo = 1; | ||
| 798 | }; | ||
| 799 | |||
| 800 | fn doTheTest() !void { | ||
| 801 | try expect(!@hasDecl(Tag(U), "foo")); | ||
| 802 | } | ||
| 803 | }; | ||
| 804 | |||
| 805 | try S.doTheTest(); | ||
| 806 | } | ||
test/behavior/usingnamespace.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | fn Foo(comptime T: type) type { | ||
| 4 | return struct { | ||
| 5 | usingnamespace T; | ||
| 6 | }; | ||
| 7 | } | ||
| 8 | |||
| 9 | test "usingnamespace inside a generic struct" { | ||
| 10 | const std2 = Foo(std); | ||
| 11 | const testing2 = Foo(std.testing); | ||
| 12 | try std2.testing.expect(true); | ||
| 13 | try testing2.expect(true); | ||
| 14 | } | ||
| 15 | |||
| 16 | usingnamespace struct { | ||
| 17 | pub const foo = 42; | ||
| 18 | }; | ||
| 19 | |||
| 20 | test "usingnamespace does not redeclare an imported variable" { | ||
| 21 | comptime try std.testing.expect(foo == 42); | ||
| 22 | } | ||
test/behavior/var_args.zig created+83| ... | @@ -0,0 +1,83 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn add(args: anytype) i32 { | ||
| 4 | var sum = @as(i32, 0); | ||
| 5 | { | ||
| 6 | comptime var i: usize = 0; | ||
| 7 | inline while (i < args.len) : (i += 1) { | ||
| 8 | sum += args[i]; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | return sum; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "add arbitrary args" { | ||
| 15 | try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); | ||
| 16 | try expect(add(.{@as(i32, 1234)}) == 1234); | ||
| 17 | try expect(add(.{}) == 0); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn readFirstVarArg(args: anytype) void { | ||
| 21 | const value = args[0]; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "send void arg to var args" { | ||
| 25 | readFirstVarArg(.{{}}); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "pass args directly" { | ||
| 29 | try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); | ||
| 30 | try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234); | ||
| 31 | try expect(addSomeStuff(.{}) == 0); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn addSomeStuff(args: anytype) i32 { | ||
| 35 | return add(args); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "runtime parameter before var args" { | ||
| 39 | try expect((try extraFn(10, .{})) == 0); | ||
| 40 | try expect((try extraFn(10, .{false})) == 1); | ||
| 41 | try expect((try extraFn(10, .{ false, true })) == 2); | ||
| 42 | |||
| 43 | comptime { | ||
| 44 | try expect((try extraFn(10, .{})) == 0); | ||
| 45 | try expect((try extraFn(10, .{false})) == 1); | ||
| 46 | try expect((try extraFn(10, .{ false, true })) == 2); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | fn extraFn(extra: u32, args: anytype) !usize { | ||
| 51 | if (args.len >= 1) { | ||
| 52 | try expect(args[0] == false); | ||
| 53 | } | ||
| 54 | if (args.len >= 2) { | ||
| 55 | try expect(args[1] == true); | ||
| 56 | } | ||
| 57 | return args.len; | ||
| 58 | } | ||
| 59 | |||
| 60 | const foos = [_]fn (anytype) bool{ | ||
| 61 | foo1, | ||
| 62 | foo2, | ||
| 63 | }; | ||
| 64 | |||
| 65 | fn foo1(args: anytype) bool { | ||
| 66 | return true; | ||
| 67 | } | ||
| 68 | fn foo2(args: anytype) bool { | ||
| 69 | return false; | ||
| 70 | } | ||
| 71 | |||
| 72 | test "array of var args functions" { | ||
| 73 | try expect(foos[0](.{})); | ||
| 74 | try expect(!foos[1](.{})); | ||
| 75 | } | ||
| 76 | |||
| 77 | test "pass zero length array to var args param" { | ||
| 78 | doNothingWithFirstArg(.{""}); | ||
| 79 | } | ||
| 80 | |||
| 81 | fn doNothingWithFirstArg(args: anytype) void { | ||
| 82 | const a = args[0]; | ||
| 83 | } | ||
test/behavior/vector.zig created+640| ... | @@ -0,0 +1,640 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const math = std.math; | ||
| 5 | const expect = std.testing.expect; | ||
| 6 | const expectEqual = std.testing.expectEqual; | ||
| 7 | const expectApproxEqRel = std.testing.expectApproxEqRel; | ||
| 8 | const Vector = std.meta.Vector; | ||
| 9 | |||
| 10 | test "implicit cast vector to array - bool" { | ||
| 11 | const S = struct { | ||
| 12 | fn doTheTest() !void { | ||
| 13 | const a: Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 14 | const result_array: [4]bool = a; | ||
| 15 | try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false })); | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | try S.doTheTest(); | ||
| 19 | comptime try S.doTheTest(); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "vector wrap operators" { | ||
| 23 | const S = struct { | ||
| 24 | fn doTheTest() !void { | ||
| 25 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 26 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 27 | try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 })); | ||
| 28 | try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 })); | ||
| 29 | try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 })); | ||
| 30 | var z: Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 }; | ||
| 31 | try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 })); | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | try S.doTheTest(); | ||
| 35 | comptime try S.doTheTest(); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "vector bin compares with mem.eql" { | ||
| 39 | const S = struct { | ||
| 40 | fn doTheTest() !void { | ||
| 41 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 42 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 }; | ||
| 43 | try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false })); | ||
| 44 | try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true })); | ||
| 45 | try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false })); | ||
| 46 | try expect(mem.eql(bool, &@as([4]bool, v > x), &[4]bool{ true, false, false, true })); | ||
| 47 | try expect(mem.eql(bool, &@as([4]bool, v <= x), &[4]bool{ false, true, true, false })); | ||
| 48 | try expect(mem.eql(bool, &@as([4]bool, v >= x), &[4]bool{ true, false, true, true })); | ||
| 49 | } | ||
| 50 | }; | ||
| 51 | try S.doTheTest(); | ||
| 52 | comptime try S.doTheTest(); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "vector int operators" { | ||
| 56 | const S = struct { | ||
| 57 | fn doTheTest() !void { | ||
| 58 | var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; | ||
| 59 | var x: Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; | ||
| 60 | try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 })); | ||
| 61 | try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 })); | ||
| 62 | try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 })); | ||
| 63 | try expect(mem.eql(i32, &@as([4]i32, -v), &[4]i32{ -10, -20, -30, -40 })); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | try S.doTheTest(); | ||
| 67 | comptime try S.doTheTest(); | ||
| 68 | } | ||
| 69 | |||
| 70 | test "vector float operators" { | ||
| 71 | const S = struct { | ||
| 72 | fn doTheTest() !void { | ||
| 73 | var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; | ||
| 74 | var x: Vector(4, f32) = [4]f32{ 1, 2, 3, 4 }; | ||
| 75 | try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 })); | ||
| 76 | try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 })); | ||
| 77 | try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 })); | ||
| 78 | try expect(mem.eql(f32, &@as([4]f32, -x), &[4]f32{ -1, -2, -3, -4 })); | ||
| 79 | } | ||
| 80 | }; | ||
| 81 | try S.doTheTest(); | ||
| 82 | comptime try S.doTheTest(); | ||
| 83 | } | ||
| 84 | |||
| 85 | test "vector bit operators" { | ||
| 86 | const S = struct { | ||
| 87 | fn doTheTest() !void { | ||
| 88 | var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; | ||
| 89 | var x: Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; | ||
| 90 | try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); | ||
| 91 | try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); | ||
| 92 | try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); | ||
| 93 | } | ||
| 94 | }; | ||
| 95 | try S.doTheTest(); | ||
| 96 | comptime try S.doTheTest(); | ||
| 97 | } | ||
| 98 | |||
| 99 | test "implicit cast vector to array" { | ||
| 100 | const S = struct { | ||
| 101 | fn doTheTest() !void { | ||
| 102 | var a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; | ||
| 103 | var result_array: [4]i32 = a; | ||
| 104 | result_array = a; | ||
| 105 | try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 })); | ||
| 106 | } | ||
| 107 | }; | ||
| 108 | try S.doTheTest(); | ||
| 109 | comptime try S.doTheTest(); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "array to vector" { | ||
| 113 | var foo: f32 = 3.14; | ||
| 114 | var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; | ||
| 115 | var vec: Vector(4, f32) = arr; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "vector casts of sizes not divisable by 8" { | ||
| 119 | // https://github.com/ziglang/zig/issues/3563 | ||
| 120 | if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest; | ||
| 121 | |||
| 122 | const S = struct { | ||
| 123 | fn doTheTest() !void { | ||
| 124 | { | ||
| 125 | var v: Vector(4, u3) = [4]u3{ 5, 2, 3, 0 }; | ||
| 126 | var x: [4]u3 = v; | ||
| 127 | try expect(mem.eql(u3, &x, &@as([4]u3, v))); | ||
| 128 | } | ||
| 129 | { | ||
| 130 | var v: Vector(4, u2) = [4]u2{ 1, 2, 3, 0 }; | ||
| 131 | var x: [4]u2 = v; | ||
| 132 | try expect(mem.eql(u2, &x, &@as([4]u2, v))); | ||
| 133 | } | ||
| 134 | { | ||
| 135 | var v: Vector(4, u1) = [4]u1{ 1, 0, 1, 0 }; | ||
| 136 | var x: [4]u1 = v; | ||
| 137 | try expect(mem.eql(u1, &x, &@as([4]u1, v))); | ||
| 138 | } | ||
| 139 | { | ||
| 140 | var v: Vector(4, bool) = [4]bool{ false, false, true, false }; | ||
| 141 | var x: [4]bool = v; | ||
| 142 | try expect(mem.eql(bool, &x, &@as([4]bool, v))); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | try S.doTheTest(); | ||
| 147 | comptime try S.doTheTest(); | ||
| 148 | } | ||
| 149 | |||
| 150 | test "vector @splat" { | ||
| 151 | const S = struct { | ||
| 152 | fn testForT(comptime N: comptime_int, v: anytype) !void { | ||
| 153 | const T = @TypeOf(v); | ||
| 154 | var vec = @splat(N, v); | ||
| 155 | try expectEqual(Vector(N, T), @TypeOf(vec)); | ||
| 156 | var as_array = @as([N]T, vec); | ||
| 157 | for (as_array) |elem| try expectEqual(v, elem); | ||
| 158 | } | ||
| 159 | fn doTheTest() !void { | ||
| 160 | // Splats with multiple-of-8 bit types that fill a 128bit vector. | ||
| 161 | try testForT(16, @as(u8, 0xEE)); | ||
| 162 | try testForT(8, @as(u16, 0xBEEF)); | ||
| 163 | try testForT(4, @as(u32, 0xDEADBEEF)); | ||
| 164 | try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF)); | ||
| 165 | |||
| 166 | try testForT(8, @as(f16, 3.1415)); | ||
| 167 | try testForT(4, @as(f32, 3.1415)); | ||
| 168 | try testForT(2, @as(f64, 3.1415)); | ||
| 169 | |||
| 170 | // Same but fill more than 128 bits. | ||
| 171 | try testForT(16 * 2, @as(u8, 0xEE)); | ||
| 172 | try testForT(8 * 2, @as(u16, 0xBEEF)); | ||
| 173 | try testForT(4 * 2, @as(u32, 0xDEADBEEF)); | ||
| 174 | try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF)); | ||
| 175 | |||
| 176 | try testForT(8 * 2, @as(f16, 3.1415)); | ||
| 177 | try testForT(4 * 2, @as(f32, 3.1415)); | ||
| 178 | try testForT(2 * 2, @as(f64, 3.1415)); | ||
| 179 | } | ||
| 180 | }; | ||
| 181 | try S.doTheTest(); | ||
| 182 | comptime try S.doTheTest(); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "load vector elements via comptime index" { | ||
| 186 | const S = struct { | ||
| 187 | fn doTheTest() !void { | ||
| 188 | var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | ||
| 189 | try expect(v[0] == 1); | ||
| 190 | try expect(v[1] == 2); | ||
| 191 | try expect(loadv(&v[2]) == 3); | ||
| 192 | } | ||
| 193 | fn loadv(ptr: anytype) i32 { | ||
| 194 | return ptr.*; | ||
| 195 | } | ||
| 196 | }; | ||
| 197 | |||
| 198 | try S.doTheTest(); | ||
| 199 | comptime try S.doTheTest(); | ||
| 200 | } | ||
| 201 | |||
| 202 | test "store vector elements via comptime index" { | ||
| 203 | const S = struct { | ||
| 204 | fn doTheTest() !void { | ||
| 205 | var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | ||
| 206 | |||
| 207 | v[2] = 42; | ||
| 208 | try expect(v[1] == 5); | ||
| 209 | v[3] = -364; | ||
| 210 | try expect(v[2] == 42); | ||
| 211 | try expect(-364 == v[3]); | ||
| 212 | |||
| 213 | storev(&v[0], 100); | ||
| 214 | try expect(v[0] == 100); | ||
| 215 | } | ||
| 216 | fn storev(ptr: anytype, x: i32) void { | ||
| 217 | ptr.* = x; | ||
| 218 | } | ||
| 219 | }; | ||
| 220 | |||
| 221 | try S.doTheTest(); | ||
| 222 | comptime try S.doTheTest(); | ||
| 223 | } | ||
| 224 | |||
| 225 | test "load vector elements via runtime index" { | ||
| 226 | const S = struct { | ||
| 227 | fn doTheTest() !void { | ||
| 228 | var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | ||
| 229 | var i: u32 = 0; | ||
| 230 | try expect(v[i] == 1); | ||
| 231 | i += 1; | ||
| 232 | try expect(v[i] == 2); | ||
| 233 | i += 1; | ||
| 234 | try expect(v[i] == 3); | ||
| 235 | } | ||
| 236 | }; | ||
| 237 | |||
| 238 | try S.doTheTest(); | ||
| 239 | comptime try S.doTheTest(); | ||
| 240 | } | ||
| 241 | |||
| 242 | test "store vector elements via runtime index" { | ||
| 243 | const S = struct { | ||
| 244 | fn doTheTest() !void { | ||
| 245 | var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | ||
| 246 | var i: u32 = 2; | ||
| 247 | v[i] = 1; | ||
| 248 | try expect(v[1] == 5); | ||
| 249 | try expect(v[2] == 1); | ||
| 250 | i += 1; | ||
| 251 | v[i] = -364; | ||
| 252 | try expect(-364 == v[3]); | ||
| 253 | } | ||
| 254 | }; | ||
| 255 | |||
| 256 | try S.doTheTest(); | ||
| 257 | comptime try S.doTheTest(); | ||
| 258 | } | ||
| 259 | |||
| 260 | test "initialize vector which is a struct field" { | ||
| 261 | const Vec4Obj = struct { | ||
| 262 | data: Vector(4, f32), | ||
| 263 | }; | ||
| 264 | |||
| 265 | const S = struct { | ||
| 266 | fn doTheTest() !void { | ||
| 267 | var foo = Vec4Obj{ | ||
| 268 | .data = [_]f32{ 1, 2, 3, 4 }, | ||
| 269 | }; | ||
| 270 | } | ||
| 271 | }; | ||
| 272 | try S.doTheTest(); | ||
| 273 | comptime try S.doTheTest(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "vector comparison operators" { | ||
| 277 | const S = struct { | ||
| 278 | fn doTheTest() !void { | ||
| 279 | { | ||
| 280 | const v1: Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 281 | const v2: Vector(4, bool) = [_]bool{ false, true, false, true }; | ||
| 282 | try expectEqual(@splat(4, true), v1 == v1); | ||
| 283 | try expectEqual(@splat(4, false), v1 == v2); | ||
| 284 | try expectEqual(@splat(4, true), v1 != v2); | ||
| 285 | try expectEqual(@splat(4, false), v2 != v2); | ||
| 286 | } | ||
| 287 | { | ||
| 288 | const v1 = @splat(4, @as(u32, 0xc0ffeeee)); | ||
| 289 | const v2: Vector(4, c_uint) = v1; | ||
| 290 | const v3 = @splat(4, @as(u32, 0xdeadbeef)); | ||
| 291 | try expectEqual(@splat(4, true), v1 == v2); | ||
| 292 | try expectEqual(@splat(4, false), v1 == v3); | ||
| 293 | try expectEqual(@splat(4, true), v1 != v3); | ||
| 294 | try expectEqual(@splat(4, false), v1 != v2); | ||
| 295 | } | ||
| 296 | { | ||
| 297 | // Comptime-known LHS/RHS | ||
| 298 | var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 }; | ||
| 299 | const v2 = @splat(4, @as(u32, 2)); | ||
| 300 | const v3: @Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 301 | try expectEqual(v3, v1 == v2); | ||
| 302 | try expectEqual(v3, v2 == v1); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | }; | ||
| 306 | try S.doTheTest(); | ||
| 307 | comptime try S.doTheTest(); | ||
| 308 | } | ||
| 309 | |||
| 310 | test "vector division operators" { | ||
| 311 | const S = struct { | ||
| 312 | fn doTheTestDiv(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void { | ||
| 313 | if (!comptime std.meta.trait.isSignedInt(T)) { | ||
| 314 | const d0 = x / y; | ||
| 315 | for (@as([4]T, d0)) |v, i| { | ||
| 316 | try expectEqual(x[i] / y[i], v); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | const d1 = @divExact(x, y); | ||
| 320 | for (@as([4]T, d1)) |v, i| { | ||
| 321 | try expectEqual(@divExact(x[i], y[i]), v); | ||
| 322 | } | ||
| 323 | const d2 = @divFloor(x, y); | ||
| 324 | for (@as([4]T, d2)) |v, i| { | ||
| 325 | try expectEqual(@divFloor(x[i], y[i]), v); | ||
| 326 | } | ||
| 327 | const d3 = @divTrunc(x, y); | ||
| 328 | for (@as([4]T, d3)) |v, i| { | ||
| 329 | try expectEqual(@divTrunc(x[i], y[i]), v); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | fn doTheTestMod(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void { | ||
| 334 | if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) { | ||
| 335 | const r0 = x % y; | ||
| 336 | for (@as([4]T, r0)) |v, i| { | ||
| 337 | try expectEqual(x[i] % y[i], v); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | const r1 = @mod(x, y); | ||
| 341 | for (@as([4]T, r1)) |v, i| { | ||
| 342 | try expectEqual(@mod(x[i], y[i]), v); | ||
| 343 | } | ||
| 344 | const r2 = @rem(x, y); | ||
| 345 | for (@as([4]T, r2)) |v, i| { | ||
| 346 | try expectEqual(@rem(x[i], y[i]), v); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | fn doTheTest() !void { | ||
| 351 | // https://github.com/ziglang/zig/issues/4952 | ||
| 352 | if (builtin.target.os.tag != .windows) { | ||
| 353 | try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 354 | } | ||
| 355 | |||
| 356 | try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 357 | try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 358 | |||
| 359 | // https://github.com/ziglang/zig/issues/4952 | ||
| 360 | if (builtin.target.os.tag != .windows) { | ||
| 361 | try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 362 | } | ||
| 363 | try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 364 | try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 365 | |||
| 366 | try doTheTestDiv(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, -1, -2 }); | ||
| 367 | try doTheTestDiv(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, -1, -2 }); | ||
| 368 | try doTheTestDiv(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, -1, -2 }); | ||
| 369 | try doTheTestDiv(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, -1, -2 }); | ||
| 370 | |||
| 371 | try doTheTestMod(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, 4, 8 }); | ||
| 372 | try doTheTestMod(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, 4, 8 }); | ||
| 373 | try doTheTestMod(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, 4, 8 }); | ||
| 374 | try doTheTestMod(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, 4, 8 }); | ||
| 375 | |||
| 376 | try doTheTestDiv(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); | ||
| 377 | try doTheTestDiv(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); | ||
| 378 | try doTheTestDiv(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); | ||
| 379 | try doTheTestDiv(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); | ||
| 380 | |||
| 381 | try doTheTestMod(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); | ||
| 382 | try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); | ||
| 383 | try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); | ||
| 384 | try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); | ||
| 385 | } | ||
| 386 | }; | ||
| 387 | |||
| 388 | try S.doTheTest(); | ||
| 389 | comptime try S.doTheTest(); | ||
| 390 | } | ||
| 391 | |||
| 392 | test "vector bitwise not operator" { | ||
| 393 | const S = struct { | ||
| 394 | fn doTheTestNot(comptime T: type, x: Vector(4, T)) !void { | ||
| 395 | var y = ~x; | ||
| 396 | for (@as([4]T, y)) |v, i| { | ||
| 397 | try expectEqual(~x[i], v); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | fn doTheTest() !void { | ||
| 401 | try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); | ||
| 402 | try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); | ||
| 403 | try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); | ||
| 404 | try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); | ||
| 405 | |||
| 406 | try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); | ||
| 407 | try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); | ||
| 408 | try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); | ||
| 409 | try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | |||
| 413 | try S.doTheTest(); | ||
| 414 | comptime try S.doTheTest(); | ||
| 415 | } | ||
| 416 | |||
| 417 | test "vector shift operators" { | ||
| 418 | // TODO investigate why this fails when cross-compiled to wasm. | ||
| 419 | if (builtin.target.os.tag == .wasi) return error.SkipZigTest; | ||
| 420 | |||
| 421 | const S = struct { | ||
| 422 | fn doTheTestShift(x: anytype, y: anytype) !void { | ||
| 423 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 424 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 425 | const TY = @typeInfo(@TypeOf(y)).Array.child; | ||
| 426 | |||
| 427 | var xv = @as(Vector(N, TX), x); | ||
| 428 | var yv = @as(Vector(N, TY), y); | ||
| 429 | |||
| 430 | var z0 = xv >> yv; | ||
| 431 | for (@as([N]TX, z0)) |v, i| { | ||
| 432 | try expectEqual(x[i] >> y[i], v); | ||
| 433 | } | ||
| 434 | var z1 = xv << yv; | ||
| 435 | for (@as([N]TX, z1)) |v, i| { | ||
| 436 | try expectEqual(x[i] << y[i], v); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void { | ||
| 440 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 441 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 442 | const TY = @typeInfo(@TypeOf(y)).Array.child; | ||
| 443 | |||
| 444 | var xv = @as(Vector(N, TX), x); | ||
| 445 | var yv = @as(Vector(N, TY), y); | ||
| 446 | |||
| 447 | var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv); | ||
| 448 | for (@as([N]TX, z)) |v, i| { | ||
| 449 | const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i]; | ||
| 450 | try expectEqual(check, v); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | fn doTheTest() !void { | ||
| 454 | try doTheTestShift([_]u8{ 0, 2, 4, math.maxInt(u8) }, [_]u3{ 2, 0, 2, 7 }); | ||
| 455 | try doTheTestShift([_]u16{ 0, 2, 4, math.maxInt(u16) }, [_]u4{ 2, 0, 2, 15 }); | ||
| 456 | try doTheTestShift([_]u24{ 0, 2, 4, math.maxInt(u24) }, [_]u5{ 2, 0, 2, 23 }); | ||
| 457 | try doTheTestShift([_]u32{ 0, 2, 4, math.maxInt(u32) }, [_]u5{ 2, 0, 2, 31 }); | ||
| 458 | try doTheTestShift([_]u64{ 0xfe, math.maxInt(u64) }, [_]u6{ 0, 63 }); | ||
| 459 | |||
| 460 | try doTheTestShift([_]i8{ 0, 2, 4, math.maxInt(i8) }, [_]u3{ 2, 0, 2, 7 }); | ||
| 461 | try doTheTestShift([_]i16{ 0, 2, 4, math.maxInt(i16) }, [_]u4{ 2, 0, 2, 7 }); | ||
| 462 | try doTheTestShift([_]i24{ 0, 2, 4, math.maxInt(i24) }, [_]u5{ 2, 0, 2, 7 }); | ||
| 463 | try doTheTestShift([_]i32{ 0, 2, 4, math.maxInt(i32) }, [_]u5{ 2, 0, 2, 7 }); | ||
| 464 | try doTheTestShift([_]i64{ 0xfe, math.maxInt(i64) }, [_]u6{ 0, 63 }); | ||
| 465 | |||
| 466 | try doTheTestShiftExact([_]u8{ 0, 1, 1 << 7, math.maxInt(u8) ^ 1 }, [_]u3{ 4, 0, 7, 1 }, .Right); | ||
| 467 | try doTheTestShiftExact([_]u16{ 0, 1, 1 << 15, math.maxInt(u16) ^ 1 }, [_]u4{ 4, 0, 15, 1 }, .Right); | ||
| 468 | try doTheTestShiftExact([_]u24{ 0, 1, 1 << 23, math.maxInt(u24) ^ 1 }, [_]u5{ 4, 0, 23, 1 }, .Right); | ||
| 469 | try doTheTestShiftExact([_]u32{ 0, 1, 1 << 31, math.maxInt(u32) ^ 1 }, [_]u5{ 4, 0, 31, 1 }, .Right); | ||
| 470 | try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 63, 0 }, .Right); | ||
| 471 | |||
| 472 | try doTheTestShiftExact([_]u8{ 0, 1, 1, math.maxInt(u8) ^ (1 << 7) }, [_]u3{ 4, 0, 7, 1 }, .Left); | ||
| 473 | try doTheTestShiftExact([_]u16{ 0, 1, 1, math.maxInt(u16) ^ (1 << 15) }, [_]u4{ 4, 0, 15, 1 }, .Left); | ||
| 474 | try doTheTestShiftExact([_]u24{ 0, 1, 1, math.maxInt(u24) ^ (1 << 23) }, [_]u5{ 4, 0, 23, 1 }, .Left); | ||
| 475 | try doTheTestShiftExact([_]u32{ 0, 1, 1, math.maxInt(u32) ^ (1 << 31) }, [_]u5{ 4, 0, 31, 1 }, .Left); | ||
| 476 | try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 0, 63 }, .Left); | ||
| 477 | } | ||
| 478 | }; | ||
| 479 | |||
| 480 | switch (builtin.target.cpu.arch) { | ||
| 481 | .i386, | ||
| 482 | .aarch64, | ||
| 483 | .aarch64_be, | ||
| 484 | .aarch64_32, | ||
| 485 | .arm, | ||
| 486 | .armeb, | ||
| 487 | .thumb, | ||
| 488 | .thumbeb, | ||
| 489 | .mips, | ||
| 490 | .mipsel, | ||
| 491 | .mips64, | ||
| 492 | .mips64el, | ||
| 493 | .riscv64, | ||
| 494 | .sparcv9, | ||
| 495 | => { | ||
| 496 | // LLVM miscompiles on this architecture | ||
| 497 | // https://github.com/ziglang/zig/issues/4951 | ||
| 498 | return error.SkipZigTest; | ||
| 499 | }, | ||
| 500 | else => {}, | ||
| 501 | } | ||
| 502 | |||
| 503 | try S.doTheTest(); | ||
| 504 | comptime try S.doTheTest(); | ||
| 505 | } | ||
| 506 | |||
| 507 | test "vector reduce operation" { | ||
| 508 | const S = struct { | ||
| 509 | fn doTheTestReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { | ||
| 510 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 511 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 512 | |||
| 513 | var r = @reduce(op, @as(Vector(N, TX), x)); | ||
| 514 | switch (@typeInfo(TX)) { | ||
| 515 | .Int, .Bool => try expectEqual(expected, r), | ||
| 516 | .Float => { | ||
| 517 | const expected_nan = math.isNan(expected); | ||
| 518 | const got_nan = math.isNan(r); | ||
| 519 | |||
| 520 | if (expected_nan and got_nan) { | ||
| 521 | // Do this check explicitly as two NaN values are never | ||
| 522 | // equal. | ||
| 523 | } else { | ||
| 524 | try expectApproxEqRel(expected, r, math.sqrt(math.epsilon(TX))); | ||
| 525 | } | ||
| 526 | }, | ||
| 527 | else => unreachable, | ||
| 528 | } | ||
| 529 | } | ||
| 530 | fn doTheTest() !void { | ||
| 531 | try doTheTestReduce(.Add, [4]i16{ -9, -99, -999, -9999 }, @as(i32, -11106)); | ||
| 532 | try doTheTestReduce(.Add, [4]u16{ 9, 99, 999, 9999 }, @as(u32, 11106)); | ||
| 533 | try doTheTestReduce(.Add, [4]i32{ -9, -99, -999, -9999 }, @as(i32, -11106)); | ||
| 534 | try doTheTestReduce(.Add, [4]u32{ 9, 99, 999, 9999 }, @as(u32, 11106)); | ||
| 535 | try doTheTestReduce(.Add, [4]i64{ -9, -99, -999, -9999 }, @as(i64, -11106)); | ||
| 536 | try doTheTestReduce(.Add, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 11106)); | ||
| 537 | try doTheTestReduce(.Add, [4]i128{ -9, -99, -999, -9999 }, @as(i128, -11106)); | ||
| 538 | try doTheTestReduce(.Add, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 11106)); | ||
| 539 | try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9)); | ||
| 540 | try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9)); | ||
| 541 | try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9)); | ||
| 542 | |||
| 543 | try doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false)); | ||
| 544 | try doTheTestReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0)); | ||
| 545 | try doTheTestReduce(.And, [4]u16{ 0xffff, 0xff55, 0xaaff, 0x1010 }, @as(u16, 0x10)); | ||
| 546 | try doTheTestReduce(.And, [4]u32{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u32, 0x1010)); | ||
| 547 | try doTheTestReduce(.And, [4]u64{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u64, 0x1010)); | ||
| 548 | |||
| 549 | try doTheTestReduce(.Min, [4]i16{ -1, 2, 3, 4 }, @as(i16, -1)); | ||
| 550 | try doTheTestReduce(.Min, [4]u16{ 1, 2, 3, 4 }, @as(u16, 1)); | ||
| 551 | try doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386)); | ||
| 552 | try doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9)); | ||
| 553 | |||
| 554 | // LLVM 11 ERROR: Cannot select type | ||
| 555 | // https://github.com/ziglang/zig/issues/7138 | ||
| 556 | if (builtin.target.cpu.arch != .aarch64) { | ||
| 557 | try doTheTestReduce(.Min, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, -386)); | ||
| 558 | try doTheTestReduce(.Min, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 9)); | ||
| 559 | } | ||
| 560 | |||
| 561 | try doTheTestReduce(.Min, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, -386)); | ||
| 562 | try doTheTestReduce(.Min, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 9)); | ||
| 563 | try doTheTestReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0)); | ||
| 564 | try doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0)); | ||
| 565 | try doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0)); | ||
| 566 | |||
| 567 | try doTheTestReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4)); | ||
| 568 | try doTheTestReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4)); | ||
| 569 | try doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567)); | ||
| 570 | try doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999)); | ||
| 571 | |||
| 572 | // LLVM 11 ERROR: Cannot select type | ||
| 573 | // https://github.com/ziglang/zig/issues/7138 | ||
| 574 | if (builtin.target.cpu.arch != .aarch64) { | ||
| 575 | try doTheTestReduce(.Max, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, 1234567)); | ||
| 576 | try doTheTestReduce(.Max, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 99999)); | ||
| 577 | } | ||
| 578 | |||
| 579 | try doTheTestReduce(.Max, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, 1234567)); | ||
| 580 | try doTheTestReduce(.Max, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 99999)); | ||
| 581 | try doTheTestReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9)); | ||
| 582 | try doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9)); | ||
| 583 | try doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9)); | ||
| 584 | |||
| 585 | try doTheTestReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24)); | ||
| 586 | try doTheTestReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24)); | ||
| 587 | try doTheTestReduce(.Mul, [4]i32{ -9, -99, -999, 999 }, @as(i32, -889218891)); | ||
| 588 | try doTheTestReduce(.Mul, [4]u32{ 1, 2, 3, 4 }, @as(u32, 24)); | ||
| 589 | try doTheTestReduce(.Mul, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 8900199891)); | ||
| 590 | try doTheTestReduce(.Mul, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 8900199891)); | ||
| 591 | try doTheTestReduce(.Mul, [4]i128{ -9, -99, -999, 9999 }, @as(i128, -8900199891)); | ||
| 592 | try doTheTestReduce(.Mul, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 8900199891)); | ||
| 593 | try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7)); | ||
| 594 | try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7)); | ||
| 595 | try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7)); | ||
| 596 | |||
| 597 | try doTheTestReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true)); | ||
| 598 | try doTheTestReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1)); | ||
| 599 | try doTheTestReduce(.Or, [4]u16{ 0xff00, 0xff00, 0xf0, 0xf }, ~@as(u16, 0)); | ||
| 600 | try doTheTestReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0)); | ||
| 601 | try doTheTestReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff)); | ||
| 602 | try doTheTestReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff)); | ||
| 603 | |||
| 604 | try doTheTestReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true)); | ||
| 605 | try doTheTestReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1)); | ||
| 606 | try doTheTestReduce(.Xor, [4]u16{ 0x0000, 0x3333, 0x8888, 0x4444 }, ~@as(u16, 0)); | ||
| 607 | try doTheTestReduce(.Xor, [4]u32{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, ~@as(u32, 0)); | ||
| 608 | try doTheTestReduce(.Xor, [4]u64{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u64, 0xffffffff)); | ||
| 609 | try doTheTestReduce(.Xor, [4]u128{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u128, 0xffffffff)); | ||
| 610 | |||
| 611 | // Test the reduction on vectors containing NaNs. | ||
| 612 | const f16_nan = math.nan(f16); | ||
| 613 | const f32_nan = math.nan(f32); | ||
| 614 | const f64_nan = math.nan(f64); | ||
| 615 | |||
| 616 | try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 617 | try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 618 | try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 619 | |||
| 620 | // LLVM 11 ERROR: Cannot select type | ||
| 621 | // https://github.com/ziglang/zig/issues/7138 | ||
| 622 | if (false) { | ||
| 623 | try doTheTestReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 624 | try doTheTestReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 625 | try doTheTestReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 626 | |||
| 627 | try doTheTestReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 628 | try doTheTestReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 629 | try doTheTestReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 630 | } | ||
| 631 | |||
| 632 | try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 633 | try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 634 | try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 635 | } | ||
| 636 | }; | ||
| 637 | |||
| 638 | try S.doTheTest(); | ||
| 639 | comptime try S.doTheTest(); | ||
| 640 | } | ||
test/behavior/void.zig created+40| ... | @@ -0,0 +1,40 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: void, | ||
| 5 | b: i32, | ||
| 6 | c: void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "compare void with void compile time known" { | ||
| 10 | comptime { | ||
| 11 | const foo = Foo{ | ||
| 12 | .a = {}, | ||
| 13 | .b = 1, | ||
| 14 | .c = {}, | ||
| 15 | }; | ||
| 16 | try expect(foo.a == {}); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "iterate over a void slice" { | ||
| 21 | var j: usize = 0; | ||
| 22 | for (times(10)) |_, i| { | ||
| 23 | try expect(i == j); | ||
| 24 | j += 1; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | fn times(n: usize) []const void { | ||
| 29 | return @as([*]void, undefined)[0..n]; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "void optional" { | ||
| 33 | var x: ?void = {}; | ||
| 34 | try expect(x != null); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "void array as a local variable initializer" { | ||
| 38 | var x = [_]void{{}} ** 1004; | ||
| 39 | var y = x[0]; | ||
| 40 | } | ||
test/behavior/wasm.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "memory size and grow" { | ||
| 5 | var prev = @wasmMemorySize(0); | ||
| 6 | try expect(prev == @wasmMemoryGrow(0, 1)); | ||
| 7 | try expect(prev + 1 == @wasmMemorySize(0)); | ||
| 8 | } | ||
test/behavior/while.zig created+283| ... | @@ -0,0 +1,283 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "while loop" { | ||
| 5 | var i: i32 = 0; | ||
| 6 | while (i < 4) { | ||
| 7 | i += 1; | ||
| 8 | } | ||
| 9 | try expect(i == 4); | ||
| 10 | try expect(whileLoop1() == 1); | ||
| 11 | } | ||
| 12 | fn whileLoop1() i32 { | ||
| 13 | return whileLoop2(); | ||
| 14 | } | ||
| 15 | fn whileLoop2() i32 { | ||
| 16 | while (true) { | ||
| 17 | return 1; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | test "static eval while" { | ||
| 22 | try expect(static_eval_while_number == 1); | ||
| 23 | } | ||
| 24 | const static_eval_while_number = staticWhileLoop1(); | ||
| 25 | fn staticWhileLoop1() i32 { | ||
| 26 | return whileLoop2(); | ||
| 27 | } | ||
| 28 | fn staticWhileLoop2() i32 { | ||
| 29 | while (true) { | ||
| 30 | return 1; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | test "continue and break" { | ||
| 35 | try runContinueAndBreakTest(); | ||
| 36 | try expect(continue_and_break_counter == 8); | ||
| 37 | } | ||
| 38 | var continue_and_break_counter: i32 = 0; | ||
| 39 | fn runContinueAndBreakTest() !void { | ||
| 40 | var i: i32 = 0; | ||
| 41 | while (true) { | ||
| 42 | continue_and_break_counter += 2; | ||
| 43 | i += 1; | ||
| 44 | if (i < 4) { | ||
| 45 | continue; | ||
| 46 | } | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | try expect(i == 4); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "return with implicit cast from while loop" { | ||
| 53 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | ||
| 54 | } | ||
| 55 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | ||
| 56 | while (true) { | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "while with continue expression" { | ||
| 62 | var sum: i32 = 0; | ||
| 63 | { | ||
| 64 | var i: i32 = 0; | ||
| 65 | while (i < 10) : (i += 1) { | ||
| 66 | if (i == 5) continue; | ||
| 67 | sum += i; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | try expect(sum == 40); | ||
| 71 | } | ||
| 72 | |||
| 73 | test "while with else" { | ||
| 74 | var sum: i32 = 0; | ||
| 75 | var i: i32 = 0; | ||
| 76 | var got_else: i32 = 0; | ||
| 77 | while (i < 10) : (i += 1) { | ||
| 78 | sum += 1; | ||
| 79 | } else { | ||
| 80 | got_else += 1; | ||
| 81 | } | ||
| 82 | try expect(sum == 10); | ||
| 83 | try expect(got_else == 1); | ||
| 84 | } | ||
| 85 | |||
| 86 | test "while with optional as condition" { | ||
| 87 | numbers_left = 10; | ||
| 88 | var sum: i32 = 0; | ||
| 89 | while (getNumberOrNull()) |value| { | ||
| 90 | sum += value; | ||
| 91 | } | ||
| 92 | try expect(sum == 45); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "while with optional as condition with else" { | ||
| 96 | numbers_left = 10; | ||
| 97 | var sum: i32 = 0; | ||
| 98 | var got_else: i32 = 0; | ||
| 99 | while (getNumberOrNull()) |value| { | ||
| 100 | sum += value; | ||
| 101 | try expect(got_else == 0); | ||
| 102 | } else { | ||
| 103 | got_else += 1; | ||
| 104 | } | ||
| 105 | try expect(sum == 45); | ||
| 106 | try expect(got_else == 1); | ||
| 107 | } | ||
| 108 | |||
| 109 | test "while with error union condition" { | ||
| 110 | numbers_left = 10; | ||
| 111 | var sum: i32 = 0; | ||
| 112 | var got_else: i32 = 0; | ||
| 113 | while (getNumberOrErr()) |value| { | ||
| 114 | sum += value; | ||
| 115 | } else |err| { | ||
| 116 | try expect(err == error.OutOfNumbers); | ||
| 117 | got_else += 1; | ||
| 118 | } | ||
| 119 | try expect(sum == 45); | ||
| 120 | try expect(got_else == 1); | ||
| 121 | } | ||
| 122 | |||
| 123 | var numbers_left: i32 = undefined; | ||
| 124 | fn getNumberOrErr() anyerror!i32 { | ||
| 125 | return if (numbers_left == 0) error.OutOfNumbers else x: { | ||
| 126 | numbers_left -= 1; | ||
| 127 | break :x numbers_left; | ||
| 128 | }; | ||
| 129 | } | ||
| 130 | fn getNumberOrNull() ?i32 { | ||
| 131 | return if (numbers_left == 0) null else x: { | ||
| 132 | numbers_left -= 1; | ||
| 133 | break :x numbers_left; | ||
| 134 | }; | ||
| 135 | } | ||
| 136 | |||
| 137 | test "while on optional with else result follow else prong" { | ||
| 138 | const result = while (returnNull()) |value| { | ||
| 139 | break value; | ||
| 140 | } else @as(i32, 2); | ||
| 141 | try expect(result == 2); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "while on optional with else result follow break prong" { | ||
| 145 | const result = while (returnOptional(10)) |value| { | ||
| 146 | break value; | ||
| 147 | } else @as(i32, 2); | ||
| 148 | try expect(result == 10); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "while on error union with else result follow else prong" { | ||
| 152 | const result = while (returnError()) |value| { | ||
| 153 | break value; | ||
| 154 | } else |err| @as(i32, 2); | ||
| 155 | try expect(result == 2); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "while on error union with else result follow break prong" { | ||
| 159 | const result = while (returnSuccess(10)) |value| { | ||
| 160 | break value; | ||
| 161 | } else |err| @as(i32, 2); | ||
| 162 | try expect(result == 10); | ||
| 163 | } | ||
| 164 | |||
| 165 | test "while on bool with else result follow else prong" { | ||
| 166 | const result = while (returnFalse()) { | ||
| 167 | break @as(i32, 10); | ||
| 168 | } else @as(i32, 2); | ||
| 169 | try expect(result == 2); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "while on bool with else result follow break prong" { | ||
| 173 | const result = while (returnTrue()) { | ||
| 174 | break @as(i32, 10); | ||
| 175 | } else @as(i32, 2); | ||
| 176 | try expect(result == 10); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "break from outer while loop" { | ||
| 180 | testBreakOuter(); | ||
| 181 | comptime testBreakOuter(); | ||
| 182 | } | ||
| 183 | |||
| 184 | fn testBreakOuter() void { | ||
| 185 | outer: while (true) { | ||
| 186 | while (true) { | ||
| 187 | break :outer; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | test "continue outer while loop" { | ||
| 193 | testContinueOuter(); | ||
| 194 | comptime testContinueOuter(); | ||
| 195 | } | ||
| 196 | |||
| 197 | fn testContinueOuter() void { | ||
| 198 | var i: usize = 0; | ||
| 199 | outer: while (i < 10) : (i += 1) { | ||
| 200 | while (true) { | ||
| 201 | continue :outer; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | fn returnNull() ?i32 { | ||
| 207 | return null; | ||
| 208 | } | ||
| 209 | fn returnOptional(x: i32) ?i32 { | ||
| 210 | return x; | ||
| 211 | } | ||
| 212 | fn returnError() anyerror!i32 { | ||
| 213 | return error.YouWantedAnError; | ||
| 214 | } | ||
| 215 | fn returnSuccess(x: i32) anyerror!i32 { | ||
| 216 | return x; | ||
| 217 | } | ||
| 218 | fn returnFalse() bool { | ||
| 219 | return false; | ||
| 220 | } | ||
| 221 | fn returnTrue() bool { | ||
| 222 | return true; | ||
| 223 | } | ||
| 224 | |||
| 225 | test "while bool 2 break statements and an else" { | ||
| 226 | const S = struct { | ||
| 227 | fn entry(t: bool, f: bool) !void { | ||
| 228 | var ok = false; | ||
| 229 | ok = while (t) { | ||
| 230 | if (f) break false; | ||
| 231 | if (t) break true; | ||
| 232 | } else false; | ||
| 233 | try expect(ok); | ||
| 234 | } | ||
| 235 | }; | ||
| 236 | try S.entry(true, false); | ||
| 237 | comptime try S.entry(true, false); | ||
| 238 | } | ||
| 239 | |||
| 240 | test "while optional 2 break statements and an else" { | ||
| 241 | const S = struct { | ||
| 242 | fn entry(opt_t: ?bool, f: bool) !void { | ||
| 243 | var ok = false; | ||
| 244 | ok = while (opt_t) |t| { | ||
| 245 | if (f) break false; | ||
| 246 | if (t) break true; | ||
| 247 | } else false; | ||
| 248 | try expect(ok); | ||
| 249 | } | ||
| 250 | }; | ||
| 251 | try S.entry(true, false); | ||
| 252 | comptime try S.entry(true, false); | ||
| 253 | } | ||
| 254 | |||
| 255 | test "while error 2 break statements and an else" { | ||
| 256 | const S = struct { | ||
| 257 | fn entry(opt_t: anyerror!bool, f: bool) !void { | ||
| 258 | var ok = false; | ||
| 259 | ok = while (opt_t) |t| { | ||
| 260 | if (f) break false; | ||
| 261 | if (t) break true; | ||
| 262 | } else |_| false; | ||
| 263 | try expect(ok); | ||
| 264 | } | ||
| 265 | }; | ||
| 266 | try S.entry(true, false); | ||
| 267 | comptime try S.entry(true, false); | ||
| 268 | } | ||
| 269 | |||
| 270 | test "while copies its payload" { | ||
| 271 | const S = struct { | ||
| 272 | fn doTheTest() !void { | ||
| 273 | var tmp: ?i32 = 10; | ||
| 274 | while (tmp) |value| { | ||
| 275 | // Modify the original variable | ||
| 276 | tmp = null; | ||
| 277 | try expect(value == 10); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | }; | ||
| 281 | try S.doTheTest(); | ||
| 282 | comptime try S.doTheTest(); | ||
| 283 | } | ||
test/behavior/widening.zig created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "integer widening" { | ||
| 6 | var a: u8 = 250; | ||
| 7 | var b: u16 = a; | ||
| 8 | var c: u32 = b; | ||
| 9 | var d: u64 = c; | ||
| 10 | var e: u64 = d; | ||
| 11 | var f: u128 = e; | ||
| 12 | try expect(f == a); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "implicit unsigned integer to signed integer" { | ||
| 16 | var a: u8 = 250; | ||
| 17 | var b: i16 = a; | ||
| 18 | try expect(b == 250); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "float widening" { | ||
| 22 | var a: f16 = 12.34; | ||
| 23 | var b: f32 = a; | ||
| 24 | var c: f64 = b; | ||
| 25 | var d: f128 = c; | ||
| 26 | try expect(a == b); | ||
| 27 | try expect(b == c); | ||
| 28 | try expect(c == d); | ||
| 29 | } | ||
| 30 | |||
| 31 | test "float widening f16 to f128" { | ||
| 32 | // TODO https://github.com/ziglang/zig/issues/3282 | ||
| 33 | if (@import("builtin").target.cpu.arch == .aarch64) return error.SkipZigTest; | ||
| 34 | if (@import("builtin").target.cpu.arch == .powerpc64le) return error.SkipZigTest; | ||
| 35 | |||
| 36 | var x: f16 = 12.34; | ||
| 37 | var y: f128 = x; | ||
| 38 | try expect(x == y); | ||
| 39 | } | ||
test/cli.zig+1-1| ... | @@ -115,7 +115,7 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { | ... | @@ -115,7 +115,7 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { |
| 115 | \\ return num * num; | 115 | \\ return num * num; |
| 116 | \\} | 116 | \\} |
| 117 | \\extern fn zig_panic() noreturn; | 117 | \\extern fn zig_panic() noreturn; |
| 118 | \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("builtin").StackTrace) noreturn { | 118 | \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace) noreturn { |
| 119 | \\ zig_panic(); | 119 | \\ zig_panic(); |
| 120 | \\} | 120 | \\} |
| 121 | ); | 121 | ); |
test/compile_errors.zig+24-24| ... | @@ -208,7 +208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -208,7 +208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 208 | }); | 208 | }); |
| 209 | 209 | ||
| 210 | cases.add("@Type with TypeInfo.Int", | 210 | cases.add("@Type with TypeInfo.Int", |
| 211 | \\const builtin = @import("builtin"); | 211 | \\const builtin = @import("std").builtin; |
| 212 | \\export fn entry() void { | 212 | \\export fn entry() void { |
| 213 | \\ _ = @Type(builtin.TypeInfo.Int { | 213 | \\ _ = @Type(builtin.TypeInfo.Int { |
| 214 | \\ .signedness = .signed, | 214 | \\ .signedness = .signed, |
| ... | @@ -242,7 +242,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -242,7 +242,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 242 | }); | 242 | }); |
| 243 | 243 | ||
| 244 | cases.add("@Type for exhaustive enum with undefined tag type", | 244 | cases.add("@Type for exhaustive enum with undefined tag type", |
| 245 | \\const TypeInfo = @import("builtin").TypeInfo; | 245 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 246 | \\const Tag = @Type(.{ | 246 | \\const Tag = @Type(.{ |
| 247 | \\ .Enum = .{ | 247 | \\ .Enum = .{ |
| 248 | \\ .layout = .Auto, | 248 | \\ .layout = .Auto, |
| ... | @@ -272,7 +272,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -272,7 +272,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 272 | }); | 272 | }); |
| 273 | 273 | ||
| 274 | cases.add("@Type for exhaustive enum with non-integer tag type", | 274 | cases.add("@Type for exhaustive enum with non-integer tag type", |
| 275 | \\const TypeInfo = @import("builtin").TypeInfo; | 275 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 276 | \\const Tag = @Type(.{ | 276 | \\const Tag = @Type(.{ |
| 277 | \\ .Enum = .{ | 277 | \\ .Enum = .{ |
| 278 | \\ .layout = .Auto, | 278 | \\ .layout = .Auto, |
| ... | @@ -331,7 +331,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -331,7 +331,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 331 | }); | 331 | }); |
| 332 | 332 | ||
| 333 | cases.add("@Type for tagged union with extra enum field", | 333 | cases.add("@Type for tagged union with extra enum field", |
| 334 | \\const TypeInfo = @import("builtin").TypeInfo; | 334 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 335 | \\const Tag = @Type(.{ | 335 | \\const Tag = @Type(.{ |
| 336 | \\ .Enum = .{ | 336 | \\ .Enum = .{ |
| 337 | \\ .layout = .Auto, | 337 | \\ .layout = .Auto, |
| ... | @@ -397,7 +397,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -397,7 +397,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 397 | \\ .is_generic = true, | 397 | \\ .is_generic = true, |
| 398 | \\ .is_var_args = false, | 398 | \\ .is_var_args = false, |
| 399 | \\ .return_type = u0, | 399 | \\ .return_type = u0, |
| 400 | \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, | 400 | \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, |
| 401 | \\ }, | 401 | \\ }, |
| 402 | \\}); | 402 | \\}); |
| 403 | \\comptime { _ = Foo; } | 403 | \\comptime { _ = Foo; } |
| ... | @@ -413,7 +413,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -413,7 +413,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 413 | \\ .is_generic = false, | 413 | \\ .is_generic = false, |
| 414 | \\ .is_var_args = true, | 414 | \\ .is_var_args = true, |
| 415 | \\ .return_type = u0, | 415 | \\ .return_type = u0, |
| 416 | \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, | 416 | \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, |
| 417 | \\ }, | 417 | \\ }, |
| 418 | \\}); | 418 | \\}); |
| 419 | \\comptime { _ = Foo; } | 419 | \\comptime { _ = Foo; } |
| ... | @@ -429,7 +429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -429,7 +429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 429 | \\ .is_generic = false, | 429 | \\ .is_generic = false, |
| 430 | \\ .is_var_args = false, | 430 | \\ .is_var_args = false, |
| 431 | \\ .return_type = null, | 431 | \\ .return_type = null, |
| 432 | \\ .args = &[_]@import("builtin").TypeInfo.FnArg{}, | 432 | \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, |
| 433 | \\ }, | 433 | \\ }, |
| 434 | \\}); | 434 | \\}); |
| 435 | \\comptime { _ = Foo; } | 435 | \\comptime { _ = Foo; } |
| ... | @@ -438,7 +438,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -438,7 +438,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 438 | }); | 438 | }); |
| 439 | 439 | ||
| 440 | cases.add("@Type for union with opaque field", | 440 | cases.add("@Type for union with opaque field", |
| 441 | \\const TypeInfo = @import("builtin").TypeInfo; | 441 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 442 | \\const Untagged = @Type(.{ | 442 | \\const Untagged = @Type(.{ |
| 443 | \\ .Union = .{ | 443 | \\ .Union = .{ |
| 444 | \\ .layout = .Auto, | 444 | \\ .layout = .Auto, |
| ... | @@ -474,7 +474,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -474,7 +474,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 474 | }); | 474 | }); |
| 475 | 475 | ||
| 476 | cases.add("@Type for union with zero fields", | 476 | cases.add("@Type for union with zero fields", |
| 477 | \\const TypeInfo = @import("builtin").TypeInfo; | 477 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 478 | \\const Untagged = @Type(.{ | 478 | \\const Untagged = @Type(.{ |
| 479 | \\ .Union = .{ | 479 | \\ .Union = .{ |
| 480 | \\ .layout = .Auto, | 480 | \\ .layout = .Auto, |
| ... | @@ -492,7 +492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -492,7 +492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 492 | }); | 492 | }); |
| 493 | 493 | ||
| 494 | cases.add("@Type for exhaustive enum with zero fields", | 494 | cases.add("@Type for exhaustive enum with zero fields", |
| 495 | \\const TypeInfo = @import("builtin").TypeInfo; | 495 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 496 | \\const Tag = @Type(.{ | 496 | \\const Tag = @Type(.{ |
| 497 | \\ .Enum = .{ | 497 | \\ .Enum = .{ |
| 498 | \\ .layout = .Auto, | 498 | \\ .layout = .Auto, |
| ... | @@ -511,7 +511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -511,7 +511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 511 | }); | 511 | }); |
| 512 | 512 | ||
| 513 | cases.add("@Type for tagged union with extra union field", | 513 | cases.add("@Type for tagged union with extra union field", |
| 514 | \\const TypeInfo = @import("builtin").TypeInfo; | 514 | \\const TypeInfo = @import("std").builtin.TypeInfo; |
| 515 | \\const Tag = @Type(.{ | 515 | \\const Tag = @Type(.{ |
| 516 | \\ .Enum = .{ | 516 | \\ .Enum = .{ |
| 517 | \\ .layout = .Auto, | 517 | \\ .layout = .Auto, |
| ... | @@ -1946,7 +1946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1946,7 +1946,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1946 | }); | 1946 | }); |
| 1947 | 1947 | ||
| 1948 | cases.add("attempt to create 17 bit float type", | 1948 | cases.add("attempt to create 17 bit float type", |
| 1949 | \\const builtin = @import("builtin"); | 1949 | \\const builtin = @import("std").builtin; |
| 1950 | \\comptime { | 1950 | \\comptime { |
| 1951 | \\ _ = @Type(builtin.TypeInfo { .Float = builtin.TypeInfo.Float { .bits = 17 } }); | 1951 | \\ _ = @Type(builtin.TypeInfo { .Float = builtin.TypeInfo.Float { .bits = 17 } }); |
| 1952 | \\} | 1952 | \\} |
| ... | @@ -1963,7 +1963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1963,7 +1963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1963 | }); | 1963 | }); |
| 1964 | 1964 | ||
| 1965 | cases.add("@Type with non-constant expression", | 1965 | cases.add("@Type with non-constant expression", |
| 1966 | \\const builtin = @import("builtin"); | 1966 | \\const builtin = @import("std").builtin; |
| 1967 | \\var globalTypeInfo : builtin.TypeInfo = undefined; | 1967 | \\var globalTypeInfo : builtin.TypeInfo = undefined; |
| 1968 | \\export fn entry() void { | 1968 | \\export fn entry() void { |
| 1969 | \\ _ = @Type(globalTypeInfo); | 1969 | \\ _ = @Type(globalTypeInfo); |
| ... | @@ -5963,7 +5963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5963,7 +5963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5963 | }); | 5963 | }); |
| 5964 | 5964 | ||
| 5965 | cases.add("atomic orderings of cmpxchg - failure stricter than success", | 5965 | cases.add("atomic orderings of cmpxchg - failure stricter than success", |
| 5966 | \\const AtomicOrder = @import("builtin").AtomicOrder; | 5966 | \\const AtomicOrder = @import("std").builtin.AtomicOrder; |
| 5967 | \\export fn f() void { | 5967 | \\export fn f() void { |
| 5968 | \\ var x: i32 = 1234; | 5968 | \\ var x: i32 = 1234; |
| 5969 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} | 5969 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} |
| ... | @@ -5973,7 +5973,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5973,7 +5973,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5973 | }); | 5973 | }); |
| 5974 | 5974 | ||
| 5975 | cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", | 5975 | cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", |
| 5976 | \\const AtomicOrder = @import("builtin").AtomicOrder; | 5976 | \\const AtomicOrder = @import("std").builtin.AtomicOrder; |
| 5977 | \\export fn f() void { | 5977 | \\export fn f() void { |
| 5978 | \\ var x: i32 = 1234; | 5978 | \\ var x: i32 = 1234; |
| 5979 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} | 5979 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} |
| ... | @@ -6579,12 +6579,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -6579,12 +6579,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6579 | }); | 6579 | }); |
| 6580 | 6580 | ||
| 6581 | cases.add("invalid member of builtin enum", | 6581 | cases.add("invalid member of builtin enum", |
| 6582 | \\const builtin = @import("builtin",); | 6582 | \\const builtin = @import("std").builtin; |
| 6583 | \\export fn entry() void { | 6583 | \\export fn entry() void { |
| 6584 | \\ const foo = builtin.Arch.x86; | 6584 | \\ const foo = builtin.Mode.x86; |
| 6585 | \\} | 6585 | \\} |
| 6586 | , &[_][]const u8{ | 6586 | , &[_][]const u8{ |
| 6587 | "tmp.zig:3:29: error: container 'std.target.Arch' has no member called 'x86'", | 6587 | "tmp.zig:3:29: error: container 'std.builtin.Mode' has no member called 'x86'", |
| 6588 | }); | 6588 | }); |
| 6589 | 6589 | ||
| 6590 | cases.add("int to ptr of 0 bits", | 6590 | cases.add("int to ptr of 0 bits", |
| ... | @@ -6853,8 +6853,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -6853,8 +6853,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6853 | 6853 | ||
| 6854 | cases.add("@setFloatMode twice for same scope", | 6854 | cases.add("@setFloatMode twice for same scope", |
| 6855 | \\export fn foo() void { | 6855 | \\export fn foo() void { |
| 6856 | \\ @setFloatMode(@import("builtin").FloatMode.Optimized); | 6856 | \\ @setFloatMode(@import("std").builtin.FloatMode.Optimized); |
| 6857 | \\ @setFloatMode(@import("builtin").FloatMode.Optimized); | 6857 | \\ @setFloatMode(@import("std").builtin.FloatMode.Optimized); |
| 6858 | \\} | 6858 | \\} |
| 6859 | , &[_][]const u8{ | 6859 | , &[_][]const u8{ |
| 6860 | "tmp.zig:3:5: error: float mode set twice for same scope", | 6860 | "tmp.zig:3:5: error: float mode set twice for same scope", |
| ... | @@ -7066,7 +7066,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7066,7 +7066,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7066 | }); | 7066 | }); |
| 7067 | 7067 | ||
| 7068 | cases.add("passing a not-aligned-enough pointer to cmpxchg", | 7068 | cases.add("passing a not-aligned-enough pointer to cmpxchg", |
| 7069 | \\const AtomicOrder = @import("builtin").AtomicOrder; | 7069 | \\const AtomicOrder = @import("std").builtin.AtomicOrder; |
| 7070 | \\export fn entry() bool { | 7070 | \\export fn entry() bool { |
| 7071 | \\ var x: i32 align(1) = 1234; | 7071 | \\ var x: i32 align(1) = 1234; |
| 7072 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} | 7072 | \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} |
| ... | @@ -7233,7 +7233,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7233,7 +7233,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7233 | }); | 7233 | }); |
| 7234 | 7234 | ||
| 7235 | cases.add("storing runtime value in compile time variable then using it", | 7235 | cases.add("storing runtime value in compile time variable then using it", |
| 7236 | \\const Mode = @import("builtin").Mode; | 7236 | \\const Mode = @import("std").builtin.Mode; |
| 7237 | \\ | 7237 | \\ |
| 7238 | \\fn Free(comptime filename: []const u8) TestCase { | 7238 | \\fn Free(comptime filename: []const u8) TestCase { |
| 7239 | \\ return TestCase { | 7239 | \\ return TestCase { |
| ... | @@ -7776,11 +7776,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7776,11 +7776,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7776 | cases.addTest("nested vectors", | 7776 | cases.addTest("nested vectors", |
| 7777 | \\export fn entry() void { | 7777 | \\export fn entry() void { |
| 7778 | \\ const V1 = @import("std").meta.Vector(4, u8); | 7778 | \\ const V1 = @import("std").meta.Vector(4, u8); |
| 7779 | \\ const V2 = @Type(@import("builtin").TypeInfo{ .Vector = .{ .len = 4, .child = V1 } }); | 7779 | \\ const V2 = @Type(@import("std").builtin.TypeInfo{ .Vector = .{ .len = 4, .child = V1 } }); |
| 7780 | \\ var v: V2 = undefined; | 7780 | \\ var v: V2 = undefined; |
| 7781 | \\} | 7781 | \\} |
| 7782 | , &[_][]const u8{ | 7782 | , &[_][]const u8{ |
| 7783 | "tmp.zig:3:49: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid", | 7783 | "tmp.zig:3:53: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid", |
| 7784 | "tmp.zig:3:16: note: referenced here", | 7784 | "tmp.zig:3:16: note: referenced here", |
| 7785 | }); | 7785 | }); |
| 7786 | 7786 |
test/runtime_safety.zig+186-138| ... | @@ -3,7 +3,7 @@ const tests = @import("tests.zig"); | ... | @@ -3,7 +3,7 @@ const tests = @import("tests.zig"); |
| 3 | pub fn addCases(cases: *tests.CompareOutputContext) void { | 3 | pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 4 | { | 4 | { |
| 5 | const check_panic_msg = | 5 | const check_panic_msg = |
| 6 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 6 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 7 | \\ if (std.mem.eql(u8, message, "reached unreachable code")) { | 7 | \\ if (std.mem.eql(u8, message, "reached unreachable code")) { |
| 8 | \\ std.process.exit(126); // good | 8 | \\ std.process.exit(126); // good |
| 9 | \\ } | 9 | \\ } |
| ... | @@ -44,7 +44,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -44,7 +44,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 44 | 44 | ||
| 45 | { | 45 | { |
| 46 | const check_panic_msg = | 46 | const check_panic_msg = |
| 47 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 47 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 48 | \\ if (std.mem.eql(u8, message, "invalid enum value")) { | 48 | \\ if (std.mem.eql(u8, message, "invalid enum value")) { |
| 49 | \\ std.process.exit(126); // good | 49 | \\ std.process.exit(126); // good |
| 50 | \\ } | 50 | \\ } |
| ... | @@ -82,7 +82,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -82,7 +82,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 82 | 82 | ||
| 83 | { | 83 | { |
| 84 | const check_panic_msg = | 84 | const check_panic_msg = |
| 85 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 85 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 86 | \\ if (std.mem.eql(u8, message, "index out of bounds")) { | 86 | \\ if (std.mem.eql(u8, message, "index out of bounds")) { |
| 87 | \\ std.process.exit(126); // good | 87 | \\ std.process.exit(126); // good |
| 88 | \\ } | 88 | \\ } |
| ... | @@ -152,7 +152,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -152,7 +152,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 152 | cases.addRuntimeSafety("truncating vector cast", | 152 | cases.addRuntimeSafety("truncating vector cast", |
| 153 | \\const std = @import("std"); | 153 | \\const std = @import("std"); |
| 154 | \\const V = @import("std").meta.Vector; | 154 | \\const V = @import("std").meta.Vector; |
| 155 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 155 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 156 | \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) { | 156 | \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) { |
| 157 | \\ std.process.exit(126); // good | 157 | \\ std.process.exit(126); // good |
| 158 | \\ } | 158 | \\ } |
| ... | @@ -167,7 +167,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -167,7 +167,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 167 | cases.addRuntimeSafety("unsigned-signed vector cast", | 167 | cases.addRuntimeSafety("unsigned-signed vector cast", |
| 168 | \\const std = @import("std"); | 168 | \\const std = @import("std"); |
| 169 | \\const V = @import("std").meta.Vector; | 169 | \\const V = @import("std").meta.Vector; |
| 170 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 170 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 171 | \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) { | 171 | \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) { |
| 172 | \\ std.process.exit(126); // good | 172 | \\ std.process.exit(126); // good |
| 173 | \\ } | 173 | \\ } |
| ... | @@ -182,7 +182,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -182,7 +182,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 182 | cases.addRuntimeSafety("signed-unsigned vector cast", | 182 | cases.addRuntimeSafety("signed-unsigned vector cast", |
| 183 | \\const std = @import("std"); | 183 | \\const std = @import("std"); |
| 184 | \\const V = @import("std").meta.Vector; | 184 | \\const V = @import("std").meta.Vector; |
| 185 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 185 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 186 | \\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) { | 186 | \\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) { |
| 187 | \\ std.process.exit(126); // good | 187 | \\ std.process.exit(126); // good |
| 188 | \\ } | 188 | \\ } |
| ... | @@ -196,7 +196,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -196,7 +196,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 196 | 196 | ||
| 197 | cases.addRuntimeSafety("shift left by huge amount", | 197 | cases.addRuntimeSafety("shift left by huge amount", |
| 198 | \\const std = @import("std"); | 198 | \\const std = @import("std"); |
| 199 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 199 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 200 | \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { | 200 | \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { |
| 201 | \\ std.process.exit(126); // good | 201 | \\ std.process.exit(126); // good |
| 202 | \\ } | 202 | \\ } |
| ... | @@ -211,7 +211,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -211,7 +211,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 211 | 211 | ||
| 212 | cases.addRuntimeSafety("shift right by huge amount", | 212 | cases.addRuntimeSafety("shift right by huge amount", |
| 213 | \\const std = @import("std"); | 213 | \\const std = @import("std"); |
| 214 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 214 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 215 | \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { | 215 | \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { |
| 216 | \\ std.process.exit(126); // good | 216 | \\ std.process.exit(126); // good |
| 217 | \\ } | 217 | \\ } |
| ... | @@ -226,7 +226,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -226,7 +226,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 226 | 226 | ||
| 227 | cases.addRuntimeSafety("slice sentinel mismatch - optional pointers", | 227 | cases.addRuntimeSafety("slice sentinel mismatch - optional pointers", |
| 228 | \\const std = @import("std"); | 228 | \\const std = @import("std"); |
| 229 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 229 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 230 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { | 230 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { |
| 231 | \\ std.process.exit(126); // good | 231 | \\ std.process.exit(126); // good |
| 232 | \\ } | 232 | \\ } |
| ... | @@ -240,7 +240,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -240,7 +240,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 240 | 240 | ||
| 241 | cases.addRuntimeSafety("slice sentinel mismatch - floats", | 241 | cases.addRuntimeSafety("slice sentinel mismatch - floats", |
| 242 | \\const std = @import("std"); | 242 | \\const std = @import("std"); |
| 243 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 243 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 244 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { | 244 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { |
| 245 | \\ std.process.exit(126); // good | 245 | \\ std.process.exit(126); // good |
| 246 | \\ } | 246 | \\ } |
| ... | @@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 254 | 254 | ||
| 255 | cases.addRuntimeSafety("pointer slice sentinel mismatch", | 255 | cases.addRuntimeSafety("pointer slice sentinel mismatch", |
| 256 | \\const std = @import("std"); | 256 | \\const std = @import("std"); |
| 257 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 257 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 258 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { | 258 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { |
| 259 | \\ std.process.exit(126); // good | 259 | \\ std.process.exit(126); // good |
| 260 | \\ } | 260 | \\ } |
| ... | @@ -269,7 +269,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -269,7 +269,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 269 | 269 | ||
| 270 | cases.addRuntimeSafety("slice slice sentinel mismatch", | 270 | cases.addRuntimeSafety("slice slice sentinel mismatch", |
| 271 | \\const std = @import("std"); | 271 | \\const std = @import("std"); |
| 272 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 272 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 273 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { | 273 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { |
| 274 | \\ std.process.exit(126); // good | 274 | \\ std.process.exit(126); // good |
| 275 | \\ } | 275 | \\ } |
| ... | @@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 284 | 284 | ||
| 285 | cases.addRuntimeSafety("array slice sentinel mismatch", | 285 | cases.addRuntimeSafety("array slice sentinel mismatch", |
| 286 | \\const std = @import("std"); | 286 | \\const std = @import("std"); |
| 287 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 287 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 288 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { | 288 | \\ if (std.mem.eql(u8, message, "sentinel mismatch")) { |
| 289 | \\ std.process.exit(126); // good | 289 | \\ std.process.exit(126); // good |
| 290 | \\ } | 290 | \\ } |
| ... | @@ -298,7 +298,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -298,7 +298,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 298 | 298 | ||
| 299 | cases.addRuntimeSafety("intToPtr with misaligned address", | 299 | cases.addRuntimeSafety("intToPtr with misaligned address", |
| 300 | \\const std = @import("std"); | 300 | \\const std = @import("std"); |
| 301 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 301 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 302 | \\ if (std.mem.eql(u8, message, "incorrect alignment")) { | 302 | \\ if (std.mem.eql(u8, message, "incorrect alignment")) { |
| 303 | \\ std.os.exit(126); // good | 303 | \\ std.os.exit(126); // good |
| 304 | \\ } | 304 | \\ } |
| ... | @@ -311,19 +311,20 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -311,19 +311,20 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 311 | ); | 311 | ); |
| 312 | 312 | ||
| 313 | cases.addRuntimeSafety("resuming a non-suspended function which never been suspended", | 313 | cases.addRuntimeSafety("resuming a non-suspended function which never been suspended", |
| 314 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 314 | \\const std = @import("std"); |
| 315 | \\ @import("std").os.exit(126); | 315 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 316 | \\ std.os.exit(126); | ||
| 316 | \\} | 317 | \\} |
| 317 | \\fn foo() void { | 318 | \\fn foo() void { |
| 318 | \\ var f = async bar(@frame()); | 319 | \\ var f = async bar(@frame()); |
| 319 | \\ @import("std").os.exit(0); | 320 | \\ std.os.exit(0); |
| 320 | \\} | 321 | \\} |
| 321 | \\ | 322 | \\ |
| 322 | \\fn bar(frame: anyframe) void { | 323 | \\fn bar(frame: anyframe) void { |
| 323 | \\ suspend { | 324 | \\ suspend { |
| 324 | \\ resume frame; | 325 | \\ resume frame; |
| 325 | \\ } | 326 | \\ } |
| 326 | \\ @import("std").os.exit(0); | 327 | \\ std.os.exit(0); |
| 327 | \\} | 328 | \\} |
| 328 | \\ | 329 | \\ |
| 329 | \\pub fn main() void { | 330 | \\pub fn main() void { |
| ... | @@ -332,35 +333,37 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -332,35 +333,37 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 332 | ); | 333 | ); |
| 333 | 334 | ||
| 334 | cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed", | 335 | cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed", |
| 335 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 336 | \\const std = @import("std"); |
| 336 | \\ @import("std").os.exit(126); | 337 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 338 | \\ std.os.exit(126); | ||
| 337 | \\} | 339 | \\} |
| 338 | \\fn foo() void { | 340 | \\fn foo() void { |
| 339 | \\ suspend { | 341 | \\ suspend { |
| 340 | \\ global_frame = @frame(); | 342 | \\ global_frame = @frame(); |
| 341 | \\ } | 343 | \\ } |
| 342 | \\ var f = async bar(@frame()); | 344 | \\ var f = async bar(@frame()); |
| 343 | \\ @import("std").os.exit(0); | 345 | \\ std.os.exit(0); |
| 344 | \\} | 346 | \\} |
| 345 | \\ | 347 | \\ |
| 346 | \\fn bar(frame: anyframe) void { | 348 | \\fn bar(frame: anyframe) void { |
| 347 | \\ suspend { | 349 | \\ suspend { |
| 348 | \\ resume frame; | 350 | \\ resume frame; |
| 349 | \\ } | 351 | \\ } |
| 350 | \\ @import("std").os.exit(0); | 352 | \\ std.os.exit(0); |
| 351 | \\} | 353 | \\} |
| 352 | \\ | 354 | \\ |
| 353 | \\var global_frame: anyframe = undefined; | 355 | \\var global_frame: anyframe = undefined; |
| 354 | \\pub fn main() void { | 356 | \\pub fn main() void { |
| 355 | \\ _ = async foo(); | 357 | \\ _ = async foo(); |
| 356 | \\ resume global_frame; | 358 | \\ resume global_frame; |
| 357 | \\ @import("std").os.exit(0); | 359 | \\ std.os.exit(0); |
| 358 | \\} | 360 | \\} |
| 359 | ); | 361 | ); |
| 360 | 362 | ||
| 361 | cases.addRuntimeSafety("nosuspend function call, callee suspends", | 363 | cases.addRuntimeSafety("nosuspend function call, callee suspends", |
| 362 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 364 | \\const std = @import("std"); |
| 363 | \\ @import("std").os.exit(126); | 365 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 366 | \\ std.os.exit(126); | ||
| 364 | \\} | 367 | \\} |
| 365 | \\pub fn main() void { | 368 | \\pub fn main() void { |
| 366 | \\ _ = nosuspend add(101, 100); | 369 | \\ _ = nosuspend add(101, 100); |
| ... | @@ -374,8 +377,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -374,8 +377,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 374 | ); | 377 | ); |
| 375 | 378 | ||
| 376 | cases.addRuntimeSafety("awaiting twice", | 379 | cases.addRuntimeSafety("awaiting twice", |
| 377 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 380 | \\const std = @import("std"); |
| 378 | \\ @import("std").os.exit(126); | 381 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 382 | \\ std.os.exit(126); | ||
| 379 | \\} | 383 | \\} |
| 380 | \\var frame: anyframe = undefined; | 384 | \\var frame: anyframe = undefined; |
| 381 | \\ | 385 | \\ |
| ... | @@ -398,8 +402,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -398,8 +402,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 398 | ); | 402 | ); |
| 399 | 403 | ||
| 400 | cases.addRuntimeSafety("@asyncCall with too small a frame", | 404 | cases.addRuntimeSafety("@asyncCall with too small a frame", |
| 401 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 405 | \\const std = @import("std"); |
| 402 | \\ @import("std").os.exit(126); | 406 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 407 | \\ std.os.exit(126); | ||
| 403 | \\} | 408 | \\} |
| 404 | \\pub fn main() void { | 409 | \\pub fn main() void { |
| 405 | \\ var bytes: [1]u8 align(16) = undefined; | 410 | \\ var bytes: [1]u8 align(16) = undefined; |
| ... | @@ -412,8 +417,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -412,8 +417,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 412 | ); | 417 | ); |
| 413 | 418 | ||
| 414 | cases.addRuntimeSafety("resuming a function which is awaiting a frame", | 419 | cases.addRuntimeSafety("resuming a function which is awaiting a frame", |
| 415 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 420 | \\const std = @import("std"); |
| 416 | \\ @import("std").os.exit(126); | 421 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 422 | \\ std.os.exit(126); | ||
| 417 | \\} | 423 | \\} |
| 418 | \\pub fn main() void { | 424 | \\pub fn main() void { |
| 419 | \\ var frame = async first(); | 425 | \\ var frame = async first(); |
| ... | @@ -429,8 +435,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -429,8 +435,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 429 | ); | 435 | ); |
| 430 | 436 | ||
| 431 | cases.addRuntimeSafety("resuming a function which is awaiting a call", | 437 | cases.addRuntimeSafety("resuming a function which is awaiting a call", |
| 432 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 438 | \\const std = @import("std"); |
| 433 | \\ @import("std").os.exit(126); | 439 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 440 | \\ std.os.exit(126); | ||
| 434 | \\} | 441 | \\} |
| 435 | \\pub fn main() void { | 442 | \\pub fn main() void { |
| 436 | \\ var frame = async first(); | 443 | \\ var frame = async first(); |
| ... | @@ -445,8 +452,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -445,8 +452,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 445 | ); | 452 | ); |
| 446 | 453 | ||
| 447 | cases.addRuntimeSafety("invalid resume of async function", | 454 | cases.addRuntimeSafety("invalid resume of async function", |
| 448 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 455 | \\const std = @import("std"); |
| 449 | \\ @import("std").os.exit(126); | 456 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 457 | \\ std.os.exit(126); | ||
| 450 | \\} | 458 | \\} |
| 451 | \\pub fn main() void { | 459 | \\pub fn main() void { |
| 452 | \\ var p = async suspendOnce(); | 460 | \\ var p = async suspendOnce(); |
| ... | @@ -459,8 +467,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -459,8 +467,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 459 | ); | 467 | ); |
| 460 | 468 | ||
| 461 | cases.addRuntimeSafety(".? operator on null pointer", | 469 | cases.addRuntimeSafety(".? operator on null pointer", |
| 462 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 470 | \\const std = @import("std"); |
| 463 | \\ @import("std").os.exit(126); | 471 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 472 | \\ std.os.exit(126); | ||
| 464 | \\} | 473 | \\} |
| 465 | \\pub fn main() void { | 474 | \\pub fn main() void { |
| 466 | \\ var ptr: ?*i32 = null; | 475 | \\ var ptr: ?*i32 = null; |
| ... | @@ -469,8 +478,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -469,8 +478,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 469 | ); | 478 | ); |
| 470 | 479 | ||
| 471 | cases.addRuntimeSafety(".? operator on C pointer", | 480 | cases.addRuntimeSafety(".? operator on C pointer", |
| 472 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 481 | \\const std = @import("std"); |
| 473 | \\ @import("std").os.exit(126); | 482 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 483 | \\ std.os.exit(126); | ||
| 474 | \\} | 484 | \\} |
| 475 | \\pub fn main() void { | 485 | \\pub fn main() void { |
| 476 | \\ var ptr: [*c]i32 = null; | 486 | \\ var ptr: [*c]i32 = null; |
| ... | @@ -479,8 +489,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -479,8 +489,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 479 | ); | 489 | ); |
| 480 | 490 | ||
| 481 | cases.addRuntimeSafety("@intToPtr address zero to non-optional pointer", | 491 | cases.addRuntimeSafety("@intToPtr address zero to non-optional pointer", |
| 482 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 492 | \\const std = @import("std"); |
| 483 | \\ @import("std").os.exit(126); | 493 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 494 | \\ std.os.exit(126); | ||
| 484 | \\} | 495 | \\} |
| 485 | \\pub fn main() void { | 496 | \\pub fn main() void { |
| 486 | \\ var zero: usize = 0; | 497 | \\ var zero: usize = 0; |
| ... | @@ -489,8 +500,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -489,8 +500,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 489 | ); | 500 | ); |
| 490 | 501 | ||
| 491 | cases.addRuntimeSafety("@intToPtr address zero to non-optional byte-aligned pointer", | 502 | cases.addRuntimeSafety("@intToPtr address zero to non-optional byte-aligned pointer", |
| 492 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 503 | \\const std = @import("std"); |
| 493 | \\ @import("std").os.exit(126); | 504 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 505 | \\ std.os.exit(126); | ||
| 494 | \\} | 506 | \\} |
| 495 | \\pub fn main() void { | 507 | \\pub fn main() void { |
| 496 | \\ var zero: usize = 0; | 508 | \\ var zero: usize = 0; |
| ... | @@ -499,8 +511,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -499,8 +511,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 499 | ); | 511 | ); |
| 500 | 512 | ||
| 501 | cases.addRuntimeSafety("pointer casting null to non-optional pointer", | 513 | cases.addRuntimeSafety("pointer casting null to non-optional pointer", |
| 502 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 514 | \\const std = @import("std"); |
| 503 | \\ @import("std").os.exit(126); | 515 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 516 | \\ std.os.exit(126); | ||
| 504 | \\} | 517 | \\} |
| 505 | \\pub fn main() void { | 518 | \\pub fn main() void { |
| 506 | \\ var c_ptr: [*c]u8 = 0; | 519 | \\ var c_ptr: [*c]u8 = 0; |
| ... | @@ -509,8 +522,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -509,8 +522,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 509 | ); | 522 | ); |
| 510 | 523 | ||
| 511 | cases.addRuntimeSafety("@intToEnum - no matching tag value", | 524 | cases.addRuntimeSafety("@intToEnum - no matching tag value", |
| 512 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 525 | \\const std = @import("std"); |
| 513 | \\ @import("std").os.exit(126); | 526 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 527 | \\ std.os.exit(126); | ||
| 514 | \\} | 528 | \\} |
| 515 | \\const Foo = enum { | 529 | \\const Foo = enum { |
| 516 | \\ A, | 530 | \\ A, |
| ... | @@ -527,8 +541,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -527,8 +541,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 527 | ); | 541 | ); |
| 528 | 542 | ||
| 529 | cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned", | 543 | cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned", |
| 530 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 544 | \\const std = @import("std"); |
| 531 | \\ @import("std").os.exit(126); | 545 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 546 | \\ std.os.exit(126); | ||
| 532 | \\} | 547 | \\} |
| 533 | \\pub fn main() void { | 548 | \\pub fn main() void { |
| 534 | \\ baz(bar(-1.1)); | 549 | \\ baz(bar(-1.1)); |
| ... | @@ -540,8 +555,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -540,8 +555,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 540 | ); | 555 | ); |
| 541 | 556 | ||
| 542 | cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range", | 557 | cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range", |
| 543 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 558 | \\const std = @import("std"); |
| 544 | \\ @import("std").os.exit(126); | 559 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 560 | \\ std.os.exit(126); | ||
| 545 | \\} | 561 | \\} |
| 546 | \\pub fn main() void { | 562 | \\pub fn main() void { |
| 547 | \\ baz(bar(-129.1)); | 563 | \\ baz(bar(-129.1)); |
| ... | @@ -553,8 +569,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -553,8 +569,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 553 | ); | 569 | ); |
| 554 | 570 | ||
| 555 | cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range", | 571 | cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range", |
| 556 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 572 | \\const std = @import("std"); |
| 557 | \\ @import("std").os.exit(126); | 573 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 574 | \\ std.os.exit(126); | ||
| 558 | \\} | 575 | \\} |
| 559 | \\pub fn main() void { | 576 | \\pub fn main() void { |
| 560 | \\ baz(bar(256.2)); | 577 | \\ baz(bar(256.2)); |
| ... | @@ -566,8 +583,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -566,8 +583,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 566 | ); | 583 | ); |
| 567 | 584 | ||
| 568 | cases.addRuntimeSafety("calling panic", | 585 | cases.addRuntimeSafety("calling panic", |
| 569 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 586 | \\const std = @import("std"); |
| 570 | \\ @import("std").os.exit(126); | 587 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 588 | \\ std.os.exit(126); | ||
| 571 | \\} | 589 | \\} |
| 572 | \\pub fn main() void { | 590 | \\pub fn main() void { |
| 573 | \\ @panic("oh no"); | 591 | \\ @panic("oh no"); |
| ... | @@ -575,8 +593,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -575,8 +593,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 575 | ); | 593 | ); |
| 576 | 594 | ||
| 577 | cases.addRuntimeSafety("out of bounds slice access", | 595 | cases.addRuntimeSafety("out of bounds slice access", |
| 578 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 596 | \\const std = @import("std"); |
| 579 | \\ @import("std").os.exit(126); | 597 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 598 | \\ std.os.exit(126); | ||
| 580 | \\} | 599 | \\} |
| 581 | \\pub fn main() void { | 600 | \\pub fn main() void { |
| 582 | \\ const a = [_]i32{1, 2, 3, 4}; | 601 | \\ const a = [_]i32{1, 2, 3, 4}; |
| ... | @@ -589,8 +608,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -589,8 +608,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 589 | ); | 608 | ); |
| 590 | 609 | ||
| 591 | cases.addRuntimeSafety("integer addition overflow", | 610 | cases.addRuntimeSafety("integer addition overflow", |
| 592 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 611 | \\const std = @import("std"); |
| 593 | \\ @import("std").os.exit(126); | 612 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 613 | \\ std.os.exit(126); | ||
| 594 | \\} | 614 | \\} |
| 595 | \\pub fn main() !void { | 615 | \\pub fn main() !void { |
| 596 | \\ const x = add(65530, 10); | 616 | \\ const x = add(65530, 10); |
| ... | @@ -602,63 +622,68 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -602,63 +622,68 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 602 | ); | 622 | ); |
| 603 | 623 | ||
| 604 | cases.addRuntimeSafety("vector integer addition overflow", | 624 | cases.addRuntimeSafety("vector integer addition overflow", |
| 605 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 625 | \\const std = @import("std"); |
| 606 | \\ @import("std").os.exit(126); | 626 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 627 | \\ std.os.exit(126); | ||
| 607 | \\} | 628 | \\} |
| 608 | \\pub fn main() void { | 629 | \\pub fn main() void { |
| 609 | \\ var a: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 }; | 630 | \\ var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 }; |
| 610 | \\ var b: @import("std").meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; | 631 | \\ var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; |
| 611 | \\ const x = add(a, b); | 632 | \\ const x = add(a, b); |
| 612 | \\} | 633 | \\} |
| 613 | \\fn add(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.Vector(4, i32) { | 634 | \\fn add(a: std.meta.Vector(4, i32), b: std.meta.Vector(4, i32)) std.meta.Vector(4, i32) { |
| 614 | \\ return a + b; | 635 | \\ return a + b; |
| 615 | \\} | 636 | \\} |
| 616 | ); | 637 | ); |
| 617 | 638 | ||
| 618 | cases.addRuntimeSafety("vector integer subtraction overflow", | 639 | cases.addRuntimeSafety("vector integer subtraction overflow", |
| 619 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 640 | \\const std = @import("std"); |
| 620 | \\ @import("std").os.exit(126); | 641 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 642 | \\ std.os.exit(126); | ||
| 621 | \\} | 643 | \\} |
| 622 | \\pub fn main() void { | 644 | \\pub fn main() void { |
| 623 | \\ var a: @import("std").meta.Vector(4, u32) = [_]u32{ 1, 2, 8, 4 }; | 645 | \\ var a: std.meta.Vector(4, u32) = [_]u32{ 1, 2, 8, 4 }; |
| 624 | \\ var b: @import("std").meta.Vector(4, u32) = [_]u32{ 5, 6, 7, 8 }; | 646 | \\ var b: std.meta.Vector(4, u32) = [_]u32{ 5, 6, 7, 8 }; |
| 625 | \\ const x = sub(b, a); | 647 | \\ const x = sub(b, a); |
| 626 | \\} | 648 | \\} |
| 627 | \\fn sub(a: @import("std").meta.Vector(4, u32), b: @import("std").meta.Vector(4, u32)) @import("std").meta.Vector(4, u32) { | 649 | \\fn sub(a: std.meta.Vector(4, u32), b: std.meta.Vector(4, u32)) std.meta.Vector(4, u32) { |
| 628 | \\ return a - b; | 650 | \\ return a - b; |
| 629 | \\} | 651 | \\} |
| 630 | ); | 652 | ); |
| 631 | 653 | ||
| 632 | cases.addRuntimeSafety("vector integer multiplication overflow", | 654 | cases.addRuntimeSafety("vector integer multiplication overflow", |
| 633 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 655 | \\const std = @import("std"); |
| 634 | \\ @import("std").os.exit(126); | 656 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 657 | \\ std.os.exit(126); | ||
| 635 | \\} | 658 | \\} |
| 636 | \\pub fn main() void { | 659 | \\pub fn main() void { |
| 637 | \\ var a: @import("std").meta.Vector(4, u8) = [_]u8{ 1, 2, 200, 4 }; | 660 | \\ var a: std.meta.Vector(4, u8) = [_]u8{ 1, 2, 200, 4 }; |
| 638 | \\ var b: @import("std").meta.Vector(4, u8) = [_]u8{ 5, 6, 2, 8 }; | 661 | \\ var b: std.meta.Vector(4, u8) = [_]u8{ 5, 6, 2, 8 }; |
| 639 | \\ const x = mul(b, a); | 662 | \\ const x = mul(b, a); |
| 640 | \\} | 663 | \\} |
| 641 | \\fn mul(a: @import("std").meta.Vector(4, u8), b: @import("std").meta.Vector(4, u8)) @import("std").meta.Vector(4, u8) { | 664 | \\fn mul(a: std.meta.Vector(4, u8), b: std.meta.Vector(4, u8)) std.meta.Vector(4, u8) { |
| 642 | \\ return a * b; | 665 | \\ return a * b; |
| 643 | \\} | 666 | \\} |
| 644 | ); | 667 | ); |
| 645 | 668 | ||
| 646 | cases.addRuntimeSafety("vector integer negation overflow", | 669 | cases.addRuntimeSafety("vector integer negation overflow", |
| 647 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 670 | \\const std = @import("std"); |
| 648 | \\ @import("std").os.exit(126); | 671 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 672 | \\ std.os.exit(126); | ||
| 649 | \\} | 673 | \\} |
| 650 | \\pub fn main() void { | 674 | \\pub fn main() void { |
| 651 | \\ var a: @import("std").meta.Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 }; | 675 | \\ var a: std.meta.Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 }; |
| 652 | \\ const x = neg(a); | 676 | \\ const x = neg(a); |
| 653 | \\} | 677 | \\} |
| 654 | \\fn neg(a: @import("std").meta.Vector(4, i16)) @import("std").meta.Vector(4, i16) { | 678 | \\fn neg(a: std.meta.Vector(4, i16)) std.meta.Vector(4, i16) { |
| 655 | \\ return -a; | 679 | \\ return -a; |
| 656 | \\} | 680 | \\} |
| 657 | ); | 681 | ); |
| 658 | 682 | ||
| 659 | cases.addRuntimeSafety("integer subtraction overflow", | 683 | cases.addRuntimeSafety("integer subtraction overflow", |
| 660 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 684 | \\const std = @import("std"); |
| 661 | \\ @import("std").os.exit(126); | 685 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 686 | \\ std.os.exit(126); | ||
| 662 | \\} | 687 | \\} |
| 663 | \\pub fn main() !void { | 688 | \\pub fn main() !void { |
| 664 | \\ const x = sub(10, 20); | 689 | \\ const x = sub(10, 20); |
| ... | @@ -670,8 +695,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -670,8 +695,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 670 | ); | 695 | ); |
| 671 | 696 | ||
| 672 | cases.addRuntimeSafety("integer multiplication overflow", | 697 | cases.addRuntimeSafety("integer multiplication overflow", |
| 673 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 698 | \\const std = @import("std"); |
| 674 | \\ @import("std").os.exit(126); | 699 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 700 | \\ std.os.exit(126); | ||
| 675 | \\} | 701 | \\} |
| 676 | \\pub fn main() !void { | 702 | \\pub fn main() !void { |
| 677 | \\ const x = mul(300, 6000); | 703 | \\ const x = mul(300, 6000); |
| ... | @@ -683,8 +709,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -683,8 +709,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 683 | ); | 709 | ); |
| 684 | 710 | ||
| 685 | cases.addRuntimeSafety("integer negation overflow", | 711 | cases.addRuntimeSafety("integer negation overflow", |
| 686 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 712 | \\const std = @import("std"); |
| 687 | \\ @import("std").os.exit(126); | 713 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 714 | \\ std.os.exit(126); | ||
| 688 | \\} | 715 | \\} |
| 689 | \\pub fn main() !void { | 716 | \\pub fn main() !void { |
| 690 | \\ const x = neg(-32768); | 717 | \\ const x = neg(-32768); |
| ... | @@ -696,8 +723,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -696,8 +723,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 696 | ); | 723 | ); |
| 697 | 724 | ||
| 698 | cases.addRuntimeSafety("signed integer division overflow", | 725 | cases.addRuntimeSafety("signed integer division overflow", |
| 699 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 726 | \\const std = @import("std"); |
| 700 | \\ @import("std").os.exit(126); | 727 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 728 | \\ std.os.exit(126); | ||
| 701 | \\} | 729 | \\} |
| 702 | \\pub fn main() !void { | 730 | \\pub fn main() !void { |
| 703 | \\ const x = div(-32768, -1); | 731 | \\ const x = div(-32768, -1); |
| ... | @@ -709,23 +737,25 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -709,23 +737,25 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 709 | ); | 737 | ); |
| 710 | 738 | ||
| 711 | cases.addRuntimeSafety("signed integer division overflow - vectors", | 739 | cases.addRuntimeSafety("signed integer division overflow - vectors", |
| 712 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 740 | \\const std = @import("std"); |
| 713 | \\ @import("std").os.exit(126); | 741 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 742 | \\ std.os.exit(126); | ||
| 714 | \\} | 743 | \\} |
| 715 | \\pub fn main() !void { | 744 | \\pub fn main() !void { |
| 716 | \\ var a: @import("std").meta.Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 }; | 745 | \\ var a: std.meta.Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 }; |
| 717 | \\ var b: @import("std").meta.Vector(4, i16) = [_]i16{ 1, 2, -1, 4 }; | 746 | \\ var b: std.meta.Vector(4, i16) = [_]i16{ 1, 2, -1, 4 }; |
| 718 | \\ const x = div(a, b); | 747 | \\ const x = div(a, b); |
| 719 | \\ if (x[2] == 32767) return error.Whatever; | 748 | \\ if (x[2] == 32767) return error.Whatever; |
| 720 | \\} | 749 | \\} |
| 721 | \\fn div(a: @import("std").meta.Vector(4, i16), b: @import("std").meta.Vector(4, i16)) @import("std").meta.Vector(4, i16) { | 750 | \\fn div(a: std.meta.Vector(4, i16), b: std.meta.Vector(4, i16)) std.meta.Vector(4, i16) { |
| 722 | \\ return @divTrunc(a, b); | 751 | \\ return @divTrunc(a, b); |
| 723 | \\} | 752 | \\} |
| 724 | ); | 753 | ); |
| 725 | 754 | ||
| 726 | cases.addRuntimeSafety("signed shift left overflow", | 755 | cases.addRuntimeSafety("signed shift left overflow", |
| 727 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 756 | \\const std = @import("std"); |
| 728 | \\ @import("std").os.exit(126); | 757 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 758 | \\ std.os.exit(126); | ||
| 729 | \\} | 759 | \\} |
| 730 | \\pub fn main() !void { | 760 | \\pub fn main() !void { |
| 731 | \\ const x = shl(-16385, 1); | 761 | \\ const x = shl(-16385, 1); |
| ... | @@ -737,8 +767,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -737,8 +767,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 737 | ); | 767 | ); |
| 738 | 768 | ||
| 739 | cases.addRuntimeSafety("unsigned shift left overflow", | 769 | cases.addRuntimeSafety("unsigned shift left overflow", |
| 740 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 770 | \\const std = @import("std"); |
| 741 | \\ @import("std").os.exit(126); | 771 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 772 | \\ std.os.exit(126); | ||
| 742 | \\} | 773 | \\} |
| 743 | \\pub fn main() !void { | 774 | \\pub fn main() !void { |
| 744 | \\ const x = shl(0b0010111111111111, 3); | 775 | \\ const x = shl(0b0010111111111111, 3); |
| ... | @@ -750,8 +781,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -750,8 +781,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 750 | ); | 781 | ); |
| 751 | 782 | ||
| 752 | cases.addRuntimeSafety("signed shift right overflow", | 783 | cases.addRuntimeSafety("signed shift right overflow", |
| 753 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 784 | \\const std = @import("std"); |
| 754 | \\ @import("std").os.exit(126); | 785 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 786 | \\ std.os.exit(126); | ||
| 755 | \\} | 787 | \\} |
| 756 | \\pub fn main() !void { | 788 | \\pub fn main() !void { |
| 757 | \\ const x = shr(-16385, 1); | 789 | \\ const x = shr(-16385, 1); |
| ... | @@ -763,8 +795,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -763,8 +795,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 763 | ); | 795 | ); |
| 764 | 796 | ||
| 765 | cases.addRuntimeSafety("unsigned shift right overflow", | 797 | cases.addRuntimeSafety("unsigned shift right overflow", |
| 766 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 798 | \\const std = @import("std"); |
| 767 | \\ @import("std").os.exit(126); | 799 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 800 | \\ std.os.exit(126); | ||
| 768 | \\} | 801 | \\} |
| 769 | \\pub fn main() !void { | 802 | \\pub fn main() !void { |
| 770 | \\ const x = shr(0b0010111111111111, 3); | 803 | \\ const x = shr(0b0010111111111111, 3); |
| ... | @@ -776,8 +809,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -776,8 +809,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 776 | ); | 809 | ); |
| 777 | 810 | ||
| 778 | cases.addRuntimeSafety("integer division by zero", | 811 | cases.addRuntimeSafety("integer division by zero", |
| 779 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 812 | \\const std = @import("std"); |
| 780 | \\ @import("std").os.exit(126); | 813 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 814 | \\ std.os.exit(126); | ||
| 781 | \\} | 815 | \\} |
| 782 | \\pub fn main() void { | 816 | \\pub fn main() void { |
| 783 | \\ const x = div0(999, 0); | 817 | \\ const x = div0(999, 0); |
| ... | @@ -788,22 +822,24 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -788,22 +822,24 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 788 | ); | 822 | ); |
| 789 | 823 | ||
| 790 | cases.addRuntimeSafety("integer division by zero - vectors", | 824 | cases.addRuntimeSafety("integer division by zero - vectors", |
| 791 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 825 | \\const std = @import("std"); |
| 792 | \\ @import("std").os.exit(126); | 826 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 827 | \\ std.os.exit(126); | ||
| 793 | \\} | 828 | \\} |
| 794 | \\pub fn main() void { | 829 | \\pub fn main() void { |
| 795 | \\ var a: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; | 830 | \\ var a: std.meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; |
| 796 | \\ var b: @import("std").meta.Vector(4, i32) = [4]i32{111, 0, 333, 444}; | 831 | \\ var b: std.meta.Vector(4, i32) = [4]i32{111, 0, 333, 444}; |
| 797 | \\ const x = div0(a, b); | 832 | \\ const x = div0(a, b); |
| 798 | \\} | 833 | \\} |
| 799 | \\fn div0(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.Vector(4, i32) { | 834 | \\fn div0(a: std.meta.Vector(4, i32), b: std.meta.Vector(4, i32)) std.meta.Vector(4, i32) { |
| 800 | \\ return @divTrunc(a, b); | 835 | \\ return @divTrunc(a, b); |
| 801 | \\} | 836 | \\} |
| 802 | ); | 837 | ); |
| 803 | 838 | ||
| 804 | cases.addRuntimeSafety("exact division failure", | 839 | cases.addRuntimeSafety("exact division failure", |
| 805 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 840 | \\const std = @import("std"); |
| 806 | \\ @import("std").os.exit(126); | 841 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 842 | \\ std.os.exit(126); | ||
| 807 | \\} | 843 | \\} |
| 808 | \\pub fn main() !void { | 844 | \\pub fn main() !void { |
| 809 | \\ const x = divExact(10, 3); | 845 | \\ const x = divExact(10, 3); |
| ... | @@ -815,15 +851,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -815,15 +851,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 815 | ); | 851 | ); |
| 816 | 852 | ||
| 817 | cases.addRuntimeSafety("exact division failure - vectors", | 853 | cases.addRuntimeSafety("exact division failure - vectors", |
| 818 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 854 | \\const std = @import("std"); |
| 819 | \\ @import("std").os.exit(126); | 855 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 856 | \\ std.os.exit(126); | ||
| 820 | \\} | 857 | \\} |
| 821 | \\pub fn main() !void { | 858 | \\pub fn main() !void { |
| 822 | \\ var a: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; | 859 | \\ var a: std.meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; |
| 823 | \\ var b: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 441}; | 860 | \\ var b: std.meta.Vector(4, i32) = [4]i32{111, 222, 333, 441}; |
| 824 | \\ const x = divExact(a, b); | 861 | \\ const x = divExact(a, b); |
| 825 | \\} | 862 | \\} |
| 826 | \\fn divExact(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.Vector(4, i32) { | 863 | \\fn divExact(a: std.meta.Vector(4, i32), b: std.meta.Vector(4, i32)) std.meta.Vector(4, i32) { |
| 827 | \\ return @divExact(a, b); | 864 | \\ return @divExact(a, b); |
| 828 | \\} | 865 | \\} |
| 829 | ); | 866 | ); |
| ... | @@ -843,8 +880,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -843,8 +880,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 843 | ); | 880 | ); |
| 844 | 881 | ||
| 845 | cases.addRuntimeSafety("value does not fit in shortening cast", | 882 | cases.addRuntimeSafety("value does not fit in shortening cast", |
| 846 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 883 | \\const std = @import("std"); |
| 847 | \\ @import("std").os.exit(126); | 884 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 885 | \\ std.os.exit(126); | ||
| 848 | \\} | 886 | \\} |
| 849 | \\pub fn main() !void { | 887 | \\pub fn main() !void { |
| 850 | \\ const x = shorten_cast(200); | 888 | \\ const x = shorten_cast(200); |
| ... | @@ -856,8 +894,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -856,8 +894,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 856 | ); | 894 | ); |
| 857 | 895 | ||
| 858 | cases.addRuntimeSafety("value does not fit in shortening cast - u0", | 896 | cases.addRuntimeSafety("value does not fit in shortening cast - u0", |
| 859 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 897 | \\const std = @import("std"); |
| 860 | \\ @import("std").os.exit(126); | 898 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 899 | \\ std.os.exit(126); | ||
| 861 | \\} | 900 | \\} |
| 862 | \\pub fn main() !void { | 901 | \\pub fn main() !void { |
| 863 | \\ const x = shorten_cast(1); | 902 | \\ const x = shorten_cast(1); |
| ... | @@ -869,8 +908,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -869,8 +908,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 869 | ); | 908 | ); |
| 870 | 909 | ||
| 871 | cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer", | 910 | cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer", |
| 872 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 911 | \\const std = @import("std"); |
| 873 | \\ @import("std").os.exit(126); | 912 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 913 | \\ std.os.exit(126); | ||
| 874 | \\} | 914 | \\} |
| 875 | \\pub fn main() !void { | 915 | \\pub fn main() !void { |
| 876 | \\ const x = unsigned_cast(-10); | 916 | \\ const x = unsigned_cast(-10); |
| ... | @@ -882,8 +922,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -882,8 +922,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 882 | ); | 922 | ); |
| 883 | 923 | ||
| 884 | cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening", | 924 | cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening", |
| 885 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 925 | \\const std = @import("std"); |
| 886 | \\ @import("std").os.exit(126); | 926 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 927 | \\ std.os.exit(126); | ||
| 887 | \\} | 928 | \\} |
| 888 | \\pub fn main() void { | 929 | \\pub fn main() void { |
| 889 | \\ var value: c_short = -1; | 930 | \\ var value: c_short = -1; |
| ... | @@ -892,8 +933,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -892,8 +933,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 892 | ); | 933 | ); |
| 893 | 934 | ||
| 894 | cases.addRuntimeSafety("unsigned integer not fitting in cast to signed integer - same bit count", | 935 | cases.addRuntimeSafety("unsigned integer not fitting in cast to signed integer - same bit count", |
| 895 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 936 | \\const std = @import("std"); |
| 896 | \\ @import("std").os.exit(126); | 937 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 938 | \\ std.os.exit(126); | ||
| 897 | \\} | 939 | \\} |
| 898 | \\pub fn main() void { | 940 | \\pub fn main() void { |
| 899 | \\ var value: u8 = 245; | 941 | \\ var value: u8 = 245; |
| ... | @@ -902,11 +944,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -902,11 +944,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 902 | ); | 944 | ); |
| 903 | 945 | ||
| 904 | cases.addRuntimeSafety("unwrap error", | 946 | cases.addRuntimeSafety("unwrap error", |
| 905 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 947 | \\const std = @import("std"); |
| 906 | \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { | 948 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 907 | \\ @import("std").os.exit(126); // good | 949 | \\ if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) { |
| 950 | \\ std.os.exit(126); // good | ||
| 908 | \\ } | 951 | \\ } |
| 909 | \\ @import("std").os.exit(0); // test failed | 952 | \\ std.os.exit(0); // test failed |
| 910 | \\} | 953 | \\} |
| 911 | \\pub fn main() void { | 954 | \\pub fn main() void { |
| 912 | \\ bar() catch unreachable; | 955 | \\ bar() catch unreachable; |
| ... | @@ -917,8 +960,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -917,8 +960,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 917 | ); | 960 | ); |
| 918 | 961 | ||
| 919 | cases.addRuntimeSafety("cast integer to global error and no code matches", | 962 | cases.addRuntimeSafety("cast integer to global error and no code matches", |
| 920 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 963 | \\const std = @import("std"); |
| 921 | \\ @import("std").os.exit(126); | 964 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 965 | \\ std.os.exit(126); | ||
| 922 | \\} | 966 | \\} |
| 923 | \\pub fn main() void { | 967 | \\pub fn main() void { |
| 924 | \\ bar(9999) catch {}; | 968 | \\ bar(9999) catch {}; |
| ... | @@ -929,8 +973,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -929,8 +973,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 929 | ); | 973 | ); |
| 930 | 974 | ||
| 931 | cases.addRuntimeSafety("@errSetCast error not present in destination", | 975 | cases.addRuntimeSafety("@errSetCast error not present in destination", |
| 932 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 976 | \\const std = @import("std"); |
| 933 | \\ @import("std").os.exit(126); | 977 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 978 | \\ std.os.exit(126); | ||
| 934 | \\} | 979 | \\} |
| 935 | \\const Set1 = error{A, B}; | 980 | \\const Set1 = error{A, B}; |
| 936 | \\const Set2 = error{A, C}; | 981 | \\const Set2 = error{A, C}; |
| ... | @@ -960,8 +1005,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -960,8 +1005,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 960 | ); | 1005 | ); |
| 961 | 1006 | ||
| 962 | cases.addRuntimeSafety("bad union field access", | 1007 | cases.addRuntimeSafety("bad union field access", |
| 963 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 1008 | \\const std = @import("std"); |
| 964 | \\ @import("std").os.exit(126); | 1009 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 1010 | \\ std.os.exit(126); | ||
| 965 | \\} | 1011 | \\} |
| 966 | \\ | 1012 | \\ |
| 967 | \\const Foo = union { | 1013 | \\const Foo = union { |
| ... | @@ -983,8 +1029,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -983,8 +1029,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 983 | // but we still emit a safety check to ensure the integer was 0 and thus | 1029 | // but we still emit a safety check to ensure the integer was 0 and thus |
| 984 | // did not truncate information. | 1030 | // did not truncate information. |
| 985 | cases.addRuntimeSafety("@intCast to u0", | 1031 | cases.addRuntimeSafety("@intCast to u0", |
| 986 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 1032 | \\const std = @import("std"); |
| 987 | \\ @import("std").os.exit(126); | 1033 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 1034 | \\ std.os.exit(126); | ||
| 988 | \\} | 1035 | \\} |
| 989 | \\ | 1036 | \\ |
| 990 | \\pub fn main() void { | 1037 | \\pub fn main() void { |
| ... | @@ -1001,7 +1048,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -1001,7 +1048,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 1001 | cases.addRuntimeSafety("error return trace across suspend points", | 1048 | cases.addRuntimeSafety("error return trace across suspend points", |
| 1002 | \\const std = @import("std"); | 1049 | \\const std = @import("std"); |
| 1003 | \\ | 1050 | \\ |
| 1004 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 1051 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 1005 | \\ std.os.exit(126); | 1052 | \\ std.os.exit(126); |
| 1006 | \\} | 1053 | \\} |
| 1007 | \\ | 1054 | \\ |
| ... | @@ -1035,8 +1082,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -1035,8 +1082,9 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 1035 | // Slicing a C pointer returns a non-allowzero slice, thus we need to emit | 1082 | // Slicing a C pointer returns a non-allowzero slice, thus we need to emit |
| 1036 | // a safety check to ensure the pointer is not null. | 1083 | // a safety check to ensure the pointer is not null. |
| 1037 | cases.addRuntimeSafety("slicing null C pointer", | 1084 | cases.addRuntimeSafety("slicing null C pointer", |
| 1038 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { | 1085 | \\const std = @import("std"); |
| 1039 | \\ @import("std").os.exit(126); | 1086 | \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 1087 | \\ std.os.exit(126); | ||
| 1040 | \\} | 1088 | \\} |
| 1041 | \\ | 1089 | \\ |
| 1042 | \\pub fn main() void { | 1090 | \\pub fn main() void { |
test/stage1/behavior.zig deleted-145| ... | @@ -1,145 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | |||
| 3 | comptime { | ||
| 4 | _ = @import("behavior/align.zig"); | ||
| 5 | _ = @import("behavior/alignof.zig"); | ||
| 6 | _ = @import("behavior/array.zig"); | ||
| 7 | if (builtin.os.tag != .wasi) { | ||
| 8 | _ = @import("behavior/asm.zig"); | ||
| 9 | _ = @import("behavior/async_fn.zig"); | ||
| 10 | } | ||
| 11 | _ = @import("behavior/atomics.zig"); | ||
| 12 | _ = @import("behavior/await_struct.zig"); | ||
| 13 | _ = @import("behavior/bit_shifting.zig"); | ||
| 14 | _ = @import("behavior/bitcast.zig"); | ||
| 15 | _ = @import("behavior/bitreverse.zig"); | ||
| 16 | _ = @import("behavior/bool.zig"); | ||
| 17 | _ = @import("behavior/bugs/1025.zig"); | ||
| 18 | _ = @import("behavior/bugs/1076.zig"); | ||
| 19 | _ = @import("behavior/bugs/1111.zig"); | ||
| 20 | _ = @import("behavior/bugs/1120.zig"); | ||
| 21 | _ = @import("behavior/bugs/1277.zig"); | ||
| 22 | _ = @import("behavior/bugs/1310.zig"); | ||
| 23 | _ = @import("behavior/bugs/1322.zig"); | ||
| 24 | _ = @import("behavior/bugs/1381.zig"); | ||
| 25 | _ = @import("behavior/bugs/1421.zig"); | ||
| 26 | _ = @import("behavior/bugs/1442.zig"); | ||
| 27 | _ = @import("behavior/bugs/1486.zig"); | ||
| 28 | _ = @import("behavior/bugs/1500.zig"); | ||
| 29 | _ = @import("behavior/bugs/1607.zig"); | ||
| 30 | _ = @import("behavior/bugs/1735.zig"); | ||
| 31 | _ = @import("behavior/bugs/1741.zig"); | ||
| 32 | _ = @import("behavior/bugs/1851.zig"); | ||
| 33 | _ = @import("behavior/bugs/1914.zig"); | ||
| 34 | _ = @import("behavior/bugs/2006.zig"); | ||
| 35 | _ = @import("behavior/bugs/2114.zig"); | ||
| 36 | _ = @import("behavior/bugs/2346.zig"); | ||
| 37 | _ = @import("behavior/bugs/2578.zig"); | ||
| 38 | _ = @import("behavior/bugs/2692.zig"); | ||
| 39 | _ = @import("behavior/bugs/2889.zig"); | ||
| 40 | _ = @import("behavior/bugs/3007.zig"); | ||
| 41 | _ = @import("behavior/bugs/3046.zig"); | ||
| 42 | _ = @import("behavior/bugs/3112.zig"); | ||
| 43 | _ = @import("behavior/bugs/3367.zig"); | ||
| 44 | _ = @import("behavior/bugs/3384.zig"); | ||
| 45 | _ = @import("behavior/bugs/3586.zig"); | ||
| 46 | _ = @import("behavior/bugs/3742.zig"); | ||
| 47 | _ = @import("behavior/bugs/4328.zig"); | ||
| 48 | _ = @import("behavior/bugs/4560.zig"); | ||
| 49 | _ = @import("behavior/bugs/4769_a.zig"); | ||
| 50 | _ = @import("behavior/bugs/4769_b.zig"); | ||
| 51 | _ = @import("behavior/bugs/4769_c.zig"); | ||
| 52 | _ = @import("behavior/bugs/4954.zig"); | ||
| 53 | _ = @import("behavior/bugs/5398.zig"); | ||
| 54 | _ = @import("behavior/bugs/5413.zig"); | ||
| 55 | _ = @import("behavior/bugs/5474.zig"); | ||
| 56 | _ = @import("behavior/bugs/5487.zig"); | ||
| 57 | _ = @import("behavior/bugs/6456.zig"); | ||
| 58 | _ = @import("behavior/bugs/6781.zig"); | ||
| 59 | _ = @import("behavior/bugs/6850.zig"); | ||
| 60 | _ = @import("behavior/bugs/7027.zig"); | ||
| 61 | _ = @import("behavior/bugs/7047.zig"); | ||
| 62 | _ = @import("behavior/bugs/7003.zig"); | ||
| 63 | _ = @import("behavior/bugs/7250.zig"); | ||
| 64 | _ = @import("behavior/bugs/394.zig"); | ||
| 65 | _ = @import("behavior/bugs/421.zig"); | ||
| 66 | _ = @import("behavior/bugs/529.zig"); | ||
| 67 | _ = @import("behavior/bugs/624.zig"); | ||
| 68 | _ = @import("behavior/bugs/655.zig"); | ||
| 69 | _ = @import("behavior/bugs/656.zig"); | ||
| 70 | _ = @import("behavior/bugs/679.zig"); | ||
| 71 | _ = @import("behavior/bugs/704.zig"); | ||
| 72 | _ = @import("behavior/bugs/718.zig"); | ||
| 73 | _ = @import("behavior/bugs/726.zig"); | ||
| 74 | _ = @import("behavior/bugs/828.zig"); | ||
| 75 | _ = @import("behavior/bugs/920.zig"); | ||
| 76 | _ = @import("behavior/byteswap.zig"); | ||
| 77 | _ = @import("behavior/byval_arg_var.zig"); | ||
| 78 | _ = @import("behavior/call.zig"); | ||
| 79 | _ = @import("behavior/cast.zig"); | ||
| 80 | _ = @import("behavior/const_slice_child.zig"); | ||
| 81 | _ = @import("behavior/defer.zig"); | ||
| 82 | _ = @import("behavior/enum.zig"); | ||
| 83 | _ = @import("behavior/enum_with_members.zig"); | ||
| 84 | _ = @import("behavior/error.zig"); | ||
| 85 | _ = @import("behavior/eval.zig"); | ||
| 86 | _ = @import("behavior/field_parent_ptr.zig"); | ||
| 87 | _ = @import("behavior/floatop.zig"); | ||
| 88 | _ = @import("behavior/fn.zig"); | ||
| 89 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); | ||
| 90 | _ = @import("behavior/fn_delegation.zig"); | ||
| 91 | _ = @import("behavior/for.zig"); | ||
| 92 | _ = @import("behavior/generics.zig"); | ||
| 93 | _ = @import("behavior/hasdecl.zig"); | ||
| 94 | _ = @import("behavior/hasfield.zig"); | ||
| 95 | _ = @import("behavior/if.zig"); | ||
| 96 | _ = @import("behavior/import.zig"); | ||
| 97 | _ = @import("behavior/incomplete_struct_param_tld.zig"); | ||
| 98 | _ = @import("behavior/inttoptr.zig"); | ||
| 99 | _ = @import("behavior/ir_block_deps.zig"); | ||
| 100 | _ = @import("behavior/math.zig"); | ||
| 101 | _ = @import("behavior/merge_error_sets.zig"); | ||
| 102 | _ = @import("behavior/misc.zig"); | ||
| 103 | _ = @import("behavior/muladd.zig"); | ||
| 104 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | ||
| 105 | _ = @import("behavior/null.zig"); | ||
| 106 | _ = @import("behavior/optional.zig"); | ||
| 107 | _ = @import("behavior/pointers.zig"); | ||
| 108 | _ = @import("behavior/popcount.zig"); | ||
| 109 | _ = @import("behavior/ptrcast.zig"); | ||
| 110 | _ = @import("behavior/pub_enum.zig"); | ||
| 111 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | ||
| 112 | _ = @import("behavior/reflection.zig"); | ||
| 113 | _ = @import("behavior/shuffle.zig"); | ||
| 114 | _ = @import("behavior/sizeof_and_typeof.zig"); | ||
| 115 | _ = @import("behavior/slice.zig"); | ||
| 116 | _ = @import("behavior/slice_sentinel_comptime.zig"); | ||
| 117 | _ = @import("behavior/struct.zig"); | ||
| 118 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | ||
| 119 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | ||
| 120 | _ = @import("behavior/switch.zig"); | ||
| 121 | _ = @import("behavior/switch_prong_err_enum.zig"); | ||
| 122 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | ||
| 123 | _ = @import("behavior/syntax.zig"); | ||
| 124 | _ = @import("behavior/this.zig"); | ||
| 125 | _ = @import("behavior/truncate.zig"); | ||
| 126 | _ = @import("behavior/try.zig"); | ||
| 127 | _ = @import("behavior/tuple.zig"); | ||
| 128 | _ = @import("behavior/type.zig"); | ||
| 129 | _ = @import("behavior/type_info.zig"); | ||
| 130 | _ = @import("behavior/typename.zig"); | ||
| 131 | _ = @import("behavior/undefined.zig"); | ||
| 132 | _ = @import("behavior/underscore.zig"); | ||
| 133 | _ = @import("behavior/union.zig"); | ||
| 134 | _ = @import("behavior/usingnamespace.zig"); | ||
| 135 | _ = @import("behavior/var_args.zig"); | ||
| 136 | _ = @import("behavior/vector.zig"); | ||
| 137 | _ = @import("behavior/void.zig"); | ||
| 138 | if (builtin.arch == .wasm32) { | ||
| 139 | _ = @import("behavior/wasm.zig"); | ||
| 140 | } | ||
| 141 | _ = @import("behavior/while.zig"); | ||
| 142 | _ = @import("behavior/widening.zig"); | ||
| 143 | _ = @import("behavior/src.zig"); | ||
| 144 | _ = @import("behavior/translate_c_macros.zig"); | ||
| 145 | } | ||
test/stage1/behavior/align.zig deleted-349| ... | @@ -1,349 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | |||
| 5 | var foo: u8 align(4) = 100; | ||
| 6 | |||
| 7 | test "global variable alignment" { | ||
| 8 | comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); | ||
| 9 | comptime try expect(@TypeOf(&foo) == *align(4) u8); | ||
| 10 | { | ||
| 11 | const slice = @as(*[1]u8, &foo)[0..]; | ||
| 12 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 13 | } | ||
| 14 | { | ||
| 15 | var runtime_zero: usize = 0; | ||
| 16 | const slice = @as(*[1]u8, &foo)[runtime_zero..]; | ||
| 17 | comptime try expect(@TypeOf(slice) == []align(4) u8); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | fn derp() align(@sizeOf(usize) * 2) i32 { | ||
| 22 | return 1234; | ||
| 23 | } | ||
| 24 | fn noop1() align(1) void {} | ||
| 25 | fn noop4() align(4) void {} | ||
| 26 | |||
| 27 | test "function alignment" { | ||
| 28 | // function alignment is a compile error on wasm32/wasm64 | ||
| 29 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 30 | |||
| 31 | try expect(derp() == 1234); | ||
| 32 | try expect(@TypeOf(noop1) == fn () align(1) void); | ||
| 33 | try expect(@TypeOf(noop4) == fn () align(4) void); | ||
| 34 | noop1(); | ||
| 35 | noop4(); | ||
| 36 | } | ||
| 37 | |||
| 38 | var baz: packed struct { | ||
| 39 | a: u32, | ||
| 40 | b: u32, | ||
| 41 | } = undefined; | ||
| 42 | |||
| 43 | test "packed struct alignment" { | ||
| 44 | try expect(@TypeOf(&baz.b) == *align(1) u32); | ||
| 45 | } | ||
| 46 | |||
| 47 | const blah: packed struct { | ||
| 48 | a: u3, | ||
| 49 | b: u3, | ||
| 50 | c: u2, | ||
| 51 | } = undefined; | ||
| 52 | |||
| 53 | test "bit field alignment" { | ||
| 54 | try expect(@TypeOf(&blah.b) == *align(1:3:1) const u3); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "default alignment allows unspecified in type syntax" { | ||
| 58 | try expect(*u32 == *align(@alignOf(u32)) u32); | ||
| 59 | } | ||
| 60 | |||
| 61 | test "implicitly decreasing pointer alignment" { | ||
| 62 | const a: u32 align(4) = 3; | ||
| 63 | const b: u32 align(8) = 4; | ||
| 64 | try expect(addUnaligned(&a, &b) == 7); | ||
| 65 | } | ||
| 66 | |||
| 67 | fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { | ||
| 68 | return a.* + b.*; | ||
| 69 | } | ||
| 70 | |||
| 71 | test "implicitly decreasing slice alignment" { | ||
| 72 | const a: u32 align(4) = 3; | ||
| 73 | const b: u32 align(8) = 4; | ||
| 74 | try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7); | ||
| 75 | } | ||
| 76 | fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { | ||
| 77 | return a[0] + b[0]; | ||
| 78 | } | ||
| 79 | |||
| 80 | test "specifying alignment allows pointer cast" { | ||
| 81 | try testBytesAlign(0x33); | ||
| 82 | } | ||
| 83 | fn testBytesAlign(b: u8) !void { | ||
| 84 | var bytes align(4) = [_]u8{ | ||
| 85 | b, | ||
| 86 | b, | ||
| 87 | b, | ||
| 88 | b, | ||
| 89 | }; | ||
| 90 | const ptr = @ptrCast(*u32, &bytes[0]); | ||
| 91 | try expect(ptr.* == 0x33333333); | ||
| 92 | } | ||
| 93 | |||
| 94 | test "@alignCast pointers" { | ||
| 95 | var x: u32 align(4) = 1; | ||
| 96 | expectsOnly1(&x); | ||
| 97 | try expect(x == 2); | ||
| 98 | } | ||
| 99 | fn expectsOnly1(x: *align(1) u32) void { | ||
| 100 | expects4(@alignCast(4, x)); | ||
| 101 | } | ||
| 102 | fn expects4(x: *align(4) u32) void { | ||
| 103 | x.* += 1; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "@alignCast slices" { | ||
| 107 | var array align(4) = [_]u32{ | ||
| 108 | 1, | ||
| 109 | 1, | ||
| 110 | }; | ||
| 111 | const slice = array[0..]; | ||
| 112 | sliceExpectsOnly1(slice); | ||
| 113 | try expect(slice[0] == 2); | ||
| 114 | } | ||
| 115 | fn sliceExpectsOnly1(slice: []align(1) u32) void { | ||
| 116 | sliceExpects4(@alignCast(4, slice)); | ||
| 117 | } | ||
| 118 | fn sliceExpects4(slice: []align(4) u32) void { | ||
| 119 | slice[0] += 1; | ||
| 120 | } | ||
| 121 | |||
| 122 | test "implicitly decreasing fn alignment" { | ||
| 123 | // function alignment is a compile error on wasm32/wasm64 | ||
| 124 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 125 | |||
| 126 | try testImplicitlyDecreaseFnAlign(alignedSmall, 1234); | ||
| 127 | try testImplicitlyDecreaseFnAlign(alignedBig, 5678); | ||
| 128 | } | ||
| 129 | |||
| 130 | fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) !void { | ||
| 131 | try expect(ptr() == answer); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn alignedSmall() align(8) i32 { | ||
| 135 | return 1234; | ||
| 136 | } | ||
| 137 | fn alignedBig() align(16) i32 { | ||
| 138 | return 5678; | ||
| 139 | } | ||
| 140 | |||
| 141 | test "@alignCast functions" { | ||
| 142 | // function alignment is a compile error on wasm32/wasm64 | ||
| 143 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 144 | if (builtin.arch == .thumb) return error.SkipZigTest; | ||
| 145 | |||
| 146 | try expect(fnExpectsOnly1(simple4) == 0x19); | ||
| 147 | } | ||
| 148 | fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { | ||
| 149 | return fnExpects4(@alignCast(4, ptr)); | ||
| 150 | } | ||
| 151 | fn fnExpects4(ptr: fn () align(4) i32) i32 { | ||
| 152 | return ptr(); | ||
| 153 | } | ||
| 154 | fn simple4() align(4) i32 { | ||
| 155 | return 0x19; | ||
| 156 | } | ||
| 157 | |||
| 158 | test "generic function with align param" { | ||
| 159 | // function alignment is a compile error on wasm32/wasm64 | ||
| 160 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 161 | if (builtin.arch == .thumb) return error.SkipZigTest; | ||
| 162 | |||
| 163 | try expect(whyWouldYouEverDoThis(1) == 0x1); | ||
| 164 | try expect(whyWouldYouEverDoThis(4) == 0x1); | ||
| 165 | try expect(whyWouldYouEverDoThis(8) == 0x1); | ||
| 166 | } | ||
| 167 | |||
| 168 | fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { | ||
| 169 | return 0x1; | ||
| 170 | } | ||
| 171 | |||
| 172 | test "@ptrCast preserves alignment of bigger source" { | ||
| 173 | var x: u32 align(16) = 1234; | ||
| 174 | const ptr = @ptrCast(*u8, &x); | ||
| 175 | try expect(@TypeOf(ptr) == *align(16) u8); | ||
| 176 | } | ||
| 177 | |||
| 178 | test "runtime known array index has best alignment possible" { | ||
| 179 | // take full advantage of over-alignment | ||
| 180 | var array align(4) = [_]u8{ 1, 2, 3, 4 }; | ||
| 181 | try expect(@TypeOf(&array[0]) == *align(4) u8); | ||
| 182 | try expect(@TypeOf(&array[1]) == *u8); | ||
| 183 | try expect(@TypeOf(&array[2]) == *align(2) u8); | ||
| 184 | try expect(@TypeOf(&array[3]) == *u8); | ||
| 185 | |||
| 186 | // because align is too small but we still figure out to use 2 | ||
| 187 | var bigger align(2) = [_]u64{ 1, 2, 3, 4 }; | ||
| 188 | try expect(@TypeOf(&bigger[0]) == *align(2) u64); | ||
| 189 | try expect(@TypeOf(&bigger[1]) == *align(2) u64); | ||
| 190 | try expect(@TypeOf(&bigger[2]) == *align(2) u64); | ||
| 191 | try expect(@TypeOf(&bigger[3]) == *align(2) u64); | ||
| 192 | |||
| 193 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | ||
| 194 | var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; | ||
| 195 | var runtime_zero: usize = 0; | ||
| 196 | comptime try expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); | ||
| 197 | comptime try expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); | ||
| 198 | try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); | ||
| 199 | try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); | ||
| 200 | try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); | ||
| 201 | try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); | ||
| 202 | |||
| 203 | // has to use ABI alignment because index known at runtime only | ||
| 204 | try testIndex2(array[runtime_zero..].ptr, 0, *u8); | ||
| 205 | try testIndex2(array[runtime_zero..].ptr, 1, *u8); | ||
| 206 | try testIndex2(array[runtime_zero..].ptr, 2, *u8); | ||
| 207 | try testIndex2(array[runtime_zero..].ptr, 3, *u8); | ||
| 208 | } | ||
| 209 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void { | ||
| 210 | comptime try expect(@TypeOf(&smaller[index]) == T); | ||
| 211 | } | ||
| 212 | fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void { | ||
| 213 | comptime try expect(@TypeOf(&ptr[index]) == T); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "alignstack" { | ||
| 217 | try expect(fnWithAlignedStack() == 1234); | ||
| 218 | } | ||
| 219 | |||
| 220 | fn fnWithAlignedStack() i32 { | ||
| 221 | @setAlignStack(256); | ||
| 222 | return 1234; | ||
| 223 | } | ||
| 224 | |||
| 225 | test "alignment of structs" { | ||
| 226 | try expect(@alignOf(struct { | ||
| 227 | a: i32, | ||
| 228 | b: *i32, | ||
| 229 | }) == @alignOf(usize)); | ||
| 230 | } | ||
| 231 | |||
| 232 | test "alignment of function with c calling convention" { | ||
| 233 | var runtime_nothing = nothing; | ||
| 234 | const casted1 = @ptrCast(*const u8, runtime_nothing); | ||
| 235 | const casted2 = @ptrCast(fn () callconv(.C) void, casted1); | ||
| 236 | casted2(); | ||
| 237 | } | ||
| 238 | |||
| 239 | fn nothing() callconv(.C) void {} | ||
| 240 | |||
| 241 | test "return error union with 128-bit integer" { | ||
| 242 | try expect(3 == try give()); | ||
| 243 | } | ||
| 244 | fn give() anyerror!u128 { | ||
| 245 | return 3; | ||
| 246 | } | ||
| 247 | |||
| 248 | test "alignment of >= 128-bit integer type" { | ||
| 249 | try expect(@alignOf(u128) == 16); | ||
| 250 | try expect(@alignOf(u129) == 16); | ||
| 251 | } | ||
| 252 | |||
| 253 | test "alignment of struct with 128-bit field" { | ||
| 254 | try expect(@alignOf(struct { | ||
| 255 | x: u128, | ||
| 256 | }) == 16); | ||
| 257 | |||
| 258 | comptime { | ||
| 259 | try expect(@alignOf(struct { | ||
| 260 | x: u128, | ||
| 261 | }) == 16); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | test "size of extern struct with 128-bit field" { | ||
| 266 | try expect(@sizeOf(extern struct { | ||
| 267 | x: u128, | ||
| 268 | y: u8, | ||
| 269 | }) == 32); | ||
| 270 | |||
| 271 | comptime { | ||
| 272 | try expect(@sizeOf(extern struct { | ||
| 273 | x: u128, | ||
| 274 | y: u8, | ||
| 275 | }) == 32); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | const DefaultAligned = struct { | ||
| 280 | nevermind: u32, | ||
| 281 | badguy: i128, | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "read 128-bit field from default aligned struct in stack memory" { | ||
| 285 | var default_aligned = DefaultAligned{ | ||
| 286 | .nevermind = 1, | ||
| 287 | .badguy = 12, | ||
| 288 | }; | ||
| 289 | try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0); | ||
| 290 | try expect(12 == default_aligned.badguy); | ||
| 291 | } | ||
| 292 | |||
| 293 | var default_aligned_global = DefaultAligned{ | ||
| 294 | .nevermind = 1, | ||
| 295 | .badguy = 12, | ||
| 296 | }; | ||
| 297 | |||
| 298 | test "read 128-bit field from default aligned struct in global memory" { | ||
| 299 | try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); | ||
| 300 | try expect(12 == default_aligned_global.badguy); | ||
| 301 | } | ||
| 302 | |||
| 303 | test "struct field explicit alignment" { | ||
| 304 | const S = struct { | ||
| 305 | const Node = struct { | ||
| 306 | next: *Node, | ||
| 307 | massive_byte: u8 align(64), | ||
| 308 | }; | ||
| 309 | }; | ||
| 310 | |||
| 311 | var node: S.Node = undefined; | ||
| 312 | node.massive_byte = 100; | ||
| 313 | try expect(node.massive_byte == 100); | ||
| 314 | comptime try expect(@TypeOf(&node.massive_byte) == *align(64) u8); | ||
| 315 | try expect(@ptrToInt(&node.massive_byte) % 64 == 0); | ||
| 316 | } | ||
| 317 | |||
| 318 | test "align(@alignOf(T)) T does not force resolution of T" { | ||
| 319 | const S = struct { | ||
| 320 | const A = struct { | ||
| 321 | a: *align(@alignOf(A)) A, | ||
| 322 | }; | ||
| 323 | fn doTheTest() void { | ||
| 324 | suspend { | ||
| 325 | resume @frame(); | ||
| 326 | } | ||
| 327 | _ = bar(@Frame(doTheTest)); | ||
| 328 | } | ||
| 329 | fn bar(comptime T: type) *align(@alignOf(T)) T { | ||
| 330 | ok = true; | ||
| 331 | return undefined; | ||
| 332 | } | ||
| 333 | |||
| 334 | var ok = false; | ||
| 335 | }; | ||
| 336 | _ = async S.doTheTest(); | ||
| 337 | try expect(S.ok); | ||
| 338 | } | ||
| 339 | |||
| 340 | test "align(N) on functions" { | ||
| 341 | // function alignment is a compile error on wasm32/wasm64 | ||
| 342 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 343 | if (builtin.arch == .thumb) return error.SkipZigTest; | ||
| 344 | |||
| 345 | try expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); | ||
| 346 | } | ||
| 347 | fn overaligned_fn() align(0x1000) i32 { | ||
| 348 | return 42; | ||
| 349 | } | ||
test/stage1/behavior/alignof.zig deleted-38| ... | @@ -1,38 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | |||
| 6 | const Foo = struct { | ||
| 7 | x: u32, | ||
| 8 | y: u32, | ||
| 9 | z: u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "@alignOf(T) before referencing T" { | ||
| 13 | comptime try expect(@alignOf(Foo) != maxInt(usize)); | ||
| 14 | if (builtin.arch == builtin.Arch.x86_64) { | ||
| 15 | comptime try expect(@alignOf(Foo) == 4); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | test "comparison of @alignOf(T) against zero" { | ||
| 20 | { | ||
| 21 | const T = struct { x: u32 }; | ||
| 22 | try expect(!(@alignOf(T) == 0)); | ||
| 23 | try expect(@alignOf(T) != 0); | ||
| 24 | try expect(!(@alignOf(T) < 0)); | ||
| 25 | try expect(!(@alignOf(T) <= 0)); | ||
| 26 | try expect(@alignOf(T) > 0); | ||
| 27 | try expect(@alignOf(T) >= 0); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | const T = struct {}; | ||
| 31 | try expect(@alignOf(T) == 0); | ||
| 32 | try expect(!(@alignOf(T) != 0)); | ||
| 33 | try expect(!(@alignOf(T) < 0)); | ||
| 34 | try expect(@alignOf(T) <= 0); | ||
| 35 | try expect(!(@alignOf(T) > 0)); | ||
| 36 | try expect(@alignOf(T) >= 0); | ||
| 37 | } | ||
| 38 | } | ||
test/stage1/behavior/array.zig deleted-489| ... | @@ -1,489 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const mem = std.mem; | ||
| 4 | const expect = testing.expect; | ||
| 5 | const expectEqual = testing.expectEqual; | ||
| 6 | |||
| 7 | test "arrays" { | ||
| 8 | var array: [5]u32 = undefined; | ||
| 9 | |||
| 10 | var i: u32 = 0; | ||
| 11 | while (i < 5) { | ||
| 12 | array[i] = i + 1; | ||
| 13 | i = array[i]; | ||
| 14 | } | ||
| 15 | |||
| 16 | i = 0; | ||
| 17 | var accumulator = @as(u32, 0); | ||
| 18 | while (i < 5) { | ||
| 19 | accumulator += array[i]; | ||
| 20 | |||
| 21 | i += 1; | ||
| 22 | } | ||
| 23 | |||
| 24 | try expect(accumulator == 15); | ||
| 25 | try expect(getArrayLen(&array) == 5); | ||
| 26 | } | ||
| 27 | fn getArrayLen(a: []const u32) usize { | ||
| 28 | return a.len; | ||
| 29 | } | ||
| 30 | |||
| 31 | test "array with sentinels" { | ||
| 32 | const S = struct { | ||
| 33 | fn doTheTest(is_ct: bool) !void { | ||
| 34 | if (is_ct) { | ||
| 35 | var zero_sized: [0:0xde]u8 = [_:0xde]u8{}; | ||
| 36 | // Disabled at runtime because of | ||
| 37 | // https://github.com/ziglang/zig/issues/4372 | ||
| 38 | try expectEqual(@as(u8, 0xde), zero_sized[0]); | ||
| 39 | var reinterpreted = @ptrCast(*[1]u8, &zero_sized); | ||
| 40 | try expectEqual(@as(u8, 0xde), reinterpreted[0]); | ||
| 41 | } | ||
| 42 | var arr: [3:0x55]u8 = undefined; | ||
| 43 | // Make sure the sentinel pointer is pointing after the last element | ||
| 44 | if (!is_ct) { | ||
| 45 | const sentinel_ptr = @ptrToInt(&arr[3]); | ||
| 46 | const last_elem_ptr = @ptrToInt(&arr[2]); | ||
| 47 | try expectEqual(@as(usize, 1), sentinel_ptr - last_elem_ptr); | ||
| 48 | } | ||
| 49 | // Make sure the sentinel is writeable | ||
| 50 | arr[3] = 0x55; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | try S.doTheTest(false); | ||
| 55 | comptime try S.doTheTest(true); | ||
| 56 | } | ||
| 57 | |||
| 58 | test "void arrays" { | ||
| 59 | var array: [4]void = undefined; | ||
| 60 | array[0] = void{}; | ||
| 61 | array[1] = array[2]; | ||
| 62 | try expect(@sizeOf(@TypeOf(array)) == 0); | ||
| 63 | try expect(array.len == 4); | ||
| 64 | } | ||
| 65 | |||
| 66 | test "array literal" { | ||
| 67 | const hex_mult = [_]u16{ | ||
| 68 | 4096, | ||
| 69 | 256, | ||
| 70 | 16, | ||
| 71 | 1, | ||
| 72 | }; | ||
| 73 | |||
| 74 | try expect(hex_mult.len == 4); | ||
| 75 | try expect(hex_mult[1] == 256); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "array dot len const expr" { | ||
| 79 | try expect(comptime x: { | ||
| 80 | break :x some_array.len == 4; | ||
| 81 | }); | ||
| 82 | } | ||
| 83 | |||
| 84 | const ArrayDotLenConstExpr = struct { | ||
| 85 | y: [some_array.len]u8, | ||
| 86 | }; | ||
| 87 | const some_array = [_]u8{ | ||
| 88 | 0, | ||
| 89 | 1, | ||
| 90 | 2, | ||
| 91 | 3, | ||
| 92 | }; | ||
| 93 | |||
| 94 | test "nested arrays" { | ||
| 95 | const array_of_strings = [_][]const u8{ | ||
| 96 | "hello", | ||
| 97 | "this", | ||
| 98 | "is", | ||
| 99 | "my", | ||
| 100 | "thing", | ||
| 101 | }; | ||
| 102 | for (array_of_strings) |s, i| { | ||
| 103 | if (i == 0) try expect(mem.eql(u8, s, "hello")); | ||
| 104 | if (i == 1) try expect(mem.eql(u8, s, "this")); | ||
| 105 | if (i == 2) try expect(mem.eql(u8, s, "is")); | ||
| 106 | if (i == 3) try expect(mem.eql(u8, s, "my")); | ||
| 107 | if (i == 4) try expect(mem.eql(u8, s, "thing")); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | var s_array: [8]Sub = undefined; | ||
| 112 | const Sub = struct { | ||
| 113 | b: u8, | ||
| 114 | }; | ||
| 115 | const Str = struct { | ||
| 116 | a: []Sub, | ||
| 117 | }; | ||
| 118 | test "set global var array via slice embedded in struct" { | ||
| 119 | var s = Str{ .a = s_array[0..] }; | ||
| 120 | |||
| 121 | s.a[0].b = 1; | ||
| 122 | s.a[1].b = 2; | ||
| 123 | s.a[2].b = 3; | ||
| 124 | |||
| 125 | try expect(s_array[0].b == 1); | ||
| 126 | try expect(s_array[1].b == 2); | ||
| 127 | try expect(s_array[2].b == 3); | ||
| 128 | } | ||
| 129 | |||
| 130 | test "array literal with specified size" { | ||
| 131 | var array = [2]u8{ | ||
| 132 | 1, | ||
| 133 | 2, | ||
| 134 | }; | ||
| 135 | try expect(array[0] == 1); | ||
| 136 | try expect(array[1] == 2); | ||
| 137 | } | ||
| 138 | |||
| 139 | test "array len field" { | ||
| 140 | var arr = [4]u8{ 0, 0, 0, 0 }; | ||
| 141 | var ptr = &arr; | ||
| 142 | try expect(arr.len == 4); | ||
| 143 | comptime try expect(arr.len == 4); | ||
| 144 | try expect(ptr.len == 4); | ||
| 145 | comptime try expect(ptr.len == 4); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "single-item pointer to array indexing and slicing" { | ||
| 149 | try testSingleItemPtrArrayIndexSlice(); | ||
| 150 | comptime try testSingleItemPtrArrayIndexSlice(); | ||
| 151 | } | ||
| 152 | |||
| 153 | fn testSingleItemPtrArrayIndexSlice() !void { | ||
| 154 | { | ||
| 155 | var array: [4]u8 = "aaaa".*; | ||
| 156 | doSomeMangling(&array); | ||
| 157 | try expect(mem.eql(u8, "azya", &array)); | ||
| 158 | } | ||
| 159 | { | ||
| 160 | var array = "aaaa".*; | ||
| 161 | doSomeMangling(&array); | ||
| 162 | try expect(mem.eql(u8, "azya", &array)); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | fn doSomeMangling(array: *[4]u8) void { | ||
| 167 | array[1] = 'z'; | ||
| 168 | array[2..3][0] = 'y'; | ||
| 169 | } | ||
| 170 | |||
| 171 | test "implicit cast single-item pointer" { | ||
| 172 | try testImplicitCastSingleItemPtr(); | ||
| 173 | comptime try testImplicitCastSingleItemPtr(); | ||
| 174 | } | ||
| 175 | |||
| 176 | fn testImplicitCastSingleItemPtr() !void { | ||
| 177 | var byte: u8 = 100; | ||
| 178 | const slice = @as(*[1]u8, &byte)[0..]; | ||
| 179 | slice[0] += 1; | ||
| 180 | try expect(byte == 101); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn testArrayByValAtComptime(b: [2]u8) u8 { | ||
| 184 | return b[0]; | ||
| 185 | } | ||
| 186 | |||
| 187 | test "comptime evalutating function that takes array by value" { | ||
| 188 | const arr = [_]u8{ 0, 1 }; | ||
| 189 | _ = comptime testArrayByValAtComptime(arr); | ||
| 190 | _ = comptime testArrayByValAtComptime(arr); | ||
| 191 | } | ||
| 192 | |||
| 193 | test "implicit comptime in array type size" { | ||
| 194 | var arr: [plusOne(10)]bool = undefined; | ||
| 195 | try expect(arr.len == 11); | ||
| 196 | } | ||
| 197 | |||
| 198 | fn plusOne(x: u32) u32 { | ||
| 199 | return x + 1; | ||
| 200 | } | ||
| 201 | |||
| 202 | test "runtime initialize array elem and then implicit cast to slice" { | ||
| 203 | var two: i32 = 2; | ||
| 204 | const x: []const i32 = &[_]i32{two}; | ||
| 205 | try expect(x[0] == 2); | ||
| 206 | } | ||
| 207 | |||
| 208 | test "array literal as argument to function" { | ||
| 209 | const S = struct { | ||
| 210 | fn entry(two: i32) !void { | ||
| 211 | try foo(&[_]i32{ | ||
| 212 | 1, | ||
| 213 | 2, | ||
| 214 | 3, | ||
| 215 | }); | ||
| 216 | try foo(&[_]i32{ | ||
| 217 | 1, | ||
| 218 | two, | ||
| 219 | 3, | ||
| 220 | }); | ||
| 221 | try foo2(true, &[_]i32{ | ||
| 222 | 1, | ||
| 223 | 2, | ||
| 224 | 3, | ||
| 225 | }); | ||
| 226 | try foo2(true, &[_]i32{ | ||
| 227 | 1, | ||
| 228 | two, | ||
| 229 | 3, | ||
| 230 | }); | ||
| 231 | } | ||
| 232 | fn foo(x: []const i32) !void { | ||
| 233 | try expect(x[0] == 1); | ||
| 234 | try expect(x[1] == 2); | ||
| 235 | try expect(x[2] == 3); | ||
| 236 | } | ||
| 237 | fn foo2(trash: bool, x: []const i32) !void { | ||
| 238 | try expect(trash); | ||
| 239 | try expect(x[0] == 1); | ||
| 240 | try expect(x[1] == 2); | ||
| 241 | try expect(x[2] == 3); | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | try S.entry(2); | ||
| 245 | comptime try S.entry(2); | ||
| 246 | } | ||
| 247 | |||
| 248 | test "double nested array to const slice cast in array literal" { | ||
| 249 | const S = struct { | ||
| 250 | fn entry(two: i32) !void { | ||
| 251 | const cases = [_][]const []const i32{ | ||
| 252 | &[_][]const i32{&[_]i32{1}}, | ||
| 253 | &[_][]const i32{&[_]i32{ 2, 3 }}, | ||
| 254 | &[_][]const i32{ | ||
| 255 | &[_]i32{4}, | ||
| 256 | &[_]i32{ 5, 6, 7 }, | ||
| 257 | }, | ||
| 258 | }; | ||
| 259 | try check(&cases); | ||
| 260 | |||
| 261 | const cases2 = [_][]const i32{ | ||
| 262 | &[_]i32{1}, | ||
| 263 | &[_]i32{ two, 3 }, | ||
| 264 | }; | ||
| 265 | try expect(cases2.len == 2); | ||
| 266 | try expect(cases2[0].len == 1); | ||
| 267 | try expect(cases2[0][0] == 1); | ||
| 268 | try expect(cases2[1].len == 2); | ||
| 269 | try expect(cases2[1][0] == 2); | ||
| 270 | try expect(cases2[1][1] == 3); | ||
| 271 | |||
| 272 | const cases3 = [_][]const []const i32{ | ||
| 273 | &[_][]const i32{&[_]i32{1}}, | ||
| 274 | &[_][]const i32{&[_]i32{ two, 3 }}, | ||
| 275 | &[_][]const i32{ | ||
| 276 | &[_]i32{4}, | ||
| 277 | &[_]i32{ 5, 6, 7 }, | ||
| 278 | }, | ||
| 279 | }; | ||
| 280 | try check(&cases3); | ||
| 281 | } | ||
| 282 | |||
| 283 | fn check(cases: []const []const []const i32) !void { | ||
| 284 | try expect(cases.len == 3); | ||
| 285 | try expect(cases[0].len == 1); | ||
| 286 | try expect(cases[0][0].len == 1); | ||
| 287 | try expect(cases[0][0][0] == 1); | ||
| 288 | try expect(cases[1].len == 1); | ||
| 289 | try expect(cases[1][0].len == 2); | ||
| 290 | try expect(cases[1][0][0] == 2); | ||
| 291 | try expect(cases[1][0][1] == 3); | ||
| 292 | try expect(cases[2].len == 2); | ||
| 293 | try expect(cases[2][0].len == 1); | ||
| 294 | try expect(cases[2][0][0] == 4); | ||
| 295 | try expect(cases[2][1].len == 3); | ||
| 296 | try expect(cases[2][1][0] == 5); | ||
| 297 | try expect(cases[2][1][1] == 6); | ||
| 298 | try expect(cases[2][1][2] == 7); | ||
| 299 | } | ||
| 300 | }; | ||
| 301 | try S.entry(2); | ||
| 302 | comptime try S.entry(2); | ||
| 303 | } | ||
| 304 | |||
| 305 | test "read/write through global variable array of struct fields initialized via array mult" { | ||
| 306 | const S = struct { | ||
| 307 | fn doTheTest() !void { | ||
| 308 | try expect(storage[0].term == 1); | ||
| 309 | storage[0] = MyStruct{ .term = 123 }; | ||
| 310 | try expect(storage[0].term == 123); | ||
| 311 | } | ||
| 312 | |||
| 313 | pub const MyStruct = struct { | ||
| 314 | term: usize, | ||
| 315 | }; | ||
| 316 | |||
| 317 | var storage: [1]MyStruct = [_]MyStruct{MyStruct{ .term = 1 }} ** 1; | ||
| 318 | }; | ||
| 319 | try S.doTheTest(); | ||
| 320 | } | ||
| 321 | |||
| 322 | test "implicit cast zero sized array ptr to slice" { | ||
| 323 | { | ||
| 324 | var b = "".*; | ||
| 325 | const c: []const u8 = &b; | ||
| 326 | try expect(c.len == 0); | ||
| 327 | } | ||
| 328 | { | ||
| 329 | var b: [0]u8 = "".*; | ||
| 330 | const c: []const u8 = &b; | ||
| 331 | try expect(c.len == 0); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | test "anonymous list literal syntax" { | ||
| 336 | const S = struct { | ||
| 337 | fn doTheTest() !void { | ||
| 338 | var array: [4]u8 = .{ 1, 2, 3, 4 }; | ||
| 339 | try expect(array[0] == 1); | ||
| 340 | try expect(array[1] == 2); | ||
| 341 | try expect(array[2] == 3); | ||
| 342 | try expect(array[3] == 4); | ||
| 343 | } | ||
| 344 | }; | ||
| 345 | try S.doTheTest(); | ||
| 346 | comptime try S.doTheTest(); | ||
| 347 | } | ||
| 348 | |||
| 349 | test "anonymous literal in array" { | ||
| 350 | const S = struct { | ||
| 351 | const Foo = struct { | ||
| 352 | a: usize = 2, | ||
| 353 | b: usize = 4, | ||
| 354 | }; | ||
| 355 | fn doTheTest() !void { | ||
| 356 | var array: [2]Foo = .{ | ||
| 357 | .{ .a = 3 }, | ||
| 358 | .{ .b = 3 }, | ||
| 359 | }; | ||
| 360 | try expect(array[0].a == 3); | ||
| 361 | try expect(array[0].b == 4); | ||
| 362 | try expect(array[1].a == 2); | ||
| 363 | try expect(array[1].b == 3); | ||
| 364 | } | ||
| 365 | }; | ||
| 366 | try S.doTheTest(); | ||
| 367 | comptime try S.doTheTest(); | ||
| 368 | } | ||
| 369 | |||
| 370 | test "access the null element of a null terminated array" { | ||
| 371 | const S = struct { | ||
| 372 | fn doTheTest() !void { | ||
| 373 | var array: [4:0]u8 = .{ 'a', 'o', 'e', 'u' }; | ||
| 374 | try expect(array[4] == 0); | ||
| 375 | var len: usize = 4; | ||
| 376 | try expect(array[len] == 0); | ||
| 377 | } | ||
| 378 | }; | ||
| 379 | try S.doTheTest(); | ||
| 380 | comptime try S.doTheTest(); | ||
| 381 | } | ||
| 382 | |||
| 383 | test "type deduction for array subscript expression" { | ||
| 384 | const S = struct { | ||
| 385 | fn doTheTest() !void { | ||
| 386 | var array = [_]u8{ 0x55, 0xAA }; | ||
| 387 | var v0 = true; | ||
| 388 | try expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]); | ||
| 389 | var v1 = false; | ||
| 390 | try expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]); | ||
| 391 | } | ||
| 392 | }; | ||
| 393 | try S.doTheTest(); | ||
| 394 | comptime try S.doTheTest(); | ||
| 395 | } | ||
| 396 | |||
| 397 | test "sentinel element count towards the ABI size calculation" { | ||
| 398 | const S = struct { | ||
| 399 | fn doTheTest() !void { | ||
| 400 | const T = packed struct { | ||
| 401 | fill_pre: u8 = 0x55, | ||
| 402 | data: [0:0]u8 = undefined, | ||
| 403 | fill_post: u8 = 0xAA, | ||
| 404 | }; | ||
| 405 | var x = T{}; | ||
| 406 | var as_slice = mem.asBytes(&x); | ||
| 407 | try expectEqual(@as(usize, 3), as_slice.len); | ||
| 408 | try expectEqual(@as(u8, 0x55), as_slice[0]); | ||
| 409 | try expectEqual(@as(u8, 0xAA), as_slice[2]); | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | |||
| 413 | try S.doTheTest(); | ||
| 414 | comptime try S.doTheTest(); | ||
| 415 | } | ||
| 416 | |||
| 417 | test "zero-sized array with recursive type definition" { | ||
| 418 | const U = struct { | ||
| 419 | fn foo(comptime T: type, comptime n: usize) type { | ||
| 420 | return struct { | ||
| 421 | s: [n]T, | ||
| 422 | x: usize = n, | ||
| 423 | }; | ||
| 424 | } | ||
| 425 | }; | ||
| 426 | |||
| 427 | const S = struct { | ||
| 428 | list: U.foo(@This(), 0), | ||
| 429 | }; | ||
| 430 | |||
| 431 | var t: S = .{ .list = .{ .s = undefined } }; | ||
| 432 | try expectEqual(@as(usize, 0), t.list.x); | ||
| 433 | } | ||
| 434 | |||
| 435 | test "type coercion of anon struct literal to array" { | ||
| 436 | const S = struct { | ||
| 437 | const U = union { | ||
| 438 | a: u32, | ||
| 439 | b: bool, | ||
| 440 | c: []const u8, | ||
| 441 | }; | ||
| 442 | |||
| 443 | fn doTheTest() !void { | ||
| 444 | var x1: u8 = 42; | ||
| 445 | const t1 = .{ x1, 56, 54 }; | ||
| 446 | var arr1: [3]u8 = t1; | ||
| 447 | try expect(arr1[0] == 42); | ||
| 448 | try expect(arr1[1] == 56); | ||
| 449 | try expect(arr1[2] == 54); | ||
| 450 | |||
| 451 | var x2: U = .{ .a = 42 }; | ||
| 452 | const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } }; | ||
| 453 | var arr2: [3]U = t2; | ||
| 454 | try expect(arr2[0].a == 42); | ||
| 455 | try expect(arr2[1].b == true); | ||
| 456 | try expect(mem.eql(u8, arr2[2].c, "hello")); | ||
| 457 | } | ||
| 458 | }; | ||
| 459 | try S.doTheTest(); | ||
| 460 | comptime try S.doTheTest(); | ||
| 461 | } | ||
| 462 | |||
| 463 | test "type coercion of pointer to anon struct literal to pointer to array" { | ||
| 464 | const S = struct { | ||
| 465 | const U = union { | ||
| 466 | a: u32, | ||
| 467 | b: bool, | ||
| 468 | c: []const u8, | ||
| 469 | }; | ||
| 470 | |||
| 471 | fn doTheTest() !void { | ||
| 472 | var x1: u8 = 42; | ||
| 473 | const t1 = &.{ x1, 56, 54 }; | ||
| 474 | var arr1: *const [3]u8 = t1; | ||
| 475 | try expect(arr1[0] == 42); | ||
| 476 | try expect(arr1[1] == 56); | ||
| 477 | try expect(arr1[2] == 54); | ||
| 478 | |||
| 479 | var x2: U = .{ .a = 42 }; | ||
| 480 | const t2 = &.{ x2, .{ .b = true }, .{ .c = "hello" } }; | ||
| 481 | var arr2: *const [3]U = t2; | ||
| 482 | try expect(arr2[0].a == 42); | ||
| 483 | try expect(arr2[1].b == true); | ||
| 484 | try expect(mem.eql(u8, arr2[2].c, "hello")); | ||
| 485 | } | ||
| 486 | }; | ||
| 487 | try S.doTheTest(); | ||
| 488 | comptime try S.doTheTest(); | ||
| 489 | } | ||
test/stage1/behavior/asm.zig deleted-109| ... | @@ -1,109 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const is_x86_64_linux = std.Target.current.cpu.arch == .x86_64 and std.Target.current.os.tag == .linux; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | if (is_x86_64_linux) { | ||
| 8 | asm ( | ||
| 9 | \\.globl this_is_my_alias; | ||
| 10 | \\.type this_is_my_alias, @function; | ||
| 11 | \\.set this_is_my_alias, derp; | ||
| 12 | ); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | test "module level assembly" { | ||
| 17 | if (is_x86_64_linux) { | ||
| 18 | try expect(this_is_my_alias() == 1234); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | test "output constraint modifiers" { | ||
| 23 | // This is only testing compilation. | ||
| 24 | var a: u32 = 3; | ||
| 25 | asm volatile ("" | ||
| 26 | : [_] "=m,r" (a) | ||
| 27 | : | ||
| 28 | : "" | ||
| 29 | ); | ||
| 30 | asm volatile ("" | ||
| 31 | : [_] "=r,m" (a) | ||
| 32 | : | ||
| 33 | : "" | ||
| 34 | ); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "alternative constraints" { | ||
| 38 | // Make sure we allow commas as a separator for alternative constraints. | ||
| 39 | var a: u32 = 3; | ||
| 40 | asm volatile ("" | ||
| 41 | : [_] "=r,m" (a) | ||
| 42 | : [_] "r,m" (a) | ||
| 43 | : "" | ||
| 44 | ); | ||
| 45 | } | ||
| 46 | |||
| 47 | test "sized integer/float in asm input" { | ||
| 48 | asm volatile ("" | ||
| 49 | : | ||
| 50 | : [_] "m" (@as(usize, 3)) | ||
| 51 | : "" | ||
| 52 | ); | ||
| 53 | asm volatile ("" | ||
| 54 | : | ||
| 55 | : [_] "m" (@as(i15, -3)) | ||
| 56 | : "" | ||
| 57 | ); | ||
| 58 | asm volatile ("" | ||
| 59 | : | ||
| 60 | : [_] "m" (@as(u3, 3)) | ||
| 61 | : "" | ||
| 62 | ); | ||
| 63 | asm volatile ("" | ||
| 64 | : | ||
| 65 | : [_] "m" (@as(i3, 3)) | ||
| 66 | : "" | ||
| 67 | ); | ||
| 68 | asm volatile ("" | ||
| 69 | : | ||
| 70 | : [_] "m" (@as(u121, 3)) | ||
| 71 | : "" | ||
| 72 | ); | ||
| 73 | asm volatile ("" | ||
| 74 | : | ||
| 75 | : [_] "m" (@as(i121, 3)) | ||
| 76 | : "" | ||
| 77 | ); | ||
| 78 | asm volatile ("" | ||
| 79 | : | ||
| 80 | : [_] "m" (@as(f32, 3.17)) | ||
| 81 | : "" | ||
| 82 | ); | ||
| 83 | asm volatile ("" | ||
| 84 | : | ||
| 85 | : [_] "m" (@as(f64, 3.17)) | ||
| 86 | : "" | ||
| 87 | ); | ||
| 88 | } | ||
| 89 | |||
| 90 | test "struct/array/union types as input values" { | ||
| 91 | asm volatile ("" | ||
| 92 | : | ||
| 93 | : [_] "m" (@as([1]u32, undefined)) | ||
| 94 | ); // fails | ||
| 95 | asm volatile ("" | ||
| 96 | : | ||
| 97 | : [_] "m" (@as(struct { x: u32, y: u8 }, undefined)) | ||
| 98 | ); // fails | ||
| 99 | asm volatile ("" | ||
| 100 | : | ||
| 101 | : [_] "m" (@as(union { x: u32, y: u8 }, undefined)) | ||
| 102 | ); // fails | ||
| 103 | } | ||
| 104 | |||
| 105 | extern fn this_is_my_alias() i32; | ||
| 106 | |||
| 107 | export fn derp() i32 { | ||
| 108 | return 1234; | ||
| 109 | } | ||
test/stage1/behavior/async_fn.zig deleted-1676| ... | @@ -1,1676 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 6 | const expectError = std.testing.expectError; | ||
| 7 | |||
| 8 | var global_x: i32 = 1; | ||
| 9 | |||
| 10 | test "simple coroutine suspend and resume" { | ||
| 11 | var frame = async simpleAsyncFn(); | ||
| 12 | try expect(global_x == 2); | ||
| 13 | resume frame; | ||
| 14 | try expect(global_x == 3); | ||
| 15 | const af: anyframe->void = &frame; | ||
| 16 | resume frame; | ||
| 17 | try expect(global_x == 4); | ||
| 18 | } | ||
| 19 | fn simpleAsyncFn() void { | ||
| 20 | global_x += 1; | ||
| 21 | suspend {} | ||
| 22 | global_x += 1; | ||
| 23 | suspend {} | ||
| 24 | global_x += 1; | ||
| 25 | } | ||
| 26 | |||
| 27 | var global_y: i32 = 1; | ||
| 28 | |||
| 29 | test "pass parameter to coroutine" { | ||
| 30 | var p = async simpleAsyncFnWithArg(2); | ||
| 31 | try expect(global_y == 3); | ||
| 32 | resume p; | ||
| 33 | try expect(global_y == 5); | ||
| 34 | } | ||
| 35 | fn simpleAsyncFnWithArg(delta: i32) void { | ||
| 36 | global_y += delta; | ||
| 37 | suspend {} | ||
| 38 | global_y += delta; | ||
| 39 | } | ||
| 40 | |||
| 41 | test "suspend at end of function" { | ||
| 42 | const S = struct { | ||
| 43 | var x: i32 = 1; | ||
| 44 | |||
| 45 | fn doTheTest() !void { | ||
| 46 | try expect(x == 1); | ||
| 47 | const p = async suspendAtEnd(); | ||
| 48 | try expect(x == 2); | ||
| 49 | } | ||
| 50 | |||
| 51 | fn suspendAtEnd() void { | ||
| 52 | x += 1; | ||
| 53 | suspend {} | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | try S.doTheTest(); | ||
| 57 | } | ||
| 58 | |||
| 59 | test "local variable in async function" { | ||
| 60 | const S = struct { | ||
| 61 | var x: i32 = 0; | ||
| 62 | |||
| 63 | fn doTheTest() !void { | ||
| 64 | try expect(x == 0); | ||
| 65 | var p = async add(1, 2); | ||
| 66 | try expect(x == 0); | ||
| 67 | resume p; | ||
| 68 | try expect(x == 0); | ||
| 69 | resume p; | ||
| 70 | try expect(x == 0); | ||
| 71 | resume p; | ||
| 72 | try expect(x == 3); | ||
| 73 | } | ||
| 74 | |||
| 75 | fn add(a: i32, b: i32) void { | ||
| 76 | var accum: i32 = 0; | ||
| 77 | suspend {} | ||
| 78 | accum += a; | ||
| 79 | suspend {} | ||
| 80 | accum += b; | ||
| 81 | suspend {} | ||
| 82 | x = accum; | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | try S.doTheTest(); | ||
| 86 | } | ||
| 87 | |||
| 88 | test "calling an inferred async function" { | ||
| 89 | const S = struct { | ||
| 90 | var x: i32 = 1; | ||
| 91 | var other_frame: *@Frame(other) = undefined; | ||
| 92 | |||
| 93 | fn doTheTest() !void { | ||
| 94 | _ = async first(); | ||
| 95 | try expect(x == 1); | ||
| 96 | resume other_frame.*; | ||
| 97 | try expect(x == 2); | ||
| 98 | } | ||
| 99 | |||
| 100 | fn first() void { | ||
| 101 | other(); | ||
| 102 | } | ||
| 103 | fn other() void { | ||
| 104 | other_frame = @frame(); | ||
| 105 | suspend {} | ||
| 106 | x += 1; | ||
| 107 | } | ||
| 108 | }; | ||
| 109 | try S.doTheTest(); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "@frameSize" { | ||
| 113 | if (builtin.arch == .thumb or builtin.arch == .thumbeb) | ||
| 114 | return error.SkipZigTest; | ||
| 115 | |||
| 116 | const S = struct { | ||
| 117 | fn doTheTest() !void { | ||
| 118 | { | ||
| 119 | var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); | ||
| 120 | const size = @frameSize(ptr); | ||
| 121 | try expect(size == @sizeOf(@Frame(other))); | ||
| 122 | } | ||
| 123 | { | ||
| 124 | var ptr = @ptrCast(fn () callconv(.Async) void, first); | ||
| 125 | const size = @frameSize(ptr); | ||
| 126 | try expect(size == @sizeOf(@Frame(first))); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | fn first() void { | ||
| 131 | other(1); | ||
| 132 | } | ||
| 133 | fn other(param: i32) void { | ||
| 134 | var local: i32 = undefined; | ||
| 135 | suspend {} | ||
| 136 | } | ||
| 137 | }; | ||
| 138 | try S.doTheTest(); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "coroutine suspend, resume" { | ||
| 142 | const S = struct { | ||
| 143 | var frame: anyframe = undefined; | ||
| 144 | |||
| 145 | fn doTheTest() !void { | ||
| 146 | _ = async amain(); | ||
| 147 | seq('d'); | ||
| 148 | resume frame; | ||
| 149 | seq('h'); | ||
| 150 | |||
| 151 | try expect(std.mem.eql(u8, &points, "abcdefgh")); | ||
| 152 | } | ||
| 153 | |||
| 154 | fn amain() void { | ||
| 155 | seq('a'); | ||
| 156 | var f = async testAsyncSeq(); | ||
| 157 | seq('c'); | ||
| 158 | await f; | ||
| 159 | seq('g'); | ||
| 160 | } | ||
| 161 | |||
| 162 | fn testAsyncSeq() void { | ||
| 163 | defer seq('f'); | ||
| 164 | |||
| 165 | seq('b'); | ||
| 166 | suspend { | ||
| 167 | frame = @frame(); | ||
| 168 | } | ||
| 169 | seq('e'); | ||
| 170 | } | ||
| 171 | var points = [_]u8{'x'} ** "abcdefgh".len; | ||
| 172 | var index: usize = 0; | ||
| 173 | |||
| 174 | fn seq(c: u8) void { | ||
| 175 | points[index] = c; | ||
| 176 | index += 1; | ||
| 177 | } | ||
| 178 | }; | ||
| 179 | try S.doTheTest(); | ||
| 180 | } | ||
| 181 | |||
| 182 | test "coroutine suspend with block" { | ||
| 183 | const p = async testSuspendBlock(); | ||
| 184 | try expect(!global_result); | ||
| 185 | resume a_promise; | ||
| 186 | try expect(global_result); | ||
| 187 | } | ||
| 188 | |||
| 189 | var a_promise: anyframe = undefined; | ||
| 190 | var global_result = false; | ||
| 191 | fn testSuspendBlock() callconv(.Async) void { | ||
| 192 | suspend { | ||
| 193 | comptime expect(@TypeOf(@frame()) == *@Frame(testSuspendBlock)) catch unreachable; | ||
| 194 | a_promise = @frame(); | ||
| 195 | } | ||
| 196 | |||
| 197 | // Test to make sure that @frame() works as advertised (issue #1296) | ||
| 198 | // var our_handle: anyframe = @frame(); | ||
| 199 | expect(a_promise == @as(anyframe, @frame())) catch @panic("test failed"); | ||
| 200 | |||
| 201 | global_result = true; | ||
| 202 | } | ||
| 203 | |||
| 204 | var await_a_promise: anyframe = undefined; | ||
| 205 | var await_final_result: i32 = 0; | ||
| 206 | |||
| 207 | test "coroutine await" { | ||
| 208 | await_seq('a'); | ||
| 209 | var p = async await_amain(); | ||
| 210 | await_seq('f'); | ||
| 211 | resume await_a_promise; | ||
| 212 | await_seq('i'); | ||
| 213 | try expect(await_final_result == 1234); | ||
| 214 | try expect(std.mem.eql(u8, &await_points, "abcdefghi")); | ||
| 215 | } | ||
| 216 | fn await_amain() callconv(.Async) void { | ||
| 217 | await_seq('b'); | ||
| 218 | var p = async await_another(); | ||
| 219 | await_seq('e'); | ||
| 220 | await_final_result = await p; | ||
| 221 | await_seq('h'); | ||
| 222 | } | ||
| 223 | fn await_another() callconv(.Async) i32 { | ||
| 224 | await_seq('c'); | ||
| 225 | suspend { | ||
| 226 | await_seq('d'); | ||
| 227 | await_a_promise = @frame(); | ||
| 228 | } | ||
| 229 | await_seq('g'); | ||
| 230 | return 1234; | ||
| 231 | } | ||
| 232 | |||
| 233 | var await_points = [_]u8{0} ** "abcdefghi".len; | ||
| 234 | var await_seq_index: usize = 0; | ||
| 235 | |||
| 236 | fn await_seq(c: u8) void { | ||
| 237 | await_points[await_seq_index] = c; | ||
| 238 | await_seq_index += 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | var early_final_result: i32 = 0; | ||
| 242 | |||
| 243 | test "coroutine await early return" { | ||
| 244 | early_seq('a'); | ||
| 245 | var p = async early_amain(); | ||
| 246 | early_seq('f'); | ||
| 247 | try expect(early_final_result == 1234); | ||
| 248 | try expect(std.mem.eql(u8, &early_points, "abcdef")); | ||
| 249 | } | ||
| 250 | fn early_amain() callconv(.Async) void { | ||
| 251 | early_seq('b'); | ||
| 252 | var p = async early_another(); | ||
| 253 | early_seq('d'); | ||
| 254 | early_final_result = await p; | ||
| 255 | early_seq('e'); | ||
| 256 | } | ||
| 257 | fn early_another() callconv(.Async) i32 { | ||
| 258 | early_seq('c'); | ||
| 259 | return 1234; | ||
| 260 | } | ||
| 261 | |||
| 262 | var early_points = [_]u8{0} ** "abcdef".len; | ||
| 263 | var early_seq_index: usize = 0; | ||
| 264 | |||
| 265 | fn early_seq(c: u8) void { | ||
| 266 | early_points[early_seq_index] = c; | ||
| 267 | early_seq_index += 1; | ||
| 268 | } | ||
| 269 | |||
| 270 | test "async function with dot syntax" { | ||
| 271 | const S = struct { | ||
| 272 | var y: i32 = 1; | ||
| 273 | fn foo() callconv(.Async) void { | ||
| 274 | y += 1; | ||
| 275 | suspend {} | ||
| 276 | } | ||
| 277 | }; | ||
| 278 | const p = async S.foo(); | ||
| 279 | try expect(S.y == 2); | ||
| 280 | } | ||
| 281 | |||
| 282 | test "async fn pointer in a struct field" { | ||
| 283 | var data: i32 = 1; | ||
| 284 | const Foo = struct { | ||
| 285 | bar: fn (*i32) callconv(.Async) void, | ||
| 286 | }; | ||
| 287 | var foo = Foo{ .bar = simpleAsyncFn2 }; | ||
| 288 | var bytes: [64]u8 align(16) = undefined; | ||
| 289 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | ||
| 290 | comptime try expect(@TypeOf(f) == anyframe->void); | ||
| 291 | try expect(data == 2); | ||
| 292 | resume f; | ||
| 293 | try expect(data == 4); | ||
| 294 | _ = async doTheAwait(f); | ||
| 295 | try expect(data == 4); | ||
| 296 | } | ||
| 297 | |||
| 298 | fn doTheAwait(f: anyframe->void) void { | ||
| 299 | await f; | ||
| 300 | } | ||
| 301 | fn simpleAsyncFn2(y: *i32) callconv(.Async) void { | ||
| 302 | defer y.* += 2; | ||
| 303 | y.* += 1; | ||
| 304 | suspend {} | ||
| 305 | } | ||
| 306 | |||
| 307 | test "@asyncCall with return type" { | ||
| 308 | const Foo = struct { | ||
| 309 | bar: fn () callconv(.Async) i32, | ||
| 310 | |||
| 311 | var global_frame: anyframe = undefined; | ||
| 312 | fn middle() callconv(.Async) i32 { | ||
| 313 | return afunc(); | ||
| 314 | } | ||
| 315 | |||
| 316 | fn afunc() i32 { | ||
| 317 | global_frame = @frame(); | ||
| 318 | suspend {} | ||
| 319 | return 1234; | ||
| 320 | } | ||
| 321 | }; | ||
| 322 | var foo = Foo{ .bar = Foo.middle }; | ||
| 323 | var bytes: [150]u8 align(16) = undefined; | ||
| 324 | var aresult: i32 = 0; | ||
| 325 | _ = @asyncCall(&bytes, &aresult, foo.bar, .{}); | ||
| 326 | try expect(aresult == 0); | ||
| 327 | resume Foo.global_frame; | ||
| 328 | try expect(aresult == 1234); | ||
| 329 | } | ||
| 330 | |||
| 331 | test "async fn with inferred error set" { | ||
| 332 | const S = struct { | ||
| 333 | var global_frame: anyframe = undefined; | ||
| 334 | |||
| 335 | fn doTheTest() !void { | ||
| 336 | var frame: [1]@Frame(middle) = undefined; | ||
| 337 | var fn_ptr = middle; | ||
| 338 | var result: @typeInfo(@typeInfo(@TypeOf(fn_ptr)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; | ||
| 339 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); | ||
| 340 | resume global_frame; | ||
| 341 | try std.testing.expectError(error.Fail, result); | ||
| 342 | } | ||
| 343 | fn middle() callconv(.Async) !void { | ||
| 344 | var f = async middle2(); | ||
| 345 | return await f; | ||
| 346 | } | ||
| 347 | |||
| 348 | fn middle2() !void { | ||
| 349 | return failing(); | ||
| 350 | } | ||
| 351 | |||
| 352 | fn failing() !void { | ||
| 353 | global_frame = @frame(); | ||
| 354 | suspend {} | ||
| 355 | return error.Fail; | ||
| 356 | } | ||
| 357 | }; | ||
| 358 | try S.doTheTest(); | ||
| 359 | } | ||
| 360 | |||
| 361 | test "error return trace across suspend points - early return" { | ||
| 362 | const p = nonFailing(); | ||
| 363 | resume p; | ||
| 364 | const p2 = async printTrace(p); | ||
| 365 | } | ||
| 366 | |||
| 367 | test "error return trace across suspend points - async return" { | ||
| 368 | const p = nonFailing(); | ||
| 369 | const p2 = async printTrace(p); | ||
| 370 | resume p; | ||
| 371 | } | ||
| 372 | |||
| 373 | fn nonFailing() (anyframe->anyerror!void) { | ||
| 374 | const Static = struct { | ||
| 375 | var frame: @Frame(suspendThenFail) = undefined; | ||
| 376 | }; | ||
| 377 | Static.frame = async suspendThenFail(); | ||
| 378 | return &Static.frame; | ||
| 379 | } | ||
| 380 | fn suspendThenFail() callconv(.Async) anyerror!void { | ||
| 381 | suspend {} | ||
| 382 | return error.Fail; | ||
| 383 | } | ||
| 384 | fn printTrace(p: anyframe->(anyerror!void)) callconv(.Async) void { | ||
| 385 | (await p) catch |e| { | ||
| 386 | std.testing.expect(e == error.Fail) catch @panic("test failure"); | ||
| 387 | if (@errorReturnTrace()) |trace| { | ||
| 388 | expect(trace.index == 1) catch @panic("test failure"); | ||
| 389 | } else switch (builtin.mode) { | ||
| 390 | .Debug, .ReleaseSafe => @panic("expected return trace"), | ||
| 391 | .ReleaseFast, .ReleaseSmall => {}, | ||
| 392 | } | ||
| 393 | }; | ||
| 394 | } | ||
| 395 | |||
| 396 | test "break from suspend" { | ||
| 397 | var my_result: i32 = 1; | ||
| 398 | const p = async testBreakFromSuspend(&my_result); | ||
| 399 | try std.testing.expect(my_result == 2); | ||
| 400 | } | ||
| 401 | fn testBreakFromSuspend(my_result: *i32) callconv(.Async) void { | ||
| 402 | suspend { | ||
| 403 | resume @frame(); | ||
| 404 | } | ||
| 405 | my_result.* += 1; | ||
| 406 | suspend {} | ||
| 407 | my_result.* += 1; | ||
| 408 | } | ||
| 409 | |||
| 410 | test "heap allocated async function frame" { | ||
| 411 | const S = struct { | ||
| 412 | var x: i32 = 42; | ||
| 413 | |||
| 414 | fn doTheTest() !void { | ||
| 415 | const frame = try std.testing.allocator.create(@Frame(someFunc)); | ||
| 416 | defer std.testing.allocator.destroy(frame); | ||
| 417 | |||
| 418 | try expect(x == 42); | ||
| 419 | frame.* = async someFunc(); | ||
| 420 | try expect(x == 43); | ||
| 421 | resume frame; | ||
| 422 | try expect(x == 44); | ||
| 423 | } | ||
| 424 | |||
| 425 | fn someFunc() void { | ||
| 426 | x += 1; | ||
| 427 | suspend {} | ||
| 428 | x += 1; | ||
| 429 | } | ||
| 430 | }; | ||
| 431 | try S.doTheTest(); | ||
| 432 | } | ||
| 433 | |||
| 434 | test "async function call return value" { | ||
| 435 | const S = struct { | ||
| 436 | var frame: anyframe = undefined; | ||
| 437 | var pt = Point{ .x = 10, .y = 11 }; | ||
| 438 | |||
| 439 | fn doTheTest() !void { | ||
| 440 | try expectEqual(pt.x, 10); | ||
| 441 | try expectEqual(pt.y, 11); | ||
| 442 | _ = async first(); | ||
| 443 | try expectEqual(pt.x, 10); | ||
| 444 | try expectEqual(pt.y, 11); | ||
| 445 | resume frame; | ||
| 446 | try expectEqual(pt.x, 1); | ||
| 447 | try expectEqual(pt.y, 2); | ||
| 448 | } | ||
| 449 | |||
| 450 | fn first() void { | ||
| 451 | pt = second(1, 2); | ||
| 452 | } | ||
| 453 | |||
| 454 | fn second(x: i32, y: i32) Point { | ||
| 455 | return other(x, y); | ||
| 456 | } | ||
| 457 | |||
| 458 | fn other(x: i32, y: i32) Point { | ||
| 459 | frame = @frame(); | ||
| 460 | suspend {} | ||
| 461 | return Point{ | ||
| 462 | .x = x, | ||
| 463 | .y = y, | ||
| 464 | }; | ||
| 465 | } | ||
| 466 | |||
| 467 | const Point = struct { | ||
| 468 | x: i32, | ||
| 469 | y: i32, | ||
| 470 | }; | ||
| 471 | }; | ||
| 472 | try S.doTheTest(); | ||
| 473 | } | ||
| 474 | |||
| 475 | test "suspension points inside branching control flow" { | ||
| 476 | const S = struct { | ||
| 477 | var result: i32 = 10; | ||
| 478 | |||
| 479 | fn doTheTest() !void { | ||
| 480 | try expect(10 == result); | ||
| 481 | var frame = async func(true); | ||
| 482 | try expect(10 == result); | ||
| 483 | resume frame; | ||
| 484 | try expect(11 == result); | ||
| 485 | resume frame; | ||
| 486 | try expect(12 == result); | ||
| 487 | resume frame; | ||
| 488 | try expect(13 == result); | ||
| 489 | } | ||
| 490 | |||
| 491 | fn func(b: bool) void { | ||
| 492 | while (b) { | ||
| 493 | suspend {} | ||
| 494 | result += 1; | ||
| 495 | } | ||
| 496 | } | ||
| 497 | }; | ||
| 498 | try S.doTheTest(); | ||
| 499 | } | ||
| 500 | |||
| 501 | test "call async function which has struct return type" { | ||
| 502 | const S = struct { | ||
| 503 | var frame: anyframe = undefined; | ||
| 504 | |||
| 505 | fn doTheTest() void { | ||
| 506 | _ = async atest(); | ||
| 507 | resume frame; | ||
| 508 | } | ||
| 509 | |||
| 510 | fn atest() void { | ||
| 511 | const result = func(); | ||
| 512 | expect(result.x == 5) catch @panic("test failed"); | ||
| 513 | expect(result.y == 6) catch @panic("test failed"); | ||
| 514 | } | ||
| 515 | |||
| 516 | const Point = struct { | ||
| 517 | x: usize, | ||
| 518 | y: usize, | ||
| 519 | }; | ||
| 520 | |||
| 521 | fn func() Point { | ||
| 522 | suspend { | ||
| 523 | frame = @frame(); | ||
| 524 | } | ||
| 525 | return Point{ | ||
| 526 | .x = 5, | ||
| 527 | .y = 6, | ||
| 528 | }; | ||
| 529 | } | ||
| 530 | }; | ||
| 531 | S.doTheTest(); | ||
| 532 | } | ||
| 533 | |||
| 534 | test "pass string literal to async function" { | ||
| 535 | const S = struct { | ||
| 536 | var frame: anyframe = undefined; | ||
| 537 | var ok: bool = false; | ||
| 538 | |||
| 539 | fn doTheTest() !void { | ||
| 540 | _ = async hello("hello"); | ||
| 541 | resume frame; | ||
| 542 | try expect(ok); | ||
| 543 | } | ||
| 544 | |||
| 545 | fn hello(msg: []const u8) void { | ||
| 546 | frame = @frame(); | ||
| 547 | suspend {} | ||
| 548 | expectEqualStrings("hello", msg) catch @panic("test failed"); | ||
| 549 | ok = true; | ||
| 550 | } | ||
| 551 | }; | ||
| 552 | try S.doTheTest(); | ||
| 553 | } | ||
| 554 | |||
| 555 | test "await inside an errdefer" { | ||
| 556 | const S = struct { | ||
| 557 | var frame: anyframe = undefined; | ||
| 558 | |||
| 559 | fn doTheTest() !void { | ||
| 560 | _ = async amainWrap(); | ||
| 561 | resume frame; | ||
| 562 | } | ||
| 563 | |||
| 564 | fn amainWrap() !void { | ||
| 565 | var foo = async func(); | ||
| 566 | errdefer await foo; | ||
| 567 | return error.Bad; | ||
| 568 | } | ||
| 569 | |||
| 570 | fn func() void { | ||
| 571 | frame = @frame(); | ||
| 572 | suspend {} | ||
| 573 | } | ||
| 574 | }; | ||
| 575 | try S.doTheTest(); | ||
| 576 | } | ||
| 577 | |||
| 578 | test "try in an async function with error union and non-zero-bit payload" { | ||
| 579 | const S = struct { | ||
| 580 | var frame: anyframe = undefined; | ||
| 581 | var ok = false; | ||
| 582 | |||
| 583 | fn doTheTest() !void { | ||
| 584 | _ = async amain(); | ||
| 585 | resume frame; | ||
| 586 | try expect(ok); | ||
| 587 | } | ||
| 588 | |||
| 589 | fn amain() void { | ||
| 590 | std.testing.expectError(error.Bad, theProblem()) catch @panic("test failed"); | ||
| 591 | ok = true; | ||
| 592 | } | ||
| 593 | |||
| 594 | fn theProblem() ![]u8 { | ||
| 595 | frame = @frame(); | ||
| 596 | suspend {} | ||
| 597 | const result = try other(); | ||
| 598 | return result; | ||
| 599 | } | ||
| 600 | |||
| 601 | fn other() ![]u8 { | ||
| 602 | return error.Bad; | ||
| 603 | } | ||
| 604 | }; | ||
| 605 | try S.doTheTest(); | ||
| 606 | } | ||
| 607 | |||
| 608 | test "returning a const error from async function" { | ||
| 609 | const S = struct { | ||
| 610 | var frame: anyframe = undefined; | ||
| 611 | var ok = false; | ||
| 612 | |||
| 613 | fn doTheTest() !void { | ||
| 614 | _ = async amain(); | ||
| 615 | resume frame; | ||
| 616 | try expect(ok); | ||
| 617 | } | ||
| 618 | |||
| 619 | fn amain() !void { | ||
| 620 | var download_frame = async fetchUrl(10, "a string"); | ||
| 621 | const download_text = try await download_frame; | ||
| 622 | |||
| 623 | @panic("should not get here"); | ||
| 624 | } | ||
| 625 | |||
| 626 | fn fetchUrl(unused: i32, url: []const u8) ![]u8 { | ||
| 627 | frame = @frame(); | ||
| 628 | suspend {} | ||
| 629 | ok = true; | ||
| 630 | return error.OutOfMemory; | ||
| 631 | } | ||
| 632 | }; | ||
| 633 | try S.doTheTest(); | ||
| 634 | } | ||
| 635 | |||
| 636 | test "async/await typical usage" { | ||
| 637 | inline for ([_]bool{ false, true }) |b1| { | ||
| 638 | inline for ([_]bool{ false, true }) |b2| { | ||
| 639 | inline for ([_]bool{ false, true }) |b3| { | ||
| 640 | inline for ([_]bool{ false, true }) |b4| { | ||
| 641 | testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest(); | ||
| 642 | } | ||
| 643 | } | ||
| 644 | } | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 648 | fn testAsyncAwaitTypicalUsage( | ||
| 649 | comptime simulate_fail_download: bool, | ||
| 650 | comptime simulate_fail_file: bool, | ||
| 651 | comptime suspend_download: bool, | ||
| 652 | comptime suspend_file: bool, | ||
| 653 | ) type { | ||
| 654 | return struct { | ||
| 655 | fn doTheTest() void { | ||
| 656 | _ = async amainWrap(); | ||
| 657 | if (suspend_file) { | ||
| 658 | resume global_file_frame; | ||
| 659 | } | ||
| 660 | if (suspend_download) { | ||
| 661 | resume global_download_frame; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | fn amainWrap() void { | ||
| 665 | if (amain()) |_| { | ||
| 666 | expect(!simulate_fail_download) catch @panic("test failure"); | ||
| 667 | expect(!simulate_fail_file) catch @panic("test failure"); | ||
| 668 | } else |e| switch (e) { | ||
| 669 | error.NoResponse => expect(simulate_fail_download) catch @panic("test failure"), | ||
| 670 | error.FileNotFound => expect(simulate_fail_file) catch @panic("test failure"), | ||
| 671 | else => @panic("test failure"), | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | fn amain() !void { | ||
| 676 | const allocator = std.testing.allocator; | ||
| 677 | var download_frame = async fetchUrl(allocator, "https://example.com/"); | ||
| 678 | var download_awaited = false; | ||
| 679 | errdefer if (!download_awaited) { | ||
| 680 | if (await download_frame) |x| allocator.free(x) else |_| {} | ||
| 681 | }; | ||
| 682 | |||
| 683 | var file_frame = async readFile(allocator, "something.txt"); | ||
| 684 | var file_awaited = false; | ||
| 685 | errdefer if (!file_awaited) { | ||
| 686 | if (await file_frame) |x| allocator.free(x) else |_| {} | ||
| 687 | }; | ||
| 688 | |||
| 689 | download_awaited = true; | ||
| 690 | const download_text = try await download_frame; | ||
| 691 | defer allocator.free(download_text); | ||
| 692 | |||
| 693 | file_awaited = true; | ||
| 694 | const file_text = try await file_frame; | ||
| 695 | defer allocator.free(file_text); | ||
| 696 | |||
| 697 | try expect(std.mem.eql(u8, "expected download text", download_text)); | ||
| 698 | try expect(std.mem.eql(u8, "expected file text", file_text)); | ||
| 699 | } | ||
| 700 | |||
| 701 | var global_download_frame: anyframe = undefined; | ||
| 702 | fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 { | ||
| 703 | const result = try std.mem.dupe(allocator, u8, "expected download text"); | ||
| 704 | errdefer allocator.free(result); | ||
| 705 | if (suspend_download) { | ||
| 706 | suspend { | ||
| 707 | global_download_frame = @frame(); | ||
| 708 | } | ||
| 709 | } | ||
| 710 | if (simulate_fail_download) return error.NoResponse; | ||
| 711 | return result; | ||
| 712 | } | ||
| 713 | |||
| 714 | var global_file_frame: anyframe = undefined; | ||
| 715 | fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 { | ||
| 716 | const result = try std.mem.dupe(allocator, u8, "expected file text"); | ||
| 717 | errdefer allocator.free(result); | ||
| 718 | if (suspend_file) { | ||
| 719 | suspend { | ||
| 720 | global_file_frame = @frame(); | ||
| 721 | } | ||
| 722 | } | ||
| 723 | if (simulate_fail_file) return error.FileNotFound; | ||
| 724 | return result; | ||
| 725 | } | ||
| 726 | }; | ||
| 727 | } | ||
| 728 | |||
| 729 | test "alignment of local variables in async functions" { | ||
| 730 | const S = struct { | ||
| 731 | fn doTheTest() !void { | ||
| 732 | var y: u8 = 123; | ||
| 733 | var x: u8 align(128) = 1; | ||
| 734 | try expect(@ptrToInt(&x) % 128 == 0); | ||
| 735 | } | ||
| 736 | }; | ||
| 737 | try S.doTheTest(); | ||
| 738 | } | ||
| 739 | |||
| 740 | test "no reason to resolve frame still works" { | ||
| 741 | _ = async simpleNothing(); | ||
| 742 | } | ||
| 743 | fn simpleNothing() void { | ||
| 744 | var x: i32 = 1234; | ||
| 745 | } | ||
| 746 | |||
| 747 | test "async call a generic function" { | ||
| 748 | const S = struct { | ||
| 749 | fn doTheTest() !void { | ||
| 750 | var f = async func(i32, 2); | ||
| 751 | const result = await f; | ||
| 752 | try expect(result == 3); | ||
| 753 | } | ||
| 754 | |||
| 755 | fn func(comptime T: type, inc: T) T { | ||
| 756 | var x: T = 1; | ||
| 757 | suspend { | ||
| 758 | resume @frame(); | ||
| 759 | } | ||
| 760 | x += inc; | ||
| 761 | return x; | ||
| 762 | } | ||
| 763 | }; | ||
| 764 | _ = async S.doTheTest(); | ||
| 765 | } | ||
| 766 | |||
| 767 | test "return from suspend block" { | ||
| 768 | const S = struct { | ||
| 769 | fn doTheTest() !void { | ||
| 770 | expect(func() == 1234) catch @panic("test failure"); | ||
| 771 | } | ||
| 772 | fn func() i32 { | ||
| 773 | suspend { | ||
| 774 | return 1234; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | }; | ||
| 778 | _ = async S.doTheTest(); | ||
| 779 | } | ||
| 780 | |||
| 781 | test "struct parameter to async function is copied to the frame" { | ||
| 782 | const S = struct { | ||
| 783 | const Point = struct { | ||
| 784 | x: i32, | ||
| 785 | y: i32, | ||
| 786 | }; | ||
| 787 | |||
| 788 | var frame: anyframe = undefined; | ||
| 789 | |||
| 790 | fn doTheTest() void { | ||
| 791 | _ = async atest(); | ||
| 792 | resume frame; | ||
| 793 | } | ||
| 794 | |||
| 795 | fn atest() void { | ||
| 796 | var f: @Frame(foo) = undefined; | ||
| 797 | bar(&f); | ||
| 798 | clobberStack(10); | ||
| 799 | } | ||
| 800 | |||
| 801 | fn clobberStack(x: i32) void { | ||
| 802 | if (x == 0) return; | ||
| 803 | clobberStack(x - 1); | ||
| 804 | var y: i32 = x; | ||
| 805 | } | ||
| 806 | |||
| 807 | fn bar(f: *@Frame(foo)) void { | ||
| 808 | var pt = Point{ .x = 1, .y = 2 }; | ||
| 809 | f.* = async foo(pt); | ||
| 810 | var result = await f; | ||
| 811 | expect(result == 1) catch @panic("test failure"); | ||
| 812 | } | ||
| 813 | |||
| 814 | fn foo(point: Point) i32 { | ||
| 815 | suspend { | ||
| 816 | frame = @frame(); | ||
| 817 | } | ||
| 818 | return point.x; | ||
| 819 | } | ||
| 820 | }; | ||
| 821 | S.doTheTest(); | ||
| 822 | } | ||
| 823 | |||
| 824 | test "cast fn to async fn when it is inferred to be async" { | ||
| 825 | const S = struct { | ||
| 826 | var frame: anyframe = undefined; | ||
| 827 | var ok = false; | ||
| 828 | |||
| 829 | fn doTheTest() void { | ||
| 830 | var ptr: fn () callconv(.Async) i32 = undefined; | ||
| 831 | ptr = func; | ||
| 832 | var buf: [100]u8 align(16) = undefined; | ||
| 833 | var result: i32 = undefined; | ||
| 834 | const f = @asyncCall(&buf, &result, ptr, .{}); | ||
| 835 | _ = await f; | ||
| 836 | expect(result == 1234) catch @panic("test failure"); | ||
| 837 | ok = true; | ||
| 838 | } | ||
| 839 | |||
| 840 | fn func() i32 { | ||
| 841 | suspend { | ||
| 842 | frame = @frame(); | ||
| 843 | } | ||
| 844 | return 1234; | ||
| 845 | } | ||
| 846 | }; | ||
| 847 | _ = async S.doTheTest(); | ||
| 848 | resume S.frame; | ||
| 849 | try expect(S.ok); | ||
| 850 | } | ||
| 851 | |||
| 852 | test "cast fn to async fn when it is inferred to be async, awaited directly" { | ||
| 853 | const S = struct { | ||
| 854 | var frame: anyframe = undefined; | ||
| 855 | var ok = false; | ||
| 856 | |||
| 857 | fn doTheTest() void { | ||
| 858 | var ptr: fn () callconv(.Async) i32 = undefined; | ||
| 859 | ptr = func; | ||
| 860 | var buf: [100]u8 align(16) = undefined; | ||
| 861 | var result: i32 = undefined; | ||
| 862 | _ = await @asyncCall(&buf, &result, ptr, .{}); | ||
| 863 | expect(result == 1234) catch @panic("test failure"); | ||
| 864 | ok = true; | ||
| 865 | } | ||
| 866 | |||
| 867 | fn func() i32 { | ||
| 868 | suspend { | ||
| 869 | frame = @frame(); | ||
| 870 | } | ||
| 871 | return 1234; | ||
| 872 | } | ||
| 873 | }; | ||
| 874 | _ = async S.doTheTest(); | ||
| 875 | resume S.frame; | ||
| 876 | try expect(S.ok); | ||
| 877 | } | ||
| 878 | |||
| 879 | test "await does not force async if callee is blocking" { | ||
| 880 | const S = struct { | ||
| 881 | fn simple() i32 { | ||
| 882 | return 1234; | ||
| 883 | } | ||
| 884 | }; | ||
| 885 | var x = async S.simple(); | ||
| 886 | try expect(await x == 1234); | ||
| 887 | } | ||
| 888 | |||
| 889 | test "recursive async function" { | ||
| 890 | try expect(recursiveAsyncFunctionTest(false).doTheTest() == 55); | ||
| 891 | try expect(recursiveAsyncFunctionTest(true).doTheTest() == 55); | ||
| 892 | } | ||
| 893 | |||
| 894 | fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type { | ||
| 895 | return struct { | ||
| 896 | fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 { | ||
| 897 | if (x <= 1) return x; | ||
| 898 | |||
| 899 | if (suspending_implementation) { | ||
| 900 | suspend { | ||
| 901 | resume @frame(); | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | const f1 = try allocator.create(@Frame(fib)); | ||
| 906 | defer allocator.destroy(f1); | ||
| 907 | |||
| 908 | const f2 = try allocator.create(@Frame(fib)); | ||
| 909 | defer allocator.destroy(f2); | ||
| 910 | |||
| 911 | f1.* = async fib(allocator, x - 1); | ||
| 912 | var f1_awaited = false; | ||
| 913 | errdefer if (!f1_awaited) { | ||
| 914 | _ = await f1; | ||
| 915 | }; | ||
| 916 | |||
| 917 | f2.* = async fib(allocator, x - 2); | ||
| 918 | var f2_awaited = false; | ||
| 919 | errdefer if (!f2_awaited) { | ||
| 920 | _ = await f2; | ||
| 921 | }; | ||
| 922 | |||
| 923 | var sum: u32 = 0; | ||
| 924 | |||
| 925 | f1_awaited = true; | ||
| 926 | sum += try await f1; | ||
| 927 | |||
| 928 | f2_awaited = true; | ||
| 929 | sum += try await f2; | ||
| 930 | |||
| 931 | return sum; | ||
| 932 | } | ||
| 933 | |||
| 934 | fn doTheTest() u32 { | ||
| 935 | if (suspending_implementation) { | ||
| 936 | var result: u32 = undefined; | ||
| 937 | _ = async amain(&result); | ||
| 938 | return result; | ||
| 939 | } else { | ||
| 940 | return fib(std.testing.allocator, 10) catch unreachable; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | fn amain(result: *u32) void { | ||
| 945 | var x = async fib(std.testing.allocator, 10); | ||
| 946 | result.* = (await x) catch unreachable; | ||
| 947 | } | ||
| 948 | }; | ||
| 949 | } | ||
| 950 | |||
| 951 | test "@asyncCall with comptime-known function, but not awaited directly" { | ||
| 952 | const S = struct { | ||
| 953 | var global_frame: anyframe = undefined; | ||
| 954 | |||
| 955 | fn doTheTest() !void { | ||
| 956 | var frame: [1]@Frame(middle) = undefined; | ||
| 957 | var result: @typeInfo(@typeInfo(@TypeOf(middle)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; | ||
| 958 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); | ||
| 959 | resume global_frame; | ||
| 960 | try std.testing.expectError(error.Fail, result); | ||
| 961 | } | ||
| 962 | fn middle() callconv(.Async) !void { | ||
| 963 | var f = async middle2(); | ||
| 964 | return await f; | ||
| 965 | } | ||
| 966 | |||
| 967 | fn middle2() !void { | ||
| 968 | return failing(); | ||
| 969 | } | ||
| 970 | |||
| 971 | fn failing() !void { | ||
| 972 | global_frame = @frame(); | ||
| 973 | suspend {} | ||
| 974 | return error.Fail; | ||
| 975 | } | ||
| 976 | }; | ||
| 977 | try S.doTheTest(); | ||
| 978 | } | ||
| 979 | |||
| 980 | test "@asyncCall with actual frame instead of byte buffer" { | ||
| 981 | const S = struct { | ||
| 982 | fn func() i32 { | ||
| 983 | suspend {} | ||
| 984 | return 1234; | ||
| 985 | } | ||
| 986 | }; | ||
| 987 | var frame: @Frame(S.func) = undefined; | ||
| 988 | var result: i32 = undefined; | ||
| 989 | const ptr = @asyncCall(&frame, &result, S.func, .{}); | ||
| 990 | resume ptr; | ||
| 991 | try expect(result == 1234); | ||
| 992 | } | ||
| 993 | |||
| 994 | test "@asyncCall using the result location inside the frame" { | ||
| 995 | const S = struct { | ||
| 996 | fn simple2(y: *i32) callconv(.Async) i32 { | ||
| 997 | defer y.* += 2; | ||
| 998 | y.* += 1; | ||
| 999 | suspend {} | ||
| 1000 | return 1234; | ||
| 1001 | } | ||
| 1002 | fn getAnswer(f: anyframe->i32, out: *i32) void { | ||
| 1003 | out.* = await f; | ||
| 1004 | } | ||
| 1005 | }; | ||
| 1006 | var data: i32 = 1; | ||
| 1007 | const Foo = struct { | ||
| 1008 | bar: fn (*i32) callconv(.Async) i32, | ||
| 1009 | }; | ||
| 1010 | var foo = Foo{ .bar = S.simple2 }; | ||
| 1011 | var bytes: [64]u8 align(16) = undefined; | ||
| 1012 | const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); | ||
| 1013 | comptime try expect(@TypeOf(f) == anyframe->i32); | ||
| 1014 | try expect(data == 2); | ||
| 1015 | resume f; | ||
| 1016 | try expect(data == 4); | ||
| 1017 | _ = async S.getAnswer(f, &data); | ||
| 1018 | try expect(data == 1234); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | test "@TypeOf an async function call of generic fn with error union type" { | ||
| 1022 | const S = struct { | ||
| 1023 | fn func(comptime x: anytype) anyerror!i32 { | ||
| 1024 | const T = @TypeOf(async func(x)); | ||
| 1025 | comptime try expect(T == @typeInfo(@TypeOf(@frame())).Pointer.child); | ||
| 1026 | return undefined; | ||
| 1027 | } | ||
| 1028 | }; | ||
| 1029 | _ = async S.func(i32); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | test "using @TypeOf on a generic function call" { | ||
| 1033 | const S = struct { | ||
| 1034 | var global_frame: anyframe = undefined; | ||
| 1035 | var global_ok = false; | ||
| 1036 | |||
| 1037 | var buf: [100]u8 align(16) = undefined; | ||
| 1038 | |||
| 1039 | fn amain(x: anytype) void { | ||
| 1040 | if (x == 0) { | ||
| 1041 | global_ok = true; | ||
| 1042 | return; | ||
| 1043 | } | ||
| 1044 | suspend { | ||
| 1045 | global_frame = @frame(); | ||
| 1046 | } | ||
| 1047 | const F = @TypeOf(async amain(x - 1)); | ||
| 1048 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | ||
| 1049 | return await @asyncCall(frame, {}, amain, .{x - 1}); | ||
| 1050 | } | ||
| 1051 | }; | ||
| 1052 | _ = async S.amain(@as(u32, 1)); | ||
| 1053 | resume S.global_frame; | ||
| 1054 | try expect(S.global_ok); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | test "recursive call of await @asyncCall with struct return type" { | ||
| 1058 | const S = struct { | ||
| 1059 | var global_frame: anyframe = undefined; | ||
| 1060 | var global_ok = false; | ||
| 1061 | |||
| 1062 | var buf: [100]u8 align(16) = undefined; | ||
| 1063 | |||
| 1064 | fn amain(x: anytype) Foo { | ||
| 1065 | if (x == 0) { | ||
| 1066 | global_ok = true; | ||
| 1067 | return Foo{ .x = 1, .y = 2, .z = 3 }; | ||
| 1068 | } | ||
| 1069 | suspend { | ||
| 1070 | global_frame = @frame(); | ||
| 1071 | } | ||
| 1072 | const F = @TypeOf(async amain(x - 1)); | ||
| 1073 | const frame = @intToPtr(*F, @ptrToInt(&buf)); | ||
| 1074 | return await @asyncCall(frame, {}, amain, .{x - 1}); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | const Foo = struct { | ||
| 1078 | x: u64, | ||
| 1079 | y: u64, | ||
| 1080 | z: u64, | ||
| 1081 | }; | ||
| 1082 | }; | ||
| 1083 | var res: S.Foo = undefined; | ||
| 1084 | var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined; | ||
| 1085 | _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)}); | ||
| 1086 | resume S.global_frame; | ||
| 1087 | try expect(S.global_ok); | ||
| 1088 | try expect(res.x == 1); | ||
| 1089 | try expect(res.y == 2); | ||
| 1090 | try expect(res.z == 3); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | test "nosuspend function call" { | ||
| 1094 | const S = struct { | ||
| 1095 | fn doTheTest() !void { | ||
| 1096 | const result = nosuspend add(50, 100); | ||
| 1097 | try expect(result == 150); | ||
| 1098 | } | ||
| 1099 | fn add(a: i32, b: i32) i32 { | ||
| 1100 | if (a > 100) { | ||
| 1101 | suspend {} | ||
| 1102 | } | ||
| 1103 | return a + b; | ||
| 1104 | } | ||
| 1105 | }; | ||
| 1106 | try S.doTheTest(); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "await used in expression and awaiting fn with no suspend but async calling convention" { | ||
| 1110 | const S = struct { | ||
| 1111 | fn atest() void { | ||
| 1112 | var f1 = async add(1, 2); | ||
| 1113 | var f2 = async add(3, 4); | ||
| 1114 | |||
| 1115 | const sum = (await f1) + (await f2); | ||
| 1116 | expect(sum == 10) catch @panic("test failure"); | ||
| 1117 | } | ||
| 1118 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1119 | return a + b; | ||
| 1120 | } | ||
| 1121 | }; | ||
| 1122 | _ = async S.atest(); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | test "await used in expression after a fn call" { | ||
| 1126 | const S = struct { | ||
| 1127 | fn atest() void { | ||
| 1128 | var f1 = async add(3, 4); | ||
| 1129 | var sum: i32 = 0; | ||
| 1130 | sum = foo() + await f1; | ||
| 1131 | expect(sum == 8) catch @panic("test failure"); | ||
| 1132 | } | ||
| 1133 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1134 | return a + b; | ||
| 1135 | } | ||
| 1136 | fn foo() i32 { | ||
| 1137 | return 1; | ||
| 1138 | } | ||
| 1139 | }; | ||
| 1140 | _ = async S.atest(); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | test "async fn call used in expression after a fn call" { | ||
| 1144 | const S = struct { | ||
| 1145 | fn atest() void { | ||
| 1146 | var sum: i32 = 0; | ||
| 1147 | sum = foo() + add(3, 4); | ||
| 1148 | expect(sum == 8) catch @panic("test failure"); | ||
| 1149 | } | ||
| 1150 | fn add(a: i32, b: i32) callconv(.Async) i32 { | ||
| 1151 | return a + b; | ||
| 1152 | } | ||
| 1153 | fn foo() i32 { | ||
| 1154 | return 1; | ||
| 1155 | } | ||
| 1156 | }; | ||
| 1157 | _ = async S.atest(); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | test "suspend in for loop" { | ||
| 1161 | const S = struct { | ||
| 1162 | var global_frame: ?anyframe = null; | ||
| 1163 | |||
| 1164 | fn doTheTest() void { | ||
| 1165 | _ = async atest(); | ||
| 1166 | while (global_frame) |f| resume f; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | fn atest() void { | ||
| 1170 | expect(func(&[_]u8{ 1, 2, 3 }) == 6) catch @panic("test failure"); | ||
| 1171 | } | ||
| 1172 | fn func(stuff: []const u8) u32 { | ||
| 1173 | global_frame = @frame(); | ||
| 1174 | var sum: u32 = 0; | ||
| 1175 | for (stuff) |x| { | ||
| 1176 | suspend {} | ||
| 1177 | sum += x; | ||
| 1178 | } | ||
| 1179 | global_frame = null; | ||
| 1180 | return sum; | ||
| 1181 | } | ||
| 1182 | }; | ||
| 1183 | S.doTheTest(); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | test "suspend in while loop" { | ||
| 1187 | const S = struct { | ||
| 1188 | var global_frame: ?anyframe = null; | ||
| 1189 | |||
| 1190 | fn doTheTest() void { | ||
| 1191 | _ = async atest(); | ||
| 1192 | while (global_frame) |f| resume f; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | fn atest() void { | ||
| 1196 | expect(optional(6) == 6) catch @panic("test failure"); | ||
| 1197 | expect(errunion(6) == 6) catch @panic("test failure"); | ||
| 1198 | } | ||
| 1199 | fn optional(stuff: ?u32) u32 { | ||
| 1200 | global_frame = @frame(); | ||
| 1201 | defer global_frame = null; | ||
| 1202 | while (stuff) |val| { | ||
| 1203 | suspend {} | ||
| 1204 | return val; | ||
| 1205 | } | ||
| 1206 | return 0; | ||
| 1207 | } | ||
| 1208 | fn errunion(stuff: anyerror!u32) u32 { | ||
| 1209 | global_frame = @frame(); | ||
| 1210 | defer global_frame = null; | ||
| 1211 | while (stuff) |val| { | ||
| 1212 | suspend {} | ||
| 1213 | return val; | ||
| 1214 | } else |err| { | ||
| 1215 | return 0; | ||
| 1216 | } | ||
| 1217 | } | ||
| 1218 | }; | ||
| 1219 | S.doTheTest(); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | test "correctly spill when returning the error union result of another async fn" { | ||
| 1223 | const S = struct { | ||
| 1224 | var global_frame: anyframe = undefined; | ||
| 1225 | |||
| 1226 | fn doTheTest() !void { | ||
| 1227 | expect((atest() catch unreachable) == 1234) catch @panic("test failure"); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | fn atest() !i32 { | ||
| 1231 | return fallible1(); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | fn fallible1() anyerror!i32 { | ||
| 1235 | suspend { | ||
| 1236 | global_frame = @frame(); | ||
| 1237 | } | ||
| 1238 | return 1234; | ||
| 1239 | } | ||
| 1240 | }; | ||
| 1241 | _ = async S.doTheTest(); | ||
| 1242 | resume S.global_frame; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | test "spill target expr in a for loop" { | ||
| 1246 | const S = struct { | ||
| 1247 | var global_frame: anyframe = undefined; | ||
| 1248 | |||
| 1249 | fn doTheTest() !void { | ||
| 1250 | var foo = Foo{ | ||
| 1251 | .slice = &[_]i32{ 1, 2 }, | ||
| 1252 | }; | ||
| 1253 | expect(atest(&foo) == 3) catch @panic("test failure"); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | const Foo = struct { | ||
| 1257 | slice: []const i32, | ||
| 1258 | }; | ||
| 1259 | |||
| 1260 | fn atest(foo: *Foo) i32 { | ||
| 1261 | var sum: i32 = 0; | ||
| 1262 | for (foo.slice) |x| { | ||
| 1263 | suspend { | ||
| 1264 | global_frame = @frame(); | ||
| 1265 | } | ||
| 1266 | sum += x; | ||
| 1267 | } | ||
| 1268 | return sum; | ||
| 1269 | } | ||
| 1270 | }; | ||
| 1271 | _ = async S.doTheTest(); | ||
| 1272 | resume S.global_frame; | ||
| 1273 | resume S.global_frame; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | test "spill target expr in a for loop, with a var decl in the loop body" { | ||
| 1277 | const S = struct { | ||
| 1278 | var global_frame: anyframe = undefined; | ||
| 1279 | |||
| 1280 | fn doTheTest() !void { | ||
| 1281 | var foo = Foo{ | ||
| 1282 | .slice = &[_]i32{ 1, 2 }, | ||
| 1283 | }; | ||
| 1284 | expect(atest(&foo) == 3) catch @panic("test failure"); | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | const Foo = struct { | ||
| 1288 | slice: []const i32, | ||
| 1289 | }; | ||
| 1290 | |||
| 1291 | fn atest(foo: *Foo) i32 { | ||
| 1292 | var sum: i32 = 0; | ||
| 1293 | for (foo.slice) |x| { | ||
| 1294 | // Previously this var decl would prevent spills. This test makes sure | ||
| 1295 | // the for loop spills still happen even though there is a VarDecl in scope | ||
| 1296 | // before the suspend. | ||
| 1297 | var anything = true; | ||
| 1298 | _ = anything; | ||
| 1299 | suspend { | ||
| 1300 | global_frame = @frame(); | ||
| 1301 | } | ||
| 1302 | sum += x; | ||
| 1303 | } | ||
| 1304 | return sum; | ||
| 1305 | } | ||
| 1306 | }; | ||
| 1307 | _ = async S.doTheTest(); | ||
| 1308 | resume S.global_frame; | ||
| 1309 | resume S.global_frame; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | test "async call with @call" { | ||
| 1313 | const S = struct { | ||
| 1314 | var global_frame: anyframe = undefined; | ||
| 1315 | fn doTheTest() void { | ||
| 1316 | _ = @call(.{ .modifier = .async_kw }, atest, .{}); | ||
| 1317 | resume global_frame; | ||
| 1318 | } | ||
| 1319 | fn atest() void { | ||
| 1320 | var frame = @call(.{ .modifier = .async_kw }, afoo, .{}); | ||
| 1321 | const res = await frame; | ||
| 1322 | expect(res == 42) catch @panic("test failure"); | ||
| 1323 | } | ||
| 1324 | fn afoo() i32 { | ||
| 1325 | suspend { | ||
| 1326 | global_frame = @frame(); | ||
| 1327 | } | ||
| 1328 | return 42; | ||
| 1329 | } | ||
| 1330 | }; | ||
| 1331 | S.doTheTest(); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | test "async function passed 0-bit arg after non-0-bit arg" { | ||
| 1335 | const S = struct { | ||
| 1336 | var global_frame: anyframe = undefined; | ||
| 1337 | var global_int: i32 = 0; | ||
| 1338 | |||
| 1339 | fn foo() void { | ||
| 1340 | bar(1, .{}) catch unreachable; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | fn bar(x: i32, args: anytype) anyerror!void { | ||
| 1344 | global_frame = @frame(); | ||
| 1345 | suspend {} | ||
| 1346 | global_int = x; | ||
| 1347 | } | ||
| 1348 | }; | ||
| 1349 | _ = async S.foo(); | ||
| 1350 | resume S.global_frame; | ||
| 1351 | try expect(S.global_int == 1); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | test "async function passed align(16) arg after align(8) arg" { | ||
| 1355 | const S = struct { | ||
| 1356 | var global_frame: anyframe = undefined; | ||
| 1357 | var global_int: u128 = 0; | ||
| 1358 | |||
| 1359 | fn foo() void { | ||
| 1360 | var a: u128 = 99; | ||
| 1361 | bar(10, .{a}) catch unreachable; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | fn bar(x: u64, args: anytype) anyerror!void { | ||
| 1365 | try expect(x == 10); | ||
| 1366 | global_frame = @frame(); | ||
| 1367 | suspend {} | ||
| 1368 | global_int = args[0]; | ||
| 1369 | } | ||
| 1370 | }; | ||
| 1371 | _ = async S.foo(); | ||
| 1372 | resume S.global_frame; | ||
| 1373 | try expect(S.global_int == 99); | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | test "async function call resolves target fn frame, comptime func" { | ||
| 1377 | const S = struct { | ||
| 1378 | var global_frame: anyframe = undefined; | ||
| 1379 | var global_int: i32 = 9; | ||
| 1380 | |||
| 1381 | fn foo() anyerror!void { | ||
| 1382 | const stack_size = 1000; | ||
| 1383 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; | ||
| 1384 | return await @asyncCall(&stack_frame, {}, bar, .{}); | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | fn bar() anyerror!void { | ||
| 1388 | global_frame = @frame(); | ||
| 1389 | suspend {} | ||
| 1390 | global_int += 1; | ||
| 1391 | } | ||
| 1392 | }; | ||
| 1393 | _ = async S.foo(); | ||
| 1394 | resume S.global_frame; | ||
| 1395 | try expect(S.global_int == 10); | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | test "async function call resolves target fn frame, runtime func" { | ||
| 1399 | const S = struct { | ||
| 1400 | var global_frame: anyframe = undefined; | ||
| 1401 | var global_int: i32 = 9; | ||
| 1402 | |||
| 1403 | fn foo() anyerror!void { | ||
| 1404 | const stack_size = 1000; | ||
| 1405 | var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; | ||
| 1406 | var func: fn () callconv(.Async) anyerror!void = bar; | ||
| 1407 | return await @asyncCall(&stack_frame, {}, func, .{}); | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | fn bar() anyerror!void { | ||
| 1411 | global_frame = @frame(); | ||
| 1412 | suspend {} | ||
| 1413 | global_int += 1; | ||
| 1414 | } | ||
| 1415 | }; | ||
| 1416 | _ = async S.foo(); | ||
| 1417 | resume S.global_frame; | ||
| 1418 | try expect(S.global_int == 10); | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | test "properly spill optional payload capture value" { | ||
| 1422 | const S = struct { | ||
| 1423 | var global_frame: anyframe = undefined; | ||
| 1424 | var global_int: usize = 2; | ||
| 1425 | |||
| 1426 | fn foo() void { | ||
| 1427 | var opt: ?usize = 1234; | ||
| 1428 | if (opt) |x| { | ||
| 1429 | bar(); | ||
| 1430 | global_int += x; | ||
| 1431 | } | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | fn bar() void { | ||
| 1435 | global_frame = @frame(); | ||
| 1436 | suspend {} | ||
| 1437 | global_int += 1; | ||
| 1438 | } | ||
| 1439 | }; | ||
| 1440 | _ = async S.foo(); | ||
| 1441 | resume S.global_frame; | ||
| 1442 | try expect(S.global_int == 1237); | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | test "handle defer interfering with return value spill" { | ||
| 1446 | const S = struct { | ||
| 1447 | var global_frame1: anyframe = undefined; | ||
| 1448 | var global_frame2: anyframe = undefined; | ||
| 1449 | var finished = false; | ||
| 1450 | var baz_happened = false; | ||
| 1451 | |||
| 1452 | fn doTheTest() !void { | ||
| 1453 | _ = async testFoo(); | ||
| 1454 | resume global_frame1; | ||
| 1455 | resume global_frame2; | ||
| 1456 | try expect(baz_happened); | ||
| 1457 | try expect(finished); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | fn testFoo() void { | ||
| 1461 | expectError(error.Bad, foo()) catch @panic("test failure"); | ||
| 1462 | finished = true; | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | fn foo() anyerror!void { | ||
| 1466 | defer baz(); | ||
| 1467 | return bar() catch |err| return err; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | fn bar() anyerror!void { | ||
| 1471 | global_frame1 = @frame(); | ||
| 1472 | suspend {} | ||
| 1473 | return error.Bad; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | fn baz() void { | ||
| 1477 | global_frame2 = @frame(); | ||
| 1478 | suspend {} | ||
| 1479 | baz_happened = true; | ||
| 1480 | } | ||
| 1481 | }; | ||
| 1482 | try S.doTheTest(); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | test "take address of temporary async frame" { | ||
| 1486 | const S = struct { | ||
| 1487 | var global_frame: anyframe = undefined; | ||
| 1488 | var finished = false; | ||
| 1489 | |||
| 1490 | fn doTheTest() !void { | ||
| 1491 | _ = async asyncDoTheTest(); | ||
| 1492 | resume global_frame; | ||
| 1493 | try expect(finished); | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | fn asyncDoTheTest() void { | ||
| 1497 | expect(finishIt(&async foo(10)) == 1245) catch @panic("test failure"); | ||
| 1498 | finished = true; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | fn foo(arg: i32) i32 { | ||
| 1502 | global_frame = @frame(); | ||
| 1503 | suspend {} | ||
| 1504 | return arg + 1234; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | fn finishIt(frame: anyframe->i32) i32 { | ||
| 1508 | return (await frame) + 1; | ||
| 1509 | } | ||
| 1510 | }; | ||
| 1511 | try S.doTheTest(); | ||
| 1512 | } | ||
| 1513 | |||
| 1514 | test "nosuspend await" { | ||
| 1515 | const S = struct { | ||
| 1516 | var finished = false; | ||
| 1517 | |||
| 1518 | fn doTheTest() !void { | ||
| 1519 | var frame = async foo(false); | ||
| 1520 | try expect(nosuspend await frame == 42); | ||
| 1521 | finished = true; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | fn foo(want_suspend: bool) i32 { | ||
| 1525 | if (want_suspend) { | ||
| 1526 | suspend {} | ||
| 1527 | } | ||
| 1528 | return 42; | ||
| 1529 | } | ||
| 1530 | }; | ||
| 1531 | try S.doTheTest(); | ||
| 1532 | try expect(S.finished); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | test "nosuspend on function calls" { | ||
| 1536 | const S0 = struct { | ||
| 1537 | b: i32 = 42, | ||
| 1538 | }; | ||
| 1539 | const S1 = struct { | ||
| 1540 | fn c() S0 { | ||
| 1541 | return S0{}; | ||
| 1542 | } | ||
| 1543 | fn d() !S0 { | ||
| 1544 | return S0{}; | ||
| 1545 | } | ||
| 1546 | }; | ||
| 1547 | try expectEqual(@as(i32, 42), nosuspend S1.c().b); | ||
| 1548 | try expectEqual(@as(i32, 42), (try nosuspend S1.d()).b); | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | test "nosuspend on async function calls" { | ||
| 1552 | const S0 = struct { | ||
| 1553 | b: i32 = 42, | ||
| 1554 | }; | ||
| 1555 | const S1 = struct { | ||
| 1556 | fn c() S0 { | ||
| 1557 | return S0{}; | ||
| 1558 | } | ||
| 1559 | fn d() !S0 { | ||
| 1560 | return S0{}; | ||
| 1561 | } | ||
| 1562 | }; | ||
| 1563 | var frame_c = nosuspend async S1.c(); | ||
| 1564 | try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1565 | var frame_d = nosuspend async S1.d(); | ||
| 1566 | try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | // test "resume nosuspend async function calls" { | ||
| 1570 | // const S0 = struct { | ||
| 1571 | // b: i32 = 42, | ||
| 1572 | // }; | ||
| 1573 | // const S1 = struct { | ||
| 1574 | // fn c() S0 { | ||
| 1575 | // suspend {} | ||
| 1576 | // return S0{}; | ||
| 1577 | // } | ||
| 1578 | // fn d() !S0 { | ||
| 1579 | // suspend {} | ||
| 1580 | // return S0{}; | ||
| 1581 | // } | ||
| 1582 | // }; | ||
| 1583 | // var frame_c = nosuspend async S1.c(); | ||
| 1584 | // resume frame_c; | ||
| 1585 | // try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1586 | // var frame_d = nosuspend async S1.d(); | ||
| 1587 | // resume frame_d; | ||
| 1588 | // try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1589 | // } | ||
| 1590 | |||
| 1591 | test "nosuspend resume async function calls" { | ||
| 1592 | const S0 = struct { | ||
| 1593 | b: i32 = 42, | ||
| 1594 | }; | ||
| 1595 | const S1 = struct { | ||
| 1596 | fn c() S0 { | ||
| 1597 | suspend {} | ||
| 1598 | return S0{}; | ||
| 1599 | } | ||
| 1600 | fn d() !S0 { | ||
| 1601 | suspend {} | ||
| 1602 | return S0{}; | ||
| 1603 | } | ||
| 1604 | }; | ||
| 1605 | var frame_c = async S1.c(); | ||
| 1606 | nosuspend resume frame_c; | ||
| 1607 | try expectEqual(@as(i32, 42), (await frame_c).b); | ||
| 1608 | var frame_d = async S1.d(); | ||
| 1609 | nosuspend resume frame_d; | ||
| 1610 | try expectEqual(@as(i32, 42), (try await frame_d).b); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | test "avoid forcing frame alignment resolution implicit cast to *c_void" { | ||
| 1614 | const S = struct { | ||
| 1615 | var x: ?*c_void = null; | ||
| 1616 | |||
| 1617 | fn foo() bool { | ||
| 1618 | suspend { | ||
| 1619 | x = @frame(); | ||
| 1620 | } | ||
| 1621 | return true; | ||
| 1622 | } | ||
| 1623 | }; | ||
| 1624 | var frame = async S.foo(); | ||
| 1625 | resume @ptrCast(anyframe->bool, @alignCast(@alignOf(@Frame(S.foo)), S.x)); | ||
| 1626 | try expect(nosuspend await frame); | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | test "@asyncCall with pass-by-value arguments" { | ||
| 1630 | const F0: u64 = 0xbeefbeefbeefbeef; | ||
| 1631 | const F1: u64 = 0xf00df00df00df00d; | ||
| 1632 | const F2: u64 = 0xcafecafecafecafe; | ||
| 1633 | |||
| 1634 | const S = struct { | ||
| 1635 | pub const ST = struct { f0: usize, f1: usize }; | ||
| 1636 | pub const AT = [5]u8; | ||
| 1637 | |||
| 1638 | pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.Async) void { | ||
| 1639 | // Check that the array and struct arguments passed by value don't | ||
| 1640 | // end up overflowing the adjacent fields in the frame structure. | ||
| 1641 | expectEqual(F0, _fill0) catch @panic("test failure"); | ||
| 1642 | expectEqual(F1, _fill1) catch @panic("test failure"); | ||
| 1643 | expectEqual(F2, _fill2) catch @panic("test failure"); | ||
| 1644 | } | ||
| 1645 | }; | ||
| 1646 | |||
| 1647 | var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; | ||
| 1648 | // The function pointer must not be comptime-known. | ||
| 1649 | var t = S.f; | ||
| 1650 | var frame_ptr = @asyncCall(&buffer, {}, t, .{ | ||
| 1651 | F0, | ||
| 1652 | .{ .f0 = 1, .f1 = 2 }, | ||
| 1653 | F1, | ||
| 1654 | [_]u8{ 1, 2, 3, 4, 5 }, | ||
| 1655 | F2, | ||
| 1656 | }); | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | test "@asyncCall with arguments having non-standard alignment" { | ||
| 1660 | const F0: u64 = 0xbeefbeef; | ||
| 1661 | const F1: u64 = 0xf00df00df00df00d; | ||
| 1662 | |||
| 1663 | const S = struct { | ||
| 1664 | pub fn f(_fill0: u32, s: struct { x: u64 align(16) }, _fill1: u64) callconv(.Async) void { | ||
| 1665 | // The compiler inserts extra alignment for s, check that the | ||
| 1666 | // generated code picks the right slot for fill1. | ||
| 1667 | expectEqual(F0, _fill0) catch @panic("test failure"); | ||
| 1668 | expectEqual(F1, _fill1) catch @panic("test failure"); | ||
| 1669 | } | ||
| 1670 | }; | ||
| 1671 | |||
| 1672 | var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; | ||
| 1673 | // The function pointer must not be comptime-known. | ||
| 1674 | var t = S.f; | ||
| 1675 | var frame_ptr = @asyncCall(&buffer, {}, t, .{ F0, undefined, F1 }); | ||
| 1676 | } | ||
test/stage1/behavior/atomics.zig deleted-219| ... | @@ -1,219 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const builtin = @import("builtin"); | ||
| 5 | |||
| 6 | test "cmpxchg" { | ||
| 7 | try testCmpxchg(); | ||
| 8 | comptime try testCmpxchg(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testCmpxchg() !void { | ||
| 12 | var x: i32 = 1234; | ||
| 13 | if (@cmpxchgWeak(i32, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 14 | try expect(x1 == 1234); | ||
| 15 | } else { | ||
| 16 | @panic("cmpxchg should have failed"); | ||
| 17 | } | ||
| 18 | |||
| 19 | while (@cmpxchgWeak(i32, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 20 | try expect(x1 == 1234); | ||
| 21 | } | ||
| 22 | try expect(x == 5678); | ||
| 23 | |||
| 24 | try expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null); | ||
| 25 | try expect(x == 42); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "fence" { | ||
| 29 | var x: i32 = 1234; | ||
| 30 | @fence(.SeqCst); | ||
| 31 | x = 5678; | ||
| 32 | } | ||
| 33 | |||
| 34 | test "atomicrmw and atomicload" { | ||
| 35 | var data: u8 = 200; | ||
| 36 | try testAtomicRmw(&data); | ||
| 37 | try expect(data == 42); | ||
| 38 | try testAtomicLoad(&data); | ||
| 39 | } | ||
| 40 | |||
| 41 | fn testAtomicRmw(ptr: *u8) !void { | ||
| 42 | const prev_value = @atomicRmw(u8, ptr, .Xchg, 42, .SeqCst); | ||
| 43 | try expect(prev_value == 200); | ||
| 44 | comptime { | ||
| 45 | var x: i32 = 1234; | ||
| 46 | const y: i32 = 12345; | ||
| 47 | try expect(@atomicLoad(i32, &x, .SeqCst) == 1234); | ||
| 48 | try expect(@atomicLoad(i32, &y, .SeqCst) == 12345); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | fn testAtomicLoad(ptr: *u8) !void { | ||
| 53 | const x = @atomicLoad(u8, ptr, .SeqCst); | ||
| 54 | try expect(x == 42); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "cmpxchg with ptr" { | ||
| 58 | var data1: i32 = 1234; | ||
| 59 | var data2: i32 = 5678; | ||
| 60 | var data3: i32 = 9101; | ||
| 61 | var x: *i32 = &data1; | ||
| 62 | if (@cmpxchgWeak(*i32, &x, &data2, &data3, .SeqCst, .SeqCst)) |x1| { | ||
| 63 | try expect(x1 == &data1); | ||
| 64 | } else { | ||
| 65 | @panic("cmpxchg should have failed"); | ||
| 66 | } | ||
| 67 | |||
| 68 | while (@cmpxchgWeak(*i32, &x, &data1, &data3, .SeqCst, .SeqCst)) |x1| { | ||
| 69 | try expect(x1 == &data1); | ||
| 70 | } | ||
| 71 | try expect(x == &data3); | ||
| 72 | |||
| 73 | try expect(@cmpxchgStrong(*i32, &x, &data3, &data2, .SeqCst, .SeqCst) == null); | ||
| 74 | try expect(x == &data2); | ||
| 75 | } | ||
| 76 | |||
| 77 | // TODO this test is disabled until this issue is resolved: | ||
| 78 | // https://github.com/ziglang/zig/issues/2883 | ||
| 79 | // otherwise cross compiling will result in: | ||
| 80 | // lld: error: undefined symbol: __sync_val_compare_and_swap_16 | ||
| 81 | //test "128-bit cmpxchg" { | ||
| 82 | // var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987 | ||
| 83 | // if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 84 | // try expect(x1 == 1234); | ||
| 85 | // } else { | ||
| 86 | // @panic("cmpxchg should have failed"); | ||
| 87 | // } | ||
| 88 | // | ||
| 89 | // while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| { | ||
| 90 | // try expect(x1 == 1234); | ||
| 91 | // } | ||
| 92 | // try expect(x == 5678); | ||
| 93 | // | ||
| 94 | // try expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null); | ||
| 95 | // try expect(x == 42); | ||
| 96 | //} | ||
| 97 | |||
| 98 | test "cmpxchg with ignored result" { | ||
| 99 | var x: i32 = 1234; | ||
| 100 | var ptr = &x; | ||
| 101 | |||
| 102 | _ = @cmpxchgStrong(i32, &x, 1234, 5678, .Monotonic, .Monotonic); | ||
| 103 | |||
| 104 | try expectEqual(@as(i32, 5678), x); | ||
| 105 | } | ||
| 106 | |||
| 107 | var a_global_variable = @as(u32, 1234); | ||
| 108 | |||
| 109 | test "cmpxchg on a global variable" { | ||
| 110 | _ = @cmpxchgWeak(u32, &a_global_variable, 1234, 42, .Acquire, .Monotonic); | ||
| 111 | try expectEqual(@as(u32, 42), a_global_variable); | ||
| 112 | } | ||
| 113 | |||
| 114 | test "atomic load and rmw with enum" { | ||
| 115 | const Value = enum(u8) { | ||
| 116 | a, | ||
| 117 | b, | ||
| 118 | c, | ||
| 119 | }; | ||
| 120 | var x = Value.a; | ||
| 121 | |||
| 122 | try expect(@atomicLoad(Value, &x, .SeqCst) != .b); | ||
| 123 | |||
| 124 | _ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst); | ||
| 125 | try expect(@atomicLoad(Value, &x, .SeqCst) == .c); | ||
| 126 | try expect(@atomicLoad(Value, &x, .SeqCst) != .a); | ||
| 127 | try expect(@atomicLoad(Value, &x, .SeqCst) != .b); | ||
| 128 | } | ||
| 129 | |||
| 130 | test "atomic store" { | ||
| 131 | var x: u32 = 0; | ||
| 132 | @atomicStore(u32, &x, 1, .SeqCst); | ||
| 133 | try expect(@atomicLoad(u32, &x, .SeqCst) == 1); | ||
| 134 | @atomicStore(u32, &x, 12345678, .SeqCst); | ||
| 135 | try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "atomic store comptime" { | ||
| 139 | comptime try testAtomicStore(); | ||
| 140 | try testAtomicStore(); | ||
| 141 | } | ||
| 142 | |||
| 143 | fn testAtomicStore() !void { | ||
| 144 | var x: u32 = 0; | ||
| 145 | @atomicStore(u32, &x, 1, .SeqCst); | ||
| 146 | try expect(@atomicLoad(u32, &x, .SeqCst) == 1); | ||
| 147 | @atomicStore(u32, &x, 12345678, .SeqCst); | ||
| 148 | try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "atomicrmw with floats" { | ||
| 152 | switch (builtin.arch) { | ||
| 153 | // https://github.com/ziglang/zig/issues/4457 | ||
| 154 | .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest, | ||
| 155 | else => {}, | ||
| 156 | } | ||
| 157 | try testAtomicRmwFloat(); | ||
| 158 | comptime try testAtomicRmwFloat(); | ||
| 159 | } | ||
| 160 | |||
| 161 | fn testAtomicRmwFloat() !void { | ||
| 162 | var x: f32 = 0; | ||
| 163 | try expect(x == 0); | ||
| 164 | _ = @atomicRmw(f32, &x, .Xchg, 1, .SeqCst); | ||
| 165 | try expect(x == 1); | ||
| 166 | _ = @atomicRmw(f32, &x, .Add, 5, .SeqCst); | ||
| 167 | try expect(x == 6); | ||
| 168 | _ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst); | ||
| 169 | try expect(x == 4); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "atomicrmw with ints" { | ||
| 173 | try testAtomicRmwInt(); | ||
| 174 | comptime try testAtomicRmwInt(); | ||
| 175 | } | ||
| 176 | |||
| 177 | fn testAtomicRmwInt() !void { | ||
| 178 | var x: u8 = 1; | ||
| 179 | var res = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst); | ||
| 180 | try expect(x == 3 and res == 1); | ||
| 181 | _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst); | ||
| 182 | try expect(x == 6); | ||
| 183 | _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst); | ||
| 184 | try expect(x == 5); | ||
| 185 | _ = @atomicRmw(u8, &x, .And, 4, .SeqCst); | ||
| 186 | try expect(x == 4); | ||
| 187 | _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst); | ||
| 188 | try expect(x == 0xfb); | ||
| 189 | _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst); | ||
| 190 | try expect(x == 0xff); | ||
| 191 | _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst); | ||
| 192 | try expect(x == 0xfd); | ||
| 193 | |||
| 194 | _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst); | ||
| 195 | try expect(x == 0xfd); | ||
| 196 | _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst); | ||
| 197 | try expect(x == 1); | ||
| 198 | } | ||
| 199 | |||
| 200 | test "atomics with different types" { | ||
| 201 | try testAtomicsWithType(bool, true, false); | ||
| 202 | inline for (.{ u1, i4, u5, i15, u24 }) |T| { | ||
| 203 | var x: T = 0; | ||
| 204 | try testAtomicsWithType(T, 0, 1); | ||
| 205 | } | ||
| 206 | try testAtomicsWithType(u0, 0, 0); | ||
| 207 | try testAtomicsWithType(i0, 0, 0); | ||
| 208 | } | ||
| 209 | |||
| 210 | fn testAtomicsWithType(comptime T: type, a: T, b: T) !void { | ||
| 211 | var x: T = b; | ||
| 212 | @atomicStore(T, &x, a, .SeqCst); | ||
| 213 | try expect(x == a); | ||
| 214 | try expect(@atomicLoad(T, &x, .SeqCst) == a); | ||
| 215 | try expect(@atomicRmw(T, &x, .Xchg, b, .SeqCst) == a); | ||
| 216 | try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst) == null); | ||
| 217 | if (@sizeOf(T) != 0) | ||
| 218 | try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a); | ||
| 219 | } | ||
test/stage1/behavior/await_struct.zig deleted-44| ... | @@ -1,44 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const Foo = struct { | ||
| 6 | x: i32, | ||
| 7 | }; | ||
| 8 | |||
| 9 | var await_a_promise: anyframe = undefined; | ||
| 10 | var await_final_result = Foo{ .x = 0 }; | ||
| 11 | |||
| 12 | test "coroutine await struct" { | ||
| 13 | await_seq('a'); | ||
| 14 | var p = async await_amain(); | ||
| 15 | await_seq('f'); | ||
| 16 | resume await_a_promise; | ||
| 17 | await_seq('i'); | ||
| 18 | try expect(await_final_result.x == 1234); | ||
| 19 | try expect(std.mem.eql(u8, &await_points, "abcdefghi")); | ||
| 20 | } | ||
| 21 | fn await_amain() callconv(.Async) void { | ||
| 22 | await_seq('b'); | ||
| 23 | var p = async await_another(); | ||
| 24 | await_seq('e'); | ||
| 25 | await_final_result = await p; | ||
| 26 | await_seq('h'); | ||
| 27 | } | ||
| 28 | fn await_another() callconv(.Async) Foo { | ||
| 29 | await_seq('c'); | ||
| 30 | suspend { | ||
| 31 | await_seq('d'); | ||
| 32 | await_a_promise = @frame(); | ||
| 33 | } | ||
| 34 | await_seq('g'); | ||
| 35 | return Foo{ .x = 1234 }; | ||
| 36 | } | ||
| 37 | |||
| 38 | var await_points = [_]u8{0} ** "abcdefghi".len; | ||
| 39 | var await_seq_index: usize = 0; | ||
| 40 | |||
| 41 | fn await_seq(c: u8) void { | ||
| 42 | await_points[await_seq_index] = c; | ||
| 43 | await_seq_index += 1; | ||
| 44 | } | ||
test/stage1/behavior/bit_shifting.zig deleted-104| ... | @@ -1,104 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { | ||
| 5 | const key_bits = @typeInfo(Key).Int.bits; | ||
| 6 | std.debug.assert(Key == std.meta.Int(.unsigned, key_bits)); | ||
| 7 | std.debug.assert(key_bits >= mask_bit_count); | ||
| 8 | const shard_key_bits = mask_bit_count; | ||
| 9 | const ShardKey = std.meta.Int(.unsigned, mask_bit_count); | ||
| 10 | const shift_amount = key_bits - shard_key_bits; | ||
| 11 | return struct { | ||
| 12 | const Self = @This(); | ||
| 13 | shards: [1 << shard_key_bits]?*Node, | ||
| 14 | |||
| 15 | pub fn create() Self { | ||
| 16 | return Self{ .shards = [_]?*Node{null} ** (1 << shard_key_bits) }; | ||
| 17 | } | ||
| 18 | |||
| 19 | fn getShardKey(key: Key) ShardKey { | ||
| 20 | // https://github.com/ziglang/zig/issues/1544 | ||
| 21 | // this special case is needed because you can't u32 >> 32. | ||
| 22 | if (ShardKey == u0) return 0; | ||
| 23 | |||
| 24 | // this can be u1 >> u0 | ||
| 25 | const shard_key = key >> shift_amount; | ||
| 26 | |||
| 27 | // TODO: https://github.com/ziglang/zig/issues/1544 | ||
| 28 | // This cast could be implicit if we teach the compiler that | ||
| 29 | // u32 >> 30 -> u2 | ||
| 30 | return @intCast(ShardKey, shard_key); | ||
| 31 | } | ||
| 32 | |||
| 33 | pub fn put(self: *Self, node: *Node) void { | ||
| 34 | const shard_key = Self.getShardKey(node.key); | ||
| 35 | node.next = self.shards[shard_key]; | ||
| 36 | self.shards[shard_key] = node; | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn get(self: *Self, key: Key) ?*Node { | ||
| 40 | const shard_key = Self.getShardKey(key); | ||
| 41 | var maybe_node = self.shards[shard_key]; | ||
| 42 | while (maybe_node) |node| : (maybe_node = node.next) { | ||
| 43 | if (node.key == key) return node; | ||
| 44 | } | ||
| 45 | return null; | ||
| 46 | } | ||
| 47 | |||
| 48 | pub const Node = struct { | ||
| 49 | key: Key, | ||
| 50 | value: V, | ||
| 51 | next: ?*Node, | ||
| 52 | |||
| 53 | pub fn init(self: *Node, key: Key, value: V) void { | ||
| 54 | self.key = key; | ||
| 55 | self.value = value; | ||
| 56 | self.next = null; | ||
| 57 | } | ||
| 58 | }; | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | test "sharded table" { | ||
| 63 | // realistic 16-way sharding | ||
| 64 | try testShardedTable(u32, 4, 8); | ||
| 65 | |||
| 66 | try testShardedTable(u5, 0, 32); // ShardKey == u0 | ||
| 67 | try testShardedTable(u5, 2, 32); | ||
| 68 | try testShardedTable(u5, 5, 32); | ||
| 69 | |||
| 70 | try testShardedTable(u1, 0, 2); | ||
| 71 | try testShardedTable(u1, 1, 2); // this does u1 >> u0 | ||
| 72 | |||
| 73 | try testShardedTable(u0, 0, 1); | ||
| 74 | } | ||
| 75 | fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) !void { | ||
| 76 | const Table = ShardedTable(Key, mask_bit_count, void); | ||
| 77 | |||
| 78 | var table = Table.create(); | ||
| 79 | var node_buffer: [node_count]Table.Node = undefined; | ||
| 80 | for (node_buffer) |*node, i| { | ||
| 81 | const key = @intCast(Key, i); | ||
| 82 | try expect(table.get(key) == null); | ||
| 83 | node.init(key, {}); | ||
| 84 | table.put(node); | ||
| 85 | } | ||
| 86 | |||
| 87 | for (node_buffer) |*node, i| { | ||
| 88 | try expect(table.get(@intCast(Key, i)) == node); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | // #2225 | ||
| 93 | test "comptime shr of BigInt" { | ||
| 94 | comptime { | ||
| 95 | var n0 = 0xdeadbeef0000000000000000; | ||
| 96 | try expect(n0 >> 64 == 0xdeadbeef); | ||
| 97 | var n1 = 17908056155735594659; | ||
| 98 | try expect(n1 >> 64 == 0); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | test "comptime shift safety check" { | ||
| 103 | const x = @as(usize, 42) << @sizeOf(usize); | ||
| 104 | } | ||
test/stage1/behavior/bitcast.zig deleted-196| ... | @@ -1,196 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const maxInt = std.math.maxInt; | ||
| 6 | |||
| 7 | test "@bitCast i32 -> u32" { | ||
| 8 | try testBitCast_i32_u32(); | ||
| 9 | comptime try testBitCast_i32_u32(); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn testBitCast_i32_u32() !void { | ||
| 13 | try expect(conv(-1) == maxInt(u32)); | ||
| 14 | try expect(conv2(maxInt(u32)) == -1); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn conv(x: i32) u32 { | ||
| 18 | return @bitCast(u32, x); | ||
| 19 | } | ||
| 20 | fn conv2(x: u32) i32 { | ||
| 21 | return @bitCast(i32, x); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "@bitCast extern enum to its integer type" { | ||
| 25 | const SOCK = extern enum { | ||
| 26 | A, | ||
| 27 | B, | ||
| 28 | |||
| 29 | fn testBitCastExternEnum() !void { | ||
| 30 | var SOCK_DGRAM = @This().B; | ||
| 31 | var sock_dgram = @bitCast(c_int, SOCK_DGRAM); | ||
| 32 | try expect(sock_dgram == 1); | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | try SOCK.testBitCastExternEnum(); | ||
| 37 | comptime try SOCK.testBitCastExternEnum(); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "@bitCast packed structs at runtime and comptime" { | ||
| 41 | const Full = packed struct { | ||
| 42 | number: u16, | ||
| 43 | }; | ||
| 44 | const Divided = packed struct { | ||
| 45 | half1: u8, | ||
| 46 | quarter3: u4, | ||
| 47 | quarter4: u4, | ||
| 48 | }; | ||
| 49 | const S = struct { | ||
| 50 | fn doTheTest() !void { | ||
| 51 | var full = Full{ .number = 0x1234 }; | ||
| 52 | var two_halves = @bitCast(Divided, full); | ||
| 53 | switch (builtin.endian) { | ||
| 54 | builtin.Endian.Big => { | ||
| 55 | try expect(two_halves.half1 == 0x12); | ||
| 56 | try expect(two_halves.quarter3 == 0x3); | ||
| 57 | try expect(two_halves.quarter4 == 0x4); | ||
| 58 | }, | ||
| 59 | builtin.Endian.Little => { | ||
| 60 | try expect(two_halves.half1 == 0x34); | ||
| 61 | try expect(two_halves.quarter3 == 0x2); | ||
| 62 | try expect(two_halves.quarter4 == 0x1); | ||
| 63 | }, | ||
| 64 | } | ||
| 65 | } | ||
| 66 | }; | ||
| 67 | try S.doTheTest(); | ||
| 68 | comptime try S.doTheTest(); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "@bitCast extern structs at runtime and comptime" { | ||
| 72 | const Full = extern struct { | ||
| 73 | number: u16, | ||
| 74 | }; | ||
| 75 | const TwoHalves = extern struct { | ||
| 76 | half1: u8, | ||
| 77 | half2: u8, | ||
| 78 | }; | ||
| 79 | const S = struct { | ||
| 80 | fn doTheTest() !void { | ||
| 81 | var full = Full{ .number = 0x1234 }; | ||
| 82 | var two_halves = @bitCast(TwoHalves, full); | ||
| 83 | switch (builtin.endian) { | ||
| 84 | builtin.Endian.Big => { | ||
| 85 | try expect(two_halves.half1 == 0x12); | ||
| 86 | try expect(two_halves.half2 == 0x34); | ||
| 87 | }, | ||
| 88 | builtin.Endian.Little => { | ||
| 89 | try expect(two_halves.half1 == 0x34); | ||
| 90 | try expect(two_halves.half2 == 0x12); | ||
| 91 | }, | ||
| 92 | } | ||
| 93 | } | ||
| 94 | }; | ||
| 95 | try S.doTheTest(); | ||
| 96 | comptime try S.doTheTest(); | ||
| 97 | } | ||
| 98 | |||
| 99 | test "bitcast packed struct to integer and back" { | ||
| 100 | const LevelUpMove = packed struct { | ||
| 101 | move_id: u9, | ||
| 102 | level: u7, | ||
| 103 | }; | ||
| 104 | const S = struct { | ||
| 105 | fn doTheTest() !void { | ||
| 106 | var move = LevelUpMove{ .move_id = 1, .level = 2 }; | ||
| 107 | var v = @bitCast(u16, move); | ||
| 108 | var back_to_a_move = @bitCast(LevelUpMove, v); | ||
| 109 | try expect(back_to_a_move.move_id == 1); | ||
| 110 | try expect(back_to_a_move.level == 2); | ||
| 111 | } | ||
| 112 | }; | ||
| 113 | try S.doTheTest(); | ||
| 114 | comptime try S.doTheTest(); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "implicit cast to error union by returning" { | ||
| 118 | const S = struct { | ||
| 119 | fn entry() !void { | ||
| 120 | try expect((func(-1) catch unreachable) == maxInt(u64)); | ||
| 121 | } | ||
| 122 | pub fn func(sz: i64) anyerror!u64 { | ||
| 123 | return @bitCast(u64, sz); | ||
| 124 | } | ||
| 125 | }; | ||
| 126 | try S.entry(); | ||
| 127 | comptime try S.entry(); | ||
| 128 | } | ||
| 129 | |||
| 130 | // issue #3010: compiler segfault | ||
| 131 | test "bitcast literal [4]u8 param to u32" { | ||
| 132 | const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); | ||
| 133 | try expect(ip == maxInt(u32)); | ||
| 134 | } | ||
| 135 | |||
| 136 | test "bitcast packed struct literal to byte" { | ||
| 137 | const Foo = packed struct { | ||
| 138 | value: u8, | ||
| 139 | }; | ||
| 140 | const casted = @bitCast(u8, Foo{ .value = 0xF }); | ||
| 141 | try expect(casted == 0xf); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "comptime bitcast used in expression has the correct type" { | ||
| 145 | const Foo = packed struct { | ||
| 146 | value: u8, | ||
| 147 | }; | ||
| 148 | try expect(@bitCast(u8, Foo{ .value = 0xF }) == 0xf); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "bitcast result to _" { | ||
| 152 | _ = @bitCast(u8, @as(i8, 1)); | ||
| 153 | } | ||
| 154 | |||
| 155 | test "nested bitcast" { | ||
| 156 | const S = struct { | ||
| 157 | fn moo(x: isize) !void { | ||
| 158 | try @import("std").testing.expectEqual(@intCast(isize, 42), x); | ||
| 159 | } | ||
| 160 | |||
| 161 | fn foo(x: isize) !void { | ||
| 162 | try @This().moo( | ||
| 163 | @bitCast(isize, if (x != 0) @bitCast(usize, x) else @bitCast(usize, x)), | ||
| 164 | ); | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | |||
| 168 | try S.foo(42); | ||
| 169 | comptime try S.foo(42); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "bitcast passed as tuple element" { | ||
| 173 | const S = struct { | ||
| 174 | fn foo(args: anytype) !void { | ||
| 175 | comptime try expect(@TypeOf(args[0]) == f32); | ||
| 176 | try expect(args[0] == 12.34); | ||
| 177 | } | ||
| 178 | }; | ||
| 179 | try S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))}); | ||
| 180 | } | ||
| 181 | |||
| 182 | test "triple level result location with bitcast sandwich passed as tuple element" { | ||
| 183 | const S = struct { | ||
| 184 | fn foo(args: anytype) !void { | ||
| 185 | comptime try expect(@TypeOf(args[0]) == f64); | ||
| 186 | try expect(args[0] > 12.33 and args[0] < 12.35); | ||
| 187 | } | ||
| 188 | }; | ||
| 189 | try S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); | ||
| 190 | } | ||
| 191 | |||
| 192 | test "bitcast generates a temporary value" { | ||
| 193 | var y = @as(u16, 0x55AA); | ||
| 194 | const x = @bitCast(u16, @bitCast([2]u8, y)); | ||
| 195 | try expectEqual(y, x); | ||
| 196 | } | ||
test/stage1/behavior/bitreverse.zig deleted-69| ... | @@ -1,69 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const minInt = std.math.minInt; | ||
| 4 | |||
| 5 | test "@bitReverse" { | ||
| 6 | comptime try testBitReverse(); | ||
| 7 | try testBitReverse(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testBitReverse() !void { | ||
| 11 | // using comptime_ints, unsigned | ||
| 12 | try expect(@bitReverse(u0, 0) == 0); | ||
| 13 | try expect(@bitReverse(u5, 0x12) == 0x9); | ||
| 14 | try expect(@bitReverse(u8, 0x12) == 0x48); | ||
| 15 | try expect(@bitReverse(u16, 0x1234) == 0x2c48); | ||
| 16 | try expect(@bitReverse(u24, 0x123456) == 0x6a2c48); | ||
| 17 | try expect(@bitReverse(u32, 0x12345678) == 0x1e6a2c48); | ||
| 18 | try expect(@bitReverse(u40, 0x123456789a) == 0x591e6a2c48); | ||
| 19 | try expect(@bitReverse(u48, 0x123456789abc) == 0x3d591e6a2c48); | ||
| 20 | try expect(@bitReverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); | ||
| 21 | try expect(@bitReverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); | ||
| 22 | try expect(@bitReverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 23 | |||
| 24 | // using runtime uints, unsigned | ||
| 25 | var num0: u0 = 0; | ||
| 26 | try expect(@bitReverse(u0, num0) == 0); | ||
| 27 | var num5: u5 = 0x12; | ||
| 28 | try expect(@bitReverse(u5, num5) == 0x9); | ||
| 29 | var num8: u8 = 0x12; | ||
| 30 | try expect(@bitReverse(u8, num8) == 0x48); | ||
| 31 | var num16: u16 = 0x1234; | ||
| 32 | try expect(@bitReverse(u16, num16) == 0x2c48); | ||
| 33 | var num24: u24 = 0x123456; | ||
| 34 | try expect(@bitReverse(u24, num24) == 0x6a2c48); | ||
| 35 | var num32: u32 = 0x12345678; | ||
| 36 | try expect(@bitReverse(u32, num32) == 0x1e6a2c48); | ||
| 37 | var num40: u40 = 0x123456789a; | ||
| 38 | try expect(@bitReverse(u40, num40) == 0x591e6a2c48); | ||
| 39 | var num48: u48 = 0x123456789abc; | ||
| 40 | try expect(@bitReverse(u48, num48) == 0x3d591e6a2c48); | ||
| 41 | var num56: u56 = 0x123456789abcde; | ||
| 42 | try expect(@bitReverse(u56, num56) == 0x7b3d591e6a2c48); | ||
| 43 | var num64: u64 = 0x123456789abcdef1; | ||
| 44 | try expect(@bitReverse(u64, num64) == 0x8f7b3d591e6a2c48); | ||
| 45 | var num128: u128 = 0x123456789abcdef11121314151617181; | ||
| 46 | try expect(@bitReverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); | ||
| 47 | |||
| 48 | // using comptime_ints, signed, positive | ||
| 49 | try expect(@bitReverse(u8, @as(u8, 0)) == 0); | ||
| 50 | try expect(@bitReverse(i8, @bitCast(i8, @as(u8, 0x92))) == @bitCast(i8, @as(u8, 0x49))); | ||
| 51 | try expect(@bitReverse(i16, @bitCast(i16, @as(u16, 0x1234))) == @bitCast(i16, @as(u16, 0x2c48))); | ||
| 52 | try expect(@bitReverse(i24, @bitCast(i24, @as(u24, 0x123456))) == @bitCast(i24, @as(u24, 0x6a2c48))); | ||
| 53 | try expect(@bitReverse(i32, @bitCast(i32, @as(u32, 0x12345678))) == @bitCast(i32, @as(u32, 0x1e6a2c48))); | ||
| 54 | try expect(@bitReverse(i40, @bitCast(i40, @as(u40, 0x123456789a))) == @bitCast(i40, @as(u40, 0x591e6a2c48))); | ||
| 55 | try expect(@bitReverse(i48, @bitCast(i48, @as(u48, 0x123456789abc))) == @bitCast(i48, @as(u48, 0x3d591e6a2c48))); | ||
| 56 | try expect(@bitReverse(i56, @bitCast(i56, @as(u56, 0x123456789abcde))) == @bitCast(i56, @as(u56, 0x7b3d591e6a2c48))); | ||
| 57 | try expect(@bitReverse(i64, @bitCast(i64, @as(u64, 0x123456789abcdef1))) == @bitCast(i64, @as(u64, 0x8f7b3d591e6a2c48))); | ||
| 58 | try expect(@bitReverse(i128, @bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181))) == @bitCast(i128, @as(u128, 0x818e868a828c84888f7b3d591e6a2c48))); | ||
| 59 | |||
| 60 | // using signed, negative. Compare to runtime ints returned from llvm. | ||
| 61 | var neg8: i8 = -18; | ||
| 62 | try expect(@bitReverse(i8, @as(i8, -18)) == @bitReverse(i8, neg8)); | ||
| 63 | var neg16: i16 = -32694; | ||
| 64 | try expect(@bitReverse(i16, @as(i16, -32694)) == @bitReverse(i16, neg16)); | ||
| 65 | var neg24: i24 = -6773785; | ||
| 66 | try expect(@bitReverse(i24, @as(i24, -6773785)) == @bitReverse(i24, neg24)); | ||
| 67 | var neg32: i32 = -16773785; | ||
| 68 | try expect(@bitReverse(i32, @as(i32, -16773785)) == @bitReverse(i32, neg32)); | ||
| 69 | } | ||
test/stage1/behavior/bool.zig deleted-35| ... | @@ -1,35 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "bool literals" { | ||
| 4 | try expect(true); | ||
| 5 | try expect(!false); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "cast bool to int" { | ||
| 9 | const t = true; | ||
| 10 | const f = false; | ||
| 11 | try expect(@boolToInt(t) == @as(u32, 1)); | ||
| 12 | try expect(@boolToInt(f) == @as(u32, 0)); | ||
| 13 | try nonConstCastBoolToInt(t, f); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn nonConstCastBoolToInt(t: bool, f: bool) !void { | ||
| 17 | try expect(@boolToInt(t) == @as(u32, 1)); | ||
| 18 | try expect(@boolToInt(f) == @as(u32, 0)); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "bool cmp" { | ||
| 22 | try expect(testBoolCmp(true, false) == false); | ||
| 23 | } | ||
| 24 | fn testBoolCmp(a: bool, b: bool) bool { | ||
| 25 | return a == b; | ||
| 26 | } | ||
| 27 | |||
| 28 | const global_f = false; | ||
| 29 | const global_t = true; | ||
| 30 | const not_global_f = !global_f; | ||
| 31 | const not_global_t = !global_t; | ||
| 32 | test "compile time bool not" { | ||
| 33 | try expect(not_global_f); | ||
| 34 | try expect(!not_global_t); | ||
| 35 | } | ||
test/stage1/behavior/bugs/1025.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const A = struct { | ||
| 2 | B: type, | ||
| 3 | }; | ||
| 4 | |||
| 5 | fn getA() A { | ||
| 6 | return A{ .B = u8 }; | ||
| 7 | } | ||
| 8 | |||
| 9 | test "bug 1025" { | ||
| 10 | const a = getA(); | ||
| 11 | try @import("std").testing.expect(a.B == u8); | ||
| 12 | } | ||
test/stage1/behavior/bugs/1076.zig deleted-23| ... | @@ -1,23 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "comptime code should not modify constant data" { | ||
| 6 | try testCastPtrOfArrayToSliceAndPtr(); | ||
| 7 | comptime try testCastPtrOfArrayToSliceAndPtr(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testCastPtrOfArrayToSliceAndPtr() !void { | ||
| 11 | { | ||
| 12 | var array = "aoeu".*; | ||
| 13 | const x: [*]u8 = &array; | ||
| 14 | x[0] += 1; | ||
| 15 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var array: [4]u8 = "aoeu".*; | ||
| 19 | const x: [*]u8 = &array; | ||
| 20 | x[0] += 1; | ||
| 21 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 22 | } | ||
| 23 | } | ||
test/stage1/behavior/bugs/1111.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const Foo = extern enum { | ||
| 2 | Bar = -1, | ||
| 3 | }; | ||
| 4 | |||
| 5 | test "issue 1111 fixed" { | ||
| 6 | const v = Foo.Bar; | ||
| 7 | |||
| 8 | switch (v) { | ||
| 9 | Foo.Bar => return, | ||
| 10 | } | ||
| 11 | } | ||
test/stage1/behavior/bugs/1120.zig deleted-23| ... | @@ -1,23 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const A = packed struct { | ||
| 5 | a: u2, | ||
| 6 | b: u6, | ||
| 7 | }; | ||
| 8 | const B = packed struct { | ||
| 9 | q: u8, | ||
| 10 | a: u2, | ||
| 11 | b: u6, | ||
| 12 | }; | ||
| 13 | test "bug 1120" { | ||
| 14 | var a = A{ .a = 2, .b = 2 }; | ||
| 15 | var b = B{ .q = 22, .a = 3, .b = 2 }; | ||
| 16 | var t: usize = 0; | ||
| 17 | const ptr = switch (t) { | ||
| 18 | 0 => &a.a, | ||
| 19 | 1 => &b.a, | ||
| 20 | else => unreachable, | ||
| 21 | }; | ||
| 22 | try expect(ptr.* == 2); | ||
| 23 | } | ||
test/stage1/behavior/bugs/1277.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const S = struct { | ||
| 4 | f: ?fn () i32, | ||
| 5 | }; | ||
| 6 | |||
| 7 | const s = S{ .f = f }; | ||
| 8 | |||
| 9 | fn f() i32 { | ||
| 10 | return 1234; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "don't emit an LLVM global for a const function when it's in an optional in a struct" { | ||
| 14 | try std.testing.expect(s.f.?() == 1234); | ||
| 15 | } | ||
test/stage1/behavior/bugs/1310.zig deleted-24| ... | @@ -1,24 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | pub const VM = ?[*]const struct_InvocationTable_; | ||
| 5 | pub const struct_InvocationTable_ = extern struct { | ||
| 6 | GetVM: ?fn (?[*]VM) callconv(.C) c_int, | ||
| 7 | }; | ||
| 8 | |||
| 9 | pub const struct_VM_ = extern struct { | ||
| 10 | functions: ?[*]const struct_InvocationTable_, | ||
| 11 | }; | ||
| 12 | |||
| 13 | //excised output from stdlib.h etc | ||
| 14 | |||
| 15 | pub const InvocationTable_ = struct_InvocationTable_; | ||
| 16 | pub const VM_ = struct_VM_; | ||
| 17 | |||
| 18 | fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 { | ||
| 19 | return 11; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "fixed" { | ||
| 23 | try expect(agent_callback(undefined, undefined) == 11); | ||
| 24 | } | ||
test/stage1/behavior/bugs/1322.zig deleted-19| ... | @@ -1,19 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | c: C, | ||
| 5 | None, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = struct { | ||
| 9 | b: B, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const C = struct {}; | ||
| 13 | |||
| 14 | test "tagged union with all void fields but a meaningful tag" { | ||
| 15 | var a: A = A{ .b = B{ .c = C{} } }; | ||
| 16 | try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).c); | ||
| 17 | a = A{ .b = B.None }; | ||
| 18 | try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).None); | ||
| 19 | } | ||
test/stage1/behavior/bugs/1381.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | D: u8, | ||
| 5 | E: u16, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = union(enum) { | ||
| 9 | B: B, | ||
| 10 | C: u8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "union that needs padding bytes inside an array" { | ||
| 14 | var as = [_]A{ | ||
| 15 | A{ .B = B{ .D = 1 } }, | ||
| 16 | A{ .B = B{ .D = 1 } }, | ||
| 17 | }; | ||
| 18 | |||
| 19 | const a = as[0].B; | ||
| 20 | try std.testing.expect(a.D == 1); | ||
| 21 | } | ||
test/stage1/behavior/bugs/1421.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | const S = struct { | ||
| 6 | fn method() builtin.TypeInfo { | ||
| 7 | return @typeInfo(S); | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | test "functions with return type required to be comptime are generic" { | ||
| 12 | const ti = S.method(); | ||
| 13 | try expect(@as(builtin.TypeId, ti) == builtin.TypeId.Struct); | ||
| 14 | } | ||
test/stage1/behavior/bugs/1442.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Union = union(enum) { | ||
| 4 | Text: []const u8, | ||
| 5 | Color: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | test "const error union field alignment" { | ||
| 9 | var union_or_err: anyerror!Union = Union{ .Color = 1234 }; | ||
| 10 | try std.testing.expect((union_or_err catch unreachable).Color == 1234); | ||
| 11 | } | ||
test/stage1/behavior/bugs/1467.zig deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | pub const E = enum(u32) { A, B, C }; | ||
| 2 | pub const S = extern struct { | ||
| 3 | e: E, | ||
| 4 | }; | ||
| 5 | test "bug 1467" { | ||
| 6 | const s: S = undefined; | ||
| 7 | } | ||
test/stage1/behavior/bugs/1486.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const ptr = &global; | ||
| 4 | var global: u64 = 123; | ||
| 5 | |||
| 6 | test "constant pointer to global variable causes runtime load" { | ||
| 7 | global = 1234; | ||
| 8 | try expect(&global == ptr); | ||
| 9 | try expect(ptr.* == 1234); | ||
| 10 | } | ||
test/stage1/behavior/bugs/1500.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | const A = struct { | ||
| 2 | b: B, | ||
| 3 | }; | ||
| 4 | |||
| 5 | const B = fn (A) void; | ||
| 6 | |||
| 7 | test "allow these dependencies" { | ||
| 8 | var a: A = undefined; | ||
| 9 | var b: B = undefined; | ||
| 10 | } | ||
test/stage1/behavior/bugs/1607.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | |||
| 4 | const a = [_]u8{ 1, 2, 3 }; | ||
| 5 | |||
| 6 | fn checkAddress(s: []const u8) !void { | ||
| 7 | for (s) |*i, j| { | ||
| 8 | try testing.expect(i == &a[j]); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | test "slices pointing at the same address as global array." { | ||
| 13 | try checkAddress(&a); | ||
| 14 | comptime try checkAddress(&a); | ||
| 15 | } | ||
test/stage1/behavior/bugs/1735.zig deleted-46| ... | @@ -1,46 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const mystruct = struct { | ||
| 4 | pending: ?listofstructs, | ||
| 5 | }; | ||
| 6 | pub fn TailQueue(comptime T: type) type { | ||
| 7 | return struct { | ||
| 8 | const Self = @This(); | ||
| 9 | |||
| 10 | pub const Node = struct { | ||
| 11 | prev: ?*Node, | ||
| 12 | next: ?*Node, | ||
| 13 | data: T, | ||
| 14 | }; | ||
| 15 | |||
| 16 | first: ?*Node, | ||
| 17 | last: ?*Node, | ||
| 18 | len: usize, | ||
| 19 | |||
| 20 | pub fn init() Self { | ||
| 21 | return Self{ | ||
| 22 | .first = null, | ||
| 23 | .last = null, | ||
| 24 | .len = 0, | ||
| 25 | }; | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | } | ||
| 29 | const listofstructs = TailQueue(mystruct); | ||
| 30 | |||
| 31 | const a = struct { | ||
| 32 | const Self = @This(); | ||
| 33 | |||
| 34 | foo: listofstructs, | ||
| 35 | |||
| 36 | pub fn init() Self { | ||
| 37 | return Self{ | ||
| 38 | .foo = listofstructs.init(), | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | test "intialization" { | ||
| 44 | var t = a.init(); | ||
| 45 | try std.testing.expect(t.foo.len == 0); | ||
| 46 | } | ||
test/stage1/behavior/bugs/1741.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "fixed" { | ||
| 4 | const x: f32 align(128) = 12.34; | ||
| 5 | try std.testing.expect(@ptrToInt(&x) % 128 == 0); | ||
| 6 | } | ||
test/stage1/behavior/bugs/1851.zig deleted-26| ... | @@ -1,26 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "allocation and looping over 3-byte integer" { | ||
| 5 | try expect(@sizeOf(u24) == 4); | ||
| 6 | try expect(@sizeOf([1]u24) == 4); | ||
| 7 | try expect(@alignOf(u24) == 4); | ||
| 8 | try expect(@alignOf([1]u24) == 4); | ||
| 9 | |||
| 10 | var x = try std.testing.allocator.alloc(u24, 2); | ||
| 11 | defer std.testing.allocator.free(x); | ||
| 12 | try expect(x.len == 2); | ||
| 13 | x[0] = 0xFFFFFF; | ||
| 14 | x[1] = 0xFFFFFF; | ||
| 15 | |||
| 16 | const bytes = std.mem.sliceAsBytes(x); | ||
| 17 | try expect(@TypeOf(bytes) == []align(4) u8); | ||
| 18 | try expect(bytes.len == 8); | ||
| 19 | |||
| 20 | for (bytes) |*b| { | ||
| 21 | b.* = 0x00; | ||
| 22 | } | ||
| 23 | |||
| 24 | try expect(x[0] == 0x00); | ||
| 25 | try expect(x[1] == 0x00); | ||
| 26 | } | ||
test/stage1/behavior/bugs/1914.zig deleted-31| ... | @@ -1,31 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const A = struct { | ||
| 4 | b_list_pointer: *const []B, | ||
| 5 | }; | ||
| 6 | const B = struct { | ||
| 7 | a_pointer: *const A, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const b_list: []B = &[_]B{}; | ||
| 11 | const a = A{ .b_list_pointer = &b_list }; | ||
| 12 | |||
| 13 | test "segfault bug" { | ||
| 14 | const assert = std.debug.assert; | ||
| 15 | const obj = B{ .a_pointer = &a }; | ||
| 16 | assert(obj.a_pointer == &a); // this makes zig crash | ||
| 17 | } | ||
| 18 | |||
| 19 | const A2 = struct { | ||
| 20 | pointer: *B, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub const B2 = struct { | ||
| 24 | pointer_array: []*A2, | ||
| 25 | }; | ||
| 26 | |||
| 27 | var b_value = B2{ .pointer_array = &[_]*A2{} }; | ||
| 28 | |||
| 29 | test "basic stuff" { | ||
| 30 | std.debug.assert(&b_value == &b_value); | ||
| 31 | } | ||
test/stage1/behavior/bugs/2006.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const S = struct { | ||
| 5 | p: *S, | ||
| 6 | }; | ||
| 7 | test "bug 2006" { | ||
| 8 | var a: S = undefined; | ||
| 9 | a = S{ .p = undefined }; | ||
| 10 | try expect(@sizeOf(S) != 0); | ||
| 11 | try expect(@sizeOf(*void) == 0); | ||
| 12 | } | ||
test/stage1/behavior/bugs/2114.zig deleted-19| ... | @@ -1,19 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const math = std.math; | ||
| 4 | |||
| 5 | fn ctz(x: anytype) usize { | ||
| 6 | return @ctz(@TypeOf(x), x); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "fixed" { | ||
| 10 | try testClz(); | ||
| 11 | comptime try testClz(); | ||
| 12 | } | ||
| 13 | |||
| 14 | fn testClz() !void { | ||
| 15 | try expect(ctz(@as(u128, 0x40000000000000000000000000000000)) == 126); | ||
| 16 | try expect(math.rotl(u128, @as(u128, 0x40000000000000000000000000000000), @as(u8, 1)) == @as(u128, 0x80000000000000000000000000000000)); | ||
| 17 | try expect(ctz(@as(u128, 0x80000000000000000000000000000000)) == 127); | ||
| 18 | try expect(ctz(math.rotl(u128, @as(u128, 0x40000000000000000000000000000000), @as(u8, 1))) == 127); | ||
| 19 | } | ||
test/stage1/behavior/bugs/2346.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | test "fixed" { | ||
| 2 | const a: *void = undefined; | ||
| 3 | const b: *[1]void = a; | ||
| 4 | const c: *[0]u8 = undefined; | ||
| 5 | const d: []u8 = c; | ||
| 6 | } | ||
test/stage1/behavior/bugs/2578.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | y: u8, | ||
| 3 | }; | ||
| 4 | |||
| 5 | var foo: Foo = undefined; | ||
| 6 | const t = &foo; | ||
| 7 | |||
| 8 | fn bar(pointer: ?*c_void) void {} | ||
| 9 | |||
| 10 | test "fixed" { | ||
| 11 | bar(t); | ||
| 12 | } | ||
test/stage1/behavior/bugs/2692.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | fn foo(a: []u8) void {} | ||
| 2 | |||
| 3 | test "address of 0 length array" { | ||
| 4 | var pt: [0]u8 = undefined; | ||
| 5 | foo(&pt); | ||
| 6 | } | ||
test/stage1/behavior/bugs/2889.zig deleted-31| ... | @@ -1,31 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const source = "A-"; | ||
| 4 | |||
| 5 | fn parseNote() ?i32 { | ||
| 6 | const letter = source[0]; | ||
| 7 | const modifier = source[1]; | ||
| 8 | |||
| 9 | const semitone = blk: { | ||
| 10 | if (letter == 'C' and modifier == '-') break :blk @as(i32, 0); | ||
| 11 | if (letter == 'C' and modifier == '#') break :blk @as(i32, 1); | ||
| 12 | if (letter == 'D' and modifier == '-') break :blk @as(i32, 2); | ||
| 13 | if (letter == 'D' and modifier == '#') break :blk @as(i32, 3); | ||
| 14 | if (letter == 'E' and modifier == '-') break :blk @as(i32, 4); | ||
| 15 | if (letter == 'F' and modifier == '-') break :blk @as(i32, 5); | ||
| 16 | if (letter == 'F' and modifier == '#') break :blk @as(i32, 6); | ||
| 17 | if (letter == 'G' and modifier == '-') break :blk @as(i32, 7); | ||
| 18 | if (letter == 'G' and modifier == '#') break :blk @as(i32, 8); | ||
| 19 | if (letter == 'A' and modifier == '-') break :blk @as(i32, 9); | ||
| 20 | if (letter == 'A' and modifier == '#') break :blk @as(i32, 10); | ||
| 21 | if (letter == 'B' and modifier == '-') break :blk @as(i32, 11); | ||
| 22 | return null; | ||
| 23 | }; | ||
| 24 | |||
| 25 | return semitone; | ||
| 26 | } | ||
| 27 | |||
| 28 | test "fixed" { | ||
| 29 | const result = parseNote(); | ||
| 30 | try std.testing.expect(result.? == 9); | ||
| 31 | } | ||
test/stage1/behavior/bugs/3007.zig deleted-23| ... | @@ -1,23 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | free: bool, | ||
| 5 | |||
| 6 | pub const FooError = error{NotFree}; | ||
| 7 | }; | ||
| 8 | |||
| 9 | var foo = Foo{ .free = true }; | ||
| 10 | var default_foo: ?*Foo = null; | ||
| 11 | |||
| 12 | fn get_foo() Foo.FooError!*Foo { | ||
| 13 | if (foo.free) { | ||
| 14 | foo.free = false; | ||
| 15 | return &foo; | ||
| 16 | } | ||
| 17 | return error.NotFree; | ||
| 18 | } | ||
| 19 | |||
| 20 | test "fixed" { | ||
| 21 | default_foo = get_foo() catch null; // This Line | ||
| 22 | try std.testing.expect(!default_foo.?.free); | ||
| 23 | } | ||
test/stage1/behavior/bugs/3046.zig deleted-19| ... | @@ -1,19 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const SomeStruct = struct { | ||
| 5 | field: i32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn couldFail() anyerror!i32 { | ||
| 9 | return 1; | ||
| 10 | } | ||
| 11 | |||
| 12 | var some_struct: SomeStruct = undefined; | ||
| 13 | |||
| 14 | test "fixed" { | ||
| 15 | some_struct = SomeStruct{ | ||
| 16 | .field = couldFail() catch |_| @as(i32, 0), | ||
| 17 | }; | ||
| 18 | try expect(some_struct.field == 1); | ||
| 19 | } | ||
test/stage1/behavior/bugs/3112.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const State = struct { | ||
| 5 | const Self = @This(); | ||
| 6 | enter: fn (previous: ?Self) void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | fn prev(p: ?State) void { | ||
| 10 | expect(p == null) catch @panic("test failure"); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "zig test crash" { | ||
| 14 | var global: State = undefined; | ||
| 15 | global.enter = prev; | ||
| 16 | global.enter(null); | ||
| 17 | } | ||
test/stage1/behavior/bugs/3367.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | usingnamespace Mixin; | ||
| 3 | }; | ||
| 4 | |||
| 5 | const Mixin = struct { | ||
| 6 | pub fn two(self: Foo) void {} | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "container member access usingnamespace decls" { | ||
| 10 | var foo = Foo{}; | ||
| 11 | foo.two(); | ||
| 12 | } | ||
test/stage1/behavior/bugs/3384.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "resolve array slice using builtin" { | ||
| 5 | try expect(@hasDecl(@This(), "std") == true); | ||
| 6 | try expect(@hasDecl(@This(), "std"[0..0]) == false); | ||
| 7 | try expect(@hasDecl(@This(), "std"[0..1]) == false); | ||
| 8 | try expect(@hasDecl(@This(), "std"[0..2]) == false); | ||
| 9 | try expect(@hasDecl(@This(), "std"[0..3]) == true); | ||
| 10 | try expect(@hasDecl(@This(), "std"[0..]) == true); | ||
| 11 | } | ||
test/stage1/behavior/bugs/3468.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | // zig fmt: off | ||
| 2 | test "pointer deref next to assignment" { | ||
| 3 | var a:i32=2; | ||
| 4 | var b=&a; | ||
| 5 | b.*=3; | ||
| 6 | } | ||
test/stage1/behavior/bugs/3586.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | const NoteParams = struct {}; | ||
| 2 | |||
| 3 | const Container = struct { | ||
| 4 | params: ?NoteParams, | ||
| 5 | }; | ||
| 6 | |||
| 7 | test "fixed" { | ||
| 8 | var ctr = Container{ | ||
| 9 | .params = NoteParams{}, | ||
| 10 | }; | ||
| 11 | } | ||
test/stage1/behavior/bugs/3742.zig deleted-38| ... | @@ -1,38 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub const GET = struct { | ||
| 4 | key: []const u8, | ||
| 5 | |||
| 6 | pub fn init(key: []const u8) GET { | ||
| 7 | return .{ .key = key }; | ||
| 8 | } | ||
| 9 | |||
| 10 | pub const Redis = struct { | ||
| 11 | pub const Command = struct { | ||
| 12 | pub fn serialize(self: GET, comptime rootSerializer: type) void { | ||
| 13 | return rootSerializer.serializeCommand(.{ "GET", self.key }); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub fn isCommand(comptime T: type) bool { | ||
| 20 | const tid = @typeInfo(T); | ||
| 21 | return (tid == .Struct or tid == .Enum or tid == .Union) and | ||
| 22 | @hasDecl(T, "Redis") and @hasDecl(T.Redis, "Command"); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub const ArgSerializer = struct { | ||
| 26 | pub fn serializeCommand(command: anytype) void { | ||
| 27 | const CmdT = @TypeOf(command); | ||
| 28 | |||
| 29 | if (comptime isCommand(CmdT)) { | ||
| 30 | // COMMENTING THE NEXT LINE REMOVES THE ERROR | ||
| 31 | return CmdT.Redis.Command.serialize(command, ArgSerializer); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | test "fixed" { | ||
| 37 | ArgSerializer.serializeCommand(GET.init("banana")); | ||
| 38 | } | ||
test/stage1/behavior/bugs/394.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | const E = union(enum) { | ||
| 2 | A: [9]u8, | ||
| 3 | B: u64, | ||
| 4 | }; | ||
| 5 | const S = struct { | ||
| 6 | x: u8, | ||
| 7 | y: E, | ||
| 8 | }; | ||
| 9 | |||
| 10 | const expect = @import("std").testing.expect; | ||
| 11 | |||
| 12 | test "bug 394 fixed" { | ||
| 13 | const x = S{ | ||
| 14 | .x = 3, | ||
| 15 | .y = E{ .B = 1 }, | ||
| 16 | }; | ||
| 17 | try expect(x.x == 3); | ||
| 18 | } | ||
test/stage1/behavior/bugs/421.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "bitCast to array" { | ||
| 4 | comptime try testBitCastArray(); | ||
| 5 | try testBitCastArray(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testBitCastArray() !void { | ||
| 9 | try expect(extractOne64(0x0123456789abcdef0123456789abcdef) == 0x0123456789abcdef); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn extractOne64(a: u128) u64 { | ||
| 13 | const x = @bitCast([2]u64, a); | ||
| 14 | return x[1]; | ||
| 15 | } | ||
test/stage1/behavior/bugs/4328.zig deleted-71| ... | @@ -1,71 +0,0 @@ | ||
| 1 | const expectEqual = @import("std").testing.expectEqual; | ||
| 2 | |||
| 3 | const FILE = extern struct { | ||
| 4 | dummy_field: u8, | ||
| 5 | }; | ||
| 6 | |||
| 7 | extern fn printf([*c]const u8, ...) c_int; | ||
| 8 | extern fn fputs([*c]const u8, noalias [*c]FILE) c_int; | ||
| 9 | extern fn ftell([*c]FILE) c_long; | ||
| 10 | extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE; | ||
| 11 | |||
| 12 | const S = extern struct { | ||
| 13 | state: c_short, | ||
| 14 | |||
| 15 | extern fn s_do_thing([*c]S, b: c_int) c_short; | ||
| 16 | }; | ||
| 17 | |||
| 18 | test "Extern function calls in @TypeOf" { | ||
| 19 | const Test = struct { | ||
| 20 | fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) { | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn test_fn_2(a: anytype) @TypeOf((S{ .state = 0 }).s_do_thing(a)) { | ||
| 25 | return 1; | ||
| 26 | } | ||
| 27 | |||
| 28 | fn doTheTest() !void { | ||
| 29 | try expectEqual(c_int, @TypeOf(test_fn_1(0, 42))); | ||
| 30 | try expectEqual(c_short, @TypeOf(test_fn_2(0))); | ||
| 31 | } | ||
| 32 | }; | ||
| 33 | |||
| 34 | try Test.doTheTest(); | ||
| 35 | comptime try Test.doTheTest(); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "Peer resolution of extern function calls in @TypeOf" { | ||
| 39 | const Test = struct { | ||
| 40 | fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | fn doTheTest() !void { | ||
| 45 | try expectEqual(c_long, @TypeOf(test_fn())); | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | try Test.doTheTest(); | ||
| 50 | comptime try Test.doTheTest(); | ||
| 51 | } | ||
| 52 | |||
| 53 | test "Extern function calls, dereferences and field access in @TypeOf" { | ||
| 54 | const Test = struct { | ||
| 55 | fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) { | ||
| 56 | return .{ .dummy_field = 0 }; | ||
| 57 | } | ||
| 58 | |||
| 59 | fn test_fn_2(a: anytype) @TypeOf(fopen("test", "r").*.dummy_field) { | ||
| 60 | return 255; | ||
| 61 | } | ||
| 62 | |||
| 63 | fn doTheTest() !void { | ||
| 64 | try expectEqual(FILE, @TypeOf(test_fn_1(0))); | ||
| 65 | try expectEqual(u8, @TypeOf(test_fn_2(0))); | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | |||
| 69 | try Test.doTheTest(); | ||
| 70 | comptime try Test.doTheTest(); | ||
| 71 | } | ||
test/stage1/behavior/bugs/4560.zig deleted-32| ... | @@ -1,32 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "fixed" { | ||
| 4 | var s: S = .{ | ||
| 5 | .a = 1, | ||
| 6 | .b = .{ | ||
| 7 | .size = 123, | ||
| 8 | .max_distance_from_start_index = 456, | ||
| 9 | }, | ||
| 10 | }; | ||
| 11 | try std.testing.expect(s.a == 1); | ||
| 12 | try std.testing.expect(s.b.size == 123); | ||
| 13 | try std.testing.expect(s.b.max_distance_from_start_index == 456); | ||
| 14 | } | ||
| 15 | |||
| 16 | const S = struct { | ||
| 17 | a: u32, | ||
| 18 | b: Map, | ||
| 19 | |||
| 20 | const Map = StringHashMap(*S); | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub fn StringHashMap(comptime V: type) type { | ||
| 24 | return HashMap([]const u8, V); | ||
| 25 | } | ||
| 26 | |||
| 27 | pub fn HashMap(comptime K: type, comptime V: type) type { | ||
| 28 | return struct { | ||
| 29 | size: usize, | ||
| 30 | max_distance_from_start_index: usize, | ||
| 31 | }; | ||
| 32 | } | ||
test/stage1/behavior/bugs/4769_a.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | // | ||
test/stage1/behavior/bugs/4769_b.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | //! | ||
test/stage1/behavior/bugs/4769_c.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | /// | ||
| \ No newline at end of file | |||
test/stage1/behavior/bugs/4954.zig deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | fn f(buf: []u8) void { | ||
| 2 | var ptr = &buf[@sizeOf(u32)]; | ||
| 3 | } | ||
| 4 | |||
| 5 | test "crash" { | ||
| 6 | var buf: [4096]u8 = undefined; | ||
| 7 | f(&buf); | ||
| 8 | } | ||
test/stage1/behavior/bugs/529.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | |||
| 5 | extern fn issue529(?*A) void; | ||
| 6 | |||
| 7 | comptime { | ||
| 8 | _ = @import("529_other_file_2.zig"); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "issue 529 fixed" { | ||
| 12 | @import("529_other_file.zig").issue529(null); | ||
| 13 | issue529(null); | ||
| 14 | } | ||
test/stage1/behavior/bugs/529_other_file.zig deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | pub const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | |||
| 5 | pub extern fn issue529(?*A) void; | ||
test/stage1/behavior/bugs/529_other_file_2.zig deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | pub const A = extern struct { | ||
| 2 | field: c_int, | ||
| 3 | }; | ||
| 4 | export fn issue529(a: ?*A) void {} | ||
test/stage1/behavior/bugs/5398.zig deleted-31| ... | @@ -1,31 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | |||
| 4 | pub const Mesh = struct { | ||
| 5 | id: u32, | ||
| 6 | }; | ||
| 7 | pub const Material = struct { | ||
| 8 | transparent: bool = true, | ||
| 9 | emits_shadows: bool = true, | ||
| 10 | render_color: bool = true, | ||
| 11 | }; | ||
| 12 | pub const Renderable = struct { | ||
| 13 | material: Material, | ||
| 14 | // The compiler inserts some padding here to ensure Mesh is correctly aligned. | ||
| 15 | mesh: Mesh, | ||
| 16 | }; | ||
| 17 | |||
| 18 | var renderable: Renderable = undefined; | ||
| 19 | |||
| 20 | test "assignment of field with padding" { | ||
| 21 | renderable = Renderable{ | ||
| 22 | .mesh = Mesh{ .id = 0 }, | ||
| 23 | .material = Material{ | ||
| 24 | .transparent = false, | ||
| 25 | .emits_shadows = false, | ||
| 26 | }, | ||
| 27 | }; | ||
| 28 | try testing.expectEqual(false, renderable.material.transparent); | ||
| 29 | try testing.expectEqual(false, renderable.material.emits_shadows); | ||
| 30 | try testing.expectEqual(true, renderable.material.render_color); | ||
| 31 | } | ||
test/stage1/behavior/bugs/5413.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "Peer type resolution with string literals and unknown length u8 pointers" { | ||
| 4 | try expect(@TypeOf("", "a", @as([*:0]const u8, "")) == [*:0]const u8); | ||
| 5 | try expect(@TypeOf(@as([*:0]const u8, "baz"), "foo", "bar") == [*:0]const u8); | ||
| 6 | } | ||
test/stage1/behavior/bugs/5474.zig deleted-57| ... | @@ -1,57 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | // baseline (control) struct with array of scalar | ||
| 4 | const Box0 = struct { | ||
| 5 | items: [4]Item, | ||
| 6 | |||
| 7 | const Item = struct { | ||
| 8 | num: u32, | ||
| 9 | }; | ||
| 10 | }; | ||
| 11 | |||
| 12 | // struct with array of empty struct | ||
| 13 | const Box1 = struct { | ||
| 14 | items: [4]Item, | ||
| 15 | |||
| 16 | const Item = struct {}; | ||
| 17 | }; | ||
| 18 | |||
| 19 | // struct with array of zero-size struct | ||
| 20 | const Box2 = struct { | ||
| 21 | items: [4]Item, | ||
| 22 | |||
| 23 | const Item = struct { | ||
| 24 | nothing: void, | ||
| 25 | }; | ||
| 26 | }; | ||
| 27 | |||
| 28 | fn doTest() !void { | ||
| 29 | // var | ||
| 30 | { | ||
| 31 | var box0: Box0 = .{ .items = undefined }; | ||
| 32 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == false); | ||
| 33 | |||
| 34 | var box1: Box1 = .{ .items = undefined }; | ||
| 35 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == false); | ||
| 36 | |||
| 37 | var box2: Box2 = .{ .items = undefined }; | ||
| 38 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == false); | ||
| 39 | } | ||
| 40 | |||
| 41 | // const | ||
| 42 | { | ||
| 43 | const box0: Box0 = .{ .items = undefined }; | ||
| 44 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == true); | ||
| 45 | |||
| 46 | const box1: Box1 = .{ .items = undefined }; | ||
| 47 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == true); | ||
| 48 | |||
| 49 | const box2: Box2 = .{ .items = undefined }; | ||
| 50 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == true); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | test "pointer-to-array constness for zero-size elements" { | ||
| 55 | try doTest(); | ||
| 56 | comptime try doTest(); | ||
| 57 | } | ||
test/stage1/behavior/bugs/5487.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const io = @import("std").io; | ||
| 2 | |||
| 3 | pub fn write(_: void, bytes: []const u8) !usize { | ||
| 4 | return 0; | ||
| 5 | } | ||
| 6 | pub fn writer() io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write) { | ||
| 7 | return io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write){ .context = {} }; | ||
| 8 | } | ||
| 9 | |||
| 10 | test "crash" { | ||
| 11 | _ = io.multiWriter(.{writer()}); | ||
| 12 | } | ||
test/stage1/behavior/bugs/624.zig deleted-23| ... | @@ -1,23 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const TestContext = struct { | ||
| 5 | server_context: *ListenerContext, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const ListenerContext = struct { | ||
| 9 | context_alloc: *ContextAllocator, | ||
| 10 | }; | ||
| 11 | |||
| 12 | const ContextAllocator = MemoryPool(TestContext); | ||
| 13 | |||
| 14 | fn MemoryPool(comptime T: type) type { | ||
| 15 | return struct { | ||
| 16 | n: usize, | ||
| 17 | }; | ||
| 18 | } | ||
| 19 | |||
| 20 | test "foo" { | ||
| 21 | var allocator = ContextAllocator{ .n = 10 }; | ||
| 22 | try expect(allocator.n == 10); | ||
| 23 | } | ||
test/stage1/behavior/bugs/6456.zig deleted-43| ... | @@ -1,43 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const StructField = builtin.TypeInfo.StructField; | ||
| 5 | const Declaration = builtin.TypeInfo.Declaration; | ||
| 6 | |||
| 7 | const text = | ||
| 8 | \\f1 | ||
| 9 | \\f2 | ||
| 10 | \\f3 | ||
| 11 | ; | ||
| 12 | |||
| 13 | test "issue 6456" { | ||
| 14 | comptime { | ||
| 15 | var fields: []const StructField = &[0]StructField{}; | ||
| 16 | |||
| 17 | var it = std.mem.tokenize(text, "\n"); | ||
| 18 | while (it.next()) |name| { | ||
| 19 | fields = fields ++ &[_]StructField{StructField{ | ||
| 20 | .alignment = 0, | ||
| 21 | .name = name, | ||
| 22 | .field_type = usize, | ||
| 23 | .default_value = @as(?usize, null), | ||
| 24 | .is_comptime = false, | ||
| 25 | }}; | ||
| 26 | } | ||
| 27 | |||
| 28 | const T = @Type(.{ | ||
| 29 | .Struct = .{ | ||
| 30 | .layout = .Auto, | ||
| 31 | .is_tuple = false, | ||
| 32 | .fields = fields, | ||
| 33 | .decls = &[_]Declaration{}, | ||
| 34 | }, | ||
| 35 | }); | ||
| 36 | |||
| 37 | const gen_fields = @typeInfo(T).Struct.fields; | ||
| 38 | try testing.expectEqual(3, gen_fields.len); | ||
| 39 | try testing.expectEqualStrings("f1", gen_fields[0].name); | ||
| 40 | try testing.expectEqualStrings("f2", gen_fields[1].name); | ||
| 41 | try testing.expectEqualStrings("f3", gen_fields[2].name); | ||
| 42 | } | ||
| 43 | } | ||
test/stage1/behavior/bugs/655.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const other_file = @import("655_other_file.zig"); | ||
| 3 | |||
| 4 | test "function with *const parameter with type dereferenced by namespace" { | ||
| 5 | const x: other_file.Integer = 1234; | ||
| 6 | comptime try std.testing.expect(@TypeOf(&x) == *const other_file.Integer); | ||
| 7 | try foo(&x); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn foo(x: *const other_file.Integer) !void { | ||
| 11 | try std.testing.expect(x.* == 1234); | ||
| 12 | } | ||
test/stage1/behavior/bugs/655_other_file.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const Integer = u32; | ||
test/stage1/behavior/bugs/656.zig deleted-31| ... | @@ -1,31 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const PrefixOp = union(enum) { | ||
| 4 | Return, | ||
| 5 | AddrOf: Value, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const Value = struct { | ||
| 9 | align_expr: ?u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { | ||
| 13 | try foo(false, true); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(a: bool, b: bool) !void { | ||
| 17 | var prefix_op = PrefixOp{ | ||
| 18 | .AddrOf = Value{ .align_expr = 1234 }, | ||
| 19 | }; | ||
| 20 | if (a) {} else { | ||
| 21 | switch (prefix_op) { | ||
| 22 | PrefixOp.AddrOf => |addr_of_info| { | ||
| 23 | if (b) {} | ||
| 24 | if (addr_of_info.align_expr) |align_expr| { | ||
| 25 | try expect(align_expr == 1234); | ||
| 26 | } | ||
| 27 | }, | ||
| 28 | PrefixOp.Return => {}, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
test/stage1/behavior/bugs/6781.zig deleted-74| ... | @@ -1,74 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 4 | const segfault = true; | ||
| 5 | |||
| 6 | pub const JournalHeader = packed struct { | ||
| 7 | hash_chain_root: u128 = undefined, | ||
| 8 | prev_hash_chain_root: u128, | ||
| 9 | checksum: u128 = undefined, | ||
| 10 | magic: u64, | ||
| 11 | command: u32, | ||
| 12 | size: u32, | ||
| 13 | |||
| 14 | pub fn calculate_checksum(self: *const JournalHeader, entry: []const u8) u128 { | ||
| 15 | assert(entry.len >= @sizeOf(JournalHeader)); | ||
| 16 | assert(entry.len == self.size); | ||
| 17 | |||
| 18 | const checksum_offset = @byteOffsetOf(JournalHeader, "checksum"); | ||
| 19 | const checksum_size = @sizeOf(@TypeOf(self.checksum)); | ||
| 20 | assert(checksum_offset == 0 + 16 + 16); | ||
| 21 | assert(checksum_size == 16); | ||
| 22 | |||
| 23 | var target: [32]u8 = undefined; | ||
| 24 | std.crypto.hash.Blake3.hash(entry[checksum_offset + checksum_size ..], target[0..], .{}); | ||
| 25 | return @bitCast(u128, target[0..checksum_size].*); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn calculate_hash_chain_root(self: *const JournalHeader) u128 { | ||
| 29 | const hash_chain_root_size = @sizeOf(@TypeOf(self.hash_chain_root)); | ||
| 30 | assert(hash_chain_root_size == 16); | ||
| 31 | |||
| 32 | const prev_hash_chain_root_offset = @byteOffsetOf(JournalHeader, "prev_hash_chain_root"); | ||
| 33 | const prev_hash_chain_root_size = @sizeOf(@TypeOf(self.prev_hash_chain_root)); | ||
| 34 | assert(prev_hash_chain_root_offset == 0 + 16); | ||
| 35 | assert(prev_hash_chain_root_size == 16); | ||
| 36 | |||
| 37 | const checksum_offset = @byteOffsetOf(JournalHeader, "checksum"); | ||
| 38 | const checksum_size = @sizeOf(@TypeOf(self.checksum)); | ||
| 39 | assert(checksum_offset == 0 + 16 + 16); | ||
| 40 | assert(checksum_size == 16); | ||
| 41 | |||
| 42 | assert(prev_hash_chain_root_offset + prev_hash_chain_root_size == checksum_offset); | ||
| 43 | |||
| 44 | const header = @bitCast([@sizeOf(JournalHeader)]u8, self.*); | ||
| 45 | const source = header[prev_hash_chain_root_offset .. checksum_offset + checksum_size]; | ||
| 46 | assert(source.len == prev_hash_chain_root_size + checksum_size); | ||
| 47 | var target: [32]u8 = undefined; | ||
| 48 | std.crypto.hash.Blake3.hash(source, target[0..], .{}); | ||
| 49 | if (segfault) { | ||
| 50 | return @bitCast(u128, target[0..hash_chain_root_size].*); | ||
| 51 | } else { | ||
| 52 | var array = target[0..hash_chain_root_size].*; | ||
| 53 | return @bitCast(u128, array); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn set_checksum_and_hash_chain_root(self: *JournalHeader, entry: []const u8) void { | ||
| 58 | self.checksum = self.calculate_checksum(entry); | ||
| 59 | self.hash_chain_root = self.calculate_hash_chain_root(); | ||
| 60 | } | ||
| 61 | }; | ||
| 62 | |||
| 63 | test "fixed" { | ||
| 64 | var buffer = [_]u8{0} ** 65536; | ||
| 65 | var entry = std.mem.bytesAsValue(JournalHeader, buffer[0..@sizeOf(JournalHeader)]); | ||
| 66 | entry.* = .{ | ||
| 67 | .prev_hash_chain_root = 0, | ||
| 68 | .magic = 0, | ||
| 69 | .command = 0, | ||
| 70 | .size = 64 + 128, | ||
| 71 | }; | ||
| 72 | entry.set_checksum_and_hash_chain_root(buffer[0..entry.size]); | ||
| 73 | try std.io.null_writer.print("{}\n", .{entry}); | ||
| 74 | } | ||
test/stage1/behavior/bugs/679.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | pub fn List(comptime T: type) type { | ||
| 5 | return u32; | ||
| 6 | } | ||
| 7 | |||
| 8 | const ElementList = List(Element); | ||
| 9 | const Element = struct { | ||
| 10 | link: ElementList, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "false dependency loop in struct definition" { | ||
| 14 | const listType = ElementList; | ||
| 15 | var x: listType = 42; | ||
| 16 | try expect(x == 42); | ||
| 17 | } | ||
test/stage1/behavior/bugs/6850.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "lazy sizeof comparison with zero" { | ||
| 4 | const Empty = struct {}; | ||
| 5 | const T = *Empty; | ||
| 6 | |||
| 7 | try std.testing.expect(hasNoBits(T)); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn hasNoBits(comptime T: type) bool { | ||
| 11 | return @sizeOf(T) == 0; | ||
| 12 | } | ||
test/stage1/behavior/bugs/7003.zig deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | test "@Type should resolve its children types" { | ||
| 2 | const sparse = enum(u2) { a, b, c }; | ||
| 3 | const dense = enum(u2) { a, b, c, d }; | ||
| 4 | |||
| 5 | comptime var sparse_info = @typeInfo(anyerror!sparse); | ||
| 6 | sparse_info.ErrorUnion.payload = dense; | ||
| 7 | const B = @Type(sparse_info); | ||
| 8 | } | ||
test/stage1/behavior/bugs/7027.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const Foobar = struct { | ||
| 2 | myTypes: [128]type, | ||
| 3 | str: [1024]u8, | ||
| 4 | |||
| 5 | fn foo() @This() { | ||
| 6 | comptime var foobar: Foobar = undefined; | ||
| 7 | foobar.str = [_]u8{'a'} ** 1024; | ||
| 8 | return foobar; | ||
| 9 | } | ||
| 10 | }; | ||
| 11 | |||
| 12 | fn foo(arg: anytype) void {} | ||
| 13 | |||
| 14 | test "" { | ||
| 15 | comptime var foobar = Foobar.foo(); | ||
| 16 | foo(foobar.str[0..10]); | ||
| 17 | } | ||
test/stage1/behavior/bugs/704.zig deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | const xxx = struct { | ||
| 2 | pub fn bar(self: *xxx) void {} | ||
| 3 | }; | ||
| 4 | test "bug 704" { | ||
| 5 | var x: xxx = undefined; | ||
| 6 | x.bar(); | ||
| 7 | } | ||
test/stage1/behavior/bugs/7047.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const U = union(enum) { | ||
| 4 | T: type, | ||
| 5 | N: void, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn S(comptime query: U) type { | ||
| 9 | return struct { | ||
| 10 | fn tag() type { | ||
| 11 | return query.T; | ||
| 12 | } | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "compiler doesn't consider equal unions with different 'type' payload" { | ||
| 17 | const s1 = S(U{ .T = u32 }).tag(); | ||
| 18 | try std.testing.expectEqual(u32, s1); | ||
| 19 | |||
| 20 | const s2 = S(U{ .T = u64 }).tag(); | ||
| 21 | try std.testing.expectEqual(u64, s2); | ||
| 22 | } | ||
test/stage1/behavior/bugs/718.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const Keys = struct { | ||
| 5 | up: bool, | ||
| 6 | down: bool, | ||
| 7 | left: bool, | ||
| 8 | right: bool, | ||
| 9 | }; | ||
| 10 | var keys: Keys = undefined; | ||
| 11 | test "zero keys with @memset" { | ||
| 12 | @memset(@ptrCast([*]u8, &keys), 0, @sizeOf(@TypeOf(keys))); | ||
| 13 | try expect(!keys.up); | ||
| 14 | try expect(!keys.down); | ||
| 15 | try expect(!keys.left); | ||
| 16 | try expect(!keys.right); | ||
| 17 | } | ||
test/stage1/behavior/bugs/7250.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const nrfx_uart_t = extern struct { | ||
| 2 | p_reg: [*c]u32, | ||
| 3 | drv_inst_idx: u8, | ||
| 4 | }; | ||
| 5 | |||
| 6 | pub fn nrfx_uart_rx(p_instance: [*c]const nrfx_uart_t) void {} | ||
| 7 | |||
| 8 | threadlocal var g_uart0 = nrfx_uart_t{ | ||
| 9 | .p_reg = 0, | ||
| 10 | .drv_inst_idx = 0, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "reference a global threadlocal variable" { | ||
| 14 | _ = nrfx_uart_rx(&g_uart0); | ||
| 15 | } | ||
test/stage1/behavior/bugs/726.zig deleted-15| ... | @@ -1,15 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@ptrCast from const to nullable" { | ||
| 4 | const c: u8 = 4; | ||
| 5 | var x: ?*const u8 = @ptrCast(?*const u8, &c); | ||
| 6 | try expect(x.?.* == 4); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "@ptrCast from var in empty struct to nullable" { | ||
| 10 | const container = struct { | ||
| 11 | var c: u8 = 4; | ||
| 12 | }; | ||
| 13 | var x: ?*const u8 = @ptrCast(?*const u8, &container.c); | ||
| 14 | try expect(x.?.* == 4); | ||
| 15 | } | ||
test/stage1/behavior/bugs/828.zig deleted-33| ... | @@ -1,33 +0,0 @@ | ||
| 1 | const CountBy = struct { | ||
| 2 | a: usize, | ||
| 3 | |||
| 4 | const One = CountBy{ .a = 1 }; | ||
| 5 | |||
| 6 | pub fn counter(self: *const CountBy) Counter { | ||
| 7 | return Counter{ .i = 0 }; | ||
| 8 | } | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Counter = struct { | ||
| 12 | i: usize, | ||
| 13 | |||
| 14 | pub fn count(self: *Counter) bool { | ||
| 15 | self.i += 1; | ||
| 16 | return self.i <= 10; | ||
| 17 | } | ||
| 18 | }; | ||
| 19 | |||
| 20 | fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { | ||
| 21 | comptime { | ||
| 22 | var cnt = cb.counter(); | ||
| 23 | if (cnt.i != 0) @compileError("Counter instance reused!"); | ||
| 24 | while (cnt.count()) {} | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "comptime struct return should not return the same instance" { | ||
| 29 | //the first parameter must be passed by reference to trigger the bug | ||
| 30 | //a second parameter is required to trigger the bug | ||
| 31 | const ValA = constCount(&CountBy.One, 12); | ||
| 32 | const ValB = constCount(&CountBy.One, 15); | ||
| 33 | } | ||
test/stage1/behavior/bugs/920.zig deleted-65| ... | @@ -1,65 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const math = std.math; | ||
| 3 | const Random = std.rand.Random; | ||
| 4 | |||
| 5 | const ZigTable = struct { | ||
| 6 | r: f64, | ||
| 7 | x: [257]f64, | ||
| 8 | f: [257]f64, | ||
| 9 | |||
| 10 | pdf: fn (f64) f64, | ||
| 11 | is_symmetric: bool, | ||
| 12 | zero_case: fn (*Random, f64) f64, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { | ||
| 16 | var tables: ZigTable = undefined; | ||
| 17 | |||
| 18 | tables.is_symmetric = is_symmetric; | ||
| 19 | tables.r = r; | ||
| 20 | tables.pdf = f; | ||
| 21 | tables.zero_case = zero_case; | ||
| 22 | |||
| 23 | tables.x[0] = v / f(r); | ||
| 24 | tables.x[1] = r; | ||
| 25 | |||
| 26 | for (tables.x[2..256]) |*entry, i| { | ||
| 27 | const last = tables.x[2 + i - 1]; | ||
| 28 | entry.* = f_inv(v / last + f(last)); | ||
| 29 | } | ||
| 30 | tables.x[256] = 0; | ||
| 31 | |||
| 32 | for (tables.f[0..]) |*entry, i| { | ||
| 33 | entry.* = f(tables.x[i]); | ||
| 34 | } | ||
| 35 | |||
| 36 | return tables; | ||
| 37 | } | ||
| 38 | |||
| 39 | const norm_r = 3.6541528853610088; | ||
| 40 | const norm_v = 0.00492867323399; | ||
| 41 | |||
| 42 | fn norm_f(x: f64) f64 { | ||
| 43 | return math.exp(-x * x / 2.0); | ||
| 44 | } | ||
| 45 | fn norm_f_inv(y: f64) f64 { | ||
| 46 | return math.sqrt(-2.0 * math.ln(y)); | ||
| 47 | } | ||
| 48 | fn norm_zero_case(random: *Random, u: f64) f64 { | ||
| 49 | return 0.0; | ||
| 50 | } | ||
| 51 | |||
| 52 | const NormalDist = blk: { | ||
| 53 | @setEvalBranchQuota(30000); | ||
| 54 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 55 | }; | ||
| 56 | |||
| 57 | test "bug 920 fixed" { | ||
| 58 | const NormalDist1 = blk: { | ||
| 59 | break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); | ||
| 60 | }; | ||
| 61 | |||
| 62 | for (NormalDist1.f) |_, i| { | ||
| 63 | try std.testing.expectEqual(NormalDist1.f[i], NormalDist.f[i]); | ||
| 64 | } | ||
| 65 | } | ||
test/stage1/behavior/byteswap.zig deleted-68| ... | @@ -1,68 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "@byteSwap integers" { | ||
| 5 | const ByteSwapIntTest = struct { | ||
| 6 | fn run() !void { | ||
| 7 | try t(u0, 0, 0); | ||
| 8 | try t(u8, 0x12, 0x12); | ||
| 9 | try t(u16, 0x1234, 0x3412); | ||
| 10 | try t(u24, 0x123456, 0x563412); | ||
| 11 | try t(u32, 0x12345678, 0x78563412); | ||
| 12 | try t(u40, 0x123456789a, 0x9a78563412); | ||
| 13 | try t(i48, 0x123456789abc, @bitCast(i48, @as(u48, 0xbc9a78563412))); | ||
| 14 | try t(u56, 0x123456789abcde, 0xdebc9a78563412); | ||
| 15 | try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); | ||
| 16 | try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | ||
| 17 | |||
| 18 | try t(u0, @as(u0, 0), 0); | ||
| 19 | try t(i8, @as(i8, -50), -50); | ||
| 20 | try t(i16, @bitCast(i16, @as(u16, 0x1234)), @bitCast(i16, @as(u16, 0x3412))); | ||
| 21 | try t(i24, @bitCast(i24, @as(u24, 0x123456)), @bitCast(i24, @as(u24, 0x563412))); | ||
| 22 | try t(i32, @bitCast(i32, @as(u32, 0x12345678)), @bitCast(i32, @as(u32, 0x78563412))); | ||
| 23 | try t(u40, @bitCast(i40, @as(u40, 0x123456789a)), @as(u40, 0x9a78563412)); | ||
| 24 | try t(i48, @bitCast(i48, @as(u48, 0x123456789abc)), @bitCast(i48, @as(u48, 0xbc9a78563412))); | ||
| 25 | try t(i56, @bitCast(i56, @as(u56, 0x123456789abcde)), @bitCast(i56, @as(u56, 0xdebc9a78563412))); | ||
| 26 | try t(i64, @bitCast(i64, @as(u64, 0x123456789abcdef1)), @bitCast(i64, @as(u64, 0xf1debc9a78563412))); | ||
| 27 | try t( | ||
| 28 | i128, | ||
| 29 | @bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181)), | ||
| 30 | @bitCast(i128, @as(u128, 0x8171615141312111f1debc9a78563412)), | ||
| 31 | ); | ||
| 32 | } | ||
| 33 | fn t(comptime I: type, input: I, expected_output: I) !void { | ||
| 34 | try std.testing.expectEqual(expected_output, @byteSwap(I, input)); | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | comptime try ByteSwapIntTest.run(); | ||
| 38 | try ByteSwapIntTest.run(); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "@byteSwap vectors" { | ||
| 42 | // https://github.com/ziglang/zig/issues/3563 | ||
| 43 | if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest; | ||
| 44 | |||
| 45 | // https://github.com/ziglang/zig/issues/3317 | ||
| 46 | if (std.Target.current.cpu.arch == .mipsel or std.Target.current.cpu.arch == .mips) return error.SkipZigTest; | ||
| 47 | |||
| 48 | const ByteSwapVectorTest = struct { | ||
| 49 | fn run() !void { | ||
| 50 | try t(u8, 2, [_]u8{ 0x12, 0x13 }, [_]u8{ 0x12, 0x13 }); | ||
| 51 | try t(u16, 2, [_]u16{ 0x1234, 0x2345 }, [_]u16{ 0x3412, 0x4523 }); | ||
| 52 | try t(u24, 2, [_]u24{ 0x123456, 0x234567 }, [_]u24{ 0x563412, 0x674523 }); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn t( | ||
| 56 | comptime I: type, | ||
| 57 | comptime n: comptime_int, | ||
| 58 | input: std.meta.Vector(n, I), | ||
| 59 | expected_vector: std.meta.Vector(n, I), | ||
| 60 | ) !void { | ||
| 61 | const actual_output: [n]I = @byteSwap(I, input); | ||
| 62 | const expected_output: [n]I = expected_vector; | ||
| 63 | try std.testing.expectEqual(expected_output, actual_output); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | comptime try ByteSwapVectorTest.run(); | ||
| 67 | try ByteSwapVectorTest.run(); | ||
| 68 | } | ||
test/stage1/behavior/byval_arg_var.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | var result: []const u8 = "wrong"; | ||
| 4 | |||
| 5 | test "pass string literal byvalue to a generic var param" { | ||
| 6 | start(); | ||
| 7 | blowUpStack(10); | ||
| 8 | |||
| 9 | try std.testing.expect(std.mem.eql(u8, result, "string literal")); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn start() void { | ||
| 13 | foo("string literal"); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn foo(x: anytype) void { | ||
| 17 | bar(x); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn bar(x: anytype) void { | ||
| 21 | result = x; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn blowUpStack(x: u32) void { | ||
| 25 | if (x == 0) return; | ||
| 26 | blowUpStack(x - 1); | ||
| 27 | } | ||
test/stage1/behavior/call.zig deleted-74| ... | @@ -1,74 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | |||
| 5 | test "basic invocations" { | ||
| 6 | const foo = struct { | ||
| 7 | fn foo() i32 { | ||
| 8 | return 1234; | ||
| 9 | } | ||
| 10 | }.foo; | ||
| 11 | try expect(@call(.{}, foo, .{}) == 1234); | ||
| 12 | comptime { | ||
| 13 | // modifiers that allow comptime calls | ||
| 14 | try expect(@call(.{}, foo, .{}) == 1234); | ||
| 15 | try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234); | ||
| 16 | try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234); | ||
| 17 | try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234); | ||
| 18 | } | ||
| 19 | { | ||
| 20 | // comptime call without comptime keyword | ||
| 21 | const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234; | ||
| 22 | comptime try expect(result); | ||
| 23 | } | ||
| 24 | { | ||
| 25 | // call of non comptime-known function | ||
| 26 | var alias_foo = foo; | ||
| 27 | try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234); | ||
| 28 | try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234); | ||
| 29 | try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | test "tuple parameters" { | ||
| 34 | const add = struct { | ||
| 35 | fn add(a: i32, b: i32) i32 { | ||
| 36 | return a + b; | ||
| 37 | } | ||
| 38 | }.add; | ||
| 39 | var a: i32 = 12; | ||
| 40 | var b: i32 = 34; | ||
| 41 | try expect(@call(.{}, add, .{ a, 34 }) == 46); | ||
| 42 | try expect(@call(.{}, add, .{ 12, b }) == 46); | ||
| 43 | try expect(@call(.{}, add, .{ a, b }) == 46); | ||
| 44 | try expect(@call(.{}, add, .{ 12, 34 }) == 46); | ||
| 45 | comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); | ||
| 46 | { | ||
| 47 | const separate_args0 = .{ a, b }; | ||
| 48 | const separate_args1 = .{ a, 34 }; | ||
| 49 | const separate_args2 = .{ 12, 34 }; | ||
| 50 | const separate_args3 = .{ 12, b }; | ||
| 51 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46); | ||
| 52 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46); | ||
| 53 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46); | ||
| 54 | try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | test "comptime call with bound function as parameter" { | ||
| 59 | const S = struct { | ||
| 60 | fn ReturnType(func: anytype) type { | ||
| 61 | return switch (@typeInfo(@TypeOf(func))) { | ||
| 62 | .BoundFn => |info| info, | ||
| 63 | else => unreachable, | ||
| 64 | }.return_type orelse void; | ||
| 65 | } | ||
| 66 | |||
| 67 | fn call_me_maybe() ?i32 { | ||
| 68 | return 123; | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | |||
| 72 | var inst: S = undefined; | ||
| 73 | try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); | ||
| 74 | } | ||
test/stage1/behavior/cast.zig deleted-926| ... | @@ -1,926 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | const maxInt = std.math.maxInt; | ||
| 5 | const Vector = std.meta.Vector; | ||
| 6 | |||
| 7 | test "int to ptr cast" { | ||
| 8 | const x = @as(usize, 13); | ||
| 9 | const y = @intToPtr(*u8, x); | ||
| 10 | const z = @ptrToInt(y); | ||
| 11 | try expect(z == 13); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "integer literal to pointer cast" { | ||
| 15 | const vga_mem = @intToPtr(*u16, 0xB8000); | ||
| 16 | try expect(@ptrToInt(vga_mem) == 0xB8000); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "pointer reinterpret const float to int" { | ||
| 20 | // The hex representation is 0x3fe3333333333303. | ||
| 21 | const float: f64 = 5.99999999999994648725e-01; | ||
| 22 | const float_ptr = &float; | ||
| 23 | const int_ptr = @ptrCast(*const i32, float_ptr); | ||
| 24 | const int_val = int_ptr.*; | ||
| 25 | if (std.builtin.endian == .Little) | ||
| 26 | try expect(int_val == 0x33333303) | ||
| 27 | else | ||
| 28 | try expect(int_val == 0x3fe33333); | ||
| 29 | } | ||
| 30 | |||
| 31 | test "implicitly cast indirect pointer to maybe-indirect pointer" { | ||
| 32 | const S = struct { | ||
| 33 | const Self = @This(); | ||
| 34 | x: u8, | ||
| 35 | fn constConst(p: *const *const Self) u8 { | ||
| 36 | return p.*.x; | ||
| 37 | } | ||
| 38 | fn maybeConstConst(p: ?*const *const Self) u8 { | ||
| 39 | return p.?.*.x; | ||
| 40 | } | ||
| 41 | fn constConstConst(p: *const *const *const Self) u8 { | ||
| 42 | return p.*.*.x; | ||
| 43 | } | ||
| 44 | fn maybeConstConstConst(p: ?*const *const *const Self) u8 { | ||
| 45 | return p.?.*.*.x; | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | const s = S{ .x = 42 }; | ||
| 49 | const p = &s; | ||
| 50 | const q = &p; | ||
| 51 | const r = &q; | ||
| 52 | try expect(42 == S.constConst(q)); | ||
| 53 | try expect(42 == S.maybeConstConst(q)); | ||
| 54 | try expect(42 == S.constConstConst(r)); | ||
| 55 | try expect(42 == S.maybeConstConstConst(r)); | ||
| 56 | } | ||
| 57 | |||
| 58 | test "explicit cast from integer to error type" { | ||
| 59 | try testCastIntToErr(error.ItBroke); | ||
| 60 | comptime try testCastIntToErr(error.ItBroke); | ||
| 61 | } | ||
| 62 | fn testCastIntToErr(err: anyerror) !void { | ||
| 63 | const x = @errorToInt(err); | ||
| 64 | const y = @intToError(x); | ||
| 65 | try expect(error.ItBroke == y); | ||
| 66 | } | ||
| 67 | |||
| 68 | test "peer resolve arrays of different size to const slice" { | ||
| 69 | try expect(mem.eql(u8, boolToStr(true), "true")); | ||
| 70 | try expect(mem.eql(u8, boolToStr(false), "false")); | ||
| 71 | comptime try expect(mem.eql(u8, boolToStr(true), "true")); | ||
| 72 | comptime try expect(mem.eql(u8, boolToStr(false), "false")); | ||
| 73 | } | ||
| 74 | fn boolToStr(b: bool) []const u8 { | ||
| 75 | return if (b) "true" else "false"; | ||
| 76 | } | ||
| 77 | |||
| 78 | test "peer resolve array and const slice" { | ||
| 79 | try testPeerResolveArrayConstSlice(true); | ||
| 80 | comptime try testPeerResolveArrayConstSlice(true); | ||
| 81 | } | ||
| 82 | fn testPeerResolveArrayConstSlice(b: bool) !void { | ||
| 83 | const value1 = if (b) "aoeu" else @as([]const u8, "zz"); | ||
| 84 | const value2 = if (b) @as([]const u8, "zz") else "aoeu"; | ||
| 85 | try expect(mem.eql(u8, value1, "aoeu")); | ||
| 86 | try expect(mem.eql(u8, value2, "zz")); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "implicitly cast from T to anyerror!?T" { | ||
| 90 | try castToOptionalTypeError(1); | ||
| 91 | comptime try castToOptionalTypeError(1); | ||
| 92 | } | ||
| 93 | |||
| 94 | const A = struct { | ||
| 95 | a: i32, | ||
| 96 | }; | ||
| 97 | fn castToOptionalTypeError(z: i32) !void { | ||
| 98 | const x = @as(i32, 1); | ||
| 99 | const y: anyerror!?i32 = x; | ||
| 100 | try expect((try y).? == 1); | ||
| 101 | |||
| 102 | const f = z; | ||
| 103 | const g: anyerror!?i32 = f; | ||
| 104 | |||
| 105 | const a = A{ .a = z }; | ||
| 106 | const b: anyerror!?A = a; | ||
| 107 | try expect((b catch unreachable).?.a == 1); | ||
| 108 | } | ||
| 109 | |||
| 110 | test "implicitly cast from int to anyerror!?T" { | ||
| 111 | implicitIntLitToOptional(); | ||
| 112 | comptime implicitIntLitToOptional(); | ||
| 113 | } | ||
| 114 | fn implicitIntLitToOptional() void { | ||
| 115 | const f: ?i32 = 1; | ||
| 116 | const g: anyerror!?i32 = 1; | ||
| 117 | } | ||
| 118 | |||
| 119 | test "return null from fn() anyerror!?&T" { | ||
| 120 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 121 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 122 | try expect((try a) == null and (try b) == null); | ||
| 123 | } | ||
| 124 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 125 | const a: ?*A = null; | ||
| 126 | return a; | ||
| 127 | } | ||
| 128 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 129 | return null; | ||
| 130 | } | ||
| 131 | |||
| 132 | test "peer type resolution: ?T and T" { | ||
| 133 | try expect(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 134 | try expect(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 135 | comptime { | ||
| 136 | try expect(peerTypeTAndOptionalT(true, false).? == 0); | ||
| 137 | try expect(peerTypeTAndOptionalT(false, false).? == 3); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { | ||
| 141 | if (c) { | ||
| 142 | return if (b) null else @as(usize, 0); | ||
| 143 | } | ||
| 144 | |||
| 145 | return @as(usize, 3); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 149 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 150 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 151 | comptime { | ||
| 152 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 153 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 157 | if (a) { | ||
| 158 | return &[_]u8{}; | ||
| 159 | } | ||
| 160 | |||
| 161 | return slice[0..1]; | ||
| 162 | } | ||
| 163 | |||
| 164 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 165 | try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 166 | comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 167 | } | ||
| 168 | |||
| 169 | fn castToOptionalSlice() ?[]const u8 { | ||
| 170 | return "hi"; | ||
| 171 | } | ||
| 172 | |||
| 173 | test "implicitly cast from [0]T to anyerror![]T" { | ||
| 174 | try testCastZeroArrayToErrSliceMut(); | ||
| 175 | comptime try testCastZeroArrayToErrSliceMut(); | ||
| 176 | } | ||
| 177 | |||
| 178 | fn testCastZeroArrayToErrSliceMut() !void { | ||
| 179 | try expect((gimmeErrOrSlice() catch unreachable).len == 0); | ||
| 180 | } | ||
| 181 | |||
| 182 | fn gimmeErrOrSlice() anyerror![]u8 { | ||
| 183 | return &[_]u8{}; | ||
| 184 | } | ||
| 185 | |||
| 186 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { | ||
| 187 | const S = struct { | ||
| 188 | fn doTheTest() anyerror!void { | ||
| 189 | { | ||
| 190 | var data = "hi".*; | ||
| 191 | const slice = data[0..]; | ||
| 192 | try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 193 | try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 194 | } | ||
| 195 | { | ||
| 196 | var data: [2]u8 = "hi".*; | ||
| 197 | const slice = data[0..]; | ||
| 198 | try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); | ||
| 199 | try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | }; | ||
| 203 | try S.doTheTest(); | ||
| 204 | comptime try S.doTheTest(); | ||
| 205 | } | ||
| 206 | fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { | ||
| 207 | if (a) { | ||
| 208 | return &[_]u8{}; | ||
| 209 | } | ||
| 210 | |||
| 211 | return slice[0..1]; | ||
| 212 | } | ||
| 213 | |||
| 214 | test "resolve undefined with integer" { | ||
| 215 | try testResolveUndefWithInt(true, 1234); | ||
| 216 | comptime try testResolveUndefWithInt(true, 1234); | ||
| 217 | } | ||
| 218 | fn testResolveUndefWithInt(b: bool, x: i32) !void { | ||
| 219 | const value = if (b) x else undefined; | ||
| 220 | if (b) { | ||
| 221 | try expect(value == x); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | test "implicit cast from &const [N]T to []const T" { | ||
| 226 | try testCastConstArrayRefToConstSlice(); | ||
| 227 | comptime try testCastConstArrayRefToConstSlice(); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn testCastConstArrayRefToConstSlice() !void { | ||
| 231 | { | ||
| 232 | const blah = "aoeu".*; | ||
| 233 | const const_array_ref = &blah; | ||
| 234 | try expect(@TypeOf(const_array_ref) == *const [4:0]u8); | ||
| 235 | const slice: []const u8 = const_array_ref; | ||
| 236 | try expect(mem.eql(u8, slice, "aoeu")); | ||
| 237 | } | ||
| 238 | { | ||
| 239 | const blah: [4]u8 = "aoeu".*; | ||
| 240 | const const_array_ref = &blah; | ||
| 241 | try expect(@TypeOf(const_array_ref) == *const [4]u8); | ||
| 242 | const slice: []const u8 = const_array_ref; | ||
| 243 | try expect(mem.eql(u8, slice, "aoeu")); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | test "peer type resolution: error and [N]T" { | ||
| 248 | try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 249 | comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); | ||
| 250 | try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 251 | comptime try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); | ||
| 252 | } | ||
| 253 | |||
| 254 | fn testPeerErrorAndArray(x: u8) anyerror![]const u8 { | ||
| 255 | return switch (x) { | ||
| 256 | 0x00 => "OK", | ||
| 257 | else => error.BadValue, | ||
| 258 | }; | ||
| 259 | } | ||
| 260 | fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { | ||
| 261 | return switch (x) { | ||
| 262 | 0x00 => "OK", | ||
| 263 | 0x01 => "OKK", | ||
| 264 | else => error.BadValue, | ||
| 265 | }; | ||
| 266 | } | ||
| 267 | |||
| 268 | test "@floatToInt" { | ||
| 269 | try testFloatToInts(); | ||
| 270 | comptime try testFloatToInts(); | ||
| 271 | } | ||
| 272 | |||
| 273 | fn testFloatToInts() !void { | ||
| 274 | const x = @as(i32, 1e4); | ||
| 275 | try expect(x == 10000); | ||
| 276 | const y = @floatToInt(i32, @as(f32, 1e4)); | ||
| 277 | try expect(y == 10000); | ||
| 278 | try expectFloatToInt(f16, 255.1, u8, 255); | ||
| 279 | try expectFloatToInt(f16, 127.2, i8, 127); | ||
| 280 | try expectFloatToInt(f16, -128.2, i8, -128); | ||
| 281 | try expectFloatToInt(f32, 255.1, u8, 255); | ||
| 282 | try expectFloatToInt(f32, 127.2, i8, 127); | ||
| 283 | try expectFloatToInt(f32, -128.2, i8, -128); | ||
| 284 | try expectFloatToInt(comptime_int, 1234, i16, 1234); | ||
| 285 | } | ||
| 286 | |||
| 287 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { | ||
| 288 | try expect(@floatToInt(I, f) == i); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "cast u128 to f128 and back" { | ||
| 292 | comptime try testCast128(); | ||
| 293 | try testCast128(); | ||
| 294 | } | ||
| 295 | |||
| 296 | fn testCast128() !void { | ||
| 297 | try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 298 | } | ||
| 299 | |||
| 300 | fn cast128Int(x: f128) u128 { | ||
| 301 | return @bitCast(u128, x); | ||
| 302 | } | ||
| 303 | |||
| 304 | fn cast128Float(x: u128) f128 { | ||
| 305 | return @bitCast(f128, x); | ||
| 306 | } | ||
| 307 | |||
| 308 | test "single-item pointer of array to slice and to unknown length pointer" { | ||
| 309 | try testCastPtrOfArrayToSliceAndPtr(); | ||
| 310 | comptime try testCastPtrOfArrayToSliceAndPtr(); | ||
| 311 | } | ||
| 312 | |||
| 313 | fn testCastPtrOfArrayToSliceAndPtr() !void { | ||
| 314 | { | ||
| 315 | var array = "aoeu".*; | ||
| 316 | const x: [*]u8 = &array; | ||
| 317 | x[0] += 1; | ||
| 318 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 319 | const y: []u8 = &array; | ||
| 320 | y[0] += 1; | ||
| 321 | try expect(mem.eql(u8, array[0..], "coeu")); | ||
| 322 | } | ||
| 323 | { | ||
| 324 | var array: [4]u8 = "aoeu".*; | ||
| 325 | const x: [*]u8 = &array; | ||
| 326 | x[0] += 1; | ||
| 327 | try expect(mem.eql(u8, array[0..], "boeu")); | ||
| 328 | const y: []u8 = &array; | ||
| 329 | y[0] += 1; | ||
| 330 | try expect(mem.eql(u8, array[0..], "coeu")); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | ||
| 335 | const window_name = [1][*]const u8{"window name"}; | ||
| 336 | const x: [*]const ?[*]const u8 = &window_name; | ||
| 337 | try expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name")); | ||
| 338 | } | ||
| 339 | |||
| 340 | test "@intCast comptime_int" { | ||
| 341 | const result = @intCast(i32, 1234); | ||
| 342 | try expect(@TypeOf(result) == i32); | ||
| 343 | try expect(result == 1234); | ||
| 344 | } | ||
| 345 | |||
| 346 | test "@floatCast comptime_int and comptime_float" { | ||
| 347 | { | ||
| 348 | const result = @floatCast(f16, 1234); | ||
| 349 | try expect(@TypeOf(result) == f16); | ||
| 350 | try expect(result == 1234.0); | ||
| 351 | } | ||
| 352 | { | ||
| 353 | const result = @floatCast(f16, 1234.0); | ||
| 354 | try expect(@TypeOf(result) == f16); | ||
| 355 | try expect(result == 1234.0); | ||
| 356 | } | ||
| 357 | { | ||
| 358 | const result = @floatCast(f32, 1234); | ||
| 359 | try expect(@TypeOf(result) == f32); | ||
| 360 | try expect(result == 1234.0); | ||
| 361 | } | ||
| 362 | { | ||
| 363 | const result = @floatCast(f32, 1234.0); | ||
| 364 | try expect(@TypeOf(result) == f32); | ||
| 365 | try expect(result == 1234.0); | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | test "vector casts" { | ||
| 370 | const S = struct { | ||
| 371 | fn doTheTest() !void { | ||
| 372 | // Upcast (implicit, equivalent to @intCast) | ||
| 373 | var up0: Vector(2, u8) = [_]u8{ 0x55, 0xaa }; | ||
| 374 | var up1 = @as(Vector(2, u16), up0); | ||
| 375 | var up2 = @as(Vector(2, u32), up0); | ||
| 376 | var up3 = @as(Vector(2, u64), up0); | ||
| 377 | // Downcast (safety-checked) | ||
| 378 | var down0 = up3; | ||
| 379 | var down1 = @intCast(Vector(2, u32), down0); | ||
| 380 | var down2 = @intCast(Vector(2, u16), down0); | ||
| 381 | var down3 = @intCast(Vector(2, u8), down0); | ||
| 382 | |||
| 383 | try expect(mem.eql(u16, &@as([2]u16, up1), &[2]u16{ 0x55, 0xaa })); | ||
| 384 | try expect(mem.eql(u32, &@as([2]u32, up2), &[2]u32{ 0x55, 0xaa })); | ||
| 385 | try expect(mem.eql(u64, &@as([2]u64, up3), &[2]u64{ 0x55, 0xaa })); | ||
| 386 | |||
| 387 | try expect(mem.eql(u32, &@as([2]u32, down1), &[2]u32{ 0x55, 0xaa })); | ||
| 388 | try expect(mem.eql(u16, &@as([2]u16, down2), &[2]u16{ 0x55, 0xaa })); | ||
| 389 | try expect(mem.eql(u8, &@as([2]u8, down3), &[2]u8{ 0x55, 0xaa })); | ||
| 390 | } | ||
| 391 | |||
| 392 | fn doTheTestFloat() !void { | ||
| 393 | var vec = @splat(2, @as(f32, 1234.0)); | ||
| 394 | var wider: Vector(2, f64) = vec; | ||
| 395 | try expect(wider[0] == 1234.0); | ||
| 396 | try expect(wider[1] == 1234.0); | ||
| 397 | } | ||
| 398 | }; | ||
| 399 | |||
| 400 | try S.doTheTest(); | ||
| 401 | comptime try S.doTheTest(); | ||
| 402 | try S.doTheTestFloat(); | ||
| 403 | comptime try S.doTheTestFloat(); | ||
| 404 | } | ||
| 405 | |||
| 406 | test "comptime_int @intToFloat" { | ||
| 407 | { | ||
| 408 | const result = @intToFloat(f16, 1234); | ||
| 409 | try expect(@TypeOf(result) == f16); | ||
| 410 | try expect(result == 1234.0); | ||
| 411 | } | ||
| 412 | { | ||
| 413 | const result = @intToFloat(f32, 1234); | ||
| 414 | try expect(@TypeOf(result) == f32); | ||
| 415 | try expect(result == 1234.0); | ||
| 416 | } | ||
| 417 | { | ||
| 418 | const result = @intToFloat(f64, 1234); | ||
| 419 | try expect(@TypeOf(result) == f64); | ||
| 420 | try expect(result == 1234.0); | ||
| 421 | } | ||
| 422 | { | ||
| 423 | const result = @intToFloat(f128, 1234); | ||
| 424 | try expect(@TypeOf(result) == f128); | ||
| 425 | try expect(result == 1234.0); | ||
| 426 | } | ||
| 427 | // big comptime_int (> 64 bits) to f128 conversion | ||
| 428 | { | ||
| 429 | const result = @intToFloat(f128, 0x1_0000_0000_0000_0000); | ||
| 430 | try expect(@TypeOf(result) == f128); | ||
| 431 | try expect(result == 0x1_0000_0000_0000_0000.0); | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | test "@intCast i32 to u7" { | ||
| 436 | var x: u128 = maxInt(u128); | ||
| 437 | var y: i32 = 120; | ||
| 438 | var z = x >> @intCast(u7, y); | ||
| 439 | try expect(z == 0xff); | ||
| 440 | } | ||
| 441 | |||
| 442 | test "@floatCast cast down" { | ||
| 443 | { | ||
| 444 | var double: f64 = 0.001534; | ||
| 445 | var single = @floatCast(f32, double); | ||
| 446 | try expect(single == 0.001534); | ||
| 447 | } | ||
| 448 | { | ||
| 449 | const double: f64 = 0.001534; | ||
| 450 | const single = @floatCast(f32, double); | ||
| 451 | try expect(single == 0.001534); | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | test "implicit cast undefined to optional" { | ||
| 456 | try expect(MakeType(void).getNull() == null); | ||
| 457 | try expect(MakeType(void).getNonNull() != null); | ||
| 458 | } | ||
| 459 | |||
| 460 | fn MakeType(comptime T: type) type { | ||
| 461 | return struct { | ||
| 462 | fn getNull() ?T { | ||
| 463 | return null; | ||
| 464 | } | ||
| 465 | |||
| 466 | fn getNonNull() ?T { | ||
| 467 | return @as(T, undefined); | ||
| 468 | } | ||
| 469 | }; | ||
| 470 | } | ||
| 471 | |||
| 472 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 473 | var x: ?[*]u16 = null; | ||
| 474 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 475 | |||
| 476 | x = &y; | ||
| 477 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 478 | x.?[0] = 8; | ||
| 479 | y[3] = 6; | ||
| 480 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 481 | } | ||
| 482 | |||
| 483 | test "implicit cast from *[N]T to [*c]T" { | ||
| 484 | var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 485 | var y: [*c]u16 = &x; | ||
| 486 | |||
| 487 | try expect(std.mem.eql(u16, x[0..4], y[0..4])); | ||
| 488 | x[0] = 8; | ||
| 489 | y[3] = 6; | ||
| 490 | try expect(std.mem.eql(u16, x[0..4], y[0..4])); | ||
| 491 | } | ||
| 492 | |||
| 493 | test "implicit cast from *T to ?*c_void" { | ||
| 494 | var a: u8 = 1; | ||
| 495 | incrementVoidPtrValue(&a); | ||
| 496 | try std.testing.expect(a == 2); | ||
| 497 | } | ||
| 498 | |||
| 499 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 500 | @ptrCast(*u8, value.?).* += 1; | ||
| 501 | } | ||
| 502 | |||
| 503 | test "implicit cast from [*]T to ?*c_void" { | ||
| 504 | var a = [_]u8{ 3, 2, 1 }; | ||
| 505 | var runtime_zero: usize = 0; | ||
| 506 | incrementVoidPtrArray(a[runtime_zero..].ptr, 3); | ||
| 507 | try expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); | ||
| 508 | } | ||
| 509 | |||
| 510 | fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { | ||
| 511 | var n: usize = 0; | ||
| 512 | while (n < len) : (n += 1) { | ||
| 513 | @ptrCast([*]u8, array.?)[n] += 1; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | test "*usize to *void" { | ||
| 518 | var i = @as(usize, 0); | ||
| 519 | var v = @ptrCast(*void, &i); | ||
| 520 | v.* = {}; | ||
| 521 | } | ||
| 522 | |||
| 523 | test "compile time int to ptr of function" { | ||
| 524 | try foobar(FUNCTION_CONSTANT); | ||
| 525 | } | ||
| 526 | |||
| 527 | pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); | ||
| 528 | pub const PFN_void = fn (*c_void) callconv(.C) void; | ||
| 529 | |||
| 530 | fn foobar(func: PFN_void) !void { | ||
| 531 | try std.testing.expect(@ptrToInt(func) == maxInt(usize)); | ||
| 532 | } | ||
| 533 | |||
| 534 | test "implicit ptr to *c_void" { | ||
| 535 | var a: u32 = 1; | ||
| 536 | var ptr: *align(@alignOf(u32)) c_void = &a; | ||
| 537 | var b: *u32 = @ptrCast(*u32, ptr); | ||
| 538 | try expect(b.* == 1); | ||
| 539 | var ptr2: ?*align(@alignOf(u32)) c_void = &a; | ||
| 540 | var c: *u32 = @ptrCast(*u32, ptr2.?); | ||
| 541 | try expect(c.* == 1); | ||
| 542 | } | ||
| 543 | |||
| 544 | test "@intCast to comptime_int" { | ||
| 545 | try expect(@intCast(comptime_int, 0) == 0); | ||
| 546 | } | ||
| 547 | |||
| 548 | test "implicit cast comptime numbers to any type when the value fits" { | ||
| 549 | const a: u64 = 255; | ||
| 550 | var b: u8 = a; | ||
| 551 | try expect(b == 255); | ||
| 552 | } | ||
| 553 | |||
| 554 | test "@intToEnum passed a comptime_int to an enum with one item" { | ||
| 555 | const E = enum { | ||
| 556 | A, | ||
| 557 | }; | ||
| 558 | const x = @intToEnum(E, 0); | ||
| 559 | try expect(x == E.A); | ||
| 560 | } | ||
| 561 | |||
| 562 | test "@intToEnum runtime to an extern enum with duplicate values" { | ||
| 563 | const E = extern enum(u8) { | ||
| 564 | A = 1, | ||
| 565 | B = 1, | ||
| 566 | }; | ||
| 567 | var a: u8 = 1; | ||
| 568 | var x = @intToEnum(E, a); | ||
| 569 | try expect(x == E.A); | ||
| 570 | try expect(x == E.B); | ||
| 571 | } | ||
| 572 | |||
| 573 | test "@intCast to u0 and use the result" { | ||
| 574 | const S = struct { | ||
| 575 | fn doTheTest(zero: u1, one: u1, bigzero: i32) !void { | ||
| 576 | try expect((one << @intCast(u0, bigzero)) == 1); | ||
| 577 | try expect((zero << @intCast(u0, bigzero)) == 0); | ||
| 578 | } | ||
| 579 | }; | ||
| 580 | try S.doTheTest(0, 1, 0); | ||
| 581 | comptime try S.doTheTest(0, 1, 0); | ||
| 582 | } | ||
| 583 | |||
| 584 | test "peer type resolution: unreachable, null, slice" { | ||
| 585 | const S = struct { | ||
| 586 | fn doTheTest(num: usize, word: []const u8) !void { | ||
| 587 | const result = switch (num) { | ||
| 588 | 0 => null, | ||
| 589 | 1 => word, | ||
| 590 | else => unreachable, | ||
| 591 | }; | ||
| 592 | try expect(mem.eql(u8, result.?, "hi")); | ||
| 593 | } | ||
| 594 | }; | ||
| 595 | try S.doTheTest(1, "hi"); | ||
| 596 | } | ||
| 597 | |||
| 598 | test "peer type resolution: unreachable, error set, unreachable" { | ||
| 599 | const Error = error{ | ||
| 600 | FileDescriptorAlreadyPresentInSet, | ||
| 601 | OperationCausesCircularLoop, | ||
| 602 | FileDescriptorNotRegistered, | ||
| 603 | SystemResources, | ||
| 604 | UserResourceLimitReached, | ||
| 605 | FileDescriptorIncompatibleWithEpoll, | ||
| 606 | Unexpected, | ||
| 607 | }; | ||
| 608 | var err = Error.SystemResources; | ||
| 609 | const transformed_err = switch (err) { | ||
| 610 | error.FileDescriptorAlreadyPresentInSet => unreachable, | ||
| 611 | error.OperationCausesCircularLoop => unreachable, | ||
| 612 | error.FileDescriptorNotRegistered => unreachable, | ||
| 613 | error.SystemResources => error.SystemResources, | ||
| 614 | error.UserResourceLimitReached => error.UserResourceLimitReached, | ||
| 615 | error.FileDescriptorIncompatibleWithEpoll => unreachable, | ||
| 616 | error.Unexpected => unreachable, | ||
| 617 | }; | ||
| 618 | try expect(transformed_err == error.SystemResources); | ||
| 619 | } | ||
| 620 | |||
| 621 | test "implicit cast comptime_int to comptime_float" { | ||
| 622 | comptime try expect(@as(comptime_float, 10) == @as(f32, 10)); | ||
| 623 | try expect(2 == 2.0); | ||
| 624 | } | ||
| 625 | |||
| 626 | test "implicit cast *[0]T to E![]const u8" { | ||
| 627 | var x = @as(anyerror![]const u8, &[0]u8{}); | ||
| 628 | try expect((x catch unreachable).len == 0); | ||
| 629 | } | ||
| 630 | |||
| 631 | test "peer cast *[0]T to E![]const T" { | ||
| 632 | var buffer: [5]u8 = "abcde".*; | ||
| 633 | var buf: anyerror![]const u8 = buffer[0..]; | ||
| 634 | var b = false; | ||
| 635 | var y = if (b) &[0]u8{} else buf; | ||
| 636 | try expect(mem.eql(u8, "abcde", y catch unreachable)); | ||
| 637 | } | ||
| 638 | |||
| 639 | test "peer cast *[0]T to []const T" { | ||
| 640 | var buffer: [5]u8 = "abcde".*; | ||
| 641 | var buf: []const u8 = buffer[0..]; | ||
| 642 | var b = false; | ||
| 643 | var y = if (b) &[0]u8{} else buf; | ||
| 644 | try expect(mem.eql(u8, "abcde", y)); | ||
| 645 | } | ||
| 646 | |||
| 647 | var global_array: [4]u8 = undefined; | ||
| 648 | test "cast from array reference to fn" { | ||
| 649 | const f = @ptrCast(fn () callconv(.C) void, &global_array); | ||
| 650 | try expect(@ptrToInt(f) == @ptrToInt(&global_array)); | ||
| 651 | } | ||
| 652 | |||
| 653 | test "*const [N]null u8 to ?[]const u8" { | ||
| 654 | const S = struct { | ||
| 655 | fn doTheTest() !void { | ||
| 656 | var a = "Hello"; | ||
| 657 | var b: ?[]const u8 = a; | ||
| 658 | try expect(mem.eql(u8, b.?, "Hello")); | ||
| 659 | } | ||
| 660 | }; | ||
| 661 | try S.doTheTest(); | ||
| 662 | comptime try S.doTheTest(); | ||
| 663 | } | ||
| 664 | |||
| 665 | test "peer resolution of string literals" { | ||
| 666 | const S = struct { | ||
| 667 | const E = extern enum { | ||
| 668 | a, | ||
| 669 | b, | ||
| 670 | c, | ||
| 671 | d, | ||
| 672 | }; | ||
| 673 | |||
| 674 | fn doTheTest(e: E) !void { | ||
| 675 | const cmd = switch (e) { | ||
| 676 | .a => "one", | ||
| 677 | .b => "two", | ||
| 678 | .c => "three", | ||
| 679 | .d => "four", | ||
| 680 | }; | ||
| 681 | try expect(mem.eql(u8, cmd, "two")); | ||
| 682 | } | ||
| 683 | }; | ||
| 684 | try S.doTheTest(.b); | ||
| 685 | comptime try S.doTheTest(.b); | ||
| 686 | } | ||
| 687 | |||
| 688 | test "type coercion related to sentinel-termination" { | ||
| 689 | const S = struct { | ||
| 690 | fn doTheTest() !void { | ||
| 691 | // [:x]T to []T | ||
| 692 | { | ||
| 693 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 694 | var slice: [:0]i32 = &array; | ||
| 695 | var dest: []i32 = slice; | ||
| 696 | try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 697 | } | ||
| 698 | |||
| 699 | // [*:x]T to [*]T | ||
| 700 | { | ||
| 701 | var array = [4:99]i32{ 1, 2, 3, 4 }; | ||
| 702 | var dest: [*]i32 = &array; | ||
| 703 | try expect(dest[0] == 1); | ||
| 704 | try expect(dest[1] == 2); | ||
| 705 | try expect(dest[2] == 3); | ||
| 706 | try expect(dest[3] == 4); | ||
| 707 | try expect(dest[4] == 99); | ||
| 708 | } | ||
| 709 | |||
| 710 | // [N:x]T to [N]T | ||
| 711 | { | ||
| 712 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 713 | var dest: [4]i32 = array; | ||
| 714 | try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 715 | } | ||
| 716 | |||
| 717 | // *[N:x]T to *[N]T | ||
| 718 | { | ||
| 719 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 720 | var dest: *[4]i32 = &array; | ||
| 721 | try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); | ||
| 722 | } | ||
| 723 | |||
| 724 | // [:x]T to [*:x]T | ||
| 725 | { | ||
| 726 | var array = [4:0]i32{ 1, 2, 3, 4 }; | ||
| 727 | var slice: [:0]i32 = &array; | ||
| 728 | var dest: [*:0]i32 = slice; | ||
| 729 | try expect(dest[0] == 1); | ||
| 730 | try expect(dest[1] == 2); | ||
| 731 | try expect(dest[2] == 3); | ||
| 732 | try expect(dest[3] == 4); | ||
| 733 | try expect(dest[4] == 0); | ||
| 734 | } | ||
| 735 | } | ||
| 736 | }; | ||
| 737 | try S.doTheTest(); | ||
| 738 | comptime try S.doTheTest(); | ||
| 739 | } | ||
| 740 | |||
| 741 | test "cast i8 fn call peers to i32 result" { | ||
| 742 | const S = struct { | ||
| 743 | fn doTheTest() !void { | ||
| 744 | var cond = true; | ||
| 745 | const value: i32 = if (cond) smallBoi() else bigBoi(); | ||
| 746 | try expect(value == 123); | ||
| 747 | } | ||
| 748 | fn smallBoi() i8 { | ||
| 749 | return 123; | ||
| 750 | } | ||
| 751 | fn bigBoi() i16 { | ||
| 752 | return 1234; | ||
| 753 | } | ||
| 754 | }; | ||
| 755 | try S.doTheTest(); | ||
| 756 | comptime try S.doTheTest(); | ||
| 757 | } | ||
| 758 | |||
| 759 | test "return u8 coercing into ?u32 return type" { | ||
| 760 | const S = struct { | ||
| 761 | fn doTheTest() !void { | ||
| 762 | try expect(foo(123).? == 123); | ||
| 763 | } | ||
| 764 | fn foo(arg: u8) ?u32 { | ||
| 765 | return arg; | ||
| 766 | } | ||
| 767 | }; | ||
| 768 | try S.doTheTest(); | ||
| 769 | comptime try S.doTheTest(); | ||
| 770 | } | ||
| 771 | |||
| 772 | test "peer result null and comptime_int" { | ||
| 773 | const S = struct { | ||
| 774 | fn blah(n: i32) ?i32 { | ||
| 775 | if (n == 0) { | ||
| 776 | return null; | ||
| 777 | } else if (n < 0) { | ||
| 778 | return -1; | ||
| 779 | } else { | ||
| 780 | return 1; | ||
| 781 | } | ||
| 782 | } | ||
| 783 | }; | ||
| 784 | |||
| 785 | try expect(S.blah(0) == null); | ||
| 786 | comptime try expect(S.blah(0) == null); | ||
| 787 | try expect(S.blah(10).? == 1); | ||
| 788 | comptime try expect(S.blah(10).? == 1); | ||
| 789 | try expect(S.blah(-10).? == -1); | ||
| 790 | comptime try expect(S.blah(-10).? == -1); | ||
| 791 | } | ||
| 792 | |||
| 793 | test "peer type resolution implicit cast to return type" { | ||
| 794 | const S = struct { | ||
| 795 | fn doTheTest() !void { | ||
| 796 | for ("hello") |c| _ = f(c); | ||
| 797 | } | ||
| 798 | fn f(c: u8) []const u8 { | ||
| 799 | return switch (c) { | ||
| 800 | 'h', 'e' => &[_]u8{c}, // should cast to slice | ||
| 801 | 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice | ||
| 802 | else => ([_]u8{c})[0..], // is a slice | ||
| 803 | }; | ||
| 804 | } | ||
| 805 | }; | ||
| 806 | try S.doTheTest(); | ||
| 807 | comptime try S.doTheTest(); | ||
| 808 | } | ||
| 809 | |||
| 810 | test "peer type resolution implicit cast to variable type" { | ||
| 811 | const S = struct { | ||
| 812 | fn doTheTest() !void { | ||
| 813 | var x: []const u8 = undefined; | ||
| 814 | for ("hello") |c| x = switch (c) { | ||
| 815 | 'h', 'e' => &[_]u8{c}, // should cast to slice | ||
| 816 | 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice | ||
| 817 | else => ([_]u8{c})[0..], // is a slice | ||
| 818 | }; | ||
| 819 | } | ||
| 820 | }; | ||
| 821 | try S.doTheTest(); | ||
| 822 | comptime try S.doTheTest(); | ||
| 823 | } | ||
| 824 | |||
| 825 | test "variable initialization uses result locations properly with regards to the type" { | ||
| 826 | var b = true; | ||
| 827 | const x: i32 = if (b) 1 else 2; | ||
| 828 | try expect(x == 1); | ||
| 829 | } | ||
| 830 | |||
| 831 | test "cast between [*c]T and ?[*:0]T on fn parameter" { | ||
| 832 | const S = struct { | ||
| 833 | const Handler = ?fn ([*c]const u8) callconv(.C) void; | ||
| 834 | fn addCallback(handler: Handler) void {} | ||
| 835 | |||
| 836 | fn myCallback(cstr: ?[*:0]const u8) callconv(.C) void {} | ||
| 837 | |||
| 838 | fn doTheTest() void { | ||
| 839 | addCallback(myCallback); | ||
| 840 | } | ||
| 841 | }; | ||
| 842 | S.doTheTest(); | ||
| 843 | } | ||
| 844 | |||
| 845 | test "cast between C pointer with different but compatible types" { | ||
| 846 | const S = struct { | ||
| 847 | fn foo(arg: [*]c_ushort) u16 { | ||
| 848 | return arg[0]; | ||
| 849 | } | ||
| 850 | fn doTheTest() !void { | ||
| 851 | var x = [_]u16{ 4, 2, 1, 3 }; | ||
| 852 | try expect(foo(@ptrCast([*]u16, &x)) == 4); | ||
| 853 | } | ||
| 854 | }; | ||
| 855 | try S.doTheTest(); | ||
| 856 | } | ||
| 857 | |||
| 858 | var global_struct: struct { f0: usize } = undefined; | ||
| 859 | |||
| 860 | test "assignment to optional pointer result loc" { | ||
| 861 | var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; | ||
| 862 | try expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); | ||
| 863 | } | ||
| 864 | |||
| 865 | test "peer type resolve string lit with sentinel-terminated mutable slice" { | ||
| 866 | var array: [4:0]u8 = undefined; | ||
| 867 | array[4] = 0; // TODO remove this when #4372 is solved | ||
| 868 | var slice: [:0]u8 = array[0..4 :0]; | ||
| 869 | comptime try expect(@TypeOf(slice, "hi") == [:0]const u8); | ||
| 870 | comptime try expect(@TypeOf("hi", slice) == [:0]const u8); | ||
| 871 | } | ||
| 872 | |||
| 873 | test "peer type unsigned int to signed" { | ||
| 874 | var w: u31 = 5; | ||
| 875 | var x: u8 = 7; | ||
| 876 | var y: i32 = -5; | ||
| 877 | var a = w + y + x; | ||
| 878 | comptime try expect(@TypeOf(a) == i32); | ||
| 879 | try expect(a == 7); | ||
| 880 | } | ||
| 881 | |||
| 882 | test "peer type resolve array pointers, one of them const" { | ||
| 883 | var array1: [4]u8 = undefined; | ||
| 884 | const array2: [5]u8 = undefined; | ||
| 885 | comptime try expect(@TypeOf(&array1, &array2) == []const u8); | ||
| 886 | comptime try expect(@TypeOf(&array2, &array1) == []const u8); | ||
| 887 | } | ||
| 888 | |||
| 889 | test "peer type resolve array pointer and unknown pointer" { | ||
| 890 | const const_array: [4]u8 = undefined; | ||
| 891 | var array: [4]u8 = undefined; | ||
| 892 | var const_ptr: [*]const u8 = undefined; | ||
| 893 | var ptr: [*]u8 = undefined; | ||
| 894 | |||
| 895 | comptime try expect(@TypeOf(&array, ptr) == [*]u8); | ||
| 896 | comptime try expect(@TypeOf(ptr, &array) == [*]u8); | ||
| 897 | |||
| 898 | comptime try expect(@TypeOf(&const_array, ptr) == [*]const u8); | ||
| 899 | comptime try expect(@TypeOf(ptr, &const_array) == [*]const u8); | ||
| 900 | |||
| 901 | comptime try expect(@TypeOf(&array, const_ptr) == [*]const u8); | ||
| 902 | comptime try expect(@TypeOf(const_ptr, &array) == [*]const u8); | ||
| 903 | |||
| 904 | comptime try expect(@TypeOf(&const_array, const_ptr) == [*]const u8); | ||
| 905 | comptime try expect(@TypeOf(const_ptr, &const_array) == [*]const u8); | ||
| 906 | } | ||
| 907 | |||
| 908 | test "comptime float casts" { | ||
| 909 | const a = @intToFloat(comptime_float, 1); | ||
| 910 | try expect(a == 1); | ||
| 911 | try expect(@TypeOf(a) == comptime_float); | ||
| 912 | const b = @floatToInt(comptime_int, 2); | ||
| 913 | try expect(b == 2); | ||
| 914 | try expect(@TypeOf(b) == comptime_int); | ||
| 915 | } | ||
| 916 | |||
| 917 | test "cast from ?[*]T to ??[*]T" { | ||
| 918 | const a: ??[*]u8 = @as(?[*]u8, null); | ||
| 919 | try expect(a != null and a.? == null); | ||
| 920 | } | ||
| 921 | |||
| 922 | test "cast between *[N]void and []void" { | ||
| 923 | var a: [4]void = undefined; | ||
| 924 | var b: []void = &a; | ||
| 925 | try expect(b.len == 4); | ||
| 926 | } | ||
test/stage1/behavior/const_slice_child.zig deleted-47| ... | @@ -1,47 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const debug = std.debug; | ||
| 3 | const testing = std.testing; | ||
| 4 | const expect = testing.expect; | ||
| 5 | |||
| 6 | var argv: [*]const [*]const u8 = undefined; | ||
| 7 | |||
| 8 | test "const slice child" { | ||
| 9 | const strs = [_][*]const u8{ | ||
| 10 | "one", | ||
| 11 | "two", | ||
| 12 | "three", | ||
| 13 | }; | ||
| 14 | argv = &strs; | ||
| 15 | try bar(strs.len); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn foo(args: [][]const u8) !void { | ||
| 19 | try expect(args.len == 3); | ||
| 20 | try expect(streql(args[0], "one")); | ||
| 21 | try expect(streql(args[1], "two")); | ||
| 22 | try expect(streql(args[2], "three")); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn bar(argc: usize) !void { | ||
| 26 | const args = testing.allocator.alloc([]const u8, argc) catch unreachable; | ||
| 27 | defer testing.allocator.free(args); | ||
| 28 | for (args) |_, i| { | ||
| 29 | const ptr = argv[i]; | ||
| 30 | args[i] = ptr[0..strlen(ptr)]; | ||
| 31 | } | ||
| 32 | try foo(args); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn strlen(ptr: [*]const u8) usize { | ||
| 36 | var count: usize = 0; | ||
| 37 | while (ptr[count] != 0) : (count += 1) {} | ||
| 38 | return count; | ||
| 39 | } | ||
| 40 | |||
| 41 | fn streql(a: []const u8, b: []const u8) bool { | ||
| 42 | if (a.len != b.len) return false; | ||
| 43 | for (a) |item, index| { | ||
| 44 | if (b[index] != item) return false; | ||
| 45 | } | ||
| 46 | return true; | ||
| 47 | } | ||
test/stage1/behavior/defer.zig deleted-114| ... | @@ -1,114 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const expectError = std.testing.expectError; | ||
| 5 | |||
| 6 | var result: [3]u8 = undefined; | ||
| 7 | var index: usize = undefined; | ||
| 8 | |||
| 9 | fn runSomeErrorDefers(x: bool) !bool { | ||
| 10 | index = 0; | ||
| 11 | defer { | ||
| 12 | result[index] = 'a'; | ||
| 13 | index += 1; | ||
| 14 | } | ||
| 15 | errdefer { | ||
| 16 | result[index] = 'b'; | ||
| 17 | index += 1; | ||
| 18 | } | ||
| 19 | defer { | ||
| 20 | result[index] = 'c'; | ||
| 21 | index += 1; | ||
| 22 | } | ||
| 23 | return if (x) x else error.FalseNotAllowed; | ||
| 24 | } | ||
| 25 | |||
| 26 | test "mixing normal and error defers" { | ||
| 27 | try expect(runSomeErrorDefers(true) catch unreachable); | ||
| 28 | try expect(result[0] == 'c'); | ||
| 29 | try expect(result[1] == 'a'); | ||
| 30 | |||
| 31 | const ok = runSomeErrorDefers(false) catch |err| x: { | ||
| 32 | try expect(err == error.FalseNotAllowed); | ||
| 33 | break :x true; | ||
| 34 | }; | ||
| 35 | try expect(ok); | ||
| 36 | try expect(result[0] == 'c'); | ||
| 37 | try expect(result[1] == 'b'); | ||
| 38 | try expect(result[2] == 'a'); | ||
| 39 | } | ||
| 40 | |||
| 41 | test "break and continue inside loop inside defer expression" { | ||
| 42 | testBreakContInDefer(10); | ||
| 43 | comptime testBreakContInDefer(10); | ||
| 44 | } | ||
| 45 | |||
| 46 | fn testBreakContInDefer(x: usize) void { | ||
| 47 | defer { | ||
| 48 | var i: usize = 0; | ||
| 49 | while (i < x) : (i += 1) { | ||
| 50 | if (i < 5) continue; | ||
| 51 | if (i == 5) break; | ||
| 52 | } | ||
| 53 | expect(i == 5) catch @panic("test failure"); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | test "defer and labeled break" { | ||
| 58 | var i = @as(usize, 0); | ||
| 59 | |||
| 60 | blk: { | ||
| 61 | defer i += 1; | ||
| 62 | break :blk; | ||
| 63 | } | ||
| 64 | |||
| 65 | try expect(i == 1); | ||
| 66 | } | ||
| 67 | |||
| 68 | test "errdefer does not apply to fn inside fn" { | ||
| 69 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad); | ||
| 70 | } | ||
| 71 | |||
| 72 | fn testNestedFnErrDefer() anyerror!void { | ||
| 73 | var a: i32 = 0; | ||
| 74 | errdefer a += 1; | ||
| 75 | const S = struct { | ||
| 76 | fn baz() anyerror { | ||
| 77 | return error.Bad; | ||
| 78 | } | ||
| 79 | }; | ||
| 80 | return S.baz(); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "return variable while defer expression in scope to modify it" { | ||
| 84 | const S = struct { | ||
| 85 | fn doTheTest() !void { | ||
| 86 | try expect(notNull().? == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn notNull() ?u8 { | ||
| 90 | var res: ?u8 = 1; | ||
| 91 | defer res = null; | ||
| 92 | return res; | ||
| 93 | } | ||
| 94 | }; | ||
| 95 | |||
| 96 | try S.doTheTest(); | ||
| 97 | comptime try S.doTheTest(); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "errdefer with payload" { | ||
| 101 | const S = struct { | ||
| 102 | fn foo() !i32 { | ||
| 103 | errdefer |a| { | ||
| 104 | expectEqual(error.One, a) catch @panic("test failure"); | ||
| 105 | } | ||
| 106 | return error.One; | ||
| 107 | } | ||
| 108 | fn doTheTest() !void { | ||
| 109 | try expectError(error.One, foo()); | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | try S.doTheTest(); | ||
| 113 | comptime try S.doTheTest(); | ||
| 114 | } | ||
test/stage1/behavior/enum.zig deleted-1204| ... | @@ -1,1204 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const Tag = @import("std").meta.Tag; | ||
| 4 | |||
| 5 | test "extern enum" { | ||
| 6 | const S = struct { | ||
| 7 | const i = extern enum { | ||
| 8 | n = 0, | ||
| 9 | o = 2, | ||
| 10 | p = 4, | ||
| 11 | q = 4, | ||
| 12 | }; | ||
| 13 | fn doTheTest(y: c_int) void { | ||
| 14 | var x = i.o; | ||
| 15 | switch (x) { | ||
| 16 | .n, .p => unreachable, | ||
| 17 | .o => {}, | ||
| 18 | } | ||
| 19 | } | ||
| 20 | }; | ||
| 21 | S.doTheTest(52); | ||
| 22 | comptime S.doTheTest(52); | ||
| 23 | } | ||
| 24 | |||
| 25 | test "non-exhaustive enum" { | ||
| 26 | const S = struct { | ||
| 27 | const E = enum(u8) { | ||
| 28 | a, | ||
| 29 | b, | ||
| 30 | _, | ||
| 31 | }; | ||
| 32 | fn doTheTest(y: u8) !void { | ||
| 33 | var e: E = .b; | ||
| 34 | try expect(switch (e) { | ||
| 35 | .a => false, | ||
| 36 | .b => true, | ||
| 37 | _ => false, | ||
| 38 | }); | ||
| 39 | e = @intToEnum(E, 12); | ||
| 40 | try expect(switch (e) { | ||
| 41 | .a => false, | ||
| 42 | .b => false, | ||
| 43 | _ => true, | ||
| 44 | }); | ||
| 45 | |||
| 46 | try expect(switch (e) { | ||
| 47 | .a => false, | ||
| 48 | .b => false, | ||
| 49 | else => true, | ||
| 50 | }); | ||
| 51 | e = .b; | ||
| 52 | try expect(switch (e) { | ||
| 53 | .a => false, | ||
| 54 | else => true, | ||
| 55 | }); | ||
| 56 | |||
| 57 | try expect(@typeInfo(E).Enum.fields.len == 2); | ||
| 58 | e = @intToEnum(E, 12); | ||
| 59 | try expect(@enumToInt(e) == 12); | ||
| 60 | e = @intToEnum(E, y); | ||
| 61 | try expect(@enumToInt(e) == 52); | ||
| 62 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 63 | } | ||
| 64 | }; | ||
| 65 | try S.doTheTest(52); | ||
| 66 | comptime try S.doTheTest(52); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "empty non-exhaustive enum" { | ||
| 70 | const S = struct { | ||
| 71 | const E = enum(u8) { | ||
| 72 | _, | ||
| 73 | }; | ||
| 74 | fn doTheTest(y: u8) !void { | ||
| 75 | var e = @intToEnum(E, y); | ||
| 76 | try expect(switch (e) { | ||
| 77 | _ => true, | ||
| 78 | }); | ||
| 79 | try expect(@enumToInt(e) == y); | ||
| 80 | |||
| 81 | try expect(@typeInfo(E).Enum.fields.len == 0); | ||
| 82 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | try S.doTheTest(42); | ||
| 86 | comptime try S.doTheTest(42); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "single field non-exhaustive enum" { | ||
| 90 | const S = struct { | ||
| 91 | const E = enum(u8) { | ||
| 92 | a, | ||
| 93 | _, | ||
| 94 | }; | ||
| 95 | fn doTheTest(y: u8) !void { | ||
| 96 | var e: E = .a; | ||
| 97 | try expect(switch (e) { | ||
| 98 | .a => true, | ||
| 99 | _ => false, | ||
| 100 | }); | ||
| 101 | e = @intToEnum(E, 12); | ||
| 102 | try expect(switch (e) { | ||
| 103 | .a => false, | ||
| 104 | _ => true, | ||
| 105 | }); | ||
| 106 | |||
| 107 | try expect(switch (e) { | ||
| 108 | .a => false, | ||
| 109 | else => true, | ||
| 110 | }); | ||
| 111 | e = .a; | ||
| 112 | try expect(switch (e) { | ||
| 113 | .a => true, | ||
| 114 | else => false, | ||
| 115 | }); | ||
| 116 | |||
| 117 | try expect(@enumToInt(@intToEnum(E, y)) == y); | ||
| 118 | try expect(@typeInfo(E).Enum.fields.len == 1); | ||
| 119 | try expect(@typeInfo(E).Enum.is_exhaustive == false); | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | try S.doTheTest(23); | ||
| 123 | comptime try S.doTheTest(23); | ||
| 124 | } | ||
| 125 | |||
| 126 | test "enum type" { | ||
| 127 | const foo1 = Foo{ .One = 13 }; | ||
| 128 | const foo2 = Foo{ | ||
| 129 | .Two = Point{ | ||
| 130 | .x = 1234, | ||
| 131 | .y = 5678, | ||
| 132 | }, | ||
| 133 | }; | ||
| 134 | const bar = Bar.B; | ||
| 135 | |||
| 136 | try expect(bar == Bar.B); | ||
| 137 | try expect(@typeInfo(Foo).Union.fields.len == 3); | ||
| 138 | try expect(@typeInfo(Bar).Enum.fields.len == 4); | ||
| 139 | try expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); | ||
| 140 | try expect(@sizeOf(Bar) == 1); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "enum as return value" { | ||
| 144 | switch (returnAnInt(13)) { | ||
| 145 | Foo.One => |value| try expect(value == 13), | ||
| 146 | else => unreachable, | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | const Point = struct { | ||
| 151 | x: u64, | ||
| 152 | y: u64, | ||
| 153 | }; | ||
| 154 | const Foo = union(enum) { | ||
| 155 | One: i32, | ||
| 156 | Two: Point, | ||
| 157 | Three: void, | ||
| 158 | }; | ||
| 159 | const FooNoVoid = union(enum) { | ||
| 160 | One: i32, | ||
| 161 | Two: Point, | ||
| 162 | }; | ||
| 163 | const Bar = enum { | ||
| 164 | A, | ||
| 165 | B, | ||
| 166 | C, | ||
| 167 | D, | ||
| 168 | }; | ||
| 169 | |||
| 170 | fn returnAnInt(x: i32) Foo { | ||
| 171 | return Foo{ .One = x }; | ||
| 172 | } | ||
| 173 | |||
| 174 | test "constant enum with payload" { | ||
| 175 | var empty = AnEnumWithPayload{ .Empty = {} }; | ||
| 176 | var full = AnEnumWithPayload{ .Full = 13 }; | ||
| 177 | shouldBeEmpty(empty); | ||
| 178 | shouldBeNotEmpty(full); | ||
| 179 | } | ||
| 180 | |||
| 181 | fn shouldBeEmpty(x: AnEnumWithPayload) void { | ||
| 182 | switch (x) { | ||
| 183 | AnEnumWithPayload.Empty => {}, | ||
| 184 | else => unreachable, | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | fn shouldBeNotEmpty(x: AnEnumWithPayload) void { | ||
| 189 | switch (x) { | ||
| 190 | AnEnumWithPayload.Empty => unreachable, | ||
| 191 | else => {}, | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | const AnEnumWithPayload = union(enum) { | ||
| 196 | Empty: void, | ||
| 197 | Full: i32, | ||
| 198 | }; | ||
| 199 | |||
| 200 | const Number = enum { | ||
| 201 | Zero, | ||
| 202 | One, | ||
| 203 | Two, | ||
| 204 | Three, | ||
| 205 | Four, | ||
| 206 | }; | ||
| 207 | |||
| 208 | test "enum to int" { | ||
| 209 | try shouldEqual(Number.Zero, 0); | ||
| 210 | try shouldEqual(Number.One, 1); | ||
| 211 | try shouldEqual(Number.Two, 2); | ||
| 212 | try shouldEqual(Number.Three, 3); | ||
| 213 | try shouldEqual(Number.Four, 4); | ||
| 214 | } | ||
| 215 | |||
| 216 | fn shouldEqual(n: Number, expected: u3) !void { | ||
| 217 | try expect(@enumToInt(n) == expected); | ||
| 218 | } | ||
| 219 | |||
| 220 | test "int to enum" { | ||
| 221 | try testIntToEnumEval(3); | ||
| 222 | } | ||
| 223 | fn testIntToEnumEval(x: i32) !void { | ||
| 224 | try expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); | ||
| 225 | } | ||
| 226 | const IntToEnumNumber = enum { | ||
| 227 | Zero, | ||
| 228 | One, | ||
| 229 | Two, | ||
| 230 | Three, | ||
| 231 | Four, | ||
| 232 | }; | ||
| 233 | |||
| 234 | test "@tagName" { | ||
| 235 | try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 236 | comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "@tagName extern enum with duplicates" { | ||
| 240 | try expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | ||
| 241 | comptime try expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | ||
| 242 | } | ||
| 243 | |||
| 244 | test "@tagName non-exhaustive enum" { | ||
| 245 | try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | ||
| 246 | comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | ||
| 247 | } | ||
| 248 | |||
| 249 | fn testEnumTagNameBare(n: anytype) []const u8 { | ||
| 250 | return @tagName(n); | ||
| 251 | } | ||
| 252 | |||
| 253 | const BareNumber = enum { | ||
| 254 | One, | ||
| 255 | Two, | ||
| 256 | Three, | ||
| 257 | }; | ||
| 258 | |||
| 259 | const ExternDuplicates = extern enum(u8) { | ||
| 260 | A = 1, | ||
| 261 | B = 1, | ||
| 262 | }; | ||
| 263 | |||
| 264 | const NonExhaustive = enum(u8) { | ||
| 265 | A, | ||
| 266 | B, | ||
| 267 | _, | ||
| 268 | }; | ||
| 269 | |||
| 270 | test "enum alignment" { | ||
| 271 | comptime { | ||
| 272 | try expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); | ||
| 273 | try expect(@alignOf(AlignTestEnum) >= @alignOf(u64)); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | const AlignTestEnum = union(enum) { | ||
| 278 | A: [9]u8, | ||
| 279 | B: u64, | ||
| 280 | }; | ||
| 281 | |||
| 282 | const ValueCount1 = enum { | ||
| 283 | I0, | ||
| 284 | }; | ||
| 285 | const ValueCount2 = enum { | ||
| 286 | I0, | ||
| 287 | I1, | ||
| 288 | }; | ||
| 289 | const ValueCount256 = enum { | ||
| 290 | I0, | ||
| 291 | I1, | ||
| 292 | I2, | ||
| 293 | I3, | ||
| 294 | I4, | ||
| 295 | I5, | ||
| 296 | I6, | ||
| 297 | I7, | ||
| 298 | I8, | ||
| 299 | I9, | ||
| 300 | I10, | ||
| 301 | I11, | ||
| 302 | I12, | ||
| 303 | I13, | ||
| 304 | I14, | ||
| 305 | I15, | ||
| 306 | I16, | ||
| 307 | I17, | ||
| 308 | I18, | ||
| 309 | I19, | ||
| 310 | I20, | ||
| 311 | I21, | ||
| 312 | I22, | ||
| 313 | I23, | ||
| 314 | I24, | ||
| 315 | I25, | ||
| 316 | I26, | ||
| 317 | I27, | ||
| 318 | I28, | ||
| 319 | I29, | ||
| 320 | I30, | ||
| 321 | I31, | ||
| 322 | I32, | ||
| 323 | I33, | ||
| 324 | I34, | ||
| 325 | I35, | ||
| 326 | I36, | ||
| 327 | I37, | ||
| 328 | I38, | ||
| 329 | I39, | ||
| 330 | I40, | ||
| 331 | I41, | ||
| 332 | I42, | ||
| 333 | I43, | ||
| 334 | I44, | ||
| 335 | I45, | ||
| 336 | I46, | ||
| 337 | I47, | ||
| 338 | I48, | ||
| 339 | I49, | ||
| 340 | I50, | ||
| 341 | I51, | ||
| 342 | I52, | ||
| 343 | I53, | ||
| 344 | I54, | ||
| 345 | I55, | ||
| 346 | I56, | ||
| 347 | I57, | ||
| 348 | I58, | ||
| 349 | I59, | ||
| 350 | I60, | ||
| 351 | I61, | ||
| 352 | I62, | ||
| 353 | I63, | ||
| 354 | I64, | ||
| 355 | I65, | ||
| 356 | I66, | ||
| 357 | I67, | ||
| 358 | I68, | ||
| 359 | I69, | ||
| 360 | I70, | ||
| 361 | I71, | ||
| 362 | I72, | ||
| 363 | I73, | ||
| 364 | I74, | ||
| 365 | I75, | ||
| 366 | I76, | ||
| 367 | I77, | ||
| 368 | I78, | ||
| 369 | I79, | ||
| 370 | I80, | ||
| 371 | I81, | ||
| 372 | I82, | ||
| 373 | I83, | ||
| 374 | I84, | ||
| 375 | I85, | ||
| 376 | I86, | ||
| 377 | I87, | ||
| 378 | I88, | ||
| 379 | I89, | ||
| 380 | I90, | ||
| 381 | I91, | ||
| 382 | I92, | ||
| 383 | I93, | ||
| 384 | I94, | ||
| 385 | I95, | ||
| 386 | I96, | ||
| 387 | I97, | ||
| 388 | I98, | ||
| 389 | I99, | ||
| 390 | I100, | ||
| 391 | I101, | ||
| 392 | I102, | ||
| 393 | I103, | ||
| 394 | I104, | ||
| 395 | I105, | ||
| 396 | I106, | ||
| 397 | I107, | ||
| 398 | I108, | ||
| 399 | I109, | ||
| 400 | I110, | ||
| 401 | I111, | ||
| 402 | I112, | ||
| 403 | I113, | ||
| 404 | I114, | ||
| 405 | I115, | ||
| 406 | I116, | ||
| 407 | I117, | ||
| 408 | I118, | ||
| 409 | I119, | ||
| 410 | I120, | ||
| 411 | I121, | ||
| 412 | I122, | ||
| 413 | I123, | ||
| 414 | I124, | ||
| 415 | I125, | ||
| 416 | I126, | ||
| 417 | I127, | ||
| 418 | I128, | ||
| 419 | I129, | ||
| 420 | I130, | ||
| 421 | I131, | ||
| 422 | I132, | ||
| 423 | I133, | ||
| 424 | I134, | ||
| 425 | I135, | ||
| 426 | I136, | ||
| 427 | I137, | ||
| 428 | I138, | ||
| 429 | I139, | ||
| 430 | I140, | ||
| 431 | I141, | ||
| 432 | I142, | ||
| 433 | I143, | ||
| 434 | I144, | ||
| 435 | I145, | ||
| 436 | I146, | ||
| 437 | I147, | ||
| 438 | I148, | ||
| 439 | I149, | ||
| 440 | I150, | ||
| 441 | I151, | ||
| 442 | I152, | ||
| 443 | I153, | ||
| 444 | I154, | ||
| 445 | I155, | ||
| 446 | I156, | ||
| 447 | I157, | ||
| 448 | I158, | ||
| 449 | I159, | ||
| 450 | I160, | ||
| 451 | I161, | ||
| 452 | I162, | ||
| 453 | I163, | ||
| 454 | I164, | ||
| 455 | I165, | ||
| 456 | I166, | ||
| 457 | I167, | ||
| 458 | I168, | ||
| 459 | I169, | ||
| 460 | I170, | ||
| 461 | I171, | ||
| 462 | I172, | ||
| 463 | I173, | ||
| 464 | I174, | ||
| 465 | I175, | ||
| 466 | I176, | ||
| 467 | I177, | ||
| 468 | I178, | ||
| 469 | I179, | ||
| 470 | I180, | ||
| 471 | I181, | ||
| 472 | I182, | ||
| 473 | I183, | ||
| 474 | I184, | ||
| 475 | I185, | ||
| 476 | I186, | ||
| 477 | I187, | ||
| 478 | I188, | ||
| 479 | I189, | ||
| 480 | I190, | ||
| 481 | I191, | ||
| 482 | I192, | ||
| 483 | I193, | ||
| 484 | I194, | ||
| 485 | I195, | ||
| 486 | I196, | ||
| 487 | I197, | ||
| 488 | I198, | ||
| 489 | I199, | ||
| 490 | I200, | ||
| 491 | I201, | ||
| 492 | I202, | ||
| 493 | I203, | ||
| 494 | I204, | ||
| 495 | I205, | ||
| 496 | I206, | ||
| 497 | I207, | ||
| 498 | I208, | ||
| 499 | I209, | ||
| 500 | I210, | ||
| 501 | I211, | ||
| 502 | I212, | ||
| 503 | I213, | ||
| 504 | I214, | ||
| 505 | I215, | ||
| 506 | I216, | ||
| 507 | I217, | ||
| 508 | I218, | ||
| 509 | I219, | ||
| 510 | I220, | ||
| 511 | I221, | ||
| 512 | I222, | ||
| 513 | I223, | ||
| 514 | I224, | ||
| 515 | I225, | ||
| 516 | I226, | ||
| 517 | I227, | ||
| 518 | I228, | ||
| 519 | I229, | ||
| 520 | I230, | ||
| 521 | I231, | ||
| 522 | I232, | ||
| 523 | I233, | ||
| 524 | I234, | ||
| 525 | I235, | ||
| 526 | I236, | ||
| 527 | I237, | ||
| 528 | I238, | ||
| 529 | I239, | ||
| 530 | I240, | ||
| 531 | I241, | ||
| 532 | I242, | ||
| 533 | I243, | ||
| 534 | I244, | ||
| 535 | I245, | ||
| 536 | I246, | ||
| 537 | I247, | ||
| 538 | I248, | ||
| 539 | I249, | ||
| 540 | I250, | ||
| 541 | I251, | ||
| 542 | I252, | ||
| 543 | I253, | ||
| 544 | I254, | ||
| 545 | I255, | ||
| 546 | }; | ||
| 547 | const ValueCount257 = enum { | ||
| 548 | I0, | ||
| 549 | I1, | ||
| 550 | I2, | ||
| 551 | I3, | ||
| 552 | I4, | ||
| 553 | I5, | ||
| 554 | I6, | ||
| 555 | I7, | ||
| 556 | I8, | ||
| 557 | I9, | ||
| 558 | I10, | ||
| 559 | I11, | ||
| 560 | I12, | ||
| 561 | I13, | ||
| 562 | I14, | ||
| 563 | I15, | ||
| 564 | I16, | ||
| 565 | I17, | ||
| 566 | I18, | ||
| 567 | I19, | ||
| 568 | I20, | ||
| 569 | I21, | ||
| 570 | I22, | ||
| 571 | I23, | ||
| 572 | I24, | ||
| 573 | I25, | ||
| 574 | I26, | ||
| 575 | I27, | ||
| 576 | I28, | ||
| 577 | I29, | ||
| 578 | I30, | ||
| 579 | I31, | ||
| 580 | I32, | ||
| 581 | I33, | ||
| 582 | I34, | ||
| 583 | I35, | ||
| 584 | I36, | ||
| 585 | I37, | ||
| 586 | I38, | ||
| 587 | I39, | ||
| 588 | I40, | ||
| 589 | I41, | ||
| 590 | I42, | ||
| 591 | I43, | ||
| 592 | I44, | ||
| 593 | I45, | ||
| 594 | I46, | ||
| 595 | I47, | ||
| 596 | I48, | ||
| 597 | I49, | ||
| 598 | I50, | ||
| 599 | I51, | ||
| 600 | I52, | ||
| 601 | I53, | ||
| 602 | I54, | ||
| 603 | I55, | ||
| 604 | I56, | ||
| 605 | I57, | ||
| 606 | I58, | ||
| 607 | I59, | ||
| 608 | I60, | ||
| 609 | I61, | ||
| 610 | I62, | ||
| 611 | I63, | ||
| 612 | I64, | ||
| 613 | I65, | ||
| 614 | I66, | ||
| 615 | I67, | ||
| 616 | I68, | ||
| 617 | I69, | ||
| 618 | I70, | ||
| 619 | I71, | ||
| 620 | I72, | ||
| 621 | I73, | ||
| 622 | I74, | ||
| 623 | I75, | ||
| 624 | I76, | ||
| 625 | I77, | ||
| 626 | I78, | ||
| 627 | I79, | ||
| 628 | I80, | ||
| 629 | I81, | ||
| 630 | I82, | ||
| 631 | I83, | ||
| 632 | I84, | ||
| 633 | I85, | ||
| 634 | I86, | ||
| 635 | I87, | ||
| 636 | I88, | ||
| 637 | I89, | ||
| 638 | I90, | ||
| 639 | I91, | ||
| 640 | I92, | ||
| 641 | I93, | ||
| 642 | I94, | ||
| 643 | I95, | ||
| 644 | I96, | ||
| 645 | I97, | ||
| 646 | I98, | ||
| 647 | I99, | ||
| 648 | I100, | ||
| 649 | I101, | ||
| 650 | I102, | ||
| 651 | I103, | ||
| 652 | I104, | ||
| 653 | I105, | ||
| 654 | I106, | ||
| 655 | I107, | ||
| 656 | I108, | ||
| 657 | I109, | ||
| 658 | I110, | ||
| 659 | I111, | ||
| 660 | I112, | ||
| 661 | I113, | ||
| 662 | I114, | ||
| 663 | I115, | ||
| 664 | I116, | ||
| 665 | I117, | ||
| 666 | I118, | ||
| 667 | I119, | ||
| 668 | I120, | ||
| 669 | I121, | ||
| 670 | I122, | ||
| 671 | I123, | ||
| 672 | I124, | ||
| 673 | I125, | ||
| 674 | I126, | ||
| 675 | I127, | ||
| 676 | I128, | ||
| 677 | I129, | ||
| 678 | I130, | ||
| 679 | I131, | ||
| 680 | I132, | ||
| 681 | I133, | ||
| 682 | I134, | ||
| 683 | I135, | ||
| 684 | I136, | ||
| 685 | I137, | ||
| 686 | I138, | ||
| 687 | I139, | ||
| 688 | I140, | ||
| 689 | I141, | ||
| 690 | I142, | ||
| 691 | I143, | ||
| 692 | I144, | ||
| 693 | I145, | ||
| 694 | I146, | ||
| 695 | I147, | ||
| 696 | I148, | ||
| 697 | I149, | ||
| 698 | I150, | ||
| 699 | I151, | ||
| 700 | I152, | ||
| 701 | I153, | ||
| 702 | I154, | ||
| 703 | I155, | ||
| 704 | I156, | ||
| 705 | I157, | ||
| 706 | I158, | ||
| 707 | I159, | ||
| 708 | I160, | ||
| 709 | I161, | ||
| 710 | I162, | ||
| 711 | I163, | ||
| 712 | I164, | ||
| 713 | I165, | ||
| 714 | I166, | ||
| 715 | I167, | ||
| 716 | I168, | ||
| 717 | I169, | ||
| 718 | I170, | ||
| 719 | I171, | ||
| 720 | I172, | ||
| 721 | I173, | ||
| 722 | I174, | ||
| 723 | I175, | ||
| 724 | I176, | ||
| 725 | I177, | ||
| 726 | I178, | ||
| 727 | I179, | ||
| 728 | I180, | ||
| 729 | I181, | ||
| 730 | I182, | ||
| 731 | I183, | ||
| 732 | I184, | ||
| 733 | I185, | ||
| 734 | I186, | ||
| 735 | I187, | ||
| 736 | I188, | ||
| 737 | I189, | ||
| 738 | I190, | ||
| 739 | I191, | ||
| 740 | I192, | ||
| 741 | I193, | ||
| 742 | I194, | ||
| 743 | I195, | ||
| 744 | I196, | ||
| 745 | I197, | ||
| 746 | I198, | ||
| 747 | I199, | ||
| 748 | I200, | ||
| 749 | I201, | ||
| 750 | I202, | ||
| 751 | I203, | ||
| 752 | I204, | ||
| 753 | I205, | ||
| 754 | I206, | ||
| 755 | I207, | ||
| 756 | I208, | ||
| 757 | I209, | ||
| 758 | I210, | ||
| 759 | I211, | ||
| 760 | I212, | ||
| 761 | I213, | ||
| 762 | I214, | ||
| 763 | I215, | ||
| 764 | I216, | ||
| 765 | I217, | ||
| 766 | I218, | ||
| 767 | I219, | ||
| 768 | I220, | ||
| 769 | I221, | ||
| 770 | I222, | ||
| 771 | I223, | ||
| 772 | I224, | ||
| 773 | I225, | ||
| 774 | I226, | ||
| 775 | I227, | ||
| 776 | I228, | ||
| 777 | I229, | ||
| 778 | I230, | ||
| 779 | I231, | ||
| 780 | I232, | ||
| 781 | I233, | ||
| 782 | I234, | ||
| 783 | I235, | ||
| 784 | I236, | ||
| 785 | I237, | ||
| 786 | I238, | ||
| 787 | I239, | ||
| 788 | I240, | ||
| 789 | I241, | ||
| 790 | I242, | ||
| 791 | I243, | ||
| 792 | I244, | ||
| 793 | I245, | ||
| 794 | I246, | ||
| 795 | I247, | ||
| 796 | I248, | ||
| 797 | I249, | ||
| 798 | I250, | ||
| 799 | I251, | ||
| 800 | I252, | ||
| 801 | I253, | ||
| 802 | I254, | ||
| 803 | I255, | ||
| 804 | I256, | ||
| 805 | }; | ||
| 806 | |||
| 807 | test "enum sizes" { | ||
| 808 | comptime { | ||
| 809 | try expect(@sizeOf(ValueCount1) == 0); | ||
| 810 | try expect(@sizeOf(ValueCount2) == 1); | ||
| 811 | try expect(@sizeOf(ValueCount256) == 1); | ||
| 812 | try expect(@sizeOf(ValueCount257) == 2); | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | const Small2 = enum(u2) { | ||
| 817 | One, | ||
| 818 | Two, | ||
| 819 | }; | ||
| 820 | const Small = enum(u2) { | ||
| 821 | One, | ||
| 822 | Two, | ||
| 823 | Three, | ||
| 824 | Four, | ||
| 825 | }; | ||
| 826 | |||
| 827 | test "set enum tag type" { | ||
| 828 | { | ||
| 829 | var x = Small.One; | ||
| 830 | x = Small.Two; | ||
| 831 | comptime try expect(Tag(Small) == u2); | ||
| 832 | } | ||
| 833 | { | ||
| 834 | var x = Small2.One; | ||
| 835 | x = Small2.Two; | ||
| 836 | comptime try expect(Tag(Small2) == u2); | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | const A = enum(u3) { | ||
| 841 | One, | ||
| 842 | Two, | ||
| 843 | Three, | ||
| 844 | Four, | ||
| 845 | One2, | ||
| 846 | Two2, | ||
| 847 | Three2, | ||
| 848 | Four2, | ||
| 849 | }; | ||
| 850 | |||
| 851 | const B = enum(u3) { | ||
| 852 | One3, | ||
| 853 | Two3, | ||
| 854 | Three3, | ||
| 855 | Four3, | ||
| 856 | One23, | ||
| 857 | Two23, | ||
| 858 | Three23, | ||
| 859 | Four23, | ||
| 860 | }; | ||
| 861 | |||
| 862 | const C = enum(u2) { | ||
| 863 | One4, | ||
| 864 | Two4, | ||
| 865 | Three4, | ||
| 866 | Four4, | ||
| 867 | }; | ||
| 868 | |||
| 869 | const BitFieldOfEnums = packed struct { | ||
| 870 | a: A, | ||
| 871 | b: B, | ||
| 872 | c: C, | ||
| 873 | }; | ||
| 874 | |||
| 875 | const bit_field_1 = BitFieldOfEnums{ | ||
| 876 | .a = A.Two, | ||
| 877 | .b = B.Three3, | ||
| 878 | .c = C.Four4, | ||
| 879 | }; | ||
| 880 | |||
| 881 | test "bit field access with enum fields" { | ||
| 882 | var data = bit_field_1; | ||
| 883 | try expect(getA(&data) == A.Two); | ||
| 884 | try expect(getB(&data) == B.Three3); | ||
| 885 | try expect(getC(&data) == C.Four4); | ||
| 886 | comptime try expect(@sizeOf(BitFieldOfEnums) == 1); | ||
| 887 | |||
| 888 | data.b = B.Four3; | ||
| 889 | try expect(data.b == B.Four3); | ||
| 890 | |||
| 891 | data.a = A.Three; | ||
| 892 | try expect(data.a == A.Three); | ||
| 893 | try expect(data.b == B.Four3); | ||
| 894 | } | ||
| 895 | |||
| 896 | fn getA(data: *const BitFieldOfEnums) A { | ||
| 897 | return data.a; | ||
| 898 | } | ||
| 899 | |||
| 900 | fn getB(data: *const BitFieldOfEnums) B { | ||
| 901 | return data.b; | ||
| 902 | } | ||
| 903 | |||
| 904 | fn getC(data: *const BitFieldOfEnums) C { | ||
| 905 | return data.c; | ||
| 906 | } | ||
| 907 | |||
| 908 | test "casting enum to its tag type" { | ||
| 909 | try testCastEnumTag(Small2.Two); | ||
| 910 | comptime try testCastEnumTag(Small2.Two); | ||
| 911 | } | ||
| 912 | |||
| 913 | fn testCastEnumTag(value: Small2) !void { | ||
| 914 | try expect(@enumToInt(value) == 1); | ||
| 915 | } | ||
| 916 | |||
| 917 | const MultipleChoice = enum(u32) { | ||
| 918 | A = 20, | ||
| 919 | B = 40, | ||
| 920 | C = 60, | ||
| 921 | D = 1000, | ||
| 922 | }; | ||
| 923 | |||
| 924 | test "enum with specified tag values" { | ||
| 925 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 926 | comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C); | ||
| 927 | } | ||
| 928 | |||
| 929 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { | ||
| 930 | try expect(@enumToInt(x) == 60); | ||
| 931 | try expect(1234 == switch (x) { | ||
| 932 | MultipleChoice.A => 1, | ||
| 933 | MultipleChoice.B => 2, | ||
| 934 | MultipleChoice.C => @as(u32, 1234), | ||
| 935 | MultipleChoice.D => 4, | ||
| 936 | }); | ||
| 937 | } | ||
| 938 | |||
| 939 | const MultipleChoice2 = enum(u32) { | ||
| 940 | Unspecified1, | ||
| 941 | A = 20, | ||
| 942 | Unspecified2, | ||
| 943 | B = 40, | ||
| 944 | Unspecified3, | ||
| 945 | C = 60, | ||
| 946 | Unspecified4, | ||
| 947 | D = 1000, | ||
| 948 | Unspecified5, | ||
| 949 | }; | ||
| 950 | |||
| 951 | test "enum with specified and unspecified tag values" { | ||
| 952 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 953 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | ||
| 954 | } | ||
| 955 | |||
| 956 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { | ||
| 957 | try expect(@enumToInt(x) == 1000); | ||
| 958 | try expect(1234 == switch (x) { | ||
| 959 | MultipleChoice2.A => 1, | ||
| 960 | MultipleChoice2.B => 2, | ||
| 961 | MultipleChoice2.C => 3, | ||
| 962 | MultipleChoice2.D => @as(u32, 1234), | ||
| 963 | MultipleChoice2.Unspecified1 => 5, | ||
| 964 | MultipleChoice2.Unspecified2 => 6, | ||
| 965 | MultipleChoice2.Unspecified3 => 7, | ||
| 966 | MultipleChoice2.Unspecified4 => 8, | ||
| 967 | MultipleChoice2.Unspecified5 => 9, | ||
| 968 | }); | ||
| 969 | } | ||
| 970 | |||
| 971 | test "cast integer literal to enum" { | ||
| 972 | try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | ||
| 973 | try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | ||
| 974 | } | ||
| 975 | |||
| 976 | const EnumWithOneMember = enum { | ||
| 977 | Eof, | ||
| 978 | }; | ||
| 979 | |||
| 980 | fn doALoopThing(id: EnumWithOneMember) void { | ||
| 981 | while (true) { | ||
| 982 | if (id == EnumWithOneMember.Eof) { | ||
| 983 | break; | ||
| 984 | } | ||
| 985 | @compileError("above if condition should be comptime"); | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | test "comparison operator on enum with one member is comptime known" { | ||
| 990 | doALoopThing(EnumWithOneMember.Eof); | ||
| 991 | } | ||
| 992 | |||
| 993 | const State = enum { | ||
| 994 | Start, | ||
| 995 | }; | ||
| 996 | test "switch on enum with one member is comptime known" { | ||
| 997 | var state = State.Start; | ||
| 998 | switch (state) { | ||
| 999 | State.Start => return, | ||
| 1000 | } | ||
| 1001 | @compileError("analysis should not reach here"); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | const EnumWithTagValues = enum(u4) { | ||
| 1005 | A = 1 << 0, | ||
| 1006 | B = 1 << 1, | ||
| 1007 | C = 1 << 2, | ||
| 1008 | D = 1 << 3, | ||
| 1009 | }; | ||
| 1010 | test "enum with tag values don't require parens" { | ||
| 1011 | try expect(@enumToInt(EnumWithTagValues.C) == 0b0100); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | test "enum with 1 field but explicit tag type should still have the tag type" { | ||
| 1015 | const Enum = enum(u8) { | ||
| 1016 | B = 2, | ||
| 1017 | }; | ||
| 1018 | comptime try expect(@sizeOf(Enum) == @sizeOf(u8)); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | test "empty extern enum with members" { | ||
| 1022 | const E = extern enum { | ||
| 1023 | A, | ||
| 1024 | B, | ||
| 1025 | C, | ||
| 1026 | }; | ||
| 1027 | try expect(@sizeOf(E) == @sizeOf(c_int)); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | test "tag name with assigned enum values" { | ||
| 1031 | const LocalFoo = enum { | ||
| 1032 | A = 1, | ||
| 1033 | B = 0, | ||
| 1034 | }; | ||
| 1035 | var b = LocalFoo.B; | ||
| 1036 | try expect(mem.eql(u8, @tagName(b), "B")); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | test "enum literal equality" { | ||
| 1040 | const x = .hi; | ||
| 1041 | const y = .ok; | ||
| 1042 | const z = .hi; | ||
| 1043 | |||
| 1044 | try expect(x != y); | ||
| 1045 | try expect(x == z); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | test "enum literal cast to enum" { | ||
| 1049 | const Color = enum { | ||
| 1050 | Auto, | ||
| 1051 | Off, | ||
| 1052 | On, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | var color1: Color = .Auto; | ||
| 1056 | var color2 = Color.Auto; | ||
| 1057 | try expect(color1 == color2); | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | test "peer type resolution with enum literal" { | ||
| 1061 | const Items = enum { | ||
| 1062 | one, | ||
| 1063 | two, | ||
| 1064 | }; | ||
| 1065 | |||
| 1066 | try expect(Items.two == .two); | ||
| 1067 | try expect(.two == Items.two); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | test "enum literal in array literal" { | ||
| 1071 | const Items = enum { | ||
| 1072 | one, | ||
| 1073 | two, | ||
| 1074 | }; | ||
| 1075 | |||
| 1076 | const array = [_]Items{ | ||
| 1077 | .one, | ||
| 1078 | .two, | ||
| 1079 | }; | ||
| 1080 | |||
| 1081 | try expect(array[0] == .one); | ||
| 1082 | try expect(array[1] == .two); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | test "signed integer as enum tag" { | ||
| 1086 | const SignedEnum = enum(i2) { | ||
| 1087 | A0 = -1, | ||
| 1088 | A1 = 0, | ||
| 1089 | A2 = 1, | ||
| 1090 | }; | ||
| 1091 | |||
| 1092 | try expect(@enumToInt(SignedEnum.A0) == -1); | ||
| 1093 | try expect(@enumToInt(SignedEnum.A1) == 0); | ||
| 1094 | try expect(@enumToInt(SignedEnum.A2) == 1); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | test "enum value allocation" { | ||
| 1098 | const LargeEnum = enum(u32) { | ||
| 1099 | A0 = 0x80000000, | ||
| 1100 | A1, | ||
| 1101 | A2, | ||
| 1102 | }; | ||
| 1103 | |||
| 1104 | try expect(@enumToInt(LargeEnum.A0) == 0x80000000); | ||
| 1105 | try expect(@enumToInt(LargeEnum.A1) == 0x80000001); | ||
| 1106 | try expect(@enumToInt(LargeEnum.A2) == 0x80000002); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | test "enum literal casting to tagged union" { | ||
| 1110 | const Arch = union(enum) { | ||
| 1111 | x86_64, | ||
| 1112 | arm: Arm32, | ||
| 1113 | |||
| 1114 | const Arm32 = enum { | ||
| 1115 | v8_5a, | ||
| 1116 | v8_4a, | ||
| 1117 | }; | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | var t = true; | ||
| 1121 | var x: Arch = .x86_64; | ||
| 1122 | var y = if (t) x else .x86_64; | ||
| 1123 | switch (y) { | ||
| 1124 | .x86_64 => {}, | ||
| 1125 | else => @panic("fail"), | ||
| 1126 | } | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | test "enum with one member and custom tag type" { | ||
| 1130 | const E = enum(u2) { | ||
| 1131 | One, | ||
| 1132 | }; | ||
| 1133 | try expect(@enumToInt(E.One) == 0); | ||
| 1134 | const E2 = enum(u2) { | ||
| 1135 | One = 2, | ||
| 1136 | }; | ||
| 1137 | try expect(@enumToInt(E2.One) == 2); | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | test "enum literal casting to optional" { | ||
| 1141 | var bar: ?Bar = undefined; | ||
| 1142 | bar = .B; | ||
| 1143 | |||
| 1144 | try expect(bar.? == Bar.B); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | test "enum literal casting to error union with payload enum" { | ||
| 1148 | var bar: error{B}!Bar = undefined; | ||
| 1149 | bar = .B; // should never cast to the error set | ||
| 1150 | |||
| 1151 | try expect((try bar) == Bar.B); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | test "enum with one member and u1 tag type @enumToInt" { | ||
| 1155 | const Enum = enum(u1) { | ||
| 1156 | Test, | ||
| 1157 | }; | ||
| 1158 | try expect(@enumToInt(Enum.Test) == 0); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | test "enum with comptime_int tag type" { | ||
| 1162 | const Enum = enum(comptime_int) { | ||
| 1163 | One = 3, | ||
| 1164 | Two = 2, | ||
| 1165 | Three = 1, | ||
| 1166 | }; | ||
| 1167 | comptime try expect(Tag(Enum) == comptime_int); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | test "enum with one member default to u0 tag type" { | ||
| 1171 | const E0 = enum { | ||
| 1172 | X, | ||
| 1173 | }; | ||
| 1174 | comptime try expect(Tag(E0) == u0); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | test "tagName on enum literals" { | ||
| 1178 | try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); | ||
| 1179 | comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | test "method call on an enum" { | ||
| 1183 | const S = struct { | ||
| 1184 | const E = enum { | ||
| 1185 | one, | ||
| 1186 | two, | ||
| 1187 | |||
| 1188 | fn method(self: *E) bool { | ||
| 1189 | return self.* == .two; | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | fn generic_method(self: *E, foo: anytype) bool { | ||
| 1193 | return self.* == .two and foo == bool; | ||
| 1194 | } | ||
| 1195 | }; | ||
| 1196 | fn doTheTest() !void { | ||
| 1197 | var e = E.two; | ||
| 1198 | try expect(e.method()); | ||
| 1199 | try expect(e.generic_method(bool)); | ||
| 1200 | } | ||
| 1201 | }; | ||
| 1202 | try S.doTheTest(); | ||
| 1203 | comptime try S.doTheTest(); | ||
| 1204 | } | ||
test/stage1/behavior/enum_with_members.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const fmt = @import("std").fmt; | ||
| 4 | |||
| 5 | const ET = union(enum) { | ||
| 6 | SINT: i32, | ||
| 7 | UINT: u32, | ||
| 8 | |||
| 9 | pub fn print(a: *const ET, buf: []u8) anyerror!usize { | ||
| 10 | return switch (a.*) { | ||
| 11 | ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}), | ||
| 12 | ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}), | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | |||
| 17 | test "enum with members" { | ||
| 18 | const a = ET{ .SINT = -42 }; | ||
| 19 | const b = ET{ .UINT = 42 }; | ||
| 20 | var buf: [20]u8 = undefined; | ||
| 21 | |||
| 22 | try expect((a.print(buf[0..]) catch unreachable) == 3); | ||
| 23 | try expect(mem.eql(u8, buf[0..3], "-42")); | ||
| 24 | |||
| 25 | try expect((b.print(buf[0..]) catch unreachable) == 2); | ||
| 26 | try expect(mem.eql(u8, buf[0..2], "42")); | ||
| 27 | } | ||
test/stage1/behavior/error.zig deleted-452| ... | @@ -1,452 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectError = std.testing.expectError; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | pub fn foo() anyerror!i32 { | ||
| 8 | const x = try bar(); | ||
| 9 | return x + 1; | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn bar() anyerror!i32 { | ||
| 13 | return 13; | ||
| 14 | } | ||
| 15 | |||
| 16 | pub fn baz() anyerror!i32 { | ||
| 17 | const y = foo() catch 1234; | ||
| 18 | return y + 1; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "error wrapping" { | ||
| 22 | try expect((baz() catch unreachable) == 15); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn gimmeItBroke() []const u8 { | ||
| 26 | return @errorName(error.ItBroke); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "@errorName" { | ||
| 30 | try expect(mem.eql(u8, @errorName(error.AnError), "AnError")); | ||
| 31 | try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "error values" { | ||
| 35 | const a = @errorToInt(error.err1); | ||
| 36 | const b = @errorToInt(error.err2); | ||
| 37 | try expect(a != b); | ||
| 38 | } | ||
| 39 | |||
| 40 | test "redefinition of error values allowed" { | ||
| 41 | shouldBeNotEqual(error.AnError, error.SecondError); | ||
| 42 | } | ||
| 43 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { | ||
| 44 | if (a == b) unreachable; | ||
| 45 | } | ||
| 46 | |||
| 47 | test "error binary operator" { | ||
| 48 | const a = errBinaryOperatorG(true) catch 3; | ||
| 49 | const b = errBinaryOperatorG(false) catch 3; | ||
| 50 | try expect(a == 3); | ||
| 51 | try expect(b == 10); | ||
| 52 | } | ||
| 53 | fn errBinaryOperatorG(x: bool) anyerror!isize { | ||
| 54 | return if (x) error.ItBroke else @as(isize, 10); | ||
| 55 | } | ||
| 56 | |||
| 57 | test "unwrap simple value from error" { | ||
| 58 | const i = unwrapSimpleValueFromErrorDo() catch unreachable; | ||
| 59 | try expect(i == 13); | ||
| 60 | } | ||
| 61 | fn unwrapSimpleValueFromErrorDo() anyerror!isize { | ||
| 62 | return 13; | ||
| 63 | } | ||
| 64 | |||
| 65 | test "error return in assignment" { | ||
| 66 | doErrReturnInAssignment() catch unreachable; | ||
| 67 | } | ||
| 68 | |||
| 69 | fn doErrReturnInAssignment() anyerror!void { | ||
| 70 | var x: i32 = undefined; | ||
| 71 | x = try makeANonErr(); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn makeANonErr() anyerror!i32 { | ||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | test "error union type " { | ||
| 79 | try testErrorUnionType(); | ||
| 80 | comptime try testErrorUnionType(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn testErrorUnionType() !void { | ||
| 84 | const x: anyerror!i32 = 1234; | ||
| 85 | if (x) |value| try expect(value == 1234) else |_| unreachable; | ||
| 86 | try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); | ||
| 87 | try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet); | ||
| 88 | try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror); | ||
| 89 | } | ||
| 90 | |||
| 91 | test "error set type" { | ||
| 92 | try testErrorSetType(); | ||
| 93 | comptime try testErrorSetType(); | ||
| 94 | } | ||
| 95 | |||
| 96 | const MyErrSet = error{ | ||
| 97 | OutOfMemory, | ||
| 98 | FileNotFound, | ||
| 99 | }; | ||
| 100 | |||
| 101 | fn testErrorSetType() !void { | ||
| 102 | try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2); | ||
| 103 | |||
| 104 | const a: MyErrSet!i32 = 5678; | ||
| 105 | const b: MyErrSet!i32 = MyErrSet.OutOfMemory; | ||
| 106 | |||
| 107 | if (a) |value| try expect(value == 5678) else |err| switch (err) { | ||
| 108 | error.OutOfMemory => unreachable, | ||
| 109 | error.FileNotFound => unreachable, | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | test "explicit error set cast" { | ||
| 114 | try testExplicitErrorSetCast(Set1.A); | ||
| 115 | comptime try testExplicitErrorSetCast(Set1.A); | ||
| 116 | } | ||
| 117 | |||
| 118 | const Set1 = error{ | ||
| 119 | A, | ||
| 120 | B, | ||
| 121 | }; | ||
| 122 | const Set2 = error{ | ||
| 123 | A, | ||
| 124 | C, | ||
| 125 | }; | ||
| 126 | |||
| 127 | fn testExplicitErrorSetCast(set1: Set1) !void { | ||
| 128 | var x = @errSetCast(Set2, set1); | ||
| 129 | var y = @errSetCast(Set1, x); | ||
| 130 | try expect(y == error.A); | ||
| 131 | } | ||
| 132 | |||
| 133 | test "comptime test error for empty error set" { | ||
| 134 | try testComptimeTestErrorEmptySet(1234); | ||
| 135 | comptime try testComptimeTestErrorEmptySet(1234); | ||
| 136 | } | ||
| 137 | |||
| 138 | const EmptyErrorSet = error{}; | ||
| 139 | |||
| 140 | fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void { | ||
| 141 | if (x) |v| try expect(v == 1234) else |err| @compileError("bad"); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "syntax: optional operator in front of error union operator" { | ||
| 145 | comptime { | ||
| 146 | try expect(?(anyerror!i32) == ?(anyerror!i32)); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | test "comptime err to int of error set with only 1 possible value" { | ||
| 151 | testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 152 | comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); | ||
| 153 | } | ||
| 154 | fn testErrToIntWithOnePossibleValue( | ||
| 155 | x: error{A}, | ||
| 156 | comptime value: u32, | ||
| 157 | ) void { | ||
| 158 | if (@errorToInt(x) != value) { | ||
| 159 | @compileError("bad"); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | test "empty error union" { | ||
| 164 | const x = error{} || error{}; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "error union peer type resolution" { | ||
| 168 | try testErrorUnionPeerTypeResolution(1); | ||
| 169 | } | ||
| 170 | |||
| 171 | fn testErrorUnionPeerTypeResolution(x: i32) !void { | ||
| 172 | const y = switch (x) { | ||
| 173 | 1 => bar_1(), | ||
| 174 | 2 => baz_1(), | ||
| 175 | else => quux_1(), | ||
| 176 | }; | ||
| 177 | if (y) |_| { | ||
| 178 | @panic("expected error"); | ||
| 179 | } else |e| { | ||
| 180 | try expect(e == error.A); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | fn bar_1() anyerror { | ||
| 185 | return error.A; | ||
| 186 | } | ||
| 187 | |||
| 188 | fn baz_1() !i32 { | ||
| 189 | return error.B; | ||
| 190 | } | ||
| 191 | |||
| 192 | fn quux_1() !i32 { | ||
| 193 | return error.C; | ||
| 194 | } | ||
| 195 | |||
| 196 | test "error: fn returning empty error set can be passed as fn returning any error" { | ||
| 197 | entry(); | ||
| 198 | comptime entry(); | ||
| 199 | } | ||
| 200 | |||
| 201 | fn entry() void { | ||
| 202 | foo2(bar2); | ||
| 203 | } | ||
| 204 | |||
| 205 | fn foo2(f: fn () anyerror!void) void { | ||
| 206 | const x = f(); | ||
| 207 | } | ||
| 208 | |||
| 209 | fn bar2() (error{}!void) {} | ||
| 210 | |||
| 211 | test "error: Zero sized error set returned with value payload crash" { | ||
| 212 | _ = foo3(0) catch {}; | ||
| 213 | _ = comptime foo3(0) catch {}; | ||
| 214 | } | ||
| 215 | |||
| 216 | const Error = error{}; | ||
| 217 | fn foo3(b: usize) Error!usize { | ||
| 218 | return b; | ||
| 219 | } | ||
| 220 | |||
| 221 | test "error: Infer error set from literals" { | ||
| 222 | _ = nullLiteral("n") catch |err| handleErrors(err); | ||
| 223 | _ = floatLiteral("n") catch |err| handleErrors(err); | ||
| 224 | _ = intLiteral("n") catch |err| handleErrors(err); | ||
| 225 | _ = comptime nullLiteral("n") catch |err| handleErrors(err); | ||
| 226 | _ = comptime floatLiteral("n") catch |err| handleErrors(err); | ||
| 227 | _ = comptime intLiteral("n") catch |err| handleErrors(err); | ||
| 228 | } | ||
| 229 | |||
| 230 | fn handleErrors(err: anytype) noreturn { | ||
| 231 | switch (err) { | ||
| 232 | error.T => {}, | ||
| 233 | } | ||
| 234 | |||
| 235 | unreachable; | ||
| 236 | } | ||
| 237 | |||
| 238 | fn nullLiteral(str: []const u8) !?i64 { | ||
| 239 | if (str[0] == 'n') return null; | ||
| 240 | |||
| 241 | return error.T; | ||
| 242 | } | ||
| 243 | |||
| 244 | fn floatLiteral(str: []const u8) !?f64 { | ||
| 245 | if (str[0] == 'n') return 1.0; | ||
| 246 | |||
| 247 | return error.T; | ||
| 248 | } | ||
| 249 | |||
| 250 | fn intLiteral(str: []const u8) !?i64 { | ||
| 251 | if (str[0] == 'n') return 1; | ||
| 252 | |||
| 253 | return error.T; | ||
| 254 | } | ||
| 255 | |||
| 256 | test "nested error union function call in optional unwrap" { | ||
| 257 | const S = struct { | ||
| 258 | const Foo = struct { | ||
| 259 | a: i32, | ||
| 260 | }; | ||
| 261 | |||
| 262 | fn errorable() !i32 { | ||
| 263 | var x: Foo = (try getFoo()) orelse return error.Other; | ||
| 264 | return x.a; | ||
| 265 | } | ||
| 266 | |||
| 267 | fn errorable2() !i32 { | ||
| 268 | var x: Foo = (try getFoo2()) orelse return error.Other; | ||
| 269 | return x.a; | ||
| 270 | } | ||
| 271 | |||
| 272 | fn errorable3() !i32 { | ||
| 273 | var x: Foo = (try getFoo3()) orelse return error.Other; | ||
| 274 | return x.a; | ||
| 275 | } | ||
| 276 | |||
| 277 | fn getFoo() anyerror!?Foo { | ||
| 278 | return Foo{ .a = 1234 }; | ||
| 279 | } | ||
| 280 | |||
| 281 | fn getFoo2() anyerror!?Foo { | ||
| 282 | return error.Failure; | ||
| 283 | } | ||
| 284 | |||
| 285 | fn getFoo3() anyerror!?Foo { | ||
| 286 | return null; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | try expect((try S.errorable()) == 1234); | ||
| 290 | try expectError(error.Failure, S.errorable2()); | ||
| 291 | try expectError(error.Other, S.errorable3()); | ||
| 292 | comptime { | ||
| 293 | try expect((try S.errorable()) == 1234); | ||
| 294 | try expectError(error.Failure, S.errorable2()); | ||
| 295 | try expectError(error.Other, S.errorable3()); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | test "widen cast integer payload of error union function call" { | ||
| 300 | const S = struct { | ||
| 301 | fn errorable() !u64 { | ||
| 302 | var x = @as(u64, try number()); | ||
| 303 | return x; | ||
| 304 | } | ||
| 305 | |||
| 306 | fn number() anyerror!u32 { | ||
| 307 | return 1234; | ||
| 308 | } | ||
| 309 | }; | ||
| 310 | try expect((try S.errorable()) == 1234); | ||
| 311 | } | ||
| 312 | |||
| 313 | test "return function call to error set from error union function" { | ||
| 314 | const S = struct { | ||
| 315 | fn errorable() anyerror!i32 { | ||
| 316 | return fail(); | ||
| 317 | } | ||
| 318 | |||
| 319 | fn fail() anyerror { | ||
| 320 | return error.Failure; | ||
| 321 | } | ||
| 322 | }; | ||
| 323 | try expectError(error.Failure, S.errorable()); | ||
| 324 | comptime try expectError(error.Failure, S.errorable()); | ||
| 325 | } | ||
| 326 | |||
| 327 | test "optional error set is the same size as error set" { | ||
| 328 | comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); | ||
| 329 | const S = struct { | ||
| 330 | fn returnsOptErrSet() ?anyerror { | ||
| 331 | return null; | ||
| 332 | } | ||
| 333 | }; | ||
| 334 | try expect(S.returnsOptErrSet() == null); | ||
| 335 | comptime try expect(S.returnsOptErrSet() == null); | ||
| 336 | } | ||
| 337 | |||
| 338 | test "debug info for optional error set" { | ||
| 339 | const SomeError = error{Hello}; | ||
| 340 | var a_local_variable: ?SomeError = null; | ||
| 341 | } | ||
| 342 | |||
| 343 | test "nested catch" { | ||
| 344 | const S = struct { | ||
| 345 | fn entry() !void { | ||
| 346 | try expectError(error.Bad, func()); | ||
| 347 | } | ||
| 348 | fn fail() anyerror!Foo { | ||
| 349 | return error.Wrong; | ||
| 350 | } | ||
| 351 | fn func() anyerror!Foo { | ||
| 352 | const x = fail() catch | ||
| 353 | fail() catch | ||
| 354 | return error.Bad; | ||
| 355 | unreachable; | ||
| 356 | } | ||
| 357 | const Foo = struct { | ||
| 358 | field: i32, | ||
| 359 | }; | ||
| 360 | }; | ||
| 361 | try S.entry(); | ||
| 362 | comptime try S.entry(); | ||
| 363 | } | ||
| 364 | |||
| 365 | test "implicit cast to optional to error union to return result loc" { | ||
| 366 | const S = struct { | ||
| 367 | fn entry() !void { | ||
| 368 | var x: Foo = undefined; | ||
| 369 | if (func(&x)) |opt| { | ||
| 370 | try expect(opt != null); | ||
| 371 | } else |_| @panic("expected non error"); | ||
| 372 | } | ||
| 373 | fn func(f: *Foo) anyerror!?*Foo { | ||
| 374 | return f; | ||
| 375 | } | ||
| 376 | const Foo = struct { | ||
| 377 | field: i32, | ||
| 378 | }; | ||
| 379 | }; | ||
| 380 | try S.entry(); | ||
| 381 | //comptime S.entry(); TODO | ||
| 382 | } | ||
| 383 | |||
| 384 | test "function pointer with return type that is error union with payload which is pointer of parent struct" { | ||
| 385 | const S = struct { | ||
| 386 | const Foo = struct { | ||
| 387 | fun: fn (a: i32) (anyerror!*Foo), | ||
| 388 | }; | ||
| 389 | |||
| 390 | const Err = error{UnspecifiedErr}; | ||
| 391 | |||
| 392 | fn bar(a: i32) anyerror!*Foo { | ||
| 393 | return Err.UnspecifiedErr; | ||
| 394 | } | ||
| 395 | |||
| 396 | fn doTheTest() !void { | ||
| 397 | var x = Foo{ .fun = bar }; | ||
| 398 | try expectError(error.UnspecifiedErr, x.fun(1)); | ||
| 399 | } | ||
| 400 | }; | ||
| 401 | try S.doTheTest(); | ||
| 402 | } | ||
| 403 | |||
| 404 | test "return result loc as peer result loc in inferred error set function" { | ||
| 405 | const S = struct { | ||
| 406 | fn doTheTest() !void { | ||
| 407 | if (foo(2)) |x| { | ||
| 408 | try expect(x.Two); | ||
| 409 | } else |e| switch (e) { | ||
| 410 | error.Whatever => @panic("fail"), | ||
| 411 | } | ||
| 412 | try expectError(error.Whatever, foo(99)); | ||
| 413 | } | ||
| 414 | const FormValue = union(enum) { | ||
| 415 | One: void, | ||
| 416 | Two: bool, | ||
| 417 | }; | ||
| 418 | |||
| 419 | fn foo(id: u64) !FormValue { | ||
| 420 | return switch (id) { | ||
| 421 | 2 => FormValue{ .Two = true }, | ||
| 422 | 1 => FormValue{ .One = {} }, | ||
| 423 | else => return error.Whatever, | ||
| 424 | }; | ||
| 425 | } | ||
| 426 | }; | ||
| 427 | try S.doTheTest(); | ||
| 428 | comptime try S.doTheTest(); | ||
| 429 | } | ||
| 430 | |||
| 431 | test "error payload type is correctly resolved" { | ||
| 432 | const MyIntWrapper = struct { | ||
| 433 | const Self = @This(); | ||
| 434 | |||
| 435 | x: i32, | ||
| 436 | |||
| 437 | pub fn create() anyerror!Self { | ||
| 438 | return Self{ .x = 42 }; | ||
| 439 | } | ||
| 440 | }; | ||
| 441 | |||
| 442 | try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create()); | ||
| 443 | } | ||
| 444 | |||
| 445 | test "error union comptime caching" { | ||
| 446 | const S = struct { | ||
| 447 | fn foo(comptime arg: anytype) void {} | ||
| 448 | }; | ||
| 449 | |||
| 450 | S.foo(@as(anyerror!void, {})); | ||
| 451 | S.foo(@as(anyerror!void, {})); | ||
| 452 | } | ||
test/stage1/behavior/eval.zig deleted-833| ... | @@ -1,833 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const builtin = @import("builtin"); | ||
| 5 | |||
| 6 | test "compile time recursion" { | ||
| 7 | try expect(some_data.len == 21); | ||
| 8 | } | ||
| 9 | var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; | ||
| 10 | fn fibonacci(x: i32) i32 { | ||
| 11 | if (x <= 1) return 1; | ||
| 12 | return fibonacci(x - 1) + fibonacci(x - 2); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn unwrapAndAddOne(blah: ?i32) i32 { | ||
| 16 | return blah.? + 1; | ||
| 17 | } | ||
| 18 | const should_be_1235 = unwrapAndAddOne(1234); | ||
| 19 | test "static add one" { | ||
| 20 | try expect(should_be_1235 == 1235); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "inlined loop" { | ||
| 24 | comptime var i = 0; | ||
| 25 | comptime var sum = 0; | ||
| 26 | inline while (i <= 5) : (i += 1) | ||
| 27 | sum += i; | ||
| 28 | try expect(sum == 15); | ||
| 29 | } | ||
| 30 | |||
| 31 | fn gimme1or2(comptime a: bool) i32 { | ||
| 32 | const x: i32 = 1; | ||
| 33 | const y: i32 = 2; | ||
| 34 | comptime var z: i32 = if (a) x else y; | ||
| 35 | return z; | ||
| 36 | } | ||
| 37 | test "inline variable gets result of const if" { | ||
| 38 | try expect(gimme1or2(true) == 1); | ||
| 39 | try expect(gimme1or2(false) == 2); | ||
| 40 | } | ||
| 41 | |||
| 42 | test "static function evaluation" { | ||
| 43 | try expect(statically_added_number == 3); | ||
| 44 | } | ||
| 45 | const statically_added_number = staticAdd(1, 2); | ||
| 46 | fn staticAdd(a: i32, b: i32) i32 { | ||
| 47 | return a + b; | ||
| 48 | } | ||
| 49 | |||
| 50 | test "const expr eval on single expr blocks" { | ||
| 51 | try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 52 | comptime try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { | ||
| 56 | const literal = 3; | ||
| 57 | |||
| 58 | const result = if (b) b: { | ||
| 59 | break :b literal; | ||
| 60 | } else b: { | ||
| 61 | break :b x; | ||
| 62 | }; | ||
| 63 | |||
| 64 | return result; | ||
| 65 | } | ||
| 66 | |||
| 67 | test "statically initialized list" { | ||
| 68 | try expect(static_point_list[0].x == 1); | ||
| 69 | try expect(static_point_list[0].y == 2); | ||
| 70 | try expect(static_point_list[1].x == 3); | ||
| 71 | try expect(static_point_list[1].y == 4); | ||
| 72 | } | ||
| 73 | const Point = struct { | ||
| 74 | x: i32, | ||
| 75 | y: i32, | ||
| 76 | }; | ||
| 77 | const static_point_list = [_]Point{ | ||
| 78 | makePoint(1, 2), | ||
| 79 | makePoint(3, 4), | ||
| 80 | }; | ||
| 81 | fn makePoint(x: i32, y: i32) Point { | ||
| 82 | return Point{ | ||
| 83 | .x = x, | ||
| 84 | .y = y, | ||
| 85 | }; | ||
| 86 | } | ||
| 87 | |||
| 88 | test "static eval list init" { | ||
| 89 | try expect(static_vec3.data[2] == 1.0); | ||
| 90 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | ||
| 91 | } | ||
| 92 | const static_vec3 = vec3(0.0, 0.0, 1.0); | ||
| 93 | pub const Vec3 = struct { | ||
| 94 | data: [3]f32, | ||
| 95 | }; | ||
| 96 | pub fn vec3(x: f32, y: f32, z: f32) Vec3 { | ||
| 97 | return Vec3{ | ||
| 98 | .data = [_]f32{ | ||
| 99 | x, | ||
| 100 | y, | ||
| 101 | z, | ||
| 102 | }, | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | test "constant expressions" { | ||
| 107 | var array: [array_size]u8 = undefined; | ||
| 108 | try expect(@sizeOf(@TypeOf(array)) == 20); | ||
| 109 | } | ||
| 110 | const array_size: u8 = 20; | ||
| 111 | |||
| 112 | test "constant struct with negation" { | ||
| 113 | try expect(vertices[0].x == -0.6); | ||
| 114 | } | ||
| 115 | const Vertex = struct { | ||
| 116 | x: f32, | ||
| 117 | y: f32, | ||
| 118 | r: f32, | ||
| 119 | g: f32, | ||
| 120 | b: f32, | ||
| 121 | }; | ||
| 122 | const vertices = [_]Vertex{ | ||
| 123 | Vertex{ | ||
| 124 | .x = -0.6, | ||
| 125 | .y = -0.4, | ||
| 126 | .r = 1.0, | ||
| 127 | .g = 0.0, | ||
| 128 | .b = 0.0, | ||
| 129 | }, | ||
| 130 | Vertex{ | ||
| 131 | .x = 0.6, | ||
| 132 | .y = -0.4, | ||
| 133 | .r = 0.0, | ||
| 134 | .g = 1.0, | ||
| 135 | .b = 0.0, | ||
| 136 | }, | ||
| 137 | Vertex{ | ||
| 138 | .x = 0.0, | ||
| 139 | .y = 0.6, | ||
| 140 | .r = 0.0, | ||
| 141 | .g = 0.0, | ||
| 142 | .b = 1.0, | ||
| 143 | }, | ||
| 144 | }; | ||
| 145 | |||
| 146 | test "statically initialized struct" { | ||
| 147 | st_init_str_foo.x += 1; | ||
| 148 | try expect(st_init_str_foo.x == 14); | ||
| 149 | } | ||
| 150 | const StInitStrFoo = struct { | ||
| 151 | x: i32, | ||
| 152 | y: bool, | ||
| 153 | }; | ||
| 154 | var st_init_str_foo = StInitStrFoo{ | ||
| 155 | .x = 13, | ||
| 156 | .y = true, | ||
| 157 | }; | ||
| 158 | |||
| 159 | test "statically initalized array literal" { | ||
| 160 | const y: [4]u8 = st_init_arr_lit_x; | ||
| 161 | try expect(y[3] == 4); | ||
| 162 | } | ||
| 163 | const st_init_arr_lit_x = [_]u8{ | ||
| 164 | 1, | ||
| 165 | 2, | ||
| 166 | 3, | ||
| 167 | 4, | ||
| 168 | }; | ||
| 169 | |||
| 170 | test "const slice" { | ||
| 171 | comptime { | ||
| 172 | const a = "1234567890"; | ||
| 173 | try expect(a.len == 10); | ||
| 174 | const b = a[1..2]; | ||
| 175 | try expect(b.len == 1); | ||
| 176 | try expect(b[0] == '2'); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | test "try to trick eval with runtime if" { | ||
| 181 | try expect(testTryToTrickEvalWithRuntimeIf(true) == 10); | ||
| 182 | } | ||
| 183 | |||
| 184 | fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { | ||
| 185 | comptime var i: usize = 0; | ||
| 186 | inline while (i < 10) : (i += 1) { | ||
| 187 | const result = if (b) false else true; | ||
| 188 | } | ||
| 189 | comptime { | ||
| 190 | return i; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { | ||
| 195 | var runtime = [1]i32{3}; | ||
| 196 | comptime var i: usize = 0; | ||
| 197 | inline while (i < 2) : (i += 1) { | ||
| 198 | const result = if (i == 0) [1]i32{2} else runtime; | ||
| 199 | } | ||
| 200 | comptime { | ||
| 201 | try expect(i == 2); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | fn max(comptime T: type, a: T, b: T) T { | ||
| 206 | if (T == bool) { | ||
| 207 | return a or b; | ||
| 208 | } else if (a > b) { | ||
| 209 | return a; | ||
| 210 | } else { | ||
| 211 | return b; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | fn letsTryToCompareBools(a: bool, b: bool) bool { | ||
| 215 | return max(bool, a, b); | ||
| 216 | } | ||
| 217 | test "inlined block and runtime block phi" { | ||
| 218 | try expect(letsTryToCompareBools(true, true)); | ||
| 219 | try expect(letsTryToCompareBools(true, false)); | ||
| 220 | try expect(letsTryToCompareBools(false, true)); | ||
| 221 | try expect(!letsTryToCompareBools(false, false)); | ||
| 222 | |||
| 223 | comptime { | ||
| 224 | try expect(letsTryToCompareBools(true, true)); | ||
| 225 | try expect(letsTryToCompareBools(true, false)); | ||
| 226 | try expect(letsTryToCompareBools(false, true)); | ||
| 227 | try expect(!letsTryToCompareBools(false, false)); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | const CmdFn = struct { | ||
| 232 | name: []const u8, | ||
| 233 | func: fn (i32) i32, | ||
| 234 | }; | ||
| 235 | |||
| 236 | const cmd_fns = [_]CmdFn{ | ||
| 237 | CmdFn{ | ||
| 238 | .name = "one", | ||
| 239 | .func = one, | ||
| 240 | }, | ||
| 241 | CmdFn{ | ||
| 242 | .name = "two", | ||
| 243 | .func = two, | ||
| 244 | }, | ||
| 245 | CmdFn{ | ||
| 246 | .name = "three", | ||
| 247 | .func = three, | ||
| 248 | }, | ||
| 249 | }; | ||
| 250 | fn one(value: i32) i32 { | ||
| 251 | return value + 1; | ||
| 252 | } | ||
| 253 | fn two(value: i32) i32 { | ||
| 254 | return value + 2; | ||
| 255 | } | ||
| 256 | fn three(value: i32) i32 { | ||
| 257 | return value + 3; | ||
| 258 | } | ||
| 259 | |||
| 260 | fn performFn(comptime prefix_char: u8, start_value: i32) i32 { | ||
| 261 | var result: i32 = start_value; | ||
| 262 | comptime var i = 0; | ||
| 263 | inline while (i < cmd_fns.len) : (i += 1) { | ||
| 264 | if (cmd_fns[i].name[0] == prefix_char) { | ||
| 265 | result = cmd_fns[i].func(result); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | return result; | ||
| 269 | } | ||
| 270 | |||
| 271 | test "comptime iterate over fn ptr list" { | ||
| 272 | try expect(performFn('t', 1) == 6); | ||
| 273 | try expect(performFn('o', 0) == 1); | ||
| 274 | try expect(performFn('w', 99) == 99); | ||
| 275 | } | ||
| 276 | |||
| 277 | test "eval @setRuntimeSafety at compile-time" { | ||
| 278 | const result = comptime fnWithSetRuntimeSafety(); | ||
| 279 | try expect(result == 1234); | ||
| 280 | } | ||
| 281 | |||
| 282 | fn fnWithSetRuntimeSafety() i32 { | ||
| 283 | @setRuntimeSafety(true); | ||
| 284 | return 1234; | ||
| 285 | } | ||
| 286 | |||
| 287 | test "eval @setFloatMode at compile-time" { | ||
| 288 | const result = comptime fnWithFloatMode(); | ||
| 289 | try expect(result == 1234.0); | ||
| 290 | } | ||
| 291 | |||
| 292 | fn fnWithFloatMode() f32 { | ||
| 293 | @setFloatMode(builtin.FloatMode.Strict); | ||
| 294 | return 1234.0; | ||
| 295 | } | ||
| 296 | |||
| 297 | const SimpleStruct = struct { | ||
| 298 | field: i32, | ||
| 299 | |||
| 300 | fn method(self: *const SimpleStruct) i32 { | ||
| 301 | return self.field + 3; | ||
| 302 | } | ||
| 303 | }; | ||
| 304 | |||
| 305 | var simple_struct = SimpleStruct{ .field = 1234 }; | ||
| 306 | |||
| 307 | const bound_fn = simple_struct.method; | ||
| 308 | |||
| 309 | test "call method on bound fn referring to var instance" { | ||
| 310 | try expect(bound_fn() == 1237); | ||
| 311 | } | ||
| 312 | |||
| 313 | test "ptr to local array argument at comptime" { | ||
| 314 | comptime { | ||
| 315 | var bytes: [10]u8 = undefined; | ||
| 316 | modifySomeBytes(bytes[0..]); | ||
| 317 | try expect(bytes[0] == 'a'); | ||
| 318 | try expect(bytes[9] == 'b'); | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | fn modifySomeBytes(bytes: []u8) void { | ||
| 323 | bytes[0] = 'a'; | ||
| 324 | bytes[9] = 'b'; | ||
| 325 | } | ||
| 326 | |||
| 327 | test "comparisons 0 <= uint and 0 > uint should be comptime" { | ||
| 328 | testCompTimeUIntComparisons(1234); | ||
| 329 | } | ||
| 330 | fn testCompTimeUIntComparisons(x: u32) void { | ||
| 331 | if (!(0 <= x)) { | ||
| 332 | @compileError("this condition should be comptime known"); | ||
| 333 | } | ||
| 334 | if (0 > x) { | ||
| 335 | @compileError("this condition should be comptime known"); | ||
| 336 | } | ||
| 337 | if (!(x >= 0)) { | ||
| 338 | @compileError("this condition should be comptime known"); | ||
| 339 | } | ||
| 340 | if (x < 0) { | ||
| 341 | @compileError("this condition should be comptime known"); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | test "const ptr to variable data changes at runtime" { | ||
| 346 | try expect(foo_ref.name[0] == 'a'); | ||
| 347 | foo_ref.name = "b"; | ||
| 348 | try expect(foo_ref.name[0] == 'b'); | ||
| 349 | } | ||
| 350 | |||
| 351 | const Foo = struct { | ||
| 352 | name: []const u8, | ||
| 353 | }; | ||
| 354 | |||
| 355 | var foo_contents = Foo{ .name = "a" }; | ||
| 356 | const foo_ref = &foo_contents; | ||
| 357 | |||
| 358 | test "create global array with for loop" { | ||
| 359 | try expect(global_array[5] == 5 * 5); | ||
| 360 | try expect(global_array[9] == 9 * 9); | ||
| 361 | } | ||
| 362 | |||
| 363 | const global_array = x: { | ||
| 364 | var result: [10]usize = undefined; | ||
| 365 | for (result) |*item, index| { | ||
| 366 | item.* = index * index; | ||
| 367 | } | ||
| 368 | break :x result; | ||
| 369 | }; | ||
| 370 | |||
| 371 | test "compile-time downcast when the bits fit" { | ||
| 372 | comptime { | ||
| 373 | const spartan_count: u16 = 255; | ||
| 374 | const byte = @intCast(u8, spartan_count); | ||
| 375 | try expect(byte == 255); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | const hi1 = "hi"; | ||
| 380 | const hi2 = hi1; | ||
| 381 | test "const global shares pointer with other same one" { | ||
| 382 | try assertEqualPtrs(&hi1[0], &hi2[0]); | ||
| 383 | comptime try expect(&hi1[0] == &hi2[0]); | ||
| 384 | } | ||
| 385 | fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { | ||
| 386 | try expect(ptr1 == ptr2); | ||
| 387 | } | ||
| 388 | |||
| 389 | test "@setEvalBranchQuota" { | ||
| 390 | comptime { | ||
| 391 | // 1001 for the loop and then 1 more for the expect fn call | ||
| 392 | @setEvalBranchQuota(1002); | ||
| 393 | var i = 0; | ||
| 394 | var sum = 0; | ||
| 395 | while (i < 1001) : (i += 1) { | ||
| 396 | sum += i; | ||
| 397 | } | ||
| 398 | try expect(sum == 500500); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | test "float literal at compile time not lossy" { | ||
| 403 | try expect(16777216.0 + 1.0 == 16777217.0); | ||
| 404 | try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); | ||
| 405 | } | ||
| 406 | |||
| 407 | test "f32 at compile time is lossy" { | ||
| 408 | try expect(@as(f32, 1 << 24) + 1 == 1 << 24); | ||
| 409 | } | ||
| 410 | |||
| 411 | test "f64 at compile time is lossy" { | ||
| 412 | try expect(@as(f64, 1 << 53) + 1 == 1 << 53); | ||
| 413 | } | ||
| 414 | |||
| 415 | test "f128 at compile time is lossy" { | ||
| 416 | try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); | ||
| 417 | } | ||
| 418 | |||
| 419 | comptime { | ||
| 420 | try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192); | ||
| 421 | } | ||
| 422 | |||
| 423 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { | ||
| 424 | return struct { | ||
| 425 | pub const Node = struct {}; | ||
| 426 | }; | ||
| 427 | } | ||
| 428 | |||
| 429 | test "string literal used as comptime slice is memoized" { | ||
| 430 | const a = "link"; | ||
| 431 | const b = "link"; | ||
| 432 | comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | ||
| 433 | comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | ||
| 434 | } | ||
| 435 | |||
| 436 | test "comptime slice of undefined pointer of length 0" { | ||
| 437 | const slice1 = @as([*]i32, undefined)[0..0]; | ||
| 438 | try expect(slice1.len == 0); | ||
| 439 | const slice2 = @as([*]i32, undefined)[100..100]; | ||
| 440 | try expect(slice2.len == 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | fn copyWithPartialInline(s: []u32, b: []u8) void { | ||
| 444 | comptime var i: usize = 0; | ||
| 445 | inline while (i < 4) : (i += 1) { | ||
| 446 | s[i] = 0; | ||
| 447 | s[i] |= @as(u32, b[i * 4 + 0]) << 24; | ||
| 448 | s[i] |= @as(u32, b[i * 4 + 1]) << 16; | ||
| 449 | s[i] |= @as(u32, b[i * 4 + 2]) << 8; | ||
| 450 | s[i] |= @as(u32, b[i * 4 + 3]) << 0; | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | test "binary math operator in partially inlined function" { | ||
| 455 | var s: [4]u32 = undefined; | ||
| 456 | var b: [16]u8 = undefined; | ||
| 457 | |||
| 458 | for (b) |*r, i| | ||
| 459 | r.* = @intCast(u8, i + 1); | ||
| 460 | |||
| 461 | copyWithPartialInline(s[0..], b[0..]); | ||
| 462 | try expect(s[0] == 0x1020304); | ||
| 463 | try expect(s[1] == 0x5060708); | ||
| 464 | try expect(s[2] == 0x90a0b0c); | ||
| 465 | try expect(s[3] == 0xd0e0f10); | ||
| 466 | } | ||
| 467 | |||
| 468 | test "comptime function with the same args is memoized" { | ||
| 469 | comptime { | ||
| 470 | try expect(MakeType(i32) == MakeType(i32)); | ||
| 471 | try expect(MakeType(i32) != MakeType(f64)); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | fn MakeType(comptime T: type) type { | ||
| 476 | return struct { | ||
| 477 | field: T, | ||
| 478 | }; | ||
| 479 | } | ||
| 480 | |||
| 481 | test "comptime function with mutable pointer is not memoized" { | ||
| 482 | comptime { | ||
| 483 | var x: i32 = 1; | ||
| 484 | const ptr = &x; | ||
| 485 | increment(ptr); | ||
| 486 | increment(ptr); | ||
| 487 | try expect(x == 3); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | fn increment(value: *i32) void { | ||
| 492 | value.* += 1; | ||
| 493 | } | ||
| 494 | |||
| 495 | fn generateTable(comptime T: type) [1010]T { | ||
| 496 | var res: [1010]T = undefined; | ||
| 497 | var i: usize = 0; | ||
| 498 | while (i < 1010) : (i += 1) { | ||
| 499 | res[i] = @intCast(T, i); | ||
| 500 | } | ||
| 501 | return res; | ||
| 502 | } | ||
| 503 | |||
| 504 | fn doesAlotT(comptime T: type, value: usize) T { | ||
| 505 | @setEvalBranchQuota(5000); | ||
| 506 | const table = comptime blk: { | ||
| 507 | break :blk generateTable(T); | ||
| 508 | }; | ||
| 509 | return table[value]; | ||
| 510 | } | ||
| 511 | |||
| 512 | test "@setEvalBranchQuota at same scope as generic function call" { | ||
| 513 | try expect(doesAlotT(u32, 2) == 2); | ||
| 514 | } | ||
| 515 | |||
| 516 | test "comptime slice of slice preserves comptime var" { | ||
| 517 | comptime { | ||
| 518 | var buff: [10]u8 = undefined; | ||
| 519 | buff[0..][0..][0] = 1; | ||
| 520 | try expect(buff[0..][0..][0] == 1); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | test "comptime slice of pointer preserves comptime var" { | ||
| 525 | comptime { | ||
| 526 | var buff: [10]u8 = undefined; | ||
| 527 | var a = @ptrCast([*]u8, &buff); | ||
| 528 | a[0..1][0] = 1; | ||
| 529 | try expect(buff[0..][0..][0] == 1); | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | const SingleFieldStruct = struct { | ||
| 534 | x: i32, | ||
| 535 | |||
| 536 | fn read_x(self: *const SingleFieldStruct) i32 { | ||
| 537 | return self.x; | ||
| 538 | } | ||
| 539 | }; | ||
| 540 | test "const ptr to comptime mutable data is not memoized" { | ||
| 541 | comptime { | ||
| 542 | var foo = SingleFieldStruct{ .x = 1 }; | ||
| 543 | try expect(foo.read_x() == 1); | ||
| 544 | foo.x = 2; | ||
| 545 | try expect(foo.read_x() == 2); | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | test "array concat of slices gives slice" { | ||
| 550 | comptime { | ||
| 551 | var a: []const u8 = "aoeu"; | ||
| 552 | var b: []const u8 = "asdf"; | ||
| 553 | const c = a ++ b; | ||
| 554 | try expect(std.mem.eql(u8, c, "aoeuasdf")); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | test "comptime shlWithOverflow" { | ||
| 559 | const ct_shifted: u64 = comptime amt: { | ||
| 560 | var amt = @as(u64, 0); | ||
| 561 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | ||
| 562 | break :amt amt; | ||
| 563 | }; | ||
| 564 | |||
| 565 | const rt_shifted: u64 = amt: { | ||
| 566 | var amt = @as(u64, 0); | ||
| 567 | _ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt); | ||
| 568 | break :amt amt; | ||
| 569 | }; | ||
| 570 | |||
| 571 | try expect(ct_shifted == rt_shifted); | ||
| 572 | } | ||
| 573 | |||
| 574 | test "runtime 128 bit integer division" { | ||
| 575 | var a: u128 = 152313999999999991610955792383; | ||
| 576 | var b: u128 = 10000000000000000000; | ||
| 577 | var c = a / b; | ||
| 578 | try expect(c == 15231399999); | ||
| 579 | } | ||
| 580 | |||
| 581 | pub const Info = struct { | ||
| 582 | version: u8, | ||
| 583 | }; | ||
| 584 | |||
| 585 | pub const diamond_info = Info{ .version = 0 }; | ||
| 586 | |||
| 587 | test "comptime modification of const struct field" { | ||
| 588 | comptime { | ||
| 589 | var res = diamond_info; | ||
| 590 | res.version = 1; | ||
| 591 | try expect(diamond_info.version == 0); | ||
| 592 | try expect(res.version == 1); | ||
| 593 | } | ||
| 594 | } | ||
| 595 | |||
| 596 | test "pointer to type" { | ||
| 597 | comptime { | ||
| 598 | var T: type = i32; | ||
| 599 | try expect(T == i32); | ||
| 600 | var ptr = &T; | ||
| 601 | try expect(@TypeOf(ptr) == *type); | ||
| 602 | ptr.* = f32; | ||
| 603 | try expect(T == f32); | ||
| 604 | try expect(*T == *f32); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | test "slice of type" { | ||
| 609 | comptime { | ||
| 610 | var types_array = [_]type{ i32, f64, type }; | ||
| 611 | for (types_array) |T, i| { | ||
| 612 | switch (i) { | ||
| 613 | 0 => try expect(T == i32), | ||
| 614 | 1 => try expect(T == f64), | ||
| 615 | 2 => try expect(T == type), | ||
| 616 | else => unreachable, | ||
| 617 | } | ||
| 618 | } | ||
| 619 | for (types_array[0..]) |T, i| { | ||
| 620 | switch (i) { | ||
| 621 | 0 => try expect(T == i32), | ||
| 622 | 1 => try expect(T == f64), | ||
| 623 | 2 => try expect(T == type), | ||
| 624 | else => unreachable, | ||
| 625 | } | ||
| 626 | } | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | const Wrapper = struct { | ||
| 631 | T: type, | ||
| 632 | }; | ||
| 633 | |||
| 634 | fn wrap(comptime T: type) Wrapper { | ||
| 635 | return Wrapper{ .T = T }; | ||
| 636 | } | ||
| 637 | |||
| 638 | test "function which returns struct with type field causes implicit comptime" { | ||
| 639 | const ty = wrap(i32).T; | ||
| 640 | try expect(ty == i32); | ||
| 641 | } | ||
| 642 | |||
| 643 | test "call method with comptime pass-by-non-copying-value self parameter" { | ||
| 644 | const S = struct { | ||
| 645 | a: u8, | ||
| 646 | |||
| 647 | fn b(comptime s: @This()) u8 { | ||
| 648 | return s.a; | ||
| 649 | } | ||
| 650 | }; | ||
| 651 | |||
| 652 | const s = S{ .a = 2 }; | ||
| 653 | var b = s.b(); | ||
| 654 | try expect(b == 2); | ||
| 655 | } | ||
| 656 | |||
| 657 | test "@tagName of @typeInfo" { | ||
| 658 | const str = @tagName(@typeInfo(u8)); | ||
| 659 | try expect(std.mem.eql(u8, str, "Int")); | ||
| 660 | } | ||
| 661 | |||
| 662 | test "setting backward branch quota just before a generic fn call" { | ||
| 663 | @setEvalBranchQuota(1001); | ||
| 664 | loopNTimes(1001); | ||
| 665 | } | ||
| 666 | |||
| 667 | fn loopNTimes(comptime n: usize) void { | ||
| 668 | comptime var i = 0; | ||
| 669 | inline while (i < n) : (i += 1) {} | ||
| 670 | } | ||
| 671 | |||
| 672 | test "variable inside inline loop that has different types on different iterations" { | ||
| 673 | try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); | ||
| 674 | } | ||
| 675 | |||
| 676 | fn testVarInsideInlineLoop(args: anytype) !void { | ||
| 677 | comptime var i = 0; | ||
| 678 | inline while (i < args.len) : (i += 1) { | ||
| 679 | const x = args[i]; | ||
| 680 | if (i == 0) try expect(x); | ||
| 681 | if (i == 1) try expect(x == 42); | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | test "inline for with same type but different values" { | ||
| 686 | var res: usize = 0; | ||
| 687 | inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| { | ||
| 688 | var a: T = undefined; | ||
| 689 | res += a.len; | ||
| 690 | } | ||
| 691 | try expect(res == 5); | ||
| 692 | } | ||
| 693 | |||
| 694 | test "refer to the type of a generic function" { | ||
| 695 | const Func = fn (type) void; | ||
| 696 | const f: Func = doNothingWithType; | ||
| 697 | f(i32); | ||
| 698 | } | ||
| 699 | |||
| 700 | fn doNothingWithType(comptime T: type) void {} | ||
| 701 | |||
| 702 | test "zero extend from u0 to u1" { | ||
| 703 | var zero_u0: u0 = 0; | ||
| 704 | var zero_u1: u1 = zero_u0; | ||
| 705 | try expect(zero_u1 == 0); | ||
| 706 | } | ||
| 707 | |||
| 708 | test "bit shift a u1" { | ||
| 709 | var x: u1 = 1; | ||
| 710 | var y = x << 0; | ||
| 711 | try expect(y == 1); | ||
| 712 | } | ||
| 713 | |||
| 714 | test "comptime pointer cast array and then slice" { | ||
| 715 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | ||
| 716 | |||
| 717 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | ||
| 718 | const sliceA: []const u8 = ptrA[0..2]; | ||
| 719 | |||
| 720 | const ptrB: [*]const u8 = &array; | ||
| 721 | const sliceB: []const u8 = ptrB[0..2]; | ||
| 722 | |||
| 723 | try expect(sliceA[1] == 2); | ||
| 724 | try expect(sliceB[1] == 2); | ||
| 725 | } | ||
| 726 | |||
| 727 | test "slice bounds in comptime concatenation" { | ||
| 728 | const bs = comptime blk: { | ||
| 729 | const b = "........1........"; | ||
| 730 | break :blk b[8..9]; | ||
| 731 | }; | ||
| 732 | const str = "" ++ bs; | ||
| 733 | try expect(str.len == 1); | ||
| 734 | try expect(std.mem.eql(u8, str, "1")); | ||
| 735 | |||
| 736 | const str2 = bs ++ ""; | ||
| 737 | try expect(str2.len == 1); | ||
| 738 | try expect(std.mem.eql(u8, str2, "1")); | ||
| 739 | } | ||
| 740 | |||
| 741 | test "comptime bitwise operators" { | ||
| 742 | comptime { | ||
| 743 | try expect(3 & 1 == 1); | ||
| 744 | try expect(3 & -1 == 3); | ||
| 745 | try expect(-3 & -1 == -3); | ||
| 746 | try expect(3 | -1 == -1); | ||
| 747 | try expect(-3 | -1 == -1); | ||
| 748 | try expect(3 ^ -1 == -4); | ||
| 749 | try expect(-3 ^ -1 == 2); | ||
| 750 | try expect(~@as(i8, -1) == 0); | ||
| 751 | try expect(~@as(i128, -1) == 0); | ||
| 752 | try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); | ||
| 753 | try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); | ||
| 754 | try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff); | ||
| 755 | } | ||
| 756 | } | ||
| 757 | |||
| 758 | test "*align(1) u16 is the same as *align(1:0:2) u16" { | ||
| 759 | comptime { | ||
| 760 | try expect(*align(1:0:2) u16 == *align(1) u16); | ||
| 761 | try expect(*align(2:0:2) u16 == *u16); | ||
| 762 | } | ||
| 763 | } | ||
| 764 | |||
| 765 | test "array concatenation forces comptime" { | ||
| 766 | var a = oneItem(3) ++ oneItem(4); | ||
| 767 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); | ||
| 768 | } | ||
| 769 | |||
| 770 | test "array multiplication forces comptime" { | ||
| 771 | var a = oneItem(3) ** scalar(2); | ||
| 772 | try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); | ||
| 773 | } | ||
| 774 | |||
| 775 | fn oneItem(x: i32) [1]i32 { | ||
| 776 | return [_]i32{x}; | ||
| 777 | } | ||
| 778 | |||
| 779 | fn scalar(x: u32) u32 { | ||
| 780 | return x; | ||
| 781 | } | ||
| 782 | |||
| 783 | test "no undeclared identifier error in unanalyzed branches" { | ||
| 784 | if (false) { | ||
| 785 | lol_this_doesnt_exist = nonsense; | ||
| 786 | } | ||
| 787 | } | ||
| 788 | |||
| 789 | test "comptime assign int to optional int" { | ||
| 790 | comptime { | ||
| 791 | var x: ?i32 = null; | ||
| 792 | x = 2; | ||
| 793 | x.? *= 10; | ||
| 794 | try expectEqual(20, x.?); | ||
| 795 | } | ||
| 796 | } | ||
| 797 | |||
| 798 | test "return 0 from function that has u0 return type" { | ||
| 799 | const S = struct { | ||
| 800 | fn foo_zero() u0 { | ||
| 801 | return 0; | ||
| 802 | } | ||
| 803 | }; | ||
| 804 | comptime { | ||
| 805 | if (S.foo_zero() != 0) { | ||
| 806 | @compileError("test failed"); | ||
| 807 | } | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | test "two comptime calls with array default initialized to undefined" { | ||
| 812 | const S = struct { | ||
| 813 | const CrossTarget = struct { | ||
| 814 | dynamic_linker: DynamicLinker = DynamicLinker{}, | ||
| 815 | |||
| 816 | pub fn parse() void { | ||
| 817 | var result: CrossTarget = .{}; | ||
| 818 | result.getCpuArch(); | ||
| 819 | } | ||
| 820 | |||
| 821 | pub fn getCpuArch(self: CrossTarget) void {} | ||
| 822 | }; | ||
| 823 | |||
| 824 | const DynamicLinker = struct { | ||
| 825 | buffer: [255]u8 = undefined, | ||
| 826 | }; | ||
| 827 | }; | ||
| 828 | |||
| 829 | comptime { | ||
| 830 | S.CrossTarget.parse(); | ||
| 831 | S.CrossTarget.parse(); | ||
| 832 | } | ||
| 833 | } | ||
test/stage1/behavior/field_parent_ptr.zig deleted-41| ... | @@ -1,41 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@fieldParentPtr non-first field" { | ||
| 4 | try testParentFieldPtr(&foo.c); | ||
| 5 | comptime try testParentFieldPtr(&foo.c); | ||
| 6 | } | ||
| 7 | |||
| 8 | test "@fieldParentPtr first field" { | ||
| 9 | try testParentFieldPtrFirst(&foo.a); | ||
| 10 | comptime try testParentFieldPtrFirst(&foo.a); | ||
| 11 | } | ||
| 12 | |||
| 13 | const Foo = struct { | ||
| 14 | a: bool, | ||
| 15 | b: f32, | ||
| 16 | c: i32, | ||
| 17 | d: i32, | ||
| 18 | }; | ||
| 19 | |||
| 20 | const foo = Foo{ | ||
| 21 | .a = true, | ||
| 22 | .b = 0.123, | ||
| 23 | .c = 1234, | ||
| 24 | .d = -10, | ||
| 25 | }; | ||
| 26 | |||
| 27 | fn testParentFieldPtr(c: *const i32) !void { | ||
| 28 | try expect(c == &foo.c); | ||
| 29 | |||
| 30 | const base = @fieldParentPtr(Foo, "c", c); | ||
| 31 | try expect(base == &foo); | ||
| 32 | try expect(&base.c == c); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn testParentFieldPtrFirst(a: *const bool) !void { | ||
| 36 | try expect(a == &foo.a); | ||
| 37 | |||
| 38 | const base = @fieldParentPtr(Foo, "a", a); | ||
| 39 | try expect(base == &foo); | ||
| 40 | try expect(&base.a == a); | ||
| 41 | } | ||
test/stage1/behavior/floatop.zig deleted-465| ... | @@ -1,465 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const math = std.math; | ||
| 4 | const pi = std.math.pi; | ||
| 5 | const e = std.math.e; | ||
| 6 | const Vector = std.meta.Vector; | ||
| 7 | |||
| 8 | const epsilon = 0.000001; | ||
| 9 | |||
| 10 | test "@sqrt" { | ||
| 11 | comptime try testSqrt(); | ||
| 12 | try testSqrt(); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn testSqrt() !void { | ||
| 16 | { | ||
| 17 | var a: f16 = 4; | ||
| 18 | try expect(@sqrt(a) == 2); | ||
| 19 | } | ||
| 20 | { | ||
| 21 | var a: f32 = 9; | ||
| 22 | try expect(@sqrt(a) == 3); | ||
| 23 | var b: f32 = 1.1; | ||
| 24 | try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon)); | ||
| 25 | } | ||
| 26 | { | ||
| 27 | var a: f64 = 25; | ||
| 28 | try expect(@sqrt(a) == 5); | ||
| 29 | } | ||
| 30 | { | ||
| 31 | const a: comptime_float = 25.0; | ||
| 32 | try expect(@sqrt(a) == 5.0); | ||
| 33 | } | ||
| 34 | // TODO https://github.com/ziglang/zig/issues/4026 | ||
| 35 | //{ | ||
| 36 | // var a: f128 = 49; | ||
| 37 | //try expect(@sqrt(a) == 7); | ||
| 38 | //} | ||
| 39 | { | ||
| 40 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 41 | var result = @sqrt(v); | ||
| 42 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon)); | ||
| 43 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon)); | ||
| 44 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon)); | ||
| 45 | try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon)); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | test "more @sqrt f16 tests" { | ||
| 50 | // TODO these are not all passing at comptime | ||
| 51 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 52 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon)); | ||
| 53 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon)); | ||
| 54 | try expect(@sqrt(@as(f16, 4.0)) == 2.0); | ||
| 55 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon)); | ||
| 56 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon)); | ||
| 57 | try expect(@sqrt(@as(f16, 64.0)) == 8.0); | ||
| 58 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon)); | ||
| 59 | try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon)); | ||
| 60 | |||
| 61 | // special cases | ||
| 62 | try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16))))); | ||
| 63 | try expect(@sqrt(@as(f16, 0.0)) == 0.0); | ||
| 64 | try expect(@sqrt(@as(f16, -0.0)) == -0.0); | ||
| 65 | try expect(math.isNan(@sqrt(@as(f16, -1.0)))); | ||
| 66 | try expect(math.isNan(@sqrt(@as(f16, math.nan(f16))))); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "@sin" { | ||
| 70 | comptime try testSin(); | ||
| 71 | try testSin(); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn testSin() !void { | ||
| 75 | // TODO test f128, and c_longdouble | ||
| 76 | // https://github.com/ziglang/zig/issues/4026 | ||
| 77 | { | ||
| 78 | var a: f16 = 0; | ||
| 79 | try expect(@sin(a) == 0); | ||
| 80 | } | ||
| 81 | { | ||
| 82 | var a: f32 = 0; | ||
| 83 | try expect(@sin(a) == 0); | ||
| 84 | } | ||
| 85 | { | ||
| 86 | var a: f64 = 0; | ||
| 87 | try expect(@sin(a) == 0); | ||
| 88 | } | ||
| 89 | { | ||
| 90 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 91 | var result = @sin(v); | ||
| 92 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon)); | ||
| 93 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon)); | ||
| 94 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon)); | ||
| 95 | try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon)); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | test "@cos" { | ||
| 100 | comptime try testCos(); | ||
| 101 | try testCos(); | ||
| 102 | } | ||
| 103 | |||
| 104 | fn testCos() !void { | ||
| 105 | // TODO test f128, and c_longdouble | ||
| 106 | // https://github.com/ziglang/zig/issues/4026 | ||
| 107 | { | ||
| 108 | var a: f16 = 0; | ||
| 109 | try expect(@cos(a) == 1); | ||
| 110 | } | ||
| 111 | { | ||
| 112 | var a: f32 = 0; | ||
| 113 | try expect(@cos(a) == 1); | ||
| 114 | } | ||
| 115 | { | ||
| 116 | var a: f64 = 0; | ||
| 117 | try expect(@cos(a) == 1); | ||
| 118 | } | ||
| 119 | { | ||
| 120 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 121 | var result = @cos(v); | ||
| 122 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon)); | ||
| 123 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon)); | ||
| 124 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon)); | ||
| 125 | try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon)); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | test "@exp" { | ||
| 130 | comptime try testExp(); | ||
| 131 | try testExp(); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn testExp() !void { | ||
| 135 | // TODO test f128, and c_longdouble | ||
| 136 | // https://github.com/ziglang/zig/issues/4026 | ||
| 137 | { | ||
| 138 | var a: f16 = 0; | ||
| 139 | try expect(@exp(a) == 1); | ||
| 140 | } | ||
| 141 | { | ||
| 142 | var a: f32 = 0; | ||
| 143 | try expect(@exp(a) == 1); | ||
| 144 | } | ||
| 145 | { | ||
| 146 | var a: f64 = 0; | ||
| 147 | try expect(@exp(a) == 1); | ||
| 148 | } | ||
| 149 | { | ||
| 150 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 151 | var result = @exp(v); | ||
| 152 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon)); | ||
| 153 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon)); | ||
| 154 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon)); | ||
| 155 | try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon)); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | test "@exp2" { | ||
| 160 | comptime try testExp2(); | ||
| 161 | try testExp2(); | ||
| 162 | } | ||
| 163 | |||
| 164 | fn testExp2() !void { | ||
| 165 | // TODO test f128, and c_longdouble | ||
| 166 | // https://github.com/ziglang/zig/issues/4026 | ||
| 167 | { | ||
| 168 | var a: f16 = 2; | ||
| 169 | try expect(@exp2(a) == 4); | ||
| 170 | } | ||
| 171 | { | ||
| 172 | var a: f32 = 2; | ||
| 173 | try expect(@exp2(a) == 4); | ||
| 174 | } | ||
| 175 | { | ||
| 176 | var a: f64 = 2; | ||
| 177 | try expect(@exp2(a) == 4); | ||
| 178 | } | ||
| 179 | { | ||
| 180 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 181 | var result = @exp2(v); | ||
| 182 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon)); | ||
| 183 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon)); | ||
| 184 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon)); | ||
| 185 | try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon)); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | test "@log" { | ||
| 190 | // Old musl (and glibc?), and our current math.ln implementation do not return 1 | ||
| 191 | // so also accept those values. | ||
| 192 | comptime try testLog(); | ||
| 193 | try testLog(); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn testLog() !void { | ||
| 197 | // TODO test f128, and c_longdouble | ||
| 198 | // https://github.com/ziglang/zig/issues/4026 | ||
| 199 | { | ||
| 200 | var a: f16 = e; | ||
| 201 | try expect(math.approxEqAbs(f16, @log(a), 1, epsilon)); | ||
| 202 | } | ||
| 203 | { | ||
| 204 | var a: f32 = e; | ||
| 205 | try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff))); | ||
| 206 | } | ||
| 207 | { | ||
| 208 | var a: f64 = e; | ||
| 209 | try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000))); | ||
| 210 | } | ||
| 211 | { | ||
| 212 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 213 | var result = @log(v); | ||
| 214 | try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon)); | ||
| 215 | try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon)); | ||
| 216 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon)); | ||
| 217 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon)); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | test "@log2" { | ||
| 222 | comptime try testLog2(); | ||
| 223 | try testLog2(); | ||
| 224 | } | ||
| 225 | |||
| 226 | fn testLog2() !void { | ||
| 227 | // TODO test f128, and c_longdouble | ||
| 228 | // https://github.com/ziglang/zig/issues/4026 | ||
| 229 | { | ||
| 230 | var a: f16 = 4; | ||
| 231 | try expect(@log2(a) == 2); | ||
| 232 | } | ||
| 233 | { | ||
| 234 | var a: f32 = 4; | ||
| 235 | try expect(@log2(a) == 2); | ||
| 236 | } | ||
| 237 | { | ||
| 238 | var a: f64 = 4; | ||
| 239 | try expect(@log2(a) == 2); | ||
| 240 | } | ||
| 241 | { | ||
| 242 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 243 | var result = @log2(v); | ||
| 244 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon)); | ||
| 245 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon)); | ||
| 246 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon)); | ||
| 247 | try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon)); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | test "@log10" { | ||
| 252 | comptime try testLog10(); | ||
| 253 | try testLog10(); | ||
| 254 | } | ||
| 255 | |||
| 256 | fn testLog10() !void { | ||
| 257 | // TODO test f128, and c_longdouble | ||
| 258 | // https://github.com/ziglang/zig/issues/4026 | ||
| 259 | { | ||
| 260 | var a: f16 = 100; | ||
| 261 | try expect(@log10(a) == 2); | ||
| 262 | } | ||
| 263 | { | ||
| 264 | var a: f32 = 100; | ||
| 265 | try expect(@log10(a) == 2); | ||
| 266 | } | ||
| 267 | { | ||
| 268 | var a: f64 = 1000; | ||
| 269 | try expect(@log10(a) == 3); | ||
| 270 | } | ||
| 271 | { | ||
| 272 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | ||
| 273 | var result = @log10(v); | ||
| 274 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon)); | ||
| 275 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon)); | ||
| 276 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon)); | ||
| 277 | try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon)); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | test "@fabs" { | ||
| 282 | comptime try testFabs(); | ||
| 283 | try testFabs(); | ||
| 284 | } | ||
| 285 | |||
| 286 | fn testFabs() !void { | ||
| 287 | // TODO test f128, and c_longdouble | ||
| 288 | // https://github.com/ziglang/zig/issues/4026 | ||
| 289 | { | ||
| 290 | var a: f16 = -2.5; | ||
| 291 | var b: f16 = 2.5; | ||
| 292 | try expect(@fabs(a) == 2.5); | ||
| 293 | try expect(@fabs(b) == 2.5); | ||
| 294 | } | ||
| 295 | { | ||
| 296 | var a: f32 = -2.5; | ||
| 297 | var b: f32 = 2.5; | ||
| 298 | try expect(@fabs(a) == 2.5); | ||
| 299 | try expect(@fabs(b) == 2.5); | ||
| 300 | } | ||
| 301 | { | ||
| 302 | var a: f64 = -2.5; | ||
| 303 | var b: f64 = 2.5; | ||
| 304 | try expect(@fabs(a) == 2.5); | ||
| 305 | try expect(@fabs(b) == 2.5); | ||
| 306 | } | ||
| 307 | { | ||
| 308 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 309 | var result = @fabs(v); | ||
| 310 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon)); | ||
| 311 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon)); | ||
| 312 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon)); | ||
| 313 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon)); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | test "@floor" { | ||
| 318 | comptime try testFloor(); | ||
| 319 | try testFloor(); | ||
| 320 | } | ||
| 321 | |||
| 322 | fn testFloor() !void { | ||
| 323 | // TODO test f128, and c_longdouble | ||
| 324 | // https://github.com/ziglang/zig/issues/4026 | ||
| 325 | { | ||
| 326 | var a: f16 = 2.1; | ||
| 327 | try expect(@floor(a) == 2); | ||
| 328 | } | ||
| 329 | { | ||
| 330 | var a: f32 = 2.1; | ||
| 331 | try expect(@floor(a) == 2); | ||
| 332 | } | ||
| 333 | { | ||
| 334 | var a: f64 = 3.5; | ||
| 335 | try expect(@floor(a) == 3); | ||
| 336 | } | ||
| 337 | { | ||
| 338 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 339 | var result = @floor(v); | ||
| 340 | try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon)); | ||
| 341 | try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon)); | ||
| 342 | try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon)); | ||
| 343 | try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon)); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | test "@ceil" { | ||
| 348 | comptime try testCeil(); | ||
| 349 | try testCeil(); | ||
| 350 | } | ||
| 351 | |||
| 352 | fn testCeil() !void { | ||
| 353 | // TODO test f128, and c_longdouble | ||
| 354 | // https://github.com/ziglang/zig/issues/4026 | ||
| 355 | { | ||
| 356 | var a: f16 = 2.1; | ||
| 357 | try expect(@ceil(a) == 3); | ||
| 358 | } | ||
| 359 | { | ||
| 360 | var a: f32 = 2.1; | ||
| 361 | try expect(@ceil(a) == 3); | ||
| 362 | } | ||
| 363 | { | ||
| 364 | var a: f64 = 3.5; | ||
| 365 | try expect(@ceil(a) == 4); | ||
| 366 | } | ||
| 367 | { | ||
| 368 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 369 | var result = @ceil(v); | ||
| 370 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon)); | ||
| 371 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon)); | ||
| 372 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon)); | ||
| 373 | try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon)); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | test "@trunc" { | ||
| 378 | comptime try testTrunc(); | ||
| 379 | try testTrunc(); | ||
| 380 | } | ||
| 381 | |||
| 382 | fn testTrunc() !void { | ||
| 383 | // TODO test f128, and c_longdouble | ||
| 384 | // https://github.com/ziglang/zig/issues/4026 | ||
| 385 | { | ||
| 386 | var a: f16 = 2.1; | ||
| 387 | try expect(@trunc(a) == 2); | ||
| 388 | } | ||
| 389 | { | ||
| 390 | var a: f32 = 2.1; | ||
| 391 | try expect(@trunc(a) == 2); | ||
| 392 | } | ||
| 393 | { | ||
| 394 | var a: f64 = -3.5; | ||
| 395 | try expect(@trunc(a) == -3); | ||
| 396 | } | ||
| 397 | { | ||
| 398 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; | ||
| 399 | var result = @trunc(v); | ||
| 400 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon)); | ||
| 401 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon)); | ||
| 402 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon)); | ||
| 403 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon)); | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | test "floating point comparisons" { | ||
| 408 | try testFloatComparisons(); | ||
| 409 | comptime try testFloatComparisons(); | ||
| 410 | } | ||
| 411 | |||
| 412 | fn testFloatComparisons() !void { | ||
| 413 | inline for ([_]type{ f16, f32, f64, f128 }) |ty| { | ||
| 414 | // No decimal part | ||
| 415 | { | ||
| 416 | const x: ty = 1.0; | ||
| 417 | try expect(x == 1); | ||
| 418 | try expect(x != 0); | ||
| 419 | try expect(x > 0); | ||
| 420 | try expect(x < 2); | ||
| 421 | try expect(x >= 1); | ||
| 422 | try expect(x <= 1); | ||
| 423 | } | ||
| 424 | // Non-zero decimal part | ||
| 425 | { | ||
| 426 | const x: ty = 1.5; | ||
| 427 | try expect(x != 1); | ||
| 428 | try expect(x != 2); | ||
| 429 | try expect(x > 1); | ||
| 430 | try expect(x < 2); | ||
| 431 | try expect(x >= 1); | ||
| 432 | try expect(x <= 2); | ||
| 433 | } | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | test "different sized float comparisons" { | ||
| 438 | try testDifferentSizedFloatComparisons(); | ||
| 439 | comptime try testDifferentSizedFloatComparisons(); | ||
| 440 | } | ||
| 441 | |||
| 442 | fn testDifferentSizedFloatComparisons() !void { | ||
| 443 | var a: f16 = 1; | ||
| 444 | var b: f64 = 2; | ||
| 445 | try expect(a < b); | ||
| 446 | } | ||
| 447 | |||
| 448 | // TODO This is waiting on library support for the Windows build (not sure why the other's don't need it) | ||
| 449 | //test "@nearbyint" { | ||
| 450 | // comptime testNearbyInt(); | ||
| 451 | // testNearbyInt(); | ||
| 452 | //} | ||
| 453 | |||
| 454 | //fn testNearbyInt() void { | ||
| 455 | // // TODO test f16, f128, and c_longdouble | ||
| 456 | // // https://github.com/ziglang/zig/issues/4026 | ||
| 457 | // { | ||
| 458 | // var a: f32 = 2.1; | ||
| 459 | // try expect(@nearbyint(a) == 2); | ||
| 460 | // } | ||
| 461 | // { | ||
| 462 | // var a: f64 = -3.75; | ||
| 463 | // try expect(@nearbyint(a) == -4); | ||
| 464 | // } | ||
| 465 | //} | ||
test/stage1/behavior/fn.zig deleted-286| ... | @@ -1,286 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "params" { | ||
| 7 | try expect(testParamsAdd(22, 11) == 33); | ||
| 8 | } | ||
| 9 | fn testParamsAdd(a: i32, b: i32) i32 { | ||
| 10 | return a + b; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "local variables" { | ||
| 14 | testLocVars(2); | ||
| 15 | } | ||
| 16 | fn testLocVars(b: i32) void { | ||
| 17 | const a: i32 = 1; | ||
| 18 | if (a + b != 3) unreachable; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "void parameters" { | ||
| 22 | try voidFun(1, void{}, 2, {}); | ||
| 23 | } | ||
| 24 | fn voidFun(a: i32, b: void, c: i32, d: void) !void { | ||
| 25 | const v = b; | ||
| 26 | const vv: void = if (a == 1) v else {}; | ||
| 27 | try expect(a + c == 3); | ||
| 28 | return vv; | ||
| 29 | } | ||
| 30 | |||
| 31 | test "mutable local variables" { | ||
| 32 | var zero: i32 = 0; | ||
| 33 | try expect(zero == 0); | ||
| 34 | |||
| 35 | var i = @as(i32, 0); | ||
| 36 | while (i != 3) { | ||
| 37 | i += 1; | ||
| 38 | } | ||
| 39 | try expect(i == 3); | ||
| 40 | } | ||
| 41 | |||
| 42 | test "separate block scopes" { | ||
| 43 | { | ||
| 44 | const no_conflict: i32 = 5; | ||
| 45 | try expect(no_conflict == 5); | ||
| 46 | } | ||
| 47 | |||
| 48 | const c = x: { | ||
| 49 | const no_conflict = @as(i32, 10); | ||
| 50 | break :x no_conflict; | ||
| 51 | }; | ||
| 52 | try expect(c == 10); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "call function with empty string" { | ||
| 56 | acceptsString(""); | ||
| 57 | } | ||
| 58 | |||
| 59 | fn acceptsString(foo: []u8) void {} | ||
| 60 | |||
| 61 | fn @"weird function name"() i32 { | ||
| 62 | return 1234; | ||
| 63 | } | ||
| 64 | test "weird function name" { | ||
| 65 | try expect(@"weird function name"() == 1234); | ||
| 66 | } | ||
| 67 | |||
| 68 | test "implicit cast function unreachable return" { | ||
| 69 | wantsFnWithVoid(fnWithUnreachable); | ||
| 70 | } | ||
| 71 | |||
| 72 | fn wantsFnWithVoid(f: fn () void) void {} | ||
| 73 | |||
| 74 | fn fnWithUnreachable() noreturn { | ||
| 75 | unreachable; | ||
| 76 | } | ||
| 77 | |||
| 78 | test "function pointers" { | ||
| 79 | const fns = [_]@TypeOf(fn1){ | ||
| 80 | fn1, | ||
| 81 | fn2, | ||
| 82 | fn3, | ||
| 83 | fn4, | ||
| 84 | }; | ||
| 85 | for (fns) |f, i| { | ||
| 86 | try expect(f() == @intCast(u32, i) + 5); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | fn fn1() u32 { | ||
| 90 | return 5; | ||
| 91 | } | ||
| 92 | fn fn2() u32 { | ||
| 93 | return 6; | ||
| 94 | } | ||
| 95 | fn fn3() u32 { | ||
| 96 | return 7; | ||
| 97 | } | ||
| 98 | fn fn4() u32 { | ||
| 99 | return 8; | ||
| 100 | } | ||
| 101 | |||
| 102 | test "number literal as an argument" { | ||
| 103 | try numberLiteralArg(3); | ||
| 104 | comptime try numberLiteralArg(3); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn numberLiteralArg(a: anytype) !void { | ||
| 108 | try expect(a == 3); | ||
| 109 | } | ||
| 110 | |||
| 111 | test "assign inline fn to const variable" { | ||
| 112 | const a = inlineFn; | ||
| 113 | a(); | ||
| 114 | } | ||
| 115 | |||
| 116 | fn inlineFn() callconv(.Inline) void {} | ||
| 117 | |||
| 118 | test "pass by non-copying value" { | ||
| 119 | try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | ||
| 120 | } | ||
| 121 | |||
| 122 | const Point = struct { | ||
| 123 | x: i32, | ||
| 124 | y: i32, | ||
| 125 | }; | ||
| 126 | |||
| 127 | fn addPointCoords(pt: Point) i32 { | ||
| 128 | return pt.x + pt.y; | ||
| 129 | } | ||
| 130 | |||
| 131 | test "pass by non-copying value through var arg" { | ||
| 132 | try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn addPointCoordsVar(pt: anytype) !i32 { | ||
| 136 | comptime try expect(@TypeOf(pt) == Point); | ||
| 137 | return pt.x + pt.y; | ||
| 138 | } | ||
| 139 | |||
| 140 | test "pass by non-copying value as method" { | ||
| 141 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 142 | try expect(pt.addPointCoords() == 3); | ||
| 143 | } | ||
| 144 | |||
| 145 | const Point2 = struct { | ||
| 146 | x: i32, | ||
| 147 | y: i32, | ||
| 148 | |||
| 149 | fn addPointCoords(self: Point2) i32 { | ||
| 150 | return self.x + self.y; | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | |||
| 154 | test "pass by non-copying value as method, which is generic" { | ||
| 155 | var pt = Point3{ .x = 1, .y = 2 }; | ||
| 156 | try expect(pt.addPointCoords(i32) == 3); | ||
| 157 | } | ||
| 158 | |||
| 159 | const Point3 = struct { | ||
| 160 | x: i32, | ||
| 161 | y: i32, | ||
| 162 | |||
| 163 | fn addPointCoords(self: Point3, comptime T: type) i32 { | ||
| 164 | return self.x + self.y; | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | |||
| 168 | test "pass by non-copying value as method, at comptime" { | ||
| 169 | comptime { | ||
| 170 | var pt = Point2{ .x = 1, .y = 2 }; | ||
| 171 | try expect(pt.addPointCoords() == 3); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | fn outer(y: u32) fn (u32) u32 { | ||
| 176 | const Y = @TypeOf(y); | ||
| 177 | const st = struct { | ||
| 178 | fn get(z: u32) u32 { | ||
| 179 | return z + @sizeOf(Y); | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | return st.get; | ||
| 183 | } | ||
| 184 | |||
| 185 | test "return inner function which references comptime variable of outer function" { | ||
| 186 | var func = outer(10); | ||
| 187 | try expect(func(3) == 7); | ||
| 188 | } | ||
| 189 | |||
| 190 | test "extern struct with stdcallcc fn pointer" { | ||
| 191 | const S = extern struct { | ||
| 192 | ptr: fn () callconv(if (std.builtin.arch == .i386) .Stdcall else .C) i32, | ||
| 193 | |||
| 194 | fn foo() callconv(if (std.builtin.arch == .i386) .Stdcall else .C) i32 { | ||
| 195 | return 1234; | ||
| 196 | } | ||
| 197 | }; | ||
| 198 | |||
| 199 | var s: S = undefined; | ||
| 200 | s.ptr = S.foo; | ||
| 201 | try expect(s.ptr() == 1234); | ||
| 202 | } | ||
| 203 | |||
| 204 | test "implicit cast fn call result to optional in field result" { | ||
| 205 | const S = struct { | ||
| 206 | fn entry() !void { | ||
| 207 | var x = Foo{ | ||
| 208 | .field = optionalPtr(), | ||
| 209 | }; | ||
| 210 | try expect(x.field.?.* == 999); | ||
| 211 | } | ||
| 212 | |||
| 213 | const glob: i32 = 999; | ||
| 214 | |||
| 215 | fn optionalPtr() *const i32 { | ||
| 216 | return &glob; | ||
| 217 | } | ||
| 218 | |||
| 219 | const Foo = struct { | ||
| 220 | field: ?*const i32, | ||
| 221 | }; | ||
| 222 | }; | ||
| 223 | try S.entry(); | ||
| 224 | comptime try S.entry(); | ||
| 225 | } | ||
| 226 | |||
| 227 | test "discard the result of a function that returns a struct" { | ||
| 228 | const S = struct { | ||
| 229 | fn entry() void { | ||
| 230 | _ = func(); | ||
| 231 | } | ||
| 232 | |||
| 233 | fn func() Foo { | ||
| 234 | return undefined; | ||
| 235 | } | ||
| 236 | |||
| 237 | const Foo = struct { | ||
| 238 | a: u64, | ||
| 239 | b: u64, | ||
| 240 | }; | ||
| 241 | }; | ||
| 242 | S.entry(); | ||
| 243 | comptime S.entry(); | ||
| 244 | } | ||
| 245 | |||
| 246 | test "function call with anon list literal" { | ||
| 247 | const S = struct { | ||
| 248 | fn doTheTest() !void { | ||
| 249 | try consumeVec(.{ 9, 8, 7 }); | ||
| 250 | } | ||
| 251 | |||
| 252 | fn consumeVec(vec: [3]f32) !void { | ||
| 253 | try expect(vec[0] == 9); | ||
| 254 | try expect(vec[1] == 8); | ||
| 255 | try expect(vec[2] == 7); | ||
| 256 | } | ||
| 257 | }; | ||
| 258 | try S.doTheTest(); | ||
| 259 | comptime try S.doTheTest(); | ||
| 260 | } | ||
| 261 | |||
| 262 | test "ability to give comptime types and non comptime types to same parameter" { | ||
| 263 | const S = struct { | ||
| 264 | fn doTheTest() !void { | ||
| 265 | var x: i32 = 1; | ||
| 266 | try expect(foo(x) == 10); | ||
| 267 | try expect(foo(i32) == 20); | ||
| 268 | } | ||
| 269 | |||
| 270 | fn foo(arg: anytype) i32 { | ||
| 271 | if (@typeInfo(@TypeOf(arg)) == .Type and arg == i32) return 20; | ||
| 272 | return 9 + arg; | ||
| 273 | } | ||
| 274 | }; | ||
| 275 | try S.doTheTest(); | ||
| 276 | comptime try S.doTheTest(); | ||
| 277 | } | ||
| 278 | |||
| 279 | test "function with inferred error set but returning no error" { | ||
| 280 | const S = struct { | ||
| 281 | fn foo() !void {} | ||
| 282 | }; | ||
| 283 | |||
| 284 | const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; | ||
| 285 | try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); | ||
| 286 | } | ||
test/stage1/behavior/fn_delegation.zig deleted-39| ... | @@ -1,39 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: u64 = 10, | ||
| 5 | |||
| 6 | fn one(self: Foo) u64 { | ||
| 7 | return self.a + 1; | ||
| 8 | } | ||
| 9 | |||
| 10 | const two = __two; | ||
| 11 | |||
| 12 | fn __two(self: Foo) u64 { | ||
| 13 | return self.a + 2; | ||
| 14 | } | ||
| 15 | |||
| 16 | const three = __three; | ||
| 17 | |||
| 18 | const four = custom(Foo, 4); | ||
| 19 | }; | ||
| 20 | |||
| 21 | fn __three(self: Foo) u64 { | ||
| 22 | return self.a + 3; | ||
| 23 | } | ||
| 24 | |||
| 25 | fn custom(comptime T: type, comptime num: u64) fn (T) u64 { | ||
| 26 | return struct { | ||
| 27 | fn function(self: T) u64 { | ||
| 28 | return self.a + num; | ||
| 29 | } | ||
| 30 | }.function; | ||
| 31 | } | ||
| 32 | |||
| 33 | test "fn delegation" { | ||
| 34 | const foo = Foo{}; | ||
| 35 | try expect(foo.one() == 11); | ||
| 36 | try expect(foo.two() == 12); | ||
| 37 | try expect(foo.three() == 13); | ||
| 38 | try expect(foo.four() == 14); | ||
| 39 | } | ||
test/stage1/behavior/fn_in_struct_in_comptime.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn get_foo() fn (*u8) usize { | ||
| 4 | comptime { | ||
| 5 | return struct { | ||
| 6 | fn func(ptr: *u8) usize { | ||
| 7 | var u = @ptrToInt(ptr); | ||
| 8 | return u; | ||
| 9 | } | ||
| 10 | }.func; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "define a function in an anonymous struct in comptime" { | ||
| 15 | const foo = get_foo(); | ||
| 16 | try expect(foo(@intToPtr(*u8, 12345)) == 12345); | ||
| 17 | } | ||
test/stage1/behavior/for.zig deleted-172| ... | @@ -1,172 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const mem = std.mem; | ||
| 5 | |||
| 6 | test "continue in for loop" { | ||
| 7 | const array = [_]i32{ | ||
| 8 | 1, | ||
| 9 | 2, | ||
| 10 | 3, | ||
| 11 | 4, | ||
| 12 | 5, | ||
| 13 | }; | ||
| 14 | var sum: i32 = 0; | ||
| 15 | for (array) |x| { | ||
| 16 | sum += x; | ||
| 17 | if (x < 3) { | ||
| 18 | continue; | ||
| 19 | } | ||
| 20 | break; | ||
| 21 | } | ||
| 22 | if (sum != 6) unreachable; | ||
| 23 | } | ||
| 24 | |||
| 25 | test "for loop with pointer elem var" { | ||
| 26 | const source = "abcdefg"; | ||
| 27 | var target: [source.len]u8 = undefined; | ||
| 28 | mem.copy(u8, target[0..], source); | ||
| 29 | mangleString(target[0..]); | ||
| 30 | try expect(mem.eql(u8, &target, "bcdefgh")); | ||
| 31 | |||
| 32 | for (source) |*c, i| | ||
| 33 | try expect(@TypeOf(c) == *const u8); | ||
| 34 | for (target) |*c, i| | ||
| 35 | try expect(@TypeOf(c) == *u8); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn mangleString(s: []u8) void { | ||
| 39 | for (s) |*c| { | ||
| 40 | c.* += 1; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | test "basic for loop" { | ||
| 45 | const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | ||
| 46 | |||
| 47 | var buffer: [expected_result.len]u8 = undefined; | ||
| 48 | var buf_index: usize = 0; | ||
| 49 | |||
| 50 | const array = [_]u8{ 9, 8, 7, 6 }; | ||
| 51 | for (array) |item| { | ||
| 52 | buffer[buf_index] = item; | ||
| 53 | buf_index += 1; | ||
| 54 | } | ||
| 55 | for (array) |item, index| { | ||
| 56 | buffer[buf_index] = @intCast(u8, index); | ||
| 57 | buf_index += 1; | ||
| 58 | } | ||
| 59 | const array_ptr = &array; | ||
| 60 | for (array_ptr) |item| { | ||
| 61 | buffer[buf_index] = item; | ||
| 62 | buf_index += 1; | ||
| 63 | } | ||
| 64 | for (array_ptr) |item, index| { | ||
| 65 | buffer[buf_index] = @intCast(u8, index); | ||
| 66 | buf_index += 1; | ||
| 67 | } | ||
| 68 | const unknown_size: []const u8 = &array; | ||
| 69 | for (unknown_size) |item| { | ||
| 70 | buffer[buf_index] = item; | ||
| 71 | buf_index += 1; | ||
| 72 | } | ||
| 73 | for (unknown_size) |item, index| { | ||
| 74 | buffer[buf_index] = @intCast(u8, index); | ||
| 75 | buf_index += 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | try expect(mem.eql(u8, buffer[0..buf_index], &expected_result)); | ||
| 79 | } | ||
| 80 | |||
| 81 | test "break from outer for loop" { | ||
| 82 | try testBreakOuter(); | ||
| 83 | comptime try testBreakOuter(); | ||
| 84 | } | ||
| 85 | |||
| 86 | fn testBreakOuter() !void { | ||
| 87 | var array = "aoeu"; | ||
| 88 | var count: usize = 0; | ||
| 89 | outer: for (array) |_| { | ||
| 90 | for (array) |_| { | ||
| 91 | count += 1; | ||
| 92 | break :outer; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | try expect(count == 1); | ||
| 96 | } | ||
| 97 | |||
| 98 | test "continue outer for loop" { | ||
| 99 | try testContinueOuter(); | ||
| 100 | comptime try testContinueOuter(); | ||
| 101 | } | ||
| 102 | |||
| 103 | fn testContinueOuter() !void { | ||
| 104 | var array = "aoeu"; | ||
| 105 | var counter: usize = 0; | ||
| 106 | outer: for (array) |_| { | ||
| 107 | for (array) |_| { | ||
| 108 | counter += 1; | ||
| 109 | continue :outer; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | try expect(counter == array.len); | ||
| 113 | } | ||
| 114 | |||
| 115 | test "2 break statements and an else" { | ||
| 116 | const S = struct { | ||
| 117 | fn entry(t: bool, f: bool) !void { | ||
| 118 | var buf: [10]u8 = undefined; | ||
| 119 | var ok = false; | ||
| 120 | ok = for (buf) |item| { | ||
| 121 | if (f) break false; | ||
| 122 | if (t) break true; | ||
| 123 | } else false; | ||
| 124 | try expect(ok); | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | try S.entry(true, false); | ||
| 128 | comptime try S.entry(true, false); | ||
| 129 | } | ||
| 130 | |||
| 131 | test "for with null and T peer types and inferred result location type" { | ||
| 132 | const S = struct { | ||
| 133 | fn doTheTest(slice: []const u8) !void { | ||
| 134 | if (for (slice) |item| { | ||
| 135 | if (item == 10) { | ||
| 136 | break item; | ||
| 137 | } | ||
| 138 | } else null) |v| { | ||
| 139 | @panic("fail"); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | try S.doTheTest(&[_]u8{ 1, 2 }); | ||
| 144 | comptime try S.doTheTest(&[_]u8{ 1, 2 }); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "for copies its payload" { | ||
| 148 | const S = struct { | ||
| 149 | fn doTheTest() !void { | ||
| 150 | var x = [_]usize{ 1, 2, 3 }; | ||
| 151 | for (x) |value, i| { | ||
| 152 | // Modify the original array | ||
| 153 | x[i] += 99; | ||
| 154 | try expectEqual(value, i + 1); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | try S.doTheTest(); | ||
| 159 | comptime try S.doTheTest(); | ||
| 160 | } | ||
| 161 | |||
| 162 | test "for on slice with allowzero ptr" { | ||
| 163 | const S = struct { | ||
| 164 | fn doTheTest(slice: []const u8) !void { | ||
| 165 | var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len]; | ||
| 166 | for (ptr) |x, i| try expect(x == i + 1); | ||
| 167 | for (ptr) |*x, i| try expect(x.* == i + 1); | ||
| 168 | } | ||
| 169 | }; | ||
| 170 | try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); | ||
| 171 | comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); | ||
| 172 | } | ||
test/stage1/behavior/generics.zig deleted-169| ... | @@ -1,169 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "simple generic fn" { | ||
| 7 | try expect(max(i32, 3, -1) == 3); | ||
| 8 | try expect(max(f32, 0.123, 0.456) == 0.456); | ||
| 9 | try expect(add(2, 3) == 5); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn max(comptime T: type, a: T, b: T) T { | ||
| 13 | return if (a > b) a else b; | ||
| 14 | } | ||
| 15 | |||
| 16 | fn add(comptime a: i32, b: i32) i32 { | ||
| 17 | return (comptime a) + b; | ||
| 18 | } | ||
| 19 | |||
| 20 | const the_max = max(u32, 1234, 5678); | ||
| 21 | test "compile time generic eval" { | ||
| 22 | try expect(the_max == 5678); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn gimmeTheBigOne(a: u32, b: u32) u32 { | ||
| 26 | return max(u32, a, b); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn shouldCallSameInstance(a: u32, b: u32) u32 { | ||
| 30 | return max(u32, a, b); | ||
| 31 | } | ||
| 32 | |||
| 33 | fn sameButWithFloats(a: f64, b: f64) f64 { | ||
| 34 | return max(f64, a, b); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "fn with comptime args" { | ||
| 38 | try expect(gimmeTheBigOne(1234, 5678) == 5678); | ||
| 39 | try expect(shouldCallSameInstance(34, 12) == 34); | ||
| 40 | try expect(sameButWithFloats(0.43, 0.49) == 0.49); | ||
| 41 | } | ||
| 42 | |||
| 43 | test "var params" { | ||
| 44 | try expect(max_i32(12, 34) == 34); | ||
| 45 | try expect(max_f64(1.2, 3.4) == 3.4); | ||
| 46 | } | ||
| 47 | |||
| 48 | comptime { | ||
| 49 | try expect(max_i32(12, 34) == 34); | ||
| 50 | try expect(max_f64(1.2, 3.4) == 3.4); | ||
| 51 | } | ||
| 52 | |||
| 53 | fn max_var(a: anytype, b: anytype) @TypeOf(a + b) { | ||
| 54 | return if (a > b) a else b; | ||
| 55 | } | ||
| 56 | |||
| 57 | fn max_i32(a: i32, b: i32) i32 { | ||
| 58 | return max_var(a, b); | ||
| 59 | } | ||
| 60 | |||
| 61 | fn max_f64(a: f64, b: f64) f64 { | ||
| 62 | return max_var(a, b); | ||
| 63 | } | ||
| 64 | |||
| 65 | pub fn List(comptime T: type) type { | ||
| 66 | return SmallList(T, 8); | ||
| 67 | } | ||
| 68 | |||
| 69 | pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { | ||
| 70 | return struct { | ||
| 71 | items: []T, | ||
| 72 | length: usize, | ||
| 73 | prealloc_items: [STATIC_SIZE]T, | ||
| 74 | }; | ||
| 75 | } | ||
| 76 | |||
| 77 | test "function with return type type" { | ||
| 78 | var list: List(i32) = undefined; | ||
| 79 | var list2: List(i32) = undefined; | ||
| 80 | list.length = 10; | ||
| 81 | list2.length = 10; | ||
| 82 | try expect(list.prealloc_items.len == 8); | ||
| 83 | try expect(list2.prealloc_items.len == 8); | ||
| 84 | } | ||
| 85 | |||
| 86 | test "generic struct" { | ||
| 87 | var a1 = GenNode(i32){ | ||
| 88 | .value = 13, | ||
| 89 | .next = null, | ||
| 90 | }; | ||
| 91 | var b1 = GenNode(bool){ | ||
| 92 | .value = true, | ||
| 93 | .next = null, | ||
| 94 | }; | ||
| 95 | try expect(a1.value == 13); | ||
| 96 | try expect(a1.value == a1.getVal()); | ||
| 97 | try expect(b1.getVal()); | ||
| 98 | } | ||
| 99 | fn GenNode(comptime T: type) type { | ||
| 100 | return struct { | ||
| 101 | value: T, | ||
| 102 | next: ?*GenNode(T), | ||
| 103 | fn getVal(n: *const GenNode(T)) T { | ||
| 104 | return n.value; | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | } | ||
| 108 | |||
| 109 | test "const decls in struct" { | ||
| 110 | try expect(GenericDataThing(3).count_plus_one == 4); | ||
| 111 | } | ||
| 112 | fn GenericDataThing(comptime count: isize) type { | ||
| 113 | return struct { | ||
| 114 | const count_plus_one = count + 1; | ||
| 115 | }; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "use generic param in generic param" { | ||
| 119 | try expect(aGenericFn(i32, 3, 4) == 7); | ||
| 120 | } | ||
| 121 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { | ||
| 122 | return a + b; | ||
| 123 | } | ||
| 124 | |||
| 125 | test "generic fn with implicit cast" { | ||
| 126 | try expect(getFirstByte(u8, &[_]u8{13}) == 13); | ||
| 127 | try expect(getFirstByte(u16, &[_]u16{ | ||
| 128 | 0, | ||
| 129 | 13, | ||
| 130 | }) == 0); | ||
| 131 | } | ||
| 132 | fn getByte(ptr: ?*const u8) u8 { | ||
| 133 | return ptr.?.*; | ||
| 134 | } | ||
| 135 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 136 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 137 | } | ||
| 138 | |||
| 139 | const foos = [_]fn (anytype) bool{ | ||
| 140 | foo1, | ||
| 141 | foo2, | ||
| 142 | }; | ||
| 143 | |||
| 144 | fn foo1(arg: anytype) bool { | ||
| 145 | return arg; | ||
| 146 | } | ||
| 147 | fn foo2(arg: anytype) bool { | ||
| 148 | return !arg; | ||
| 149 | } | ||
| 150 | |||
| 151 | test "array of generic fns" { | ||
| 152 | try expect(foos[0](true)); | ||
| 153 | try expect(!foos[1](true)); | ||
| 154 | } | ||
| 155 | |||
| 156 | test "generic fn keeps non-generic parameter types" { | ||
| 157 | const A = 128; | ||
| 158 | |||
| 159 | const S = struct { | ||
| 160 | fn f(comptime T: type, s: []T) !void { | ||
| 161 | try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment); | ||
| 162 | } | ||
| 163 | }; | ||
| 164 | |||
| 165 | // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that | ||
| 166 | // `x` type not affect `s` parameter type. | ||
| 167 | var x: [16]u8 align(A) = undefined; | ||
| 168 | try S.f(u8, &x); | ||
| 169 | } | ||
test/stage1/behavior/hasdecl.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const Foo = @import("hasdecl/foo.zig"); | ||
| 5 | |||
| 6 | const Bar = struct { | ||
| 7 | nope: i32, | ||
| 8 | |||
| 9 | const hi = 1; | ||
| 10 | pub var blah = "xxx"; | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "@hasDecl" { | ||
| 14 | try expect(@hasDecl(Foo, "public_thing")); | ||
| 15 | try expect(!@hasDecl(Foo, "private_thing")); | ||
| 16 | try expect(!@hasDecl(Foo, "no_thing")); | ||
| 17 | |||
| 18 | try expect(@hasDecl(Bar, "hi")); | ||
| 19 | try expect(@hasDecl(Bar, "blah")); | ||
| 20 | try expect(!@hasDecl(Bar, "nope")); | ||
| 21 | } | ||
test/stage1/behavior/hasdecl/foo.zig deleted-2| ... | @@ -1,2 +0,0 @@ | ||
| 1 | pub const public_thing = 42; | ||
| 2 | const private_thing = 666; | ||
test/stage1/behavior/hasfield.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | test "@hasField" { | ||
| 5 | const struc = struct { | ||
| 6 | a: i32, | ||
| 7 | b: []u8, | ||
| 8 | |||
| 9 | pub const nope = 1; | ||
| 10 | }; | ||
| 11 | try expect(@hasField(struc, "a") == true); | ||
| 12 | try expect(@hasField(struc, "b") == true); | ||
| 13 | try expect(@hasField(struc, "non-existant") == false); | ||
| 14 | try expect(@hasField(struc, "nope") == false); | ||
| 15 | |||
| 16 | const unin = union { | ||
| 17 | a: u64, | ||
| 18 | b: []u16, | ||
| 19 | |||
| 20 | pub const nope = 1; | ||
| 21 | }; | ||
| 22 | try expect(@hasField(unin, "a") == true); | ||
| 23 | try expect(@hasField(unin, "b") == true); | ||
| 24 | try expect(@hasField(unin, "non-existant") == false); | ||
| 25 | try expect(@hasField(unin, "nope") == false); | ||
| 26 | |||
| 27 | const enm = enum { | ||
| 28 | a, | ||
| 29 | b, | ||
| 30 | |||
| 31 | pub const nope = 1; | ||
| 32 | }; | ||
| 33 | try expect(@hasField(enm, "a") == true); | ||
| 34 | try expect(@hasField(enm, "b") == true); | ||
| 35 | try expect(@hasField(enm, "non-existant") == false); | ||
| 36 | try expect(@hasField(enm, "nope") == false); | ||
| 37 | } | ||
test/stage1/behavior/if.zig deleted-109| ... | @@ -1,109 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | |||
| 5 | test "if statements" { | ||
| 6 | shouldBeEqual(1, 1); | ||
| 7 | firstEqlThird(2, 1, 2); | ||
| 8 | } | ||
| 9 | fn shouldBeEqual(a: i32, b: i32) void { | ||
| 10 | if (a != b) { | ||
| 11 | unreachable; | ||
| 12 | } else { | ||
| 13 | return; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | fn firstEqlThird(a: i32, b: i32, c: i32) void { | ||
| 17 | if (a == b) { | ||
| 18 | unreachable; | ||
| 19 | } else if (b == c) { | ||
| 20 | unreachable; | ||
| 21 | } else if (a == c) { | ||
| 22 | return; | ||
| 23 | } else { | ||
| 24 | unreachable; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | test "else if expression" { | ||
| 29 | try expect(elseIfExpressionF(1) == 1); | ||
| 30 | } | ||
| 31 | fn elseIfExpressionF(c: u8) u8 { | ||
| 32 | if (c == 0) { | ||
| 33 | return 0; | ||
| 34 | } else if (c == 1) { | ||
| 35 | return 1; | ||
| 36 | } else { | ||
| 37 | return @as(u8, 2); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // #2297 | ||
| 42 | var global_with_val: anyerror!u32 = 0; | ||
| 43 | var global_with_err: anyerror!u32 = error.SomeError; | ||
| 44 | |||
| 45 | test "unwrap mutable global var" { | ||
| 46 | if (global_with_val) |v| { | ||
| 47 | try expect(v == 0); | ||
| 48 | } else |e| { | ||
| 49 | unreachable; | ||
| 50 | } | ||
| 51 | if (global_with_err) |_| { | ||
| 52 | unreachable; | ||
| 53 | } else |e| { | ||
| 54 | try expect(e == error.SomeError); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | test "labeled break inside comptime if inside runtime if" { | ||
| 59 | var answer: i32 = 0; | ||
| 60 | var c = true; | ||
| 61 | if (c) { | ||
| 62 | answer = if (true) blk: { | ||
| 63 | break :blk @as(i32, 42); | ||
| 64 | }; | ||
| 65 | } | ||
| 66 | try expect(answer == 42); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "const result loc, runtime if cond, else unreachable" { | ||
| 70 | const Num = enum { | ||
| 71 | One, | ||
| 72 | Two, | ||
| 73 | }; | ||
| 74 | |||
| 75 | var t = true; | ||
| 76 | const x = if (t) Num.Two else unreachable; | ||
| 77 | try expect(x == .Two); | ||
| 78 | } | ||
| 79 | |||
| 80 | test "if prongs cast to expected type instead of peer type resolution" { | ||
| 81 | const S = struct { | ||
| 82 | fn doTheTest(f: bool) !void { | ||
| 83 | var x: i32 = 0; | ||
| 84 | x = if (f) 1 else 2; | ||
| 85 | try expect(x == 2); | ||
| 86 | |||
| 87 | var b = true; | ||
| 88 | const y: i32 = if (b) 1 else 2; | ||
| 89 | try expect(y == 1); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | try S.doTheTest(false); | ||
| 93 | comptime try S.doTheTest(false); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "while copies its payload" { | ||
| 97 | const S = struct { | ||
| 98 | fn doTheTest() !void { | ||
| 99 | var tmp: ?i32 = 10; | ||
| 100 | if (tmp) |value| { | ||
| 101 | // Modify the original variable | ||
| 102 | tmp = null; | ||
| 103 | try expectEqual(@as(i32, 10), value); | ||
| 104 | } else unreachable; | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | try S.doTheTest(); | ||
| 108 | comptime try S.doTheTest(); | ||
| 109 | } | ||
test/stage1/behavior/import.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const expectEqual = @import("std").testing.expectEqual; | ||
| 3 | const a_namespace = @import("import/a_namespace.zig"); | ||
| 4 | |||
| 5 | test "call fn via namespace lookup" { | ||
| 6 | try expectEqual(@as(i32, 1234), a_namespace.foo()); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "importing the same thing gives the same import" { | ||
| 10 | try expect(@import("std") == @import("std")); | ||
| 11 | } | ||
| 12 | |||
| 13 | test "import in non-toplevel scope" { | ||
| 14 | const S = struct { | ||
| 15 | usingnamespace @import("import/a_namespace.zig"); | ||
| 16 | }; | ||
| 17 | try expectEqual(@as(i32, 1234), S.foo()); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "import empty file" { | ||
| 21 | const empty = @import("import/empty.zig"); | ||
| 22 | } | ||
test/stage1/behavior/import/a_namespace.zig deleted-3| ... | @@ -1,3 +0,0 @@ | ||
| 1 | pub fn foo() i32 { | ||
| 2 | return 1234; | ||
| 3 | } | ||
test/stage1/behavior/import/empty.zig deletedtest/stage1/behavior/incomplete_struct_param_tld.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 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: 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{ .x = 13 }, | ||
| 27 | }, | ||
| 28 | }; | ||
| 29 | try expect(foo(a) == 13); | ||
| 30 | } | ||
test/stage1/behavior/inttoptr.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | test "casting random address to function pointer" { | ||
| 2 | randomAddressToFunction(); | ||
| 3 | comptime randomAddressToFunction(); | ||
| 4 | } | ||
| 5 | |||
| 6 | fn randomAddressToFunction() void { | ||
| 7 | var addr: usize = 0xdeadbeef; | ||
| 8 | var ptr = @intToPtr(fn () void, addr); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "mutate through ptr initialized with constant intToPtr value" { | ||
| 12 | forceCompilerAnalyzeBranchHardCodedPtrDereference(false); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { | ||
| 16 | const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); | ||
| 17 | if (x) { | ||
| 18 | hardCodedP.* = hardCodedP.* | 10; | ||
| 19 | } else { | ||
| 20 | return; | ||
| 21 | } | ||
| 22 | } | ||
test/stage1/behavior/ir_block_deps.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn foo(id: u64) !i32 { | ||
| 4 | return switch (id) { | ||
| 5 | 1 => getErrInt(), | ||
| 6 | 2 => { | ||
| 7 | const size = try getErrInt(); | ||
| 8 | return try getErrInt(); | ||
| 9 | }, | ||
| 10 | else => error.ItBroke, | ||
| 11 | }; | ||
| 12 | } | ||
| 13 | |||
| 14 | fn getErrInt() anyerror!i32 { | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "ir block deps" { | ||
| 19 | try expect((foo(1) catch unreachable) == 0); | ||
| 20 | try expect((foo(2) catch unreachable) == 0); | ||
| 21 | } | ||
test/stage1/behavior/math.zig deleted-872| ... | @@ -1,872 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 5 | const maxInt = std.math.maxInt; | ||
| 6 | const minInt = std.math.minInt; | ||
| 7 | const mem = std.mem; | ||
| 8 | |||
| 9 | test "division" { | ||
| 10 | try testDivision(); | ||
| 11 | comptime try testDivision(); | ||
| 12 | } | ||
| 13 | fn testDivision() !void { | ||
| 14 | try expect(div(u32, 13, 3) == 4); | ||
| 15 | try expect(div(f16, 1.0, 2.0) == 0.5); | ||
| 16 | try expect(div(f32, 1.0, 2.0) == 0.5); | ||
| 17 | |||
| 18 | try expect(divExact(u32, 55, 11) == 5); | ||
| 19 | try expect(divExact(i32, -55, 11) == -5); | ||
| 20 | try expect(divExact(f16, 55.0, 11.0) == 5.0); | ||
| 21 | try expect(divExact(f16, -55.0, 11.0) == -5.0); | ||
| 22 | try expect(divExact(f32, 55.0, 11.0) == 5.0); | ||
| 23 | try expect(divExact(f32, -55.0, 11.0) == -5.0); | ||
| 24 | |||
| 25 | try expect(divFloor(i32, 5, 3) == 1); | ||
| 26 | try expect(divFloor(i32, -5, 3) == -2); | ||
| 27 | try expect(divFloor(f16, 5.0, 3.0) == 1.0); | ||
| 28 | try expect(divFloor(f16, -5.0, 3.0) == -2.0); | ||
| 29 | try expect(divFloor(f32, 5.0, 3.0) == 1.0); | ||
| 30 | try expect(divFloor(f32, -5.0, 3.0) == -2.0); | ||
| 31 | try expect(divFloor(i32, -0x80000000, -2) == 0x40000000); | ||
| 32 | try expect(divFloor(i32, 0, -0x80000000) == 0); | ||
| 33 | try expect(divFloor(i32, -0x40000001, 0x40000000) == -2); | ||
| 34 | try expect(divFloor(i32, -0x80000000, 1) == -0x80000000); | ||
| 35 | try expect(divFloor(i32, 10, 12) == 0); | ||
| 36 | try expect(divFloor(i32, -14, 12) == -2); | ||
| 37 | try expect(divFloor(i32, -2, 12) == -1); | ||
| 38 | |||
| 39 | try expect(divTrunc(i32, 5, 3) == 1); | ||
| 40 | try expect(divTrunc(i32, -5, 3) == -1); | ||
| 41 | try expect(divTrunc(f16, 5.0, 3.0) == 1.0); | ||
| 42 | try expect(divTrunc(f16, -5.0, 3.0) == -1.0); | ||
| 43 | try expect(divTrunc(f32, 5.0, 3.0) == 1.0); | ||
| 44 | try expect(divTrunc(f32, -5.0, 3.0) == -1.0); | ||
| 45 | try expect(divTrunc(f64, 5.0, 3.0) == 1.0); | ||
| 46 | try expect(divTrunc(f64, -5.0, 3.0) == -1.0); | ||
| 47 | try expect(divTrunc(i32, 10, 12) == 0); | ||
| 48 | try expect(divTrunc(i32, -14, 12) == -1); | ||
| 49 | try expect(divTrunc(i32, -2, 12) == 0); | ||
| 50 | |||
| 51 | try expect(mod(i32, 10, 12) == 10); | ||
| 52 | try expect(mod(i32, -14, 12) == 10); | ||
| 53 | try expect(mod(i32, -2, 12) == 10); | ||
| 54 | |||
| 55 | comptime { | ||
| 56 | try expect( | ||
| 57 | 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, | ||
| 58 | ); | ||
| 59 | try expect( | ||
| 60 | @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, | ||
| 61 | ); | ||
| 62 | try expect( | ||
| 63 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, | ||
| 64 | ); | ||
| 65 | try expect( | ||
| 66 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | ||
| 67 | ); | ||
| 68 | try expect( | ||
| 69 | @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, | ||
| 70 | ); | ||
| 71 | try expect( | ||
| 72 | @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, | ||
| 73 | ); | ||
| 74 | try expect( | ||
| 75 | 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, | ||
| 76 | ); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | fn div(comptime T: type, a: T, b: T) T { | ||
| 80 | return a / b; | ||
| 81 | } | ||
| 82 | fn divExact(comptime T: type, a: T, b: T) T { | ||
| 83 | return @divExact(a, b); | ||
| 84 | } | ||
| 85 | fn divFloor(comptime T: type, a: T, b: T) T { | ||
| 86 | return @divFloor(a, b); | ||
| 87 | } | ||
| 88 | fn divTrunc(comptime T: type, a: T, b: T) T { | ||
| 89 | return @divTrunc(a, b); | ||
| 90 | } | ||
| 91 | fn mod(comptime T: type, a: T, b: T) T { | ||
| 92 | return @mod(a, b); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "@addWithOverflow" { | ||
| 96 | var result: u8 = undefined; | ||
| 97 | try expect(@addWithOverflow(u8, 250, 100, &result)); | ||
| 98 | try expect(!@addWithOverflow(u8, 100, 150, &result)); | ||
| 99 | try expect(result == 250); | ||
| 100 | } | ||
| 101 | |||
| 102 | // TODO test mulWithOverflow | ||
| 103 | // TODO test subWithOverflow | ||
| 104 | |||
| 105 | test "@shlWithOverflow" { | ||
| 106 | var result: u16 = undefined; | ||
| 107 | try expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); | ||
| 108 | try expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); | ||
| 109 | try expect(result == 0b1011111111111100); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "@*WithOverflow with u0 values" { | ||
| 113 | var result: u0 = undefined; | ||
| 114 | try expect(!@addWithOverflow(u0, 0, 0, &result)); | ||
| 115 | try expect(!@subWithOverflow(u0, 0, 0, &result)); | ||
| 116 | try expect(!@mulWithOverflow(u0, 0, 0, &result)); | ||
| 117 | try expect(!@shlWithOverflow(u0, 0, 0, &result)); | ||
| 118 | } | ||
| 119 | |||
| 120 | test "@clz" { | ||
| 121 | try testClz(); | ||
| 122 | comptime try testClz(); | ||
| 123 | } | ||
| 124 | |||
| 125 | fn testClz() !void { | ||
| 126 | try expect(clz(u8, 0b10001010) == 0); | ||
| 127 | try expect(clz(u8, 0b00001010) == 4); | ||
| 128 | try expect(clz(u8, 0b00011010) == 3); | ||
| 129 | try expect(clz(u8, 0b00000000) == 8); | ||
| 130 | try expect(clz(u128, 0xffffffffffffffff) == 64); | ||
| 131 | try expect(clz(u128, 0x10000000000000000) == 63); | ||
| 132 | } | ||
| 133 | |||
| 134 | fn clz(comptime T: type, x: T) usize { | ||
| 135 | return @clz(T, x); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "@ctz" { | ||
| 139 | try testCtz(); | ||
| 140 | comptime try testCtz(); | ||
| 141 | } | ||
| 142 | |||
| 143 | fn testCtz() !void { | ||
| 144 | try expect(ctz(u8, 0b10100000) == 5); | ||
| 145 | try expect(ctz(u8, 0b10001010) == 1); | ||
| 146 | try expect(ctz(u8, 0b00000000) == 8); | ||
| 147 | try expect(ctz(u16, 0b00000000) == 16); | ||
| 148 | } | ||
| 149 | |||
| 150 | fn ctz(comptime T: type, x: T) usize { | ||
| 151 | return @ctz(T, x); | ||
| 152 | } | ||
| 153 | |||
| 154 | test "assignment operators" { | ||
| 155 | var i: u32 = 0; | ||
| 156 | i += 5; | ||
| 157 | try expect(i == 5); | ||
| 158 | i -= 2; | ||
| 159 | try expect(i == 3); | ||
| 160 | i *= 20; | ||
| 161 | try expect(i == 60); | ||
| 162 | i /= 3; | ||
| 163 | try expect(i == 20); | ||
| 164 | i %= 11; | ||
| 165 | try expect(i == 9); | ||
| 166 | i <<= 1; | ||
| 167 | try expect(i == 18); | ||
| 168 | i >>= 2; | ||
| 169 | try expect(i == 4); | ||
| 170 | i = 6; | ||
| 171 | i &= 5; | ||
| 172 | try expect(i == 4); | ||
| 173 | i ^= 6; | ||
| 174 | try expect(i == 2); | ||
| 175 | i = 6; | ||
| 176 | i |= 3; | ||
| 177 | try expect(i == 7); | ||
| 178 | } | ||
| 179 | |||
| 180 | test "three expr in a row" { | ||
| 181 | try testThreeExprInARow(false, true); | ||
| 182 | comptime try testThreeExprInARow(false, true); | ||
| 183 | } | ||
| 184 | fn testThreeExprInARow(f: bool, t: bool) !void { | ||
| 185 | try assertFalse(f or f or f); | ||
| 186 | try assertFalse(t and t and f); | ||
| 187 | try assertFalse(1 | 2 | 4 != 7); | ||
| 188 | try assertFalse(3 ^ 6 ^ 8 != 13); | ||
| 189 | try assertFalse(7 & 14 & 28 != 4); | ||
| 190 | try assertFalse(9 << 1 << 2 != 9 << 3); | ||
| 191 | try assertFalse(90 >> 1 >> 2 != 90 >> 3); | ||
| 192 | try assertFalse(100 - 1 + 1000 != 1099); | ||
| 193 | try assertFalse(5 * 4 / 2 % 3 != 1); | ||
| 194 | try assertFalse(@as(i32, @as(i32, 5)) != 5); | ||
| 195 | try assertFalse(!!false); | ||
| 196 | try assertFalse(@as(i32, 7) != --(@as(i32, 7))); | ||
| 197 | } | ||
| 198 | fn assertFalse(b: bool) !void { | ||
| 199 | try expect(!b); | ||
| 200 | } | ||
| 201 | |||
| 202 | test "const number literal" { | ||
| 203 | const one = 1; | ||
| 204 | const eleven = ten + one; | ||
| 205 | |||
| 206 | try expect(eleven == 11); | ||
| 207 | } | ||
| 208 | const ten = 10; | ||
| 209 | |||
| 210 | test "unsigned wrapping" { | ||
| 211 | try testUnsignedWrappingEval(maxInt(u32)); | ||
| 212 | comptime try testUnsignedWrappingEval(maxInt(u32)); | ||
| 213 | } | ||
| 214 | fn testUnsignedWrappingEval(x: u32) !void { | ||
| 215 | const zero = x +% 1; | ||
| 216 | try expect(zero == 0); | ||
| 217 | const orig = zero -% 1; | ||
| 218 | try expect(orig == maxInt(u32)); | ||
| 219 | } | ||
| 220 | |||
| 221 | test "signed wrapping" { | ||
| 222 | try testSignedWrappingEval(maxInt(i32)); | ||
| 223 | comptime try testSignedWrappingEval(maxInt(i32)); | ||
| 224 | } | ||
| 225 | fn testSignedWrappingEval(x: i32) !void { | ||
| 226 | const min_val = x +% 1; | ||
| 227 | try expect(min_val == minInt(i32)); | ||
| 228 | const max_val = min_val -% 1; | ||
| 229 | try expect(max_val == maxInt(i32)); | ||
| 230 | } | ||
| 231 | |||
| 232 | test "signed negation wrapping" { | ||
| 233 | try testSignedNegationWrappingEval(minInt(i16)); | ||
| 234 | comptime try testSignedNegationWrappingEval(minInt(i16)); | ||
| 235 | } | ||
| 236 | fn testSignedNegationWrappingEval(x: i16) !void { | ||
| 237 | try expect(x == -32768); | ||
| 238 | const neg = -%x; | ||
| 239 | try expect(neg == -32768); | ||
| 240 | } | ||
| 241 | |||
| 242 | test "unsigned negation wrapping" { | ||
| 243 | try testUnsignedNegationWrappingEval(1); | ||
| 244 | comptime try testUnsignedNegationWrappingEval(1); | ||
| 245 | } | ||
| 246 | fn testUnsignedNegationWrappingEval(x: u16) !void { | ||
| 247 | try expect(x == 1); | ||
| 248 | const neg = -%x; | ||
| 249 | try expect(neg == maxInt(u16)); | ||
| 250 | } | ||
| 251 | |||
| 252 | test "unsigned 64-bit division" { | ||
| 253 | try test_u64_div(); | ||
| 254 | comptime try test_u64_div(); | ||
| 255 | } | ||
| 256 | fn test_u64_div() !void { | ||
| 257 | const result = divWithResult(1152921504606846976, 34359738365); | ||
| 258 | try expect(result.quotient == 33554432); | ||
| 259 | try expect(result.remainder == 100663296); | ||
| 260 | } | ||
| 261 | fn divWithResult(a: u64, b: u64) DivResult { | ||
| 262 | return DivResult{ | ||
| 263 | .quotient = a / b, | ||
| 264 | .remainder = a % b, | ||
| 265 | }; | ||
| 266 | } | ||
| 267 | const DivResult = struct { | ||
| 268 | quotient: u64, | ||
| 269 | remainder: u64, | ||
| 270 | }; | ||
| 271 | |||
| 272 | test "binary not" { | ||
| 273 | try expect(comptime x: { | ||
| 274 | break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101; | ||
| 275 | }); | ||
| 276 | try expect(comptime x: { | ||
| 277 | break :x ~@as(u64, 2147483647) == 18446744071562067968; | ||
| 278 | }); | ||
| 279 | try testBinaryNot(0b1010101010101010); | ||
| 280 | } | ||
| 281 | |||
| 282 | fn testBinaryNot(x: u16) !void { | ||
| 283 | try expect(~x == 0b0101010101010101); | ||
| 284 | } | ||
| 285 | |||
| 286 | test "small int addition" { | ||
| 287 | var x: u2 = 0; | ||
| 288 | try expect(x == 0); | ||
| 289 | |||
| 290 | x += 1; | ||
| 291 | try expect(x == 1); | ||
| 292 | |||
| 293 | x += 1; | ||
| 294 | try expect(x == 2); | ||
| 295 | |||
| 296 | x += 1; | ||
| 297 | try expect(x == 3); | ||
| 298 | |||
| 299 | var result: @TypeOf(x) = 3; | ||
| 300 | try expect(@addWithOverflow(@TypeOf(x), x, 1, &result)); | ||
| 301 | |||
| 302 | try expect(result == 0); | ||
| 303 | } | ||
| 304 | |||
| 305 | test "float equality" { | ||
| 306 | const x: f64 = 0.012; | ||
| 307 | const y: f64 = x + 1.0; | ||
| 308 | |||
| 309 | try testFloatEqualityImpl(x, y); | ||
| 310 | comptime try testFloatEqualityImpl(x, y); | ||
| 311 | } | ||
| 312 | |||
| 313 | fn testFloatEqualityImpl(x: f64, y: f64) !void { | ||
| 314 | const y2 = x + 1.0; | ||
| 315 | try expect(y == y2); | ||
| 316 | } | ||
| 317 | |||
| 318 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { | ||
| 319 | try expect(5 / 3 == 1); | ||
| 320 | try expect(-5 / -3 == 1); | ||
| 321 | try expect(-6 / 3 == -2); | ||
| 322 | |||
| 323 | try expect(5 % 3 == 2); | ||
| 324 | try expect(-6 % 3 == 0); | ||
| 325 | } | ||
| 326 | |||
| 327 | test "hex float literal parsing" { | ||
| 328 | comptime try expect(0x1.0 == 1.0); | ||
| 329 | } | ||
| 330 | |||
| 331 | test "quad hex float literal parsing in range" { | ||
| 332 | const a = 0x1.af23456789bbaaab347645365cdep+5; | ||
| 333 | const b = 0x1.dedafcff354b6ae9758763545432p-9; | ||
| 334 | const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; | ||
| 335 | const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; | ||
| 336 | } | ||
| 337 | |||
| 338 | test "quad hex float literal parsing accurate" { | ||
| 339 | const a: f128 = 0x1.1111222233334444555566667777p+0; | ||
| 340 | |||
| 341 | // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. | ||
| 342 | const expected: u128 = 0x3fff1111222233334444555566667777; | ||
| 343 | try expect(@bitCast(u128, a) == expected); | ||
| 344 | |||
| 345 | // non-normalized | ||
| 346 | const b: f128 = 0x11.111222233334444555566667777p-4; | ||
| 347 | try expect(@bitCast(u128, b) == expected); | ||
| 348 | |||
| 349 | const S = struct { | ||
| 350 | fn doTheTest() !void { | ||
| 351 | { | ||
| 352 | var f: f128 = 0x1.2eab345678439abcdefea56782346p+5; | ||
| 353 | try expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234); | ||
| 354 | } | ||
| 355 | { | ||
| 356 | var f: f128 = 0x1.edcb34a235253948765432134674fp-1; | ||
| 357 | try expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674); | ||
| 358 | } | ||
| 359 | { | ||
| 360 | var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50; | ||
| 361 | try expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff50); | ||
| 362 | } | ||
| 363 | { | ||
| 364 | var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9; | ||
| 365 | try expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214568); | ||
| 366 | } | ||
| 367 | const exp2ft = [_]f64{ | ||
| 368 | 0x1.6a09e667f3bcdp-1, | ||
| 369 | 0x1.7a11473eb0187p-1, | ||
| 370 | 0x1.8ace5422aa0dbp-1, | ||
| 371 | 0x1.9c49182a3f090p-1, | ||
| 372 | 0x1.ae89f995ad3adp-1, | ||
| 373 | 0x1.c199bdd85529cp-1, | ||
| 374 | 0x1.d5818dcfba487p-1, | ||
| 375 | 0x1.ea4afa2a490dap-1, | ||
| 376 | 0x1.0000000000000p+0, | ||
| 377 | 0x1.0b5586cf9890fp+0, | ||
| 378 | 0x1.172b83c7d517bp+0, | ||
| 379 | 0x1.2387a6e756238p+0, | ||
| 380 | 0x1.306fe0a31b715p+0, | ||
| 381 | 0x1.3dea64c123422p+0, | ||
| 382 | 0x1.4bfdad5362a27p+0, | ||
| 383 | 0x1.5ab07dd485429p+0, | ||
| 384 | 0x1.8p23, | ||
| 385 | 0x1.62e430p-1, | ||
| 386 | 0x1.ebfbe0p-3, | ||
| 387 | 0x1.c6b348p-5, | ||
| 388 | 0x1.3b2c9cp-7, | ||
| 389 | 0x1.0p127, | ||
| 390 | -0x1.0p-149, | ||
| 391 | }; | ||
| 392 | |||
| 393 | const answers = [_]u64{ | ||
| 394 | 0x3fe6a09e667f3bcd, | ||
| 395 | 0x3fe7a11473eb0187, | ||
| 396 | 0x3fe8ace5422aa0db, | ||
| 397 | 0x3fe9c49182a3f090, | ||
| 398 | 0x3feae89f995ad3ad, | ||
| 399 | 0x3fec199bdd85529c, | ||
| 400 | 0x3fed5818dcfba487, | ||
| 401 | 0x3feea4afa2a490da, | ||
| 402 | 0x3ff0000000000000, | ||
| 403 | 0x3ff0b5586cf9890f, | ||
| 404 | 0x3ff172b83c7d517b, | ||
| 405 | 0x3ff2387a6e756238, | ||
| 406 | 0x3ff306fe0a31b715, | ||
| 407 | 0x3ff3dea64c123422, | ||
| 408 | 0x3ff4bfdad5362a27, | ||
| 409 | 0x3ff5ab07dd485429, | ||
| 410 | 0x4168000000000000, | ||
| 411 | 0x3fe62e4300000000, | ||
| 412 | 0x3fcebfbe00000000, | ||
| 413 | 0x3fac6b3480000000, | ||
| 414 | 0x3f83b2c9c0000000, | ||
| 415 | 0x47e0000000000000, | ||
| 416 | 0xb6a0000000000000, | ||
| 417 | }; | ||
| 418 | |||
| 419 | for (exp2ft) |x, i| { | ||
| 420 | try expect(@bitCast(u64, x) == answers[i]); | ||
| 421 | } | ||
| 422 | } | ||
| 423 | }; | ||
| 424 | try S.doTheTest(); | ||
| 425 | comptime try S.doTheTest(); | ||
| 426 | } | ||
| 427 | |||
| 428 | test "underscore separator parsing" { | ||
| 429 | try expect(0_0_0_0 == 0); | ||
| 430 | try expect(1_234_567 == 1234567); | ||
| 431 | try expect(001_234_567 == 1234567); | ||
| 432 | try expect(0_0_1_2_3_4_5_6_7 == 1234567); | ||
| 433 | |||
| 434 | try expect(0b0_0_0_0 == 0); | ||
| 435 | try expect(0b1010_1010 == 0b10101010); | ||
| 436 | try expect(0b0000_1010_1010 == 0b10101010); | ||
| 437 | try expect(0b1_0_1_0_1_0_1_0 == 0b10101010); | ||
| 438 | |||
| 439 | try expect(0o0_0_0_0 == 0); | ||
| 440 | try expect(0o1010_1010 == 0o10101010); | ||
| 441 | try expect(0o0000_1010_1010 == 0o10101010); | ||
| 442 | try expect(0o1_0_1_0_1_0_1_0 == 0o10101010); | ||
| 443 | |||
| 444 | try expect(0x0_0_0_0 == 0); | ||
| 445 | try expect(0x1010_1010 == 0x10101010); | ||
| 446 | try expect(0x0000_1010_1010 == 0x10101010); | ||
| 447 | try expect(0x1_0_1_0_1_0_1_0 == 0x10101010); | ||
| 448 | |||
| 449 | try expect(123_456.789_000e1_0 == 123456.789000e10); | ||
| 450 | try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10); | ||
| 451 | |||
| 452 | try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10); | ||
| 453 | try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10); | ||
| 454 | } | ||
| 455 | |||
| 456 | test "hex float literal within range" { | ||
| 457 | const a = 0x1.0p16383; | ||
| 458 | const b = 0x0.1p16387; | ||
| 459 | const c = 0x1.0p-16382; | ||
| 460 | } | ||
| 461 | |||
| 462 | test "truncating shift left" { | ||
| 463 | try testShlTrunc(maxInt(u16)); | ||
| 464 | comptime try testShlTrunc(maxInt(u16)); | ||
| 465 | } | ||
| 466 | fn testShlTrunc(x: u16) !void { | ||
| 467 | const shifted = x << 1; | ||
| 468 | try expect(shifted == 65534); | ||
| 469 | } | ||
| 470 | |||
| 471 | test "truncating shift right" { | ||
| 472 | try testShrTrunc(maxInt(u16)); | ||
| 473 | comptime try testShrTrunc(maxInt(u16)); | ||
| 474 | } | ||
| 475 | fn testShrTrunc(x: u16) !void { | ||
| 476 | const shifted = x >> 1; | ||
| 477 | try expect(shifted == 32767); | ||
| 478 | } | ||
| 479 | |||
| 480 | test "exact shift left" { | ||
| 481 | try testShlExact(0b00110101); | ||
| 482 | comptime try testShlExact(0b00110101); | ||
| 483 | } | ||
| 484 | fn testShlExact(x: u8) !void { | ||
| 485 | const shifted = @shlExact(x, 2); | ||
| 486 | try expect(shifted == 0b11010100); | ||
| 487 | } | ||
| 488 | |||
| 489 | test "exact shift right" { | ||
| 490 | try testShrExact(0b10110100); | ||
| 491 | comptime try testShrExact(0b10110100); | ||
| 492 | } | ||
| 493 | fn testShrExact(x: u8) !void { | ||
| 494 | const shifted = @shrExact(x, 2); | ||
| 495 | try expect(shifted == 0b00101101); | ||
| 496 | } | ||
| 497 | |||
| 498 | test "shift left/right on u0 operand" { | ||
| 499 | const S = struct { | ||
| 500 | fn doTheTest() !void { | ||
| 501 | var x: u0 = 0; | ||
| 502 | var y: u0 = 0; | ||
| 503 | try expectEqual(@as(u0, 0), x << 0); | ||
| 504 | try expectEqual(@as(u0, 0), x >> 0); | ||
| 505 | try expectEqual(@as(u0, 0), x << y); | ||
| 506 | try expectEqual(@as(u0, 0), x >> y); | ||
| 507 | try expectEqual(@as(u0, 0), @shlExact(x, 0)); | ||
| 508 | try expectEqual(@as(u0, 0), @shrExact(x, 0)); | ||
| 509 | try expectEqual(@as(u0, 0), @shlExact(x, y)); | ||
| 510 | try expectEqual(@as(u0, 0), @shrExact(x, y)); | ||
| 511 | } | ||
| 512 | }; | ||
| 513 | try S.doTheTest(); | ||
| 514 | comptime try S.doTheTest(); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "comptime_int addition" { | ||
| 518 | comptime { | ||
| 519 | try expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); | ||
| 520 | try expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | test "comptime_int multiplication" { | ||
| 525 | comptime { | ||
| 526 | try expect( | ||
| 527 | 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, | ||
| 528 | ); | ||
| 529 | try expect( | ||
| 530 | 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, | ||
| 531 | ); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | test "comptime_int shifting" { | ||
| 536 | comptime { | ||
| 537 | try expect((@as(u128, 1) << 127) == 0x80000000000000000000000000000000); | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | test "comptime_int multi-limb shift and mask" { | ||
| 542 | comptime { | ||
| 543 | var a = 0xefffffffa0000001eeeeeeefaaaaaaab; | ||
| 544 | |||
| 545 | try expect(@as(u32, a & 0xffffffff) == 0xaaaaaaab); | ||
| 546 | a >>= 32; | ||
| 547 | try expect(@as(u32, a & 0xffffffff) == 0xeeeeeeef); | ||
| 548 | a >>= 32; | ||
| 549 | try expect(@as(u32, a & 0xffffffff) == 0xa0000001); | ||
| 550 | a >>= 32; | ||
| 551 | try expect(@as(u32, a & 0xffffffff) == 0xefffffff); | ||
| 552 | a >>= 32; | ||
| 553 | |||
| 554 | try expect(a == 0); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | test "comptime_int multi-limb partial shift right" { | ||
| 559 | comptime { | ||
| 560 | var a = 0x1ffffffffeeeeeeee; | ||
| 561 | a >>= 16; | ||
| 562 | try expect(a == 0x1ffffffffeeee); | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | test "xor" { | ||
| 567 | try test_xor(); | ||
| 568 | comptime try test_xor(); | ||
| 569 | } | ||
| 570 | |||
| 571 | fn test_xor() !void { | ||
| 572 | try expect(0xFF ^ 0x00 == 0xFF); | ||
| 573 | try expect(0xF0 ^ 0x0F == 0xFF); | ||
| 574 | try expect(0xFF ^ 0xF0 == 0x0F); | ||
| 575 | try expect(0xFF ^ 0x0F == 0xF0); | ||
| 576 | try expect(0xFF ^ 0xFF == 0x00); | ||
| 577 | } | ||
| 578 | |||
| 579 | test "comptime_int xor" { | ||
| 580 | comptime { | ||
| 581 | try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 582 | try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 583 | try expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); | ||
| 584 | try expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); | ||
| 585 | try expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); | ||
| 586 | try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); | ||
| 587 | try expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); | ||
| 588 | try expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | test "f128" { | ||
| 593 | try test_f128(); | ||
| 594 | comptime try test_f128(); | ||
| 595 | } | ||
| 596 | |||
| 597 | fn make_f128(x: f128) f128 { | ||
| 598 | return x; | ||
| 599 | } | ||
| 600 | |||
| 601 | fn test_f128() !void { | ||
| 602 | try expect(@sizeOf(f128) == 16); | ||
| 603 | try expect(make_f128(1.0) == 1.0); | ||
| 604 | try expect(make_f128(1.0) != 1.1); | ||
| 605 | try expect(make_f128(1.0) > 0.9); | ||
| 606 | try expect(make_f128(1.0) >= 0.9); | ||
| 607 | try expect(make_f128(1.0) >= 1.0); | ||
| 608 | try should_not_be_zero(1.0); | ||
| 609 | } | ||
| 610 | |||
| 611 | fn should_not_be_zero(x: f128) !void { | ||
| 612 | try expect(x != 0.0); | ||
| 613 | } | ||
| 614 | |||
| 615 | test "comptime float rem int" { | ||
| 616 | comptime { | ||
| 617 | var x = @as(f32, 1) % 2; | ||
| 618 | try expect(x == 1.0); | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | test "remainder division" { | ||
| 623 | comptime try remdiv(f16); | ||
| 624 | comptime try remdiv(f32); | ||
| 625 | comptime try remdiv(f64); | ||
| 626 | comptime try remdiv(f128); | ||
| 627 | try remdiv(f16); | ||
| 628 | try remdiv(f64); | ||
| 629 | try remdiv(f128); | ||
| 630 | } | ||
| 631 | |||
| 632 | fn remdiv(comptime T: type) !void { | ||
| 633 | try expect(@as(T, 1) == @as(T, 1) % @as(T, 2)); | ||
| 634 | try expect(@as(T, 1) == @as(T, 7) % @as(T, 3)); | ||
| 635 | } | ||
| 636 | |||
| 637 | test "@sqrt" { | ||
| 638 | try testSqrt(f64, 12.0); | ||
| 639 | comptime try testSqrt(f64, 12.0); | ||
| 640 | try testSqrt(f32, 13.0); | ||
| 641 | comptime try testSqrt(f32, 13.0); | ||
| 642 | try testSqrt(f16, 13.0); | ||
| 643 | comptime try testSqrt(f16, 13.0); | ||
| 644 | |||
| 645 | const x = 14.0; | ||
| 646 | const y = x * x; | ||
| 647 | const z = @sqrt(y); | ||
| 648 | comptime try expect(z == x); | ||
| 649 | } | ||
| 650 | |||
| 651 | fn testSqrt(comptime T: type, x: T) !void { | ||
| 652 | try expect(@sqrt(x * x) == x); | ||
| 653 | } | ||
| 654 | |||
| 655 | test "@fabs" { | ||
| 656 | try testFabs(f128, 12.0); | ||
| 657 | comptime try testFabs(f128, 12.0); | ||
| 658 | try testFabs(f64, 12.0); | ||
| 659 | comptime try testFabs(f64, 12.0); | ||
| 660 | try testFabs(f32, 12.0); | ||
| 661 | comptime try testFabs(f32, 12.0); | ||
| 662 | try testFabs(f16, 12.0); | ||
| 663 | comptime try testFabs(f16, 12.0); | ||
| 664 | |||
| 665 | const x = 14.0; | ||
| 666 | const y = -x; | ||
| 667 | const z = @fabs(y); | ||
| 668 | comptime try expectEqual(x, z); | ||
| 669 | } | ||
| 670 | |||
| 671 | fn testFabs(comptime T: type, x: T) !void { | ||
| 672 | const y = -x; | ||
| 673 | const z = @fabs(y); | ||
| 674 | try expectEqual(x, z); | ||
| 675 | } | ||
| 676 | |||
| 677 | test "@floor" { | ||
| 678 | // FIXME: Generates a floorl function call | ||
| 679 | // testFloor(f128, 12.0); | ||
| 680 | comptime try testFloor(f128, 12.0); | ||
| 681 | try testFloor(f64, 12.0); | ||
| 682 | comptime try testFloor(f64, 12.0); | ||
| 683 | try testFloor(f32, 12.0); | ||
| 684 | comptime try testFloor(f32, 12.0); | ||
| 685 | try testFloor(f16, 12.0); | ||
| 686 | comptime try testFloor(f16, 12.0); | ||
| 687 | |||
| 688 | const x = 14.0; | ||
| 689 | const y = x + 0.7; | ||
| 690 | const z = @floor(y); | ||
| 691 | comptime try expectEqual(x, z); | ||
| 692 | } | ||
| 693 | |||
| 694 | fn testFloor(comptime T: type, x: T) !void { | ||
| 695 | const y = x + 0.6; | ||
| 696 | const z = @floor(y); | ||
| 697 | try expectEqual(x, z); | ||
| 698 | } | ||
| 699 | |||
| 700 | test "@ceil" { | ||
| 701 | // FIXME: Generates a ceill function call | ||
| 702 | //testCeil(f128, 12.0); | ||
| 703 | comptime try testCeil(f128, 12.0); | ||
| 704 | try testCeil(f64, 12.0); | ||
| 705 | comptime try testCeil(f64, 12.0); | ||
| 706 | try testCeil(f32, 12.0); | ||
| 707 | comptime try testCeil(f32, 12.0); | ||
| 708 | try testCeil(f16, 12.0); | ||
| 709 | comptime try testCeil(f16, 12.0); | ||
| 710 | |||
| 711 | const x = 14.0; | ||
| 712 | const y = x - 0.7; | ||
| 713 | const z = @ceil(y); | ||
| 714 | comptime try expectEqual(x, z); | ||
| 715 | } | ||
| 716 | |||
| 717 | fn testCeil(comptime T: type, x: T) !void { | ||
| 718 | const y = x - 0.8; | ||
| 719 | const z = @ceil(y); | ||
| 720 | try expectEqual(x, z); | ||
| 721 | } | ||
| 722 | |||
| 723 | test "@trunc" { | ||
| 724 | // FIXME: Generates a truncl function call | ||
| 725 | //testTrunc(f128, 12.0); | ||
| 726 | comptime try testTrunc(f128, 12.0); | ||
| 727 | try testTrunc(f64, 12.0); | ||
| 728 | comptime try testTrunc(f64, 12.0); | ||
| 729 | try testTrunc(f32, 12.0); | ||
| 730 | comptime try testTrunc(f32, 12.0); | ||
| 731 | try testTrunc(f16, 12.0); | ||
| 732 | comptime try testTrunc(f16, 12.0); | ||
| 733 | |||
| 734 | const x = 14.0; | ||
| 735 | const y = x + 0.7; | ||
| 736 | const z = @trunc(y); | ||
| 737 | comptime try expectEqual(x, z); | ||
| 738 | } | ||
| 739 | |||
| 740 | fn testTrunc(comptime T: type, x: T) !void { | ||
| 741 | { | ||
| 742 | const y = x + 0.8; | ||
| 743 | const z = @trunc(y); | ||
| 744 | try expectEqual(x, z); | ||
| 745 | } | ||
| 746 | |||
| 747 | { | ||
| 748 | const y = -x - 0.8; | ||
| 749 | const z = @trunc(y); | ||
| 750 | try expectEqual(-x, z); | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | test "@round" { | ||
| 755 | // FIXME: Generates a roundl function call | ||
| 756 | //testRound(f128, 12.0); | ||
| 757 | comptime try testRound(f128, 12.0); | ||
| 758 | try testRound(f64, 12.0); | ||
| 759 | comptime try testRound(f64, 12.0); | ||
| 760 | try testRound(f32, 12.0); | ||
| 761 | comptime try testRound(f32, 12.0); | ||
| 762 | try testRound(f16, 12.0); | ||
| 763 | comptime try testRound(f16, 12.0); | ||
| 764 | |||
| 765 | const x = 14.0; | ||
| 766 | const y = x + 0.4; | ||
| 767 | const z = @round(y); | ||
| 768 | comptime try expectEqual(x, z); | ||
| 769 | } | ||
| 770 | |||
| 771 | fn testRound(comptime T: type, x: T) !void { | ||
| 772 | const y = x - 0.5; | ||
| 773 | const z = @round(y); | ||
| 774 | try expectEqual(x, z); | ||
| 775 | } | ||
| 776 | |||
| 777 | test "comptime_int param and return" { | ||
| 778 | const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); | ||
| 779 | try expect(a == 137114567242441932203689521744947848950); | ||
| 780 | |||
| 781 | const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); | ||
| 782 | try expect(b == 985095453608931032642182098849559179469148836107390954364380); | ||
| 783 | } | ||
| 784 | |||
| 785 | fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { | ||
| 786 | return a + b; | ||
| 787 | } | ||
| 788 | |||
| 789 | test "vector integer addition" { | ||
| 790 | const S = struct { | ||
| 791 | fn doTheTest() !void { | ||
| 792 | var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; | ||
| 793 | var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; | ||
| 794 | var result = a + b; | ||
| 795 | var result_array: [4]i32 = result; | ||
| 796 | const expected = [_]i32{ 6, 8, 10, 12 }; | ||
| 797 | try expectEqualSlices(i32, &expected, &result_array); | ||
| 798 | } | ||
| 799 | }; | ||
| 800 | try S.doTheTest(); | ||
| 801 | comptime try S.doTheTest(); | ||
| 802 | } | ||
| 803 | |||
| 804 | test "NaN comparison" { | ||
| 805 | try testNanEqNan(f16); | ||
| 806 | try testNanEqNan(f32); | ||
| 807 | try testNanEqNan(f64); | ||
| 808 | try testNanEqNan(f128); | ||
| 809 | comptime try testNanEqNan(f16); | ||
| 810 | comptime try testNanEqNan(f32); | ||
| 811 | comptime try testNanEqNan(f64); | ||
| 812 | comptime try testNanEqNan(f128); | ||
| 813 | } | ||
| 814 | |||
| 815 | fn testNanEqNan(comptime F: type) !void { | ||
| 816 | var nan1 = std.math.nan(F); | ||
| 817 | var nan2 = std.math.nan(F); | ||
| 818 | try expect(nan1 != nan2); | ||
| 819 | try expect(!(nan1 == nan2)); | ||
| 820 | try expect(!(nan1 > nan2)); | ||
| 821 | try expect(!(nan1 >= nan2)); | ||
| 822 | try expect(!(nan1 < nan2)); | ||
| 823 | try expect(!(nan1 <= nan2)); | ||
| 824 | } | ||
| 825 | |||
| 826 | test "128-bit multiplication" { | ||
| 827 | var a: i128 = 3; | ||
| 828 | var b: i128 = 2; | ||
| 829 | var c = a * b; | ||
| 830 | try expect(c == 6); | ||
| 831 | } | ||
| 832 | |||
| 833 | test "vector comparison" { | ||
| 834 | const S = struct { | ||
| 835 | fn doTheTest() !void { | ||
| 836 | var a: std.meta.Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 }; | ||
| 837 | var b: std.meta.Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 }; | ||
| 838 | try expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false })); | ||
| 839 | try expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false })); | ||
| 840 | try expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false })); | ||
| 841 | try expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true })); | ||
| 842 | try expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true })); | ||
| 843 | try expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true })); | ||
| 844 | } | ||
| 845 | }; | ||
| 846 | try S.doTheTest(); | ||
| 847 | comptime try S.doTheTest(); | ||
| 848 | } | ||
| 849 | |||
| 850 | test "compare undefined literal with comptime_int" { | ||
| 851 | var x = undefined == 1; | ||
| 852 | // x is now undefined with type bool | ||
| 853 | x = true; | ||
| 854 | try expect(x); | ||
| 855 | } | ||
| 856 | |||
| 857 | test "signed zeros are represented properly" { | ||
| 858 | const S = struct { | ||
| 859 | fn doTheTest() !void { | ||
| 860 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | ||
| 861 | const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | ||
| 862 | var as_fp_val = -@as(T, 0.0); | ||
| 863 | var as_uint_val = @bitCast(ST, as_fp_val); | ||
| 864 | // Ensure the sign bit is set. | ||
| 865 | try expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1); | ||
| 866 | } | ||
| 867 | } | ||
| 868 | }; | ||
| 869 | |||
| 870 | try S.doTheTest(); | ||
| 871 | comptime try S.doTheTest(); | ||
| 872 | } | ||
test/stage1/behavior/merge_error_sets.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const A = error{ | ||
| 2 | FileNotFound, | ||
| 3 | NotDir, | ||
| 4 | }; | ||
| 5 | const B = error{OutOfMemory}; | ||
| 6 | |||
| 7 | const C = A || B; | ||
| 8 | |||
| 9 | fn foo() C!void { | ||
| 10 | return error.NotDir; | ||
| 11 | } | ||
| 12 | |||
| 13 | test "merge error sets" { | ||
| 14 | if (foo()) { | ||
| 15 | @panic("unexpected"); | ||
| 16 | } else |err| switch (err) { | ||
| 17 | error.OutOfMemory => @panic("unexpected"), | ||
| 18 | error.FileNotFound => @panic("unexpected"), | ||
| 19 | error.NotDir => {}, | ||
| 20 | } | ||
| 21 | } | ||
test/stage1/behavior/misc.zig deleted-761| ... | @@ -1,761 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const mem = std.mem; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | |||
| 7 | // normal comment | ||
| 8 | |||
| 9 | /// this is a documentation comment | ||
| 10 | /// doc comment line 2 | ||
| 11 | fn emptyFunctionWithComments() void {} | ||
| 12 | |||
| 13 | test "empty function with comments" { | ||
| 14 | emptyFunctionWithComments(); | ||
| 15 | } | ||
| 16 | |||
| 17 | comptime { | ||
| 18 | @export(disabledExternFn, .{ .name = "disabledExternFn", .linkage = .Internal }); | ||
| 19 | } | ||
| 20 | |||
| 21 | fn disabledExternFn() callconv(.C) void {} | ||
| 22 | |||
| 23 | test "call disabled extern fn" { | ||
| 24 | disabledExternFn(); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "short circuit" { | ||
| 28 | try testShortCircuit(false, true); | ||
| 29 | comptime try testShortCircuit(false, true); | ||
| 30 | } | ||
| 31 | |||
| 32 | fn testShortCircuit(f: bool, t: bool) !void { | ||
| 33 | var hit_1 = f; | ||
| 34 | var hit_2 = f; | ||
| 35 | var hit_3 = f; | ||
| 36 | var hit_4 = f; | ||
| 37 | |||
| 38 | if (t or x: { | ||
| 39 | try expect(f); | ||
| 40 | break :x f; | ||
| 41 | }) { | ||
| 42 | hit_1 = t; | ||
| 43 | } | ||
| 44 | if (f or x: { | ||
| 45 | hit_2 = t; | ||
| 46 | break :x f; | ||
| 47 | }) { | ||
| 48 | try expect(f); | ||
| 49 | } | ||
| 50 | |||
| 51 | if (t and x: { | ||
| 52 | hit_3 = t; | ||
| 53 | break :x f; | ||
| 54 | }) { | ||
| 55 | try expect(f); | ||
| 56 | } | ||
| 57 | if (f and x: { | ||
| 58 | try expect(f); | ||
| 59 | break :x f; | ||
| 60 | }) { | ||
| 61 | try expect(f); | ||
| 62 | } else { | ||
| 63 | hit_4 = t; | ||
| 64 | } | ||
| 65 | try expect(hit_1); | ||
| 66 | try expect(hit_2); | ||
| 67 | try expect(hit_3); | ||
| 68 | try expect(hit_4); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "truncate" { | ||
| 72 | try expect(testTruncate(0x10fd) == 0xfd); | ||
| 73 | } | ||
| 74 | fn testTruncate(x: u32) u8 { | ||
| 75 | return @truncate(u8, x); | ||
| 76 | } | ||
| 77 | |||
| 78 | fn first4KeysOfHomeRow() []const u8 { | ||
| 79 | return "aoeu"; | ||
| 80 | } | ||
| 81 | |||
| 82 | test "return string from function" { | ||
| 83 | try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 84 | } | ||
| 85 | |||
| 86 | const g1: i32 = 1233 + 1; | ||
| 87 | var g2: i32 = 0; | ||
| 88 | |||
| 89 | test "global variables" { | ||
| 90 | try expect(g2 == 0); | ||
| 91 | g2 = g1; | ||
| 92 | try expect(g2 == 1234); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "memcpy and memset intrinsics" { | ||
| 96 | var foo: [20]u8 = undefined; | ||
| 97 | var bar: [20]u8 = undefined; | ||
| 98 | |||
| 99 | @memset(&foo, 'A', foo.len); | ||
| 100 | @memcpy(&bar, &foo, bar.len); | ||
| 101 | |||
| 102 | if (bar[11] != 'A') unreachable; | ||
| 103 | } | ||
| 104 | |||
| 105 | test "builtin static eval" { | ||
| 106 | const x: i32 = comptime x: { | ||
| 107 | break :x 1 + 2 + 3; | ||
| 108 | }; | ||
| 109 | try expect(x == comptime 6); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "slicing" { | ||
| 113 | var array: [20]i32 = undefined; | ||
| 114 | |||
| 115 | array[5] = 1234; | ||
| 116 | |||
| 117 | var slice = array[5..10]; | ||
| 118 | |||
| 119 | if (slice.len != 5) unreachable; | ||
| 120 | |||
| 121 | const ptr = &slice[0]; | ||
| 122 | if (ptr.* != 1234) unreachable; | ||
| 123 | |||
| 124 | var slice_rest = array[10..]; | ||
| 125 | if (slice_rest.len != 10) unreachable; | ||
| 126 | } | ||
| 127 | |||
| 128 | test "constant equal function pointers" { | ||
| 129 | const alias = emptyFn; | ||
| 130 | try expect(comptime x: { | ||
| 131 | break :x emptyFn == alias; | ||
| 132 | }); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn emptyFn() void {} | ||
| 136 | |||
| 137 | test "hex escape" { | ||
| 138 | try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "string concatenation" { | ||
| 142 | try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); | ||
| 143 | } | ||
| 144 | |||
| 145 | test "array mult operator" { | ||
| 146 | try expect(mem.eql(u8, "ab" ** 5, "ababababab")); | ||
| 147 | } | ||
| 148 | |||
| 149 | test "string escapes" { | ||
| 150 | try expect(mem.eql(u8, "\"", "\x22")); | ||
| 151 | try expect(mem.eql(u8, "\'", "\x27")); | ||
| 152 | try expect(mem.eql(u8, "\n", "\x0a")); | ||
| 153 | try expect(mem.eql(u8, "\r", "\x0d")); | ||
| 154 | try expect(mem.eql(u8, "\t", "\x09")); | ||
| 155 | try expect(mem.eql(u8, "\\", "\x5c")); | ||
| 156 | try expect(mem.eql(u8, "\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01")); | ||
| 157 | } | ||
| 158 | |||
| 159 | test "multiline string" { | ||
| 160 | const s1 = | ||
| 161 | \\one | ||
| 162 | \\two) | ||
| 163 | \\three | ||
| 164 | ; | ||
| 165 | const s2 = "one\ntwo)\nthree"; | ||
| 166 | try expect(mem.eql(u8, s1, s2)); | ||
| 167 | } | ||
| 168 | |||
| 169 | test "multiline string comments at start" { | ||
| 170 | const s1 = | ||
| 171 | //\\one | ||
| 172 | \\two) | ||
| 173 | \\three | ||
| 174 | ; | ||
| 175 | const s2 = "two)\nthree"; | ||
| 176 | try expect(mem.eql(u8, s1, s2)); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "multiline string comments at end" { | ||
| 180 | const s1 = | ||
| 181 | \\one | ||
| 182 | \\two) | ||
| 183 | //\\three | ||
| 184 | ; | ||
| 185 | const s2 = "one\ntwo)"; | ||
| 186 | try expect(mem.eql(u8, s1, s2)); | ||
| 187 | } | ||
| 188 | |||
| 189 | test "multiline string comments in middle" { | ||
| 190 | const s1 = | ||
| 191 | \\one | ||
| 192 | //\\two) | ||
| 193 | \\three | ||
| 194 | ; | ||
| 195 | const s2 = "one\nthree"; | ||
| 196 | try expect(mem.eql(u8, s1, s2)); | ||
| 197 | } | ||
| 198 | |||
| 199 | test "multiline string comments at multiple places" { | ||
| 200 | const s1 = | ||
| 201 | \\one | ||
| 202 | //\\two | ||
| 203 | \\three | ||
| 204 | //\\four | ||
| 205 | \\five | ||
| 206 | ; | ||
| 207 | const s2 = "one\nthree\nfive"; | ||
| 208 | try expect(mem.eql(u8, s1, s2)); | ||
| 209 | } | ||
| 210 | |||
| 211 | test "multiline C string" { | ||
| 212 | const s1 = | ||
| 213 | \\one | ||
| 214 | \\two) | ||
| 215 | \\three | ||
| 216 | ; | ||
| 217 | const s2 = "one\ntwo)\nthree"; | ||
| 218 | try expect(std.cstr.cmp(s1, s2) == 0); | ||
| 219 | } | ||
| 220 | |||
| 221 | test "type equality" { | ||
| 222 | try expect(*const u8 != *u8); | ||
| 223 | } | ||
| 224 | |||
| 225 | const global_a: i32 = 1234; | ||
| 226 | const global_b: *const i32 = &global_a; | ||
| 227 | const global_c: *const f32 = @ptrCast(*const f32, global_b); | ||
| 228 | test "compile time global reinterpret" { | ||
| 229 | const d = @ptrCast(*const i32, global_c); | ||
| 230 | try expect(d.* == 1234); | ||
| 231 | } | ||
| 232 | |||
| 233 | test "explicit cast maybe pointers" { | ||
| 234 | const a: ?*i32 = undefined; | ||
| 235 | const b: ?*f32 = @ptrCast(?*f32, a); | ||
| 236 | } | ||
| 237 | |||
| 238 | test "generic malloc free" { | ||
| 239 | const a = memAlloc(u8, 10) catch unreachable; | ||
| 240 | memFree(u8, a); | ||
| 241 | } | ||
| 242 | var some_mem: [100]u8 = undefined; | ||
| 243 | fn memAlloc(comptime T: type, n: usize) anyerror![]T { | ||
| 244 | return @ptrCast([*]T, &some_mem[0])[0..n]; | ||
| 245 | } | ||
| 246 | fn memFree(comptime T: type, memory: []T) void {} | ||
| 247 | |||
| 248 | test "cast undefined" { | ||
| 249 | const array: [100]u8 = undefined; | ||
| 250 | const slice = @as([]const u8, &array); | ||
| 251 | testCastUndefined(slice); | ||
| 252 | } | ||
| 253 | fn testCastUndefined(x: []const u8) void {} | ||
| 254 | |||
| 255 | test "cast small unsigned to larger signed" { | ||
| 256 | try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200)); | ||
| 257 | try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999)); | ||
| 258 | } | ||
| 259 | fn castSmallUnsignedToLargerSigned1(x: u8) i16 { | ||
| 260 | return x; | ||
| 261 | } | ||
| 262 | fn castSmallUnsignedToLargerSigned2(x: u16) i64 { | ||
| 263 | return x; | ||
| 264 | } | ||
| 265 | |||
| 266 | test "implicit cast after unreachable" { | ||
| 267 | try expect(outer() == 1234); | ||
| 268 | } | ||
| 269 | fn inner() i32 { | ||
| 270 | return 1234; | ||
| 271 | } | ||
| 272 | fn outer() i64 { | ||
| 273 | return inner(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "pointer dereferencing" { | ||
| 277 | var x = @as(i32, 3); | ||
| 278 | const y = &x; | ||
| 279 | |||
| 280 | y.* += 1; | ||
| 281 | |||
| 282 | try expect(x == 4); | ||
| 283 | try expect(y.* == 4); | ||
| 284 | } | ||
| 285 | |||
| 286 | test "call result of if else expression" { | ||
| 287 | try expect(mem.eql(u8, f2(true), "a")); | ||
| 288 | try expect(mem.eql(u8, f2(false), "b")); | ||
| 289 | } | ||
| 290 | fn f2(x: bool) []const u8 { | ||
| 291 | return (if (x) fA else fB)(); | ||
| 292 | } | ||
| 293 | fn fA() []const u8 { | ||
| 294 | return "a"; | ||
| 295 | } | ||
| 296 | fn fB() []const u8 { | ||
| 297 | return "b"; | ||
| 298 | } | ||
| 299 | |||
| 300 | test "const expression eval handling of variables" { | ||
| 301 | var x = true; | ||
| 302 | while (x) { | ||
| 303 | x = false; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | test "constant enum initialization with differing sizes" { | ||
| 308 | try test3_1(test3_foo); | ||
| 309 | try test3_2(test3_bar); | ||
| 310 | } | ||
| 311 | const Test3Foo = union(enum) { | ||
| 312 | One: void, | ||
| 313 | Two: f32, | ||
| 314 | Three: Test3Point, | ||
| 315 | }; | ||
| 316 | const Test3Point = struct { | ||
| 317 | x: i32, | ||
| 318 | y: i32, | ||
| 319 | }; | ||
| 320 | const test3_foo = Test3Foo{ | ||
| 321 | .Three = Test3Point{ | ||
| 322 | .x = 3, | ||
| 323 | .y = 4, | ||
| 324 | }, | ||
| 325 | }; | ||
| 326 | const test3_bar = Test3Foo{ .Two = 13 }; | ||
| 327 | fn test3_1(f: Test3Foo) !void { | ||
| 328 | switch (f) { | ||
| 329 | Test3Foo.Three => |pt| { | ||
| 330 | try expect(pt.x == 3); | ||
| 331 | try expect(pt.y == 4); | ||
| 332 | }, | ||
| 333 | else => unreachable, | ||
| 334 | } | ||
| 335 | } | ||
| 336 | fn test3_2(f: Test3Foo) !void { | ||
| 337 | switch (f) { | ||
| 338 | Test3Foo.Two => |x| { | ||
| 339 | try expect(x == 13); | ||
| 340 | }, | ||
| 341 | else => unreachable, | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | test "character literals" { | ||
| 346 | try expect('\'' == single_quote); | ||
| 347 | } | ||
| 348 | const single_quote = '\''; | ||
| 349 | |||
| 350 | test "take address of parameter" { | ||
| 351 | try testTakeAddressOfParameter(12.34); | ||
| 352 | } | ||
| 353 | fn testTakeAddressOfParameter(f: f32) !void { | ||
| 354 | const f_ptr = &f; | ||
| 355 | try expect(f_ptr.* == 12.34); | ||
| 356 | } | ||
| 357 | |||
| 358 | test "pointer comparison" { | ||
| 359 | const a = @as([]const u8, "a"); | ||
| 360 | const b = &a; | ||
| 361 | try expect(ptrEql(b, b)); | ||
| 362 | } | ||
| 363 | fn ptrEql(a: *const []const u8, b: *const []const u8) bool { | ||
| 364 | return a == b; | ||
| 365 | } | ||
| 366 | |||
| 367 | test "string concatenation" { | ||
| 368 | const a = "OK" ++ " IT " ++ "WORKED"; | ||
| 369 | const b = "OK IT WORKED"; | ||
| 370 | |||
| 371 | comptime try expect(@TypeOf(a) == *const [12:0]u8); | ||
| 372 | comptime try expect(@TypeOf(b) == *const [12:0]u8); | ||
| 373 | |||
| 374 | const len = mem.len(b); | ||
| 375 | const len_with_null = len + 1; | ||
| 376 | { | ||
| 377 | var i: u32 = 0; | ||
| 378 | while (i < len_with_null) : (i += 1) { | ||
| 379 | try expect(a[i] == b[i]); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | try expect(a[len] == 0); | ||
| 383 | try expect(b[len] == 0); | ||
| 384 | } | ||
| 385 | |||
| 386 | test "pointer to void return type" { | ||
| 387 | testPointerToVoidReturnType() catch unreachable; | ||
| 388 | } | ||
| 389 | fn testPointerToVoidReturnType() anyerror!void { | ||
| 390 | const a = testPointerToVoidReturnType2(); | ||
| 391 | return a.*; | ||
| 392 | } | ||
| 393 | const test_pointer_to_void_return_type_x = void{}; | ||
| 394 | fn testPointerToVoidReturnType2() *const void { | ||
| 395 | return &test_pointer_to_void_return_type_x; | ||
| 396 | } | ||
| 397 | |||
| 398 | test "non const ptr to aliased type" { | ||
| 399 | const int = i32; | ||
| 400 | try expect(?*int == ?*i32); | ||
| 401 | } | ||
| 402 | |||
| 403 | test "array 2D const double ptr" { | ||
| 404 | const rect_2d_vertexes = [_][1]f32{ | ||
| 405 | [_]f32{1.0}, | ||
| 406 | [_]f32{2.0}, | ||
| 407 | }; | ||
| 408 | try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); | ||
| 409 | } | ||
| 410 | |||
| 411 | fn testArray2DConstDoublePtr(ptr: *const f32) !void { | ||
| 412 | const ptr2 = @ptrCast([*]const f32, ptr); | ||
| 413 | try expect(ptr2[0] == 1.0); | ||
| 414 | try expect(ptr2[1] == 2.0); | ||
| 415 | } | ||
| 416 | |||
| 417 | const AStruct = struct { | ||
| 418 | x: i32, | ||
| 419 | }; | ||
| 420 | const AnEnum = enum { | ||
| 421 | One, | ||
| 422 | Two, | ||
| 423 | }; | ||
| 424 | const AUnionEnum = union(enum) { | ||
| 425 | One: i32, | ||
| 426 | Two: void, | ||
| 427 | }; | ||
| 428 | const AUnion = union { | ||
| 429 | One: void, | ||
| 430 | Two: void, | ||
| 431 | }; | ||
| 432 | |||
| 433 | test "@typeName" { | ||
| 434 | const Struct = struct {}; | ||
| 435 | const Union = union { | ||
| 436 | unused: u8, | ||
| 437 | }; | ||
| 438 | const Enum = enum { | ||
| 439 | Unused, | ||
| 440 | }; | ||
| 441 | comptime { | ||
| 442 | try expect(mem.eql(u8, @typeName(i64), "i64")); | ||
| 443 | try expect(mem.eql(u8, @typeName(*usize), "*usize")); | ||
| 444 | // https://github.com/ziglang/zig/issues/675 | ||
| 445 | try expect(mem.eql(u8, "behavior.misc.TypeFromFn(u8)", @typeName(TypeFromFn(u8)))); | ||
| 446 | try expect(mem.eql(u8, @typeName(Struct), "Struct")); | ||
| 447 | try expect(mem.eql(u8, @typeName(Union), "Union")); | ||
| 448 | try expect(mem.eql(u8, @typeName(Enum), "Enum")); | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | fn TypeFromFn(comptime T: type) type { | ||
| 453 | return struct {}; | ||
| 454 | } | ||
| 455 | |||
| 456 | test "double implicit cast in same expression" { | ||
| 457 | var x = @as(i32, @as(u16, nine())); | ||
| 458 | try expect(x == 9); | ||
| 459 | } | ||
| 460 | fn nine() u8 { | ||
| 461 | return 9; | ||
| 462 | } | ||
| 463 | |||
| 464 | test "global variable initialized to global variable array element" { | ||
| 465 | try expect(global_ptr == &gdt[0]); | ||
| 466 | } | ||
| 467 | const GDTEntry = struct { | ||
| 468 | field: i32, | ||
| 469 | }; | ||
| 470 | var gdt = [_]GDTEntry{ | ||
| 471 | GDTEntry{ .field = 1 }, | ||
| 472 | GDTEntry{ .field = 2 }, | ||
| 473 | }; | ||
| 474 | var global_ptr = &gdt[0]; | ||
| 475 | |||
| 476 | // can't really run this test but we can make sure it has no compile error | ||
| 477 | // and generates code | ||
| 478 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 479 | export fn writeToVRam() void { | ||
| 480 | vram[0] = 'X'; | ||
| 481 | } | ||
| 482 | |||
| 483 | const OpaqueA = opaque {}; | ||
| 484 | const OpaqueB = opaque {}; | ||
| 485 | test "opaque types" { | ||
| 486 | try expect(*OpaqueA != *OpaqueB); | ||
| 487 | try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); | ||
| 488 | try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | ||
| 489 | } | ||
| 490 | |||
| 491 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 492 | var x: i32 = 1234; | ||
| 493 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 494 | } | ||
| 495 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 496 | var a = ptr; | ||
| 497 | return a; | ||
| 498 | } | ||
| 499 | |||
| 500 | test "comptime if inside runtime while which unconditionally breaks" { | ||
| 501 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 502 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | ||
| 503 | } | ||
| 504 | fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { | ||
| 505 | while (cond) { | ||
| 506 | if (false) {} | ||
| 507 | break; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | test "implicit comptime while" { | ||
| 512 | while (false) { | ||
| 513 | @compileError("bad"); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | fn fnThatClosesOverLocalConst() type { | ||
| 518 | const c = 1; | ||
| 519 | return struct { | ||
| 520 | fn g() i32 { | ||
| 521 | return c; | ||
| 522 | } | ||
| 523 | }; | ||
| 524 | } | ||
| 525 | |||
| 526 | test "function closes over local const" { | ||
| 527 | const x = fnThatClosesOverLocalConst().g(); | ||
| 528 | try expect(x == 1); | ||
| 529 | } | ||
| 530 | |||
| 531 | test "cold function" { | ||
| 532 | thisIsAColdFn(); | ||
| 533 | comptime thisIsAColdFn(); | ||
| 534 | } | ||
| 535 | |||
| 536 | fn thisIsAColdFn() void { | ||
| 537 | @setCold(true); | ||
| 538 | } | ||
| 539 | |||
| 540 | const PackedStruct = packed struct { | ||
| 541 | a: u8, | ||
| 542 | b: u8, | ||
| 543 | }; | ||
| 544 | const PackedUnion = packed union { | ||
| 545 | a: u8, | ||
| 546 | b: u32, | ||
| 547 | }; | ||
| 548 | const PackedEnum = packed enum { | ||
| 549 | A, | ||
| 550 | B, | ||
| 551 | }; | ||
| 552 | |||
| 553 | test "packed struct, enum, union parameters in extern function" { | ||
| 554 | testPackedStuff(&(PackedStruct{ | ||
| 555 | .a = 1, | ||
| 556 | .b = 2, | ||
| 557 | }), &(PackedUnion{ .a = 1 }), PackedEnum.A); | ||
| 558 | } | ||
| 559 | |||
| 560 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} | ||
| 561 | |||
| 562 | test "slicing zero length array" { | ||
| 563 | const s1 = ""[0..]; | ||
| 564 | const s2 = ([_]u32{})[0..]; | ||
| 565 | try expect(s1.len == 0); | ||
| 566 | try expect(s2.len == 0); | ||
| 567 | try expect(mem.eql(u8, s1, "")); | ||
| 568 | try expect(mem.eql(u32, s2, &[_]u32{})); | ||
| 569 | } | ||
| 570 | |||
| 571 | const addr1 = @ptrCast(*const u8, emptyFn); | ||
| 572 | test "comptime cast fn to ptr" { | ||
| 573 | const addr2 = @ptrCast(*const u8, emptyFn); | ||
| 574 | comptime try expect(addr1 == addr2); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "equality compare fn ptrs" { | ||
| 578 | var a = emptyFn; | ||
| 579 | try expect(a == a); | ||
| 580 | } | ||
| 581 | |||
| 582 | test "self reference through fn ptr field" { | ||
| 583 | const S = struct { | ||
| 584 | const A = struct { | ||
| 585 | f: fn (A) u8, | ||
| 586 | }; | ||
| 587 | |||
| 588 | fn foo(a: A) u8 { | ||
| 589 | return 12; | ||
| 590 | } | ||
| 591 | }; | ||
| 592 | var a: S.A = undefined; | ||
| 593 | a.f = S.foo; | ||
| 594 | try expect(a.f(a) == 12); | ||
| 595 | } | ||
| 596 | |||
| 597 | test "volatile load and store" { | ||
| 598 | var number: i32 = 1234; | ||
| 599 | const ptr = @as(*volatile i32, &number); | ||
| 600 | ptr.* += 1; | ||
| 601 | try expect(ptr.* == 1235); | ||
| 602 | } | ||
| 603 | |||
| 604 | test "slice string literal has correct type" { | ||
| 605 | comptime { | ||
| 606 | try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); | ||
| 607 | const array = [_]i32{ 1, 2, 3, 4 }; | ||
| 608 | try expect(@TypeOf(array[0..]) == *const [4]i32); | ||
| 609 | } | ||
| 610 | var runtime_zero: usize = 0; | ||
| 611 | comptime try expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); | ||
| 612 | const array = [_]i32{ 1, 2, 3, 4 }; | ||
| 613 | comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32); | ||
| 614 | } | ||
| 615 | |||
| 616 | test "struct inside function" { | ||
| 617 | try testStructInFn(); | ||
| 618 | comptime try testStructInFn(); | ||
| 619 | } | ||
| 620 | |||
| 621 | fn testStructInFn() !void { | ||
| 622 | const BlockKind = u32; | ||
| 623 | |||
| 624 | const Block = struct { | ||
| 625 | kind: BlockKind, | ||
| 626 | }; | ||
| 627 | |||
| 628 | var block = Block{ .kind = 1234 }; | ||
| 629 | |||
| 630 | block.kind += 1; | ||
| 631 | |||
| 632 | try expect(block.kind == 1235); | ||
| 633 | } | ||
| 634 | |||
| 635 | test "fn call returning scalar optional in equality expression" { | ||
| 636 | try expect(getNull() == null); | ||
| 637 | } | ||
| 638 | |||
| 639 | fn getNull() ?*i32 { | ||
| 640 | return null; | ||
| 641 | } | ||
| 642 | |||
| 643 | test "thread local variable" { | ||
| 644 | const S = struct { | ||
| 645 | threadlocal var t: i32 = 1234; | ||
| 646 | }; | ||
| 647 | S.t += 1; | ||
| 648 | try expect(S.t == 1235); | ||
| 649 | } | ||
| 650 | |||
| 651 | test "unicode escape in character literal" { | ||
| 652 | var a: u24 = '\u{01f4a9}'; | ||
| 653 | try expect(a == 128169); | ||
| 654 | } | ||
| 655 | |||
| 656 | test "unicode character in character literal" { | ||
| 657 | try expect('💩' == 128169); | ||
| 658 | } | ||
| 659 | |||
| 660 | test "result location zero sized array inside struct field implicit cast to slice" { | ||
| 661 | const E = struct { | ||
| 662 | entries: []u32, | ||
| 663 | }; | ||
| 664 | var foo = E{ .entries = &[_]u32{} }; | ||
| 665 | try expect(foo.entries.len == 0); | ||
| 666 | } | ||
| 667 | |||
| 668 | var global_foo: *i32 = undefined; | ||
| 669 | |||
| 670 | test "global variable assignment with optional unwrapping with var initialized to undefined" { | ||
| 671 | const S = struct { | ||
| 672 | var data: i32 = 1234; | ||
| 673 | fn foo() ?*i32 { | ||
| 674 | return &data; | ||
| 675 | } | ||
| 676 | }; | ||
| 677 | global_foo = S.foo() orelse { | ||
| 678 | @panic("bad"); | ||
| 679 | }; | ||
| 680 | try expect(global_foo.* == 1234); | ||
| 681 | } | ||
| 682 | |||
| 683 | test "peer result location with typed parent, runtime condition, comptime prongs" { | ||
| 684 | const S = struct { | ||
| 685 | fn doTheTest(arg: i32) i32 { | ||
| 686 | const st = Structy{ | ||
| 687 | .bleh = if (arg == 1) 1 else 1, | ||
| 688 | }; | ||
| 689 | |||
| 690 | if (st.bleh == 1) | ||
| 691 | return 1234; | ||
| 692 | return 0; | ||
| 693 | } | ||
| 694 | |||
| 695 | const Structy = struct { | ||
| 696 | bleh: i32, | ||
| 697 | }; | ||
| 698 | }; | ||
| 699 | try expect(S.doTheTest(0) == 1234); | ||
| 700 | try expect(S.doTheTest(1) == 1234); | ||
| 701 | } | ||
| 702 | |||
| 703 | test "nested optional field in struct" { | ||
| 704 | const S2 = struct { | ||
| 705 | y: u8, | ||
| 706 | }; | ||
| 707 | const S1 = struct { | ||
| 708 | x: ?S2, | ||
| 709 | }; | ||
| 710 | var s = S1{ | ||
| 711 | .x = S2{ .y = 127 }, | ||
| 712 | }; | ||
| 713 | try expect(s.x.?.y == 127); | ||
| 714 | } | ||
| 715 | |||
| 716 | fn maybe(x: bool) anyerror!?u32 { | ||
| 717 | return switch (x) { | ||
| 718 | true => @as(u32, 42), | ||
| 719 | else => null, | ||
| 720 | }; | ||
| 721 | } | ||
| 722 | |||
| 723 | test "result location is optional inside error union" { | ||
| 724 | const x = maybe(true) catch unreachable; | ||
| 725 | try expect(x.? == 42); | ||
| 726 | } | ||
| 727 | |||
| 728 | threadlocal var buffer: [11]u8 = undefined; | ||
| 729 | |||
| 730 | test "pointer to thread local array" { | ||
| 731 | const s = "Hello world"; | ||
| 732 | std.mem.copy(u8, buffer[0..], s); | ||
| 733 | try std.testing.expectEqualSlices(u8, buffer[0..], s); | ||
| 734 | } | ||
| 735 | |||
| 736 | test "auto created variables have correct alignment" { | ||
| 737 | const S = struct { | ||
| 738 | fn foo(str: [*]const u8) u32 { | ||
| 739 | for (@ptrCast([*]align(1) const u32, str)[0..1]) |v| { | ||
| 740 | return v; | ||
| 741 | } | ||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | }; | ||
| 745 | try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); | ||
| 746 | comptime try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); | ||
| 747 | } | ||
| 748 | |||
| 749 | extern var opaque_extern_var: opaque {}; | ||
| 750 | var var_to_export: u32 = 42; | ||
| 751 | test "extern variable with non-pointer opaque type" { | ||
| 752 | @export(var_to_export, .{ .name = "opaque_extern_var" }); | ||
| 753 | try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42); | ||
| 754 | } | ||
| 755 | |||
| 756 | test "lazy typeInfo value as generic parameter" { | ||
| 757 | const S = struct { | ||
| 758 | fn foo(args: anytype) void {} | ||
| 759 | }; | ||
| 760 | S.foo(@typeInfo(@TypeOf(.{}))); | ||
| 761 | } | ||
test/stage1/behavior/muladd.zig deleted-34| ... | @@ -1,34 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@mulAdd" { | ||
| 4 | comptime try testMulAdd(); | ||
| 5 | try testMulAdd(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testMulAdd() !void { | ||
| 9 | { | ||
| 10 | var a: f16 = 5.5; | ||
| 11 | var b: f16 = 2.5; | ||
| 12 | var c: f16 = 6.25; | ||
| 13 | try expect(@mulAdd(f16, a, b, c) == 20); | ||
| 14 | } | ||
| 15 | { | ||
| 16 | var a: f32 = 5.5; | ||
| 17 | var b: f32 = 2.5; | ||
| 18 | var c: f32 = 6.25; | ||
| 19 | try expect(@mulAdd(f32, a, b, c) == 20); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var a: f64 = 5.5; | ||
| 23 | var b: f64 = 2.5; | ||
| 24 | var c: f64 = 6.25; | ||
| 25 | try expect(@mulAdd(f64, a, b, c) == 20); | ||
| 26 | } | ||
| 27 | // Awaits implementation in libm.zig | ||
| 28 | //{ | ||
| 29 | // var a: f16 = 5.5; | ||
| 30 | // var b: f128 = 2.5; | ||
| 31 | // var c: f128 = 6.25; | ||
| 32 | //try expect(@mulAdd(f128, a, b, c) == 20); | ||
| 33 | //} | ||
| 34 | } | ||
test/stage1/behavior/namespace_depends_on_compile_var.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "namespace depends on compile var" { | ||
| 5 | if (some_namespace.a_bool) { | ||
| 6 | try expect(some_namespace.a_bool); | ||
| 7 | } else { | ||
| 8 | try expect(!some_namespace.a_bool); | ||
| 9 | } | ||
| 10 | } | ||
| 11 | const some_namespace = switch (std.builtin.os.tag) { | ||
| 12 | .linux => @import("namespace_depends_on_compile_var/a.zig"), | ||
| 13 | else => @import("namespace_depends_on_compile_var/b.zig"), | ||
| 14 | }; | ||
test/stage1/behavior/namespace_depends_on_compile_var/a.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const a_bool = true; | ||
test/stage1/behavior/namespace_depends_on_compile_var/b.zig deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | pub const a_bool = false; | ||
test/stage1/behavior/null.zig deleted-162| ... | @@ -1,162 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "optional type" { | ||
| 4 | const x: ?bool = true; | ||
| 5 | |||
| 6 | if (x) |y| { | ||
| 7 | if (y) { | ||
| 8 | // OK | ||
| 9 | } else { | ||
| 10 | unreachable; | ||
| 11 | } | ||
| 12 | } else { | ||
| 13 | unreachable; | ||
| 14 | } | ||
| 15 | |||
| 16 | const next_x: ?i32 = null; | ||
| 17 | |||
| 18 | const z = next_x orelse 1234; | ||
| 19 | |||
| 20 | try expect(z == 1234); | ||
| 21 | |||
| 22 | const final_x: ?i32 = 13; | ||
| 23 | |||
| 24 | const num = final_x orelse unreachable; | ||
| 25 | |||
| 26 | try expect(num == 13); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "test maybe object and get a pointer to the inner value" { | ||
| 30 | var maybe_bool: ?bool = true; | ||
| 31 | |||
| 32 | if (maybe_bool) |*b| { | ||
| 33 | b.* = false; | ||
| 34 | } | ||
| 35 | |||
| 36 | try expect(maybe_bool.? == false); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "rhs maybe unwrap return" { | ||
| 40 | const x: ?bool = true; | ||
| 41 | const y = x orelse return; | ||
| 42 | } | ||
| 43 | |||
| 44 | test "maybe return" { | ||
| 45 | try maybeReturnImpl(); | ||
| 46 | comptime try maybeReturnImpl(); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn maybeReturnImpl() !void { | ||
| 50 | try expect(foo(1235).?); | ||
| 51 | if (foo(null) != null) unreachable; | ||
| 52 | try expect(!foo(1234).?); | ||
| 53 | } | ||
| 54 | |||
| 55 | fn foo(x: ?i32) ?bool { | ||
| 56 | const value = x orelse return null; | ||
| 57 | return value > 1234; | ||
| 58 | } | ||
| 59 | |||
| 60 | test "if var maybe pointer" { | ||
| 61 | try expect(shouldBeAPlus1(Particle{ | ||
| 62 | .a = 14, | ||
| 63 | .b = 1, | ||
| 64 | .c = 1, | ||
| 65 | .d = 1, | ||
| 66 | }) == 15); | ||
| 67 | } | ||
| 68 | fn shouldBeAPlus1(p: Particle) u64 { | ||
| 69 | var maybe_particle: ?Particle = p; | ||
| 70 | if (maybe_particle) |*particle| { | ||
| 71 | particle.a += 1; | ||
| 72 | } | ||
| 73 | if (maybe_particle) |particle| { | ||
| 74 | return particle.a; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | const Particle = struct { | ||
| 79 | a: u64, | ||
| 80 | b: u64, | ||
| 81 | c: u64, | ||
| 82 | d: u64, | ||
| 83 | }; | ||
| 84 | |||
| 85 | test "null literal outside function" { | ||
| 86 | const is_null = here_is_a_null_literal.context == null; | ||
| 87 | try expect(is_null); | ||
| 88 | |||
| 89 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 90 | try expect(!is_non_null); | ||
| 91 | } | ||
| 92 | const SillyStruct = struct { | ||
| 93 | context: ?i32, | ||
| 94 | }; | ||
| 95 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 96 | |||
| 97 | test "test null runtime" { | ||
| 98 | try testTestNullRuntime(null); | ||
| 99 | } | ||
| 100 | fn testTestNullRuntime(x: ?i32) !void { | ||
| 101 | try expect(x == null); | ||
| 102 | try expect(!(x != null)); | ||
| 103 | } | ||
| 104 | |||
| 105 | test "optional void" { | ||
| 106 | try optionalVoidImpl(); | ||
| 107 | comptime try optionalVoidImpl(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn optionalVoidImpl() !void { | ||
| 111 | try expect(bar(null) == null); | ||
| 112 | try expect(bar({}) != null); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn bar(x: ?void) ?void { | ||
| 116 | if (x) |_| { | ||
| 117 | return {}; | ||
| 118 | } else { | ||
| 119 | return null; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | const StructWithOptional = struct { | ||
| 124 | field: ?i32, | ||
| 125 | }; | ||
| 126 | |||
| 127 | var struct_with_optional: StructWithOptional = undefined; | ||
| 128 | |||
| 129 | test "unwrap optional which is field of global var" { | ||
| 130 | struct_with_optional.field = null; | ||
| 131 | if (struct_with_optional.field) |payload| { | ||
| 132 | unreachable; | ||
| 133 | } | ||
| 134 | struct_with_optional.field = 1234; | ||
| 135 | if (struct_with_optional.field) |payload| { | ||
| 136 | try expect(payload == 1234); | ||
| 137 | } else { | ||
| 138 | unreachable; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | test "null with default unwrap" { | ||
| 143 | const x: i32 = null orelse 1; | ||
| 144 | try expect(x == 1); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "optional types" { | ||
| 148 | comptime { | ||
| 149 | const opt_type_struct = StructWithOptionalType{ .t = u8 }; | ||
| 150 | try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | const StructWithOptionalType = struct { | ||
| 155 | t: ?type, | ||
| 156 | }; | ||
| 157 | |||
| 158 | test "optional pointer to 0 bit type null value at runtime" { | ||
| 159 | const EmptyStruct = struct {}; | ||
| 160 | var x: ?*EmptyStruct = null; | ||
| 161 | try expect(x == null); | ||
| 162 | } | ||
test/stage1/behavior/optional.zig deleted-269| ... | @@ -1,269 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | pub const EmptyStruct = struct {}; | ||
| 7 | |||
| 8 | test "optional pointer to size zero struct" { | ||
| 9 | var e = EmptyStruct{}; | ||
| 10 | var o: ?*EmptyStruct = &e; | ||
| 11 | try expect(o != null); | ||
| 12 | } | ||
| 13 | |||
| 14 | test "equality compare nullable pointers" { | ||
| 15 | try testNullPtrsEql(); | ||
| 16 | comptime try testNullPtrsEql(); | ||
| 17 | } | ||
| 18 | |||
| 19 | fn testNullPtrsEql() !void { | ||
| 20 | var number: i32 = 1234; | ||
| 21 | |||
| 22 | var x: ?*i32 = null; | ||
| 23 | var y: ?*i32 = null; | ||
| 24 | try expect(x == y); | ||
| 25 | y = &number; | ||
| 26 | try expect(x != y); | ||
| 27 | try expect(x != &number); | ||
| 28 | try expect(&number != x); | ||
| 29 | x = &number; | ||
| 30 | try expect(x == y); | ||
| 31 | try expect(x == &number); | ||
| 32 | try expect(&number == x); | ||
| 33 | } | ||
| 34 | |||
| 35 | test "address of unwrap optional" { | ||
| 36 | const S = struct { | ||
| 37 | const Foo = struct { | ||
| 38 | a: i32, | ||
| 39 | }; | ||
| 40 | |||
| 41 | var global: ?Foo = null; | ||
| 42 | |||
| 43 | pub fn getFoo() anyerror!*Foo { | ||
| 44 | return &global.?; | ||
| 45 | } | ||
| 46 | }; | ||
| 47 | S.global = S.Foo{ .a = 1234 }; | ||
| 48 | const foo = S.getFoo() catch unreachable; | ||
| 49 | try expect(foo.a == 1234); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "equality compare optional with non-optional" { | ||
| 53 | try test_cmp_optional_non_optional(); | ||
| 54 | comptime try test_cmp_optional_non_optional(); | ||
| 55 | } | ||
| 56 | |||
| 57 | fn test_cmp_optional_non_optional() !void { | ||
| 58 | var ten: i32 = 10; | ||
| 59 | var opt_ten: ?i32 = 10; | ||
| 60 | var five: i32 = 5; | ||
| 61 | var int_n: ?i32 = null; | ||
| 62 | |||
| 63 | try expect(int_n != ten); | ||
| 64 | try expect(opt_ten == ten); | ||
| 65 | try expect(opt_ten != five); | ||
| 66 | |||
| 67 | // test evaluation is always lexical | ||
| 68 | // ensure that the optional isn't always computed before the non-optional | ||
| 69 | var mutable_state: i32 = 0; | ||
| 70 | _ = blk1: { | ||
| 71 | mutable_state += 1; | ||
| 72 | break :blk1 @as(?f64, 10.0); | ||
| 73 | } != blk2: { | ||
| 74 | try expect(mutable_state == 1); | ||
| 75 | break :blk2 @as(f64, 5.0); | ||
| 76 | }; | ||
| 77 | _ = blk1: { | ||
| 78 | mutable_state += 1; | ||
| 79 | break :blk1 @as(f64, 10.0); | ||
| 80 | } != blk2: { | ||
| 81 | try expect(mutable_state == 2); | ||
| 82 | break :blk2 @as(?f64, 5.0); | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 86 | test "passing an optional integer as a parameter" { | ||
| 87 | const S = struct { | ||
| 88 | fn entry() bool { | ||
| 89 | var x: i32 = 1234; | ||
| 90 | return foo(x); | ||
| 91 | } | ||
| 92 | |||
| 93 | fn foo(x: ?i32) bool { | ||
| 94 | return x.? == 1234; | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | try expect(S.entry()); | ||
| 98 | comptime try expect(S.entry()); | ||
| 99 | } | ||
| 100 | |||
| 101 | test "unwrap function call with optional pointer return value" { | ||
| 102 | const S = struct { | ||
| 103 | fn entry() !void { | ||
| 104 | try expect(foo().?.* == 1234); | ||
| 105 | try expect(bar() == null); | ||
| 106 | } | ||
| 107 | const global: i32 = 1234; | ||
| 108 | fn foo() ?*const i32 { | ||
| 109 | return &global; | ||
| 110 | } | ||
| 111 | fn bar() ?*i32 { | ||
| 112 | return null; | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | try S.entry(); | ||
| 116 | comptime try S.entry(); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "nested orelse" { | ||
| 120 | const S = struct { | ||
| 121 | fn entry() !void { | ||
| 122 | try expect(func() == null); | ||
| 123 | } | ||
| 124 | fn maybe() ?Foo { | ||
| 125 | return null; | ||
| 126 | } | ||
| 127 | fn func() ?Foo { | ||
| 128 | const x = maybe() orelse | ||
| 129 | maybe() orelse | ||
| 130 | return null; | ||
| 131 | unreachable; | ||
| 132 | } | ||
| 133 | const Foo = struct { | ||
| 134 | field: i32, | ||
| 135 | }; | ||
| 136 | }; | ||
| 137 | try S.entry(); | ||
| 138 | comptime try S.entry(); | ||
| 139 | } | ||
| 140 | |||
| 141 | test "self-referential struct through a slice of optional" { | ||
| 142 | const S = struct { | ||
| 143 | const Node = struct { | ||
| 144 | children: []?Node, | ||
| 145 | data: ?u8, | ||
| 146 | |||
| 147 | fn new() Node { | ||
| 148 | return Node{ | ||
| 149 | .children = undefined, | ||
| 150 | .data = null, | ||
| 151 | }; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | }; | ||
| 155 | |||
| 156 | var n = S.Node.new(); | ||
| 157 | try expect(n.data == null); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "assigning to an unwrapped optional field in an inline loop" { | ||
| 161 | comptime var maybe_pos_arg: ?comptime_int = null; | ||
| 162 | inline for ("ab") |x| { | ||
| 163 | maybe_pos_arg = 0; | ||
| 164 | if (maybe_pos_arg.? != 0) { | ||
| 165 | @compileError("bad"); | ||
| 166 | } | ||
| 167 | maybe_pos_arg.? = 10; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | test "coerce an anon struct literal to optional struct" { | ||
| 172 | const S = struct { | ||
| 173 | const Struct = struct { | ||
| 174 | field: u32, | ||
| 175 | }; | ||
| 176 | fn doTheTest() !void { | ||
| 177 | var maybe_dims: ?Struct = null; | ||
| 178 | maybe_dims = .{ .field = 1 }; | ||
| 179 | try expect(maybe_dims.?.field == 1); | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | try S.doTheTest(); | ||
| 183 | comptime try S.doTheTest(); | ||
| 184 | } | ||
| 185 | |||
| 186 | test "optional with void type" { | ||
| 187 | const Foo = struct { | ||
| 188 | x: ?void, | ||
| 189 | }; | ||
| 190 | var x = Foo{ .x = null }; | ||
| 191 | try expect(x.x == null); | ||
| 192 | } | ||
| 193 | |||
| 194 | test "0-bit child type coerced to optional return ptr result location" { | ||
| 195 | const S = struct { | ||
| 196 | fn doTheTest() !void { | ||
| 197 | var y = Foo{}; | ||
| 198 | var z = y.thing(); | ||
| 199 | try expect(z != null); | ||
| 200 | } | ||
| 201 | |||
| 202 | const Foo = struct { | ||
| 203 | pub const Bar = struct { | ||
| 204 | field: *Foo, | ||
| 205 | }; | ||
| 206 | |||
| 207 | pub fn thing(self: *Foo) ?Bar { | ||
| 208 | return Bar{ .field = self }; | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | }; | ||
| 212 | try S.doTheTest(); | ||
| 213 | comptime try S.doTheTest(); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "0-bit child type coerced to optional" { | ||
| 217 | const S = struct { | ||
| 218 | fn doTheTest() !void { | ||
| 219 | var it: Foo = .{ | ||
| 220 | .list = undefined, | ||
| 221 | }; | ||
| 222 | try expect(it.foo() != null); | ||
| 223 | } | ||
| 224 | |||
| 225 | const Empty = struct {}; | ||
| 226 | const Foo = struct { | ||
| 227 | list: [10]Empty, | ||
| 228 | |||
| 229 | fn foo(self: *Foo) ?*Empty { | ||
| 230 | const data = &self.list[0]; | ||
| 231 | return data; | ||
| 232 | } | ||
| 233 | }; | ||
| 234 | }; | ||
| 235 | try S.doTheTest(); | ||
| 236 | comptime try S.doTheTest(); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "array of optional unaligned types" { | ||
| 240 | const Enum = enum { one, two, three }; | ||
| 241 | |||
| 242 | const SomeUnion = union(enum) { | ||
| 243 | Num: Enum, | ||
| 244 | Other: u32, | ||
| 245 | }; | ||
| 246 | |||
| 247 | const values = [_]?SomeUnion{ | ||
| 248 | SomeUnion{ .Num = .one }, | ||
| 249 | SomeUnion{ .Num = .two }, | ||
| 250 | SomeUnion{ .Num = .three }, | ||
| 251 | SomeUnion{ .Num = .one }, | ||
| 252 | SomeUnion{ .Num = .two }, | ||
| 253 | SomeUnion{ .Num = .three }, | ||
| 254 | }; | ||
| 255 | |||
| 256 | // The index must be a runtime value | ||
| 257 | var i: usize = 0; | ||
| 258 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 259 | i += 1; | ||
| 260 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 261 | i += 1; | ||
| 262 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 263 | i += 1; | ||
| 264 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 265 | i += 1; | ||
| 266 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 267 | i += 1; | ||
| 268 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 269 | } | ||
test/stage1/behavior/pointers.zig deleted-339| ... | @@ -1,339 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectError = testing.expectError; | ||
| 5 | |||
| 6 | test "dereference pointer" { | ||
| 7 | comptime try testDerefPtr(); | ||
| 8 | try testDerefPtr(); | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testDerefPtr() !void { | ||
| 12 | var x: i32 = 1234; | ||
| 13 | var y = &x; | ||
| 14 | y.* += 1; | ||
| 15 | try expect(x == 1235); | ||
| 16 | } | ||
| 17 | |||
| 18 | const Foo1 = struct { | ||
| 19 | x: void, | ||
| 20 | }; | ||
| 21 | |||
| 22 | test "dereference pointer again" { | ||
| 23 | try testDerefPtrOneVal(); | ||
| 24 | comptime try testDerefPtrOneVal(); | ||
| 25 | } | ||
| 26 | |||
| 27 | fn testDerefPtrOneVal() !void { | ||
| 28 | // Foo1 satisfies the OnePossibleValueYes criteria | ||
| 29 | const x = &Foo1{ .x = {} }; | ||
| 30 | const y = x.*; | ||
| 31 | try expect(@TypeOf(y.x) == void); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "pointer arithmetic" { | ||
| 35 | var ptr: [*]const u8 = "abcd"; | ||
| 36 | |||
| 37 | try expect(ptr[0] == 'a'); | ||
| 38 | ptr += 1; | ||
| 39 | try expect(ptr[0] == 'b'); | ||
| 40 | ptr += 1; | ||
| 41 | try expect(ptr[0] == 'c'); | ||
| 42 | ptr += 1; | ||
| 43 | try expect(ptr[0] == 'd'); | ||
| 44 | ptr += 1; | ||
| 45 | try expect(ptr[0] == 0); | ||
| 46 | ptr -= 1; | ||
| 47 | try expect(ptr[0] == 'd'); | ||
| 48 | ptr -= 1; | ||
| 49 | try expect(ptr[0] == 'c'); | ||
| 50 | ptr -= 1; | ||
| 51 | try expect(ptr[0] == 'b'); | ||
| 52 | ptr -= 1; | ||
| 53 | try expect(ptr[0] == 'a'); | ||
| 54 | } | ||
| 55 | |||
| 56 | test "double pointer parsing" { | ||
| 57 | comptime try expect(PtrOf(PtrOf(i32)) == **i32); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn PtrOf(comptime T: type) type { | ||
| 61 | return *T; | ||
| 62 | } | ||
| 63 | |||
| 64 | test "assigning integer to C pointer" { | ||
| 65 | var x: i32 = 0; | ||
| 66 | var ptr: [*c]u8 = 0; | ||
| 67 | var ptr2: [*c]u8 = x; | ||
| 68 | } | ||
| 69 | |||
| 70 | test "implicit cast single item pointer to C pointer and back" { | ||
| 71 | var y: u8 = 11; | ||
| 72 | var x: [*c]u8 = &y; | ||
| 73 | var z: *u8 = x; | ||
| 74 | z.* += 1; | ||
| 75 | try expect(y == 12); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "C pointer comparison and arithmetic" { | ||
| 79 | const S = struct { | ||
| 80 | fn doTheTest() !void { | ||
| 81 | var one: usize = 1; | ||
| 82 | var ptr1: [*c]u32 = 0; | ||
| 83 | var ptr2 = ptr1 + 10; | ||
| 84 | try expect(ptr1 == 0); | ||
| 85 | try expect(ptr1 >= 0); | ||
| 86 | try expect(ptr1 <= 0); | ||
| 87 | // expect(ptr1 < 1); | ||
| 88 | // expect(ptr1 < one); | ||
| 89 | // expect(1 > ptr1); | ||
| 90 | // expect(one > ptr1); | ||
| 91 | try expect(ptr1 < ptr2); | ||
| 92 | try expect(ptr2 > ptr1); | ||
| 93 | try expect(ptr2 >= 40); | ||
| 94 | try expect(ptr2 == 40); | ||
| 95 | try expect(ptr2 <= 40); | ||
| 96 | ptr2 -= 10; | ||
| 97 | try expect(ptr1 == ptr2); | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | try S.doTheTest(); | ||
| 101 | comptime try S.doTheTest(); | ||
| 102 | } | ||
| 103 | |||
| 104 | test "peer type resolution with C pointers" { | ||
| 105 | var ptr_one: *u8 = undefined; | ||
| 106 | var ptr_many: [*]u8 = undefined; | ||
| 107 | var ptr_c: [*c]u8 = undefined; | ||
| 108 | var t = true; | ||
| 109 | var x1 = if (t) ptr_one else ptr_c; | ||
| 110 | var x2 = if (t) ptr_many else ptr_c; | ||
| 111 | var x3 = if (t) ptr_c else ptr_one; | ||
| 112 | var x4 = if (t) ptr_c else ptr_many; | ||
| 113 | try expect(@TypeOf(x1) == [*c]u8); | ||
| 114 | try expect(@TypeOf(x2) == [*c]u8); | ||
| 115 | try expect(@TypeOf(x3) == [*c]u8); | ||
| 116 | try expect(@TypeOf(x4) == [*c]u8); | ||
| 117 | } | ||
| 118 | |||
| 119 | test "implicit casting between C pointer and optional non-C pointer" { | ||
| 120 | var slice: []const u8 = "aoeu"; | ||
| 121 | const opt_many_ptr: ?[*]const u8 = slice.ptr; | ||
| 122 | var ptr_opt_many_ptr = &opt_many_ptr; | ||
| 123 | var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; | ||
| 124 | try expect(c_ptr.*.* == 'a'); | ||
| 125 | ptr_opt_many_ptr = c_ptr; | ||
| 126 | try expect(ptr_opt_many_ptr.*.?[1] == 'o'); | ||
| 127 | } | ||
| 128 | |||
| 129 | test "implicit cast error unions with non-optional to optional pointer" { | ||
| 130 | const S = struct { | ||
| 131 | fn doTheTest() !void { | ||
| 132 | try expectError(error.Fail, foo()); | ||
| 133 | } | ||
| 134 | fn foo() anyerror!?*u8 { | ||
| 135 | return bar() orelse error.Fail; | ||
| 136 | } | ||
| 137 | fn bar() ?*u8 { | ||
| 138 | return null; | ||
| 139 | } | ||
| 140 | }; | ||
| 141 | try S.doTheTest(); | ||
| 142 | comptime try S.doTheTest(); | ||
| 143 | } | ||
| 144 | |||
| 145 | test "initialize const optional C pointer to null" { | ||
| 146 | const a: ?[*c]i32 = null; | ||
| 147 | try expect(a == null); | ||
| 148 | comptime try expect(a == null); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "compare equality of optional and non-optional pointer" { | ||
| 152 | const a = @intToPtr(*const usize, 0x12345678); | ||
| 153 | const b = @intToPtr(?*usize, 0x12345678); | ||
| 154 | try expect(a == b); | ||
| 155 | try expect(b == a); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "allowzero pointer and slice" { | ||
| 159 | var ptr = @intToPtr([*]allowzero i32, 0); | ||
| 160 | var opt_ptr: ?[*]allowzero i32 = ptr; | ||
| 161 | try expect(opt_ptr != null); | ||
| 162 | try expect(@ptrToInt(ptr) == 0); | ||
| 163 | var runtime_zero: usize = 0; | ||
| 164 | var slice = ptr[runtime_zero..10]; | ||
| 165 | comptime try expect(@TypeOf(slice) == []allowzero i32); | ||
| 166 | try expect(@ptrToInt(&slice[5]) == 20); | ||
| 167 | |||
| 168 | comptime try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); | ||
| 169 | comptime try expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "assign null directly to C pointer and test null equality" { | ||
| 173 | var x: [*c]i32 = null; | ||
| 174 | try expect(x == null); | ||
| 175 | try expect(null == x); | ||
| 176 | try expect(!(x != null)); | ||
| 177 | try expect(!(null != x)); | ||
| 178 | if (x) |same_x| { | ||
| 179 | @panic("fail"); | ||
| 180 | } | ||
| 181 | var otherx: i32 = undefined; | ||
| 182 | try expect((x orelse &otherx) == &otherx); | ||
| 183 | |||
| 184 | const y: [*c]i32 = null; | ||
| 185 | comptime try expect(y == null); | ||
| 186 | comptime try expect(null == y); | ||
| 187 | comptime try expect(!(y != null)); | ||
| 188 | comptime try expect(!(null != y)); | ||
| 189 | if (y) |same_y| @panic("fail"); | ||
| 190 | const othery: i32 = undefined; | ||
| 191 | comptime try expect((y orelse &othery) == &othery); | ||
| 192 | |||
| 193 | var n: i32 = 1234; | ||
| 194 | var x1: [*c]i32 = &n; | ||
| 195 | try expect(!(x1 == null)); | ||
| 196 | try expect(!(null == x1)); | ||
| 197 | try expect(x1 != null); | ||
| 198 | try expect(null != x1); | ||
| 199 | try expect(x1.?.* == 1234); | ||
| 200 | if (x1) |same_x1| { | ||
| 201 | try expect(same_x1.* == 1234); | ||
| 202 | } else { | ||
| 203 | @panic("fail"); | ||
| 204 | } | ||
| 205 | try expect((x1 orelse &otherx) == x1); | ||
| 206 | |||
| 207 | const nc: i32 = 1234; | ||
| 208 | const y1: [*c]const i32 = &nc; | ||
| 209 | comptime try expect(!(y1 == null)); | ||
| 210 | comptime try expect(!(null == y1)); | ||
| 211 | comptime try expect(y1 != null); | ||
| 212 | comptime try expect(null != y1); | ||
| 213 | comptime try expect(y1.?.* == 1234); | ||
| 214 | if (y1) |same_y1| { | ||
| 215 | try expect(same_y1.* == 1234); | ||
| 216 | } else { | ||
| 217 | @compileError("fail"); | ||
| 218 | } | ||
| 219 | comptime try expect((y1 orelse &othery) == y1); | ||
| 220 | } | ||
| 221 | |||
| 222 | test "null terminated pointer" { | ||
| 223 | const S = struct { | ||
| 224 | fn doTheTest() !void { | ||
| 225 | var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' }; | ||
| 226 | var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero); | ||
| 227 | var no_zero_ptr: [*]const u8 = zero_ptr; | ||
| 228 | var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr); | ||
| 229 | try expect(std.mem.eql(u8, std.mem.spanZ(zero_ptr_again), "hello")); | ||
| 230 | } | ||
| 231 | }; | ||
| 232 | try S.doTheTest(); | ||
| 233 | comptime try S.doTheTest(); | ||
| 234 | } | ||
| 235 | |||
| 236 | test "allow any sentinel" { | ||
| 237 | const S = struct { | ||
| 238 | fn doTheTest() !void { | ||
| 239 | var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 }; | ||
| 240 | var ptr: [*:std.math.minInt(i32)]i32 = &array; | ||
| 241 | try expect(ptr[4] == std.math.minInt(i32)); | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | try S.doTheTest(); | ||
| 245 | comptime try S.doTheTest(); | ||
| 246 | } | ||
| 247 | |||
| 248 | test "pointer sentinel with enums" { | ||
| 249 | const S = struct { | ||
| 250 | const Number = enum { | ||
| 251 | one, | ||
| 252 | two, | ||
| 253 | sentinel, | ||
| 254 | }; | ||
| 255 | |||
| 256 | fn doTheTest() !void { | ||
| 257 | var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one }; | ||
| 258 | try expect(ptr[4] == .sentinel); // TODO this should be comptime try expect, see #3731 | ||
| 259 | } | ||
| 260 | }; | ||
| 261 | try S.doTheTest(); | ||
| 262 | comptime try S.doTheTest(); | ||
| 263 | } | ||
| 264 | |||
| 265 | test "pointer sentinel with optional element" { | ||
| 266 | const S = struct { | ||
| 267 | fn doTheTest() !void { | ||
| 268 | var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 }; | ||
| 269 | try expect(ptr[4] == null); // TODO this should be comptime try expect, see #3731 | ||
| 270 | } | ||
| 271 | }; | ||
| 272 | try S.doTheTest(); | ||
| 273 | comptime try S.doTheTest(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "pointer sentinel with +inf" { | ||
| 277 | const S = struct { | ||
| 278 | fn doTheTest() !void { | ||
| 279 | const inf = std.math.inf_f32; | ||
| 280 | var ptr: [*:inf]const f32 = &[_:inf]f32{ 1.1, 2.2, 3.3, 4.4 }; | ||
| 281 | try expect(ptr[4] == inf); // TODO this should be comptime try expect, see #3731 | ||
| 282 | } | ||
| 283 | }; | ||
| 284 | try S.doTheTest(); | ||
| 285 | comptime try S.doTheTest(); | ||
| 286 | } | ||
| 287 | |||
| 288 | test "pointer to array at fixed address" { | ||
| 289 | const array = @intToPtr(*volatile [1]u32, 0x10); | ||
| 290 | // Silly check just to reference `array` | ||
| 291 | try expect(@ptrToInt(&array[0]) == 0x10); | ||
| 292 | } | ||
| 293 | |||
| 294 | test "pointer arithmetic affects the alignment" { | ||
| 295 | { | ||
| 296 | var ptr: [*]align(8) u32 = undefined; | ||
| 297 | var x: usize = 1; | ||
| 298 | |||
| 299 | try expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8); | ||
| 300 | const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4 | ||
| 301 | try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4); | ||
| 302 | const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8 | ||
| 303 | try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8); | ||
| 304 | const ptr3 = ptr + 0; // no-op | ||
| 305 | try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); | ||
| 306 | const ptr4 = ptr + x; // runtime-known addend | ||
| 307 | try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); | ||
| 308 | } | ||
| 309 | { | ||
| 310 | var ptr: [*]align(8) [3]u8 = undefined; | ||
| 311 | var x: usize = 1; | ||
| 312 | |||
| 313 | const ptr1 = ptr + 17; // 3 * 17 = 51 | ||
| 314 | try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1); | ||
| 315 | const ptr2 = ptr + x; // runtime-known addend | ||
| 316 | try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1); | ||
| 317 | const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8 | ||
| 318 | try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); | ||
| 319 | const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4 | ||
| 320 | try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | test "@ptrToInt on null optional at comptime" { | ||
| 325 | { | ||
| 326 | const pointer = @intToPtr(?*u8, 0x000); | ||
| 327 | const x = @ptrToInt(pointer); | ||
| 328 | comptime try expect(0 == @ptrToInt(pointer)); | ||
| 329 | } | ||
| 330 | { | ||
| 331 | const pointer = @intToPtr(?*u8, 0xf00); | ||
| 332 | comptime try expect(0xf00 == @ptrToInt(pointer)); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | test "indexing array with sentinel returns correct type" { | ||
| 337 | var s: [:0]const u8 = "abc"; | ||
| 338 | try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0]))); | ||
| 339 | } | ||
test/stage1/behavior/popcount.zig deleted-43| ... | @@ -1,43 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@popCount" { | ||
| 4 | comptime try testPopCount(); | ||
| 5 | try testPopCount(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testPopCount() !void { | ||
| 9 | { | ||
| 10 | var x: u32 = 0xffffffff; | ||
| 11 | try expect(@popCount(u32, x) == 32); | ||
| 12 | } | ||
| 13 | { | ||
| 14 | var x: u5 = 0x1f; | ||
| 15 | try expect(@popCount(u5, x) == 5); | ||
| 16 | } | ||
| 17 | { | ||
| 18 | var x: u32 = 0xaa; | ||
| 19 | try expect(@popCount(u32, x) == 4); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var x: u32 = 0xaaaaaaaa; | ||
| 23 | try expect(@popCount(u32, x) == 16); | ||
| 24 | } | ||
| 25 | { | ||
| 26 | var x: u32 = 0xaaaaaaaa; | ||
| 27 | try expect(@popCount(u32, x) == 16); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | var x: i16 = -1; | ||
| 31 | try expect(@popCount(i16, x) == 16); | ||
| 32 | } | ||
| 33 | { | ||
| 34 | var x: i8 = -120; | ||
| 35 | try expect(@popCount(i8, x) == 2); | ||
| 36 | } | ||
| 37 | comptime { | ||
| 38 | try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2); | ||
| 39 | } | ||
| 40 | comptime { | ||
| 41 | try expect(@popCount(i128, 0b11111111000110001100010000100001000011000011100101010001) == 24); | ||
| 42 | } | ||
| 43 | } | ||
test/stage1/behavior/ptrcast.zig deleted-72| ... | @@ -1,72 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "reinterpret bytes as integer with nonzero offset" { | ||
| 6 | try testReinterpretBytesAsInteger(); | ||
| 7 | comptime try testReinterpretBytesAsInteger(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testReinterpretBytesAsInteger() !void { | ||
| 11 | const bytes = "\x12\x34\x56\x78\xab"; | ||
| 12 | const expected = switch (builtin.endian) { | ||
| 13 | builtin.Endian.Little => 0xab785634, | ||
| 14 | builtin.Endian.Big => 0x345678ab, | ||
| 15 | }; | ||
| 16 | try expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "reinterpret bytes of an array into an extern struct" { | ||
| 20 | try testReinterpretBytesAsExternStruct(); | ||
| 21 | comptime try testReinterpretBytesAsExternStruct(); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn testReinterpretBytesAsExternStruct() !void { | ||
| 25 | var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 }; | ||
| 26 | |||
| 27 | const S = extern struct { | ||
| 28 | a: u8, | ||
| 29 | b: u16, | ||
| 30 | c: u8, | ||
| 31 | }; | ||
| 32 | |||
| 33 | var ptr = @ptrCast(*const S, &bytes); | ||
| 34 | var val = ptr.c; | ||
| 35 | try expect(val == 5); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "reinterpret struct field at comptime" { | ||
| 39 | const numNative = comptime Bytes.init(0x12345678); | ||
| 40 | if (builtin.endian != .Little) { | ||
| 41 | try expect(std.mem.eql(u8, &[_]u8{ 0x12, 0x34, 0x56, 0x78 }, &numNative.bytes)); | ||
| 42 | } else { | ||
| 43 | try expect(std.mem.eql(u8, &[_]u8{ 0x78, 0x56, 0x34, 0x12 }, &numNative.bytes)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | const Bytes = struct { | ||
| 48 | bytes: [4]u8, | ||
| 49 | |||
| 50 | pub fn init(v: u32) Bytes { | ||
| 51 | var res: Bytes = undefined; | ||
| 52 | @ptrCast(*align(1) u32, &res.bytes).* = v; | ||
| 53 | |||
| 54 | return res; | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | |||
| 58 | test "comptime ptrcast keeps larger alignment" { | ||
| 59 | comptime { | ||
| 60 | const a: u32 = 1234; | ||
| 61 | const p = @ptrCast([*]const u8, &a); | ||
| 62 | try expect(@TypeOf(p) == [*]align(@alignOf(u32)) const u8); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | test "implicit optional pointer to optional c_void pointer" { | ||
| 67 | var buf: [4]u8 = "aoeu".*; | ||
| 68 | var x: ?[*]u8 = &buf; | ||
| 69 | var y: ?*c_void = x; | ||
| 70 | var z = @ptrCast(*[4]u8, y); | ||
| 71 | try expect(std.mem.eql(u8, z, "aoeu")); | ||
| 72 | } | ||
test/stage1/behavior/pub_enum.zig deleted-13| ... | @@ -1,13 +0,0 @@ | ||
| 1 | const other = @import("pub_enum/other.zig"); | ||
| 2 | const expect = @import("std").testing.expect; | ||
| 3 | |||
| 4 | test "pub enum" { | ||
| 5 | try pubEnumTest(other.APubEnum.Two); | ||
| 6 | } | ||
| 7 | fn pubEnumTest(foo: other.APubEnum) !void { | ||
| 8 | try expect(foo == other.APubEnum.Two); | ||
| 9 | } | ||
| 10 | |||
| 11 | test "cast with imported symbol" { | ||
| 12 | try expect(@as(other.size_t, 42) == 42); | ||
| 13 | } | ||
test/stage1/behavior/pub_enum/other.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | pub const APubEnum = enum { | ||
| 2 | One, | ||
| 3 | Two, | ||
| 4 | Three, | ||
| 5 | }; | ||
| 6 | pub const size_t = u64; | ||
test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | |||
| 4 | var ok: bool = false; | ||
| 5 | test "reference a variable in an if after an if in the 2nd switch prong" { | ||
| 6 | try foo(true, Num.Two, false, "aoeu"); | ||
| 7 | try expect(!ok); | ||
| 8 | try foo(false, Num.One, false, "aoeu"); | ||
| 9 | try expect(!ok); | ||
| 10 | try foo(true, Num.One, false, "aoeu"); | ||
| 11 | try expect(ok); | ||
| 12 | } | ||
| 13 | |||
| 14 | const Num = enum { | ||
| 15 | One, | ||
| 16 | Two, | ||
| 17 | }; | ||
| 18 | |||
| 19 | fn foo(c: bool, k: Num, c2: bool, b: []const u8) !void { | ||
| 20 | switch (k) { | ||
| 21 | Num.Two => {}, | ||
| 22 | Num.One => { | ||
| 23 | if (c) { | ||
| 24 | const output_path = b; | ||
| 25 | |||
| 26 | if (c2) {} | ||
| 27 | |||
| 28 | try a(output_path); | ||
| 29 | } | ||
| 30 | }, | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn a(x: []const u8) !void { | ||
| 35 | try expect(mem.eql(u8, x, "aoeu")); | ||
| 36 | ok = true; | ||
| 37 | } | ||
test/stage1/behavior/reflection.zig deleted-55| ... | @@ -1,55 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const mem = @import("std").mem; | ||
| 3 | const reflection = @This(); | ||
| 4 | |||
| 5 | test "reflection: function return type, var args, and param types" { | ||
| 6 | comptime { | ||
| 7 | const info = @typeInfo(@TypeOf(dummy)).Fn; | ||
| 8 | try expect(info.return_type.? == i32); | ||
| 9 | try expect(!info.is_var_args); | ||
| 10 | try expect(info.args.len == 3); | ||
| 11 | try expect(info.args[0].arg_type.? == bool); | ||
| 12 | try expect(info.args[1].arg_type.? == i32); | ||
| 13 | try expect(info.args[2].arg_type.? == f32); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | fn dummy(a: bool, b: i32, c: f32) i32 { | ||
| 18 | return 1234; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "reflection: @field" { | ||
| 22 | var f = Foo{ | ||
| 23 | .one = 42, | ||
| 24 | .two = true, | ||
| 25 | .three = void{}, | ||
| 26 | }; | ||
| 27 | |||
| 28 | try expect(f.one == f.one); | ||
| 29 | try expect(@field(f, "o" ++ "ne") == f.one); | ||
| 30 | try expect(@field(f, "t" ++ "wo") == f.two); | ||
| 31 | try expect(@field(f, "th" ++ "ree") == f.three); | ||
| 32 | try expect(@field(Foo, "const" ++ "ant") == Foo.constant); | ||
| 33 | try expect(@field(Bar, "O" ++ "ne") == Bar.One); | ||
| 34 | try expect(@field(Bar, "T" ++ "wo") == Bar.Two); | ||
| 35 | try expect(@field(Bar, "Th" ++ "ree") == Bar.Three); | ||
| 36 | try expect(@field(Bar, "F" ++ "our") == Bar.Four); | ||
| 37 | try expect(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); | ||
| 38 | @field(f, "o" ++ "ne") = 4; | ||
| 39 | try expect(f.one == 4); | ||
| 40 | } | ||
| 41 | |||
| 42 | const Foo = struct { | ||
| 43 | const constant = 52; | ||
| 44 | |||
| 45 | one: i32, | ||
| 46 | two: bool, | ||
| 47 | three: void, | ||
| 48 | }; | ||
| 49 | |||
| 50 | const Bar = union(enum) { | ||
| 51 | One: void, | ||
| 52 | Two: i32, | ||
| 53 | Three: bool, | ||
| 54 | Four: f64, | ||
| 55 | }; | ||
test/stage1/behavior/shuffle.zig deleted-63| ... | @@ -1,63 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const Vector = std.meta.Vector; | ||
| 6 | |||
| 7 | test "@shuffle" { | ||
| 8 | // TODO investigate why this fails when cross-compiling to wasm. | ||
| 9 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 10 | |||
| 11 | const S = struct { | ||
| 12 | fn doTheTest() !void { | ||
| 13 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 14 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 15 | const mask: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }; | ||
| 16 | var res = @shuffle(i32, v, x, mask); | ||
| 17 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); | ||
| 18 | |||
| 19 | // Implicit cast from array (of mask) | ||
| 20 | res = @shuffle(i32, v, x, [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) }); | ||
| 21 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 })); | ||
| 22 | |||
| 23 | // Undefined | ||
| 24 | const mask2: Vector(4, i32) = [4]i32{ 3, 1, 2, 0 }; | ||
| 25 | res = @shuffle(i32, v, undefined, mask2); | ||
| 26 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 40, -2, 30, 2147483647 })); | ||
| 27 | |||
| 28 | // Upcasting of b | ||
| 29 | var v2: Vector(2, i32) = [2]i32{ 2147483647, undefined }; | ||
| 30 | const mask3: Vector(4, i32) = [4]i32{ ~@as(i32, 0), 2, ~@as(i32, 0), 3 }; | ||
| 31 | res = @shuffle(i32, x, v2, mask3); | ||
| 32 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 2147483647, 4 })); | ||
| 33 | |||
| 34 | // Upcasting of a | ||
| 35 | var v3: Vector(2, i32) = [2]i32{ 2147483647, -2 }; | ||
| 36 | const mask4: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 1, ~@as(i32, 3) }; | ||
| 37 | res = @shuffle(i32, v3, x, mask4); | ||
| 38 | try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, -2, 4 })); | ||
| 39 | |||
| 40 | // bool | ||
| 41 | // Disabled because of #3317 | ||
| 42 | if (@import("builtin").arch != .mipsel and std.Target.current.cpu.arch != .mips) { | ||
| 43 | var x2: Vector(4, bool) = [4]bool{ false, true, false, true }; | ||
| 44 | var v4: Vector(2, bool) = [2]bool{ true, false }; | ||
| 45 | const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; | ||
| 46 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 47 | try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false })); | ||
| 48 | } | ||
| 49 | |||
| 50 | // TODO re-enable when LLVM codegen is fixed | ||
| 51 | // https://github.com/ziglang/zig/issues/3246 | ||
| 52 | if (false) { | ||
| 53 | var x2: Vector(3, bool) = [3]bool{ false, true, false }; | ||
| 54 | var v4: Vector(2, bool) = [2]bool{ true, false }; | ||
| 55 | const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 }; | ||
| 56 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 57 | try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false })); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | }; | ||
| 61 | try S.doTheTest(); | ||
| 62 | comptime try S.doTheTest(); | ||
| 63 | } | ||
test/stage1/behavior/sizeof_and_typeof.zig deleted-264| ... | @@ -1,264 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | |||
| 6 | test "@sizeOf and @TypeOf" { | ||
| 7 | const y: @TypeOf(x) = 120; | ||
| 8 | try expect(@sizeOf(@TypeOf(y)) == 2); | ||
| 9 | } | ||
| 10 | const x: u16 = 13; | ||
| 11 | const z: @TypeOf(x) = 19; | ||
| 12 | |||
| 13 | const A = struct { | ||
| 14 | a: u8, | ||
| 15 | b: u32, | ||
| 16 | c: u8, | ||
| 17 | d: u3, | ||
| 18 | e: u5, | ||
| 19 | f: u16, | ||
| 20 | g: u16, | ||
| 21 | h: u9, | ||
| 22 | i: u7, | ||
| 23 | }; | ||
| 24 | |||
| 25 | const P = packed struct { | ||
| 26 | a: u8, | ||
| 27 | b: u32, | ||
| 28 | c: u8, | ||
| 29 | d: u3, | ||
| 30 | e: u5, | ||
| 31 | f: u16, | ||
| 32 | g: u16, | ||
| 33 | h: u9, | ||
| 34 | i: u7, | ||
| 35 | }; | ||
| 36 | |||
| 37 | test "@byteOffsetOf" { | ||
| 38 | // Packed structs have fixed memory layout | ||
| 39 | try expect(@byteOffsetOf(P, "a") == 0); | ||
| 40 | try expect(@byteOffsetOf(P, "b") == 1); | ||
| 41 | try expect(@byteOffsetOf(P, "c") == 5); | ||
| 42 | try expect(@byteOffsetOf(P, "d") == 6); | ||
| 43 | try expect(@byteOffsetOf(P, "e") == 6); | ||
| 44 | try expect(@byteOffsetOf(P, "f") == 7); | ||
| 45 | try expect(@byteOffsetOf(P, "g") == 9); | ||
| 46 | try expect(@byteOffsetOf(P, "h") == 11); | ||
| 47 | try expect(@byteOffsetOf(P, "i") == 12); | ||
| 48 | |||
| 49 | // Normal struct fields can be moved/padded | ||
| 50 | var a: A = undefined; | ||
| 51 | try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); | ||
| 52 | try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); | ||
| 53 | try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); | ||
| 54 | try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); | ||
| 55 | try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); | ||
| 56 | try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); | ||
| 57 | try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); | ||
| 58 | try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @byteOffsetOf(A, "h")); | ||
| 59 | try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @byteOffsetOf(A, "i")); | ||
| 60 | } | ||
| 61 | |||
| 62 | test "@byteOffsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" { | ||
| 63 | const p3a_len = 3; | ||
| 64 | const P3 = packed struct { | ||
| 65 | a: [p3a_len]u8, | ||
| 66 | b: usize, | ||
| 67 | }; | ||
| 68 | try std.testing.expectEqual(0, @byteOffsetOf(P3, "a")); | ||
| 69 | try std.testing.expectEqual(p3a_len, @byteOffsetOf(P3, "b")); | ||
| 70 | |||
| 71 | const p5a_len = 5; | ||
| 72 | const P5 = packed struct { | ||
| 73 | a: [p5a_len]u8, | ||
| 74 | b: usize, | ||
| 75 | }; | ||
| 76 | try std.testing.expectEqual(0, @byteOffsetOf(P5, "a")); | ||
| 77 | try std.testing.expectEqual(p5a_len, @byteOffsetOf(P5, "b")); | ||
| 78 | |||
| 79 | const p6a_len = 6; | ||
| 80 | const P6 = packed struct { | ||
| 81 | a: [p6a_len]u8, | ||
| 82 | b: usize, | ||
| 83 | }; | ||
| 84 | try std.testing.expectEqual(0, @byteOffsetOf(P6, "a")); | ||
| 85 | try std.testing.expectEqual(p6a_len, @byteOffsetOf(P6, "b")); | ||
| 86 | |||
| 87 | const p7a_len = 7; | ||
| 88 | const P7 = packed struct { | ||
| 89 | a: [p7a_len]u8, | ||
| 90 | b: usize, | ||
| 91 | }; | ||
| 92 | try std.testing.expectEqual(0, @byteOffsetOf(P7, "a")); | ||
| 93 | try std.testing.expectEqual(p7a_len, @byteOffsetOf(P7, "b")); | ||
| 94 | |||
| 95 | const p9a_len = 9; | ||
| 96 | const P9 = packed struct { | ||
| 97 | a: [p9a_len]u8, | ||
| 98 | b: usize, | ||
| 99 | }; | ||
| 100 | try std.testing.expectEqual(0, @byteOffsetOf(P9, "a")); | ||
| 101 | try std.testing.expectEqual(p9a_len, @byteOffsetOf(P9, "b")); | ||
| 102 | |||
| 103 | // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases | ||
| 104 | } | ||
| 105 | |||
| 106 | test "@bitOffsetOf" { | ||
| 107 | // Packed structs have fixed memory layout | ||
| 108 | try expect(@bitOffsetOf(P, "a") == 0); | ||
| 109 | try expect(@bitOffsetOf(P, "b") == 8); | ||
| 110 | try expect(@bitOffsetOf(P, "c") == 40); | ||
| 111 | try expect(@bitOffsetOf(P, "d") == 48); | ||
| 112 | try expect(@bitOffsetOf(P, "e") == 51); | ||
| 113 | try expect(@bitOffsetOf(P, "f") == 56); | ||
| 114 | try expect(@bitOffsetOf(P, "g") == 72); | ||
| 115 | |||
| 116 | try expect(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 117 | try expect(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 118 | try expect(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 119 | try expect(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 120 | try expect(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 121 | try expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 122 | try expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 123 | } | ||
| 124 | |||
| 125 | test "@sizeOf on compile-time types" { | ||
| 126 | try expect(@sizeOf(comptime_int) == 0); | ||
| 127 | try expect(@sizeOf(comptime_float) == 0); | ||
| 128 | try expect(@sizeOf(@TypeOf(.hi)) == 0); | ||
| 129 | try expect(@sizeOf(@TypeOf(type)) == 0); | ||
| 130 | } | ||
| 131 | |||
| 132 | test "@sizeOf(T) == 0 doesn't force resolving struct size" { | ||
| 133 | const S = struct { | ||
| 134 | const Foo = struct { | ||
| 135 | y: if (@sizeOf(Foo) == 0) u64 else u32, | ||
| 136 | }; | ||
| 137 | const Bar = struct { | ||
| 138 | x: i32, | ||
| 139 | y: if (0 == @sizeOf(Bar)) u64 else u32, | ||
| 140 | }; | ||
| 141 | }; | ||
| 142 | |||
| 143 | try expect(@sizeOf(S.Foo) == 4); | ||
| 144 | try expect(@sizeOf(S.Bar) == 8); | ||
| 145 | } | ||
| 146 | |||
| 147 | test "@TypeOf() has no runtime side effects" { | ||
| 148 | const S = struct { | ||
| 149 | fn foo(comptime T: type, ptr: *T) T { | ||
| 150 | ptr.* += 1; | ||
| 151 | return ptr.*; | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | var data: i32 = 0; | ||
| 155 | const T = @TypeOf(S.foo(i32, &data)); | ||
| 156 | comptime try expect(T == i32); | ||
| 157 | try expect(data == 0); | ||
| 158 | } | ||
| 159 | |||
| 160 | test "@TypeOf() with multiple arguments" { | ||
| 161 | { | ||
| 162 | var var_1: u32 = undefined; | ||
| 163 | var var_2: u8 = undefined; | ||
| 164 | var var_3: u64 = undefined; | ||
| 165 | comptime try expect(@TypeOf(var_1, var_2, var_3) == u64); | ||
| 166 | } | ||
| 167 | { | ||
| 168 | var var_1: f16 = undefined; | ||
| 169 | var var_2: f32 = undefined; | ||
| 170 | var var_3: f64 = undefined; | ||
| 171 | comptime try expect(@TypeOf(var_1, var_2, var_3) == f64); | ||
| 172 | } | ||
| 173 | { | ||
| 174 | var var_1: u16 = undefined; | ||
| 175 | comptime try expect(@TypeOf(var_1, 0xffff) == u16); | ||
| 176 | } | ||
| 177 | { | ||
| 178 | var var_1: f32 = undefined; | ||
| 179 | comptime try expect(@TypeOf(var_1, 3.1415) == f32); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | test "branching logic inside @TypeOf" { | ||
| 184 | const S = struct { | ||
| 185 | var data: i32 = 0; | ||
| 186 | fn foo() anyerror!i32 { | ||
| 187 | data += 1; | ||
| 188 | return undefined; | ||
| 189 | } | ||
| 190 | }; | ||
| 191 | const T = @TypeOf(S.foo() catch undefined); | ||
| 192 | comptime try expect(T == i32); | ||
| 193 | try expect(S.data == 0); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn fn1(alpha: bool) void { | ||
| 197 | const n: usize = 7; | ||
| 198 | const v = if (alpha) n else @sizeOf(usize); | ||
| 199 | } | ||
| 200 | |||
| 201 | test "lazy @sizeOf result is checked for definedness" { | ||
| 202 | const f = fn1; | ||
| 203 | } | ||
| 204 | |||
| 205 | test "@bitSizeOf" { | ||
| 206 | try expect(@bitSizeOf(u2) == 2); | ||
| 207 | try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); | ||
| 208 | try expect(@bitSizeOf(struct { | ||
| 209 | a: u2, | ||
| 210 | }) == 8); | ||
| 211 | try expect(@bitSizeOf(packed struct { | ||
| 212 | a: u2, | ||
| 213 | }) == 2); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "@sizeOf comparison against zero" { | ||
| 217 | const S0 = struct { | ||
| 218 | f: *@This(), | ||
| 219 | }; | ||
| 220 | const U0 = union { | ||
| 221 | f: *@This(), | ||
| 222 | }; | ||
| 223 | const S1 = struct { | ||
| 224 | fn H(comptime T: type) type { | ||
| 225 | return struct { | ||
| 226 | x: T, | ||
| 227 | }; | ||
| 228 | } | ||
| 229 | f0: H(*@This()), | ||
| 230 | f1: H(**@This()), | ||
| 231 | f2: H(***@This()), | ||
| 232 | }; | ||
| 233 | const U1 = union { | ||
| 234 | fn H(comptime T: type) type { | ||
| 235 | return struct { | ||
| 236 | x: T, | ||
| 237 | }; | ||
| 238 | } | ||
| 239 | f0: H(*@This()), | ||
| 240 | f1: H(**@This()), | ||
| 241 | f2: H(***@This()), | ||
| 242 | }; | ||
| 243 | const S = struct { | ||
| 244 | fn doTheTest(comptime T: type, comptime result: bool) !void { | ||
| 245 | try expectEqual(result, @sizeOf(T) > 0); | ||
| 246 | } | ||
| 247 | }; | ||
| 248 | // Zero-sized type | ||
| 249 | try S.doTheTest(u0, false); | ||
| 250 | try S.doTheTest(*u0, false); | ||
| 251 | // Non byte-sized type | ||
| 252 | try S.doTheTest(u1, true); | ||
| 253 | try S.doTheTest(*u1, true); | ||
| 254 | // Regular type | ||
| 255 | try S.doTheTest(u8, true); | ||
| 256 | try S.doTheTest(*u8, true); | ||
| 257 | try S.doTheTest(f32, true); | ||
| 258 | try S.doTheTest(*f32, true); | ||
| 259 | // Container with ptr pointing to themselves | ||
| 260 | try S.doTheTest(S0, true); | ||
| 261 | try S.doTheTest(U0, true); | ||
| 262 | try S.doTheTest(S1, true); | ||
| 263 | try S.doTheTest(U1, true); | ||
| 264 | } | ||
test/stage1/behavior/slice.zig deleted-337| ... | @@ -1,337 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | ||
| 8 | const y = x[0x100..]; | ||
| 9 | test "compile time slice of pointer to hard coded address" { | ||
| 10 | try expect(@ptrToInt(x) == 0x1000); | ||
| 11 | try expect(x.len == 0x500); | ||
| 12 | |||
| 13 | try expect(@ptrToInt(y) == 0x1100); | ||
| 14 | try expect(y.len == 0x400); | ||
| 15 | } | ||
| 16 | |||
| 17 | test "runtime safety lets us slice from len..len" { | ||
| 18 | var an_array = [_]u8{ | ||
| 19 | 1, | ||
| 20 | 2, | ||
| 21 | 3, | ||
| 22 | }; | ||
| 23 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | ||
| 27 | return a_slice[start..end]; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "implicitly cast array of size 0 to slice" { | ||
| 31 | var msg = [_]u8{}; | ||
| 32 | try assertLenIsZero(&msg); | ||
| 33 | } | ||
| 34 | |||
| 35 | fn assertLenIsZero(msg: []const u8) !void { | ||
| 36 | try expect(msg.len == 0); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "C pointer" { | ||
| 40 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | ||
| 41 | var len: u32 = 10; | ||
| 42 | var slice = buf[0..len]; | ||
| 43 | try expectEqualSlices(u8, "kjdhfkjdhf", slice); | ||
| 44 | } | ||
| 45 | |||
| 46 | test "C pointer slice access" { | ||
| 47 | var buf: [10]u32 = [1]u32{42} ** 10; | ||
| 48 | const c_ptr = @ptrCast([*c]const u32, &buf); | ||
| 49 | |||
| 50 | var runtime_zero: usize = 0; | ||
| 51 | comptime try expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); | ||
| 52 | comptime try expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); | ||
| 53 | |||
| 54 | for (c_ptr[0..5]) |*cl| { | ||
| 55 | try expectEqual(@as(u32, 42), cl.*); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | fn sliceSum(comptime q: []const u8) i32 { | ||
| 60 | comptime var result = 0; | ||
| 61 | inline for (q) |item| { | ||
| 62 | result += item; | ||
| 63 | } | ||
| 64 | return result; | ||
| 65 | } | ||
| 66 | |||
| 67 | test "comptime slices are disambiguated" { | ||
| 68 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | ||
| 69 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | ||
| 70 | } | ||
| 71 | |||
| 72 | test "slice type with custom alignment" { | ||
| 73 | const LazilyResolvedType = struct { | ||
| 74 | anything: i32, | ||
| 75 | }; | ||
| 76 | var slice: []align(32) LazilyResolvedType = undefined; | ||
| 77 | var array: [10]LazilyResolvedType align(32) = undefined; | ||
| 78 | slice = &array; | ||
| 79 | slice[1].anything = 42; | ||
| 80 | try expect(array[1].anything == 42); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "access len index of sentinel-terminated slice" { | ||
| 84 | const S = struct { | ||
| 85 | fn doTheTest() !void { | ||
| 86 | var slice: [:0]const u8 = "hello"; | ||
| 87 | |||
| 88 | try expect(slice.len == 5); | ||
| 89 | try expect(slice[5] == 0); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | try S.doTheTest(); | ||
| 93 | comptime try S.doTheTest(); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "obtaining a null terminated slice" { | ||
| 97 | // here we have a normal array | ||
| 98 | var buf: [50]u8 = undefined; | ||
| 99 | |||
| 100 | buf[0] = 'a'; | ||
| 101 | buf[1] = 'b'; | ||
| 102 | buf[2] = 'c'; | ||
| 103 | buf[3] = 0; | ||
| 104 | |||
| 105 | // now we obtain a null terminated slice: | ||
| 106 | const ptr = buf[0..3 :0]; | ||
| 107 | |||
| 108 | var runtime_len: usize = 3; | ||
| 109 | const ptr2 = buf[0..runtime_len :0]; | ||
| 110 | // ptr2 is a null-terminated slice | ||
| 111 | comptime try expect(@TypeOf(ptr2) == [:0]u8); | ||
| 112 | comptime try expect(@TypeOf(ptr2[0..2]) == *[2]u8); | ||
| 113 | var runtime_zero: usize = 0; | ||
| 114 | comptime try expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "empty array to slice" { | ||
| 118 | const S = struct { | ||
| 119 | fn doTheTest() !void { | ||
| 120 | const empty: []align(16) u8 = &[_]u8{}; | ||
| 121 | const align_1: []align(1) u8 = empty; | ||
| 122 | const align_4: []align(4) u8 = empty; | ||
| 123 | const align_16: []align(16) u8 = empty; | ||
| 124 | try expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment); | ||
| 125 | try expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment); | ||
| 126 | try expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment); | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | |||
| 130 | try S.doTheTest(); | ||
| 131 | comptime try S.doTheTest(); | ||
| 132 | } | ||
| 133 | |||
| 134 | test "@ptrCast slice to pointer" { | ||
| 135 | const S = struct { | ||
| 136 | fn doTheTest() !void { | ||
| 137 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
| 138 | var slice: []u8 = &array; | ||
| 139 | var ptr = @ptrCast(*u16, slice); | ||
| 140 | try expect(ptr.* == 65535); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | |||
| 144 | try S.doTheTest(); | ||
| 145 | comptime try S.doTheTest(); | ||
| 146 | } | ||
| 147 | |||
| 148 | test "slice syntax resulting in pointer-to-array" { | ||
| 149 | const S = struct { | ||
| 150 | fn doTheTest() !void { | ||
| 151 | try testArray(); | ||
| 152 | try testArrayZ(); | ||
| 153 | try testArray0(); | ||
| 154 | try testArrayAlign(); | ||
| 155 | try testPointer(); | ||
| 156 | try testPointerZ(); | ||
| 157 | try testPointer0(); | ||
| 158 | try testPointerAlign(); | ||
| 159 | try testSlice(); | ||
| 160 | try testSliceZ(); | ||
| 161 | try testSlice0(); | ||
| 162 | try testSliceOpt(); | ||
| 163 | try testSliceAlign(); | ||
| 164 | } | ||
| 165 | |||
| 166 | fn testArray() !void { | ||
| 167 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 168 | var slice = array[1..3]; | ||
| 169 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 170 | try expect(slice[0] == 2); | ||
| 171 | try expect(slice[1] == 3); | ||
| 172 | } | ||
| 173 | |||
| 174 | fn testArrayZ() !void { | ||
| 175 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 176 | comptime try expect(@TypeOf(array[1..3]) == *[2]u8); | ||
| 177 | comptime try expect(@TypeOf(array[1..5]) == *[4:0]u8); | ||
| 178 | comptime try expect(@TypeOf(array[1..]) == *[4:0]u8); | ||
| 179 | comptime try expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); | ||
| 180 | } | ||
| 181 | |||
| 182 | fn testArray0() !void { | ||
| 183 | { | ||
| 184 | var array = [0]u8{}; | ||
| 185 | var slice = array[0..0]; | ||
| 186 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 187 | } | ||
| 188 | { | ||
| 189 | var array = [0:0]u8{}; | ||
| 190 | var slice = array[0..0]; | ||
| 191 | comptime try expect(@TypeOf(slice) == *[0:0]u8); | ||
| 192 | try expect(slice[0] == 0); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | fn testArrayAlign() !void { | ||
| 197 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 198 | var slice = array[4..5]; | ||
| 199 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 200 | try expect(slice[0] == 5); | ||
| 201 | comptime try expect(@TypeOf(array[0..2]) == *align(4) [2]u8); | ||
| 202 | } | ||
| 203 | |||
| 204 | fn testPointer() !void { | ||
| 205 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 206 | var pointer: [*]u8 = &array; | ||
| 207 | var slice = pointer[1..3]; | ||
| 208 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 209 | try expect(slice[0] == 2); | ||
| 210 | try expect(slice[1] == 3); | ||
| 211 | } | ||
| 212 | |||
| 213 | fn testPointerZ() !void { | ||
| 214 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 215 | var pointer: [*:0]u8 = &array; | ||
| 216 | comptime try expect(@TypeOf(pointer[1..3]) == *[2]u8); | ||
| 217 | comptime try expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); | ||
| 218 | } | ||
| 219 | |||
| 220 | fn testPointer0() !void { | ||
| 221 | var pointer: [*]const u0 = &[1]u0{0}; | ||
| 222 | var slice = pointer[0..1]; | ||
| 223 | comptime try expect(@TypeOf(slice) == *const [1]u0); | ||
| 224 | try expect(slice[0] == 0); | ||
| 225 | } | ||
| 226 | |||
| 227 | fn testPointerAlign() !void { | ||
| 228 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 229 | var pointer: [*]align(4) u8 = &array; | ||
| 230 | var slice = pointer[4..5]; | ||
| 231 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 232 | try expect(slice[0] == 5); | ||
| 233 | comptime try expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); | ||
| 234 | } | ||
| 235 | |||
| 236 | fn testSlice() !void { | ||
| 237 | var array = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 238 | var src_slice: []u8 = &array; | ||
| 239 | var slice = src_slice[1..3]; | ||
| 240 | comptime try expect(@TypeOf(slice) == *[2]u8); | ||
| 241 | try expect(slice[0] == 2); | ||
| 242 | try expect(slice[1] == 3); | ||
| 243 | } | ||
| 244 | |||
| 245 | fn testSliceZ() !void { | ||
| 246 | var array = [5:0]u8{ 1, 2, 3, 4, 5 }; | ||
| 247 | var slice: [:0]u8 = &array; | ||
| 248 | comptime try expect(@TypeOf(slice[1..3]) == *[2]u8); | ||
| 249 | comptime try expect(@TypeOf(slice[1..]) == [:0]u8); | ||
| 250 | comptime try expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); | ||
| 251 | } | ||
| 252 | |||
| 253 | fn testSliceOpt() !void { | ||
| 254 | var array: [2]u8 = [2]u8{ 1, 2 }; | ||
| 255 | var slice: ?[]u8 = &array; | ||
| 256 | comptime try expect(@TypeOf(&array, slice) == ?[]u8); | ||
| 257 | comptime try expect(@TypeOf(slice.?[0..2]) == *[2]u8); | ||
| 258 | } | ||
| 259 | |||
| 260 | fn testSlice0() !void { | ||
| 261 | { | ||
| 262 | var array = [0]u8{}; | ||
| 263 | var src_slice: []u8 = &array; | ||
| 264 | var slice = src_slice[0..0]; | ||
| 265 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 266 | } | ||
| 267 | { | ||
| 268 | var array = [0:0]u8{}; | ||
| 269 | var src_slice: [:0]u8 = &array; | ||
| 270 | var slice = src_slice[0..0]; | ||
| 271 | comptime try expect(@TypeOf(slice) == *[0]u8); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | fn testSliceAlign() !void { | ||
| 276 | var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; | ||
| 277 | var src_slice: []align(4) u8 = &array; | ||
| 278 | var slice = src_slice[4..5]; | ||
| 279 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 280 | try expect(slice[0] == 5); | ||
| 281 | comptime try expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); | ||
| 282 | } | ||
| 283 | |||
| 284 | fn testConcatStrLiterals() !void { | ||
| 285 | try expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); | ||
| 286 | try expectEqualSlices("a"[0.. :0] ++ "b"[0.. :0], "ab"); | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | |||
| 290 | try S.doTheTest(); | ||
| 291 | comptime try S.doTheTest(); | ||
| 292 | } | ||
| 293 | |||
| 294 | test "slice of hardcoded address to pointer" { | ||
| 295 | const S = struct { | ||
| 296 | fn doTheTest() !void { | ||
| 297 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | ||
| 298 | comptime try expect(@TypeOf(pointer) == *[2]u8); | ||
| 299 | const slice: []const u8 = pointer; | ||
| 300 | try expect(@ptrToInt(slice.ptr) == 4); | ||
| 301 | try expect(slice.len == 2); | ||
| 302 | } | ||
| 303 | }; | ||
| 304 | |||
| 305 | try S.doTheTest(); | ||
| 306 | } | ||
| 307 | |||
| 308 | test "type coercion of pointer to anon struct literal to pointer to slice" { | ||
| 309 | const S = struct { | ||
| 310 | const U = union { | ||
| 311 | a: u32, | ||
| 312 | b: bool, | ||
| 313 | c: []const u8, | ||
| 314 | }; | ||
| 315 | |||
| 316 | fn doTheTest() !void { | ||
| 317 | var x1: u8 = 42; | ||
| 318 | const t1 = &.{ x1, 56, 54 }; | ||
| 319 | var slice1: []const u8 = t1; | ||
| 320 | try expect(slice1.len == 3); | ||
| 321 | try expect(slice1[0] == 42); | ||
| 322 | try expect(slice1[1] == 56); | ||
| 323 | try expect(slice1[2] == 54); | ||
| 324 | |||
| 325 | var x2: []const u8 = "hello"; | ||
| 326 | const t2 = &.{ x2, ", ", "world!" }; | ||
| 327 | // @compileLog(@TypeOf(t2)); | ||
| 328 | var slice2: []const []const u8 = t2; | ||
| 329 | try expect(slice2.len == 3); | ||
| 330 | try expect(mem.eql(u8, slice2[0], "hello")); | ||
| 331 | try expect(mem.eql(u8, slice2[1], ", ")); | ||
| 332 | try expect(mem.eql(u8, slice2[2], "world!")); | ||
| 333 | } | ||
| 334 | }; | ||
| 335 | // try S.doTheTest(); | ||
| 336 | comptime try S.doTheTest(); | ||
| 337 | } | ||
test/stage1/behavior/slice_sentinel_comptime.zig deleted-199| ... | @@ -1,199 +0,0 @@ | ||
| 1 | test "comptime slice-sentinel in bounds (unterminated)" { | ||
| 2 | // array | ||
| 3 | comptime { | ||
| 4 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 5 | const slice = target[0..3 :'d']; | ||
| 6 | } | ||
| 7 | |||
| 8 | // ptr_array | ||
| 9 | comptime { | ||
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 11 | var target = &buf; | ||
| 12 | const slice = target[0..3 :'d']; | ||
| 13 | } | ||
| 14 | |||
| 15 | // vector_ConstPtrSpecialBaseArray | ||
| 16 | comptime { | ||
| 17 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 18 | var target: [*]u8 = &buf; | ||
| 19 | const slice = target[0..3 :'d']; | ||
| 20 | } | ||
| 21 | |||
| 22 | // vector_ConstPtrSpecialRef | ||
| 23 | comptime { | ||
| 24 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 25 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 26 | const slice = target[0..3 :'d']; | ||
| 27 | } | ||
| 28 | |||
| 29 | // cvector_ConstPtrSpecialBaseArray | ||
| 30 | comptime { | ||
| 31 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 32 | var target: [*c]u8 = &buf; | ||
| 33 | const slice = target[0..3 :'d']; | ||
| 34 | } | ||
| 35 | |||
| 36 | // cvector_ConstPtrSpecialRef | ||
| 37 | comptime { | ||
| 38 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 39 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 40 | const slice = target[0..3 :'d']; | ||
| 41 | } | ||
| 42 | |||
| 43 | // slice | ||
| 44 | comptime { | ||
| 45 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 46 | var target: []u8 = &buf; | ||
| 47 | const slice = target[0..3 :'d']; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | test "comptime slice-sentinel in bounds (end,unterminated)" { | ||
| 52 | // array | ||
| 53 | comptime { | ||
| 54 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 55 | const slice = target[0..13 :0xff]; | ||
| 56 | } | ||
| 57 | |||
| 58 | // ptr_array | ||
| 59 | comptime { | ||
| 60 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 61 | var target = &buf; | ||
| 62 | const slice = target[0..13 :0xff]; | ||
| 63 | } | ||
| 64 | |||
| 65 | // vector_ConstPtrSpecialBaseArray | ||
| 66 | comptime { | ||
| 67 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 68 | var target: [*]u8 = &buf; | ||
| 69 | const slice = target[0..13 :0xff]; | ||
| 70 | } | ||
| 71 | |||
| 72 | // vector_ConstPtrSpecialRef | ||
| 73 | comptime { | ||
| 74 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 75 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 76 | const slice = target[0..13 :0xff]; | ||
| 77 | } | ||
| 78 | |||
| 79 | // cvector_ConstPtrSpecialBaseArray | ||
| 80 | comptime { | ||
| 81 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 82 | var target: [*c]u8 = &buf; | ||
| 83 | const slice = target[0..13 :0xff]; | ||
| 84 | } | ||
| 85 | |||
| 86 | // cvector_ConstPtrSpecialRef | ||
| 87 | comptime { | ||
| 88 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 89 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 90 | const slice = target[0..13 :0xff]; | ||
| 91 | } | ||
| 92 | |||
| 93 | // slice | ||
| 94 | comptime { | ||
| 95 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{0xff} ** 10; | ||
| 96 | var target: []u8 = &buf; | ||
| 97 | const slice = target[0..13 :0xff]; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | test "comptime slice-sentinel in bounds (terminated)" { | ||
| 102 | // array | ||
| 103 | comptime { | ||
| 104 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 105 | const slice = target[0..3 :'d']; | ||
| 106 | } | ||
| 107 | |||
| 108 | // ptr_array | ||
| 109 | comptime { | ||
| 110 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 111 | var target = &buf; | ||
| 112 | const slice = target[0..3 :'d']; | ||
| 113 | } | ||
| 114 | |||
| 115 | // vector_ConstPtrSpecialBaseArray | ||
| 116 | comptime { | ||
| 117 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 118 | var target: [*]u8 = &buf; | ||
| 119 | const slice = target[0..3 :'d']; | ||
| 120 | } | ||
| 121 | |||
| 122 | // vector_ConstPtrSpecialRef | ||
| 123 | comptime { | ||
| 124 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 125 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 126 | const slice = target[0..3 :'d']; | ||
| 127 | } | ||
| 128 | |||
| 129 | // cvector_ConstPtrSpecialBaseArray | ||
| 130 | comptime { | ||
| 131 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 132 | var target: [*c]u8 = &buf; | ||
| 133 | const slice = target[0..3 :'d']; | ||
| 134 | } | ||
| 135 | |||
| 136 | // cvector_ConstPtrSpecialRef | ||
| 137 | comptime { | ||
| 138 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 139 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 140 | const slice = target[0..3 :'d']; | ||
| 141 | } | ||
| 142 | |||
| 143 | // slice | ||
| 144 | comptime { | ||
| 145 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 146 | var target: []u8 = &buf; | ||
| 147 | const slice = target[0..3 :'d']; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | test "comptime slice-sentinel in bounds (on target sentinel)" { | ||
| 152 | // array | ||
| 153 | comptime { | ||
| 154 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 155 | const slice = target[0..14 :0]; | ||
| 156 | } | ||
| 157 | |||
| 158 | // ptr_array | ||
| 159 | comptime { | ||
| 160 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 161 | var target = &buf; | ||
| 162 | const slice = target[0..14 :0]; | ||
| 163 | } | ||
| 164 | |||
| 165 | // vector_ConstPtrSpecialBaseArray | ||
| 166 | comptime { | ||
| 167 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 168 | var target: [*]u8 = &buf; | ||
| 169 | const slice = target[0..14 :0]; | ||
| 170 | } | ||
| 171 | |||
| 172 | // vector_ConstPtrSpecialRef | ||
| 173 | comptime { | ||
| 174 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 175 | var target: [*]u8 = @ptrCast([*]u8, &buf); | ||
| 176 | const slice = target[0..14 :0]; | ||
| 177 | } | ||
| 178 | |||
| 179 | // cvector_ConstPtrSpecialBaseArray | ||
| 180 | comptime { | ||
| 181 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 182 | var target: [*c]u8 = &buf; | ||
| 183 | const slice = target[0..14 :0]; | ||
| 184 | } | ||
| 185 | |||
| 186 | // cvector_ConstPtrSpecialRef | ||
| 187 | comptime { | ||
| 188 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 189 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | ||
| 190 | const slice = target[0..14 :0]; | ||
| 191 | } | ||
| 192 | |||
| 193 | // slice | ||
| 194 | comptime { | ||
| 195 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | ||
| 196 | var target: []u8 = &buf; | ||
| 197 | const slice = target[0..14 :0]; | ||
| 198 | } | ||
| 199 | } | ||
test/stage1/behavior/src.zig deleted-17| ... | @@ -1,17 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "@src" { | ||
| 5 | try doTheTest(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn doTheTest() !void { | ||
| 9 | const src = @src(); | ||
| 10 | |||
| 11 | try expect(src.line == 9); | ||
| 12 | try expect(src.column == 17); | ||
| 13 | try expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); | ||
| 14 | try expect(std.mem.endsWith(u8, src.file, "src.zig")); | ||
| 15 | try expect(src.fn_name[src.fn_name.len] == 0); | ||
| 16 | try expect(src.file[src.file.len] == 0); | ||
| 17 | } | ||
test/stage1/behavior/struct.zig deleted-945| ... | @@ -1,945 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 6 | const maxInt = std.math.maxInt; | ||
| 7 | const StructWithNoFields = struct { | ||
| 8 | fn add(a: i32, b: i32) i32 { | ||
| 9 | return a + b; | ||
| 10 | } | ||
| 11 | }; | ||
| 12 | const empty_global_instance = StructWithNoFields{}; | ||
| 13 | |||
| 14 | top_level_field: i32, | ||
| 15 | |||
| 16 | test "top level fields" { | ||
| 17 | var instance = @This(){ | ||
| 18 | .top_level_field = 1234, | ||
| 19 | }; | ||
| 20 | instance.top_level_field += 1; | ||
| 21 | try expectEqual(@as(i32, 1235), instance.top_level_field); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "call struct static method" { | ||
| 25 | const result = StructWithNoFields.add(3, 4); | ||
| 26 | try expect(result == 7); | ||
| 27 | } | ||
| 28 | |||
| 29 | test "return empty struct instance" { | ||
| 30 | _ = returnEmptyStructInstance(); | ||
| 31 | } | ||
| 32 | fn returnEmptyStructInstance() StructWithNoFields { | ||
| 33 | return empty_global_instance; | ||
| 34 | } | ||
| 35 | |||
| 36 | const should_be_11 = StructWithNoFields.add(5, 6); | ||
| 37 | |||
| 38 | test "invoke static method in global scope" { | ||
| 39 | try expect(should_be_11 == 11); | ||
| 40 | } | ||
| 41 | |||
| 42 | test "void struct fields" { | ||
| 43 | const foo = VoidStructFieldsFoo{ | ||
| 44 | .a = void{}, | ||
| 45 | .b = 1, | ||
| 46 | .c = void{}, | ||
| 47 | }; | ||
| 48 | try expect(foo.b == 1); | ||
| 49 | try expect(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 50 | } | ||
| 51 | const VoidStructFieldsFoo = struct { | ||
| 52 | a: void, | ||
| 53 | b: i32, | ||
| 54 | c: void, | ||
| 55 | }; | ||
| 56 | |||
| 57 | test "structs" { | ||
| 58 | var foo: StructFoo = undefined; | ||
| 59 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 60 | foo.a += 1; | ||
| 61 | foo.b = foo.a == 1; | ||
| 62 | try testFoo(foo); | ||
| 63 | testMutation(&foo); | ||
| 64 | try expect(foo.c == 100); | ||
| 65 | } | ||
| 66 | const StructFoo = struct { | ||
| 67 | a: i32, | ||
| 68 | b: bool, | ||
| 69 | c: f32, | ||
| 70 | }; | ||
| 71 | fn testFoo(foo: StructFoo) !void { | ||
| 72 | try expect(foo.b); | ||
| 73 | } | ||
| 74 | fn testMutation(foo: *StructFoo) void { | ||
| 75 | foo.c = 100; | ||
| 76 | } | ||
| 77 | |||
| 78 | const Node = struct { | ||
| 79 | val: Val, | ||
| 80 | next: *Node, | ||
| 81 | }; | ||
| 82 | |||
| 83 | const Val = struct { | ||
| 84 | x: i32, | ||
| 85 | }; | ||
| 86 | |||
| 87 | test "struct point to self" { | ||
| 88 | var root: Node = undefined; | ||
| 89 | root.val.x = 1; | ||
| 90 | |||
| 91 | var node: Node = undefined; | ||
| 92 | node.next = &root; | ||
| 93 | node.val.x = 2; | ||
| 94 | |||
| 95 | root.next = &node; | ||
| 96 | |||
| 97 | try expect(node.next.next.next.val.x == 1); | ||
| 98 | } | ||
| 99 | |||
| 100 | test "struct byval assign" { | ||
| 101 | var foo1: StructFoo = undefined; | ||
| 102 | var foo2: StructFoo = undefined; | ||
| 103 | |||
| 104 | foo1.a = 1234; | ||
| 105 | foo2.a = 0; | ||
| 106 | try expect(foo2.a == 0); | ||
| 107 | foo2 = foo1; | ||
| 108 | try expect(foo2.a == 1234); | ||
| 109 | } | ||
| 110 | |||
| 111 | fn structInitializer() void { | ||
| 112 | const val = Val{ .x = 42 }; | ||
| 113 | try expect(val.x == 42); | ||
| 114 | } | ||
| 115 | |||
| 116 | test "fn call of struct field" { | ||
| 117 | const Foo = struct { | ||
| 118 | ptr: fn () i32, | ||
| 119 | }; | ||
| 120 | const S = struct { | ||
| 121 | fn aFunc() i32 { | ||
| 122 | return 13; | ||
| 123 | } | ||
| 124 | |||
| 125 | fn callStructField(foo: Foo) i32 { | ||
| 126 | return foo.ptr(); | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | |||
| 130 | try expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13); | ||
| 131 | } | ||
| 132 | |||
| 133 | test "store member function in variable" { | ||
| 134 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 135 | const memberFn = MemberFnTestFoo.member; | ||
| 136 | const result = memberFn(instance); | ||
| 137 | try expect(result == 1234); | ||
| 138 | } | ||
| 139 | const MemberFnTestFoo = struct { | ||
| 140 | x: i32, | ||
| 141 | fn member(foo: MemberFnTestFoo) i32 { | ||
| 142 | return foo.x; | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 146 | test "call member function directly" { | ||
| 147 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 148 | const result = MemberFnTestFoo.member(instance); | ||
| 149 | try expect(result == 1234); | ||
| 150 | } | ||
| 151 | |||
| 152 | test "member functions" { | ||
| 153 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 154 | try expect(r.getSeed() == 1234); | ||
| 155 | } | ||
| 156 | const MemberFnRand = struct { | ||
| 157 | seed: u32, | ||
| 158 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 159 | return r.seed; | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 163 | test "return struct byval from function" { | ||
| 164 | const bar = makeBar(1234, 5678); | ||
| 165 | try expect(bar.y == 5678); | ||
| 166 | } | ||
| 167 | const Bar = struct { | ||
| 168 | x: i32, | ||
| 169 | y: i32, | ||
| 170 | }; | ||
| 171 | fn makeBar(x: i32, y: i32) Bar { | ||
| 172 | return Bar{ | ||
| 173 | .x = x, | ||
| 174 | .y = y, | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | test "empty struct method call" { | ||
| 179 | const es = EmptyStruct{}; | ||
| 180 | try expect(es.method() == 1234); | ||
| 181 | } | ||
| 182 | const EmptyStruct = struct { | ||
| 183 | fn method(es: *const EmptyStruct) i32 { | ||
| 184 | return 1234; | ||
| 185 | } | ||
| 186 | }; | ||
| 187 | |||
| 188 | test "return empty struct from fn" { | ||
| 189 | _ = testReturnEmptyStructFromFn(); | ||
| 190 | } | ||
| 191 | const EmptyStruct2 = struct {}; | ||
| 192 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 193 | return EmptyStruct2{}; | ||
| 194 | } | ||
| 195 | |||
| 196 | test "pass slice of empty struct to fn" { | ||
| 197 | try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1); | ||
| 198 | } | ||
| 199 | fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { | ||
| 200 | return slice.len; | ||
| 201 | } | ||
| 202 | |||
| 203 | const APackedStruct = packed struct { | ||
| 204 | x: u8, | ||
| 205 | y: u8, | ||
| 206 | }; | ||
| 207 | |||
| 208 | test "packed struct" { | ||
| 209 | var foo = APackedStruct{ | ||
| 210 | .x = 1, | ||
| 211 | .y = 2, | ||
| 212 | }; | ||
| 213 | foo.y += 1; | ||
| 214 | const four = foo.x + foo.y; | ||
| 215 | try expect(four == 4); | ||
| 216 | } | ||
| 217 | |||
| 218 | const BitField1 = packed struct { | ||
| 219 | a: u3, | ||
| 220 | b: u3, | ||
| 221 | c: u2, | ||
| 222 | }; | ||
| 223 | |||
| 224 | const bit_field_1 = BitField1{ | ||
| 225 | .a = 1, | ||
| 226 | .b = 2, | ||
| 227 | .c = 3, | ||
| 228 | }; | ||
| 229 | |||
| 230 | test "bit field access" { | ||
| 231 | var data = bit_field_1; | ||
| 232 | try expect(getA(&data) == 1); | ||
| 233 | try expect(getB(&data) == 2); | ||
| 234 | try expect(getC(&data) == 3); | ||
| 235 | comptime try expect(@sizeOf(BitField1) == 1); | ||
| 236 | |||
| 237 | data.b += 1; | ||
| 238 | try expect(data.b == 3); | ||
| 239 | |||
| 240 | data.a += 1; | ||
| 241 | try expect(data.a == 2); | ||
| 242 | try expect(data.b == 3); | ||
| 243 | } | ||
| 244 | |||
| 245 | fn getA(data: *const BitField1) u3 { | ||
| 246 | return data.a; | ||
| 247 | } | ||
| 248 | |||
| 249 | fn getB(data: *const BitField1) u3 { | ||
| 250 | return data.b; | ||
| 251 | } | ||
| 252 | |||
| 253 | fn getC(data: *const BitField1) u2 { | ||
| 254 | return data.c; | ||
| 255 | } | ||
| 256 | |||
| 257 | const Foo24Bits = packed struct { | ||
| 258 | field: u24, | ||
| 259 | }; | ||
| 260 | const Foo96Bits = packed struct { | ||
| 261 | a: u24, | ||
| 262 | b: u24, | ||
| 263 | c: u24, | ||
| 264 | d: u24, | ||
| 265 | }; | ||
| 266 | |||
| 267 | test "packed struct 24bits" { | ||
| 268 | comptime { | ||
| 269 | try expect(@sizeOf(Foo24Bits) == 4); | ||
| 270 | if (@sizeOf(usize) == 4) { | ||
| 271 | try expect(@sizeOf(Foo96Bits) == 12); | ||
| 272 | } else { | ||
| 273 | try expect(@sizeOf(Foo96Bits) == 16); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | var value = Foo96Bits{ | ||
| 278 | .a = 0, | ||
| 279 | .b = 0, | ||
| 280 | .c = 0, | ||
| 281 | .d = 0, | ||
| 282 | }; | ||
| 283 | value.a += 1; | ||
| 284 | try expect(value.a == 1); | ||
| 285 | try expect(value.b == 0); | ||
| 286 | try expect(value.c == 0); | ||
| 287 | try expect(value.d == 0); | ||
| 288 | |||
| 289 | value.b += 1; | ||
| 290 | try expect(value.a == 1); | ||
| 291 | try expect(value.b == 1); | ||
| 292 | try expect(value.c == 0); | ||
| 293 | try expect(value.d == 0); | ||
| 294 | |||
| 295 | value.c += 1; | ||
| 296 | try expect(value.a == 1); | ||
| 297 | try expect(value.b == 1); | ||
| 298 | try expect(value.c == 1); | ||
| 299 | try expect(value.d == 0); | ||
| 300 | |||
| 301 | value.d += 1; | ||
| 302 | try expect(value.a == 1); | ||
| 303 | try expect(value.b == 1); | ||
| 304 | try expect(value.c == 1); | ||
| 305 | try expect(value.d == 1); | ||
| 306 | } | ||
| 307 | |||
| 308 | const Foo32Bits = packed struct { | ||
| 309 | field: u24, | ||
| 310 | pad: u8, | ||
| 311 | }; | ||
| 312 | |||
| 313 | const FooArray24Bits = packed struct { | ||
| 314 | a: u16, | ||
| 315 | b: [2]Foo32Bits, | ||
| 316 | c: u16, | ||
| 317 | }; | ||
| 318 | |||
| 319 | // TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512 | ||
| 320 | test "packed array 24bits" { | ||
| 321 | comptime { | ||
| 322 | try expect(@sizeOf([9]Foo32Bits) == 9 * 4); | ||
| 323 | try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2); | ||
| 324 | } | ||
| 325 | |||
| 326 | var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1); | ||
| 327 | bytes[bytes.len - 1] = 0xaa; | ||
| 328 | const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; | ||
| 329 | try expect(ptr.a == 0); | ||
| 330 | try expect(ptr.b[0].field == 0); | ||
| 331 | try expect(ptr.b[1].field == 0); | ||
| 332 | try expect(ptr.c == 0); | ||
| 333 | |||
| 334 | ptr.a = maxInt(u16); | ||
| 335 | try expect(ptr.a == maxInt(u16)); | ||
| 336 | try expect(ptr.b[0].field == 0); | ||
| 337 | try expect(ptr.b[1].field == 0); | ||
| 338 | try expect(ptr.c == 0); | ||
| 339 | |||
| 340 | ptr.b[0].field = maxInt(u24); | ||
| 341 | try expect(ptr.a == maxInt(u16)); | ||
| 342 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 343 | try expect(ptr.b[1].field == 0); | ||
| 344 | try expect(ptr.c == 0); | ||
| 345 | |||
| 346 | ptr.b[1].field = maxInt(u24); | ||
| 347 | try expect(ptr.a == maxInt(u16)); | ||
| 348 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 349 | try expect(ptr.b[1].field == maxInt(u24)); | ||
| 350 | try expect(ptr.c == 0); | ||
| 351 | |||
| 352 | ptr.c = maxInt(u16); | ||
| 353 | try expect(ptr.a == maxInt(u16)); | ||
| 354 | try expect(ptr.b[0].field == maxInt(u24)); | ||
| 355 | try expect(ptr.b[1].field == maxInt(u24)); | ||
| 356 | try expect(ptr.c == maxInt(u16)); | ||
| 357 | |||
| 358 | try expect(bytes[bytes.len - 1] == 0xaa); | ||
| 359 | } | ||
| 360 | |||
| 361 | const FooStructAligned = packed struct { | ||
| 362 | a: u8, | ||
| 363 | b: u8, | ||
| 364 | }; | ||
| 365 | |||
| 366 | const FooArrayOfAligned = packed struct { | ||
| 367 | a: [2]FooStructAligned, | ||
| 368 | }; | ||
| 369 | |||
| 370 | test "aligned array of packed struct" { | ||
| 371 | comptime { | ||
| 372 | try expect(@sizeOf(FooStructAligned) == 2); | ||
| 373 | try expect(@sizeOf(FooArrayOfAligned) == 2 * 2); | ||
| 374 | } | ||
| 375 | |||
| 376 | var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned); | ||
| 377 | const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0]; | ||
| 378 | |||
| 379 | try expect(ptr.a[0].a == 0xbb); | ||
| 380 | try expect(ptr.a[0].b == 0xbb); | ||
| 381 | try expect(ptr.a[1].a == 0xbb); | ||
| 382 | try expect(ptr.a[1].b == 0xbb); | ||
| 383 | } | ||
| 384 | |||
| 385 | test "runtime struct initialization of bitfield" { | ||
| 386 | const s1 = Nibbles{ | ||
| 387 | .x = x1, | ||
| 388 | .y = x1, | ||
| 389 | }; | ||
| 390 | const s2 = Nibbles{ | ||
| 391 | .x = @intCast(u4, x2), | ||
| 392 | .y = @intCast(u4, x2), | ||
| 393 | }; | ||
| 394 | |||
| 395 | try expect(s1.x == x1); | ||
| 396 | try expect(s1.y == x1); | ||
| 397 | try expect(s2.x == @intCast(u4, x2)); | ||
| 398 | try expect(s2.y == @intCast(u4, x2)); | ||
| 399 | } | ||
| 400 | |||
| 401 | var x1 = @as(u4, 1); | ||
| 402 | var x2 = @as(u8, 2); | ||
| 403 | |||
| 404 | const Nibbles = packed struct { | ||
| 405 | x: u4, | ||
| 406 | y: u4, | ||
| 407 | }; | ||
| 408 | |||
| 409 | const Bitfields = packed struct { | ||
| 410 | f1: u16, | ||
| 411 | f2: u16, | ||
| 412 | f3: u8, | ||
| 413 | f4: u8, | ||
| 414 | f5: u4, | ||
| 415 | f6: u4, | ||
| 416 | f7: u8, | ||
| 417 | }; | ||
| 418 | |||
| 419 | test "native bit field understands endianness" { | ||
| 420 | var all: u64 = if (builtin.endian != .Little) | ||
| 421 | 0x1111222233445677 | ||
| 422 | else | ||
| 423 | 0x7765443322221111; | ||
| 424 | var bytes: [8]u8 = undefined; | ||
| 425 | @memcpy(&bytes, @ptrCast([*]u8, &all), 8); | ||
| 426 | var bitfields = @ptrCast(*Bitfields, &bytes).*; | ||
| 427 | |||
| 428 | try expect(bitfields.f1 == 0x1111); | ||
| 429 | try expect(bitfields.f2 == 0x2222); | ||
| 430 | try expect(bitfields.f3 == 0x33); | ||
| 431 | try expect(bitfields.f4 == 0x44); | ||
| 432 | try expect(bitfields.f5 == 0x5); | ||
| 433 | try expect(bitfields.f6 == 0x6); | ||
| 434 | try expect(bitfields.f7 == 0x77); | ||
| 435 | } | ||
| 436 | |||
| 437 | test "align 1 field before self referential align 8 field as slice return type" { | ||
| 438 | const result = alloc(Expr); | ||
| 439 | try expect(result.len == 0); | ||
| 440 | } | ||
| 441 | |||
| 442 | const Expr = union(enum) { | ||
| 443 | Literal: u8, | ||
| 444 | Question: *Expr, | ||
| 445 | }; | ||
| 446 | |||
| 447 | fn alloc(comptime T: type) []T { | ||
| 448 | return &[_]T{}; | ||
| 449 | } | ||
| 450 | |||
| 451 | test "call method with mutable reference to struct with no fields" { | ||
| 452 | const S = struct { | ||
| 453 | fn doC(s: *const @This()) bool { | ||
| 454 | return true; | ||
| 455 | } | ||
| 456 | fn do(s: *@This()) bool { | ||
| 457 | return true; | ||
| 458 | } | ||
| 459 | }; | ||
| 460 | |||
| 461 | var s = S{}; | ||
| 462 | try expect(S.doC(&s)); | ||
| 463 | try expect(s.doC()); | ||
| 464 | try expect(S.do(&s)); | ||
| 465 | try expect(s.do()); | ||
| 466 | } | ||
| 467 | |||
| 468 | test "implicit cast packed struct field to const ptr" { | ||
| 469 | const LevelUpMove = packed struct { | ||
| 470 | move_id: u9, | ||
| 471 | level: u7, | ||
| 472 | |||
| 473 | fn toInt(value: u7) u7 { | ||
| 474 | return value; | ||
| 475 | } | ||
| 476 | }; | ||
| 477 | |||
| 478 | var lup: LevelUpMove = undefined; | ||
| 479 | lup.level = 12; | ||
| 480 | const res = LevelUpMove.toInt(lup.level); | ||
| 481 | try expect(res == 12); | ||
| 482 | } | ||
| 483 | |||
| 484 | test "pointer to packed struct member in a stack variable" { | ||
| 485 | const S = packed struct { | ||
| 486 | a: u2, | ||
| 487 | b: u2, | ||
| 488 | }; | ||
| 489 | |||
| 490 | var s = S{ .a = 2, .b = 0 }; | ||
| 491 | var b_ptr = &s.b; | ||
| 492 | try expect(s.b == 0); | ||
| 493 | b_ptr.* = 2; | ||
| 494 | try expect(s.b == 2); | ||
| 495 | } | ||
| 496 | |||
| 497 | test "non-byte-aligned array inside packed struct" { | ||
| 498 | const Foo = packed struct { | ||
| 499 | a: bool, | ||
| 500 | b: [0x16]u8, | ||
| 501 | }; | ||
| 502 | const S = struct { | ||
| 503 | fn bar(slice: []const u8) !void { | ||
| 504 | try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu"); | ||
| 505 | } | ||
| 506 | fn doTheTest() !void { | ||
| 507 | var foo = Foo{ | ||
| 508 | .a = true, | ||
| 509 | .b = "abcdefghijklmnopqurstu".*, | ||
| 510 | }; | ||
| 511 | const value = foo.b; | ||
| 512 | try bar(&value); | ||
| 513 | } | ||
| 514 | }; | ||
| 515 | try S.doTheTest(); | ||
| 516 | comptime try S.doTheTest(); | ||
| 517 | } | ||
| 518 | |||
| 519 | test "packed struct with u0 field access" { | ||
| 520 | const S = packed struct { | ||
| 521 | f0: u0, | ||
| 522 | }; | ||
| 523 | var s = S{ .f0 = 0 }; | ||
| 524 | comptime try expect(s.f0 == 0); | ||
| 525 | } | ||
| 526 | |||
| 527 | const S0 = struct { | ||
| 528 | bar: S1, | ||
| 529 | |||
| 530 | pub const S1 = struct { | ||
| 531 | value: u8, | ||
| 532 | }; | ||
| 533 | |||
| 534 | fn init() @This() { | ||
| 535 | return S0{ .bar = S1{ .value = 123 } }; | ||
| 536 | } | ||
| 537 | }; | ||
| 538 | |||
| 539 | var g_foo: S0 = S0.init(); | ||
| 540 | |||
| 541 | test "access to global struct fields" { | ||
| 542 | g_foo.bar.value = 42; | ||
| 543 | try expect(g_foo.bar.value == 42); | ||
| 544 | } | ||
| 545 | |||
| 546 | test "packed struct with fp fields" { | ||
| 547 | const S = packed struct { | ||
| 548 | data: [3]f32, | ||
| 549 | |||
| 550 | pub fn frob(self: *@This()) void { | ||
| 551 | self.data[0] += self.data[1] + self.data[2]; | ||
| 552 | self.data[1] += self.data[0] + self.data[2]; | ||
| 553 | self.data[2] += self.data[0] + self.data[1]; | ||
| 554 | } | ||
| 555 | }; | ||
| 556 | |||
| 557 | var s: S = undefined; | ||
| 558 | s.data[0] = 1.0; | ||
| 559 | s.data[1] = 2.0; | ||
| 560 | s.data[2] = 3.0; | ||
| 561 | s.frob(); | ||
| 562 | try expectEqual(@as(f32, 6.0), s.data[0]); | ||
| 563 | try expectEqual(@as(f32, 11.0), s.data[1]); | ||
| 564 | try expectEqual(@as(f32, 20.0), s.data[2]); | ||
| 565 | } | ||
| 566 | |||
| 567 | test "use within struct scope" { | ||
| 568 | const S = struct { | ||
| 569 | usingnamespace struct { | ||
| 570 | pub fn inner() i32 { | ||
| 571 | return 42; | ||
| 572 | } | ||
| 573 | }; | ||
| 574 | }; | ||
| 575 | try expectEqual(@as(i32, 42), S.inner()); | ||
| 576 | } | ||
| 577 | |||
| 578 | test "default struct initialization fields" { | ||
| 579 | const S = struct { | ||
| 580 | a: i32 = 1234, | ||
| 581 | b: i32, | ||
| 582 | }; | ||
| 583 | const x = S{ | ||
| 584 | .b = 5, | ||
| 585 | }; | ||
| 586 | if (x.a + x.b != 1239) { | ||
| 587 | @compileError("it should be comptime known"); | ||
| 588 | } | ||
| 589 | var five: i32 = 5; | ||
| 590 | const y = S{ | ||
| 591 | .b = five, | ||
| 592 | }; | ||
| 593 | try expectEqual(1239, x.a + x.b); | ||
| 594 | } | ||
| 595 | |||
| 596 | test "fn with C calling convention returns struct by value" { | ||
| 597 | const S = struct { | ||
| 598 | fn entry() !void { | ||
| 599 | var x = makeBar(10); | ||
| 600 | try expectEqual(@as(i32, 10), x.handle); | ||
| 601 | } | ||
| 602 | |||
| 603 | const ExternBar = extern struct { | ||
| 604 | handle: i32, | ||
| 605 | }; | ||
| 606 | |||
| 607 | fn makeBar(t: i32) callconv(.C) ExternBar { | ||
| 608 | return ExternBar{ | ||
| 609 | .handle = t, | ||
| 610 | }; | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | try S.entry(); | ||
| 614 | comptime try S.entry(); | ||
| 615 | } | ||
| 616 | |||
| 617 | test "for loop over pointers to struct, getting field from struct pointer" { | ||
| 618 | const S = struct { | ||
| 619 | const Foo = struct { | ||
| 620 | name: []const u8, | ||
| 621 | }; | ||
| 622 | |||
| 623 | var ok = true; | ||
| 624 | |||
| 625 | fn eql(a: []const u8) bool { | ||
| 626 | return true; | ||
| 627 | } | ||
| 628 | |||
| 629 | const ArrayList = struct { | ||
| 630 | fn toSlice(self: *ArrayList) []*Foo { | ||
| 631 | return @as([*]*Foo, undefined)[0..0]; | ||
| 632 | } | ||
| 633 | }; | ||
| 634 | |||
| 635 | fn doTheTest() !void { | ||
| 636 | var objects: ArrayList = undefined; | ||
| 637 | |||
| 638 | for (objects.toSlice()) |obj| { | ||
| 639 | if (eql(obj.name)) { | ||
| 640 | ok = false; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | try expect(ok); | ||
| 645 | } | ||
| 646 | }; | ||
| 647 | try S.doTheTest(); | ||
| 648 | } | ||
| 649 | |||
| 650 | test "zero-bit field in packed struct" { | ||
| 651 | const S = packed struct { | ||
| 652 | x: u10, | ||
| 653 | y: void, | ||
| 654 | }; | ||
| 655 | var x: S = undefined; | ||
| 656 | } | ||
| 657 | |||
| 658 | test "struct field init with catch" { | ||
| 659 | const S = struct { | ||
| 660 | fn doTheTest() !void { | ||
| 661 | var x: anyerror!isize = 1; | ||
| 662 | var req = Foo{ | ||
| 663 | .field = x catch undefined, | ||
| 664 | }; | ||
| 665 | try expect(req.field == 1); | ||
| 666 | } | ||
| 667 | |||
| 668 | pub const Foo = extern struct { | ||
| 669 | field: isize, | ||
| 670 | }; | ||
| 671 | }; | ||
| 672 | try S.doTheTest(); | ||
| 673 | comptime try S.doTheTest(); | ||
| 674 | } | ||
| 675 | |||
| 676 | test "packed struct with non-ABI-aligned field" { | ||
| 677 | const S = packed struct { | ||
| 678 | x: u9, | ||
| 679 | y: u183, | ||
| 680 | }; | ||
| 681 | var s: S = undefined; | ||
| 682 | s.x = 1; | ||
| 683 | s.y = 42; | ||
| 684 | try expect(s.x == 1); | ||
| 685 | try expect(s.y == 42); | ||
| 686 | } | ||
| 687 | |||
| 688 | test "non-packed struct with u128 entry in union" { | ||
| 689 | const U = union(enum) { | ||
| 690 | Num: u128, | ||
| 691 | Void, | ||
| 692 | }; | ||
| 693 | |||
| 694 | const S = struct { | ||
| 695 | f1: U, | ||
| 696 | f2: U, | ||
| 697 | }; | ||
| 698 | |||
| 699 | var sx: S = undefined; | ||
| 700 | var s = &sx; | ||
| 701 | try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @byteOffsetOf(S, "f2")); | ||
| 702 | var v2 = U{ .Num = 123 }; | ||
| 703 | s.f2 = v2; | ||
| 704 | try std.testing.expect(s.f2.Num == 123); | ||
| 705 | } | ||
| 706 | |||
| 707 | test "packed struct field passed to generic function" { | ||
| 708 | const S = struct { | ||
| 709 | const P = packed struct { | ||
| 710 | b: u5, | ||
| 711 | g: u5, | ||
| 712 | r: u5, | ||
| 713 | a: u1, | ||
| 714 | }; | ||
| 715 | |||
| 716 | fn genericReadPackedField(ptr: anytype) u5 { | ||
| 717 | return ptr.*; | ||
| 718 | } | ||
| 719 | }; | ||
| 720 | |||
| 721 | var p: S.P = undefined; | ||
| 722 | p.b = 29; | ||
| 723 | var loaded = S.genericReadPackedField(&p.b); | ||
| 724 | try expect(loaded == 29); | ||
| 725 | } | ||
| 726 | |||
| 727 | test "anonymous struct literal syntax" { | ||
| 728 | const S = struct { | ||
| 729 | const Point = struct { | ||
| 730 | x: i32, | ||
| 731 | y: i32, | ||
| 732 | }; | ||
| 733 | |||
| 734 | fn doTheTest() !void { | ||
| 735 | var p: Point = .{ | ||
| 736 | .x = 1, | ||
| 737 | .y = 2, | ||
| 738 | }; | ||
| 739 | try expect(p.x == 1); | ||
| 740 | try expect(p.y == 2); | ||
| 741 | } | ||
| 742 | }; | ||
| 743 | try S.doTheTest(); | ||
| 744 | comptime try S.doTheTest(); | ||
| 745 | } | ||
| 746 | |||
| 747 | test "fully anonymous struct" { | ||
| 748 | const S = struct { | ||
| 749 | fn doTheTest() !void { | ||
| 750 | try dump(.{ | ||
| 751 | .int = @as(u32, 1234), | ||
| 752 | .float = @as(f64, 12.34), | ||
| 753 | .b = true, | ||
| 754 | .s = "hi", | ||
| 755 | }); | ||
| 756 | } | ||
| 757 | fn dump(args: anytype) !void { | ||
| 758 | try expect(args.int == 1234); | ||
| 759 | try expect(args.float == 12.34); | ||
| 760 | try expect(args.b); | ||
| 761 | try expect(args.s[0] == 'h'); | ||
| 762 | try expect(args.s[1] == 'i'); | ||
| 763 | } | ||
| 764 | }; | ||
| 765 | try S.doTheTest(); | ||
| 766 | comptime try S.doTheTest(); | ||
| 767 | } | ||
| 768 | |||
| 769 | test "fully anonymous list literal" { | ||
| 770 | const S = struct { | ||
| 771 | fn doTheTest() !void { | ||
| 772 | try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); | ||
| 773 | } | ||
| 774 | fn dump(args: anytype) !void { | ||
| 775 | try expect(args.@"0" == 1234); | ||
| 776 | try expect(args.@"1" == 12.34); | ||
| 777 | try expect(args.@"2"); | ||
| 778 | try expect(args.@"3"[0] == 'h'); | ||
| 779 | try expect(args.@"3"[1] == 'i'); | ||
| 780 | } | ||
| 781 | }; | ||
| 782 | try S.doTheTest(); | ||
| 783 | comptime try S.doTheTest(); | ||
| 784 | } | ||
| 785 | |||
| 786 | test "anonymous struct literal assigned to variable" { | ||
| 787 | var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; | ||
| 788 | try expect(vec.@"0" == 22); | ||
| 789 | try expect(vec.@"1" == 55); | ||
| 790 | try expect(vec.@"2" == 99); | ||
| 791 | } | ||
| 792 | |||
| 793 | test "struct with var field" { | ||
| 794 | const Point = struct { | ||
| 795 | x: anytype, | ||
| 796 | y: anytype, | ||
| 797 | }; | ||
| 798 | const pt = Point{ | ||
| 799 | .x = 1, | ||
| 800 | .y = 2, | ||
| 801 | }; | ||
| 802 | try expect(pt.x == 1); | ||
| 803 | try expect(pt.y == 2); | ||
| 804 | } | ||
| 805 | |||
| 806 | test "comptime struct field" { | ||
| 807 | const T = struct { | ||
| 808 | a: i32, | ||
| 809 | comptime b: i32 = 1234, | ||
| 810 | }; | ||
| 811 | |||
| 812 | var foo: T = undefined; | ||
| 813 | comptime try expect(foo.b == 1234); | ||
| 814 | } | ||
| 815 | |||
| 816 | test "anon struct literal field value initialized with fn call" { | ||
| 817 | const S = struct { | ||
| 818 | fn doTheTest() !void { | ||
| 819 | var x = .{foo()}; | ||
| 820 | try expectEqualSlices(u8, x[0], "hi"); | ||
| 821 | } | ||
| 822 | fn foo() []const u8 { | ||
| 823 | return "hi"; | ||
| 824 | } | ||
| 825 | }; | ||
| 826 | try S.doTheTest(); | ||
| 827 | comptime try S.doTheTest(); | ||
| 828 | } | ||
| 829 | |||
| 830 | test "self-referencing struct via array member" { | ||
| 831 | const T = struct { | ||
| 832 | children: [1]*@This(), | ||
| 833 | }; | ||
| 834 | var x: T = undefined; | ||
| 835 | x = T{ .children = .{&x} }; | ||
| 836 | try expect(x.children[0] == &x); | ||
| 837 | } | ||
| 838 | |||
| 839 | test "struct with union field" { | ||
| 840 | const Value = struct { | ||
| 841 | ref: u32 = 2, | ||
| 842 | kind: union(enum) { | ||
| 843 | None: usize, | ||
| 844 | Bool: bool, | ||
| 845 | }, | ||
| 846 | }; | ||
| 847 | |||
| 848 | var True = Value{ | ||
| 849 | .kind = .{ .Bool = true }, | ||
| 850 | }; | ||
| 851 | try expectEqual(@as(u32, 2), True.ref); | ||
| 852 | try expectEqual(true, True.kind.Bool); | ||
| 853 | } | ||
| 854 | |||
| 855 | test "type coercion of anon struct literal to struct" { | ||
| 856 | const S = struct { | ||
| 857 | const S2 = struct { | ||
| 858 | A: u32, | ||
| 859 | B: []const u8, | ||
| 860 | C: void, | ||
| 861 | D: Foo = .{}, | ||
| 862 | }; | ||
| 863 | |||
| 864 | const Foo = struct { | ||
| 865 | field: i32 = 1234, | ||
| 866 | }; | ||
| 867 | |||
| 868 | fn doTheTest() !void { | ||
| 869 | var y: u32 = 42; | ||
| 870 | const t0 = .{ .A = 123, .B = "foo", .C = {} }; | ||
| 871 | const t1 = .{ .A = y, .B = "foo", .C = {} }; | ||
| 872 | const y0: S2 = t0; | ||
| 873 | var y1: S2 = t1; | ||
| 874 | try expect(y0.A == 123); | ||
| 875 | try expect(std.mem.eql(u8, y0.B, "foo")); | ||
| 876 | try expect(y0.C == {}); | ||
| 877 | try expect(y0.D.field == 1234); | ||
| 878 | try expect(y1.A == y); | ||
| 879 | try expect(std.mem.eql(u8, y1.B, "foo")); | ||
| 880 | try expect(y1.C == {}); | ||
| 881 | try expect(y1.D.field == 1234); | ||
| 882 | } | ||
| 883 | }; | ||
| 884 | try S.doTheTest(); | ||
| 885 | comptime try S.doTheTest(); | ||
| 886 | } | ||
| 887 | |||
| 888 | test "type coercion of pointer to anon struct literal to pointer to struct" { | ||
| 889 | const S = struct { | ||
| 890 | const S2 = struct { | ||
| 891 | A: u32, | ||
| 892 | B: []const u8, | ||
| 893 | C: void, | ||
| 894 | D: Foo = .{}, | ||
| 895 | }; | ||
| 896 | |||
| 897 | const Foo = struct { | ||
| 898 | field: i32 = 1234, | ||
| 899 | }; | ||
| 900 | |||
| 901 | fn doTheTest() !void { | ||
| 902 | var y: u32 = 42; | ||
| 903 | const t0 = &.{ .A = 123, .B = "foo", .C = {} }; | ||
| 904 | const t1 = &.{ .A = y, .B = "foo", .C = {} }; | ||
| 905 | const y0: *const S2 = t0; | ||
| 906 | var y1: *const S2 = t1; | ||
| 907 | try expect(y0.A == 123); | ||
| 908 | try expect(std.mem.eql(u8, y0.B, "foo")); | ||
| 909 | try expect(y0.C == {}); | ||
| 910 | try expect(y0.D.field == 1234); | ||
| 911 | try expect(y1.A == y); | ||
| 912 | try expect(std.mem.eql(u8, y1.B, "foo")); | ||
| 913 | try expect(y1.C == {}); | ||
| 914 | try expect(y1.D.field == 1234); | ||
| 915 | } | ||
| 916 | }; | ||
| 917 | try S.doTheTest(); | ||
| 918 | comptime try S.doTheTest(); | ||
| 919 | } | ||
| 920 | |||
| 921 | test "packed struct with undefined initializers" { | ||
| 922 | const S = struct { | ||
| 923 | const P = packed struct { | ||
| 924 | a: u3, | ||
| 925 | _a: u3 = undefined, | ||
| 926 | b: u3, | ||
| 927 | _b: u3 = undefined, | ||
| 928 | c: u3, | ||
| 929 | _c: u3 = undefined, | ||
| 930 | }; | ||
| 931 | |||
| 932 | fn doTheTest() !void { | ||
| 933 | var p: P = undefined; | ||
| 934 | p = P{ .a = 2, .b = 4, .c = 6 }; | ||
| 935 | // Make sure the compiler doesn't touch the unprefixed fields. | ||
| 936 | // Use expect since i386-linux doesn't like expectEqual | ||
| 937 | try expect(p.a == 2); | ||
| 938 | try expect(p.b == 4); | ||
| 939 | try expect(p.c == 6); | ||
| 940 | } | ||
| 941 | }; | ||
| 942 | |||
| 943 | try S.doTheTest(); | ||
| 944 | comptime try S.doTheTest(); | ||
| 945 | } | ||
test/stage1/behavior/struct_contains_null_ptr_itself.zig deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "struct contains null pointer which contains original struct" { | ||
| 5 | var x: ?*NodeLineComment = null; | ||
| 6 | try expect(x == null); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub const Node = struct { | ||
| 10 | id: Id, | ||
| 11 | comment: ?*NodeLineComment, | ||
| 12 | |||
| 13 | pub const Id = enum { | ||
| 14 | Root, | ||
| 15 | LineComment, | ||
| 16 | }; | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub const NodeLineComment = struct { | ||
| 20 | base: Node, | ||
| 21 | }; | ||
test/stage1/behavior/struct_contains_slice_of_itself.zig deleted-85| ... | @@ -1,85 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Node = struct { | ||
| 4 | payload: i32, | ||
| 5 | children: []Node, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const NodeAligned = struct { | ||
| 9 | payload: i32, | ||
| 10 | children: []align(@alignOf(NodeAligned)) NodeAligned, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "struct contains slice of itself" { | ||
| 14 | var other_nodes = [_]Node{ | ||
| 15 | Node{ | ||
| 16 | .payload = 31, | ||
| 17 | .children = &[_]Node{}, | ||
| 18 | }, | ||
| 19 | Node{ | ||
| 20 | .payload = 32, | ||
| 21 | .children = &[_]Node{}, | ||
| 22 | }, | ||
| 23 | }; | ||
| 24 | var nodes = [_]Node{ | ||
| 25 | Node{ | ||
| 26 | .payload = 1, | ||
| 27 | .children = &[_]Node{}, | ||
| 28 | }, | ||
| 29 | Node{ | ||
| 30 | .payload = 2, | ||
| 31 | .children = &[_]Node{}, | ||
| 32 | }, | ||
| 33 | Node{ | ||
| 34 | .payload = 3, | ||
| 35 | .children = other_nodes[0..], | ||
| 36 | }, | ||
| 37 | }; | ||
| 38 | const root = Node{ | ||
| 39 | .payload = 1234, | ||
| 40 | .children = nodes[0..], | ||
| 41 | }; | ||
| 42 | try expect(root.payload == 1234); | ||
| 43 | try expect(root.children[0].payload == 1); | ||
| 44 | try expect(root.children[1].payload == 2); | ||
| 45 | try expect(root.children[2].payload == 3); | ||
| 46 | try expect(root.children[2].children[0].payload == 31); | ||
| 47 | try expect(root.children[2].children[1].payload == 32); | ||
| 48 | } | ||
| 49 | |||
| 50 | test "struct contains aligned slice of itself" { | ||
| 51 | var other_nodes = [_]NodeAligned{ | ||
| 52 | NodeAligned{ | ||
| 53 | .payload = 31, | ||
| 54 | .children = &[_]NodeAligned{}, | ||
| 55 | }, | ||
| 56 | NodeAligned{ | ||
| 57 | .payload = 32, | ||
| 58 | .children = &[_]NodeAligned{}, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | var nodes = [_]NodeAligned{ | ||
| 62 | NodeAligned{ | ||
| 63 | .payload = 1, | ||
| 64 | .children = &[_]NodeAligned{}, | ||
| 65 | }, | ||
| 66 | NodeAligned{ | ||
| 67 | .payload = 2, | ||
| 68 | .children = &[_]NodeAligned{}, | ||
| 69 | }, | ||
| 70 | NodeAligned{ | ||
| 71 | .payload = 3, | ||
| 72 | .children = other_nodes[0..], | ||
| 73 | }, | ||
| 74 | }; | ||
| 75 | const root = NodeAligned{ | ||
| 76 | .payload = 1234, | ||
| 77 | .children = nodes[0..], | ||
| 78 | }; | ||
| 79 | try expect(root.payload == 1234); | ||
| 80 | try expect(root.children[0].payload == 1); | ||
| 81 | try expect(root.children[1].payload == 2); | ||
| 82 | try expect(root.children[2].payload == 3); | ||
| 83 | try expect(root.children[2].children[0].payload == 31); | ||
| 84 | try expect(root.children[2].children[1].payload == 32); | ||
| 85 | } | ||
test/stage1/behavior/switch.zig deleted-537| ... | @@ -1,537 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectError = std.testing.expectError; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | |||
| 6 | test "switch with numbers" { | ||
| 7 | try testSwitchWithNumbers(13); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testSwitchWithNumbers(x: u32) !void { | ||
| 11 | const result = switch (x) { | ||
| 12 | 1, 2, 3, 4...8 => false, | ||
| 13 | 13 => true, | ||
| 14 | else => false, | ||
| 15 | }; | ||
| 16 | try expect(result); | ||
| 17 | } | ||
| 18 | |||
| 19 | test "switch with all ranges" { | ||
| 20 | try expect(testSwitchWithAllRanges(50, 3) == 1); | ||
| 21 | try expect(testSwitchWithAllRanges(101, 0) == 2); | ||
| 22 | try expect(testSwitchWithAllRanges(300, 5) == 3); | ||
| 23 | try expect(testSwitchWithAllRanges(301, 6) == 6); | ||
| 24 | } | ||
| 25 | |||
| 26 | fn testSwitchWithAllRanges(x: u32, y: u32) u32 { | ||
| 27 | return switch (x) { | ||
| 28 | 0...100 => 1, | ||
| 29 | 101...200 => 2, | ||
| 30 | 201...300 => 3, | ||
| 31 | else => y, | ||
| 32 | }; | ||
| 33 | } | ||
| 34 | |||
| 35 | test "implicit comptime switch" { | ||
| 36 | const x = 3 + 4; | ||
| 37 | const result = switch (x) { | ||
| 38 | 3 => 10, | ||
| 39 | 4 => 11, | ||
| 40 | 5, 6 => 12, | ||
| 41 | 7, 8 => 13, | ||
| 42 | else => 14, | ||
| 43 | }; | ||
| 44 | |||
| 45 | comptime { | ||
| 46 | try expect(result + 1 == 14); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | test "switch on enum" { | ||
| 51 | const fruit = Fruit.Orange; | ||
| 52 | nonConstSwitchOnEnum(fruit); | ||
| 53 | } | ||
| 54 | const Fruit = enum { | ||
| 55 | Apple, | ||
| 56 | Orange, | ||
| 57 | Banana, | ||
| 58 | }; | ||
| 59 | fn nonConstSwitchOnEnum(fruit: Fruit) void { | ||
| 60 | switch (fruit) { | ||
| 61 | Fruit.Apple => unreachable, | ||
| 62 | Fruit.Orange => {}, | ||
| 63 | Fruit.Banana => unreachable, | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | test "switch statement" { | ||
| 68 | try nonConstSwitch(SwitchStatmentFoo.C); | ||
| 69 | } | ||
| 70 | fn nonConstSwitch(foo: SwitchStatmentFoo) !void { | ||
| 71 | const val = switch (foo) { | ||
| 72 | SwitchStatmentFoo.A => @as(i32, 1), | ||
| 73 | SwitchStatmentFoo.B => 2, | ||
| 74 | SwitchStatmentFoo.C => 3, | ||
| 75 | SwitchStatmentFoo.D => 4, | ||
| 76 | }; | ||
| 77 | try expect(val == 3); | ||
| 78 | } | ||
| 79 | const SwitchStatmentFoo = enum { | ||
| 80 | A, | ||
| 81 | B, | ||
| 82 | C, | ||
| 83 | D, | ||
| 84 | }; | ||
| 85 | |||
| 86 | test "switch prong with variable" { | ||
| 87 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | ||
| 88 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | ||
| 89 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); | ||
| 90 | } | ||
| 91 | const SwitchProngWithVarEnum = union(enum) { | ||
| 92 | One: i32, | ||
| 93 | Two: f32, | ||
| 94 | Meh: void, | ||
| 95 | }; | ||
| 96 | fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { | ||
| 97 | switch (a) { | ||
| 98 | SwitchProngWithVarEnum.One => |x| { | ||
| 99 | try expect(x == 13); | ||
| 100 | }, | ||
| 101 | SwitchProngWithVarEnum.Two => |x| { | ||
| 102 | try expect(x == 13.0); | ||
| 103 | }, | ||
| 104 | SwitchProngWithVarEnum.Meh => |x| { | ||
| 105 | const v: void = x; | ||
| 106 | }, | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | test "switch on enum using pointer capture" { | ||
| 111 | try testSwitchEnumPtrCapture(); | ||
| 112 | comptime try testSwitchEnumPtrCapture(); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn testSwitchEnumPtrCapture() !void { | ||
| 116 | var value = SwitchProngWithVarEnum{ .One = 1234 }; | ||
| 117 | switch (value) { | ||
| 118 | SwitchProngWithVarEnum.One => |*x| x.* += 1, | ||
| 119 | else => unreachable, | ||
| 120 | } | ||
| 121 | switch (value) { | ||
| 122 | SwitchProngWithVarEnum.One => |x| try expect(x == 1235), | ||
| 123 | else => unreachable, | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | test "switch with multiple expressions" { | ||
| 128 | const x = switch (returnsFive()) { | ||
| 129 | 1, 2, 3 => 1, | ||
| 130 | 4, 5, 6 => 2, | ||
| 131 | else => @as(i32, 3), | ||
| 132 | }; | ||
| 133 | try expect(x == 2); | ||
| 134 | } | ||
| 135 | fn returnsFive() i32 { | ||
| 136 | return 5; | ||
| 137 | } | ||
| 138 | |||
| 139 | const Number = union(enum) { | ||
| 140 | One: u64, | ||
| 141 | Two: u8, | ||
| 142 | Three: f32, | ||
| 143 | }; | ||
| 144 | |||
| 145 | const number = Number{ .Three = 1.23 }; | ||
| 146 | |||
| 147 | fn returnsFalse() bool { | ||
| 148 | switch (number) { | ||
| 149 | Number.One => |x| return x > 1234, | ||
| 150 | Number.Two => |x| return x == 'a', | ||
| 151 | Number.Three => |x| return x > 12.34, | ||
| 152 | } | ||
| 153 | } | ||
| 154 | test "switch on const enum with var" { | ||
| 155 | try expect(!returnsFalse()); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "switch on type" { | ||
| 159 | try expect(trueIfBoolFalseOtherwise(bool)); | ||
| 160 | try expect(!trueIfBoolFalseOtherwise(i32)); | ||
| 161 | } | ||
| 162 | |||
| 163 | fn trueIfBoolFalseOtherwise(comptime T: type) bool { | ||
| 164 | return switch (T) { | ||
| 165 | bool => true, | ||
| 166 | else => false, | ||
| 167 | }; | ||
| 168 | } | ||
| 169 | |||
| 170 | test "switch handles all cases of number" { | ||
| 171 | try testSwitchHandleAllCases(); | ||
| 172 | comptime try testSwitchHandleAllCases(); | ||
| 173 | } | ||
| 174 | |||
| 175 | fn testSwitchHandleAllCases() !void { | ||
| 176 | try expect(testSwitchHandleAllCasesExhaustive(0) == 3); | ||
| 177 | try expect(testSwitchHandleAllCasesExhaustive(1) == 2); | ||
| 178 | try expect(testSwitchHandleAllCasesExhaustive(2) == 1); | ||
| 179 | try expect(testSwitchHandleAllCasesExhaustive(3) == 0); | ||
| 180 | |||
| 181 | try expect(testSwitchHandleAllCasesRange(100) == 0); | ||
| 182 | try expect(testSwitchHandleAllCasesRange(200) == 1); | ||
| 183 | try expect(testSwitchHandleAllCasesRange(201) == 2); | ||
| 184 | try expect(testSwitchHandleAllCasesRange(202) == 4); | ||
| 185 | try expect(testSwitchHandleAllCasesRange(230) == 3); | ||
| 186 | } | ||
| 187 | |||
| 188 | fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { | ||
| 189 | return switch (x) { | ||
| 190 | 0 => @as(u2, 3), | ||
| 191 | 1 => 2, | ||
| 192 | 2 => 1, | ||
| 193 | 3 => 0, | ||
| 194 | }; | ||
| 195 | } | ||
| 196 | |||
| 197 | fn testSwitchHandleAllCasesRange(x: u8) u8 { | ||
| 198 | return switch (x) { | ||
| 199 | 0...100 => @as(u8, 0), | ||
| 200 | 101...200 => 1, | ||
| 201 | 201, 203 => 2, | ||
| 202 | 202 => 4, | ||
| 203 | 204...255 => 3, | ||
| 204 | }; | ||
| 205 | } | ||
| 206 | |||
| 207 | test "switch all prongs unreachable" { | ||
| 208 | try testAllProngsUnreachable(); | ||
| 209 | comptime try testAllProngsUnreachable(); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn testAllProngsUnreachable() !void { | ||
| 213 | try expect(switchWithUnreachable(1) == 2); | ||
| 214 | try expect(switchWithUnreachable(2) == 10); | ||
| 215 | } | ||
| 216 | |||
| 217 | fn switchWithUnreachable(x: i32) i32 { | ||
| 218 | while (true) { | ||
| 219 | switch (x) { | ||
| 220 | 1 => return 2, | ||
| 221 | 2 => break, | ||
| 222 | else => continue, | ||
| 223 | } | ||
| 224 | } | ||
| 225 | return 10; | ||
| 226 | } | ||
| 227 | |||
| 228 | fn return_a_number() anyerror!i32 { | ||
| 229 | return 1; | ||
| 230 | } | ||
| 231 | |||
| 232 | test "capture value of switch with all unreachable prongs" { | ||
| 233 | const x = return_a_number() catch |err| switch (err) { | ||
| 234 | else => unreachable, | ||
| 235 | }; | ||
| 236 | try expect(x == 1); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "switching on booleans" { | ||
| 240 | try testSwitchOnBools(); | ||
| 241 | comptime try testSwitchOnBools(); | ||
| 242 | } | ||
| 243 | |||
| 244 | fn testSwitchOnBools() !void { | ||
| 245 | try expect(testSwitchOnBoolsTrueAndFalse(true) == false); | ||
| 246 | try expect(testSwitchOnBoolsTrueAndFalse(false) == true); | ||
| 247 | |||
| 248 | try expect(testSwitchOnBoolsTrueWithElse(true) == false); | ||
| 249 | try expect(testSwitchOnBoolsTrueWithElse(false) == true); | ||
| 250 | |||
| 251 | try expect(testSwitchOnBoolsFalseWithElse(true) == false); | ||
| 252 | try expect(testSwitchOnBoolsFalseWithElse(false) == true); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { | ||
| 256 | return switch (x) { | ||
| 257 | true => false, | ||
| 258 | false => true, | ||
| 259 | }; | ||
| 260 | } | ||
| 261 | |||
| 262 | fn testSwitchOnBoolsTrueWithElse(x: bool) bool { | ||
| 263 | return switch (x) { | ||
| 264 | true => false, | ||
| 265 | else => true, | ||
| 266 | }; | ||
| 267 | } | ||
| 268 | |||
| 269 | fn testSwitchOnBoolsFalseWithElse(x: bool) bool { | ||
| 270 | return switch (x) { | ||
| 271 | false => true, | ||
| 272 | else => false, | ||
| 273 | }; | ||
| 274 | } | ||
| 275 | |||
| 276 | test "u0" { | ||
| 277 | var val: u0 = 0; | ||
| 278 | switch (val) { | ||
| 279 | 0 => try expect(val == 0), | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | test "undefined.u0" { | ||
| 284 | var val: u0 = undefined; | ||
| 285 | switch (val) { | ||
| 286 | 0 => try expect(val == 0), | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | test "anon enum literal used in switch on union enum" { | ||
| 291 | const Foo = union(enum) { | ||
| 292 | a: i32, | ||
| 293 | }; | ||
| 294 | |||
| 295 | var foo = Foo{ .a = 1234 }; | ||
| 296 | switch (foo) { | ||
| 297 | .a => |x| { | ||
| 298 | try expect(x == 1234); | ||
| 299 | }, | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | test "else prong of switch on error set excludes other cases" { | ||
| 304 | const S = struct { | ||
| 305 | fn doTheTest() !void { | ||
| 306 | try expectError(error.C, bar()); | ||
| 307 | } | ||
| 308 | const E = error{ | ||
| 309 | A, | ||
| 310 | B, | ||
| 311 | } || E2; | ||
| 312 | |||
| 313 | const E2 = error{ | ||
| 314 | C, | ||
| 315 | D, | ||
| 316 | }; | ||
| 317 | |||
| 318 | fn foo() E!void { | ||
| 319 | return error.C; | ||
| 320 | } | ||
| 321 | |||
| 322 | fn bar() E2!void { | ||
| 323 | foo() catch |err| switch (err) { | ||
| 324 | error.A, error.B => {}, | ||
| 325 | else => |e| return e, | ||
| 326 | }; | ||
| 327 | } | ||
| 328 | }; | ||
| 329 | try S.doTheTest(); | ||
| 330 | comptime try S.doTheTest(); | ||
| 331 | } | ||
| 332 | |||
| 333 | test "switch prongs with error set cases make a new error set type for capture value" { | ||
| 334 | const S = struct { | ||
| 335 | fn doTheTest() !void { | ||
| 336 | try expectError(error.B, bar()); | ||
| 337 | } | ||
| 338 | const E = E1 || E2; | ||
| 339 | |||
| 340 | const E1 = error{ | ||
| 341 | A, | ||
| 342 | B, | ||
| 343 | }; | ||
| 344 | |||
| 345 | const E2 = error{ | ||
| 346 | C, | ||
| 347 | D, | ||
| 348 | }; | ||
| 349 | |||
| 350 | fn foo() E!void { | ||
| 351 | return error.B; | ||
| 352 | } | ||
| 353 | |||
| 354 | fn bar() E1!void { | ||
| 355 | foo() catch |err| switch (err) { | ||
| 356 | error.A, error.B => |e| return e, | ||
| 357 | else => {}, | ||
| 358 | }; | ||
| 359 | } | ||
| 360 | }; | ||
| 361 | try S.doTheTest(); | ||
| 362 | comptime try S.doTheTest(); | ||
| 363 | } | ||
| 364 | |||
| 365 | test "return result loc and then switch with range implicit casted to error union" { | ||
| 366 | const S = struct { | ||
| 367 | fn doTheTest() !void { | ||
| 368 | try expect((func(0xb) catch unreachable) == 0xb); | ||
| 369 | } | ||
| 370 | fn func(d: u8) anyerror!u8 { | ||
| 371 | return switch (d) { | ||
| 372 | 0xa...0xf => d, | ||
| 373 | else => unreachable, | ||
| 374 | }; | ||
| 375 | } | ||
| 376 | }; | ||
| 377 | try S.doTheTest(); | ||
| 378 | comptime try S.doTheTest(); | ||
| 379 | } | ||
| 380 | |||
| 381 | test "switch with null and T peer types and inferred result location type" { | ||
| 382 | const S = struct { | ||
| 383 | fn doTheTest(c: u8) !void { | ||
| 384 | if (switch (c) { | ||
| 385 | 0 => true, | ||
| 386 | else => null, | ||
| 387 | }) |v| { | ||
| 388 | @panic("fail"); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | }; | ||
| 392 | try S.doTheTest(1); | ||
| 393 | comptime try S.doTheTest(1); | ||
| 394 | } | ||
| 395 | |||
| 396 | test "switch prongs with cases with identical payload types" { | ||
| 397 | const Union = union(enum) { | ||
| 398 | A: usize, | ||
| 399 | B: isize, | ||
| 400 | C: usize, | ||
| 401 | }; | ||
| 402 | const S = struct { | ||
| 403 | fn doTheTest() !void { | ||
| 404 | try doTheSwitch1(Union{ .A = 8 }); | ||
| 405 | try doTheSwitch2(Union{ .B = -8 }); | ||
| 406 | } | ||
| 407 | fn doTheSwitch1(u: Union) !void { | ||
| 408 | switch (u) { | ||
| 409 | .A, .C => |e| { | ||
| 410 | try expect(@TypeOf(e) == usize); | ||
| 411 | try expect(e == 8); | ||
| 412 | }, | ||
| 413 | .B => |e| @panic("fail"), | ||
| 414 | } | ||
| 415 | } | ||
| 416 | fn doTheSwitch2(u: Union) !void { | ||
| 417 | switch (u) { | ||
| 418 | .A, .C => |e| @panic("fail"), | ||
| 419 | .B => |e| { | ||
| 420 | try expect(@TypeOf(e) == isize); | ||
| 421 | try expect(e == -8); | ||
| 422 | }, | ||
| 423 | } | ||
| 424 | } | ||
| 425 | }; | ||
| 426 | try S.doTheTest(); | ||
| 427 | comptime try S.doTheTest(); | ||
| 428 | } | ||
| 429 | |||
| 430 | test "switch with disjoint range" { | ||
| 431 | var q: u8 = 0; | ||
| 432 | switch (q) { | ||
| 433 | 0...125 => {}, | ||
| 434 | 127...255 => {}, | ||
| 435 | 126...126 => {}, | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | test "switch variable for range and multiple prongs" { | ||
| 440 | const S = struct { | ||
| 441 | fn doTheTest() !void { | ||
| 442 | var u: u8 = 16; | ||
| 443 | try doTheSwitch(u); | ||
| 444 | comptime try doTheSwitch(u); | ||
| 445 | var v: u8 = 42; | ||
| 446 | try doTheSwitch(v); | ||
| 447 | comptime try doTheSwitch(v); | ||
| 448 | } | ||
| 449 | fn doTheSwitch(q: u8) !void { | ||
| 450 | switch (q) { | ||
| 451 | 0...40 => |x| try expect(x == 16), | ||
| 452 | 41, 42, 43 => |x| try expect(x == 42), | ||
| 453 | else => try expect(false), | ||
| 454 | } | ||
| 455 | } | ||
| 456 | }; | ||
| 457 | } | ||
| 458 | |||
| 459 | var state: u32 = 0; | ||
| 460 | fn poll() void { | ||
| 461 | switch (state) { | ||
| 462 | 0 => { | ||
| 463 | state = 1; | ||
| 464 | }, | ||
| 465 | else => { | ||
| 466 | state += 1; | ||
| 467 | }, | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | test "switch on global mutable var isn't constant-folded" { | ||
| 472 | while (state < 2) { | ||
| 473 | poll(); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | test "switch on pointer type" { | ||
| 478 | const S = struct { | ||
| 479 | const X = struct { | ||
| 480 | field: u32, | ||
| 481 | }; | ||
| 482 | |||
| 483 | const P1 = @intToPtr(*X, 0x400); | ||
| 484 | const P2 = @intToPtr(*X, 0x800); | ||
| 485 | const P3 = @intToPtr(*X, 0xC00); | ||
| 486 | |||
| 487 | fn doTheTest(arg: *X) i32 { | ||
| 488 | switch (arg) { | ||
| 489 | P1 => return 1, | ||
| 490 | P2 => return 2, | ||
| 491 | else => return 3, | ||
| 492 | } | ||
| 493 | } | ||
| 494 | }; | ||
| 495 | |||
| 496 | try expect(1 == S.doTheTest(S.P1)); | ||
| 497 | try expect(2 == S.doTheTest(S.P2)); | ||
| 498 | try expect(3 == S.doTheTest(S.P3)); | ||
| 499 | comptime try expect(1 == S.doTheTest(S.P1)); | ||
| 500 | comptime try expect(2 == S.doTheTest(S.P2)); | ||
| 501 | comptime try expect(3 == S.doTheTest(S.P3)); | ||
| 502 | } | ||
| 503 | |||
| 504 | test "switch on error set with single else" { | ||
| 505 | const S = struct { | ||
| 506 | fn doTheTest() !void { | ||
| 507 | var some: error{Foo} = error.Foo; | ||
| 508 | try expect(switch (some) { | ||
| 509 | else => |a| true, | ||
| 510 | }); | ||
| 511 | } | ||
| 512 | }; | ||
| 513 | |||
| 514 | try S.doTheTest(); | ||
| 515 | comptime try S.doTheTest(); | ||
| 516 | } | ||
| 517 | |||
| 518 | test "while copies its payload" { | ||
| 519 | const S = struct { | ||
| 520 | fn doTheTest() !void { | ||
| 521 | var tmp: union(enum) { | ||
| 522 | A: u8, | ||
| 523 | B: u32, | ||
| 524 | } = .{ .A = 42 }; | ||
| 525 | switch (tmp) { | ||
| 526 | .A => |value| { | ||
| 527 | // Modify the original union | ||
| 528 | tmp = .{ .B = 0x10101010 }; | ||
| 529 | try expectEqual(@as(u8, 42), value); | ||
| 530 | }, | ||
| 531 | else => unreachable, | ||
| 532 | } | ||
| 533 | } | ||
| 534 | }; | ||
| 535 | try S.doTheTest(); | ||
| 536 | comptime try S.doTheTest(); | ||
| 537 | } | ||
test/stage1/behavior/switch_prong_err_enum.zig deleted-30| ... | @@ -1,30 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | var read_count: u64 = 0; | ||
| 4 | |||
| 5 | fn readOnce() anyerror!u64 { | ||
| 6 | read_count += 1; | ||
| 7 | return read_count; | ||
| 8 | } | ||
| 9 | |||
| 10 | const FormValue = union(enum) { | ||
| 11 | Address: u64, | ||
| 12 | Other: bool, | ||
| 13 | }; | ||
| 14 | |||
| 15 | fn doThing(form_id: u64) anyerror!FormValue { | ||
| 16 | return switch (form_id) { | ||
| 17 | 17 => FormValue{ .Address = try readOnce() }, | ||
| 18 | else => error.InvalidDebugInfo, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "switch prong returns error enum" { | ||
| 23 | switch (doThing(17) catch unreachable) { | ||
| 24 | FormValue.Address => |payload| { | ||
| 25 | try expect(payload == 1); | ||
| 26 | }, | ||
| 27 | else => unreachable, | ||
| 28 | } | ||
| 29 | try expect(read_count == 1); | ||
| 30 | } | ||
test/stage1/behavior/switch_prong_implicit_cast.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const FormValue = union(enum) { | ||
| 4 | One: void, | ||
| 5 | Two: bool, | ||
| 6 | }; | ||
| 7 | |||
| 8 | fn foo(id: u64) !FormValue { | ||
| 9 | return switch (id) { | ||
| 10 | 2 => FormValue{ .Two = true }, | ||
| 11 | 1 => FormValue{ .One = {} }, | ||
| 12 | else => return error.Whatever, | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "switch prong implicit cast" { | ||
| 17 | const result = switch (foo(2) catch unreachable) { | ||
| 18 | FormValue.One => false, | ||
| 19 | FormValue.Two => |x| x, | ||
| 20 | }; | ||
| 21 | try expect(result); | ||
| 22 | } | ||
test/stage1/behavior/syntax.zig deleted-68| ... | @@ -1,68 +0,0 @@ | ||
| 1 | // Test trailing comma syntax | ||
| 2 | // zig fmt: off | ||
| 3 | |||
| 4 | extern var a: c_int; | ||
| 5 | extern "c" var b: c_int; | ||
| 6 | export var c: c_int = 0; | ||
| 7 | threadlocal var d: c_int; | ||
| 8 | extern threadlocal var e: c_int; | ||
| 9 | extern "c" threadlocal var f: c_int; | ||
| 10 | export threadlocal var g: c_int = 0; | ||
| 11 | |||
| 12 | const struct_trailing_comma = struct { x: i32, y: i32, }; | ||
| 13 | const struct_no_comma = struct { x: i32, y: i32 }; | ||
| 14 | const struct_fn_no_comma = struct { fn m() void {} y: i32 }; | ||
| 15 | |||
| 16 | const enum_no_comma = enum { A, B }; | ||
| 17 | |||
| 18 | fn container_init() void { | ||
| 19 | const S = struct { x: i32, y: i32 }; | ||
| 20 | _ = S { .x = 1, .y = 2 }; | ||
| 21 | _ = S { .x = 1, .y = 2, }; | ||
| 22 | } | ||
| 23 | |||
| 24 | fn type_expr_return1() if (true) A {} | ||
| 25 | fn type_expr_return2() for (true) |_| A {} | ||
| 26 | fn type_expr_return3() while (true) A {} | ||
| 27 | fn type_expr_return4() comptime A {} | ||
| 28 | |||
| 29 | fn switch_cases(x: i32) void { | ||
| 30 | switch (x) { | ||
| 31 | 1,2,3 => {}, | ||
| 32 | 4,5, => {}, | ||
| 33 | 6...8, => {}, | ||
| 34 | else => {}, | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | fn switch_prongs(x: i32) void { | ||
| 39 | switch (x) { | ||
| 40 | 0 => {}, | ||
| 41 | else => {}, | ||
| 42 | } | ||
| 43 | switch (x) { | ||
| 44 | 0 => {}, | ||
| 45 | else => {} | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | const fn_no_comma = fn(i32, i32)void; | ||
| 50 | const fn_trailing_comma = fn(i32, i32,)void; | ||
| 51 | |||
| 52 | fn fn_calls() void { | ||
| 53 | fn add(x: i32, y: i32,) i32 { x + y }; | ||
| 54 | _ = add(1, 2); | ||
| 55 | _ = add(1, 2,); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn asm_lists() void { | ||
| 59 | if (false) { // Build AST but don't analyze | ||
| 60 | asm ("not real assembly" | ||
| 61 | :[a] "x" (x),); | ||
| 62 | asm ("not real assembly" | ||
| 63 | :[a] "x" (->i32),:[a] "x" (1),); | ||
| 64 | asm ("still not real assembly" | ||
| 65 | :::"a","b",); | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
test/stage1/behavior/this.zig deleted-34| ... | @@ -1,34 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const module = @This(); | ||
| 4 | |||
| 5 | fn Point(comptime T: type) type { | ||
| 6 | return struct { | ||
| 7 | const Self = @This(); | ||
| 8 | x: T, | ||
| 9 | y: T, | ||
| 10 | |||
| 11 | fn addOne(self: *Self) void { | ||
| 12 | self.x += 1; | ||
| 13 | self.y += 1; | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | fn add(x: i32, y: i32) i32 { | ||
| 19 | return x + y; | ||
| 20 | } | ||
| 21 | |||
| 22 | test "this refer to module call private fn" { | ||
| 23 | try expect(module.add(1, 2) == 3); | ||
| 24 | } | ||
| 25 | |||
| 26 | test "this refer to container" { | ||
| 27 | var pt = Point(i32){ | ||
| 28 | .x = 12, | ||
| 29 | .y = 34, | ||
| 30 | }; | ||
| 31 | pt.addOne(); | ||
| 32 | try expect(pt.x == 13); | ||
| 33 | try expect(pt.y == 35); | ||
| 34 | } | ||
test/stage1/behavior/translate_c_macros.h deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | // initializer list expression | ||
| 2 | typedef struct Color { | ||
| 3 | unsigned char r; | ||
| 4 | unsigned char g; | ||
| 5 | unsigned char b; | ||
| 6 | unsigned char a; | ||
| 7 | } Color; | ||
| 8 | #define CLITERAL(type) (type) | ||
| 9 | #define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray | ||
| 10 | |||
| 11 | #define MY_SIZEOF(x) ((int)sizeof(x)) | ||
| 12 | #define MY_SIZEOF2(x) ((int)sizeof x) | ||
| 13 | |||
| 14 | struct Foo { | ||
| 15 | int a; | ||
| 16 | }; | ||
| 17 | |||
| 18 | #define SIZE_OF_FOO sizeof(struct Foo) | ||
test/stage1/behavior/translate_c_macros.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const expectEqual = @import("std").testing.expectEqual; | ||
| 3 | |||
| 4 | const h = @cImport(@cInclude("stage1/behavior/translate_c_macros.h")); | ||
| 5 | |||
| 6 | test "initializer list expression" { | ||
| 7 | try expectEqual(h.Color{ | ||
| 8 | .r = 200, | ||
| 9 | .g = 200, | ||
| 10 | .b = 200, | ||
| 11 | .a = 255, | ||
| 12 | }, h.LIGHTGRAY); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "sizeof in macros" { | ||
| 16 | try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32)); | ||
| 17 | try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32)); | ||
| 18 | } | ||
| 19 | |||
| 20 | test "reference to a struct type" { | ||
| 21 | try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); | ||
| 22 | } | ||
test/stage1/behavior/truncate.zig deleted-36| ... | @@ -1,36 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "truncate u0 to larger integer allowed and has comptime known result" { | ||
| 5 | var x: u0 = 0; | ||
| 6 | const y = @truncate(u8, x); | ||
| 7 | comptime try expect(y == 0); | ||
| 8 | } | ||
| 9 | |||
| 10 | test "truncate.u0.literal" { | ||
| 11 | var z = @truncate(u0, 0); | ||
| 12 | try expect(z == 0); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "truncate.u0.const" { | ||
| 16 | const c0: usize = 0; | ||
| 17 | var z = @truncate(u0, c0); | ||
| 18 | try expect(z == 0); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "truncate.u0.var" { | ||
| 22 | var d: u8 = 2; | ||
| 23 | var z = @truncate(u0, d); | ||
| 24 | try expect(z == 0); | ||
| 25 | } | ||
| 26 | |||
| 27 | test "truncate sign mismatch but comptime known so it works anyway" { | ||
| 28 | const x: u32 = 10; | ||
| 29 | var result = @truncate(i8, x); | ||
| 30 | try expect(result == 10); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "truncate on comptime integer" { | ||
| 34 | var x = @truncate(u16, 9999); | ||
| 35 | try expect(x == 9999); | ||
| 36 | } | ||
test/stage1/behavior/try.zig deleted-43| ... | @@ -1,43 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "try on error union" { | ||
| 4 | try tryOnErrorUnionImpl(); | ||
| 5 | comptime try tryOnErrorUnionImpl(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn tryOnErrorUnionImpl() !void { | ||
| 9 | const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { | ||
| 10 | error.ItBroke, error.NoMem => 1, | ||
| 11 | error.CrappedOut => @as(i32, 2), | ||
| 12 | else => unreachable, | ||
| 13 | }; | ||
| 14 | try expect(x == 11); | ||
| 15 | } | ||
| 16 | |||
| 17 | fn returnsTen() anyerror!i32 { | ||
| 18 | return 10; | ||
| 19 | } | ||
| 20 | |||
| 21 | test "try without vars" { | ||
| 22 | const result1 = if (failIfTrue(true)) 1 else |_| @as(i32, 2); | ||
| 23 | try expect(result1 == 2); | ||
| 24 | |||
| 25 | const result2 = if (failIfTrue(false)) 1 else |_| @as(i32, 2); | ||
| 26 | try expect(result2 == 1); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn failIfTrue(ok: bool) anyerror!void { | ||
| 30 | if (ok) { | ||
| 31 | return error.ItBroke; | ||
| 32 | } else { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "try then not executed with assignment" { | ||
| 38 | if (failIfTrue(true)) { | ||
| 39 | unreachable; | ||
| 40 | } else |err| { | ||
| 41 | try expect(err == error.ItBroke); | ||
| 42 | } | ||
| 43 | } | ||
test/stage1/behavior/tuple.zig deleted-113| ... | @@ -1,113 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "tuple concatenation" { | ||
| 7 | const S = struct { | ||
| 8 | fn doTheTest() !void { | ||
| 9 | var a: i32 = 1; | ||
| 10 | var b: i32 = 2; | ||
| 11 | var x = .{a}; | ||
| 12 | var y = .{b}; | ||
| 13 | var c = x ++ y; | ||
| 14 | try expectEqual(@as(i32, 1), c[0]); | ||
| 15 | try expectEqual(@as(i32, 2), c[1]); | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | try S.doTheTest(); | ||
| 19 | comptime try S.doTheTest(); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "tuple multiplication" { | ||
| 23 | const S = struct { | ||
| 24 | fn doTheTest() !void { | ||
| 25 | { | ||
| 26 | const t = .{} ** 4; | ||
| 27 | try expectEqual(0, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | const t = .{'a'} ** 4; | ||
| 31 | try expectEqual(4, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 32 | inline for (t) |x| try expectEqual('a', x); | ||
| 33 | } | ||
| 34 | { | ||
| 35 | const t = .{ 1, 2, 3 } ** 4; | ||
| 36 | try expectEqual(12, @typeInfo(@TypeOf(t)).Struct.fields.len); | ||
| 37 | inline for (t) |x, i| try expectEqual(1 + i % 3, x); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | try S.doTheTest(); | ||
| 42 | comptime try S.doTheTest(); | ||
| 43 | |||
| 44 | const T = struct { | ||
| 45 | fn consume_tuple(tuple: anytype, len: usize) !void { | ||
| 46 | try expect(tuple.len == len); | ||
| 47 | } | ||
| 48 | |||
| 49 | fn doTheTest() !void { | ||
| 50 | const t1 = .{}; | ||
| 51 | |||
| 52 | var rt_var: u8 = 42; | ||
| 53 | const t2 = .{rt_var} ++ .{}; | ||
| 54 | |||
| 55 | try expect(t2.len == 1); | ||
| 56 | try expect(t2.@"0" == rt_var); | ||
| 57 | try expect(t2.@"0" == 42); | ||
| 58 | try expect(&t2.@"0" != &rt_var); | ||
| 59 | |||
| 60 | try consume_tuple(t1 ++ t1, 0); | ||
| 61 | try consume_tuple(.{} ++ .{}, 0); | ||
| 62 | try consume_tuple(.{0} ++ .{}, 1); | ||
| 63 | try consume_tuple(.{0} ++ .{1}, 2); | ||
| 64 | try consume_tuple(.{ 0, 1, 2 } ++ .{ u8, 1, noreturn }, 6); | ||
| 65 | try consume_tuple(t2 ++ t1, 1); | ||
| 66 | try consume_tuple(t1 ++ t2, 1); | ||
| 67 | try consume_tuple(t2 ++ t2, 2); | ||
| 68 | try consume_tuple(.{rt_var} ++ .{}, 1); | ||
| 69 | try consume_tuple(.{rt_var} ++ t1, 1); | ||
| 70 | try consume_tuple(.{} ++ .{rt_var}, 1); | ||
| 71 | try consume_tuple(t2 ++ .{void}, 2); | ||
| 72 | try consume_tuple(t2 ++ .{0}, 2); | ||
| 73 | try consume_tuple(.{0} ++ t2, 2); | ||
| 74 | try consume_tuple(.{void} ++ t2, 2); | ||
| 75 | try consume_tuple(.{u8} ++ .{rt_var} ++ .{true}, 3); | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | try T.doTheTest(); | ||
| 80 | comptime try T.doTheTest(); | ||
| 81 | } | ||
| 82 | |||
| 83 | test "pass tuple to comptime var parameter" { | ||
| 84 | const S = struct { | ||
| 85 | fn Foo(comptime args: anytype) !void { | ||
| 86 | try expect(args[0] == 1); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn doTheTest() !void { | ||
| 90 | try Foo(.{1}); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | try S.doTheTest(); | ||
| 94 | comptime try S.doTheTest(); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "tuple initializer for var" { | ||
| 98 | const S = struct { | ||
| 99 | fn doTheTest() void { | ||
| 100 | const Bytes = struct { | ||
| 101 | id: usize, | ||
| 102 | }; | ||
| 103 | |||
| 104 | var tmp = .{ | ||
| 105 | .id = @as(usize, 2), | ||
| 106 | .name = Bytes{ .id = 20 }, | ||
| 107 | }; | ||
| 108 | } | ||
| 109 | }; | ||
| 110 | |||
| 111 | S.doTheTest(); | ||
| 112 | comptime S.doTheTest(); | ||
| 113 | } | ||
test/stage1/behavior/type.zig deleted-454| ... | @@ -1,454 +0,0 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const TypeInfo = builtin.TypeInfo; | ||
| 3 | |||
| 4 | const std = @import("std"); | ||
| 5 | const testing = std.testing; | ||
| 6 | |||
| 7 | fn testTypes(comptime types: []const type) !void { | ||
| 8 | inline for (types) |testType| { | ||
| 9 | try testing.expect(testType == @Type(@typeInfo(testType))); | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | test "Type.MetaType" { | ||
| 14 | try testing.expect(type == @Type(TypeInfo{ .Type = undefined })); | ||
| 15 | try testTypes(&[_]type{type}); | ||
| 16 | } | ||
| 17 | |||
| 18 | test "Type.Void" { | ||
| 19 | try testing.expect(void == @Type(TypeInfo{ .Void = undefined })); | ||
| 20 | try testTypes(&[_]type{void}); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "Type.Bool" { | ||
| 24 | try testing.expect(bool == @Type(TypeInfo{ .Bool = undefined })); | ||
| 25 | try testTypes(&[_]type{bool}); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "Type.NoReturn" { | ||
| 29 | try testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined })); | ||
| 30 | try testTypes(&[_]type{noreturn}); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "Type.Int" { | ||
| 34 | try testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 1 } })); | ||
| 35 | try testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 1 } })); | ||
| 36 | try testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 8 } })); | ||
| 37 | try testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 8 } })); | ||
| 38 | try testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 64 } })); | ||
| 39 | try testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 64 } })); | ||
| 40 | try testTypes(&[_]type{ u8, u32, i64 }); | ||
| 41 | } | ||
| 42 | |||
| 43 | test "Type.Float" { | ||
| 44 | try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } })); | ||
| 45 | try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } })); | ||
| 46 | try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } })); | ||
| 47 | try testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } })); | ||
| 48 | try testTypes(&[_]type{ f16, f32, f64, f128 }); | ||
| 49 | } | ||
| 50 | |||
| 51 | test "Type.Pointer" { | ||
| 52 | try testTypes(&[_]type{ | ||
| 53 | // One Value Pointer Types | ||
| 54 | *u8, *const u8, | ||
| 55 | *volatile u8, *const volatile u8, | ||
| 56 | *align(4) u8, *align(4) const u8, | ||
| 57 | *align(4) volatile u8, *align(4) const volatile u8, | ||
| 58 | *align(8) u8, *align(8) const u8, | ||
| 59 | *align(8) volatile u8, *align(8) const volatile u8, | ||
| 60 | *allowzero u8, *allowzero const u8, | ||
| 61 | *allowzero volatile u8, *allowzero const volatile u8, | ||
| 62 | *allowzero align(4) u8, *allowzero align(4) const u8, | ||
| 63 | *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, | ||
| 64 | // Many Values Pointer Types | ||
| 65 | [*]u8, [*]const u8, | ||
| 66 | [*]volatile u8, [*]const volatile u8, | ||
| 67 | [*]align(4) u8, [*]align(4) const u8, | ||
| 68 | [*]align(4) volatile u8, [*]align(4) const volatile u8, | ||
| 69 | [*]align(8) u8, [*]align(8) const u8, | ||
| 70 | [*]align(8) volatile u8, [*]align(8) const volatile u8, | ||
| 71 | [*]allowzero u8, [*]allowzero const u8, | ||
| 72 | [*]allowzero volatile u8, [*]allowzero const volatile u8, | ||
| 73 | [*]allowzero align(4) u8, [*]allowzero align(4) const u8, | ||
| 74 | [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, | ||
| 75 | // Slice Types | ||
| 76 | []u8, []const u8, | ||
| 77 | []volatile u8, []const volatile u8, | ||
| 78 | []align(4) u8, []align(4) const u8, | ||
| 79 | []align(4) volatile u8, []align(4) const volatile u8, | ||
| 80 | []align(8) u8, []align(8) const u8, | ||
| 81 | []align(8) volatile u8, []align(8) const volatile u8, | ||
| 82 | []allowzero u8, []allowzero const u8, | ||
| 83 | []allowzero volatile u8, []allowzero const volatile u8, | ||
| 84 | []allowzero align(4) u8, []allowzero align(4) const u8, | ||
| 85 | []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, | ||
| 86 | // C Pointer Types | ||
| 87 | [*c]u8, [*c]const u8, | ||
| 88 | [*c]volatile u8, [*c]const volatile u8, | ||
| 89 | [*c]align(4) u8, [*c]align(4) const u8, | ||
| 90 | [*c]align(4) volatile u8, [*c]align(4) const volatile u8, | ||
| 91 | [*c]align(8) u8, [*c]align(8) const u8, | ||
| 92 | [*c]align(8) volatile u8, [*c]align(8) const volatile u8, | ||
| 93 | }); | ||
| 94 | } | ||
| 95 | |||
| 96 | test "Type.Array" { | ||
| 97 | try testing.expect([123]u8 == @Type(TypeInfo{ | ||
| 98 | .Array = TypeInfo.Array{ | ||
| 99 | .len = 123, | ||
| 100 | .child = u8, | ||
| 101 | .sentinel = null, | ||
| 102 | }, | ||
| 103 | })); | ||
| 104 | try testing.expect([2]u32 == @Type(TypeInfo{ | ||
| 105 | .Array = TypeInfo.Array{ | ||
| 106 | .len = 2, | ||
| 107 | .child = u32, | ||
| 108 | .sentinel = null, | ||
| 109 | }, | ||
| 110 | })); | ||
| 111 | try testing.expect([2:0]u32 == @Type(TypeInfo{ | ||
| 112 | .Array = TypeInfo.Array{ | ||
| 113 | .len = 2, | ||
| 114 | .child = u32, | ||
| 115 | .sentinel = 0, | ||
| 116 | }, | ||
| 117 | })); | ||
| 118 | try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool }); | ||
| 119 | } | ||
| 120 | |||
| 121 | test "Type.ComptimeFloat" { | ||
| 122 | try testTypes(&[_]type{comptime_float}); | ||
| 123 | } | ||
| 124 | test "Type.ComptimeInt" { | ||
| 125 | try testTypes(&[_]type{comptime_int}); | ||
| 126 | } | ||
| 127 | test "Type.Undefined" { | ||
| 128 | try testTypes(&[_]type{@TypeOf(undefined)}); | ||
| 129 | } | ||
| 130 | test "Type.Null" { | ||
| 131 | try testTypes(&[_]type{@TypeOf(null)}); | ||
| 132 | } | ||
| 133 | test "@Type create slice with null sentinel" { | ||
| 134 | const Slice = @Type(builtin.TypeInfo{ | ||
| 135 | .Pointer = .{ | ||
| 136 | .size = .Slice, | ||
| 137 | .is_const = true, | ||
| 138 | .is_volatile = false, | ||
| 139 | .is_allowzero = false, | ||
| 140 | .alignment = 8, | ||
| 141 | .child = *i32, | ||
| 142 | .sentinel = null, | ||
| 143 | }, | ||
| 144 | }); | ||
| 145 | try testing.expect(Slice == []align(8) const *i32); | ||
| 146 | } | ||
| 147 | test "@Type picks up the sentinel value from TypeInfo" { | ||
| 148 | try testTypes(&[_]type{ | ||
| 149 | [11:0]u8, [4:10]u8, | ||
| 150 | [*:0]u8, [*:0]const u8, | ||
| 151 | [*:0]volatile u8, [*:0]const volatile u8, | ||
| 152 | [*:0]align(4) u8, [*:0]align(4) const u8, | ||
| 153 | [*:0]align(4) volatile u8, [*:0]align(4) const volatile u8, | ||
| 154 | [*:0]align(8) u8, [*:0]align(8) const u8, | ||
| 155 | [*:0]align(8) volatile u8, [*:0]align(8) const volatile u8, | ||
| 156 | [*:0]allowzero u8, [*:0]allowzero const u8, | ||
| 157 | [*:0]allowzero volatile u8, [*:0]allowzero const volatile u8, | ||
| 158 | [*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8, | ||
| 159 | [*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8, | ||
| 160 | [*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8, | ||
| 161 | [:0]u8, [:0]const u8, | ||
| 162 | [:0]volatile u8, [:0]const volatile u8, | ||
| 163 | [:0]align(4) u8, [:0]align(4) const u8, | ||
| 164 | [:0]align(4) volatile u8, [:0]align(4) const volatile u8, | ||
| 165 | [:0]align(8) u8, [:0]align(8) const u8, | ||
| 166 | [:0]align(8) volatile u8, [:0]align(8) const volatile u8, | ||
| 167 | [:0]allowzero u8, [:0]allowzero const u8, | ||
| 168 | [:0]allowzero volatile u8, [:0]allowzero const volatile u8, | ||
| 169 | [:0]allowzero align(4) u8, [:0]allowzero align(4) const u8, | ||
| 170 | [:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8, | ||
| 171 | [:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8, | ||
| 172 | }); | ||
| 173 | } | ||
| 174 | |||
| 175 | test "Type.Optional" { | ||
| 176 | try testTypes(&[_]type{ | ||
| 177 | ?u8, | ||
| 178 | ?*u8, | ||
| 179 | ?[]u8, | ||
| 180 | ?[*]u8, | ||
| 181 | ?[*c]u8, | ||
| 182 | }); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "Type.ErrorUnion" { | ||
| 186 | try testTypes(&[_]type{ | ||
| 187 | error{}!void, | ||
| 188 | error{Error}!void, | ||
| 189 | }); | ||
| 190 | } | ||
| 191 | |||
| 192 | test "Type.Opaque" { | ||
| 193 | const Opaque = @Type(.{ | ||
| 194 | .Opaque = .{ | ||
| 195 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 196 | }, | ||
| 197 | }); | ||
| 198 | try testing.expect(Opaque != opaque {}); | ||
| 199 | try testing.expectEqualSlices( | ||
| 200 | TypeInfo.Declaration, | ||
| 201 | &[_]TypeInfo.Declaration{}, | ||
| 202 | @typeInfo(Opaque).Opaque.decls, | ||
| 203 | ); | ||
| 204 | } | ||
| 205 | |||
| 206 | test "Type.Vector" { | ||
| 207 | try testTypes(&[_]type{ | ||
| 208 | @Vector(0, u8), | ||
| 209 | @Vector(4, u8), | ||
| 210 | @Vector(8, *u8), | ||
| 211 | std.meta.Vector(0, u8), | ||
| 212 | std.meta.Vector(4, u8), | ||
| 213 | std.meta.Vector(8, *u8), | ||
| 214 | }); | ||
| 215 | } | ||
| 216 | |||
| 217 | test "Type.AnyFrame" { | ||
| 218 | try testTypes(&[_]type{ | ||
| 219 | anyframe, | ||
| 220 | anyframe->u8, | ||
| 221 | anyframe->anyframe->u8, | ||
| 222 | }); | ||
| 223 | } | ||
| 224 | |||
| 225 | test "Type.EnumLiteral" { | ||
| 226 | try testTypes(&[_]type{ | ||
| 227 | @TypeOf(.Dummy), | ||
| 228 | }); | ||
| 229 | } | ||
| 230 | |||
| 231 | fn add(a: i32, b: i32) i32 { | ||
| 232 | return a + b; | ||
| 233 | } | ||
| 234 | |||
| 235 | test "Type.Frame" { | ||
| 236 | try testTypes(&[_]type{ | ||
| 237 | @Frame(add), | ||
| 238 | }); | ||
| 239 | } | ||
| 240 | |||
| 241 | test "Type.ErrorSet" { | ||
| 242 | // error sets don't compare equal so just check if they compile | ||
| 243 | _ = @Type(@typeInfo(error{})); | ||
| 244 | _ = @Type(@typeInfo(error{A})); | ||
| 245 | _ = @Type(@typeInfo(error{ A, B, C })); | ||
| 246 | } | ||
| 247 | |||
| 248 | test "Type.Struct" { | ||
| 249 | const A = @Type(@typeInfo(struct { x: u8, y: u32 })); | ||
| 250 | const infoA = @typeInfo(A).Struct; | ||
| 251 | try testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout); | ||
| 252 | try testing.expectEqualSlices(u8, "x", infoA.fields[0].name); | ||
| 253 | try testing.expectEqual(u8, infoA.fields[0].field_type); | ||
| 254 | try testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value); | ||
| 255 | try testing.expectEqualSlices(u8, "y", infoA.fields[1].name); | ||
| 256 | try testing.expectEqual(u32, infoA.fields[1].field_type); | ||
| 257 | try testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value); | ||
| 258 | try testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls); | ||
| 259 | try testing.expectEqual(@as(bool, false), infoA.is_tuple); | ||
| 260 | |||
| 261 | var a = A{ .x = 0, .y = 1 }; | ||
| 262 | try testing.expectEqual(@as(u8, 0), a.x); | ||
| 263 | try testing.expectEqual(@as(u32, 1), a.y); | ||
| 264 | a.y += 1; | ||
| 265 | try testing.expectEqual(@as(u32, 2), a.y); | ||
| 266 | |||
| 267 | const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 })); | ||
| 268 | const infoB = @typeInfo(B).Struct; | ||
| 269 | try testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout); | ||
| 270 | try testing.expectEqualSlices(u8, "x", infoB.fields[0].name); | ||
| 271 | try testing.expectEqual(u8, infoB.fields[0].field_type); | ||
| 272 | try testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value); | ||
| 273 | try testing.expectEqualSlices(u8, "y", infoB.fields[1].name); | ||
| 274 | try testing.expectEqual(u32, infoB.fields[1].field_type); | ||
| 275 | try testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value); | ||
| 276 | try testing.expectEqual(@as(usize, 0), infoB.decls.len); | ||
| 277 | try testing.expectEqual(@as(bool, false), infoB.is_tuple); | ||
| 278 | |||
| 279 | const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 })); | ||
| 280 | const infoC = @typeInfo(C).Struct; | ||
| 281 | try testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout); | ||
| 282 | try testing.expectEqualSlices(u8, "x", infoC.fields[0].name); | ||
| 283 | try testing.expectEqual(u8, infoC.fields[0].field_type); | ||
| 284 | try testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value); | ||
| 285 | try testing.expectEqualSlices(u8, "y", infoC.fields[1].name); | ||
| 286 | try testing.expectEqual(u32, infoC.fields[1].field_type); | ||
| 287 | try testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value); | ||
| 288 | try testing.expectEqual(@as(usize, 0), infoC.decls.len); | ||
| 289 | try testing.expectEqual(@as(bool, false), infoC.is_tuple); | ||
| 290 | } | ||
| 291 | |||
| 292 | test "Type.Enum" { | ||
| 293 | const Foo = @Type(.{ | ||
| 294 | .Enum = .{ | ||
| 295 | .layout = .Auto, | ||
| 296 | .tag_type = u8, | ||
| 297 | .fields = &[_]TypeInfo.EnumField{ | ||
| 298 | .{ .name = "a", .value = 1 }, | ||
| 299 | .{ .name = "b", .value = 5 }, | ||
| 300 | }, | ||
| 301 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 302 | .is_exhaustive = true, | ||
| 303 | }, | ||
| 304 | }); | ||
| 305 | try testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive); | ||
| 306 | try testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a)); | ||
| 307 | try testing.expectEqual(@as(u8, 5), @enumToInt(Foo.b)); | ||
| 308 | const Bar = @Type(.{ | ||
| 309 | .Enum = .{ | ||
| 310 | .layout = .Extern, | ||
| 311 | .tag_type = u32, | ||
| 312 | .fields = &[_]TypeInfo.EnumField{ | ||
| 313 | .{ .name = "a", .value = 1 }, | ||
| 314 | .{ .name = "b", .value = 5 }, | ||
| 315 | }, | ||
| 316 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 317 | .is_exhaustive = false, | ||
| 318 | }, | ||
| 319 | }); | ||
| 320 | try testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive); | ||
| 321 | try testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a)); | ||
| 322 | try testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); | ||
| 323 | try testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); | ||
| 324 | } | ||
| 325 | |||
| 326 | test "Type.Union" { | ||
| 327 | const Untagged = @Type(.{ | ||
| 328 | .Union = .{ | ||
| 329 | .layout = .Auto, | ||
| 330 | .tag_type = null, | ||
| 331 | .fields = &[_]TypeInfo.UnionField{ | ||
| 332 | .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) }, | ||
| 333 | .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) }, | ||
| 334 | }, | ||
| 335 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 336 | }, | ||
| 337 | }); | ||
| 338 | var untagged = Untagged{ .int = 1 }; | ||
| 339 | untagged.float = 2.0; | ||
| 340 | untagged.int = 3; | ||
| 341 | try testing.expectEqual(@as(i32, 3), untagged.int); | ||
| 342 | |||
| 343 | const PackedUntagged = @Type(.{ | ||
| 344 | .Union = .{ | ||
| 345 | .layout = .Packed, | ||
| 346 | .tag_type = null, | ||
| 347 | .fields = &[_]TypeInfo.UnionField{ | ||
| 348 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | ||
| 349 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 350 | }, | ||
| 351 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 352 | }, | ||
| 353 | }); | ||
| 354 | var packed_untagged = PackedUntagged{ .signed = -1 }; | ||
| 355 | try testing.expectEqual(@as(i32, -1), packed_untagged.signed); | ||
| 356 | try testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned); | ||
| 357 | |||
| 358 | const Tag = @Type(.{ | ||
| 359 | .Enum = .{ | ||
| 360 | .layout = .Auto, | ||
| 361 | .tag_type = u1, | ||
| 362 | .fields = &[_]TypeInfo.EnumField{ | ||
| 363 | .{ .name = "signed", .value = 0 }, | ||
| 364 | .{ .name = "unsigned", .value = 1 }, | ||
| 365 | }, | ||
| 366 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 367 | .is_exhaustive = true, | ||
| 368 | }, | ||
| 369 | }); | ||
| 370 | const Tagged = @Type(.{ | ||
| 371 | .Union = .{ | ||
| 372 | .layout = .Auto, | ||
| 373 | .tag_type = Tag, | ||
| 374 | .fields = &[_]TypeInfo.UnionField{ | ||
| 375 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | ||
| 376 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 377 | }, | ||
| 378 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 379 | }, | ||
| 380 | }); | ||
| 381 | var tagged = Tagged{ .signed = -1 }; | ||
| 382 | try testing.expectEqual(Tag.signed, tagged); | ||
| 383 | tagged = .{ .unsigned = 1 }; | ||
| 384 | try testing.expectEqual(Tag.unsigned, tagged); | ||
| 385 | } | ||
| 386 | |||
| 387 | test "Type.Union from Type.Enum" { | ||
| 388 | const Tag = @Type(.{ | ||
| 389 | .Enum = .{ | ||
| 390 | .layout = .Auto, | ||
| 391 | .tag_type = u0, | ||
| 392 | .fields = &[_]TypeInfo.EnumField{ | ||
| 393 | .{ .name = "working_as_expected", .value = 0 }, | ||
| 394 | }, | ||
| 395 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 396 | .is_exhaustive = true, | ||
| 397 | }, | ||
| 398 | }); | ||
| 399 | const T = @Type(.{ | ||
| 400 | .Union = .{ | ||
| 401 | .layout = .Auto, | ||
| 402 | .tag_type = Tag, | ||
| 403 | .fields = &[_]TypeInfo.UnionField{ | ||
| 404 | .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 405 | }, | ||
| 406 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 407 | }, | ||
| 408 | }); | ||
| 409 | _ = T; | ||
| 410 | _ = @typeInfo(T).Union; | ||
| 411 | } | ||
| 412 | |||
| 413 | test "Type.Union from regular enum" { | ||
| 414 | const E = enum { working_as_expected = 0 }; | ||
| 415 | const T = @Type(.{ | ||
| 416 | .Union = .{ | ||
| 417 | .layout = .Auto, | ||
| 418 | .tag_type = E, | ||
| 419 | .fields = &[_]TypeInfo.UnionField{ | ||
| 420 | .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 421 | }, | ||
| 422 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 423 | }, | ||
| 424 | }); | ||
| 425 | _ = T; | ||
| 426 | _ = @typeInfo(T).Union; | ||
| 427 | } | ||
| 428 | |||
| 429 | test "Type.Fn" { | ||
| 430 | // wasm doesn't support align attributes on functions | ||
| 431 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 432 | |||
| 433 | const foo = struct { | ||
| 434 | fn func(a: usize, b: bool) align(4) callconv(.C) usize { | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | }.func; | ||
| 438 | const Foo = @Type(@typeInfo(@TypeOf(foo))); | ||
| 439 | const foo_2: Foo = foo; | ||
| 440 | } | ||
| 441 | |||
| 442 | test "Type.BoundFn" { | ||
| 443 | // wasm doesn't support align attributes on functions | ||
| 444 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 445 | |||
| 446 | const TestStruct = packed struct { | ||
| 447 | pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {} | ||
| 448 | }; | ||
| 449 | const test_instance: TestStruct = undefined; | ||
| 450 | try testing.expect(std.meta.eql( | ||
| 451 | @typeName(@TypeOf(test_instance.foo)), | ||
| 452 | @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))), | ||
| 453 | )); | ||
| 454 | } | ||
test/stage1/behavior/type_info.zig deleted-484| ... | @@ -1,484 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | const TypeInfo = builtin.TypeInfo; | ||
| 6 | const TypeId = builtin.TypeId; | ||
| 7 | |||
| 8 | const expect = std.testing.expect; | ||
| 9 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 10 | |||
| 11 | test "type info: tag type, void info" { | ||
| 12 | try testBasic(); | ||
| 13 | comptime try testBasic(); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn testBasic() !void { | ||
| 17 | try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId); | ||
| 18 | const void_info = @typeInfo(void); | ||
| 19 | try expect(void_info == TypeId.Void); | ||
| 20 | try expect(void_info.Void == {}); | ||
| 21 | } | ||
| 22 | |||
| 23 | test "type info: integer, floating point type info" { | ||
| 24 | try testIntFloat(); | ||
| 25 | comptime try testIntFloat(); | ||
| 26 | } | ||
| 27 | |||
| 28 | fn testIntFloat() !void { | ||
| 29 | const u8_info = @typeInfo(u8); | ||
| 30 | try expect(u8_info == .Int); | ||
| 31 | try expect(u8_info.Int.signedness == .unsigned); | ||
| 32 | try expect(u8_info.Int.bits == 8); | ||
| 33 | |||
| 34 | const f64_info = @typeInfo(f64); | ||
| 35 | try expect(f64_info == .Float); | ||
| 36 | try expect(f64_info.Float.bits == 64); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "type info: pointer type info" { | ||
| 40 | try testPointer(); | ||
| 41 | comptime try testPointer(); | ||
| 42 | } | ||
| 43 | |||
| 44 | fn testPointer() !void { | ||
| 45 | const u32_ptr_info = @typeInfo(*u32); | ||
| 46 | try expect(u32_ptr_info == .Pointer); | ||
| 47 | try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); | ||
| 48 | try expect(u32_ptr_info.Pointer.is_const == false); | ||
| 49 | try expect(u32_ptr_info.Pointer.is_volatile == false); | ||
| 50 | try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32)); | ||
| 51 | try expect(u32_ptr_info.Pointer.child == u32); | ||
| 52 | try expect(u32_ptr_info.Pointer.sentinel == null); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "type info: unknown length pointer type info" { | ||
| 56 | try testUnknownLenPtr(); | ||
| 57 | comptime try testUnknownLenPtr(); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn testUnknownLenPtr() !void { | ||
| 61 | const u32_ptr_info = @typeInfo([*]const volatile f64); | ||
| 62 | try expect(u32_ptr_info == .Pointer); | ||
| 63 | try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); | ||
| 64 | try expect(u32_ptr_info.Pointer.is_const == true); | ||
| 65 | try expect(u32_ptr_info.Pointer.is_volatile == true); | ||
| 66 | try expect(u32_ptr_info.Pointer.sentinel == null); | ||
| 67 | try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64)); | ||
| 68 | try expect(u32_ptr_info.Pointer.child == f64); | ||
| 69 | } | ||
| 70 | |||
| 71 | test "type info: null terminated pointer type info" { | ||
| 72 | try testNullTerminatedPtr(); | ||
| 73 | comptime try testNullTerminatedPtr(); | ||
| 74 | } | ||
| 75 | |||
| 76 | fn testNullTerminatedPtr() !void { | ||
| 77 | const ptr_info = @typeInfo([*:0]u8); | ||
| 78 | try expect(ptr_info == .Pointer); | ||
| 79 | try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); | ||
| 80 | try expect(ptr_info.Pointer.is_const == false); | ||
| 81 | try expect(ptr_info.Pointer.is_volatile == false); | ||
| 82 | try expect(ptr_info.Pointer.sentinel.? == 0); | ||
| 83 | |||
| 84 | try expect(@typeInfo([:0]u8).Pointer.sentinel != null); | ||
| 85 | } | ||
| 86 | |||
| 87 | test "type info: C pointer type info" { | ||
| 88 | try testCPtr(); | ||
| 89 | comptime try testCPtr(); | ||
| 90 | } | ||
| 91 | |||
| 92 | fn testCPtr() !void { | ||
| 93 | const ptr_info = @typeInfo([*c]align(4) const i8); | ||
| 94 | try expect(ptr_info == .Pointer); | ||
| 95 | try expect(ptr_info.Pointer.size == .C); | ||
| 96 | try expect(ptr_info.Pointer.is_const); | ||
| 97 | try expect(!ptr_info.Pointer.is_volatile); | ||
| 98 | try expect(ptr_info.Pointer.alignment == 4); | ||
| 99 | try expect(ptr_info.Pointer.child == i8); | ||
| 100 | } | ||
| 101 | |||
| 102 | test "type info: slice type info" { | ||
| 103 | try testSlice(); | ||
| 104 | comptime try testSlice(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn testSlice() !void { | ||
| 108 | const u32_slice_info = @typeInfo([]u32); | ||
| 109 | try expect(u32_slice_info == .Pointer); | ||
| 110 | try expect(u32_slice_info.Pointer.size == .Slice); | ||
| 111 | try expect(u32_slice_info.Pointer.is_const == false); | ||
| 112 | try expect(u32_slice_info.Pointer.is_volatile == false); | ||
| 113 | try expect(u32_slice_info.Pointer.alignment == 4); | ||
| 114 | try expect(u32_slice_info.Pointer.child == u32); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "type info: array type info" { | ||
| 118 | try testArray(); | ||
| 119 | comptime try testArray(); | ||
| 120 | } | ||
| 121 | |||
| 122 | fn testArray() !void { | ||
| 123 | { | ||
| 124 | const info = @typeInfo([42]u8); | ||
| 125 | try expect(info == .Array); | ||
| 126 | try expect(info.Array.len == 42); | ||
| 127 | try expect(info.Array.child == u8); | ||
| 128 | try expect(info.Array.sentinel == null); | ||
| 129 | } | ||
| 130 | |||
| 131 | { | ||
| 132 | const info = @typeInfo([10:0]u8); | ||
| 133 | try expect(info.Array.len == 10); | ||
| 134 | try expect(info.Array.child == u8); | ||
| 135 | try expect(info.Array.sentinel.? == @as(u8, 0)); | ||
| 136 | try expect(@sizeOf([10:0]u8) == info.Array.len + 1); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | test "type info: optional type info" { | ||
| 141 | try testOptional(); | ||
| 142 | comptime try testOptional(); | ||
| 143 | } | ||
| 144 | |||
| 145 | fn testOptional() !void { | ||
| 146 | const null_info = @typeInfo(?void); | ||
| 147 | try expect(null_info == .Optional); | ||
| 148 | try expect(null_info.Optional.child == void); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "type info: error set, error union info" { | ||
| 152 | try testErrorSet(); | ||
| 153 | comptime try testErrorSet(); | ||
| 154 | } | ||
| 155 | |||
| 156 | fn testErrorSet() !void { | ||
| 157 | const TestErrorSet = error{ | ||
| 158 | First, | ||
| 159 | Second, | ||
| 160 | Third, | ||
| 161 | }; | ||
| 162 | |||
| 163 | const error_set_info = @typeInfo(TestErrorSet); | ||
| 164 | try expect(error_set_info == .ErrorSet); | ||
| 165 | try expect(error_set_info.ErrorSet.?.len == 3); | ||
| 166 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First")); | ||
| 167 | |||
| 168 | const error_union_info = @typeInfo(TestErrorSet!usize); | ||
| 169 | try expect(error_union_info == .ErrorUnion); | ||
| 170 | try expect(error_union_info.ErrorUnion.error_set == TestErrorSet); | ||
| 171 | try expect(error_union_info.ErrorUnion.payload == usize); | ||
| 172 | |||
| 173 | const global_info = @typeInfo(anyerror); | ||
| 174 | try expect(global_info == .ErrorSet); | ||
| 175 | try expect(global_info.ErrorSet == null); | ||
| 176 | } | ||
| 177 | |||
| 178 | test "type info: enum info" { | ||
| 179 | try testEnum(); | ||
| 180 | comptime try testEnum(); | ||
| 181 | } | ||
| 182 | |||
| 183 | fn testEnum() !void { | ||
| 184 | const Os = enum { | ||
| 185 | Windows, | ||
| 186 | Macos, | ||
| 187 | Linux, | ||
| 188 | FreeBSD, | ||
| 189 | }; | ||
| 190 | |||
| 191 | const os_info = @typeInfo(Os); | ||
| 192 | try expect(os_info == .Enum); | ||
| 193 | try expect(os_info.Enum.layout == .Auto); | ||
| 194 | try expect(os_info.Enum.fields.len == 4); | ||
| 195 | try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); | ||
| 196 | try expect(os_info.Enum.fields[3].value == 3); | ||
| 197 | try expect(os_info.Enum.tag_type == u2); | ||
| 198 | try expect(os_info.Enum.decls.len == 0); | ||
| 199 | } | ||
| 200 | |||
| 201 | test "type info: union info" { | ||
| 202 | try testUnion(); | ||
| 203 | comptime try testUnion(); | ||
| 204 | } | ||
| 205 | |||
| 206 | fn testUnion() !void { | ||
| 207 | const typeinfo_info = @typeInfo(TypeInfo); | ||
| 208 | try expect(typeinfo_info == .Union); | ||
| 209 | try expect(typeinfo_info.Union.layout == .Auto); | ||
| 210 | try expect(typeinfo_info.Union.tag_type.? == TypeId); | ||
| 211 | try expect(typeinfo_info.Union.fields.len == 25); | ||
| 212 | try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); | ||
| 213 | try expect(typeinfo_info.Union.decls.len == 22); | ||
| 214 | |||
| 215 | const TestNoTagUnion = union { | ||
| 216 | Foo: void, | ||
| 217 | Bar: u32, | ||
| 218 | }; | ||
| 219 | |||
| 220 | const notag_union_info = @typeInfo(TestNoTagUnion); | ||
| 221 | try expect(notag_union_info == .Union); | ||
| 222 | try expect(notag_union_info.Union.tag_type == null); | ||
| 223 | try expect(notag_union_info.Union.layout == .Auto); | ||
| 224 | try expect(notag_union_info.Union.fields.len == 2); | ||
| 225 | try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void)); | ||
| 226 | try expect(notag_union_info.Union.fields[1].field_type == u32); | ||
| 227 | try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32)); | ||
| 228 | |||
| 229 | const TestExternUnion = extern union { | ||
| 230 | foo: *c_void, | ||
| 231 | }; | ||
| 232 | |||
| 233 | const extern_union_info = @typeInfo(TestExternUnion); | ||
| 234 | try expect(extern_union_info.Union.layout == .Extern); | ||
| 235 | try expect(extern_union_info.Union.tag_type == null); | ||
| 236 | try expect(extern_union_info.Union.fields[0].field_type == *c_void); | ||
| 237 | } | ||
| 238 | |||
| 239 | test "type info: struct info" { | ||
| 240 | try testStruct(); | ||
| 241 | comptime try testStruct(); | ||
| 242 | } | ||
| 243 | |||
| 244 | fn testStruct() !void { | ||
| 245 | const unpacked_struct_info = @typeInfo(TestUnpackedStruct); | ||
| 246 | try expect(unpacked_struct_info.Struct.is_tuple == false); | ||
| 247 | try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32)); | ||
| 248 | try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4); | ||
| 249 | try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?); | ||
| 250 | |||
| 251 | const struct_info = @typeInfo(TestStruct); | ||
| 252 | try expect(struct_info == .Struct); | ||
| 253 | try expect(struct_info.Struct.is_tuple == false); | ||
| 254 | try expect(struct_info.Struct.layout == .Packed); | ||
| 255 | try expect(struct_info.Struct.fields.len == 4); | ||
| 256 | try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize)); | ||
| 257 | try expect(struct_info.Struct.fields[2].field_type == *TestStruct); | ||
| 258 | try expect(struct_info.Struct.fields[2].default_value == null); | ||
| 259 | try expect(struct_info.Struct.fields[3].default_value.? == 4); | ||
| 260 | try expect(struct_info.Struct.fields[3].alignment == 1); | ||
| 261 | try expect(struct_info.Struct.decls.len == 2); | ||
| 262 | try expect(struct_info.Struct.decls[0].is_pub); | ||
| 263 | try expect(!struct_info.Struct.decls[0].data.Fn.is_extern); | ||
| 264 | try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null); | ||
| 265 | try expect(struct_info.Struct.decls[0].data.Fn.return_type == void); | ||
| 266 | try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void); | ||
| 267 | } | ||
| 268 | |||
| 269 | const TestUnpackedStruct = struct { | ||
| 270 | fieldA: u32 = 4, | ||
| 271 | fieldB: *const [6:0]u8 = "foobar", | ||
| 272 | }; | ||
| 273 | |||
| 274 | const TestStruct = packed struct { | ||
| 275 | fieldA: usize align(2 * @alignOf(usize)), | ||
| 276 | fieldB: void, | ||
| 277 | fieldC: *Self, | ||
| 278 | fieldD: u32 = 4, | ||
| 279 | |||
| 280 | pub fn foo(self: *const Self) void {} | ||
| 281 | const Self = @This(); | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "type info: opaque info" { | ||
| 285 | try testOpaque(); | ||
| 286 | comptime try testOpaque(); | ||
| 287 | } | ||
| 288 | |||
| 289 | fn testOpaque() !void { | ||
| 290 | const Foo = opaque { | ||
| 291 | const A = 1; | ||
| 292 | fn b() void {} | ||
| 293 | }; | ||
| 294 | |||
| 295 | const foo_info = @typeInfo(Foo); | ||
| 296 | try expect(foo_info.Opaque.decls.len == 2); | ||
| 297 | } | ||
| 298 | |||
| 299 | test "type info: function type info" { | ||
| 300 | // wasm doesn't support align attributes on functions | ||
| 301 | if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest; | ||
| 302 | try testFunction(); | ||
| 303 | comptime try testFunction(); | ||
| 304 | } | ||
| 305 | |||
| 306 | fn testFunction() !void { | ||
| 307 | const fn_info = @typeInfo(@TypeOf(foo)); | ||
| 308 | try expect(fn_info == .Fn); | ||
| 309 | try expect(fn_info.Fn.alignment > 0); | ||
| 310 | try expect(fn_info.Fn.calling_convention == .C); | ||
| 311 | try expect(!fn_info.Fn.is_generic); | ||
| 312 | try expect(fn_info.Fn.args.len == 2); | ||
| 313 | try expect(fn_info.Fn.is_var_args); | ||
| 314 | try expect(fn_info.Fn.return_type.? == usize); | ||
| 315 | const fn_aligned_info = @typeInfo(@TypeOf(fooAligned)); | ||
| 316 | try expect(fn_aligned_info.Fn.alignment == 4); | ||
| 317 | |||
| 318 | const test_instance: TestStruct = undefined; | ||
| 319 | const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo)); | ||
| 320 | try expect(bound_fn_info == .BoundFn); | ||
| 321 | try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); | ||
| 322 | } | ||
| 323 | |||
| 324 | extern fn foo(a: usize, b: bool, ...) callconv(.C) usize; | ||
| 325 | extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize; | ||
| 326 | |||
| 327 | test "typeInfo with comptime parameter in struct fn def" { | ||
| 328 | const S = struct { | ||
| 329 | pub fn func(comptime x: f32) void {} | ||
| 330 | }; | ||
| 331 | comptime var info = @typeInfo(S); | ||
| 332 | } | ||
| 333 | |||
| 334 | test "type info: vectors" { | ||
| 335 | try testVector(); | ||
| 336 | comptime try testVector(); | ||
| 337 | } | ||
| 338 | |||
| 339 | fn testVector() !void { | ||
| 340 | const vec_info = @typeInfo(std.meta.Vector(4, i32)); | ||
| 341 | try expect(vec_info == .Vector); | ||
| 342 | try expect(vec_info.Vector.len == 4); | ||
| 343 | try expect(vec_info.Vector.child == i32); | ||
| 344 | } | ||
| 345 | |||
| 346 | test "type info: anyframe and anyframe->T" { | ||
| 347 | try testAnyFrame(); | ||
| 348 | comptime try testAnyFrame(); | ||
| 349 | } | ||
| 350 | |||
| 351 | fn testAnyFrame() !void { | ||
| 352 | { | ||
| 353 | const anyframe_info = @typeInfo(anyframe->i32); | ||
| 354 | try expect(anyframe_info == .AnyFrame); | ||
| 355 | try expect(anyframe_info.AnyFrame.child.? == i32); | ||
| 356 | } | ||
| 357 | |||
| 358 | { | ||
| 359 | const anyframe_info = @typeInfo(anyframe); | ||
| 360 | try expect(anyframe_info == .AnyFrame); | ||
| 361 | try expect(anyframe_info.AnyFrame.child == null); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | test "type info: pass to function" { | ||
| 366 | _ = passTypeInfo(@typeInfo(void)); | ||
| 367 | _ = comptime passTypeInfo(@typeInfo(void)); | ||
| 368 | } | ||
| 369 | |||
| 370 | fn passTypeInfo(comptime info: TypeInfo) type { | ||
| 371 | return void; | ||
| 372 | } | ||
| 373 | |||
| 374 | test "type info: TypeId -> TypeInfo impl cast" { | ||
| 375 | _ = passTypeInfo(TypeId.Void); | ||
| 376 | _ = comptime passTypeInfo(TypeId.Void); | ||
| 377 | } | ||
| 378 | |||
| 379 | test "type info: extern fns with and without lib names" { | ||
| 380 | const S = struct { | ||
| 381 | extern fn bar1() void; | ||
| 382 | extern "cool" fn bar2() void; | ||
| 383 | }; | ||
| 384 | const info = @typeInfo(S); | ||
| 385 | comptime { | ||
| 386 | for (info.Struct.decls) |decl| { | ||
| 387 | if (std.mem.eql(u8, decl.name, "bar1")) { | ||
| 388 | try expect(decl.data.Fn.lib_name == null); | ||
| 389 | } else { | ||
| 390 | try expectEqualStrings("cool", decl.data.Fn.lib_name.?); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | test "data field is a compile-time value" { | ||
| 397 | const S = struct { | ||
| 398 | const Bar = @as(isize, -1); | ||
| 399 | }; | ||
| 400 | comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize); | ||
| 401 | } | ||
| 402 | |||
| 403 | test "sentinel of opaque pointer type" { | ||
| 404 | const c_void_info = @typeInfo(*c_void); | ||
| 405 | try expect(c_void_info.Pointer.sentinel == null); | ||
| 406 | } | ||
| 407 | |||
| 408 | test "@typeInfo does not force declarations into existence" { | ||
| 409 | const S = struct { | ||
| 410 | x: i32, | ||
| 411 | |||
| 412 | fn doNotReferenceMe() void { | ||
| 413 | @compileError("test failed"); | ||
| 414 | } | ||
| 415 | }; | ||
| 416 | comptime try expect(@typeInfo(S).Struct.fields.len == 1); | ||
| 417 | } | ||
| 418 | |||
| 419 | test "defaut value for a var-typed field" { | ||
| 420 | const S = struct { x: anytype }; | ||
| 421 | try expect(@typeInfo(S).Struct.fields[0].default_value == null); | ||
| 422 | } | ||
| 423 | |||
| 424 | fn add(a: i32, b: i32) i32 { | ||
| 425 | return a + b; | ||
| 426 | } | ||
| 427 | |||
| 428 | test "type info for async frames" { | ||
| 429 | switch (@typeInfo(@Frame(add))) { | ||
| 430 | .Frame => |frame| { | ||
| 431 | try expect(frame.function == add); | ||
| 432 | }, | ||
| 433 | else => unreachable, | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | test "type info: value is correctly copied" { | ||
| 438 | comptime { | ||
| 439 | var ptrInfo = @typeInfo([]u32); | ||
| 440 | ptrInfo.Pointer.size = .One; | ||
| 441 | try expect(@typeInfo([]u32).Pointer.size == .Slice); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | test "Declarations are returned in declaration order" { | ||
| 446 | const S = struct { | ||
| 447 | const a = 1; | ||
| 448 | const b = 2; | ||
| 449 | const c = 3; | ||
| 450 | const d = 4; | ||
| 451 | const e = 5; | ||
| 452 | }; | ||
| 453 | const d = @typeInfo(S).Struct.decls; | ||
| 454 | try expect(std.mem.eql(u8, d[0].name, "a")); | ||
| 455 | try expect(std.mem.eql(u8, d[1].name, "b")); | ||
| 456 | try expect(std.mem.eql(u8, d[2].name, "c")); | ||
| 457 | try expect(std.mem.eql(u8, d[3].name, "d")); | ||
| 458 | try expect(std.mem.eql(u8, d[4].name, "e")); | ||
| 459 | } | ||
| 460 | |||
| 461 | test "Struct.is_tuple" { | ||
| 462 | try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple); | ||
| 463 | try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple); | ||
| 464 | } | ||
| 465 | |||
| 466 | test "StructField.is_comptime" { | ||
| 467 | const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct; | ||
| 468 | try expect(!info.fields[0].is_comptime); | ||
| 469 | try expect(info.fields[1].is_comptime); | ||
| 470 | } | ||
| 471 | |||
| 472 | test "typeInfo resolves usingnamespace declarations" { | ||
| 473 | const A = struct { | ||
| 474 | pub const f1 = 42; | ||
| 475 | }; | ||
| 476 | |||
| 477 | const B = struct { | ||
| 478 | const f0 = 42; | ||
| 479 | usingnamespace A; | ||
| 480 | }; | ||
| 481 | |||
| 482 | try expect(@typeInfo(B).Struct.decls.len == 2); | ||
| 483 | //a | ||
| 484 | } | ||
test/stage1/behavior/typename.zig deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | |||
| 5 | test "slice" { | ||
| 6 | try expectEqualSlices(u8, "[]u8", @typeName([]u8)); | ||
| 7 | } | ||
test/stage1/behavior/undefined.zig deleted-69| ... | @@ -1,69 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | fn initStaticArray() [10]i32 { | ||
| 6 | var array: [10]i32 = undefined; | ||
| 7 | array[0] = 1; | ||
| 8 | array[4] = 2; | ||
| 9 | array[7] = 3; | ||
| 10 | array[9] = 4; | ||
| 11 | return array; | ||
| 12 | } | ||
| 13 | const static_array = initStaticArray(); | ||
| 14 | test "init static array to undefined" { | ||
| 15 | try expect(static_array[0] == 1); | ||
| 16 | try expect(static_array[4] == 2); | ||
| 17 | try expect(static_array[7] == 3); | ||
| 18 | try expect(static_array[9] == 4); | ||
| 19 | |||
| 20 | comptime { | ||
| 21 | try expect(static_array[0] == 1); | ||
| 22 | try expect(static_array[4] == 2); | ||
| 23 | try expect(static_array[7] == 3); | ||
| 24 | try expect(static_array[9] == 4); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | const Foo = struct { | ||
| 29 | x: i32, | ||
| 30 | |||
| 31 | fn setFooXMethod(foo: *Foo) void { | ||
| 32 | foo.x = 3; | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | fn setFooX(foo: *Foo) void { | ||
| 37 | foo.x = 2; | ||
| 38 | } | ||
| 39 | |||
| 40 | test "assign undefined to struct" { | ||
| 41 | comptime { | ||
| 42 | var foo: Foo = undefined; | ||
| 43 | setFooX(&foo); | ||
| 44 | try expect(foo.x == 2); | ||
| 45 | } | ||
| 46 | { | ||
| 47 | var foo: Foo = undefined; | ||
| 48 | setFooX(&foo); | ||
| 49 | try expect(foo.x == 2); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | test "assign undefined to struct with method" { | ||
| 54 | comptime { | ||
| 55 | var foo: Foo = undefined; | ||
| 56 | foo.setFooXMethod(); | ||
| 57 | try expect(foo.x == 3); | ||
| 58 | } | ||
| 59 | { | ||
| 60 | var foo: Foo = undefined; | ||
| 61 | foo.setFooXMethod(); | ||
| 62 | try expect(foo.x == 3); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | test "type name of undefined" { | ||
| 67 | const x = undefined; | ||
| 68 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)")); | ||
| 69 | } | ||
test/stage1/behavior/underscore.zig deleted-28| ... | @@ -1,28 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "ignore lval with underscore" { | ||
| 5 | _ = false; | ||
| 6 | } | ||
| 7 | |||
| 8 | test "ignore lval with underscore (for loop)" { | ||
| 9 | for ([_]void{}) |_, i| { | ||
| 10 | for ([_]void{}) |_, j| { | ||
| 11 | break; | ||
| 12 | } | ||
| 13 | break; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | test "ignore lval with underscore (while loop)" { | ||
| 18 | while (optionalReturnError()) |_| { | ||
| 19 | while (optionalReturnError()) |_| { | ||
| 20 | break; | ||
| 21 | } else |_| {} | ||
| 22 | break; | ||
| 23 | } else |_| {} | ||
| 24 | } | ||
| 25 | |||
| 26 | fn optionalReturnError() !?u32 { | ||
| 27 | return error.optionalReturnError; | ||
| 28 | } | ||
test/stage1/behavior/union.zig deleted-806| ... | @@ -1,806 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const Tag = std.meta.Tag; | ||
| 5 | |||
| 6 | const Value = union(enum) { | ||
| 7 | Int: u64, | ||
| 8 | Array: [9]u8, | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Agg = struct { | ||
| 12 | val1: Value, | ||
| 13 | val2: Value, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const v1 = Value{ .Int = 1234 }; | ||
| 17 | const v2 = Value{ .Array = [_]u8{3} ** 9 }; | ||
| 18 | |||
| 19 | const err = @as(anyerror!Agg, Agg{ | ||
| 20 | .val1 = v1, | ||
| 21 | .val2 = v2, | ||
| 22 | }); | ||
| 23 | |||
| 24 | const array = [_]Value{ | ||
| 25 | v1, | ||
| 26 | v2, | ||
| 27 | v1, | ||
| 28 | v2, | ||
| 29 | }; | ||
| 30 | |||
| 31 | test "unions embedded in aggregate types" { | ||
| 32 | switch (array[1]) { | ||
| 33 | Value.Array => |arr| try expect(arr[4] == 3), | ||
| 34 | else => unreachable, | ||
| 35 | } | ||
| 36 | switch ((err catch unreachable).val1) { | ||
| 37 | Value.Int => |x| try expect(x == 1234), | ||
| 38 | else => unreachable, | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | const Foo = union { | ||
| 43 | float: f64, | ||
| 44 | int: i32, | ||
| 45 | }; | ||
| 46 | |||
| 47 | test "basic unions" { | ||
| 48 | var foo = Foo{ .int = 1 }; | ||
| 49 | try expect(foo.int == 1); | ||
| 50 | foo = Foo{ .float = 12.34 }; | ||
| 51 | try expect(foo.float == 12.34); | ||
| 52 | } | ||
| 53 | |||
| 54 | test "comptime union field access" { | ||
| 55 | comptime { | ||
| 56 | var foo = Foo{ .int = 0 }; | ||
| 57 | try expect(foo.int == 0); | ||
| 58 | |||
| 59 | foo = Foo{ .float = 42.42 }; | ||
| 60 | try expect(foo.float == 42.42); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | test "init union with runtime value" { | ||
| 65 | var foo: Foo = undefined; | ||
| 66 | |||
| 67 | setFloat(&foo, 12.34); | ||
| 68 | try expect(foo.float == 12.34); | ||
| 69 | |||
| 70 | setInt(&foo, 42); | ||
| 71 | try expect(foo.int == 42); | ||
| 72 | } | ||
| 73 | |||
| 74 | fn setFloat(foo: *Foo, x: f64) void { | ||
| 75 | foo.* = Foo{ .float = x }; | ||
| 76 | } | ||
| 77 | |||
| 78 | fn setInt(foo: *Foo, x: i32) void { | ||
| 79 | foo.* = Foo{ .int = x }; | ||
| 80 | } | ||
| 81 | |||
| 82 | const FooExtern = extern union { | ||
| 83 | float: f64, | ||
| 84 | int: i32, | ||
| 85 | }; | ||
| 86 | |||
| 87 | test "basic extern unions" { | ||
| 88 | var foo = FooExtern{ .int = 1 }; | ||
| 89 | try expect(foo.int == 1); | ||
| 90 | foo.float = 12.34; | ||
| 91 | try expect(foo.float == 12.34); | ||
| 92 | } | ||
| 93 | |||
| 94 | const Letter = enum { | ||
| 95 | A, | ||
| 96 | B, | ||
| 97 | C, | ||
| 98 | }; | ||
| 99 | const Payload = union(Letter) { | ||
| 100 | A: i32, | ||
| 101 | B: f64, | ||
| 102 | C: bool, | ||
| 103 | }; | ||
| 104 | |||
| 105 | test "union with specified enum tag" { | ||
| 106 | try doTest(); | ||
| 107 | comptime try doTest(); | ||
| 108 | } | ||
| 109 | |||
| 110 | fn doTest() !void { | ||
| 111 | try expect((try bar(Payload{ .A = 1234 })) == -10); | ||
| 112 | } | ||
| 113 | |||
| 114 | fn bar(value: Payload) !i32 { | ||
| 115 | try expect(@as(Letter, value) == Letter.A); | ||
| 116 | return switch (value) { | ||
| 117 | Payload.A => |x| return x - 1244, | ||
| 118 | Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21, | ||
| 119 | Payload.C => |x| if (x) @as(i32, 30) else 31, | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | |||
| 123 | const MultipleChoice = union(enum(u32)) { | ||
| 124 | A = 20, | ||
| 125 | B = 40, | ||
| 126 | C = 60, | ||
| 127 | D = 1000, | ||
| 128 | }; | ||
| 129 | test "simple union(enum(u32))" { | ||
| 130 | var x = MultipleChoice.C; | ||
| 131 | try expect(x == MultipleChoice.C); | ||
| 132 | try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60); | ||
| 133 | } | ||
| 134 | |||
| 135 | const MultipleChoice2 = union(enum(u32)) { | ||
| 136 | Unspecified1: i32, | ||
| 137 | A: f32 = 20, | ||
| 138 | Unspecified2: void, | ||
| 139 | B: bool = 40, | ||
| 140 | Unspecified3: i32, | ||
| 141 | C: i8 = 60, | ||
| 142 | Unspecified4: void, | ||
| 143 | D: void = 1000, | ||
| 144 | Unspecified5: i32, | ||
| 145 | }; | ||
| 146 | |||
| 147 | test "union(enum(u32)) with specified and unspecified tag values" { | ||
| 148 | comptime try expect(Tag(Tag(MultipleChoice2)) == u32); | ||
| 149 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 150 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); | ||
| 151 | } | ||
| 152 | |||
| 153 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { | ||
| 154 | try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60); | ||
| 155 | try expect(1123 == switch (x) { | ||
| 156 | MultipleChoice2.A => 1, | ||
| 157 | MultipleChoice2.B => 2, | ||
| 158 | MultipleChoice2.C => |v| @as(i32, 1000) + v, | ||
| 159 | MultipleChoice2.D => 4, | ||
| 160 | MultipleChoice2.Unspecified1 => 5, | ||
| 161 | MultipleChoice2.Unspecified2 => 6, | ||
| 162 | MultipleChoice2.Unspecified3 => 7, | ||
| 163 | MultipleChoice2.Unspecified4 => 8, | ||
| 164 | MultipleChoice2.Unspecified5 => 9, | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | |||
| 168 | const ExternPtrOrInt = extern union { | ||
| 169 | ptr: *u8, | ||
| 170 | int: u64, | ||
| 171 | }; | ||
| 172 | test "extern union size" { | ||
| 173 | comptime try expect(@sizeOf(ExternPtrOrInt) == 8); | ||
| 174 | } | ||
| 175 | |||
| 176 | const PackedPtrOrInt = packed union { | ||
| 177 | ptr: *u8, | ||
| 178 | int: u64, | ||
| 179 | }; | ||
| 180 | test "extern union size" { | ||
| 181 | comptime try expect(@sizeOf(PackedPtrOrInt) == 8); | ||
| 182 | } | ||
| 183 | |||
| 184 | const ZeroBits = union { | ||
| 185 | OnlyField: void, | ||
| 186 | }; | ||
| 187 | test "union with only 1 field which is void should be zero bits" { | ||
| 188 | comptime try expect(@sizeOf(ZeroBits) == 0); | ||
| 189 | } | ||
| 190 | |||
| 191 | const TheTag = enum { | ||
| 192 | A, | ||
| 193 | B, | ||
| 194 | C, | ||
| 195 | }; | ||
| 196 | const TheUnion = union(TheTag) { | ||
| 197 | A: i32, | ||
| 198 | B: i32, | ||
| 199 | C: i32, | ||
| 200 | }; | ||
| 201 | test "union field access gives the enum values" { | ||
| 202 | try expect(TheUnion.A == TheTag.A); | ||
| 203 | try expect(TheUnion.B == TheTag.B); | ||
| 204 | try expect(TheUnion.C == TheTag.C); | ||
| 205 | } | ||
| 206 | |||
| 207 | test "cast union to tag type of union" { | ||
| 208 | try testCastUnionToTag(TheUnion{ .B = 1234 }); | ||
| 209 | comptime try testCastUnionToTag(TheUnion{ .B = 1234 }); | ||
| 210 | } | ||
| 211 | |||
| 212 | fn testCastUnionToTag(x: TheUnion) !void { | ||
| 213 | try expect(@as(TheTag, x) == TheTag.B); | ||
| 214 | } | ||
| 215 | |||
| 216 | test "cast tag type of union to union" { | ||
| 217 | var x: Value2 = Letter2.B; | ||
| 218 | try expect(@as(Letter2, x) == Letter2.B); | ||
| 219 | } | ||
| 220 | const Letter2 = enum { | ||
| 221 | A, | ||
| 222 | B, | ||
| 223 | C, | ||
| 224 | }; | ||
| 225 | const Value2 = union(Letter2) { | ||
| 226 | A: i32, | ||
| 227 | B, | ||
| 228 | C, | ||
| 229 | }; | ||
| 230 | |||
| 231 | test "implicit cast union to its tag type" { | ||
| 232 | var x: Value2 = Letter2.B; | ||
| 233 | try expect(x == Letter2.B); | ||
| 234 | try giveMeLetterB(x); | ||
| 235 | } | ||
| 236 | fn giveMeLetterB(x: Letter2) !void { | ||
| 237 | try expect(x == Value2.B); | ||
| 238 | } | ||
| 239 | |||
| 240 | pub const PackThis = union(enum) { | ||
| 241 | Invalid: bool, | ||
| 242 | StringLiteral: u2, | ||
| 243 | }; | ||
| 244 | |||
| 245 | test "constant packed union" { | ||
| 246 | try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); | ||
| 247 | } | ||
| 248 | |||
| 249 | fn testConstPackedUnion(expected_tokens: []const PackThis) !void { | ||
| 250 | try expect(expected_tokens[0].StringLiteral == 1); | ||
| 251 | } | ||
| 252 | |||
| 253 | test "switch on union with only 1 field" { | ||
| 254 | var r: PartialInst = undefined; | ||
| 255 | r = PartialInst.Compiled; | ||
| 256 | switch (r) { | ||
| 257 | PartialInst.Compiled => { | ||
| 258 | var z: PartialInstWithPayload = undefined; | ||
| 259 | z = PartialInstWithPayload{ .Compiled = 1234 }; | ||
| 260 | switch (z) { | ||
| 261 | PartialInstWithPayload.Compiled => |x| { | ||
| 262 | try expect(x == 1234); | ||
| 263 | return; | ||
| 264 | }, | ||
| 265 | } | ||
| 266 | }, | ||
| 267 | } | ||
| 268 | unreachable; | ||
| 269 | } | ||
| 270 | |||
| 271 | const PartialInst = union(enum) { | ||
| 272 | Compiled, | ||
| 273 | }; | ||
| 274 | |||
| 275 | const PartialInstWithPayload = union(enum) { | ||
| 276 | Compiled: i32, | ||
| 277 | }; | ||
| 278 | |||
| 279 | test "access a member of tagged union with conflicting enum tag name" { | ||
| 280 | const Bar = union(enum) { | ||
| 281 | A: A, | ||
| 282 | B: B, | ||
| 283 | |||
| 284 | const A = u8; | ||
| 285 | const B = void; | ||
| 286 | }; | ||
| 287 | |||
| 288 | comptime try expect(Bar.A == u8); | ||
| 289 | } | ||
| 290 | |||
| 291 | test "tagged union initialization with runtime void" { | ||
| 292 | try expect(testTaggedUnionInit({})); | ||
| 293 | } | ||
| 294 | |||
| 295 | const TaggedUnionWithAVoid = union(enum) { | ||
| 296 | A, | ||
| 297 | B: i32, | ||
| 298 | }; | ||
| 299 | |||
| 300 | fn testTaggedUnionInit(x: anytype) bool { | ||
| 301 | const y = TaggedUnionWithAVoid{ .A = x }; | ||
| 302 | return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A; | ||
| 303 | } | ||
| 304 | |||
| 305 | pub const UnionEnumNoPayloads = union(enum) { | ||
| 306 | A, | ||
| 307 | B, | ||
| 308 | }; | ||
| 309 | |||
| 310 | test "tagged union with no payloads" { | ||
| 311 | const a = UnionEnumNoPayloads{ .B = {} }; | ||
| 312 | switch (a) { | ||
| 313 | Tag(UnionEnumNoPayloads).A => @panic("wrong"), | ||
| 314 | Tag(UnionEnumNoPayloads).B => {}, | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | test "union with only 1 field casted to its enum type" { | ||
| 319 | const Literal = union(enum) { | ||
| 320 | Number: f64, | ||
| 321 | Bool: bool, | ||
| 322 | }; | ||
| 323 | |||
| 324 | const Expr = union(enum) { | ||
| 325 | Literal: Literal, | ||
| 326 | }; | ||
| 327 | |||
| 328 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 329 | const ExprTag = Tag(Expr); | ||
| 330 | comptime try expect(Tag(ExprTag) == u0); | ||
| 331 | var t = @as(ExprTag, e); | ||
| 332 | try expect(t == Expr.Literal); | ||
| 333 | } | ||
| 334 | |||
| 335 | test "union with only 1 field casted to its enum type which has enum value specified" { | ||
| 336 | const Literal = union(enum) { | ||
| 337 | Number: f64, | ||
| 338 | Bool: bool, | ||
| 339 | }; | ||
| 340 | |||
| 341 | const ExprTag = enum(comptime_int) { | ||
| 342 | Literal = 33, | ||
| 343 | }; | ||
| 344 | |||
| 345 | const Expr = union(ExprTag) { | ||
| 346 | Literal: Literal, | ||
| 347 | }; | ||
| 348 | |||
| 349 | var e = Expr{ .Literal = Literal{ .Bool = true } }; | ||
| 350 | comptime try expect(Tag(ExprTag) == comptime_int); | ||
| 351 | var t = @as(ExprTag, e); | ||
| 352 | try expect(t == Expr.Literal); | ||
| 353 | try expect(@enumToInt(t) == 33); | ||
| 354 | comptime try expect(@enumToInt(t) == 33); | ||
| 355 | } | ||
| 356 | |||
| 357 | test "@enumToInt works on unions" { | ||
| 358 | const Bar = union(enum) { | ||
| 359 | A: bool, | ||
| 360 | B: u8, | ||
| 361 | C, | ||
| 362 | }; | ||
| 363 | |||
| 364 | const a = Bar{ .A = true }; | ||
| 365 | var b = Bar{ .B = undefined }; | ||
| 366 | var c = Bar.C; | ||
| 367 | try expect(@enumToInt(a) == 0); | ||
| 368 | try expect(@enumToInt(b) == 1); | ||
| 369 | try expect(@enumToInt(c) == 2); | ||
| 370 | } | ||
| 371 | |||
| 372 | const Attribute = union(enum) { | ||
| 373 | A: bool, | ||
| 374 | B: u8, | ||
| 375 | }; | ||
| 376 | |||
| 377 | fn setAttribute(attr: Attribute) void {} | ||
| 378 | |||
| 379 | fn Setter(attr: Attribute) type { | ||
| 380 | return struct { | ||
| 381 | fn set() void { | ||
| 382 | setAttribute(attr); | ||
| 383 | } | ||
| 384 | }; | ||
| 385 | } | ||
| 386 | |||
| 387 | test "comptime union field value equality" { | ||
| 388 | const a0 = Setter(Attribute{ .A = false }); | ||
| 389 | const a1 = Setter(Attribute{ .A = true }); | ||
| 390 | const a2 = Setter(Attribute{ .A = false }); | ||
| 391 | |||
| 392 | const b0 = Setter(Attribute{ .B = 5 }); | ||
| 393 | const b1 = Setter(Attribute{ .B = 9 }); | ||
| 394 | const b2 = Setter(Attribute{ .B = 5 }); | ||
| 395 | |||
| 396 | try expect(a0 == a0); | ||
| 397 | try expect(a1 == a1); | ||
| 398 | try expect(a0 == a2); | ||
| 399 | |||
| 400 | try expect(b0 == b0); | ||
| 401 | try expect(b1 == b1); | ||
| 402 | try expect(b0 == b2); | ||
| 403 | |||
| 404 | try expect(a0 != b0); | ||
| 405 | try expect(a0 != a1); | ||
| 406 | try expect(b0 != b1); | ||
| 407 | } | ||
| 408 | |||
| 409 | test "return union init with void payload" { | ||
| 410 | const S = struct { | ||
| 411 | fn entry() !void { | ||
| 412 | try expect(func().state == State.one); | ||
| 413 | } | ||
| 414 | const Outer = union(enum) { | ||
| 415 | state: State, | ||
| 416 | }; | ||
| 417 | const State = union(enum) { | ||
| 418 | one: void, | ||
| 419 | two: u32, | ||
| 420 | }; | ||
| 421 | fn func() Outer { | ||
| 422 | return Outer{ .state = State{ .one = {} } }; | ||
| 423 | } | ||
| 424 | }; | ||
| 425 | try S.entry(); | ||
| 426 | comptime try S.entry(); | ||
| 427 | } | ||
| 428 | |||
| 429 | test "@unionInit can modify a union type" { | ||
| 430 | const UnionInitEnum = union(enum) { | ||
| 431 | Boolean: bool, | ||
| 432 | Byte: u8, | ||
| 433 | }; | ||
| 434 | |||
| 435 | var value: UnionInitEnum = undefined; | ||
| 436 | |||
| 437 | value = @unionInit(UnionInitEnum, "Boolean", true); | ||
| 438 | try expect(value.Boolean == true); | ||
| 439 | value.Boolean = false; | ||
| 440 | try expect(value.Boolean == false); | ||
| 441 | |||
| 442 | value = @unionInit(UnionInitEnum, "Byte", 2); | ||
| 443 | try expect(value.Byte == 2); | ||
| 444 | value.Byte = 3; | ||
| 445 | try expect(value.Byte == 3); | ||
| 446 | } | ||
| 447 | |||
| 448 | test "@unionInit can modify a pointer value" { | ||
| 449 | const UnionInitEnum = union(enum) { | ||
| 450 | Boolean: bool, | ||
| 451 | Byte: u8, | ||
| 452 | }; | ||
| 453 | |||
| 454 | var value: UnionInitEnum = undefined; | ||
| 455 | var value_ptr = &value; | ||
| 456 | |||
| 457 | value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true); | ||
| 458 | try expect(value.Boolean == true); | ||
| 459 | |||
| 460 | value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2); | ||
| 461 | try expect(value.Byte == 2); | ||
| 462 | } | ||
| 463 | |||
| 464 | test "union no tag with struct member" { | ||
| 465 | const Struct = struct {}; | ||
| 466 | const Union = union { | ||
| 467 | s: Struct, | ||
| 468 | pub fn foo(self: *@This()) void {} | ||
| 469 | }; | ||
| 470 | var u = Union{ .s = Struct{} }; | ||
| 471 | u.foo(); | ||
| 472 | } | ||
| 473 | |||
| 474 | fn testComparison() !void { | ||
| 475 | var x = Payload{ .A = 42 }; | ||
| 476 | try expect(x == .A); | ||
| 477 | try expect(x != .B); | ||
| 478 | try expect(x != .C); | ||
| 479 | try expect((x == .B) == false); | ||
| 480 | try expect((x == .C) == false); | ||
| 481 | try expect((x != .A) == false); | ||
| 482 | } | ||
| 483 | |||
| 484 | test "comparison between union and enum literal" { | ||
| 485 | try testComparison(); | ||
| 486 | comptime try testComparison(); | ||
| 487 | } | ||
| 488 | |||
| 489 | test "packed union generates correctly aligned LLVM type" { | ||
| 490 | const U = packed union { | ||
| 491 | f1: fn () error{TestUnexpectedResult}!void, | ||
| 492 | f2: u32, | ||
| 493 | }; | ||
| 494 | var foo = [_]U{ | ||
| 495 | U{ .f1 = doTest }, | ||
| 496 | U{ .f2 = 0 }, | ||
| 497 | }; | ||
| 498 | try foo[0].f1(); | ||
| 499 | } | ||
| 500 | |||
| 501 | test "union with one member defaults to u0 tag type" { | ||
| 502 | const U0 = union(enum) { | ||
| 503 | X: u32, | ||
| 504 | }; | ||
| 505 | comptime try expect(Tag(Tag(U0)) == u0); | ||
| 506 | } | ||
| 507 | |||
| 508 | test "union with comptime_int tag" { | ||
| 509 | const Union = union(enum(comptime_int)) { | ||
| 510 | X: u32, | ||
| 511 | Y: u16, | ||
| 512 | Z: u8, | ||
| 513 | }; | ||
| 514 | comptime try expect(Tag(Tag(Union)) == comptime_int); | ||
| 515 | } | ||
| 516 | |||
| 517 | test "extern union doesn't trigger field check at comptime" { | ||
| 518 | const U = extern union { | ||
| 519 | x: u32, | ||
| 520 | y: u8, | ||
| 521 | }; | ||
| 522 | |||
| 523 | const x = U{ .x = 0x55AAAA55 }; | ||
| 524 | comptime try expect(x.y == 0x55); | ||
| 525 | } | ||
| 526 | |||
| 527 | const Foo1 = union(enum) { | ||
| 528 | f: struct { | ||
| 529 | x: usize, | ||
| 530 | }, | ||
| 531 | }; | ||
| 532 | var glbl: Foo1 = undefined; | ||
| 533 | |||
| 534 | test "global union with single field is correctly initialized" { | ||
| 535 | glbl = Foo1{ | ||
| 536 | .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 }, | ||
| 537 | }; | ||
| 538 | try expect(glbl.f.x == 123); | ||
| 539 | } | ||
| 540 | |||
| 541 | pub const FooUnion = union(enum) { | ||
| 542 | U0: usize, | ||
| 543 | U1: u8, | ||
| 544 | }; | ||
| 545 | |||
| 546 | var glbl_array: [2]FooUnion = undefined; | ||
| 547 | |||
| 548 | test "initialize global array of union" { | ||
| 549 | glbl_array[1] = FooUnion{ .U1 = 2 }; | ||
| 550 | glbl_array[0] = FooUnion{ .U0 = 1 }; | ||
| 551 | try expect(glbl_array[0].U0 == 1); | ||
| 552 | try expect(glbl_array[1].U1 == 2); | ||
| 553 | } | ||
| 554 | |||
| 555 | test "anonymous union literal syntax" { | ||
| 556 | const S = struct { | ||
| 557 | const Number = union { | ||
| 558 | int: i32, | ||
| 559 | float: f64, | ||
| 560 | }; | ||
| 561 | |||
| 562 | fn doTheTest() !void { | ||
| 563 | var i: Number = .{ .int = 42 }; | ||
| 564 | var f = makeNumber(); | ||
| 565 | try expect(i.int == 42); | ||
| 566 | try expect(f.float == 12.34); | ||
| 567 | } | ||
| 568 | |||
| 569 | fn makeNumber() Number { | ||
| 570 | return .{ .float = 12.34 }; | ||
| 571 | } | ||
| 572 | }; | ||
| 573 | try S.doTheTest(); | ||
| 574 | comptime try S.doTheTest(); | ||
| 575 | } | ||
| 576 | |||
| 577 | test "update the tag value for zero-sized unions" { | ||
| 578 | const S = union(enum) { | ||
| 579 | U0: void, | ||
| 580 | U1: void, | ||
| 581 | }; | ||
| 582 | var x = S{ .U0 = {} }; | ||
| 583 | try expect(x == .U0); | ||
| 584 | x = S{ .U1 = {} }; | ||
| 585 | try expect(x == .U1); | ||
| 586 | } | ||
| 587 | |||
| 588 | test "function call result coerces from tagged union to the tag" { | ||
| 589 | const S = struct { | ||
| 590 | const Arch = union(enum) { | ||
| 591 | One, | ||
| 592 | Two: usize, | ||
| 593 | }; | ||
| 594 | |||
| 595 | const ArchTag = Tag(Arch); | ||
| 596 | |||
| 597 | fn doTheTest() !void { | ||
| 598 | var x: ArchTag = getArch1(); | ||
| 599 | try expect(x == .One); | ||
| 600 | |||
| 601 | var y: ArchTag = getArch2(); | ||
| 602 | try expect(y == .Two); | ||
| 603 | } | ||
| 604 | |||
| 605 | pub fn getArch1() Arch { | ||
| 606 | return .One; | ||
| 607 | } | ||
| 608 | |||
| 609 | pub fn getArch2() Arch { | ||
| 610 | return .{ .Two = 99 }; | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | try S.doTheTest(); | ||
| 614 | comptime try S.doTheTest(); | ||
| 615 | } | ||
| 616 | |||
| 617 | test "0-sized extern union definition" { | ||
| 618 | const U = extern union { | ||
| 619 | a: void, | ||
| 620 | const f = 1; | ||
| 621 | }; | ||
| 622 | |||
| 623 | try expect(U.f == 1); | ||
| 624 | } | ||
| 625 | |||
| 626 | test "union initializer generates padding only if needed" { | ||
| 627 | const U = union(enum) { | ||
| 628 | A: u24, | ||
| 629 | }; | ||
| 630 | |||
| 631 | var v = U{ .A = 532 }; | ||
| 632 | try expect(v.A == 532); | ||
| 633 | } | ||
| 634 | |||
| 635 | test "runtime tag name with single field" { | ||
| 636 | const U = union(enum) { | ||
| 637 | A: i32, | ||
| 638 | }; | ||
| 639 | |||
| 640 | var v = U{ .A = 42 }; | ||
| 641 | try expect(std.mem.eql(u8, @tagName(v), "A")); | ||
| 642 | } | ||
| 643 | |||
| 644 | test "cast from anonymous struct to union" { | ||
| 645 | const S = struct { | ||
| 646 | const U = union(enum) { | ||
| 647 | A: u32, | ||
| 648 | B: []const u8, | ||
| 649 | C: void, | ||
| 650 | }; | ||
| 651 | fn doTheTest() !void { | ||
| 652 | var y: u32 = 42; | ||
| 653 | const t0 = .{ .A = 123 }; | ||
| 654 | const t1 = .{ .B = "foo" }; | ||
| 655 | const t2 = .{ .C = {} }; | ||
| 656 | const t3 = .{ .A = y }; | ||
| 657 | const x0: U = t0; | ||
| 658 | var x1: U = t1; | ||
| 659 | const x2: U = t2; | ||
| 660 | var x3: U = t3; | ||
| 661 | try expect(x0.A == 123); | ||
| 662 | try expect(std.mem.eql(u8, x1.B, "foo")); | ||
| 663 | try expect(x2 == .C); | ||
| 664 | try expect(x3.A == y); | ||
| 665 | } | ||
| 666 | }; | ||
| 667 | try S.doTheTest(); | ||
| 668 | comptime try S.doTheTest(); | ||
| 669 | } | ||
| 670 | |||
| 671 | test "cast from pointer to anonymous struct to pointer to union" { | ||
| 672 | const S = struct { | ||
| 673 | const U = union(enum) { | ||
| 674 | A: u32, | ||
| 675 | B: []const u8, | ||
| 676 | C: void, | ||
| 677 | }; | ||
| 678 | fn doTheTest() !void { | ||
| 679 | var y: u32 = 42; | ||
| 680 | const t0 = &.{ .A = 123 }; | ||
| 681 | const t1 = &.{ .B = "foo" }; | ||
| 682 | const t2 = &.{ .C = {} }; | ||
| 683 | const t3 = &.{ .A = y }; | ||
| 684 | const x0: *const U = t0; | ||
| 685 | var x1: *const U = t1; | ||
| 686 | const x2: *const U = t2; | ||
| 687 | var x3: *const U = t3; | ||
| 688 | try expect(x0.A == 123); | ||
| 689 | try expect(std.mem.eql(u8, x1.B, "foo")); | ||
| 690 | try expect(x2.* == .C); | ||
| 691 | try expect(x3.A == y); | ||
| 692 | } | ||
| 693 | }; | ||
| 694 | try S.doTheTest(); | ||
| 695 | comptime try S.doTheTest(); | ||
| 696 | } | ||
| 697 | |||
| 698 | test "method call on an empty union" { | ||
| 699 | const S = struct { | ||
| 700 | const MyUnion = union(MyUnionTag) { | ||
| 701 | pub const MyUnionTag = enum { X1, X2 }; | ||
| 702 | X1: [0]u8, | ||
| 703 | X2: [0]u8, | ||
| 704 | |||
| 705 | pub fn useIt(self: *@This()) bool { | ||
| 706 | return true; | ||
| 707 | } | ||
| 708 | }; | ||
| 709 | |||
| 710 | fn doTheTest() !void { | ||
| 711 | var u = MyUnion{ .X1 = [0]u8{} }; | ||
| 712 | try expect(u.useIt()); | ||
| 713 | } | ||
| 714 | }; | ||
| 715 | try S.doTheTest(); | ||
| 716 | comptime try S.doTheTest(); | ||
| 717 | } | ||
| 718 | |||
| 719 | test "switching on non exhaustive union" { | ||
| 720 | const S = struct { | ||
| 721 | const E = enum(u8) { | ||
| 722 | a, | ||
| 723 | b, | ||
| 724 | _, | ||
| 725 | }; | ||
| 726 | const U = union(E) { | ||
| 727 | a: i32, | ||
| 728 | b: u32, | ||
| 729 | }; | ||
| 730 | fn doTheTest() !void { | ||
| 731 | var a = U{ .a = 2 }; | ||
| 732 | switch (a) { | ||
| 733 | .a => |val| try expect(val == 2), | ||
| 734 | .b => unreachable, | ||
| 735 | } | ||
| 736 | } | ||
| 737 | }; | ||
| 738 | try S.doTheTest(); | ||
| 739 | comptime try S.doTheTest(); | ||
| 740 | } | ||
| 741 | |||
| 742 | test "containers with single-field enums" { | ||
| 743 | const S = struct { | ||
| 744 | const A = union(enum) { f1 }; | ||
| 745 | const B = union(enum) { f1: void }; | ||
| 746 | const C = struct { a: A }; | ||
| 747 | const D = struct { a: B }; | ||
| 748 | |||
| 749 | fn doTheTest() !void { | ||
| 750 | var array1 = [1]A{A{ .f1 = {} }}; | ||
| 751 | var array2 = [1]B{B{ .f1 = {} }}; | ||
| 752 | try expect(array1[0] == .f1); | ||
| 753 | try expect(array2[0] == .f1); | ||
| 754 | |||
| 755 | var struct1 = C{ .a = A{ .f1 = {} } }; | ||
| 756 | var struct2 = D{ .a = B{ .f1 = {} } }; | ||
| 757 | try expect(struct1.a == .f1); | ||
| 758 | try expect(struct2.a == .f1); | ||
| 759 | } | ||
| 760 | }; | ||
| 761 | |||
| 762 | try S.doTheTest(); | ||
| 763 | comptime try S.doTheTest(); | ||
| 764 | } | ||
| 765 | |||
| 766 | test "@unionInit on union w/ tag but no fields" { | ||
| 767 | const S = struct { | ||
| 768 | const Type = enum(u8) { no_op = 105 }; | ||
| 769 | |||
| 770 | const Data = union(Type) { | ||
| 771 | no_op: void, | ||
| 772 | |||
| 773 | pub fn decode(buf: []const u8) Data { | ||
| 774 | return @unionInit(Data, "no_op", {}); | ||
| 775 | } | ||
| 776 | }; | ||
| 777 | |||
| 778 | comptime { | ||
| 779 | try expect(@sizeOf(Data) != 0); | ||
| 780 | } | ||
| 781 | |||
| 782 | fn doTheTest() !void { | ||
| 783 | var data: Data = .{ .no_op = .{} }; | ||
| 784 | var o = Data.decode(&[_]u8{}); | ||
| 785 | try expectEqual(Type.no_op, o); | ||
| 786 | } | ||
| 787 | }; | ||
| 788 | |||
| 789 | try S.doTheTest(); | ||
| 790 | comptime try S.doTheTest(); | ||
| 791 | } | ||
| 792 | |||
| 793 | test "union enum type gets a separate scope" { | ||
| 794 | const S = struct { | ||
| 795 | const U = union(enum) { | ||
| 796 | a: u8, | ||
| 797 | const foo = 1; | ||
| 798 | }; | ||
| 799 | |||
| 800 | fn doTheTest() !void { | ||
| 801 | try expect(!@hasDecl(Tag(U), "foo")); | ||
| 802 | } | ||
| 803 | }; | ||
| 804 | |||
| 805 | try S.doTheTest(); | ||
| 806 | } | ||
test/stage1/behavior/usingnamespace.zig deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | fn Foo(comptime T: type) type { | ||
| 4 | return struct { | ||
| 5 | usingnamespace T; | ||
| 6 | }; | ||
| 7 | } | ||
| 8 | |||
| 9 | test "usingnamespace inside a generic struct" { | ||
| 10 | const std2 = Foo(std); | ||
| 11 | const testing2 = Foo(std.testing); | ||
| 12 | try std2.testing.expect(true); | ||
| 13 | try testing2.expect(true); | ||
| 14 | } | ||
| 15 | |||
| 16 | usingnamespace struct { | ||
| 17 | pub const foo = 42; | ||
| 18 | }; | ||
| 19 | |||
| 20 | test "usingnamespace does not redeclare an imported variable" { | ||
| 21 | comptime try std.testing.expect(foo == 42); | ||
| 22 | } | ||
test/stage1/behavior/var_args.zig deleted-83| ... | @@ -1,83 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | fn add(args: anytype) i32 { | ||
| 4 | var sum = @as(i32, 0); | ||
| 5 | { | ||
| 6 | comptime var i: usize = 0; | ||
| 7 | inline while (i < args.len) : (i += 1) { | ||
| 8 | sum += args[i]; | ||
| 9 | } | ||
| 10 | } | ||
| 11 | return sum; | ||
| 12 | } | ||
| 13 | |||
| 14 | test "add arbitrary args" { | ||
| 15 | try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); | ||
| 16 | try expect(add(.{@as(i32, 1234)}) == 1234); | ||
| 17 | try expect(add(.{}) == 0); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn readFirstVarArg(args: anytype) void { | ||
| 21 | const value = args[0]; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "send void arg to var args" { | ||
| 25 | readFirstVarArg(.{{}}); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "pass args directly" { | ||
| 29 | try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); | ||
| 30 | try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234); | ||
| 31 | try expect(addSomeStuff(.{}) == 0); | ||
| 32 | } | ||
| 33 | |||
| 34 | fn addSomeStuff(args: anytype) i32 { | ||
| 35 | return add(args); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "runtime parameter before var args" { | ||
| 39 | try expect((try extraFn(10, .{})) == 0); | ||
| 40 | try expect((try extraFn(10, .{false})) == 1); | ||
| 41 | try expect((try extraFn(10, .{ false, true })) == 2); | ||
| 42 | |||
| 43 | comptime { | ||
| 44 | try expect((try extraFn(10, .{})) == 0); | ||
| 45 | try expect((try extraFn(10, .{false})) == 1); | ||
| 46 | try expect((try extraFn(10, .{ false, true })) == 2); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | fn extraFn(extra: u32, args: anytype) !usize { | ||
| 51 | if (args.len >= 1) { | ||
| 52 | try expect(args[0] == false); | ||
| 53 | } | ||
| 54 | if (args.len >= 2) { | ||
| 55 | try expect(args[1] == true); | ||
| 56 | } | ||
| 57 | return args.len; | ||
| 58 | } | ||
| 59 | |||
| 60 | const foos = [_]fn (anytype) bool{ | ||
| 61 | foo1, | ||
| 62 | foo2, | ||
| 63 | }; | ||
| 64 | |||
| 65 | fn foo1(args: anytype) bool { | ||
| 66 | return true; | ||
| 67 | } | ||
| 68 | fn foo2(args: anytype) bool { | ||
| 69 | return false; | ||
| 70 | } | ||
| 71 | |||
| 72 | test "array of var args functions" { | ||
| 73 | try expect(foos[0](.{})); | ||
| 74 | try expect(!foos[1](.{})); | ||
| 75 | } | ||
| 76 | |||
| 77 | test "pass zero length array to var args param" { | ||
| 78 | doNothingWithFirstArg(.{""}); | ||
| 79 | } | ||
| 80 | |||
| 81 | fn doNothingWithFirstArg(args: anytype) void { | ||
| 82 | const a = args[0]; | ||
| 83 | } | ||
test/stage1/behavior/vector.zig deleted-640| ... | @@ -1,640 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const math = std.math; | ||
| 5 | const expect = std.testing.expect; | ||
| 6 | const expectEqual = std.testing.expectEqual; | ||
| 7 | const expectApproxEqRel = std.testing.expectApproxEqRel; | ||
| 8 | const Vector = std.meta.Vector; | ||
| 9 | |||
| 10 | test "implicit cast vector to array - bool" { | ||
| 11 | const S = struct { | ||
| 12 | fn doTheTest() !void { | ||
| 13 | const a: Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 14 | const result_array: [4]bool = a; | ||
| 15 | try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false })); | ||
| 16 | } | ||
| 17 | }; | ||
| 18 | try S.doTheTest(); | ||
| 19 | comptime try S.doTheTest(); | ||
| 20 | } | ||
| 21 | |||
| 22 | test "vector wrap operators" { | ||
| 23 | const S = struct { | ||
| 24 | fn doTheTest() !void { | ||
| 25 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 26 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 27 | try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 })); | ||
| 28 | try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 })); | ||
| 29 | try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 })); | ||
| 30 | var z: Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 }; | ||
| 31 | try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 })); | ||
| 32 | } | ||
| 33 | }; | ||
| 34 | try S.doTheTest(); | ||
| 35 | comptime try S.doTheTest(); | ||
| 36 | } | ||
| 37 | |||
| 38 | test "vector bin compares with mem.eql" { | ||
| 39 | const S = struct { | ||
| 40 | fn doTheTest() !void { | ||
| 41 | var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 42 | var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 }; | ||
| 43 | try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false })); | ||
| 44 | try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true })); | ||
| 45 | try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false })); | ||
| 46 | try expect(mem.eql(bool, &@as([4]bool, v > x), &[4]bool{ true, false, false, true })); | ||
| 47 | try expect(mem.eql(bool, &@as([4]bool, v <= x), &[4]bool{ false, true, true, false })); | ||
| 48 | try expect(mem.eql(bool, &@as([4]bool, v >= x), &[4]bool{ true, false, true, true })); | ||
| 49 | } | ||
| 50 | }; | ||
| 51 | try S.doTheTest(); | ||
| 52 | comptime try S.doTheTest(); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "vector int operators" { | ||
| 56 | const S = struct { | ||
| 57 | fn doTheTest() !void { | ||
| 58 | var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; | ||
| 59 | var x: Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; | ||
| 60 | try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 })); | ||
| 61 | try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 })); | ||
| 62 | try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 })); | ||
| 63 | try expect(mem.eql(i32, &@as([4]i32, -v), &[4]i32{ -10, -20, -30, -40 })); | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | try S.doTheTest(); | ||
| 67 | comptime try S.doTheTest(); | ||
| 68 | } | ||
| 69 | |||
| 70 | test "vector float operators" { | ||
| 71 | const S = struct { | ||
| 72 | fn doTheTest() !void { | ||
| 73 | var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 }; | ||
| 74 | var x: Vector(4, f32) = [4]f32{ 1, 2, 3, 4 }; | ||
| 75 | try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 })); | ||
| 76 | try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 })); | ||
| 77 | try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 })); | ||
| 78 | try expect(mem.eql(f32, &@as([4]f32, -x), &[4]f32{ -1, -2, -3, -4 })); | ||
| 79 | } | ||
| 80 | }; | ||
| 81 | try S.doTheTest(); | ||
| 82 | comptime try S.doTheTest(); | ||
| 83 | } | ||
| 84 | |||
| 85 | test "vector bit operators" { | ||
| 86 | const S = struct { | ||
| 87 | fn doTheTest() !void { | ||
| 88 | var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 }; | ||
| 89 | var x: Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 }; | ||
| 90 | try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 })); | ||
| 91 | try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 })); | ||
| 92 | try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 })); | ||
| 93 | } | ||
| 94 | }; | ||
| 95 | try S.doTheTest(); | ||
| 96 | comptime try S.doTheTest(); | ||
| 97 | } | ||
| 98 | |||
| 99 | test "implicit cast vector to array" { | ||
| 100 | const S = struct { | ||
| 101 | fn doTheTest() !void { | ||
| 102 | var a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; | ||
| 103 | var result_array: [4]i32 = a; | ||
| 104 | result_array = a; | ||
| 105 | try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 })); | ||
| 106 | } | ||
| 107 | }; | ||
| 108 | try S.doTheTest(); | ||
| 109 | comptime try S.doTheTest(); | ||
| 110 | } | ||
| 111 | |||
| 112 | test "array to vector" { | ||
| 113 | var foo: f32 = 3.14; | ||
| 114 | var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; | ||
| 115 | var vec: Vector(4, f32) = arr; | ||
| 116 | } | ||
| 117 | |||
| 118 | test "vector casts of sizes not divisable by 8" { | ||
| 119 | // https://github.com/ziglang/zig/issues/3563 | ||
| 120 | if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest; | ||
| 121 | |||
| 122 | const S = struct { | ||
| 123 | fn doTheTest() !void { | ||
| 124 | { | ||
| 125 | var v: Vector(4, u3) = [4]u3{ 5, 2, 3, 0 }; | ||
| 126 | var x: [4]u3 = v; | ||
| 127 | try expect(mem.eql(u3, &x, &@as([4]u3, v))); | ||
| 128 | } | ||
| 129 | { | ||
| 130 | var v: Vector(4, u2) = [4]u2{ 1, 2, 3, 0 }; | ||
| 131 | var x: [4]u2 = v; | ||
| 132 | try expect(mem.eql(u2, &x, &@as([4]u2, v))); | ||
| 133 | } | ||
| 134 | { | ||
| 135 | var v: Vector(4, u1) = [4]u1{ 1, 0, 1, 0 }; | ||
| 136 | var x: [4]u1 = v; | ||
| 137 | try expect(mem.eql(u1, &x, &@as([4]u1, v))); | ||
| 138 | } | ||
| 139 | { | ||
| 140 | var v: Vector(4, bool) = [4]bool{ false, false, true, false }; | ||
| 141 | var x: [4]bool = v; | ||
| 142 | try expect(mem.eql(bool, &x, &@as([4]bool, v))); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | try S.doTheTest(); | ||
| 147 | comptime try S.doTheTest(); | ||
| 148 | } | ||
| 149 | |||
| 150 | test "vector @splat" { | ||
| 151 | const S = struct { | ||
| 152 | fn testForT(comptime N: comptime_int, v: anytype) !void { | ||
| 153 | const T = @TypeOf(v); | ||
| 154 | var vec = @splat(N, v); | ||
| 155 | try expectEqual(Vector(N, T), @TypeOf(vec)); | ||
| 156 | var as_array = @as([N]T, vec); | ||
| 157 | for (as_array) |elem| try expectEqual(v, elem); | ||
| 158 | } | ||
| 159 | fn doTheTest() !void { | ||
| 160 | // Splats with multiple-of-8 bit types that fill a 128bit vector. | ||
| 161 | try testForT(16, @as(u8, 0xEE)); | ||
| 162 | try testForT(8, @as(u16, 0xBEEF)); | ||
| 163 | try testForT(4, @as(u32, 0xDEADBEEF)); | ||
| 164 | try testForT(2, @as(u64, 0xCAFEF00DDEADBEEF)); | ||
| 165 | |||
| 166 | try testForT(8, @as(f16, 3.1415)); | ||
| 167 | try testForT(4, @as(f32, 3.1415)); | ||
| 168 | try testForT(2, @as(f64, 3.1415)); | ||
| 169 | |||
| 170 | // Same but fill more than 128 bits. | ||
| 171 | try testForT(16 * 2, @as(u8, 0xEE)); | ||
| 172 | try testForT(8 * 2, @as(u16, 0xBEEF)); | ||
| 173 | try testForT(4 * 2, @as(u32, 0xDEADBEEF)); | ||
| 174 | try testForT(2 * 2, @as(u64, 0xCAFEF00DDEADBEEF)); | ||
| 175 | |||
| 176 | try testForT(8 * 2, @as(f16, 3.1415)); | ||
| 177 | try testForT(4 * 2, @as(f32, 3.1415)); | ||
| 178 | try testForT(2 * 2, @as(f64, 3.1415)); | ||
| 179 | } | ||
| 180 | }; | ||
| 181 | try S.doTheTest(); | ||
| 182 | comptime try S.doTheTest(); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "load vector elements via comptime index" { | ||
| 186 | const S = struct { | ||
| 187 | fn doTheTest() !void { | ||
| 188 | var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | ||
| 189 | try expect(v[0] == 1); | ||
| 190 | try expect(v[1] == 2); | ||
| 191 | try expect(loadv(&v[2]) == 3); | ||
| 192 | } | ||
| 193 | fn loadv(ptr: anytype) i32 { | ||
| 194 | return ptr.*; | ||
| 195 | } | ||
| 196 | }; | ||
| 197 | |||
| 198 | try S.doTheTest(); | ||
| 199 | comptime try S.doTheTest(); | ||
| 200 | } | ||
| 201 | |||
| 202 | test "store vector elements via comptime index" { | ||
| 203 | const S = struct { | ||
| 204 | fn doTheTest() !void { | ||
| 205 | var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | ||
| 206 | |||
| 207 | v[2] = 42; | ||
| 208 | try expect(v[1] == 5); | ||
| 209 | v[3] = -364; | ||
| 210 | try expect(v[2] == 42); | ||
| 211 | try expect(-364 == v[3]); | ||
| 212 | |||
| 213 | storev(&v[0], 100); | ||
| 214 | try expect(v[0] == 100); | ||
| 215 | } | ||
| 216 | fn storev(ptr: anytype, x: i32) void { | ||
| 217 | ptr.* = x; | ||
| 218 | } | ||
| 219 | }; | ||
| 220 | |||
| 221 | try S.doTheTest(); | ||
| 222 | comptime try S.doTheTest(); | ||
| 223 | } | ||
| 224 | |||
| 225 | test "load vector elements via runtime index" { | ||
| 226 | const S = struct { | ||
| 227 | fn doTheTest() !void { | ||
| 228 | var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | ||
| 229 | var i: u32 = 0; | ||
| 230 | try expect(v[i] == 1); | ||
| 231 | i += 1; | ||
| 232 | try expect(v[i] == 2); | ||
| 233 | i += 1; | ||
| 234 | try expect(v[i] == 3); | ||
| 235 | } | ||
| 236 | }; | ||
| 237 | |||
| 238 | try S.doTheTest(); | ||
| 239 | comptime try S.doTheTest(); | ||
| 240 | } | ||
| 241 | |||
| 242 | test "store vector elements via runtime index" { | ||
| 243 | const S = struct { | ||
| 244 | fn doTheTest() !void { | ||
| 245 | var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | ||
| 246 | var i: u32 = 2; | ||
| 247 | v[i] = 1; | ||
| 248 | try expect(v[1] == 5); | ||
| 249 | try expect(v[2] == 1); | ||
| 250 | i += 1; | ||
| 251 | v[i] = -364; | ||
| 252 | try expect(-364 == v[3]); | ||
| 253 | } | ||
| 254 | }; | ||
| 255 | |||
| 256 | try S.doTheTest(); | ||
| 257 | comptime try S.doTheTest(); | ||
| 258 | } | ||
| 259 | |||
| 260 | test "initialize vector which is a struct field" { | ||
| 261 | const Vec4Obj = struct { | ||
| 262 | data: Vector(4, f32), | ||
| 263 | }; | ||
| 264 | |||
| 265 | const S = struct { | ||
| 266 | fn doTheTest() !void { | ||
| 267 | var foo = Vec4Obj{ | ||
| 268 | .data = [_]f32{ 1, 2, 3, 4 }, | ||
| 269 | }; | ||
| 270 | } | ||
| 271 | }; | ||
| 272 | try S.doTheTest(); | ||
| 273 | comptime try S.doTheTest(); | ||
| 274 | } | ||
| 275 | |||
| 276 | test "vector comparison operators" { | ||
| 277 | const S = struct { | ||
| 278 | fn doTheTest() !void { | ||
| 279 | { | ||
| 280 | const v1: Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 281 | const v2: Vector(4, bool) = [_]bool{ false, true, false, true }; | ||
| 282 | try expectEqual(@splat(4, true), v1 == v1); | ||
| 283 | try expectEqual(@splat(4, false), v1 == v2); | ||
| 284 | try expectEqual(@splat(4, true), v1 != v2); | ||
| 285 | try expectEqual(@splat(4, false), v2 != v2); | ||
| 286 | } | ||
| 287 | { | ||
| 288 | const v1 = @splat(4, @as(u32, 0xc0ffeeee)); | ||
| 289 | const v2: Vector(4, c_uint) = v1; | ||
| 290 | const v3 = @splat(4, @as(u32, 0xdeadbeef)); | ||
| 291 | try expectEqual(@splat(4, true), v1 == v2); | ||
| 292 | try expectEqual(@splat(4, false), v1 == v3); | ||
| 293 | try expectEqual(@splat(4, true), v1 != v3); | ||
| 294 | try expectEqual(@splat(4, false), v1 != v2); | ||
| 295 | } | ||
| 296 | { | ||
| 297 | // Comptime-known LHS/RHS | ||
| 298 | var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 }; | ||
| 299 | const v2 = @splat(4, @as(u32, 2)); | ||
| 300 | const v3: @Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 301 | try expectEqual(v3, v1 == v2); | ||
| 302 | try expectEqual(v3, v2 == v1); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | }; | ||
| 306 | try S.doTheTest(); | ||
| 307 | comptime try S.doTheTest(); | ||
| 308 | } | ||
| 309 | |||
| 310 | test "vector division operators" { | ||
| 311 | const S = struct { | ||
| 312 | fn doTheTestDiv(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void { | ||
| 313 | if (!comptime std.meta.trait.isSignedInt(T)) { | ||
| 314 | const d0 = x / y; | ||
| 315 | for (@as([4]T, d0)) |v, i| { | ||
| 316 | try expectEqual(x[i] / y[i], v); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | const d1 = @divExact(x, y); | ||
| 320 | for (@as([4]T, d1)) |v, i| { | ||
| 321 | try expectEqual(@divExact(x[i], y[i]), v); | ||
| 322 | } | ||
| 323 | const d2 = @divFloor(x, y); | ||
| 324 | for (@as([4]T, d2)) |v, i| { | ||
| 325 | try expectEqual(@divFloor(x[i], y[i]), v); | ||
| 326 | } | ||
| 327 | const d3 = @divTrunc(x, y); | ||
| 328 | for (@as([4]T, d3)) |v, i| { | ||
| 329 | try expectEqual(@divTrunc(x[i], y[i]), v); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | fn doTheTestMod(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void { | ||
| 334 | if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) { | ||
| 335 | const r0 = x % y; | ||
| 336 | for (@as([4]T, r0)) |v, i| { | ||
| 337 | try expectEqual(x[i] % y[i], v); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | const r1 = @mod(x, y); | ||
| 341 | for (@as([4]T, r1)) |v, i| { | ||
| 342 | try expectEqual(@mod(x[i], y[i]), v); | ||
| 343 | } | ||
| 344 | const r2 = @rem(x, y); | ||
| 345 | for (@as([4]T, r2)) |v, i| { | ||
| 346 | try expectEqual(@rem(x[i], y[i]), v); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | fn doTheTest() !void { | ||
| 351 | // https://github.com/ziglang/zig/issues/4952 | ||
| 352 | if (std.builtin.os.tag != .windows) { | ||
| 353 | try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 354 | } | ||
| 355 | |||
| 356 | try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 357 | try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 }); | ||
| 358 | |||
| 359 | // https://github.com/ziglang/zig/issues/4952 | ||
| 360 | if (std.builtin.os.tag != .windows) { | ||
| 361 | try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 362 | } | ||
| 363 | try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 364 | try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 }); | ||
| 365 | |||
| 366 | try doTheTestDiv(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, -1, -2 }); | ||
| 367 | try doTheTestDiv(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, -1, -2 }); | ||
| 368 | try doTheTestDiv(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, -1, -2 }); | ||
| 369 | try doTheTestDiv(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, -1, -2 }); | ||
| 370 | |||
| 371 | try doTheTestMod(i8, [4]i8{ 4, -4, 4, -4 }, [4]i8{ 1, 2, 4, 8 }); | ||
| 372 | try doTheTestMod(i16, [4]i16{ 4, -4, 4, -4 }, [4]i16{ 1, 2, 4, 8 }); | ||
| 373 | try doTheTestMod(i32, [4]i32{ 4, -4, 4, -4 }, [4]i32{ 1, 2, 4, 8 }); | ||
| 374 | try doTheTestMod(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 1, 2, 4, 8 }); | ||
| 375 | |||
| 376 | try doTheTestDiv(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); | ||
| 377 | try doTheTestDiv(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); | ||
| 378 | try doTheTestDiv(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); | ||
| 379 | try doTheTestDiv(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); | ||
| 380 | |||
| 381 | try doTheTestMod(u8, [4]u8{ 1, 2, 4, 8 }, [4]u8{ 1, 1, 2, 4 }); | ||
| 382 | try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); | ||
| 383 | try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); | ||
| 384 | try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); | ||
| 385 | } | ||
| 386 | }; | ||
| 387 | |||
| 388 | try S.doTheTest(); | ||
| 389 | comptime try S.doTheTest(); | ||
| 390 | } | ||
| 391 | |||
| 392 | test "vector bitwise not operator" { | ||
| 393 | const S = struct { | ||
| 394 | fn doTheTestNot(comptime T: type, x: Vector(4, T)) !void { | ||
| 395 | var y = ~x; | ||
| 396 | for (@as([4]T, y)) |v, i| { | ||
| 397 | try expectEqual(~x[i], v); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | fn doTheTest() !void { | ||
| 401 | try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); | ||
| 402 | try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); | ||
| 403 | try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); | ||
| 404 | try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); | ||
| 405 | |||
| 406 | try doTheTestNot(u8, [_]u8{ 0, 2, 4, 255 }); | ||
| 407 | try doTheTestNot(u16, [_]u16{ 0, 2, 4, 255 }); | ||
| 408 | try doTheTestNot(u32, [_]u32{ 0, 2, 4, 255 }); | ||
| 409 | try doTheTestNot(u64, [_]u64{ 0, 2, 4, 255 }); | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | |||
| 413 | try S.doTheTest(); | ||
| 414 | comptime try S.doTheTest(); | ||
| 415 | } | ||
| 416 | |||
| 417 | test "vector shift operators" { | ||
| 418 | // TODO investigate why this fails when cross-compiled to wasm. | ||
| 419 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 420 | |||
| 421 | const S = struct { | ||
| 422 | fn doTheTestShift(x: anytype, y: anytype) !void { | ||
| 423 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 424 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 425 | const TY = @typeInfo(@TypeOf(y)).Array.child; | ||
| 426 | |||
| 427 | var xv = @as(Vector(N, TX), x); | ||
| 428 | var yv = @as(Vector(N, TY), y); | ||
| 429 | |||
| 430 | var z0 = xv >> yv; | ||
| 431 | for (@as([N]TX, z0)) |v, i| { | ||
| 432 | try expectEqual(x[i] >> y[i], v); | ||
| 433 | } | ||
| 434 | var z1 = xv << yv; | ||
| 435 | for (@as([N]TX, z1)) |v, i| { | ||
| 436 | try expectEqual(x[i] << y[i], v); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void { | ||
| 440 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 441 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 442 | const TY = @typeInfo(@TypeOf(y)).Array.child; | ||
| 443 | |||
| 444 | var xv = @as(Vector(N, TX), x); | ||
| 445 | var yv = @as(Vector(N, TY), y); | ||
| 446 | |||
| 447 | var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv); | ||
| 448 | for (@as([N]TX, z)) |v, i| { | ||
| 449 | const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i]; | ||
| 450 | try expectEqual(check, v); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | fn doTheTest() !void { | ||
| 454 | try doTheTestShift([_]u8{ 0, 2, 4, math.maxInt(u8) }, [_]u3{ 2, 0, 2, 7 }); | ||
| 455 | try doTheTestShift([_]u16{ 0, 2, 4, math.maxInt(u16) }, [_]u4{ 2, 0, 2, 15 }); | ||
| 456 | try doTheTestShift([_]u24{ 0, 2, 4, math.maxInt(u24) }, [_]u5{ 2, 0, 2, 23 }); | ||
| 457 | try doTheTestShift([_]u32{ 0, 2, 4, math.maxInt(u32) }, [_]u5{ 2, 0, 2, 31 }); | ||
| 458 | try doTheTestShift([_]u64{ 0xfe, math.maxInt(u64) }, [_]u6{ 0, 63 }); | ||
| 459 | |||
| 460 | try doTheTestShift([_]i8{ 0, 2, 4, math.maxInt(i8) }, [_]u3{ 2, 0, 2, 7 }); | ||
| 461 | try doTheTestShift([_]i16{ 0, 2, 4, math.maxInt(i16) }, [_]u4{ 2, 0, 2, 7 }); | ||
| 462 | try doTheTestShift([_]i24{ 0, 2, 4, math.maxInt(i24) }, [_]u5{ 2, 0, 2, 7 }); | ||
| 463 | try doTheTestShift([_]i32{ 0, 2, 4, math.maxInt(i32) }, [_]u5{ 2, 0, 2, 7 }); | ||
| 464 | try doTheTestShift([_]i64{ 0xfe, math.maxInt(i64) }, [_]u6{ 0, 63 }); | ||
| 465 | |||
| 466 | try doTheTestShiftExact([_]u8{ 0, 1, 1 << 7, math.maxInt(u8) ^ 1 }, [_]u3{ 4, 0, 7, 1 }, .Right); | ||
| 467 | try doTheTestShiftExact([_]u16{ 0, 1, 1 << 15, math.maxInt(u16) ^ 1 }, [_]u4{ 4, 0, 15, 1 }, .Right); | ||
| 468 | try doTheTestShiftExact([_]u24{ 0, 1, 1 << 23, math.maxInt(u24) ^ 1 }, [_]u5{ 4, 0, 23, 1 }, .Right); | ||
| 469 | try doTheTestShiftExact([_]u32{ 0, 1, 1 << 31, math.maxInt(u32) ^ 1 }, [_]u5{ 4, 0, 31, 1 }, .Right); | ||
| 470 | try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 63, 0 }, .Right); | ||
| 471 | |||
| 472 | try doTheTestShiftExact([_]u8{ 0, 1, 1, math.maxInt(u8) ^ (1 << 7) }, [_]u3{ 4, 0, 7, 1 }, .Left); | ||
| 473 | try doTheTestShiftExact([_]u16{ 0, 1, 1, math.maxInt(u16) ^ (1 << 15) }, [_]u4{ 4, 0, 15, 1 }, .Left); | ||
| 474 | try doTheTestShiftExact([_]u24{ 0, 1, 1, math.maxInt(u24) ^ (1 << 23) }, [_]u5{ 4, 0, 23, 1 }, .Left); | ||
| 475 | try doTheTestShiftExact([_]u32{ 0, 1, 1, math.maxInt(u32) ^ (1 << 31) }, [_]u5{ 4, 0, 31, 1 }, .Left); | ||
| 476 | try doTheTestShiftExact([_]u64{ 1 << 63, 1 }, [_]u6{ 0, 63 }, .Left); | ||
| 477 | } | ||
| 478 | }; | ||
| 479 | |||
| 480 | switch (std.builtin.arch) { | ||
| 481 | .i386, | ||
| 482 | .aarch64, | ||
| 483 | .aarch64_be, | ||
| 484 | .aarch64_32, | ||
| 485 | .arm, | ||
| 486 | .armeb, | ||
| 487 | .thumb, | ||
| 488 | .thumbeb, | ||
| 489 | .mips, | ||
| 490 | .mipsel, | ||
| 491 | .mips64, | ||
| 492 | .mips64el, | ||
| 493 | .riscv64, | ||
| 494 | .sparcv9, | ||
| 495 | => { | ||
| 496 | // LLVM miscompiles on this architecture | ||
| 497 | // https://github.com/ziglang/zig/issues/4951 | ||
| 498 | return error.SkipZigTest; | ||
| 499 | }, | ||
| 500 | else => {}, | ||
| 501 | } | ||
| 502 | |||
| 503 | try S.doTheTest(); | ||
| 504 | comptime try S.doTheTest(); | ||
| 505 | } | ||
| 506 | |||
| 507 | test "vector reduce operation" { | ||
| 508 | const S = struct { | ||
| 509 | fn doTheTestReduce(comptime op: builtin.ReduceOp, x: anytype, expected: anytype) !void { | ||
| 510 | const N = @typeInfo(@TypeOf(x)).Array.len; | ||
| 511 | const TX = @typeInfo(@TypeOf(x)).Array.child; | ||
| 512 | |||
| 513 | var r = @reduce(op, @as(Vector(N, TX), x)); | ||
| 514 | switch (@typeInfo(TX)) { | ||
| 515 | .Int, .Bool => try expectEqual(expected, r), | ||
| 516 | .Float => { | ||
| 517 | const expected_nan = math.isNan(expected); | ||
| 518 | const got_nan = math.isNan(r); | ||
| 519 | |||
| 520 | if (expected_nan and got_nan) { | ||
| 521 | // Do this check explicitly as two NaN values are never | ||
| 522 | // equal. | ||
| 523 | } else { | ||
| 524 | try expectApproxEqRel(expected, r, math.sqrt(math.epsilon(TX))); | ||
| 525 | } | ||
| 526 | }, | ||
| 527 | else => unreachable, | ||
| 528 | } | ||
| 529 | } | ||
| 530 | fn doTheTest() !void { | ||
| 531 | try doTheTestReduce(.Add, [4]i16{ -9, -99, -999, -9999 }, @as(i32, -11106)); | ||
| 532 | try doTheTestReduce(.Add, [4]u16{ 9, 99, 999, 9999 }, @as(u32, 11106)); | ||
| 533 | try doTheTestReduce(.Add, [4]i32{ -9, -99, -999, -9999 }, @as(i32, -11106)); | ||
| 534 | try doTheTestReduce(.Add, [4]u32{ 9, 99, 999, 9999 }, @as(u32, 11106)); | ||
| 535 | try doTheTestReduce(.Add, [4]i64{ -9, -99, -999, -9999 }, @as(i64, -11106)); | ||
| 536 | try doTheTestReduce(.Add, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 11106)); | ||
| 537 | try doTheTestReduce(.Add, [4]i128{ -9, -99, -999, -9999 }, @as(i128, -11106)); | ||
| 538 | try doTheTestReduce(.Add, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 11106)); | ||
| 539 | try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 42.9)); | ||
| 540 | try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9)); | ||
| 541 | try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9)); | ||
| 542 | |||
| 543 | try doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false)); | ||
| 544 | try doTheTestReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0)); | ||
| 545 | try doTheTestReduce(.And, [4]u16{ 0xffff, 0xff55, 0xaaff, 0x1010 }, @as(u16, 0x10)); | ||
| 546 | try doTheTestReduce(.And, [4]u32{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u32, 0x1010)); | ||
| 547 | try doTheTestReduce(.And, [4]u64{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u64, 0x1010)); | ||
| 548 | |||
| 549 | try doTheTestReduce(.Min, [4]i16{ -1, 2, 3, 4 }, @as(i16, -1)); | ||
| 550 | try doTheTestReduce(.Min, [4]u16{ 1, 2, 3, 4 }, @as(u16, 1)); | ||
| 551 | try doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386)); | ||
| 552 | try doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9)); | ||
| 553 | |||
| 554 | // LLVM 11 ERROR: Cannot select type | ||
| 555 | // https://github.com/ziglang/zig/issues/7138 | ||
| 556 | if (std.builtin.arch != .aarch64) { | ||
| 557 | try doTheTestReduce(.Min, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, -386)); | ||
| 558 | try doTheTestReduce(.Min, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 9)); | ||
| 559 | } | ||
| 560 | |||
| 561 | try doTheTestReduce(.Min, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, -386)); | ||
| 562 | try doTheTestReduce(.Min, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 9)); | ||
| 563 | try doTheTestReduce(.Min, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, -100.0)); | ||
| 564 | try doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0)); | ||
| 565 | try doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0)); | ||
| 566 | |||
| 567 | try doTheTestReduce(.Max, [4]i16{ -1, 2, 3, 4 }, @as(i16, 4)); | ||
| 568 | try doTheTestReduce(.Max, [4]u16{ 1, 2, 3, 4 }, @as(u16, 4)); | ||
| 569 | try doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567)); | ||
| 570 | try doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999)); | ||
| 571 | |||
| 572 | // LLVM 11 ERROR: Cannot select type | ||
| 573 | // https://github.com/ziglang/zig/issues/7138 | ||
| 574 | if (std.builtin.arch != .aarch64) { | ||
| 575 | try doTheTestReduce(.Max, [4]i64{ 1234567, -386, 0, 3 }, @as(i64, 1234567)); | ||
| 576 | try doTheTestReduce(.Max, [4]u64{ 99, 9999, 9, 99999 }, @as(u64, 99999)); | ||
| 577 | } | ||
| 578 | |||
| 579 | try doTheTestReduce(.Max, [4]i128{ 1234567, -386, 0, 3 }, @as(i128, 1234567)); | ||
| 580 | try doTheTestReduce(.Max, [4]u128{ 99, 9999, 9, 99999 }, @as(u128, 99999)); | ||
| 581 | try doTheTestReduce(.Max, [4]f16{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f16, 10.0e9)); | ||
| 582 | try doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9)); | ||
| 583 | try doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9)); | ||
| 584 | |||
| 585 | try doTheTestReduce(.Mul, [4]i16{ -1, 2, 3, 4 }, @as(i16, -24)); | ||
| 586 | try doTheTestReduce(.Mul, [4]u16{ 1, 2, 3, 4 }, @as(u16, 24)); | ||
| 587 | try doTheTestReduce(.Mul, [4]i32{ -9, -99, -999, 999 }, @as(i32, -889218891)); | ||
| 588 | try doTheTestReduce(.Mul, [4]u32{ 1, 2, 3, 4 }, @as(u32, 24)); | ||
| 589 | try doTheTestReduce(.Mul, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 8900199891)); | ||
| 590 | try doTheTestReduce(.Mul, [4]u64{ 9, 99, 999, 9999 }, @as(u64, 8900199891)); | ||
| 591 | try doTheTestReduce(.Mul, [4]i128{ -9, -99, -999, 9999 }, @as(i128, -8900199891)); | ||
| 592 | try doTheTestReduce(.Mul, [4]u128{ 9, 99, 999, 9999 }, @as(u128, 8900199891)); | ||
| 593 | try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, -60.3, 100.0 }, @as(f16, 58430.7)); | ||
| 594 | try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7)); | ||
| 595 | try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7)); | ||
| 596 | |||
| 597 | try doTheTestReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true)); | ||
| 598 | try doTheTestReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1)); | ||
| 599 | try doTheTestReduce(.Or, [4]u16{ 0xff00, 0xff00, 0xf0, 0xf }, ~@as(u16, 0)); | ||
| 600 | try doTheTestReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0)); | ||
| 601 | try doTheTestReduce(.Or, [4]u64{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u64, 0xffffffff)); | ||
| 602 | try doTheTestReduce(.Or, [4]u128{ 0xffff0000, 0xff00, 0xf0, 0xf }, @as(u128, 0xffffffff)); | ||
| 603 | |||
| 604 | try doTheTestReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true)); | ||
| 605 | try doTheTestReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1)); | ||
| 606 | try doTheTestReduce(.Xor, [4]u16{ 0x0000, 0x3333, 0x8888, 0x4444 }, ~@as(u16, 0)); | ||
| 607 | try doTheTestReduce(.Xor, [4]u32{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, ~@as(u32, 0)); | ||
| 608 | try doTheTestReduce(.Xor, [4]u64{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u64, 0xffffffff)); | ||
| 609 | try doTheTestReduce(.Xor, [4]u128{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, @as(u128, 0xffffffff)); | ||
| 610 | |||
| 611 | // Test the reduction on vectors containing NaNs. | ||
| 612 | const f16_nan = math.nan(f16); | ||
| 613 | const f32_nan = math.nan(f32); | ||
| 614 | const f64_nan = math.nan(f64); | ||
| 615 | |||
| 616 | try doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 617 | try doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 618 | try doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 619 | |||
| 620 | // LLVM 11 ERROR: Cannot select type | ||
| 621 | // https://github.com/ziglang/zig/issues/7138 | ||
| 622 | if (false) { | ||
| 623 | try doTheTestReduce(.Min, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 624 | try doTheTestReduce(.Min, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 625 | try doTheTestReduce(.Min, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 626 | |||
| 627 | try doTheTestReduce(.Max, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 628 | try doTheTestReduce(.Max, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 629 | try doTheTestReduce(.Max, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 630 | } | ||
| 631 | |||
| 632 | try doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan); | ||
| 633 | try doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan); | ||
| 634 | try doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan); | ||
| 635 | } | ||
| 636 | }; | ||
| 637 | |||
| 638 | try S.doTheTest(); | ||
| 639 | comptime try S.doTheTest(); | ||
| 640 | } | ||
test/stage1/behavior/void.zig deleted-40| ... | @@ -1,40 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | const Foo = struct { | ||
| 4 | a: void, | ||
| 5 | b: i32, | ||
| 6 | c: void, | ||
| 7 | }; | ||
| 8 | |||
| 9 | test "compare void with void compile time known" { | ||
| 10 | comptime { | ||
| 11 | const foo = Foo{ | ||
| 12 | .a = {}, | ||
| 13 | .b = 1, | ||
| 14 | .c = {}, | ||
| 15 | }; | ||
| 16 | try expect(foo.a == {}); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | test "iterate over a void slice" { | ||
| 21 | var j: usize = 0; | ||
| 22 | for (times(10)) |_, i| { | ||
| 23 | try expect(i == j); | ||
| 24 | j += 1; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | fn times(n: usize) []const void { | ||
| 29 | return @as([*]void, undefined)[0..n]; | ||
| 30 | } | ||
| 31 | |||
| 32 | test "void optional" { | ||
| 33 | var x: ?void = {}; | ||
| 34 | try expect(x != null); | ||
| 35 | } | ||
| 36 | |||
| 37 | test "void array as a local variable initializer" { | ||
| 38 | var x = [_]void{{}} ** 1004; | ||
| 39 | var y = x[0]; | ||
| 40 | } | ||
test/stage1/behavior/wasm.zig deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "memory size and grow" { | ||
| 5 | var prev = @wasmMemorySize(0); | ||
| 6 | try expect(prev == @wasmMemoryGrow(0, 1)); | ||
| 7 | try expect(prev + 1 == @wasmMemorySize(0)); | ||
| 8 | } | ||
test/stage1/behavior/while.zig deleted-283| ... | @@ -1,283 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "while loop" { | ||
| 5 | var i: i32 = 0; | ||
| 6 | while (i < 4) { | ||
| 7 | i += 1; | ||
| 8 | } | ||
| 9 | try expect(i == 4); | ||
| 10 | try expect(whileLoop1() == 1); | ||
| 11 | } | ||
| 12 | fn whileLoop1() i32 { | ||
| 13 | return whileLoop2(); | ||
| 14 | } | ||
| 15 | fn whileLoop2() i32 { | ||
| 16 | while (true) { | ||
| 17 | return 1; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | test "static eval while" { | ||
| 22 | try expect(static_eval_while_number == 1); | ||
| 23 | } | ||
| 24 | const static_eval_while_number = staticWhileLoop1(); | ||
| 25 | fn staticWhileLoop1() i32 { | ||
| 26 | return whileLoop2(); | ||
| 27 | } | ||
| 28 | fn staticWhileLoop2() i32 { | ||
| 29 | while (true) { | ||
| 30 | return 1; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | test "continue and break" { | ||
| 35 | try runContinueAndBreakTest(); | ||
| 36 | try expect(continue_and_break_counter == 8); | ||
| 37 | } | ||
| 38 | var continue_and_break_counter: i32 = 0; | ||
| 39 | fn runContinueAndBreakTest() !void { | ||
| 40 | var i: i32 = 0; | ||
| 41 | while (true) { | ||
| 42 | continue_and_break_counter += 2; | ||
| 43 | i += 1; | ||
| 44 | if (i < 4) { | ||
| 45 | continue; | ||
| 46 | } | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | try expect(i == 4); | ||
| 50 | } | ||
| 51 | |||
| 52 | test "return with implicit cast from while loop" { | ||
| 53 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | ||
| 54 | } | ||
| 55 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | ||
| 56 | while (true) { | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | test "while with continue expression" { | ||
| 62 | var sum: i32 = 0; | ||
| 63 | { | ||
| 64 | var i: i32 = 0; | ||
| 65 | while (i < 10) : (i += 1) { | ||
| 66 | if (i == 5) continue; | ||
| 67 | sum += i; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | try expect(sum == 40); | ||
| 71 | } | ||
| 72 | |||
| 73 | test "while with else" { | ||
| 74 | var sum: i32 = 0; | ||
| 75 | var i: i32 = 0; | ||
| 76 | var got_else: i32 = 0; | ||
| 77 | while (i < 10) : (i += 1) { | ||
| 78 | sum += 1; | ||
| 79 | } else { | ||
| 80 | got_else += 1; | ||
| 81 | } | ||
| 82 | try expect(sum == 10); | ||
| 83 | try expect(got_else == 1); | ||
| 84 | } | ||
| 85 | |||
| 86 | test "while with optional as condition" { | ||
| 87 | numbers_left = 10; | ||
| 88 | var sum: i32 = 0; | ||
| 89 | while (getNumberOrNull()) |value| { | ||
| 90 | sum += value; | ||
| 91 | } | ||
| 92 | try expect(sum == 45); | ||
| 93 | } | ||
| 94 | |||
| 95 | test "while with optional as condition with else" { | ||
| 96 | numbers_left = 10; | ||
| 97 | var sum: i32 = 0; | ||
| 98 | var got_else: i32 = 0; | ||
| 99 | while (getNumberOrNull()) |value| { | ||
| 100 | sum += value; | ||
| 101 | try expect(got_else == 0); | ||
| 102 | } else { | ||
| 103 | got_else += 1; | ||
| 104 | } | ||
| 105 | try expect(sum == 45); | ||
| 106 | try expect(got_else == 1); | ||
| 107 | } | ||
| 108 | |||
| 109 | test "while with error union condition" { | ||
| 110 | numbers_left = 10; | ||
| 111 | var sum: i32 = 0; | ||
| 112 | var got_else: i32 = 0; | ||
| 113 | while (getNumberOrErr()) |value| { | ||
| 114 | sum += value; | ||
| 115 | } else |err| { | ||
| 116 | try expect(err == error.OutOfNumbers); | ||
| 117 | got_else += 1; | ||
| 118 | } | ||
| 119 | try expect(sum == 45); | ||
| 120 | try expect(got_else == 1); | ||
| 121 | } | ||
| 122 | |||
| 123 | var numbers_left: i32 = undefined; | ||
| 124 | fn getNumberOrErr() anyerror!i32 { | ||
| 125 | return if (numbers_left == 0) error.OutOfNumbers else x: { | ||
| 126 | numbers_left -= 1; | ||
| 127 | break :x numbers_left; | ||
| 128 | }; | ||
| 129 | } | ||
| 130 | fn getNumberOrNull() ?i32 { | ||
| 131 | return if (numbers_left == 0) null else x: { | ||
| 132 | numbers_left -= 1; | ||
| 133 | break :x numbers_left; | ||
| 134 | }; | ||
| 135 | } | ||
| 136 | |||
| 137 | test "while on optional with else result follow else prong" { | ||
| 138 | const result = while (returnNull()) |value| { | ||
| 139 | break value; | ||
| 140 | } else @as(i32, 2); | ||
| 141 | try expect(result == 2); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "while on optional with else result follow break prong" { | ||
| 145 | const result = while (returnOptional(10)) |value| { | ||
| 146 | break value; | ||
| 147 | } else @as(i32, 2); | ||
| 148 | try expect(result == 10); | ||
| 149 | } | ||
| 150 | |||
| 151 | test "while on error union with else result follow else prong" { | ||
| 152 | const result = while (returnError()) |value| { | ||
| 153 | break value; | ||
| 154 | } else |err| @as(i32, 2); | ||
| 155 | try expect(result == 2); | ||
| 156 | } | ||
| 157 | |||
| 158 | test "while on error union with else result follow break prong" { | ||
| 159 | const result = while (returnSuccess(10)) |value| { | ||
| 160 | break value; | ||
| 161 | } else |err| @as(i32, 2); | ||
| 162 | try expect(result == 10); | ||
| 163 | } | ||
| 164 | |||
| 165 | test "while on bool with else result follow else prong" { | ||
| 166 | const result = while (returnFalse()) { | ||
| 167 | break @as(i32, 10); | ||
| 168 | } else @as(i32, 2); | ||
| 169 | try expect(result == 2); | ||
| 170 | } | ||
| 171 | |||
| 172 | test "while on bool with else result follow break prong" { | ||
| 173 | const result = while (returnTrue()) { | ||
| 174 | break @as(i32, 10); | ||
| 175 | } else @as(i32, 2); | ||
| 176 | try expect(result == 10); | ||
| 177 | } | ||
| 178 | |||
| 179 | test "break from outer while loop" { | ||
| 180 | testBreakOuter(); | ||
| 181 | comptime testBreakOuter(); | ||
| 182 | } | ||
| 183 | |||
| 184 | fn testBreakOuter() void { | ||
| 185 | outer: while (true) { | ||
| 186 | while (true) { | ||
| 187 | break :outer; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | test "continue outer while loop" { | ||
| 193 | testContinueOuter(); | ||
| 194 | comptime testContinueOuter(); | ||
| 195 | } | ||
| 196 | |||
| 197 | fn testContinueOuter() void { | ||
| 198 | var i: usize = 0; | ||
| 199 | outer: while (i < 10) : (i += 1) { | ||
| 200 | while (true) { | ||
| 201 | continue :outer; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | fn returnNull() ?i32 { | ||
| 207 | return null; | ||
| 208 | } | ||
| 209 | fn returnOptional(x: i32) ?i32 { | ||
| 210 | return x; | ||
| 211 | } | ||
| 212 | fn returnError() anyerror!i32 { | ||
| 213 | return error.YouWantedAnError; | ||
| 214 | } | ||
| 215 | fn returnSuccess(x: i32) anyerror!i32 { | ||
| 216 | return x; | ||
| 217 | } | ||
| 218 | fn returnFalse() bool { | ||
| 219 | return false; | ||
| 220 | } | ||
| 221 | fn returnTrue() bool { | ||
| 222 | return true; | ||
| 223 | } | ||
| 224 | |||
| 225 | test "while bool 2 break statements and an else" { | ||
| 226 | const S = struct { | ||
| 227 | fn entry(t: bool, f: bool) !void { | ||
| 228 | var ok = false; | ||
| 229 | ok = while (t) { | ||
| 230 | if (f) break false; | ||
| 231 | if (t) break true; | ||
| 232 | } else false; | ||
| 233 | try expect(ok); | ||
| 234 | } | ||
| 235 | }; | ||
| 236 | try S.entry(true, false); | ||
| 237 | comptime try S.entry(true, false); | ||
| 238 | } | ||
| 239 | |||
| 240 | test "while optional 2 break statements and an else" { | ||
| 241 | const S = struct { | ||
| 242 | fn entry(opt_t: ?bool, f: bool) !void { | ||
| 243 | var ok = false; | ||
| 244 | ok = while (opt_t) |t| { | ||
| 245 | if (f) break false; | ||
| 246 | if (t) break true; | ||
| 247 | } else false; | ||
| 248 | try expect(ok); | ||
| 249 | } | ||
| 250 | }; | ||
| 251 | try S.entry(true, false); | ||
| 252 | comptime try S.entry(true, false); | ||
| 253 | } | ||
| 254 | |||
| 255 | test "while error 2 break statements and an else" { | ||
| 256 | const S = struct { | ||
| 257 | fn entry(opt_t: anyerror!bool, f: bool) !void { | ||
| 258 | var ok = false; | ||
| 259 | ok = while (opt_t) |t| { | ||
| 260 | if (f) break false; | ||
| 261 | if (t) break true; | ||
| 262 | } else |_| false; | ||
| 263 | try expect(ok); | ||
| 264 | } | ||
| 265 | }; | ||
| 266 | try S.entry(true, false); | ||
| 267 | comptime try S.entry(true, false); | ||
| 268 | } | ||
| 269 | |||
| 270 | test "while copies its payload" { | ||
| 271 | const S = struct { | ||
| 272 | fn doTheTest() !void { | ||
| 273 | var tmp: ?i32 = 10; | ||
| 274 | while (tmp) |value| { | ||
| 275 | // Modify the original variable | ||
| 276 | tmp = null; | ||
| 277 | try expect(value == 10); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | }; | ||
| 281 | try S.doTheTest(); | ||
| 282 | comptime try S.doTheTest(); | ||
| 283 | } | ||
test/stage1/behavior/widening.zig deleted-39| ... | @@ -1,39 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const mem = std.mem; | ||
| 4 | |||
| 5 | test "integer widening" { | ||
| 6 | var a: u8 = 250; | ||
| 7 | var b: u16 = a; | ||
| 8 | var c: u32 = b; | ||
| 9 | var d: u64 = c; | ||
| 10 | var e: u64 = d; | ||
| 11 | var f: u128 = e; | ||
| 12 | try expect(f == a); | ||
| 13 | } | ||
| 14 | |||
| 15 | test "implicit unsigned integer to signed integer" { | ||
| 16 | var a: u8 = 250; | ||
| 17 | var b: i16 = a; | ||
| 18 | try expect(b == 250); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "float widening" { | ||
| 22 | var a: f16 = 12.34; | ||
| 23 | var b: f32 = a; | ||
| 24 | var c: f64 = b; | ||
| 25 | var d: f128 = c; | ||
| 26 | try expect(a == b); | ||
| 27 | try expect(b == c); | ||
| 28 | try expect(c == d); | ||
| 29 | } | ||
| 30 | |||
| 31 | test "float widening f16 to f128" { | ||
| 32 | // TODO https://github.com/ziglang/zig/issues/3282 | ||
| 33 | if (@import("builtin").arch == .aarch64) return error.SkipZigTest; | ||
| 34 | if (@import("builtin").arch == .powerpc64le) return error.SkipZigTest; | ||
| 35 | |||
| 36 | var x: f16 = 12.34; | ||
| 37 | var y: f128 = x; | ||
| 38 | try expect(x == y); | ||
| 39 | } | ||
test/stage2/aarch64.zig+2-2| ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 11 | var case = ctx.exe("linux_aarch64 hello world", linux_aarch64); | 11 | var case = ctx.exe("linux_aarch64 hello world", linux_aarch64); |
| 12 | // Regular old hello world | 12 | // Regular old hello world |
| 13 | case.addCompareOutput( | 13 | case.addCompareOutput( |
| 14 | \\export fn _start() noreturn { | 14 | \\pub export fn _start() noreturn { |
| 15 | \\ print(); | 15 | \\ print(); |
| 16 | \\ exit(); | 16 | \\ exit(); |
| 17 | \\} | 17 | \\} |
| ... | @@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 51 | var case = ctx.exe("exit fn taking argument", linux_aarch64); | 51 | var case = ctx.exe("exit fn taking argument", linux_aarch64); |
| 52 | 52 | ||
| 53 | case.addCompareOutput( | 53 | case.addCompareOutput( |
| 54 | \\export fn _start() noreturn { | 54 | \\pub export fn _start() noreturn { |
| 55 | \\ exit(0); | 55 | \\ exit(0); |
| 56 | \\} | 56 | \\} |
| 57 | \\ | 57 | \\ |
test/stage2/arm.zig+19-172| ... | @@ -9,9 +9,9 @@ const linux_arm = std.zig.CrossTarget{ | ... | @@ -9,9 +9,9 @@ const linux_arm = std.zig.CrossTarget{ |
| 9 | pub fn addCases(ctx: *TestContext) !void { | 9 | pub fn addCases(ctx: *TestContext) !void { |
| 10 | { | 10 | { |
| 11 | var case = ctx.exe("linux_arm hello world", linux_arm); | 11 | var case = ctx.exe("linux_arm hello world", linux_arm); |
| 12 | // Regular old hello world | 12 | // Hello world using _start and inline asm. |
| 13 | case.addCompareOutput( | 13 | case.addCompareOutput( |
| 14 | \\export fn _start() noreturn { | 14 | \\pub export fn _start() noreturn { |
| 15 | \\ print(); | 15 | \\ print(); |
| 16 | \\ exit(); | 16 | \\ exit(); |
| 17 | \\} | 17 | \\} |
| ... | @@ -50,9 +50,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -50,9 +50,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 50 | // be in a specific order because otherwise the write to r0 | 50 | // be in a specific order because otherwise the write to r0 |
| 51 | // would overwrite the len parameter which resides in r0 | 51 | // would overwrite the len parameter which resides in r0 |
| 52 | case.addCompareOutput( | 52 | case.addCompareOutput( |
| 53 | \\export fn _start() noreturn { | 53 | \\pub fn main() void { |
| 54 | \\ print(id(14)); | 54 | \\ print(id(14)); |
| 55 | \\ exit(); | ||
| 56 | \\} | 55 | \\} |
| 57 | \\ | 56 | \\ |
| 58 | \\fn id(x: u32) u32 { | 57 | \\fn id(x: u32) u32 { |
| ... | @@ -70,16 +69,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -70,16 +69,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 70 | \\ ); | 69 | \\ ); |
| 71 | \\ return; | 70 | \\ return; |
| 72 | \\} | 71 | \\} |
| 73 | \\ | ||
| 74 | \\fn exit() noreturn { | ||
| 75 | \\ asm volatile ("svc #0" | ||
| 76 | \\ : | ||
| 77 | \\ : [number] "{r7}" (1), | ||
| 78 | \\ [arg1] "{r0}" (0) | ||
| 79 | \\ : "memory" | ||
| 80 | \\ ); | ||
| 81 | \\ unreachable; | ||
| 82 | \\} | ||
| 83 | , | 72 | , |
| 84 | "Hello, World!\n", | 73 | "Hello, World!\n", |
| 85 | ); | 74 | ); |
| ... | @@ -89,9 +78,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -89,9 +78,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 89 | var case = ctx.exe("non-leaf functions", linux_arm); | 78 | var case = ctx.exe("non-leaf functions", linux_arm); |
| 90 | // Testing non-leaf functions | 79 | // Testing non-leaf functions |
| 91 | case.addCompareOutput( | 80 | case.addCompareOutput( |
| 92 | \\export fn _start() noreturn { | 81 | \\pub fn main() void { |
| 93 | \\ foo(); | 82 | \\ foo(); |
| 94 | \\ exit(); | ||
| 95 | \\} | 83 | \\} |
| 96 | \\ | 84 | \\ |
| 97 | \\fn foo() void { | 85 | \\fn foo() void { |
| ... | @@ -99,16 +87,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -99,16 +87,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 99 | \\} | 87 | \\} |
| 100 | \\ | 88 | \\ |
| 101 | \\fn bar() void {} | 89 | \\fn bar() void {} |
| 102 | \\ | ||
| 103 | \\fn exit() noreturn { | ||
| 104 | \\ asm volatile ("svc #0" | ||
| 105 | \\ : | ||
| 106 | \\ : [number] "{r7}" (1), | ||
| 107 | \\ [arg1] "{r0}" (0) | ||
| 108 | \\ : "memory" | ||
| 109 | \\ ); | ||
| 110 | \\ unreachable; | ||
| 111 | \\} | ||
| 112 | , | 90 | , |
| 113 | "", | 91 | "", |
| 114 | ); | 92 | ); |
| ... | @@ -119,10 +97,9 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -119,10 +97,9 @@ pub fn addCases(ctx: *TestContext) !void { |
| 119 | 97 | ||
| 120 | // Add two numbers | 98 | // Add two numbers |
| 121 | case.addCompareOutput( | 99 | case.addCompareOutput( |
| 122 | \\export fn _start() noreturn { | 100 | \\pub fn main() void { |
| 123 | \\ print(2, 4); | 101 | \\ print(2, 4); |
| 124 | \\ print(1, 7); | 102 | \\ print(1, 7); |
| 125 | \\ exit(); | ||
| 126 | \\} | 103 | \\} |
| 127 | \\ | 104 | \\ |
| 128 | \\fn print(a: u32, b: u32) void { | 105 | \\fn print(a: u32, b: u32) void { |
| ... | @@ -136,26 +113,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -136,26 +113,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 136 | \\ ); | 113 | \\ ); |
| 137 | \\ return; | 114 | \\ return; |
| 138 | \\} | 115 | \\} |
| 139 | \\ | ||
| 140 | \\fn exit() noreturn { | ||
| 141 | \\ asm volatile ("svc #0" | ||
| 142 | \\ : | ||
| 143 | \\ : [number] "{r7}" (1), | ||
| 144 | \\ [arg1] "{r0}" (0) | ||
| 145 | \\ : "memory" | ||
| 146 | \\ ); | ||
| 147 | \\ unreachable; | ||
| 148 | \\} | ||
| 149 | , | 116 | , |
| 150 | "12345612345678", | 117 | "12345612345678", |
| 151 | ); | 118 | ); |
| 152 | 119 | ||
| 153 | // Subtract two numbers | 120 | // Subtract two numbers |
| 154 | case.addCompareOutput( | 121 | case.addCompareOutput( |
| 155 | \\export fn _start() noreturn { | 122 | \\pub fn main() void { |
| 156 | \\ print(10, 5); | 123 | \\ print(10, 5); |
| 157 | \\ print(4, 3); | 124 | \\ print(4, 3); |
| 158 | \\ exit(); | ||
| 159 | \\} | 125 | \\} |
| 160 | \\ | 126 | \\ |
| 161 | \\fn print(a: u32, b: u32) void { | 127 | \\fn print(a: u32, b: u32) void { |
| ... | @@ -169,26 +135,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -169,26 +135,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 169 | \\ ); | 135 | \\ ); |
| 170 | \\ return; | 136 | \\ return; |
| 171 | \\} | 137 | \\} |
| 172 | \\ | ||
| 173 | \\fn exit() noreturn { | ||
| 174 | \\ asm volatile ("svc #0" | ||
| 175 | \\ : | ||
| 176 | \\ : [number] "{r7}" (1), | ||
| 177 | \\ [arg1] "{r0}" (0) | ||
| 178 | \\ : "memory" | ||
| 179 | \\ ); | ||
| 180 | \\ unreachable; | ||
| 181 | \\} | ||
| 182 | , | 138 | , |
| 183 | "123451", | 139 | "123451", |
| 184 | ); | 140 | ); |
| 185 | 141 | ||
| 186 | // Bitwise And | 142 | // Bitwise And |
| 187 | case.addCompareOutput( | 143 | case.addCompareOutput( |
| 188 | \\export fn _start() noreturn { | 144 | \\pub fn main() void { |
| 189 | \\ print(8, 9); | 145 | \\ print(8, 9); |
| 190 | \\ print(3, 7); | 146 | \\ print(3, 7); |
| 191 | \\ exit(); | ||
| 192 | \\} | 147 | \\} |
| 193 | \\ | 148 | \\ |
| 194 | \\fn print(a: u32, b: u32) void { | 149 | \\fn print(a: u32, b: u32) void { |
| ... | @@ -202,26 +157,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -202,26 +157,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 202 | \\ ); | 157 | \\ ); |
| 203 | \\ return; | 158 | \\ return; |
| 204 | \\} | 159 | \\} |
| 205 | \\ | ||
| 206 | \\fn exit() noreturn { | ||
| 207 | \\ asm volatile ("svc #0" | ||
| 208 | \\ : | ||
| 209 | \\ : [number] "{r7}" (1), | ||
| 210 | \\ [arg1] "{r0}" (0) | ||
| 211 | \\ : "memory" | ||
| 212 | \\ ); | ||
| 213 | \\ unreachable; | ||
| 214 | \\} | ||
| 215 | , | 160 | , |
| 216 | "12345678123", | 161 | "12345678123", |
| 217 | ); | 162 | ); |
| 218 | 163 | ||
| 219 | // Bitwise Or | 164 | // Bitwise Or |
| 220 | case.addCompareOutput( | 165 | case.addCompareOutput( |
| 221 | \\export fn _start() noreturn { | 166 | \\pub fn main() void { |
| 222 | \\ print(4, 2); | 167 | \\ print(4, 2); |
| 223 | \\ print(3, 7); | 168 | \\ print(3, 7); |
| 224 | \\ exit(); | ||
| 225 | \\} | 169 | \\} |
| 226 | \\ | 170 | \\ |
| 227 | \\fn print(a: u32, b: u32) void { | 171 | \\fn print(a: u32, b: u32) void { |
| ... | @@ -235,26 +179,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -235,26 +179,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 235 | \\ ); | 179 | \\ ); |
| 236 | \\ return; | 180 | \\ return; |
| 237 | \\} | 181 | \\} |
| 238 | \\ | ||
| 239 | \\fn exit() noreturn { | ||
| 240 | \\ asm volatile ("svc #0" | ||
| 241 | \\ : | ||
| 242 | \\ : [number] "{r7}" (1), | ||
| 243 | \\ [arg1] "{r0}" (0) | ||
| 244 | \\ : "memory" | ||
| 245 | \\ ); | ||
| 246 | \\ unreachable; | ||
| 247 | \\} | ||
| 248 | , | 182 | , |
| 249 | "1234561234567", | 183 | "1234561234567", |
| 250 | ); | 184 | ); |
| 251 | 185 | ||
| 252 | // Bitwise Xor | 186 | // Bitwise Xor |
| 253 | case.addCompareOutput( | 187 | case.addCompareOutput( |
| 254 | \\export fn _start() noreturn { | 188 | \\pub fn main() void { |
| 255 | \\ print(42, 42); | 189 | \\ print(42, 42); |
| 256 | \\ print(3, 5); | 190 | \\ print(3, 5); |
| 257 | \\ exit(); | ||
| 258 | \\} | 191 | \\} |
| 259 | \\ | 192 | \\ |
| 260 | \\fn print(a: u32, b: u32) void { | 193 | \\fn print(a: u32, b: u32) void { |
| ... | @@ -268,16 +201,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -268,16 +201,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 268 | \\ ); | 201 | \\ ); |
| 269 | \\ return; | 202 | \\ return; |
| 270 | \\} | 203 | \\} |
| 271 | \\ | ||
| 272 | \\fn exit() noreturn { | ||
| 273 | \\ asm volatile ("svc #0" | ||
| 274 | \\ : | ||
| 275 | \\ : [number] "{r7}" (1), | ||
| 276 | \\ [arg1] "{r0}" (0) | ||
| 277 | \\ : "memory" | ||
| 278 | \\ ); | ||
| 279 | \\ unreachable; | ||
| 280 | \\} | ||
| 281 | , | 204 | , |
| 282 | "123456", | 205 | "123456", |
| 283 | ); | 206 | ); |
| ... | @@ -287,26 +210,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -287,26 +210,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 287 | var case = ctx.exe("if statements", linux_arm); | 210 | var case = ctx.exe("if statements", linux_arm); |
| 288 | // Simple if statement in assert | 211 | // Simple if statement in assert |
| 289 | case.addCompareOutput( | 212 | case.addCompareOutput( |
| 290 | \\export fn _start() noreturn { | 213 | \\pub fn main() void { |
| 291 | \\ var x: u32 = 123; | 214 | \\ var x: u32 = 123; |
| 292 | \\ var y: u32 = 42; | 215 | \\ var y: u32 = 42; |
| 293 | \\ assert(x > y); | 216 | \\ assert(x > y); |
| 294 | \\ exit(); | ||
| 295 | \\} | 217 | \\} |
| 296 | \\ | 218 | \\ |
| 297 | \\fn assert(ok: bool) void { | 219 | \\fn assert(ok: bool) void { |
| 298 | \\ if (!ok) unreachable; | 220 | \\ if (!ok) unreachable; |
| 299 | \\} | 221 | \\} |
| 300 | \\ | ||
| 301 | \\fn exit() noreturn { | ||
| 302 | \\ asm volatile ("svc #0" | ||
| 303 | \\ : | ||
| 304 | \\ : [number] "{r7}" (1), | ||
| 305 | \\ [arg1] "{r0}" (0) | ||
| 306 | \\ : "memory" | ||
| 307 | \\ ); | ||
| 308 | \\ unreachable; | ||
| 309 | \\} | ||
| 310 | , | 222 | , |
| 311 | "", | 223 | "", |
| 312 | ); | 224 | ); |
| ... | @@ -316,7 +228,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -316,7 +228,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 316 | var case = ctx.exe("while loops", linux_arm); | 228 | var case = ctx.exe("while loops", linux_arm); |
| 317 | // Simple while loop with assert | 229 | // Simple while loop with assert |
| 318 | case.addCompareOutput( | 230 | case.addCompareOutput( |
| 319 | \\export fn _start() noreturn { | 231 | \\pub fn main() void { |
| 320 | \\ var x: u32 = 2020; | 232 | \\ var x: u32 = 2020; |
| 321 | \\ var i: u32 = 0; | 233 | \\ var i: u32 = 0; |
| 322 | \\ while (x > 0) { | 234 | \\ while (x > 0) { |
| ... | @@ -324,22 +236,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -324,22 +236,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 324 | \\ i += 1; | 236 | \\ i += 1; |
| 325 | \\ } | 237 | \\ } |
| 326 | \\ assert(i == 1010); | 238 | \\ assert(i == 1010); |
| 327 | \\ exit(); | ||
| 328 | \\} | 239 | \\} |
| 329 | \\ | 240 | \\ |
| 330 | \\fn assert(ok: bool) void { | 241 | \\fn assert(ok: bool) void { |
| 331 | \\ if (!ok) unreachable; | 242 | \\ if (!ok) unreachable; |
| 332 | \\} | 243 | \\} |
| 333 | \\ | ||
| 334 | \\fn exit() noreturn { | ||
| 335 | \\ asm volatile ("svc #0" | ||
| 336 | \\ : | ||
| 337 | \\ : [number] "{r7}" (1), | ||
| 338 | \\ [arg1] "{r0}" (0) | ||
| 339 | \\ : "memory" | ||
| 340 | \\ ); | ||
| 341 | \\ unreachable; | ||
| 342 | \\} | ||
| 343 | , | 244 | , |
| 344 | "", | 245 | "", |
| 345 | ); | 246 | ); |
| ... | @@ -349,12 +250,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -349,12 +250,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 349 | var case = ctx.exe("integer multiplication", linux_arm); | 250 | var case = ctx.exe("integer multiplication", linux_arm); |
| 350 | // Simple u32 integer multiplication | 251 | // Simple u32 integer multiplication |
| 351 | case.addCompareOutput( | 252 | case.addCompareOutput( |
| 352 | \\export fn _start() noreturn { | 253 | \\pub fn main() void { |
| 353 | \\ assert(mul(1, 1) == 1); | 254 | \\ assert(mul(1, 1) == 1); |
| 354 | \\ assert(mul(42, 1) == 42); | 255 | \\ assert(mul(42, 1) == 42); |
| 355 | \\ assert(mul(1, 42) == 42); | 256 | \\ assert(mul(1, 42) == 42); |
| 356 | \\ assert(mul(123, 42) == 5166); | 257 | \\ assert(mul(123, 42) == 5166); |
| 357 | \\ exit(); | ||
| 358 | \\} | 258 | \\} |
| 359 | \\ | 259 | \\ |
| 360 | \\fn mul(x: u32, y: u32) u32 { | 260 | \\fn mul(x: u32, y: u32) u32 { |
| ... | @@ -364,16 +264,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -364,16 +264,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 364 | \\fn assert(ok: bool) void { | 264 | \\fn assert(ok: bool) void { |
| 365 | \\ if (!ok) unreachable; | 265 | \\ if (!ok) unreachable; |
| 366 | \\} | 266 | \\} |
| 367 | \\ | ||
| 368 | \\fn exit() noreturn { | ||
| 369 | \\ asm volatile ("svc #0" | ||
| 370 | \\ : | ||
| 371 | \\ : [number] "{r7}" (1), | ||
| 372 | \\ [arg1] "{r0}" (0) | ||
| 373 | \\ : "memory" | ||
| 374 | \\ ); | ||
| 375 | \\ unreachable; | ||
| 376 | \\} | ||
| 377 | , | 267 | , |
| 378 | "", | 268 | "", |
| 379 | ); | 269 | ); |
| ... | @@ -385,9 +275,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -385,9 +275,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 385 | // callee preserved register, otherwise it will be overwritten | 275 | // callee preserved register, otherwise it will be overwritten |
| 386 | // by the first parameter to baz. | 276 | // by the first parameter to baz. |
| 387 | case.addCompareOutput( | 277 | case.addCompareOutput( |
| 388 | \\export fn _start() noreturn { | 278 | \\pub fn main() void { |
| 389 | \\ assert(foo() == 43); | 279 | \\ assert(foo() == 43); |
| 390 | \\ exit(); | ||
| 391 | \\} | 280 | \\} |
| 392 | \\ | 281 | \\ |
| 393 | \\fn foo() u32 { | 282 | \\fn foo() u32 { |
| ... | @@ -405,16 +294,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -405,16 +294,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 405 | \\fn assert(ok: bool) void { | 294 | \\fn assert(ok: bool) void { |
| 406 | \\ if (!ok) unreachable; | 295 | \\ if (!ok) unreachable; |
| 407 | \\} | 296 | \\} |
| 408 | \\ | ||
| 409 | \\fn exit() noreturn { | ||
| 410 | \\ asm volatile ("svc #0" | ||
| 411 | \\ : | ||
| 412 | \\ : [number] "{r7}" (1), | ||
| 413 | \\ [arg1] "{r0}" (0) | ||
| 414 | \\ : "memory" | ||
| 415 | \\ ); | ||
| 416 | \\ unreachable; | ||
| 417 | \\} | ||
| 418 | , | 297 | , |
| 419 | "", | 298 | "", |
| 420 | ); | 299 | ); |
| ... | @@ -423,14 +302,13 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -423,14 +302,13 @@ pub fn addCases(ctx: *TestContext) !void { |
| 423 | { | 302 | { |
| 424 | var case = ctx.exe("recursive fibonacci", linux_arm); | 303 | var case = ctx.exe("recursive fibonacci", linux_arm); |
| 425 | case.addCompareOutput( | 304 | case.addCompareOutput( |
| 426 | \\export fn _start() noreturn { | 305 | \\pub fn main() void { |
| 427 | \\ assert(fib(0) == 0); | 306 | \\ assert(fib(0) == 0); |
| 428 | \\ assert(fib(1) == 1); | 307 | \\ assert(fib(1) == 1); |
| 429 | \\ assert(fib(2) == 1); | 308 | \\ assert(fib(2) == 1); |
| 430 | \\ assert(fib(3) == 2); | 309 | \\ assert(fib(3) == 2); |
| 431 | \\ assert(fib(10) == 55); | 310 | \\ assert(fib(10) == 55); |
| 432 | \\ assert(fib(20) == 6765); | 311 | \\ assert(fib(20) == 6765); |
| 433 | \\ exit(); | ||
| 434 | \\} | 312 | \\} |
| 435 | \\ | 313 | \\ |
| 436 | \\fn fib(n: u32) u32 { | 314 | \\fn fib(n: u32) u32 { |
| ... | @@ -444,16 +322,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -444,16 +322,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 444 | \\fn assert(ok: bool) void { | 322 | \\fn assert(ok: bool) void { |
| 445 | \\ if (!ok) unreachable; | 323 | \\ if (!ok) unreachable; |
| 446 | \\} | 324 | \\} |
| 447 | \\ | ||
| 448 | \\fn exit() noreturn { | ||
| 449 | \\ asm volatile ("svc #0" | ||
| 450 | \\ : | ||
| 451 | \\ : [number] "{r7}" (1), | ||
| 452 | \\ [arg1] "{r0}" (0) | ||
| 453 | \\ : "memory" | ||
| 454 | \\ ); | ||
| 455 | \\ unreachable; | ||
| 456 | \\} | ||
| 457 | , | 325 | , |
| 458 | "", | 326 | "", |
| 459 | ); | 327 | ); |
| ... | @@ -462,9 +330,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -462,9 +330,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 462 | { | 330 | { |
| 463 | var case = ctx.exe("spilling registers", linux_arm); | 331 | var case = ctx.exe("spilling registers", linux_arm); |
| 464 | case.addCompareOutput( | 332 | case.addCompareOutput( |
| 465 | \\export fn _start() noreturn { | 333 | \\pub fn main() void { |
| 466 | \\ assert(add(3, 4) == 791); | 334 | \\ assert(add(3, 4) == 791); |
| 467 | \\ exit(); | ||
| 468 | \\} | 335 | \\} |
| 469 | \\ | 336 | \\ |
| 470 | \\fn add(a: u32, b: u32) u32 { | 337 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -497,24 +364,13 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -497,24 +364,13 @@ pub fn addCases(ctx: *TestContext) !void { |
| 497 | \\fn assert(ok: bool) void { | 364 | \\fn assert(ok: bool) void { |
| 498 | \\ if (!ok) unreachable; | 365 | \\ if (!ok) unreachable; |
| 499 | \\} | 366 | \\} |
| 500 | \\ | ||
| 501 | \\fn exit() noreturn { | ||
| 502 | \\ asm volatile ("svc #0" | ||
| 503 | \\ : | ||
| 504 | \\ : [number] "{r7}" (1), | ||
| 505 | \\ [arg1] "{r0}" (0) | ||
| 506 | \\ : "memory" | ||
| 507 | \\ ); | ||
| 508 | \\ unreachable; | ||
| 509 | \\} | ||
| 510 | , | 367 | , |
| 511 | "", | 368 | "", |
| 512 | ); | 369 | ); |
| 513 | 370 | ||
| 514 | case.addCompareOutput( | 371 | case.addCompareOutput( |
| 515 | \\export fn _start() noreturn { | 372 | \\pub fn main() void { |
| 516 | \\ assert(addMul(3, 4) == 357747496); | 373 | \\ assert(addMul(3, 4) == 357747496); |
| 517 | \\ exit(); | ||
| 518 | \\} | 374 | \\} |
| 519 | \\ | 375 | \\ |
| 520 | \\fn addMul(a: u32, b: u32) u32 { | 376 | \\fn addMul(a: u32, b: u32) u32 { |
| ... | @@ -547,17 +403,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -547,17 +403,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 547 | \\fn assert(ok: bool) void { | 403 | \\fn assert(ok: bool) void { |
| 548 | \\ if (!ok) unreachable; | 404 | \\ if (!ok) unreachable; |
| 549 | \\} | 405 | \\} |
| 550 | \\ | 406 | , |
| 551 | \\fn exit() noreturn { | 407 | "", |
| 552 | \\ asm volatile ("svc #0" | 408 | ); |
| 553 | \\ : | ||
| 554 | \\ : [number] "{r7}" (1), | ||
| 555 | \\ [arg1] "{r0}" (0) | ||
| 556 | \\ : "memory" | ||
| 557 | \\ ); | ||
| 558 | \\ unreachable; | ||
| 559 | \\} | ||
| 560 | , | ||
| 561 | "",); | ||
| 562 | } | 409 | } |
| 563 | } | 410 | } |
test/stage2/cbe.zig+59-55| ... | @@ -15,7 +15,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -15,7 +15,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 15 | // Regular old hello world | 15 | // Regular old hello world |
| 16 | case.addCompareOutput( | 16 | case.addCompareOutput( |
| 17 | \\extern fn puts(s: [*:0]const u8) c_int; | 17 | \\extern fn puts(s: [*:0]const u8) c_int; |
| 18 | \\export fn main() c_int { | 18 | \\pub export fn main() c_int { |
| 19 | \\ _ = puts("hello world!"); | 19 | \\ _ = puts("hello world!"); |
| 20 | \\ return 0; | 20 | \\ return 0; |
| 21 | \\} | 21 | \\} |
| ... | @@ -24,7 +24,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -24,7 +24,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 24 | // Now change the message only | 24 | // Now change the message only |
| 25 | case.addCompareOutput( | 25 | case.addCompareOutput( |
| 26 | \\extern fn puts(s: [*:0]const u8) c_int; | 26 | \\extern fn puts(s: [*:0]const u8) c_int; |
| 27 | \\export fn main() c_int { | 27 | \\pub export fn main() c_int { |
| 28 | \\ _ = puts("yo"); | 28 | \\ _ = puts("yo"); |
| 29 | \\ return 0; | 29 | \\ return 0; |
| 30 | \\} | 30 | \\} |
| ... | @@ -33,7 +33,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -33,7 +33,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 33 | // Add an unused Decl | 33 | // Add an unused Decl |
| 34 | case.addCompareOutput( | 34 | case.addCompareOutput( |
| 35 | \\extern fn puts(s: [*:0]const u8) c_int; | 35 | \\extern fn puts(s: [*:0]const u8) c_int; |
| 36 | \\export fn main() c_int { | 36 | \\pub export fn main() c_int { |
| 37 | \\ _ = puts("yo!"); | 37 | \\ _ = puts("yo!"); |
| 38 | \\ return 0; | 38 | \\ return 0; |
| 39 | \\} | 39 | \\} |
| ... | @@ -43,7 +43,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -43,7 +43,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 43 | // Comptime return type and calling convention expected. | 43 | // Comptime return type and calling convention expected. |
| 44 | case.addError( | 44 | case.addError( |
| 45 | \\var x: i32 = 1234; | 45 | \\var x: i32 = 1234; |
| 46 | \\export fn main() x { | 46 | \\pub export fn main() x { |
| 47 | \\ return 0; | 47 | \\ return 0; |
| 48 | \\} | 48 | \\} |
| 49 | \\export fn foo() callconv(y) c_int { | 49 | \\export fn foo() callconv(y) c_int { |
| ... | @@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -51,7 +51,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 51 | \\} | 51 | \\} |
| 52 | \\var y: i32 = 1234; | 52 | \\var y: i32 = 1234; |
| 53 | , &.{ | 53 | , &.{ |
| 54 | ":2:18: error: unable to resolve comptime value", | 54 | ":2:22: error: unable to resolve comptime value", |
| 55 | ":5:26: error: unable to resolve comptime value", | 55 | ":5:26: error: unable to resolve comptime value", |
| 56 | }); | 56 | }); |
| 57 | } | 57 | } |
| ... | @@ -62,7 +62,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -62,7 +62,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 62 | case.addCompareOutput( | 62 | case.addCompareOutput( |
| 63 | \\extern fn printf(format: [*:0]const u8, ...) c_int; | 63 | \\extern fn printf(format: [*:0]const u8, ...) c_int; |
| 64 | \\ | 64 | \\ |
| 65 | \\export fn main() c_int { | 65 | \\pub export fn main() c_int { |
| 66 | \\ _ = printf("Hello, %s!\n", "world"); | 66 | \\ _ = printf("Hello, %s!\n", "world"); |
| 67 | \\ return 0; | 67 | \\ return 0; |
| 68 | \\} | 68 | \\} |
| ... | @@ -119,14 +119,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -119,14 +119,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 119 | \\ unreachable; | 119 | \\ unreachable; |
| 120 | \\} | 120 | \\} |
| 121 | \\ | 121 | \\ |
| 122 | \\export fn main() c_int { | 122 | \\pub export fn main() c_int { |
| 123 | \\ exitGood(); | 123 | \\ exitGood(); |
| 124 | \\} | 124 | \\} |
| 125 | , ""); | 125 | , ""); |
| 126 | 126 | ||
| 127 | // Pass a usize parameter to exit | 127 | // Pass a usize parameter to exit |
| 128 | case.addCompareOutput( | 128 | case.addCompareOutput( |
| 129 | \\export fn main() c_int { | 129 | \\pub export fn main() c_int { |
| 130 | \\ exit(0); | 130 | \\ exit(0); |
| 131 | \\} | 131 | \\} |
| 132 | \\ | 132 | \\ |
| ... | @@ -142,7 +142,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -142,7 +142,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 142 | 142 | ||
| 143 | // Change the parameter to u8 | 143 | // Change the parameter to u8 |
| 144 | case.addCompareOutput( | 144 | case.addCompareOutput( |
| 145 | \\export fn main() c_int { | 145 | \\pub export fn main() c_int { |
| 146 | \\ exit(0); | 146 | \\ exit(0); |
| 147 | \\} | 147 | \\} |
| 148 | \\ | 148 | \\ |
| ... | @@ -158,7 +158,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -158,7 +158,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 158 | 158 | ||
| 159 | // Do some arithmetic at the exit callsite | 159 | // Do some arithmetic at the exit callsite |
| 160 | case.addCompareOutput( | 160 | case.addCompareOutput( |
| 161 | \\export fn main() c_int { | 161 | \\pub export fn main() c_int { |
| 162 | \\ exitMath(1); | 162 | \\ exitMath(1); |
| 163 | \\} | 163 | \\} |
| 164 | \\ | 164 | \\ |
| ... | @@ -179,7 +179,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -179,7 +179,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 179 | 179 | ||
| 180 | // Invert the arithmetic | 180 | // Invert the arithmetic |
| 181 | case.addCompareOutput( | 181 | case.addCompareOutput( |
| 182 | \\export fn main() c_int { | 182 | \\pub export fn main() c_int { |
| 183 | \\ exitMath(1); | 183 | \\ exitMath(1); |
| 184 | \\} | 184 | \\} |
| 185 | \\ | 185 | \\ |
| ... | @@ -211,7 +211,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -211,7 +211,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 211 | \\ return add(a, b); | 211 | \\ return add(a, b); |
| 212 | \\} | 212 | \\} |
| 213 | \\ | 213 | \\ |
| 214 | \\export fn main() c_int { | 214 | \\pub export fn main() c_int { |
| 215 | \\ return addIndirect(1, 2) - 3; | 215 | \\ return addIndirect(1, 2) - 3; |
| 216 | \\} | 216 | \\} |
| 217 | , ""); | 217 | , ""); |
| ... | @@ -225,7 +225,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -225,7 +225,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 225 | \\ return a + b; | 225 | \\ return a + b; |
| 226 | \\} | 226 | \\} |
| 227 | \\ | 227 | \\ |
| 228 | \\export fn main() c_int { | 228 | \\pub export fn main() c_int { |
| 229 | \\ const x = add(1, 2); | 229 | \\ const x = add(1, 2); |
| 230 | \\ var y = add(3, 0); | 230 | \\ var y = add(3, 0); |
| 231 | \\ y -= x; | 231 | \\ y -= x; |
| ... | @@ -233,11 +233,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -233,11 +233,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 233 | \\} | 233 | \\} |
| 234 | , ""); | 234 | , ""); |
| 235 | } | 235 | } |
| 236 | { | 236 | // This will make a pretty deep call stack, so this test can only be enabled |
| 237 | // on hosts where Zig's linking strategy can honor the 16 MiB (default) we | ||
| 238 | // link the self-hosted compiler with. | ||
| 239 | const host_supports_custom_stack_size = @import("builtin").target.os.tag == .linux; | ||
| 240 | if (host_supports_custom_stack_size) { | ||
| 237 | var case = ctx.exeFromCompiledC("@setEvalBranchQuota", .{}); | 241 | var case = ctx.exeFromCompiledC("@setEvalBranchQuota", .{}); |
| 238 | 242 | ||
| 239 | case.addCompareOutput( | 243 | case.addCompareOutput( |
| 240 | \\export fn main() i32 { | 244 | \\pub export fn main() i32 { |
| 241 | \\ @setEvalBranchQuota(1001); | 245 | \\ @setEvalBranchQuota(1001); |
| 242 | \\ const y = rec(1001); | 246 | \\ const y = rec(1001); |
| 243 | \\ return y - 1; | 247 | \\ return y - 1; |
| ... | @@ -254,14 +258,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -254,14 +258,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 254 | 258 | ||
| 255 | // Simple while loop | 259 | // Simple while loop |
| 256 | case.addCompareOutput( | 260 | case.addCompareOutput( |
| 257 | \\export fn main() c_int { | 261 | \\pub export fn main() c_int { |
| 258 | \\ var a: c_int = 0; | 262 | \\ var a: c_int = 0; |
| 259 | \\ while (a < 5) : (a+=1) {} | 263 | \\ while (a < 5) : (a+=1) {} |
| 260 | \\ return a - 5; | 264 | \\ return a - 5; |
| 261 | \\} | 265 | \\} |
| 262 | , ""); | 266 | , ""); |
| 263 | case.addCompareOutput( | 267 | case.addCompareOutput( |
| 264 | \\export fn main() c_int { | 268 | \\pub export fn main() c_int { |
| 265 | \\ var a = true; | 269 | \\ var a = true; |
| 266 | \\ while (!a) {} | 270 | \\ while (!a) {} |
| 267 | \\ return 0; | 271 | \\ return 0; |
| ... | @@ -270,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -270,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 270 | 274 | ||
| 271 | // If expression | 275 | // If expression |
| 272 | case.addCompareOutput( | 276 | case.addCompareOutput( |
| 273 | \\export fn main() c_int { | 277 | \\pub export fn main() c_int { |
| 274 | \\ var cond: c_int = 0; | 278 | \\ var cond: c_int = 0; |
| 275 | \\ var a: c_int = @as(c_int, if (cond == 0) | 279 | \\ var a: c_int = @as(c_int, if (cond == 0) |
| 276 | \\ 2 | 280 | \\ 2 |
| ... | @@ -282,7 +286,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -282,7 +286,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 282 | 286 | ||
| 283 | // If expression with breakpoint that does not get hit | 287 | // If expression with breakpoint that does not get hit |
| 284 | case.addCompareOutput( | 288 | case.addCompareOutput( |
| 285 | \\export fn main() c_int { | 289 | \\pub export fn main() c_int { |
| 286 | \\ var x: i32 = 1; | 290 | \\ var x: i32 = 1; |
| 287 | \\ if (x != 1) @breakpoint(); | 291 | \\ if (x != 1) @breakpoint(); |
| 288 | \\ return 0; | 292 | \\ return 0; |
| ... | @@ -291,7 +295,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -291,7 +295,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 291 | 295 | ||
| 292 | // Switch expression | 296 | // Switch expression |
| 293 | case.addCompareOutput( | 297 | case.addCompareOutput( |
| 294 | \\export fn main() c_int { | 298 | \\pub export fn main() c_int { |
| 295 | \\ var cond: c_int = 0; | 299 | \\ var cond: c_int = 0; |
| 296 | \\ var a: c_int = switch (cond) { | 300 | \\ var a: c_int = switch (cond) { |
| 297 | \\ 1 => 1, | 301 | \\ 1 => 1, |
| ... | @@ -306,7 +310,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -306,7 +310,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 306 | 310 | ||
| 307 | // Switch expression missing else case. | 311 | // Switch expression missing else case. |
| 308 | case.addError( | 312 | case.addError( |
| 309 | \\export fn main() c_int { | 313 | \\pub export fn main() c_int { |
| 310 | \\ var cond: c_int = 0; | 314 | \\ var cond: c_int = 0; |
| 311 | \\ const a: c_int = switch (cond) { | 315 | \\ const a: c_int = switch (cond) { |
| 312 | \\ 1 => 1, | 316 | \\ 1 => 1, |
| ... | @@ -320,7 +324,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -320,7 +324,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 320 | 324 | ||
| 321 | // Switch expression, has an unreachable prong. | 325 | // Switch expression, has an unreachable prong. |
| 322 | case.addCompareOutput( | 326 | case.addCompareOutput( |
| 323 | \\export fn main() c_int { | 327 | \\pub export fn main() c_int { |
| 324 | \\ var cond: c_int = 0; | 328 | \\ var cond: c_int = 0; |
| 325 | \\ const a: c_int = switch (cond) { | 329 | \\ const a: c_int = switch (cond) { |
| 326 | \\ 1 => 1, | 330 | \\ 1 => 1, |
| ... | @@ -337,7 +341,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -337,7 +341,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 337 | // Switch expression, has an unreachable prong and prongs write | 341 | // Switch expression, has an unreachable prong and prongs write |
| 338 | // to result locations. | 342 | // to result locations. |
| 339 | case.addCompareOutput( | 343 | case.addCompareOutput( |
| 340 | \\export fn main() c_int { | 344 | \\pub export fn main() c_int { |
| 341 | \\ var cond: c_int = 0; | 345 | \\ var cond: c_int = 0; |
| 342 | \\ var a: c_int = switch (cond) { | 346 | \\ var a: c_int = switch (cond) { |
| 343 | \\ 1 => 1, | 347 | \\ 1 => 1, |
| ... | @@ -353,7 +357,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -353,7 +357,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 353 | 357 | ||
| 354 | // Integer switch expression has duplicate case value. | 358 | // Integer switch expression has duplicate case value. |
| 355 | case.addError( | 359 | case.addError( |
| 356 | \\export fn main() c_int { | 360 | \\pub export fn main() c_int { |
| 357 | \\ var cond: c_int = 0; | 361 | \\ var cond: c_int = 0; |
| 358 | \\ const a: c_int = switch (cond) { | 362 | \\ const a: c_int = switch (cond) { |
| 359 | \\ 1 => 1, | 363 | \\ 1 => 1, |
| ... | @@ -372,7 +376,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -372,7 +376,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 372 | 376 | ||
| 373 | // Boolean switch expression has duplicate case value. | 377 | // Boolean switch expression has duplicate case value. |
| 374 | case.addError( | 378 | case.addError( |
| 375 | \\export fn main() c_int { | 379 | \\pub export fn main() c_int { |
| 376 | \\ var a: bool = false; | 380 | \\ var a: bool = false; |
| 377 | \\ const b: c_int = switch (a) { | 381 | \\ const b: c_int = switch (a) { |
| 378 | \\ false => 1, | 382 | \\ false => 1, |
| ... | @@ -386,7 +390,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -386,7 +390,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 386 | 390 | ||
| 387 | // Sparse (no range capable) switch expression has duplicate case value. | 391 | // Sparse (no range capable) switch expression has duplicate case value. |
| 388 | case.addError( | 392 | case.addError( |
| 389 | \\export fn main() c_int { | 393 | \\pub export fn main() c_int { |
| 390 | \\ const A: type = i32; | 394 | \\ const A: type = i32; |
| 391 | \\ const b: c_int = switch (A) { | 395 | \\ const b: c_int = switch (A) { |
| 392 | \\ i32 => 1, | 396 | \\ i32 => 1, |
| ... | @@ -402,7 +406,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -402,7 +406,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 402 | 406 | ||
| 403 | // Ranges not allowed for some kinds of switches. | 407 | // Ranges not allowed for some kinds of switches. |
| 404 | case.addError( | 408 | case.addError( |
| 405 | \\export fn main() c_int { | 409 | \\pub export fn main() c_int { |
| 406 | \\ const A: type = i32; | 410 | \\ const A: type = i32; |
| 407 | \\ const b: c_int = switch (A) { | 411 | \\ const b: c_int = switch (A) { |
| 408 | \\ i32 => 1, | 412 | \\ i32 => 1, |
| ... | @@ -418,7 +422,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -418,7 +422,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 418 | 422 | ||
| 419 | // Switch expression has unreachable else prong. | 423 | // Switch expression has unreachable else prong. |
| 420 | case.addError( | 424 | case.addError( |
| 421 | \\export fn main() c_int { | 425 | \\pub export fn main() c_int { |
| 422 | \\ var a: u2 = 0; | 426 | \\ var a: u2 = 0; |
| 423 | \\ const b: i32 = switch (a) { | 427 | \\ const b: i32 = switch (a) { |
| 424 | \\ 0 => 10, | 428 | \\ 0 => 10, |
| ... | @@ -437,7 +441,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -437,7 +441,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 437 | 441 | ||
| 438 | // // Simple while loop | 442 | // // Simple while loop |
| 439 | // case.addCompareOutput( | 443 | // case.addCompareOutput( |
| 440 | // \\export fn main() c_int { | 444 | // \\pub export fn main() c_int { |
| 441 | // \\ var count: c_int = 0; | 445 | // \\ var count: c_int = 0; |
| 442 | // \\ var opt_ptr: ?*c_int = &count; | 446 | // \\ var opt_ptr: ?*c_int = &count; |
| 443 | // \\ while (opt_ptr) |_| : (count += 1) { | 447 | // \\ while (opt_ptr) |_| : (count += 1) { |
| ... | @@ -449,7 +453,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -449,7 +453,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 449 | 453 | ||
| 450 | // // Same with non pointer optionals | 454 | // // Same with non pointer optionals |
| 451 | // case.addCompareOutput( | 455 | // case.addCompareOutput( |
| 452 | // \\export fn main() c_int { | 456 | // \\pub export fn main() c_int { |
| 453 | // \\ var count: c_int = 0; | 457 | // \\ var count: c_int = 0; |
| 454 | // \\ var opt_ptr: ?c_int = count; | 458 | // \\ var opt_ptr: ?c_int = count; |
| 455 | // \\ while (opt_ptr) |_| : (count += 1) { | 459 | // \\ while (opt_ptr) |_| : (count += 1) { |
| ... | @@ -463,7 +467,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -463,7 +467,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 463 | { | 467 | { |
| 464 | var case = ctx.exeFromCompiledC("errors", .{}); | 468 | var case = ctx.exeFromCompiledC("errors", .{}); |
| 465 | case.addCompareOutput( | 469 | case.addCompareOutput( |
| 466 | \\export fn main() c_int { | 470 | \\pub export fn main() c_int { |
| 467 | \\ var e1 = error.Foo; | 471 | \\ var e1 = error.Foo; |
| 468 | \\ var e2 = error.Bar; | 472 | \\ var e2 = error.Bar; |
| 469 | \\ assert(e1 != e2); | 473 | \\ assert(e1 != e2); |
| ... | @@ -476,14 +480,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -476,14 +480,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 476 | \\} | 480 | \\} |
| 477 | , ""); | 481 | , ""); |
| 478 | case.addCompareOutput( | 482 | case.addCompareOutput( |
| 479 | \\export fn main() c_int { | 483 | \\pub export fn main() c_int { |
| 480 | \\ var e: anyerror!c_int = 0; | 484 | \\ var e: anyerror!c_int = 0; |
| 481 | \\ const i = e catch 69; | 485 | \\ const i = e catch 69; |
| 482 | \\ return i; | 486 | \\ return i; |
| 483 | \\} | 487 | \\} |
| 484 | , ""); | 488 | , ""); |
| 485 | case.addCompareOutput( | 489 | case.addCompareOutput( |
| 486 | \\export fn main() c_int { | 490 | \\pub export fn main() c_int { |
| 487 | \\ var e: anyerror!c_int = error.Foo; | 491 | \\ var e: anyerror!c_int = error.Foo; |
| 488 | \\ const i = e catch 69; | 492 | \\ const i = e catch 69; |
| 489 | \\ return 69 - i; | 493 | \\ return 69 - i; |
| ... | @@ -495,7 +499,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -495,7 +499,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 495 | var case = ctx.exeFromCompiledC("structs", .{}); | 499 | var case = ctx.exeFromCompiledC("structs", .{}); |
| 496 | case.addError( | 500 | case.addError( |
| 497 | \\const Point = struct { x: i32, y: i32 }; | 501 | \\const Point = struct { x: i32, y: i32 }; |
| 498 | \\export fn main() c_int { | 502 | \\pub export fn main() c_int { |
| 499 | \\ var p: Point = .{ | 503 | \\ var p: Point = .{ |
| 500 | \\ .y = 24, | 504 | \\ .y = 24, |
| 501 | \\ .x = 12, | 505 | \\ .x = 12, |
| ... | @@ -509,19 +513,19 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -509,19 +513,19 @@ pub fn addCases(ctx: *TestContext) !void { |
| 509 | }); | 513 | }); |
| 510 | case.addError( | 514 | case.addError( |
| 511 | \\const Point = struct { x: i32, y: i32 }; | 515 | \\const Point = struct { x: i32, y: i32 }; |
| 512 | \\export fn main() c_int { | 516 | \\pub export fn main() c_int { |
| 513 | \\ var p: Point = .{ | 517 | \\ var p: Point = .{ |
| 514 | \\ .y = 24, | 518 | \\ .y = 24, |
| 515 | \\ }; | 519 | \\ }; |
| 516 | \\ return p.y - p.x - p.x; | 520 | \\ return p.y - p.x - p.x; |
| 517 | \\} | 521 | \\} |
| 518 | , &.{ | 522 | , &.{ |
| 519 | ":3:21: error: mising struct field: x", | 523 | ":3:21: error: missing struct field: x", |
| 520 | ":1:15: note: struct 'Point' declared here", | 524 | ":1:15: note: struct 'test_case.Point' declared here", |
| 521 | }); | 525 | }); |
| 522 | case.addError( | 526 | case.addError( |
| 523 | \\const Point = struct { x: i32, y: i32 }; | 527 | \\const Point = struct { x: i32, y: i32 }; |
| 524 | \\export fn main() c_int { | 528 | \\pub export fn main() c_int { |
| 525 | \\ var p: Point = .{ | 529 | \\ var p: Point = .{ |
| 526 | \\ .x = 12, | 530 | \\ .x = 12, |
| 527 | \\ .y = 24, | 531 | \\ .y = 24, |
| ... | @@ -530,12 +534,12 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -530,12 +534,12 @@ pub fn addCases(ctx: *TestContext) !void { |
| 530 | \\ return p.y - p.x - p.x; | 534 | \\ return p.y - p.x - p.x; |
| 531 | \\} | 535 | \\} |
| 532 | , &.{ | 536 | , &.{ |
| 533 | ":6:10: error: no field named 'z' in struct 'Point'", | 537 | ":6:10: error: no field named 'z' in struct 'test_case.Point'", |
| 534 | ":1:15: note: struct declared here", | 538 | ":1:15: note: struct declared here", |
| 535 | }); | 539 | }); |
| 536 | case.addCompareOutput( | 540 | case.addCompareOutput( |
| 537 | \\const Point = struct { x: i32, y: i32 }; | 541 | \\const Point = struct { x: i32, y: i32 }; |
| 538 | \\export fn main() c_int { | 542 | \\pub export fn main() c_int { |
| 539 | \\ var p: Point = .{ | 543 | \\ var p: Point = .{ |
| 540 | \\ .x = 12, | 544 | \\ .x = 12, |
| 541 | \\ .y = 24, | 545 | \\ .y = 24, |
| ... | @@ -589,7 +593,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -589,7 +593,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 589 | case.addCompareOutput( | 593 | case.addCompareOutput( |
| 590 | \\const Number = enum { One, Two, Three }; | 594 | \\const Number = enum { One, Two, Three }; |
| 591 | \\ | 595 | \\ |
| 592 | \\export fn main() c_int { | 596 | \\pub export fn main() c_int { |
| 593 | \\ var number1 = Number.One; | 597 | \\ var number1 = Number.One; |
| 594 | \\ var number2: Number = .Two; | 598 | \\ var number2: Number = .Two; |
| 595 | \\ const number3 = @intToEnum(Number, 2); | 599 | \\ const number3 = @intToEnum(Number, 2); |
| ... | @@ -676,7 +680,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -676,7 +680,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 676 | 680 | ||
| 677 | case.addError( | 681 | case.addError( |
| 678 | \\const E1 = enum { a, b, c, b, d }; | 682 | \\const E1 = enum { a, b, c, b, d }; |
| 679 | \\export fn foo() void { | 683 | \\pub export fn main() c_int { |
| 680 | \\ const x = E1.a; | 684 | \\ const x = E1.a; |
| 681 | \\} | 685 | \\} |
| 682 | , &.{ | 686 | , &.{ |
| ... | @@ -685,7 +689,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -685,7 +689,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 685 | }); | 689 | }); |
| 686 | 690 | ||
| 687 | case.addError( | 691 | case.addError( |
| 688 | \\export fn foo() void { | 692 | \\pub export fn main() c_int { |
| 689 | \\ const a = true; | 693 | \\ const a = true; |
| 690 | \\ const b = @enumToInt(a); | 694 | \\ const b = @enumToInt(a); |
| 691 | \\} | 695 | \\} |
| ... | @@ -694,7 +698,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -694,7 +698,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 694 | }); | 698 | }); |
| 695 | 699 | ||
| 696 | case.addError( | 700 | case.addError( |
| 697 | \\export fn foo() void { | 701 | \\pub export fn main() c_int { |
| 698 | \\ const a = 1; | 702 | \\ const a = 1; |
| 699 | \\ const b = @intToEnum(bool, a); | 703 | \\ const b = @intToEnum(bool, a); |
| 700 | \\} | 704 | \\} |
| ... | @@ -704,17 +708,17 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -704,17 +708,17 @@ pub fn addCases(ctx: *TestContext) !void { |
| 704 | 708 | ||
| 705 | case.addError( | 709 | case.addError( |
| 706 | \\const E = enum { a, b, c }; | 710 | \\const E = enum { a, b, c }; |
| 707 | \\export fn foo() void { | 711 | \\pub export fn main() c_int { |
| 708 | \\ const b = @intToEnum(E, 3); | 712 | \\ const b = @intToEnum(E, 3); |
| 709 | \\} | 713 | \\} |
| 710 | , &.{ | 714 | , &.{ |
| 711 | ":3:15: error: enum 'E' has no tag with value 3", | 715 | ":3:15: error: enum 'test_case.E' has no tag with value 3", |
| 712 | ":1:11: note: enum declared here", | 716 | ":1:11: note: enum declared here", |
| 713 | }); | 717 | }); |
| 714 | 718 | ||
| 715 | case.addError( | 719 | case.addError( |
| 716 | \\const E = enum { a, b, c }; | 720 | \\const E = enum { a, b, c }; |
| 717 | \\export fn foo() void { | 721 | \\pub export fn main() c_int { |
| 718 | \\ var x: E = .a; | 722 | \\ var x: E = .a; |
| 719 | \\ switch (x) { | 723 | \\ switch (x) { |
| 720 | \\ .a => {}, | 724 | \\ .a => {}, |
| ... | @@ -724,12 +728,12 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -724,12 +728,12 @@ pub fn addCases(ctx: *TestContext) !void { |
| 724 | , &.{ | 728 | , &.{ |
| 725 | ":4:5: error: switch must handle all possibilities", | 729 | ":4:5: error: switch must handle all possibilities", |
| 726 | ":4:5: note: unhandled enumeration value: 'b'", | 730 | ":4:5: note: unhandled enumeration value: 'b'", |
| 727 | ":1:11: note: enum 'E' declared here", | 731 | ":1:11: note: enum 'test_case.E' declared here", |
| 728 | }); | 732 | }); |
| 729 | 733 | ||
| 730 | case.addError( | 734 | case.addError( |
| 731 | \\const E = enum { a, b, c }; | 735 | \\const E = enum { a, b, c }; |
| 732 | \\export fn foo() void { | 736 | \\pub export fn main() c_int { |
| 733 | \\ var x: E = .a; | 737 | \\ var x: E = .a; |
| 734 | \\ switch (x) { | 738 | \\ switch (x) { |
| 735 | \\ .a => {}, | 739 | \\ .a => {}, |
| ... | @@ -745,7 +749,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -745,7 +749,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 745 | 749 | ||
| 746 | case.addError( | 750 | case.addError( |
| 747 | \\const E = enum { a, b, c }; | 751 | \\const E = enum { a, b, c }; |
| 748 | \\export fn foo() void { | 752 | \\pub export fn main() c_int { |
| 749 | \\ var x: E = .a; | 753 | \\ var x: E = .a; |
| 750 | \\ switch (x) { | 754 | \\ switch (x) { |
| 751 | \\ .a => {}, | 755 | \\ .a => {}, |
| ... | @@ -760,7 +764,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -760,7 +764,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 760 | 764 | ||
| 761 | case.addError( | 765 | case.addError( |
| 762 | \\const E = enum { a, b, c }; | 766 | \\const E = enum { a, b, c }; |
| 763 | \\export fn foo() void { | 767 | \\pub export fn main() c_int { |
| 764 | \\ var x: E = .a; | 768 | \\ var x: E = .a; |
| 765 | \\ switch (x) { | 769 | \\ switch (x) { |
| 766 | \\ .a => {}, | 770 | \\ .a => {}, |
| ... | @@ -775,21 +779,21 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -775,21 +779,21 @@ pub fn addCases(ctx: *TestContext) !void { |
| 775 | 779 | ||
| 776 | case.addError( | 780 | case.addError( |
| 777 | \\const E = enum { a, b, c }; | 781 | \\const E = enum { a, b, c }; |
| 778 | \\export fn foo() void { | 782 | \\pub export fn main() c_int { |
| 779 | \\ var x = E.d; | 783 | \\ var x = E.d; |
| 780 | \\} | 784 | \\} |
| 781 | , &.{ | 785 | , &.{ |
| 782 | ":3:14: error: enum 'E' has no member named 'd'", | 786 | ":3:14: error: enum 'test_case.E' has no member named 'd'", |
| 783 | ":1:11: note: enum declared here", | 787 | ":1:11: note: enum declared here", |
| 784 | }); | 788 | }); |
| 785 | 789 | ||
| 786 | case.addError( | 790 | case.addError( |
| 787 | \\const E = enum { a, b, c }; | 791 | \\const E = enum { a, b, c }; |
| 788 | \\export fn foo() void { | 792 | \\pub export fn main() c_int { |
| 789 | \\ var x: E = .d; | 793 | \\ var x: E = .d; |
| 790 | \\} | 794 | \\} |
| 791 | , &.{ | 795 | , &.{ |
| 792 | ":3:17: error: enum 'E' has no field named 'd'", | 796 | ":3:17: error: enum 'test_case.E' has no field named 'd'", |
| 793 | ":1:11: note: enum declared here", | 797 | ":1:11: note: enum declared here", |
| 794 | }); | 798 | }); |
| 795 | } | 799 | } |
test/stage2/darwin.zig+13-9| ... | @@ -13,20 +13,24 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -13,20 +13,24 @@ pub fn addCases(ctx: *TestContext) !void { |
| 13 | }; | 13 | }; |
| 14 | { | 14 | { |
| 15 | var case = ctx.exe("hello world with updates", target); | 15 | var case = ctx.exe("hello world with updates", target); |
| 16 | case.addError("", &[_][]const u8{"error: no entry point found"}); | 16 | case.addError("", &[_][]const u8{ |
| 17 | ":84:9: error: struct 'test_case.test_case' has no member named 'main'", | ||
| 18 | }); | ||
| 17 | 19 | ||
| 18 | // Incorrect return type | 20 | // Incorrect return type |
| 19 | case.addError( | 21 | case.addError( |
| 20 | \\export fn main() noreturn { | 22 | \\pub export fn main() noreturn { |
| 21 | \\} | 23 | \\} |
| 22 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); | 24 | , &[_][]const u8{ |
| 25 | ":2:1: error: expected noreturn, found void", | ||
| 26 | }); | ||
| 23 | 27 | ||
| 24 | // Regular old hello world | 28 | // Regular old hello world |
| 25 | case.addCompareOutput( | 29 | case.addCompareOutput( |
| 26 | \\extern "c" fn write(usize, usize, usize) usize; | 30 | \\extern "c" fn write(usize, usize, usize) usize; |
| 27 | \\extern "c" fn exit(usize) noreturn; | 31 | \\extern "c" fn exit(usize) noreturn; |
| 28 | \\ | 32 | \\ |
| 29 | \\export fn main() noreturn { | 33 | \\pub export fn main() noreturn { |
| 30 | \\ print(); | 34 | \\ print(); |
| 31 | \\ | 35 | \\ |
| 32 | \\ exit(0); | 36 | \\ exit(0); |
| ... | @@ -46,7 +50,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -46,7 +50,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 46 | \\extern "c" fn write(usize, usize, usize) usize; | 50 | \\extern "c" fn write(usize, usize, usize) usize; |
| 47 | \\extern "c" fn exit(usize) noreturn; | 51 | \\extern "c" fn exit(usize) noreturn; |
| 48 | \\ | 52 | \\ |
| 49 | \\export fn main() noreturn { | 53 | \\pub export fn main() noreturn { |
| 50 | \\ print(); | 54 | \\ print(); |
| 51 | \\ print(); | 55 | \\ print(); |
| 52 | \\ print(); | 56 | \\ print(); |
| ... | @@ -73,7 +77,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -73,7 +77,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 73 | \\extern "c" fn write(usize, usize, usize) usize; | 77 | \\extern "c" fn write(usize, usize, usize) usize; |
| 74 | \\extern "c" fn exit(usize) noreturn; | 78 | \\extern "c" fn exit(usize) noreturn; |
| 75 | \\ | 79 | \\ |
| 76 | \\export fn main() noreturn { | 80 | \\pub export fn main() noreturn { |
| 77 | \\ print(); | 81 | \\ print(); |
| 78 | \\ | 82 | \\ |
| 79 | \\ exit(0); | 83 | \\ exit(0); |
| ... | @@ -93,7 +97,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -93,7 +97,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 93 | \\extern "c" fn write(usize, usize, usize) usize; | 97 | \\extern "c" fn write(usize, usize, usize) usize; |
| 94 | \\extern "c" fn exit(usize) noreturn; | 98 | \\extern "c" fn exit(usize) noreturn; |
| 95 | \\ | 99 | \\ |
| 96 | \\export fn main() noreturn { | 100 | \\pub export fn main() noreturn { |
| 97 | \\ print(); | 101 | \\ print(); |
| 98 | \\ print(); | 102 | \\ print(); |
| 99 | \\ | 103 | \\ |
| ... | @@ -119,7 +123,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -119,7 +123,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 119 | case.addCompareOutput( | 123 | case.addCompareOutput( |
| 120 | \\extern "c" fn exit(usize) noreturn; | 124 | \\extern "c" fn exit(usize) noreturn; |
| 121 | \\ | 125 | \\ |
| 122 | \\export fn main() noreturn { | 126 | \\pub export fn main() noreturn { |
| 123 | \\ exit(0); | 127 | \\ exit(0); |
| 124 | \\} | 128 | \\} |
| 125 | , | 129 | , |
| ... | @@ -130,7 +134,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -130,7 +134,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 130 | \\extern "c" fn exit(usize) noreturn; | 134 | \\extern "c" fn exit(usize) noreturn; |
| 131 | \\extern "c" fn write(usize, usize, usize) usize; | 135 | \\extern "c" fn write(usize, usize, usize) usize; |
| 132 | \\ | 136 | \\ |
| 133 | \\export fn main() noreturn { | 137 | \\pub export fn main() noreturn { |
| 134 | \\ _ = write(1, @ptrToInt("Hey!\n"), 5); | 138 | \\ _ = write(1, @ptrToInt("Hey!\n"), 5); |
| 135 | \\ exit(0); | 139 | \\ exit(0); |
| 136 | \\} | 140 | \\} |
test/stage2/llvm.zig+8-8| ... | @@ -18,7 +18,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -18,7 +18,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 18 | \\ return a + b; | 18 | \\ return a + b; |
| 19 | \\} | 19 | \\} |
| 20 | \\ | 20 | \\ |
| 21 | \\export fn main() c_int { | 21 | \\pub export fn main() c_int { |
| 22 | \\ var a: i32 = -5; | 22 | \\ var a: i32 = -5; |
| 23 | \\ const x = add(a, 7); | 23 | \\ const x = add(a, 7); |
| 24 | \\ var y = add(2, 0); | 24 | \\ var y = add(2, 0); |
| ... | @@ -34,7 +34,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -34,7 +34,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 34 | case.addCompareOutput( | 34 | case.addCompareOutput( |
| 35 | \\extern fn puts(s: [*:0]const u8) c_int; | 35 | \\extern fn puts(s: [*:0]const u8) c_int; |
| 36 | \\ | 36 | \\ |
| 37 | \\export fn main() c_int { | 37 | \\pub export fn main() c_int { |
| 38 | \\ _ = puts("hello world!"); | 38 | \\ _ = puts("hello world!"); |
| 39 | \\ return 0; | 39 | \\ return 0; |
| 40 | \\} | 40 | \\} |
| ... | @@ -53,7 +53,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -53,7 +53,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 53 | \\ if (!ok) unreachable; | 53 | \\ if (!ok) unreachable; |
| 54 | \\} | 54 | \\} |
| 55 | \\ | 55 | \\ |
| 56 | \\export fn main() c_int { | 56 | \\pub export fn main() c_int { |
| 57 | \\ assert(add(1,2) == 3); | 57 | \\ assert(add(1,2) == 3); |
| 58 | \\ return 0; | 58 | \\ return 0; |
| 59 | \\} | 59 | \\} |
| ... | @@ -77,7 +77,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -77,7 +77,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 77 | \\ return val + 10; | 77 | \\ return val + 10; |
| 78 | \\} | 78 | \\} |
| 79 | \\ | 79 | \\ |
| 80 | \\export fn main() c_int { | 80 | \\pub export fn main() c_int { |
| 81 | \\ assert(foo(false) == 20); | 81 | \\ assert(foo(false) == 20); |
| 82 | \\ assert(foo(true) == 30); | 82 | \\ assert(foo(true) == 30); |
| 83 | \\ return 0; | 83 | \\ return 0; |
| ... | @@ -104,7 +104,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -104,7 +104,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 104 | \\ return val; | 104 | \\ return val; |
| 105 | \\} | 105 | \\} |
| 106 | \\ | 106 | \\ |
| 107 | \\export fn main() c_int { | 107 | \\pub export fn main() c_int { |
| 108 | \\ assert(foo(false) == 10); | 108 | \\ assert(foo(false) == 10); |
| 109 | \\ assert(foo(true) == 20); | 109 | \\ assert(foo(true) == 20); |
| 110 | \\ return 0; | 110 | \\ return 0; |
| ... | @@ -120,7 +120,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -120,7 +120,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 120 | \\ if (!ok) unreachable; | 120 | \\ if (!ok) unreachable; |
| 121 | \\} | 121 | \\} |
| 122 | \\ | 122 | \\ |
| 123 | \\export fn main() c_int { | 123 | \\pub export fn main() c_int { |
| 124 | \\ var sum: u32 = 0; | 124 | \\ var sum: u32 = 0; |
| 125 | \\ var i: u32 = 0; | 125 | \\ var i: u32 = 0; |
| 126 | \\ while (i < 5) : (i += 1) { | 126 | \\ while (i < 5) : (i += 1) { |
| ... | @@ -141,7 +141,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -141,7 +141,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 141 | \\ if (!ok) unreachable; | 141 | \\ if (!ok) unreachable; |
| 142 | \\} | 142 | \\} |
| 143 | \\ | 143 | \\ |
| 144 | \\export fn main() c_int { | 144 | \\pub export fn main() c_int { |
| 145 | \\ var opt_val: ?i32 = 10; | 145 | \\ var opt_val: ?i32 = 10; |
| 146 | \\ var null_val: ?i32 = null; | 146 | \\ var null_val: ?i32 = null; |
| 147 | \\ | 147 | \\ |
| ... | @@ -190,7 +190,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -190,7 +190,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 190 | \\ if (!ok) unreachable; | 190 | \\ if (!ok) unreachable; |
| 191 | \\} | 191 | \\} |
| 192 | \\ | 192 | \\ |
| 193 | \\export fn main() c_int { | 193 | \\pub export fn main() c_int { |
| 194 | \\ var x: u32 = 0; | 194 | \\ var x: u32 = 0; |
| 195 | \\ for ("hello") |_| { | 195 | \\ for ("hello") |_| { |
| 196 | \\ x += 1; | 196 | \\ x += 1; |
test/stage2/riscv64.zig+1-1| ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 11 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | 11 | var case = ctx.exe("riscv64 hello world", linux_riscv64); |
| 12 | // Regular old hello world | 12 | // Regular old hello world |
| 13 | case.addCompareOutput( | 13 | case.addCompareOutput( |
| 14 | \\export fn _start() noreturn { | 14 | \\pub export fn _start() noreturn { |
| 15 | \\ print(); | 15 | \\ print(); |
| 16 | \\ | 16 | \\ |
| 17 | \\ exit(); | 17 | \\ exit(); |
test/stage2/spu-ii.zig deleted-23| ... | @@ -1,23 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const TestContext = @import("../../src/test.zig").TestContext; | ||
| 3 | |||
| 4 | const spu = std.zig.CrossTarget{ | ||
| 5 | .cpu_arch = .spu_2, | ||
| 6 | .os_tag = .freestanding, | ||
| 7 | }; | ||
| 8 | |||
| 9 | pub fn addCases(ctx: *TestContext) !void { | ||
| 10 | { | ||
| 11 | var case = ctx.exe("SPU-II Basic Test", spu); | ||
| 12 | case.addCompareOutput( | ||
| 13 | \\fn killEmulator() noreturn { | ||
| 14 | \\ asm volatile ("undefined0"); | ||
| 15 | \\ unreachable; | ||
| 16 | \\} | ||
| 17 | \\ | ||
| 18 | \\export fn _start() noreturn { | ||
| 19 | \\ killEmulator(); | ||
| 20 | \\} | ||
| 21 | , ""); | ||
| 22 | } | ||
| 23 | } | ||
test/stage2/test.zig+144-492| ... | @@ -13,7 +13,6 @@ const linux_x64 = std.zig.CrossTarget{ | ... | @@ -13,7 +13,6 @@ const linux_x64 = std.zig.CrossTarget{ |
| 13 | 13 | ||
| 14 | pub fn addCases(ctx: *TestContext) !void { | 14 | pub fn addCases(ctx: *TestContext) !void { |
| 15 | try @import("cbe.zig").addCases(ctx); | 15 | try @import("cbe.zig").addCases(ctx); |
| 16 | try @import("spu-ii.zig").addCases(ctx); | ||
| 17 | try @import("arm.zig").addCases(ctx); | 16 | try @import("arm.zig").addCases(ctx); |
| 18 | try @import("aarch64.zig").addCases(ctx); | 17 | try @import("aarch64.zig").addCases(ctx); |
| 19 | try @import("llvm.zig").addCases(ctx); | 18 | try @import("llvm.zig").addCases(ctx); |
| ... | @@ -24,17 +23,19 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -24,17 +23,19 @@ pub fn addCases(ctx: *TestContext) !void { |
| 24 | { | 23 | { |
| 25 | var case = ctx.exe("hello world with updates", linux_x64); | 24 | var case = ctx.exe("hello world with updates", linux_x64); |
| 26 | 25 | ||
| 27 | case.addError("", &[_][]const u8{"error: no entry point found"}); | 26 | case.addError("", &[_][]const u8{ |
| 27 | ":84:9: error: struct 'test_case.test_case' has no member named 'main'", | ||
| 28 | }); | ||
| 28 | 29 | ||
| 29 | // Incorrect return type | 30 | // Incorrect return type |
| 30 | case.addError( | 31 | case.addError( |
| 31 | \\export fn _start() noreturn { | 32 | \\pub export fn _start() noreturn { |
| 32 | \\} | 33 | \\} |
| 33 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); | 34 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); |
| 34 | 35 | ||
| 35 | // Regular old hello world | 36 | // Regular old hello world |
| 36 | case.addCompareOutput( | 37 | case.addCompareOutput( |
| 37 | \\export fn _start() noreturn { | 38 | \\pub export fn _start() noreturn { |
| 38 | \\ print(); | 39 | \\ print(); |
| 39 | \\ | 40 | \\ |
| 40 | \\ exit(); | 41 | \\ exit(); |
| ... | @@ -64,12 +65,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -64,12 +65,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 64 | , | 65 | , |
| 65 | "Hello, World!\n", | 66 | "Hello, World!\n", |
| 66 | ); | 67 | ); |
| 67 | // Now change the message only | 68 | |
| 69 | // Convert to pub fn main | ||
| 68 | case.addCompareOutput( | 70 | case.addCompareOutput( |
| 69 | \\export fn _start() noreturn { | 71 | \\pub fn main() void { |
| 70 | \\ print(); | 72 | \\ print(); |
| 71 | \\ | ||
| 72 | \\ exit(); | ||
| 73 | \\} | 73 | \\} |
| 74 | \\ | 74 | \\ |
| 75 | \\fn print() void { | 75 | \\fn print() void { |
| ... | @@ -77,32 +77,41 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -77,32 +77,41 @@ pub fn addCases(ctx: *TestContext) !void { |
| 77 | \\ : | 77 | \\ : |
| 78 | \\ : [number] "{rax}" (1), | 78 | \\ : [number] "{rax}" (1), |
| 79 | \\ [arg1] "{rdi}" (1), | 79 | \\ [arg1] "{rdi}" (1), |
| 80 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | 80 | \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), |
| 81 | \\ [arg3] "{rdx}" (104) | 81 | \\ [arg3] "{rdx}" (14) |
| 82 | \\ : "rcx", "r11", "memory" | 82 | \\ : "rcx", "r11", "memory" |
| 83 | \\ ); | 83 | \\ ); |
| 84 | \\ return; | 84 | \\ return; |
| 85 | \\} | 85 | \\} |
| 86 | , | ||
| 87 | "Hello, World!\n", | ||
| 88 | ); | ||
| 89 | |||
| 90 | // Now change the message only | ||
| 91 | case.addCompareOutput( | ||
| 92 | \\pub fn main() void { | ||
| 93 | \\ print(); | ||
| 94 | \\} | ||
| 86 | \\ | 95 | \\ |
| 87 | \\fn exit() noreturn { | 96 | \\fn print() void { |
| 88 | \\ asm volatile ("syscall" | 97 | \\ asm volatile ("syscall" |
| 89 | \\ : | 98 | \\ : |
| 90 | \\ : [number] "{rax}" (231), | 99 | \\ : [number] "{rax}" (1), |
| 91 | \\ [arg1] "{rdi}" (0) | 100 | \\ [arg1] "{rdi}" (1), |
| 101 | \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), | ||
| 102 | \\ [arg3] "{rdx}" (104) | ||
| 92 | \\ : "rcx", "r11", "memory" | 103 | \\ : "rcx", "r11", "memory" |
| 93 | \\ ); | 104 | \\ ); |
| 94 | \\ unreachable; | 105 | \\ return; |
| 95 | \\} | 106 | \\} |
| 96 | , | 107 | , |
| 97 | "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", | 108 | "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", |
| 98 | ); | 109 | ); |
| 99 | // Now we print it twice. | 110 | // Now we print it twice. |
| 100 | case.addCompareOutput( | 111 | case.addCompareOutput( |
| 101 | \\export fn _start() noreturn { | 112 | \\pub fn main() void { |
| 102 | \\ print(); | 113 | \\ print(); |
| 103 | \\ print(); | 114 | \\ print(); |
| 104 | \\ | ||
| 105 | \\ exit(); | ||
| 106 | \\} | 115 | \\} |
| 107 | \\ | 116 | \\ |
| 108 | \\fn print() void { | 117 | \\fn print() void { |
| ... | @@ -116,16 +125,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -116,16 +125,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 116 | \\ ); | 125 | \\ ); |
| 117 | \\ return; | 126 | \\ return; |
| 118 | \\} | 127 | \\} |
| 119 | \\ | ||
| 120 | \\fn exit() noreturn { | ||
| 121 | \\ asm volatile ("syscall" | ||
| 122 | \\ : | ||
| 123 | \\ : [number] "{rax}" (231), | ||
| 124 | \\ [arg1] "{rdi}" (0) | ||
| 125 | \\ : "rcx", "r11", "memory" | ||
| 126 | \\ ); | ||
| 127 | \\ unreachable; | ||
| 128 | \\} | ||
| 129 | , | 128 | , |
| 130 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | 129 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. |
| 131 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. | 130 | \\What is up? This is a longer message that will force the data to be relocated in virtual address space. |
| ... | @@ -136,7 +135,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -136,7 +135,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 136 | { | 135 | { |
| 137 | var case = ctx.exe("adding numbers at comptime", linux_x64); | 136 | var case = ctx.exe("adding numbers at comptime", linux_x64); |
| 138 | case.addCompareOutput( | 137 | case.addCompareOutput( |
| 139 | \\export fn _start() noreturn { | 138 | \\pub export fn _start() noreturn { |
| 140 | \\ asm volatile ("syscall" | 139 | \\ asm volatile ("syscall" |
| 141 | \\ : | 140 | \\ : |
| 142 | \\ : [number] "{rax}" (1), | 141 | \\ : [number] "{rax}" (1), |
| ... | @@ -161,7 +160,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -161,7 +160,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 161 | { | 160 | { |
| 162 | var case = ctx.exe("adding numbers at runtime and comptime", linux_x64); | 161 | var case = ctx.exe("adding numbers at runtime and comptime", linux_x64); |
| 163 | case.addCompareOutput( | 162 | case.addCompareOutput( |
| 164 | \\export fn _start() noreturn { | 163 | \\pub export fn _start() noreturn { |
| 165 | \\ add(3, 4); | 164 | \\ add(3, 4); |
| 166 | \\ | 165 | \\ |
| 167 | \\ exit(); | 166 | \\ exit(); |
| ... | @@ -185,7 +184,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -185,7 +184,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 185 | ); | 184 | ); |
| 186 | // comptime function call | 185 | // comptime function call |
| 187 | case.addCompareOutput( | 186 | case.addCompareOutput( |
| 188 | \\export fn _start() noreturn { | 187 | \\pub export fn _start() noreturn { |
| 189 | \\ exit(); | 188 | \\ exit(); |
| 190 | \\} | 189 | \\} |
| 191 | \\ | 190 | \\ |
| ... | @@ -209,7 +208,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -209,7 +208,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 209 | ); | 208 | ); |
| 210 | // Inline function call | 209 | // Inline function call |
| 211 | case.addCompareOutput( | 210 | case.addCompareOutput( |
| 212 | \\export fn _start() noreturn { | 211 | \\pub export fn _start() noreturn { |
| 213 | \\ var x: usize = 3; | 212 | \\ var x: usize = 3; |
| 214 | \\ const y = add(1, 2, x); | 213 | \\ const y = add(1, 2, x); |
| 215 | \\ exit(y - 6); | 214 | \\ exit(y - 6); |
| ... | @@ -236,25 +235,13 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -236,25 +235,13 @@ pub fn addCases(ctx: *TestContext) !void { |
| 236 | { | 235 | { |
| 237 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); | 236 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); |
| 238 | case.addCompareOutput( | 237 | case.addCompareOutput( |
| 239 | \\export fn _start() noreturn { | 238 | \\pub fn main() void { |
| 240 | \\ sub(7, 4); | 239 | \\ sub(7, 4); |
| 241 | \\ | ||
| 242 | \\ exit(); | ||
| 243 | \\} | 240 | \\} |
| 244 | \\ | 241 | \\ |
| 245 | \\fn sub(a: u32, b: u32) void { | 242 | \\fn sub(a: u32, b: u32) void { |
| 246 | \\ if (a - b != 3) unreachable; | 243 | \\ if (a - b != 3) unreachable; |
| 247 | \\} | 244 | \\} |
| 248 | \\ | ||
| 249 | \\fn exit() noreturn { | ||
| 250 | \\ asm volatile ("syscall" | ||
| 251 | \\ : | ||
| 252 | \\ : [number] "{rax}" (231), | ||
| 253 | \\ [arg1] "{rdi}" (0) | ||
| 254 | \\ : "rcx", "r11", "memory" | ||
| 255 | \\ ); | ||
| 256 | \\ unreachable; | ||
| 257 | \\} | ||
| 258 | , | 245 | , |
| 259 | "", | 246 | "", |
| 260 | ); | 247 | ); |
| ... | @@ -262,58 +249,33 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -262,58 +249,33 @@ pub fn addCases(ctx: *TestContext) !void { |
| 262 | { | 249 | { |
| 263 | var case = ctx.exe("@TypeOf", linux_x64); | 250 | var case = ctx.exe("@TypeOf", linux_x64); |
| 264 | case.addCompareOutput( | 251 | case.addCompareOutput( |
| 265 | \\export fn _start() noreturn { | 252 | \\pub fn main() void { |
| 266 | \\ var x: usize = 0; | 253 | \\ var x: usize = 0; |
| 267 | \\ const z = @TypeOf(x, @as(u128, 5)); | 254 | \\ const z = @TypeOf(x, @as(u128, 5)); |
| 268 | \\ assert(z == u128); | 255 | \\ assert(z == u128); |
| 269 | \\ | ||
| 270 | \\ exit(); | ||
| 271 | \\} | 256 | \\} |
| 272 | \\ | 257 | \\ |
| 273 | \\pub fn assert(ok: bool) void { | 258 | \\pub fn assert(ok: bool) void { |
| 274 | \\ if (!ok) unreachable; // assertion failure | 259 | \\ if (!ok) unreachable; // assertion failure |
| 275 | \\} | 260 | \\} |
| 276 | \\ | ||
| 277 | \\fn exit() noreturn { | ||
| 278 | \\ asm volatile ("syscall" | ||
| 279 | \\ : | ||
| 280 | \\ : [number] "{rax}" (231), | ||
| 281 | \\ [arg1] "{rdi}" (0) | ||
| 282 | \\ : "rcx", "r11", "memory" | ||
| 283 | \\ ); | ||
| 284 | \\ unreachable; | ||
| 285 | \\} | ||
| 286 | , | 261 | , |
| 287 | "", | 262 | "", |
| 288 | ); | 263 | ); |
| 289 | case.addCompareOutput( | 264 | case.addCompareOutput( |
| 290 | \\export fn _start() noreturn { | 265 | \\pub fn main() void { |
| 291 | \\ const z = @TypeOf(true); | 266 | \\ const z = @TypeOf(true); |
| 292 | \\ assert(z == bool); | 267 | \\ assert(z == bool); |
| 293 | \\ | ||
| 294 | \\ exit(); | ||
| 295 | \\} | 268 | \\} |
| 296 | \\ | 269 | \\ |
| 297 | \\pub fn assert(ok: bool) void { | 270 | \\pub fn assert(ok: bool) void { |
| 298 | \\ if (!ok) unreachable; // assertion failure | 271 | \\ if (!ok) unreachable; // assertion failure |
| 299 | \\} | 272 | \\} |
| 300 | \\ | ||
| 301 | \\fn exit() noreturn { | ||
| 302 | \\ asm volatile ("syscall" | ||
| 303 | \\ : | ||
| 304 | \\ : [number] "{rax}" (231), | ||
| 305 | \\ [arg1] "{rdi}" (0) | ||
| 306 | \\ : "rcx", "r11", "memory" | ||
| 307 | \\ ); | ||
| 308 | \\ unreachable; | ||
| 309 | \\} | ||
| 310 | , | 273 | , |
| 311 | "", | 274 | "", |
| 312 | ); | 275 | ); |
| 313 | case.addError( | 276 | case.addError( |
| 314 | \\export fn _start() noreturn { | 277 | \\pub fn main() void { |
| 315 | \\ const z = @TypeOf(true, 1); | 278 | \\ const z = @TypeOf(true, 1); |
| 316 | \\ unreachable; | ||
| 317 | \\} | 279 | \\} |
| 318 | , &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"}); | 280 | , &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"}); |
| 319 | } | 281 | } |
| ... | @@ -321,7 +283,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -321,7 +283,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 321 | { | 283 | { |
| 322 | var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64); | 284 | var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64); |
| 323 | case.addCompareOutput( | 285 | case.addCompareOutput( |
| 324 | \\export fn _start() noreturn { | 286 | \\pub export fn _start() noreturn { |
| 325 | \\ mul(3, 4); | 287 | \\ mul(3, 4); |
| 326 | \\ | 288 | \\ |
| 327 | \\ exit(); | 289 | \\ exit(); |
| ... | @@ -345,7 +307,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -345,7 +307,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 345 | ); | 307 | ); |
| 346 | // comptime function call | 308 | // comptime function call |
| 347 | case.addCompareOutput( | 309 | case.addCompareOutput( |
| 348 | \\export fn _start() noreturn { | 310 | \\pub fn _start() noreturn { |
| 349 | \\ exit(); | 311 | \\ exit(); |
| 350 | \\} | 312 | \\} |
| 351 | \\ | 313 | \\ |
| ... | @@ -369,7 +331,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -369,7 +331,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 369 | ); | 331 | ); |
| 370 | // Inline function call | 332 | // Inline function call |
| 371 | case.addCompareOutput( | 333 | case.addCompareOutput( |
| 372 | \\export fn _start() noreturn { | 334 | \\pub export fn _start() noreturn { |
| 373 | \\ var x: usize = 5; | 335 | \\ var x: usize = 5; |
| 374 | \\ const y = mul(2, 3, x); | 336 | \\ const y = mul(2, 3, x); |
| 375 | \\ exit(y - 30); | 337 | \\ exit(y - 30); |
| ... | @@ -396,10 +358,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -396,10 +358,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 396 | { | 358 | { |
| 397 | var case = ctx.exe("assert function", linux_x64); | 359 | var case = ctx.exe("assert function", linux_x64); |
| 398 | case.addCompareOutput( | 360 | case.addCompareOutput( |
| 399 | \\export fn _start() noreturn { | 361 | \\pub fn main() void { |
| 400 | \\ add(3, 4); | 362 | \\ add(3, 4); |
| 401 | \\ | ||
| 402 | \\ exit(); | ||
| 403 | \\} | 363 | \\} |
| 404 | \\ | 364 | \\ |
| 405 | \\fn add(a: u32, b: u32) void { | 365 | \\fn add(a: u32, b: u32) void { |
| ... | @@ -426,10 +386,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -426,10 +386,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 426 | // Tests copying a register. For the `c = a + b`, it has to | 386 | // Tests copying a register. For the `c = a + b`, it has to |
| 427 | // preserve both a and b, because they are both used later. | 387 | // preserve both a and b, because they are both used later. |
| 428 | case.addCompareOutput( | 388 | case.addCompareOutput( |
| 429 | \\export fn _start() noreturn { | 389 | \\pub fn main() void { |
| 430 | \\ add(3, 4); | 390 | \\ add(3, 4); |
| 431 | \\ | ||
| 432 | \\ exit(); | ||
| 433 | \\} | 391 | \\} |
| 434 | \\ | 392 | \\ |
| 435 | \\fn add(a: u32, b: u32) void { | 393 | \\fn add(a: u32, b: u32) void { |
| ... | @@ -442,26 +400,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -442,26 +400,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 442 | \\pub fn assert(ok: bool) void { | 400 | \\pub fn assert(ok: bool) void { |
| 443 | \\ if (!ok) unreachable; // assertion failure | 401 | \\ if (!ok) unreachable; // assertion failure |
| 444 | \\} | 402 | \\} |
| 445 | \\ | ||
| 446 | \\fn exit() noreturn { | ||
| 447 | \\ asm volatile ("syscall" | ||
| 448 | \\ : | ||
| 449 | \\ : [number] "{rax}" (231), | ||
| 450 | \\ [arg1] "{rdi}" (0) | ||
| 451 | \\ : "rcx", "r11", "memory" | ||
| 452 | \\ ); | ||
| 453 | \\ unreachable; | ||
| 454 | \\} | ||
| 455 | , | 403 | , |
| 456 | "", | 404 | "", |
| 457 | ); | 405 | ); |
| 458 | 406 | ||
| 459 | // More stress on the liveness detection. | 407 | // More stress on the liveness detection. |
| 460 | case.addCompareOutput( | 408 | case.addCompareOutput( |
| 461 | \\export fn _start() noreturn { | 409 | \\pub fn main() void { |
| 462 | \\ add(3, 4); | 410 | \\ add(3, 4); |
| 463 | \\ | ||
| 464 | \\ exit(); | ||
| 465 | \\} | 411 | \\} |
| 466 | \\ | 412 | \\ |
| 467 | \\fn add(a: u32, b: u32) void { | 413 | \\fn add(a: u32, b: u32) void { |
| ... | @@ -478,26 +424,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -478,26 +424,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 478 | \\pub fn assert(ok: bool) void { | 424 | \\pub fn assert(ok: bool) void { |
| 479 | \\ if (!ok) unreachable; // assertion failure | 425 | \\ if (!ok) unreachable; // assertion failure |
| 480 | \\} | 426 | \\} |
| 481 | \\ | ||
| 482 | \\fn exit() noreturn { | ||
| 483 | \\ asm volatile ("syscall" | ||
| 484 | \\ : | ||
| 485 | \\ : [number] "{rax}" (231), | ||
| 486 | \\ [arg1] "{rdi}" (0) | ||
| 487 | \\ : "rcx", "r11", "memory" | ||
| 488 | \\ ); | ||
| 489 | \\ unreachable; | ||
| 490 | \\} | ||
| 491 | , | 427 | , |
| 492 | "", | 428 | "", |
| 493 | ); | 429 | ); |
| 494 | 430 | ||
| 495 | // Requires a second move. The register allocator should figure out to re-use rax. | 431 | // Requires a second move. The register allocator should figure out to re-use rax. |
| 496 | case.addCompareOutput( | 432 | case.addCompareOutput( |
| 497 | \\export fn _start() noreturn { | 433 | \\pub fn main() void { |
| 498 | \\ add(3, 4); | 434 | \\ add(3, 4); |
| 499 | \\ | ||
| 500 | \\ exit(); | ||
| 501 | \\} | 435 | \\} |
| 502 | \\ | 436 | \\ |
| 503 | \\fn add(a: u32, b: u32) void { | 437 | \\fn add(a: u32, b: u32) void { |
| ... | @@ -515,27 +449,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -515,27 +449,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 515 | \\pub fn assert(ok: bool) void { | 449 | \\pub fn assert(ok: bool) void { |
| 516 | \\ if (!ok) unreachable; // assertion failure | 450 | \\ if (!ok) unreachable; // assertion failure |
| 517 | \\} | 451 | \\} |
| 518 | \\ | ||
| 519 | \\fn exit() noreturn { | ||
| 520 | \\ asm volatile ("syscall" | ||
| 521 | \\ : | ||
| 522 | \\ : [number] "{rax}" (231), | ||
| 523 | \\ [arg1] "{rdi}" (0) | ||
| 524 | \\ : "rcx", "r11", "memory" | ||
| 525 | \\ ); | ||
| 526 | \\ unreachable; | ||
| 527 | \\} | ||
| 528 | , | 452 | , |
| 529 | "", | 453 | "", |
| 530 | ); | 454 | ); |
| 531 | 455 | ||
| 532 | // Now we test integer return values. | 456 | // Now we test integer return values. |
| 533 | case.addCompareOutput( | 457 | case.addCompareOutput( |
| 534 | \\export fn _start() noreturn { | 458 | \\pub fn main() void { |
| 535 | \\ assert(add(3, 4) == 7); | 459 | \\ assert(add(3, 4) == 7); |
| 536 | \\ assert(add(20, 10) == 30); | 460 | \\ assert(add(20, 10) == 30); |
| 537 | \\ | ||
| 538 | \\ exit(); | ||
| 539 | \\} | 461 | \\} |
| 540 | \\ | 462 | \\ |
| 541 | \\fn add(a: u32, b: u32) u32 { | 463 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -545,27 +467,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -545,27 +467,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 545 | \\pub fn assert(ok: bool) void { | 467 | \\pub fn assert(ok: bool) void { |
| 546 | \\ if (!ok) unreachable; // assertion failure | 468 | \\ if (!ok) unreachable; // assertion failure |
| 547 | \\} | 469 | \\} |
| 548 | \\ | ||
| 549 | \\fn exit() noreturn { | ||
| 550 | \\ asm volatile ("syscall" | ||
| 551 | \\ : | ||
| 552 | \\ : [number] "{rax}" (231), | ||
| 553 | \\ [arg1] "{rdi}" (0) | ||
| 554 | \\ : "rcx", "r11", "memory" | ||
| 555 | \\ ); | ||
| 556 | \\ unreachable; | ||
| 557 | \\} | ||
| 558 | , | 470 | , |
| 559 | "", | 471 | "", |
| 560 | ); | 472 | ); |
| 561 | 473 | ||
| 562 | // Local mutable variables. | 474 | // Local mutable variables. |
| 563 | case.addCompareOutput( | 475 | case.addCompareOutput( |
| 564 | \\export fn _start() noreturn { | 476 | \\pub fn main() void { |
| 565 | \\ assert(add(3, 4) == 7); | 477 | \\ assert(add(3, 4) == 7); |
| 566 | \\ assert(add(20, 10) == 30); | 478 | \\ assert(add(20, 10) == 30); |
| 567 | \\ | ||
| 568 | \\ exit(); | ||
| 569 | \\} | 479 | \\} |
| 570 | \\ | 480 | \\ |
| 571 | \\fn add(a: u32, b: u32) u32 { | 481 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -579,39 +489,17 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -579,39 +489,17 @@ pub fn addCases(ctx: *TestContext) !void { |
| 579 | \\pub fn assert(ok: bool) void { | 489 | \\pub fn assert(ok: bool) void { |
| 580 | \\ if (!ok) unreachable; // assertion failure | 490 | \\ if (!ok) unreachable; // assertion failure |
| 581 | \\} | 491 | \\} |
| 582 | \\ | ||
| 583 | \\fn exit() noreturn { | ||
| 584 | \\ asm volatile ("syscall" | ||
| 585 | \\ : | ||
| 586 | \\ : [number] "{rax}" (231), | ||
| 587 | \\ [arg1] "{rdi}" (0) | ||
| 588 | \\ : "rcx", "r11", "memory" | ||
| 589 | \\ ); | ||
| 590 | \\ unreachable; | ||
| 591 | \\} | ||
| 592 | , | 492 | , |
| 593 | "", | 493 | "", |
| 594 | ); | 494 | ); |
| 595 | 495 | ||
| 596 | // Optionals | 496 | // Optionals |
| 597 | case.addCompareOutput( | 497 | case.addCompareOutput( |
| 598 | \\export fn _start() noreturn { | 498 | \\pub fn main() void { |
| 599 | \\ const a: u32 = 2; | 499 | \\ const a: u32 = 2; |
| 600 | \\ const b: ?u32 = a; | 500 | \\ const b: ?u32 = a; |
| 601 | \\ const c = b.?; | 501 | \\ const c = b.?; |
| 602 | \\ if (c != 2) unreachable; | 502 | \\ if (c != 2) unreachable; |
| 603 | \\ | ||
| 604 | \\ exit(); | ||
| 605 | \\} | ||
| 606 | \\ | ||
| 607 | \\fn exit() noreturn { | ||
| 608 | \\ asm volatile ("syscall" | ||
| 609 | \\ : | ||
| 610 | \\ : [number] "{rax}" (231), | ||
| 611 | \\ [arg1] "{rdi}" (0) | ||
| 612 | \\ : "rcx", "r11", "memory" | ||
| 613 | \\ ); | ||
| 614 | \\ unreachable; | ||
| 615 | \\} | 503 | \\} |
| 616 | , | 504 | , |
| 617 | "", | 505 | "", |
| ... | @@ -619,12 +507,10 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -619,12 +507,10 @@ pub fn addCases(ctx: *TestContext) !void { |
| 619 | 507 | ||
| 620 | // While loops | 508 | // While loops |
| 621 | case.addCompareOutput( | 509 | case.addCompareOutput( |
| 622 | \\export fn _start() noreturn { | 510 | \\pub fn main() void { |
| 623 | \\ var i: u32 = 0; | 511 | \\ var i: u32 = 0; |
| 624 | \\ while (i < 4) : (i += 1) print(); | 512 | \\ while (i < 4) : (i += 1) print(); |
| 625 | \\ assert(i == 4); | 513 | \\ assert(i == 4); |
| 626 | \\ | ||
| 627 | \\ exit(); | ||
| 628 | \\} | 514 | \\} |
| 629 | \\ | 515 | \\ |
| 630 | \\fn print() void { | 516 | \\fn print() void { |
| ... | @@ -642,28 +528,16 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -642,28 +528,16 @@ pub fn addCases(ctx: *TestContext) !void { |
| 642 | \\pub fn assert(ok: bool) void { | 528 | \\pub fn assert(ok: bool) void { |
| 643 | \\ if (!ok) unreachable; // assertion failure | 529 | \\ if (!ok) unreachable; // assertion failure |
| 644 | \\} | 530 | \\} |
| 645 | \\ | ||
| 646 | \\fn exit() noreturn { | ||
| 647 | \\ asm volatile ("syscall" | ||
| 648 | \\ : | ||
| 649 | \\ : [number] "{rax}" (231), | ||
| 650 | \\ [arg1] "{rdi}" (0) | ||
| 651 | \\ : "rcx", "r11", "memory" | ||
| 652 | \\ ); | ||
| 653 | \\ unreachable; | ||
| 654 | \\} | ||
| 655 | , | 531 | , |
| 656 | "hello\nhello\nhello\nhello\n", | 532 | "hello\nhello\nhello\nhello\n", |
| 657 | ); | 533 | ); |
| 658 | 534 | ||
| 659 | // inline while requires the condition to be comptime known. | 535 | // inline while requires the condition to be comptime known. |
| 660 | case.addError( | 536 | case.addError( |
| 661 | \\export fn _start() noreturn { | 537 | \\pub fn main() void { |
| 662 | \\ var i: u32 = 0; | 538 | \\ var i: u32 = 0; |
| 663 | \\ inline while (i < 4) : (i += 1) print(); | 539 | \\ inline while (i < 4) : (i += 1) print(); |
| 664 | \\ assert(i == 4); | 540 | \\ assert(i == 4); |
| 665 | \\ | ||
| 666 | \\ exit(); | ||
| 667 | \\} | 541 | \\} |
| 668 | \\ | 542 | \\ |
| 669 | \\fn print() void { | 543 | \\fn print() void { |
| ... | @@ -681,24 +555,12 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -681,24 +555,12 @@ pub fn addCases(ctx: *TestContext) !void { |
| 681 | \\pub fn assert(ok: bool) void { | 555 | \\pub fn assert(ok: bool) void { |
| 682 | \\ if (!ok) unreachable; // assertion failure | 556 | \\ if (!ok) unreachable; // assertion failure |
| 683 | \\} | 557 | \\} |
| 684 | \\ | ||
| 685 | \\fn exit() noreturn { | ||
| 686 | \\ asm volatile ("syscall" | ||
| 687 | \\ : | ||
| 688 | \\ : [number] "{rax}" (231), | ||
| 689 | \\ [arg1] "{rdi}" (0) | ||
| 690 | \\ : "rcx", "r11", "memory" | ||
| 691 | \\ ); | ||
| 692 | \\ unreachable; | ||
| 693 | \\} | ||
| 694 | , &[_][]const u8{":3:21: error: unable to resolve comptime value"}); | 558 | , &[_][]const u8{":3:21: error: unable to resolve comptime value"}); |
| 695 | 559 | ||
| 696 | // Labeled blocks (no conditional branch) | 560 | // Labeled blocks (no conditional branch) |
| 697 | case.addCompareOutput( | 561 | case.addCompareOutput( |
| 698 | \\export fn _start() noreturn { | 562 | \\pub fn main() void { |
| 699 | \\ assert(add(3, 4) == 20); | 563 | \\ assert(add(3, 4) == 20); |
| 700 | \\ | ||
| 701 | \\ exit(); | ||
| 702 | \\} | 564 | \\} |
| 703 | \\ | 565 | \\ |
| 704 | \\fn add(a: u32, b: u32) u32 { | 566 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -716,26 +578,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -716,26 +578,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 716 | \\pub fn assert(ok: bool) void { | 578 | \\pub fn assert(ok: bool) void { |
| 717 | \\ if (!ok) unreachable; // assertion failure | 579 | \\ if (!ok) unreachable; // assertion failure |
| 718 | \\} | 580 | \\} |
| 719 | \\ | ||
| 720 | \\fn exit() noreturn { | ||
| 721 | \\ asm volatile ("syscall" | ||
| 722 | \\ : | ||
| 723 | \\ : [number] "{rax}" (231), | ||
| 724 | \\ [arg1] "{rdi}" (0) | ||
| 725 | \\ : "rcx", "r11", "memory" | ||
| 726 | \\ ); | ||
| 727 | \\ unreachable; | ||
| 728 | \\} | ||
| 729 | , | 581 | , |
| 730 | "", | 582 | "", |
| 731 | ); | 583 | ); |
| 732 | 584 | ||
| 733 | // This catches a possible bug in the logic for re-using dying operands. | 585 | // This catches a possible bug in the logic for re-using dying operands. |
| 734 | case.addCompareOutput( | 586 | case.addCompareOutput( |
| 735 | \\export fn _start() noreturn { | 587 | \\pub fn main() void { |
| 736 | \\ assert(add(3, 4) == 116); | 588 | \\ assert(add(3, 4) == 116); |
| 737 | \\ | ||
| 738 | \\ exit(); | ||
| 739 | \\} | 589 | \\} |
| 740 | \\ | 590 | \\ |
| 741 | \\fn add(a: u32, b: u32) u32 { | 591 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -758,27 +608,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -758,27 +608,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 758 | \\pub fn assert(ok: bool) void { | 608 | \\pub fn assert(ok: bool) void { |
| 759 | \\ if (!ok) unreachable; // assertion failure | 609 | \\ if (!ok) unreachable; // assertion failure |
| 760 | \\} | 610 | \\} |
| 761 | \\ | ||
| 762 | \\fn exit() noreturn { | ||
| 763 | \\ asm volatile ("syscall" | ||
| 764 | \\ : | ||
| 765 | \\ : [number] "{rax}" (231), | ||
| 766 | \\ [arg1] "{rdi}" (0) | ||
| 767 | \\ : "rcx", "r11", "memory" | ||
| 768 | \\ ); | ||
| 769 | \\ unreachable; | ||
| 770 | \\} | ||
| 771 | , | 611 | , |
| 772 | "", | 612 | "", |
| 773 | ); | 613 | ); |
| 774 | 614 | ||
| 775 | // Spilling registers to the stack. | 615 | // Spilling registers to the stack. |
| 776 | case.addCompareOutput( | 616 | case.addCompareOutput( |
| 777 | \\export fn _start() noreturn { | 617 | \\pub fn main() void { |
| 778 | \\ assert(add(3, 4) == 1221); | 618 | \\ assert(add(3, 4) == 1221); |
| 779 | \\ assert(mul(3, 4) == 21609); | 619 | \\ assert(mul(3, 4) == 21609); |
| 780 | \\ | ||
| 781 | \\ exit(); | ||
| 782 | \\} | 620 | \\} |
| 783 | \\ | 621 | \\ |
| 784 | \\fn add(a: u32, b: u32) u32 { | 622 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -839,27 +677,15 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -839,27 +677,15 @@ pub fn addCases(ctx: *TestContext) !void { |
| 839 | \\pub fn assert(ok: bool) void { | 677 | \\pub fn assert(ok: bool) void { |
| 840 | \\ if (!ok) unreachable; // assertion failure | 678 | \\ if (!ok) unreachable; // assertion failure |
| 841 | \\} | 679 | \\} |
| 842 | \\ | ||
| 843 | \\fn exit() noreturn { | ||
| 844 | \\ asm volatile ("syscall" | ||
| 845 | \\ : | ||
| 846 | \\ : [number] "{rax}" (231), | ||
| 847 | \\ [arg1] "{rdi}" (0) | ||
| 848 | \\ : "rcx", "r11", "memory" | ||
| 849 | \\ ); | ||
| 850 | \\ unreachable; | ||
| 851 | \\} | ||
| 852 | , | 680 | , |
| 853 | "", | 681 | "", |
| 854 | ); | 682 | ); |
| 855 | 683 | ||
| 856 | // Reusing the registers of dead operands playing nicely with conditional branching. | 684 | // Reusing the registers of dead operands playing nicely with conditional branching. |
| 857 | case.addCompareOutput( | 685 | case.addCompareOutput( |
| 858 | \\export fn _start() noreturn { | 686 | \\pub fn main() void { |
| 859 | \\ assert(add(3, 4) == 791); | 687 | \\ assert(add(3, 4) == 791); |
| 860 | \\ assert(add(4, 3) == 79); | 688 | \\ assert(add(4, 3) == 79); |
| 861 | \\ | ||
| 862 | \\ exit(); | ||
| 863 | \\} | 689 | \\} |
| 864 | \\ | 690 | \\ |
| 865 | \\fn add(a: u32, b: u32) u32 { | 691 | \\fn add(a: u32, b: u32) u32 { |
| ... | @@ -901,30 +727,18 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -901,30 +727,18 @@ pub fn addCases(ctx: *TestContext) !void { |
| 901 | \\pub fn assert(ok: bool) void { | 727 | \\pub fn assert(ok: bool) void { |
| 902 | \\ if (!ok) unreachable; // assertion failure | 728 | \\ if (!ok) unreachable; // assertion failure |
| 903 | \\} | 729 | \\} |
| 904 | \\ | ||
| 905 | \\fn exit() noreturn { | ||
| 906 | \\ asm volatile ("syscall" | ||
| 907 | \\ : | ||
| 908 | \\ : [number] "{rax}" (231), | ||
| 909 | \\ [arg1] "{rdi}" (0) | ||
| 910 | \\ : "rcx", "r11", "memory" | ||
| 911 | \\ ); | ||
| 912 | \\ unreachable; | ||
| 913 | \\} | ||
| 914 | , | 730 | , |
| 915 | "", | 731 | "", |
| 916 | ); | 732 | ); |
| 917 | 733 | ||
| 918 | // Character literals and multiline strings. | 734 | // Character literals and multiline strings. |
| 919 | case.addCompareOutput( | 735 | case.addCompareOutput( |
| 920 | \\export fn _start() noreturn { | 736 | \\pub fn main() void { |
| 921 | \\ const ignore = | 737 | \\ const ignore = |
| 922 | \\ \\ cool thx | 738 | \\ \\ cool thx |
| 923 | \\ \\ | 739 | \\ \\ |
| 924 | \\ ; | 740 | \\ ; |
| 925 | \\ add('ぁ', '\x03'); | 741 | \\ add('ぁ', '\x03'); |
| 926 | \\ | ||
| 927 | \\ exit(); | ||
| 928 | \\} | 742 | \\} |
| 929 | \\ | 743 | \\ |
| 930 | \\fn add(a: u32, b: u32) void { | 744 | \\fn add(a: u32, b: u32) void { |
| ... | @@ -934,26 +748,14 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -934,26 +748,14 @@ pub fn addCases(ctx: *TestContext) !void { |
| 934 | \\pub fn assert(ok: bool) void { | 748 | \\pub fn assert(ok: bool) void { |
| 935 | \\ if (!ok) unreachable; // assertion failure | 749 | \\ if (!ok) unreachable; // assertion failure |
| 936 | \\} | 750 | \\} |
| 937 | \\ | ||
| 938 | \\fn exit() noreturn { | ||
| 939 | \\ asm volatile ("syscall" | ||
| 940 | \\ : | ||
| 941 | \\ : [number] "{rax}" (231), | ||
| 942 | \\ [arg1] "{rdi}" (0) | ||
| 943 | \\ : "rcx", "r11", "memory" | ||
| 944 | \\ ); | ||
| 945 | \\ unreachable; | ||
| 946 | \\} | ||
| 947 | , | 751 | , |
| 948 | "", | 752 | "", |
| 949 | ); | 753 | ); |
| 950 | 754 | ||
| 951 | // Global const. | 755 | // Global const. |
| 952 | case.addCompareOutput( | 756 | case.addCompareOutput( |
| 953 | \\export fn _start() noreturn { | 757 | \\pub fn main() void { |
| 954 | \\ add(aa, bb); | 758 | \\ add(aa, bb); |
| 955 | \\ | ||
| 956 | \\ exit(); | ||
| 957 | \\} | 759 | \\} |
| 958 | \\ | 760 | \\ |
| 959 | \\const aa = 'ぁ'; | 761 | \\const aa = 'ぁ'; |
| ... | @@ -966,41 +768,19 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -966,41 +768,19 @@ pub fn addCases(ctx: *TestContext) !void { |
| 966 | \\pub fn assert(ok: bool) void { | 768 | \\pub fn assert(ok: bool) void { |
| 967 | \\ if (!ok) unreachable; // assertion failure | 769 | \\ if (!ok) unreachable; // assertion failure |
| 968 | \\} | 770 | \\} |
| 969 | \\ | ||
| 970 | \\fn exit() noreturn { | ||
| 971 | \\ asm volatile ("syscall" | ||
| 972 | \\ : | ||
| 973 | \\ : [number] "{rax}" (231), | ||
| 974 | \\ [arg1] "{rdi}" (0) | ||
| 975 | \\ : "rcx", "r11", "memory" | ||
| 976 | \\ ); | ||
| 977 | \\ unreachable; | ||
| 978 | \\} | ||
| 979 | , | 771 | , |
| 980 | "", | 772 | "", |
| 981 | ); | 773 | ); |
| 982 | 774 | ||
| 983 | // Array access. | 775 | // Array access. |
| 984 | case.addCompareOutput( | 776 | case.addCompareOutput( |
| 985 | \\export fn _start() noreturn { | 777 | \\pub fn main() void { |
| 986 | \\ assert("hello"[0] == 'h'); | 778 | \\ assert("hello"[0] == 'h'); |
| 987 | \\ | ||
| 988 | \\ exit(); | ||
| 989 | \\} | 779 | \\} |
| 990 | \\ | 780 | \\ |
| 991 | \\pub fn assert(ok: bool) void { | 781 | \\pub fn assert(ok: bool) void { |
| 992 | \\ if (!ok) unreachable; // assertion failure | 782 | \\ if (!ok) unreachable; // assertion failure |
| 993 | \\} | 783 | \\} |
| 994 | \\ | ||
| 995 | \\fn exit() noreturn { | ||
| 996 | \\ asm volatile ("syscall" | ||
| 997 | \\ : | ||
| 998 | \\ : [number] "{rax}" (231), | ||
| 999 | \\ [arg1] "{rdi}" (0) | ||
| 1000 | \\ : "rcx", "r11", "memory" | ||
| 1001 | \\ ); | ||
| 1002 | \\ unreachable; | ||
| 1003 | \\} | ||
| 1004 | , | 784 | , |
| 1005 | "", | 785 | "", |
| 1006 | ); | 786 | ); |
| ... | @@ -1008,61 +788,35 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1008,61 +788,35 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1008 | // Array access to a global array. | 788 | // Array access to a global array. |
| 1009 | case.addCompareOutput( | 789 | case.addCompareOutput( |
| 1010 | \\const hello = "hello".*; | 790 | \\const hello = "hello".*; |
| 1011 | \\export fn _start() noreturn { | 791 | \\pub fn main() void { |
| 1012 | \\ assert(hello[1] == 'e'); | 792 | \\ assert(hello[1] == 'e'); |
| 1013 | \\ | ||
| 1014 | \\ exit(); | ||
| 1015 | \\} | 793 | \\} |
| 1016 | \\ | 794 | \\ |
| 1017 | \\pub fn assert(ok: bool) void { | 795 | \\pub fn assert(ok: bool) void { |
| 1018 | \\ if (!ok) unreachable; // assertion failure | 796 | \\ if (!ok) unreachable; // assertion failure |
| 1019 | \\} | 797 | \\} |
| 1020 | \\ | ||
| 1021 | \\fn exit() noreturn { | ||
| 1022 | \\ asm volatile ("syscall" | ||
| 1023 | \\ : | ||
| 1024 | \\ : [number] "{rax}" (231), | ||
| 1025 | \\ [arg1] "{rdi}" (0) | ||
| 1026 | \\ : "rcx", "r11", "memory" | ||
| 1027 | \\ ); | ||
| 1028 | \\ unreachable; | ||
| 1029 | \\} | ||
| 1030 | , | 798 | , |
| 1031 | "", | 799 | "", |
| 1032 | ); | 800 | ); |
| 1033 | 801 | ||
| 1034 | // 64bit set stack | 802 | // 64bit set stack |
| 1035 | case.addCompareOutput( | 803 | case.addCompareOutput( |
| 1036 | \\export fn _start() noreturn { | 804 | \\pub fn main() void { |
| 1037 | \\ var i: u64 = 0xFFEEDDCCBBAA9988; | 805 | \\ var i: u64 = 0xFFEEDDCCBBAA9988; |
| 1038 | \\ assert(i == 0xFFEEDDCCBBAA9988); | 806 | \\ assert(i == 0xFFEEDDCCBBAA9988); |
| 1039 | \\ | ||
| 1040 | \\ exit(); | ||
| 1041 | \\} | 807 | \\} |
| 1042 | \\ | 808 | \\ |
| 1043 | \\pub fn assert(ok: bool) void { | 809 | \\pub fn assert(ok: bool) void { |
| 1044 | \\ if (!ok) unreachable; // assertion failure | 810 | \\ if (!ok) unreachable; // assertion failure |
| 1045 | \\} | 811 | \\} |
| 1046 | \\ | ||
| 1047 | \\fn exit() noreturn { | ||
| 1048 | \\ asm volatile ("syscall" | ||
| 1049 | \\ : | ||
| 1050 | \\ : [number] "{rax}" (231), | ||
| 1051 | \\ [arg1] "{rdi}" (0) | ||
| 1052 | \\ : "rcx", "r11", "memory" | ||
| 1053 | \\ ); | ||
| 1054 | \\ unreachable; | ||
| 1055 | \\} | ||
| 1056 | , | 812 | , |
| 1057 | "", | 813 | "", |
| 1058 | ); | 814 | ); |
| 1059 | 815 | ||
| 1060 | // Basic for loop | 816 | // Basic for loop |
| 1061 | case.addCompareOutput( | 817 | case.addCompareOutput( |
| 1062 | \\export fn _start() noreturn { | 818 | \\pub fn main() void { |
| 1063 | \\ for ("hello") |_| print(); | 819 | \\ for ("hello") |_| print(); |
| 1064 | \\ | ||
| 1065 | \\ exit(); | ||
| 1066 | \\} | 820 | \\} |
| 1067 | \\ | 821 | \\ |
| 1068 | \\fn print() void { | 822 | \\fn print() void { |
| ... | @@ -1076,16 +830,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1076,16 +830,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1076 | \\ ); | 830 | \\ ); |
| 1077 | \\ return; | 831 | \\ return; |
| 1078 | \\} | 832 | \\} |
| 1079 | \\ | ||
| 1080 | \\fn exit() noreturn { | ||
| 1081 | \\ asm volatile ("syscall" | ||
| 1082 | \\ : | ||
| 1083 | \\ : [number] "{rax}" (231), | ||
| 1084 | \\ [arg1] "{rdi}" (0) | ||
| 1085 | \\ : "rcx", "r11", "memory" | ||
| 1086 | \\ ); | ||
| 1087 | \\ unreachable; | ||
| 1088 | \\} | ||
| 1089 | , | 833 | , |
| 1090 | "hello\nhello\nhello\nhello\nhello\n", | 834 | "hello\nhello\nhello\nhello\nhello\n", |
| 1091 | ); | 835 | ); |
| ... | @@ -1094,19 +838,8 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1094,19 +838,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1094 | { | 838 | { |
| 1095 | var case = ctx.exe("basic import", linux_x64); | 839 | var case = ctx.exe("basic import", linux_x64); |
| 1096 | case.addCompareOutput( | 840 | case.addCompareOutput( |
| 1097 | \\export fn _start() noreturn { | 841 | \\pub fn main() void { |
| 1098 | \\ @import("print.zig").print(); | 842 | \\ @import("print.zig").print(); |
| 1099 | \\ exit(); | ||
| 1100 | \\} | ||
| 1101 | \\ | ||
| 1102 | \\fn exit() noreturn { | ||
| 1103 | \\ asm volatile ("syscall" | ||
| 1104 | \\ : | ||
| 1105 | \\ : [number] "{rax}" (231), | ||
| 1106 | \\ [arg1] "{rdi}" (@as(usize, 0)) | ||
| 1107 | \\ : "rcx", "r11", "memory" | ||
| 1108 | \\ ); | ||
| 1109 | \\ unreachable; | ||
| 1110 | \\} | 843 | \\} |
| 1111 | , | 844 | , |
| 1112 | "Hello, World!\n", | 845 | "Hello, World!\n", |
| ... | @@ -1128,28 +861,40 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1128,28 +861,40 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1128 | .path = "print.zig", | 861 | .path = "print.zig", |
| 1129 | }); | 862 | }); |
| 1130 | } | 863 | } |
| 864 | { | ||
| 865 | var case = ctx.exe("redundant comptime", linux_x64); | ||
| 866 | case.addError( | ||
| 867 | \\pub fn main() void { | ||
| 868 | \\ var a: comptime u32 = 0; | ||
| 869 | \\} | ||
| 870 | , | ||
| 871 | &.{":2:12: error: redundant comptime keyword in already comptime scope"}, | ||
| 872 | ); | ||
| 873 | case.addError( | ||
| 874 | \\pub fn main() void { | ||
| 875 | \\ comptime { | ||
| 876 | \\ var a: u32 = comptime 0; | ||
| 877 | \\ } | ||
| 878 | \\} | ||
| 879 | , | ||
| 880 | &.{":3:22: error: redundant comptime keyword in already comptime scope"}, | ||
| 881 | ); | ||
| 882 | } | ||
| 1131 | { | 883 | { |
| 1132 | var case = ctx.exe("import private", linux_x64); | 884 | var case = ctx.exe("import private", linux_x64); |
| 1133 | case.addError( | 885 | case.addError( |
| 1134 | \\export fn _start() noreturn { | 886 | \\pub fn main() void { |
| 1135 | \\ @import("print.zig").print(); | 887 | \\ @import("print.zig").print(); |
| 1136 | \\ exit(); | ||
| 1137 | \\} | ||
| 1138 | \\ | ||
| 1139 | \\fn exit() noreturn { | ||
| 1140 | \\ asm volatile ("syscall" | ||
| 1141 | \\ : | ||
| 1142 | \\ : [number] "{rax}" (231), | ||
| 1143 | \\ [arg1] "{rdi}" (@as(usize, 0)) | ||
| 1144 | \\ : "rcx", "r11", "memory" | ||
| 1145 | \\ ); | ||
| 1146 | \\ unreachable; | ||
| 1147 | \\} | 888 | \\} |
| 1148 | , | 889 | , |
| 1149 | &.{":2:25: error: 'print' is private"}, | 890 | &.{ |
| 891 | ":2:25: error: 'print' is not marked 'pub'", | ||
| 892 | "print.zig:2:1: note: declared here", | ||
| 893 | }, | ||
| 1150 | ); | 894 | ); |
| 1151 | try case.files.append(.{ | 895 | try case.files.append(.{ |
| 1152 | .src = | 896 | .src = |
| 897 | \\// dummy comment to make print be on line 2 | ||
| 1153 | \\fn print() void { | 898 | \\fn print() void { |
| 1154 | \\ asm volatile ("syscall" | 899 | \\ asm volatile ("syscall" |
| 1155 | \\ : | 900 | \\ : |
| ... | @@ -1166,50 +911,56 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1166,50 +911,56 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1166 | }); | 911 | }); |
| 1167 | } | 912 | } |
| 1168 | 913 | ||
| 1169 | ctx.compileError("function redefinition", linux_x64, | 914 | ctx.compileError("function redeclaration", linux_x64, |
| 1170 | \\// dummy comment | 915 | \\// dummy comment |
| 1171 | \\fn entry() void {} | 916 | \\fn entry() void {} |
| 1172 | \\fn entry() void {} | 917 | \\fn entry() void {} |
| 918 | \\ | ||
| 919 | \\fn foo() void { | ||
| 920 | \\ var foo = 1234; | ||
| 921 | \\} | ||
| 1173 | , &[_][]const u8{ | 922 | , &[_][]const u8{ |
| 1174 | ":3:4: error: redefinition of 'entry'", | 923 | ":3:1: error: redeclaration of 'entry'", |
| 1175 | ":2:1: note: previous definition here", | 924 | ":2:1: note: other declaration here", |
| 925 | ":6:9: error: local shadows declaration of 'foo'", | ||
| 926 | ":5:1: note: declared here", | ||
| 1176 | }); | 927 | }); |
| 1177 | 928 | ||
| 1178 | ctx.compileError("global variable redefinition", linux_x64, | 929 | ctx.compileError("global variable redeclaration", linux_x64, |
| 1179 | \\// dummy comment | 930 | \\// dummy comment |
| 1180 | \\var foo = false; | 931 | \\var foo = false; |
| 1181 | \\var foo = true; | 932 | \\var foo = true; |
| 1182 | , &[_][]const u8{ | 933 | , &[_][]const u8{ |
| 1183 | ":3:5: error: redefinition of 'foo'", | 934 | ":3:1: error: redeclaration of 'foo'", |
| 1184 | ":2:1: note: previous definition here", | 935 | ":2:1: note: other declaration here", |
| 1185 | }); | 936 | }); |
| 1186 | 937 | ||
| 1187 | ctx.compileError("compileError", linux_x64, | 938 | ctx.compileError("compileError", linux_x64, |
| 1188 | \\export fn _start() noreturn { | 939 | \\export fn foo() void { |
| 1189 | \\ @compileError("this is an error"); | 940 | \\ @compileError("this is an error"); |
| 1190 | \\ unreachable; | ||
| 1191 | \\} | 941 | \\} |
| 1192 | , &[_][]const u8{":2:3: error: this is an error"}); | 942 | , &[_][]const u8{":2:3: error: this is an error"}); |
| 1193 | 943 | ||
| 1194 | { | 944 | { |
| 1195 | var case = ctx.obj("variable shadowing", linux_x64); | 945 | var case = ctx.obj("variable shadowing", linux_x64); |
| 1196 | case.addError( | 946 | case.addError( |
| 1197 | \\export fn _start() noreturn { | 947 | \\pub fn main() void { |
| 1198 | \\ var i: u32 = 10; | 948 | \\ var i: u32 = 10; |
| 1199 | \\ var i: u32 = 10; | 949 | \\ var i: u32 = 10; |
| 1200 | \\ unreachable; | ||
| 1201 | \\} | 950 | \\} |
| 1202 | , &[_][]const u8{ | 951 | , &[_][]const u8{ |
| 1203 | ":3:9: error: redefinition of 'i'", | 952 | ":3:9: error: redeclaration of 'i'", |
| 1204 | ":2:9: note: previous definition is here", | 953 | ":2:9: note: previously declared here", |
| 1205 | }); | 954 | }); |
| 1206 | case.addError( | 955 | case.addError( |
| 1207 | \\var testing: i64 = 10; | 956 | \\var testing: i64 = 10; |
| 1208 | \\export fn _start() noreturn { | 957 | \\pub fn main() void { |
| 1209 | \\ var testing: i64 = 20; | 958 | \\ var testing: i64 = 20; |
| 1210 | \\ unreachable; | ||
| 1211 | \\} | 959 | \\} |
| 1212 | , &[_][]const u8{":3:9: error: redefinition of 'testing'"}); | 960 | , &[_][]const u8{ |
| 961 | ":3:9: error: local shadows declaration of 'testing'", | ||
| 962 | ":1:1: note: declared here", | ||
| 963 | }); | ||
| 1213 | } | 964 | } |
| 1214 | 965 | ||
| 1215 | { | 966 | { |
| ... | @@ -1273,43 +1024,19 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1273,43 +1024,19 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1273 | 1024 | ||
| 1274 | // Break out of loop | 1025 | // Break out of loop |
| 1275 | case.addCompareOutput( | 1026 | case.addCompareOutput( |
| 1276 | \\export fn _start() noreturn { | 1027 | \\pub fn main() void { |
| 1277 | \\ while (true) { | 1028 | \\ while (true) { |
| 1278 | \\ break; | 1029 | \\ break; |
| 1279 | \\ } | 1030 | \\ } |
| 1280 | \\ | ||
| 1281 | \\ exit(); | ||
| 1282 | \\} | ||
| 1283 | \\ | ||
| 1284 | \\fn exit() noreturn { | ||
| 1285 | \\ asm volatile ("syscall" | ||
| 1286 | \\ : | ||
| 1287 | \\ : [number] "{rax}" (231), | ||
| 1288 | \\ [arg1] "{rdi}" (0) | ||
| 1289 | \\ : "rcx", "r11", "memory" | ||
| 1290 | \\ ); | ||
| 1291 | \\ unreachable; | ||
| 1292 | \\} | 1031 | \\} |
| 1293 | , | 1032 | , |
| 1294 | "", | 1033 | "", |
| 1295 | ); | 1034 | ); |
| 1296 | case.addCompareOutput( | 1035 | case.addCompareOutput( |
| 1297 | \\export fn _start() noreturn { | 1036 | \\pub fn main() void { |
| 1298 | \\ foo: while (true) { | 1037 | \\ foo: while (true) { |
| 1299 | \\ break :foo; | 1038 | \\ break :foo; |
| 1300 | \\ } | 1039 | \\ } |
| 1301 | \\ | ||
| 1302 | \\ exit(); | ||
| 1303 | \\} | ||
| 1304 | \\ | ||
| 1305 | \\fn exit() noreturn { | ||
| 1306 | \\ asm volatile ("syscall" | ||
| 1307 | \\ : | ||
| 1308 | \\ : [number] "{rax}" (231), | ||
| 1309 | \\ [arg1] "{rdi}" (0) | ||
| 1310 | \\ : "rcx", "r11", "memory" | ||
| 1311 | \\ ); | ||
| 1312 | \\ unreachable; | ||
| 1313 | \\} | 1040 | \\} |
| 1314 | , | 1041 | , |
| 1315 | "", | 1042 | "", |
| ... | @@ -1317,7 +1044,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1317,7 +1044,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1317 | 1044 | ||
| 1318 | // Continue in loop | 1045 | // Continue in loop |
| 1319 | case.addCompareOutput( | 1046 | case.addCompareOutput( |
| 1320 | \\export fn _start() noreturn { | 1047 | \\pub export fn _start() noreturn { |
| 1321 | \\ var i: u64 = 0; | 1048 | \\ var i: u64 = 0; |
| 1322 | \\ while (true) : (i+=1) { | 1049 | \\ while (true) : (i+=1) { |
| 1323 | \\ if (i == 4) exit(); | 1050 | \\ if (i == 4) exit(); |
| ... | @@ -1338,7 +1065,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1338,7 +1065,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1338 | "", | 1065 | "", |
| 1339 | ); | 1066 | ); |
| 1340 | case.addCompareOutput( | 1067 | case.addCompareOutput( |
| 1341 | \\export fn _start() noreturn { | 1068 | \\pub export fn _start() noreturn { |
| 1342 | \\ var i: u64 = 0; | 1069 | \\ var i: u64 = 0; |
| 1343 | \\ foo: while (true) : (i+=1) { | 1070 | \\ foo: while (true) : (i+=1) { |
| 1344 | \\ if (i == 4) exit(); | 1071 | \\ if (i == 4) exit(); |
| ... | @@ -1390,16 +1117,18 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1390,16 +1117,18 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1390 | { | 1117 | { |
| 1391 | var case = ctx.exe("bad inferred variable type", linux_x64); | 1118 | var case = ctx.exe("bad inferred variable type", linux_x64); |
| 1392 | case.addError( | 1119 | case.addError( |
| 1393 | \\export fn foo() void { | 1120 | \\pub fn main() void { |
| 1394 | \\ var x = null; | 1121 | \\ var x = null; |
| 1395 | \\} | 1122 | \\} |
| 1396 | , &[_][]const u8{":2:9: error: variable of type '@Type(.Null)' must be const or comptime"}); | 1123 | , &[_][]const u8{ |
| 1124 | ":2:9: error: variable of type '@Type(.Null)' must be const or comptime", | ||
| 1125 | }); | ||
| 1397 | } | 1126 | } |
| 1398 | 1127 | ||
| 1399 | { | 1128 | { |
| 1400 | var case = ctx.exe("compile error in inline fn call fixed", linux_x64); | 1129 | var case = ctx.exe("compile error in inline fn call fixed", linux_x64); |
| 1401 | case.addError( | 1130 | case.addError( |
| 1402 | \\export fn _start() noreturn { | 1131 | \\pub export fn _start() noreturn { |
| 1403 | \\ var x: usize = 3; | 1132 | \\ var x: usize = 3; |
| 1404 | \\ const y = add(10, 2, x); | 1133 | \\ const y = add(10, 2, x); |
| 1405 | \\ exit(y - 6); | 1134 | \\ exit(y - 6); |
| ... | @@ -1422,7 +1151,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1422,7 +1151,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1422 | , &[_][]const u8{":8:18: error: bad"}); | 1151 | , &[_][]const u8{":8:18: error: bad"}); |
| 1423 | 1152 | ||
| 1424 | case.addCompareOutput( | 1153 | case.addCompareOutput( |
| 1425 | \\export fn _start() noreturn { | 1154 | \\pub export fn _start() noreturn { |
| 1426 | \\ var x: usize = 3; | 1155 | \\ var x: usize = 3; |
| 1427 | \\ const y = add(1, 2, x); | 1156 | \\ const y = add(1, 2, x); |
| 1428 | \\ exit(y - 6); | 1157 | \\ exit(y - 6); |
| ... | @@ -1449,7 +1178,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1449,7 +1178,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1449 | { | 1178 | { |
| 1450 | var case = ctx.exe("recursive inline function", linux_x64); | 1179 | var case = ctx.exe("recursive inline function", linux_x64); |
| 1451 | case.addCompareOutput( | 1180 | case.addCompareOutput( |
| 1452 | \\export fn _start() noreturn { | 1181 | \\pub export fn _start() noreturn { |
| 1453 | \\ const y = fibonacci(7); | 1182 | \\ const y = fibonacci(7); |
| 1454 | \\ exit(y - 21); | 1183 | \\ exit(y - 21); |
| 1455 | \\} | 1184 | \\} |
| ... | @@ -1475,7 +1204,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1475,7 +1204,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1475 | // Without storing source locations relative to the owner decl, the compile error | 1204 | // Without storing source locations relative to the owner decl, the compile error |
| 1476 | // here would be off by 2 bytes (from the "7" -> "999"). | 1205 | // here would be off by 2 bytes (from the "7" -> "999"). |
| 1477 | case.addError( | 1206 | case.addError( |
| 1478 | \\export fn _start() noreturn { | 1207 | \\pub export fn _start() noreturn { |
| 1479 | \\ const y = fibonacci(999); | 1208 | \\ const y = fibonacci(999); |
| 1480 | \\ exit(y - 21); | 1209 | \\ exit(y - 21); |
| 1481 | \\} | 1210 | \\} |
| ... | @@ -1499,46 +1228,26 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1499,46 +1228,26 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1499 | { | 1228 | { |
| 1500 | var case = ctx.exe("orelse at comptime", linux_x64); | 1229 | var case = ctx.exe("orelse at comptime", linux_x64); |
| 1501 | case.addCompareOutput( | 1230 | case.addCompareOutput( |
| 1502 | \\export fn _start() noreturn { | 1231 | \\pub fn main() void { |
| 1503 | \\ const i: ?u64 = 0; | 1232 | \\ const i: ?u64 = 0; |
| 1504 | \\ const orelsed = i orelse 5; | 1233 | \\ const result = i orelse 5; |
| 1505 | \\ assert(orelsed == 0); | 1234 | \\ assert(result == 0); |
| 1506 | \\ exit(); | ||
| 1507 | \\} | 1235 | \\} |
| 1508 | \\fn assert(b: bool) void { | 1236 | \\fn assert(b: bool) void { |
| 1509 | \\ if (!b) unreachable; | 1237 | \\ if (!b) unreachable; |
| 1510 | \\} | 1238 | \\} |
| 1511 | \\fn exit() noreturn { | ||
| 1512 | \\ asm volatile ("syscall" | ||
| 1513 | \\ : | ||
| 1514 | \\ : [number] "{rax}" (231), | ||
| 1515 | \\ [arg1] "{rdi}" (0) | ||
| 1516 | \\ : "rcx", "r11", "memory" | ||
| 1517 | \\ ); | ||
| 1518 | \\ unreachable; | ||
| 1519 | \\} | ||
| 1520 | , | 1239 | , |
| 1521 | "", | 1240 | "", |
| 1522 | ); | 1241 | ); |
| 1523 | case.addCompareOutput( | 1242 | case.addCompareOutput( |
| 1524 | \\export fn _start() noreturn { | 1243 | \\pub fn main() void { |
| 1525 | \\ const i: ?u64 = null; | 1244 | \\ const i: ?u64 = null; |
| 1526 | \\ const orelsed = i orelse 5; | 1245 | \\ const result = i orelse 5; |
| 1527 | \\ assert(orelsed == 5); | 1246 | \\ assert(result == 5); |
| 1528 | \\ exit(); | ||
| 1529 | \\} | 1247 | \\} |
| 1530 | \\fn assert(b: bool) void { | 1248 | \\fn assert(b: bool) void { |
| 1531 | \\ if (!b) unreachable; | 1249 | \\ if (!b) unreachable; |
| 1532 | \\} | 1250 | \\} |
| 1533 | \\fn exit() noreturn { | ||
| 1534 | \\ asm volatile ("syscall" | ||
| 1535 | \\ : | ||
| 1536 | \\ : [number] "{rax}" (231), | ||
| 1537 | \\ [arg1] "{rdi}" (0) | ||
| 1538 | \\ : "rcx", "r11", "memory" | ||
| 1539 | \\ ); | ||
| 1540 | \\ unreachable; | ||
| 1541 | \\} | ||
| 1542 | , | 1251 | , |
| 1543 | "", | 1252 | "", |
| 1544 | ); | 1253 | ); |
| ... | @@ -1547,7 +1256,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1547,7 +1256,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1547 | { | 1256 | { |
| 1548 | var case = ctx.exe("only 1 function and it gets updated", linux_x64); | 1257 | var case = ctx.exe("only 1 function and it gets updated", linux_x64); |
| 1549 | case.addCompareOutput( | 1258 | case.addCompareOutput( |
| 1550 | \\export fn _start() noreturn { | 1259 | \\pub export fn _start() noreturn { |
| 1551 | \\ asm volatile ("syscall" | 1260 | \\ asm volatile ("syscall" |
| 1552 | \\ : | 1261 | \\ : |
| 1553 | \\ : [number] "{rax}" (60), // exit | 1262 | \\ : [number] "{rax}" (60), // exit |
| ... | @@ -1560,7 +1269,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1560,7 +1269,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1560 | "", | 1269 | "", |
| 1561 | ); | 1270 | ); |
| 1562 | case.addCompareOutput( | 1271 | case.addCompareOutput( |
| 1563 | \\export fn _start() noreturn { | 1272 | \\pub export fn _start() noreturn { |
| 1564 | \\ asm volatile ("syscall" | 1273 | \\ asm volatile ("syscall" |
| 1565 | \\ : | 1274 | \\ : |
| 1566 | \\ : [number] "{rax}" (231), // exit_group | 1275 | \\ : [number] "{rax}" (231), // exit_group |
| ... | @@ -1576,20 +1285,10 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1576,20 +1285,10 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1576 | { | 1285 | { |
| 1577 | var case = ctx.exe("passing u0 to function", linux_x64); | 1286 | var case = ctx.exe("passing u0 to function", linux_x64); |
| 1578 | case.addCompareOutput( | 1287 | case.addCompareOutput( |
| 1579 | \\export fn _start() noreturn { | 1288 | \\pub fn main() void { |
| 1580 | \\ doNothing(0); | 1289 | \\ doNothing(0); |
| 1581 | \\ exit(); | ||
| 1582 | \\} | 1290 | \\} |
| 1583 | \\fn doNothing(arg: u0) void {} | 1291 | \\fn doNothing(arg: u0) void {} |
| 1584 | \\fn exit() noreturn { | ||
| 1585 | \\ asm volatile ("syscall" | ||
| 1586 | \\ : | ||
| 1587 | \\ : [number] "{rax}" (231), | ||
| 1588 | \\ [arg1] "{rdi}" (0) | ||
| 1589 | \\ : "rcx", "r11", "memory" | ||
| 1590 | \\ ); | ||
| 1591 | \\ unreachable; | ||
| 1592 | \\} | ||
| 1593 | , | 1292 | , |
| 1594 | "", | 1293 | "", |
| 1595 | ); | 1294 | ); |
| ... | @@ -1597,119 +1296,67 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1597,119 +1296,67 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1597 | { | 1296 | { |
| 1598 | var case = ctx.exe("catch at comptime", linux_x64); | 1297 | var case = ctx.exe("catch at comptime", linux_x64); |
| 1599 | case.addCompareOutput( | 1298 | case.addCompareOutput( |
| 1600 | \\export fn _start() noreturn { | 1299 | \\pub fn main() void { |
| 1601 | \\ const i: anyerror!u64 = 0; | 1300 | \\ const i: anyerror!u64 = 0; |
| 1602 | \\ const caught = i catch 5; | 1301 | \\ const caught = i catch 5; |
| 1603 | \\ assert(caught == 0); | 1302 | \\ assert(caught == 0); |
| 1604 | \\ exit(); | ||
| 1605 | \\} | 1303 | \\} |
| 1606 | \\fn assert(b: bool) void { | 1304 | \\fn assert(b: bool) void { |
| 1607 | \\ if (!b) unreachable; | 1305 | \\ if (!b) unreachable; |
| 1608 | \\} | 1306 | \\} |
| 1609 | \\fn exit() noreturn { | ||
| 1610 | \\ asm volatile ("syscall" | ||
| 1611 | \\ : | ||
| 1612 | \\ : [number] "{rax}" (231), | ||
| 1613 | \\ [arg1] "{rdi}" (0) | ||
| 1614 | \\ : "rcx", "r11", "memory" | ||
| 1615 | \\ ); | ||
| 1616 | \\ unreachable; | ||
| 1617 | \\} | ||
| 1618 | , | 1307 | , |
| 1619 | "", | 1308 | "", |
| 1620 | ); | 1309 | ); |
| 1621 | 1310 | ||
| 1622 | case.addCompareOutput( | 1311 | case.addCompareOutput( |
| 1623 | \\export fn _start() noreturn { | 1312 | \\pub fn main() void { |
| 1624 | \\ const i: anyerror!u64 = error.B; | 1313 | \\ const i: anyerror!u64 = error.B; |
| 1625 | \\ const caught = i catch 5; | 1314 | \\ const caught = i catch 5; |
| 1626 | \\ assert(caught == 5); | 1315 | \\ assert(caught == 5); |
| 1627 | \\ exit(); | ||
| 1628 | \\} | 1316 | \\} |
| 1629 | \\fn assert(b: bool) void { | 1317 | \\fn assert(b: bool) void { |
| 1630 | \\ if (!b) unreachable; | 1318 | \\ if (!b) unreachable; |
| 1631 | \\} | 1319 | \\} |
| 1632 | \\fn exit() noreturn { | ||
| 1633 | \\ asm volatile ("syscall" | ||
| 1634 | \\ : | ||
| 1635 | \\ : [number] "{rax}" (231), | ||
| 1636 | \\ [arg1] "{rdi}" (0) | ||
| 1637 | \\ : "rcx", "r11", "memory" | ||
| 1638 | \\ ); | ||
| 1639 | \\ unreachable; | ||
| 1640 | \\} | ||
| 1641 | , | 1320 | , |
| 1642 | "", | 1321 | "", |
| 1643 | ); | 1322 | ); |
| 1644 | 1323 | ||
| 1645 | case.addCompareOutput( | 1324 | case.addCompareOutput( |
| 1646 | \\export fn _start() noreturn { | 1325 | \\pub fn main() void { |
| 1647 | \\ const a: anyerror!comptime_int = 42; | 1326 | \\ const a: anyerror!comptime_int = 42; |
| 1648 | \\ const b: *const comptime_int = &(a catch unreachable); | 1327 | \\ const b: *const comptime_int = &(a catch unreachable); |
| 1649 | \\ assert(b.* == 42); | 1328 | \\ assert(b.* == 42); |
| 1650 | \\ | ||
| 1651 | \\ exit(); | ||
| 1652 | \\} | 1329 | \\} |
| 1653 | \\fn assert(b: bool) void { | 1330 | \\fn assert(b: bool) void { |
| 1654 | \\ if (!b) unreachable; // assertion failure | 1331 | \\ if (!b) unreachable; // assertion failure |
| 1655 | \\} | 1332 | \\} |
| 1656 | \\fn exit() noreturn { | ||
| 1657 | \\ asm volatile ("syscall" | ||
| 1658 | \\ : | ||
| 1659 | \\ : [number] "{rax}" (231), | ||
| 1660 | \\ [arg1] "{rdi}" (0) | ||
| 1661 | \\ : "rcx", "r11", "memory" | ||
| 1662 | \\ ); | ||
| 1663 | \\ unreachable; | ||
| 1664 | \\} | ||
| 1665 | , ""); | 1333 | , ""); |
| 1666 | 1334 | ||
| 1667 | case.addCompareOutput( | 1335 | case.addCompareOutput( |
| 1668 | \\export fn _start() noreturn { | 1336 | \\pub fn main() void { |
| 1669 | \\ const a: anyerror!u32 = error.B; | 1337 | \\ const a: anyerror!u32 = error.B; |
| 1670 | \\ _ = &(a catch |err| assert(err == error.B)); | 1338 | \\ _ = &(a catch |err| assert(err == error.B)); |
| 1671 | \\ exit(); | ||
| 1672 | \\} | 1339 | \\} |
| 1673 | \\fn assert(b: bool) void { | 1340 | \\fn assert(b: bool) void { |
| 1674 | \\ if (!b) unreachable; | 1341 | \\ if (!b) unreachable; |
| 1675 | \\} | 1342 | \\} |
| 1676 | \\fn exit() noreturn { | ||
| 1677 | \\ asm volatile ("syscall" | ||
| 1678 | \\ : | ||
| 1679 | \\ : [number] "{rax}" (231), | ||
| 1680 | \\ [arg1] "{rdi}" (0) | ||
| 1681 | \\ : "rcx", "r11", "memory" | ||
| 1682 | \\ ); | ||
| 1683 | \\ unreachable; | ||
| 1684 | \\} | ||
| 1685 | , ""); | 1343 | , ""); |
| 1686 | 1344 | ||
| 1687 | case.addCompareOutput( | 1345 | case.addCompareOutput( |
| 1688 | \\export fn _start() noreturn { | 1346 | \\pub fn main() void { |
| 1689 | \\ const a: anyerror!u32 = error.Bar; | 1347 | \\ const a: anyerror!u32 = error.Bar; |
| 1690 | \\ a catch |err| assert(err == error.Bar); | 1348 | \\ a catch |err| assert(err == error.Bar); |
| 1691 | \\ | ||
| 1692 | \\ exit(); | ||
| 1693 | \\} | 1349 | \\} |
| 1694 | \\fn assert(b: bool) void { | 1350 | \\fn assert(b: bool) void { |
| 1695 | \\ if (!b) unreachable; | 1351 | \\ if (!b) unreachable; |
| 1696 | \\} | 1352 | \\} |
| 1697 | \\fn exit() noreturn { | ||
| 1698 | \\ asm volatile ("syscall" | ||
| 1699 | \\ : | ||
| 1700 | \\ : [number] "{rax}" (231), | ||
| 1701 | \\ [arg1] "{rdi}" (0) | ||
| 1702 | \\ : "rcx", "r11", "memory" | ||
| 1703 | \\ ); | ||
| 1704 | \\ unreachable; | ||
| 1705 | \\} | ||
| 1706 | , ""); | 1353 | , ""); |
| 1707 | } | 1354 | } |
| 1708 | { | 1355 | { |
| 1709 | var case = ctx.exe("merge error sets", linux_x64); | 1356 | var case = ctx.exe("merge error sets", linux_x64); |
| 1710 | 1357 | ||
| 1711 | case.addCompareOutput( | 1358 | case.addCompareOutput( |
| 1712 | \\export fn _start() noreturn { | 1359 | \\pub fn main() void { |
| 1713 | \\ const E = error{ A, B, D } || error { A, B, C }; | 1360 | \\ const E = error{ A, B, D } || error { A, B, C }; |
| 1714 | \\ const a = E.A; | 1361 | \\ const a = E.A; |
| 1715 | \\ const b = E.B; | 1362 | \\ const b = E.B; |
| ... | @@ -1720,22 +1367,27 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1720,22 +1367,27 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1720 | \\ const y = E2.Y; | 1367 | \\ const y = E2.Y; |
| 1721 | \\ const z = E2.Z; | 1368 | \\ const z = E2.Z; |
| 1722 | \\ assert(anyerror || error { Z } == anyerror); | 1369 | \\ assert(anyerror || error { Z } == anyerror); |
| 1723 | \\ exit(); | ||
| 1724 | \\} | 1370 | \\} |
| 1725 | \\fn assert(b: bool) void { | 1371 | \\fn assert(b: bool) void { |
| 1726 | \\ if (!b) unreachable; | 1372 | \\ if (!b) unreachable; |
| 1727 | \\} | 1373 | \\} |
| 1728 | \\fn exit() noreturn { | 1374 | , |
| 1729 | \\ asm volatile ("syscall" | 1375 | "", |
| 1730 | \\ : | 1376 | ); |
| 1377 | } | ||
| 1378 | { | ||
| 1379 | var case = ctx.exe("inline assembly", linux_x64); | ||
| 1380 | |||
| 1381 | case.addError( | ||
| 1382 | \\pub fn main() void { | ||
| 1383 | \\ const number = 1234; | ||
| 1384 | \\ const x = asm volatile ("syscall" | ||
| 1385 | \\ : [o] "{rax}" (-> number) | ||
| 1731 | \\ : [number] "{rax}" (231), | 1386 | \\ : [number] "{rax}" (231), |
| 1732 | \\ [arg1] "{rdi}" (0) | 1387 | \\ [arg1] "{rdi}" (code) |
| 1733 | \\ : "rcx", "r11", "memory" | 1388 | \\ : "rcx", "r11", "memory" |
| 1734 | \\ ); | 1389 | \\ ); |
| 1735 | \\ unreachable; | ||
| 1736 | \\} | 1390 | \\} |
| 1737 | , | 1391 | , &[_][]const u8{":4:27: error: expected type, found comptime_int"}); |
| 1738 | "", | ||
| 1739 | ); | ||
| 1740 | } | 1392 | } |
| 1741 | } | 1393 | } |
test/stage2/wasm.zig+32-32| ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -11,7 +11,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 11 | var case = ctx.exe("wasm function calls", wasi); | 11 | var case = ctx.exe("wasm function calls", wasi); |
| 12 | 12 | ||
| 13 | case.addCompareOutput( | 13 | case.addCompareOutput( |
| 14 | \\export fn _start() u32 { | 14 | \\pub export fn _start() u32 { |
| 15 | \\ foo(); | 15 | \\ foo(); |
| 16 | \\ bar(); | 16 | \\ bar(); |
| 17 | \\ return 42; | 17 | \\ return 42; |
| ... | @@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -26,7 +26,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 26 | ); | 26 | ); |
| 27 | 27 | ||
| 28 | case.addCompareOutput( | 28 | case.addCompareOutput( |
| 29 | \\export fn _start() i64 { | 29 | \\pub export fn _start() i64 { |
| 30 | \\ bar(); | 30 | \\ bar(); |
| 31 | \\ foo(); | 31 | \\ foo(); |
| 32 | \\ foo(); | 32 | \\ foo(); |
| ... | @@ -44,7 +44,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -44,7 +44,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 44 | ); | 44 | ); |
| 45 | 45 | ||
| 46 | case.addCompareOutput( | 46 | case.addCompareOutput( |
| 47 | \\export fn _start() f32 { | 47 | \\pub export fn _start() f32 { |
| 48 | \\ bar(); | 48 | \\ bar(); |
| 49 | \\ foo(); | 49 | \\ foo(); |
| 50 | \\ return 42.0; | 50 | \\ return 42.0; |
| ... | @@ -66,7 +66,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -66,7 +66,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 66 | ); | 66 | ); |
| 67 | 67 | ||
| 68 | case.addCompareOutput( | 68 | case.addCompareOutput( |
| 69 | \\export fn _start() u32 { | 69 | \\pub export fn _start() u32 { |
| 70 | \\ foo(10, 20); | 70 | \\ foo(10, 20); |
| 71 | \\ return 5; | 71 | \\ return 5; |
| 72 | \\} | 72 | \\} |
| ... | @@ -78,7 +78,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -78,7 +78,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 78 | var case = ctx.exe("wasm locals", wasi); | 78 | var case = ctx.exe("wasm locals", wasi); |
| 79 | 79 | ||
| 80 | case.addCompareOutput( | 80 | case.addCompareOutput( |
| 81 | \\export fn _start() u32 { | 81 | \\pub export fn _start() u32 { |
| 82 | \\ var i: u32 = 5; | 82 | \\ var i: u32 = 5; |
| 83 | \\ var y: f32 = 42.0; | 83 | \\ var y: f32 = 42.0; |
| 84 | \\ var x: u32 = 10; | 84 | \\ var x: u32 = 10; |
| ... | @@ -87,7 +87,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -87,7 +87,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 87 | , "5\n"); | 87 | , "5\n"); |
| 88 | 88 | ||
| 89 | case.addCompareOutput( | 89 | case.addCompareOutput( |
| 90 | \\export fn _start() u32 { | 90 | \\pub export fn _start() u32 { |
| 91 | \\ var i: u32 = 5; | 91 | \\ var i: u32 = 5; |
| 92 | \\ var y: f32 = 42.0; | 92 | \\ var y: f32 = 42.0; |
| 93 | \\ var x: u32 = 10; | 93 | \\ var x: u32 = 10; |
| ... | @@ -106,7 +106,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -106,7 +106,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 106 | var case = ctx.exe("wasm binary operands", wasi); | 106 | var case = ctx.exe("wasm binary operands", wasi); |
| 107 | 107 | ||
| 108 | case.addCompareOutput( | 108 | case.addCompareOutput( |
| 109 | \\export fn _start() u32 { | 109 | \\pub export fn _start() u32 { |
| 110 | \\ var i: u32 = 5; | 110 | \\ var i: u32 = 5; |
| 111 | \\ i += 20; | 111 | \\ i += 20; |
| 112 | \\ return i; | 112 | \\ return i; |
| ... | @@ -114,7 +114,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -114,7 +114,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 114 | , "25\n"); | 114 | , "25\n"); |
| 115 | 115 | ||
| 116 | case.addCompareOutput( | 116 | case.addCompareOutput( |
| 117 | \\export fn _start() u32 { | 117 | \\pub export fn _start() u32 { |
| 118 | \\ var i: u32 = 5; | 118 | \\ var i: u32 = 5; |
| 119 | \\ i += 20; | 119 | \\ i += 20; |
| 120 | \\ var result: u32 = foo(i, 10); | 120 | \\ var result: u32 = foo(i, 10); |
| ... | @@ -126,7 +126,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -126,7 +126,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 126 | , "35\n"); | 126 | , "35\n"); |
| 127 | 127 | ||
| 128 | case.addCompareOutput( | 128 | case.addCompareOutput( |
| 129 | \\export fn _start() u32 { | 129 | \\pub export fn _start() u32 { |
| 130 | \\ var i: u32 = 20; | 130 | \\ var i: u32 = 20; |
| 131 | \\ i -= 5; | 131 | \\ i -= 5; |
| 132 | \\ return i; | 132 | \\ return i; |
| ... | @@ -134,7 +134,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -134,7 +134,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 134 | , "15\n"); | 134 | , "15\n"); |
| 135 | 135 | ||
| 136 | case.addCompareOutput( | 136 | case.addCompareOutput( |
| 137 | \\export fn _start() u32 { | 137 | \\pub export fn _start() u32 { |
| 138 | \\ var i: u32 = 5; | 138 | \\ var i: u32 = 5; |
| 139 | \\ i -= 3; | 139 | \\ i -= 3; |
| 140 | \\ var result: u32 = foo(i, 10); | 140 | \\ var result: u32 = foo(i, 10); |
| ... | @@ -146,7 +146,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -146,7 +146,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 146 | , "8\n"); | 146 | , "8\n"); |
| 147 | 147 | ||
| 148 | case.addCompareOutput( | 148 | case.addCompareOutput( |
| 149 | \\export fn _start() u32 { | 149 | \\pub export fn _start() u32 { |
| 150 | \\ var i: u32 = 5; | 150 | \\ var i: u32 = 5; |
| 151 | \\ i *= 7; | 151 | \\ i *= 7; |
| 152 | \\ var result: u32 = foo(i, 10); | 152 | \\ var result: u32 = foo(i, 10); |
| ... | @@ -158,7 +158,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -158,7 +158,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 158 | , "350\n"); | 158 | , "350\n"); |
| 159 | 159 | ||
| 160 | case.addCompareOutput( | 160 | case.addCompareOutput( |
| 161 | \\export fn _start() u32 { | 161 | \\pub export fn _start() u32 { |
| 162 | \\ var i: u32 = 352; | 162 | \\ var i: u32 = 352; |
| 163 | \\ i /= 7; // i = 50 | 163 | \\ i /= 7; // i = 50 |
| 164 | \\ var result: u32 = foo(i, 7); | 164 | \\ var result: u32 = foo(i, 7); |
| ... | @@ -170,7 +170,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -170,7 +170,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 170 | , "7\n"); | 170 | , "7\n"); |
| 171 | 171 | ||
| 172 | case.addCompareOutput( | 172 | case.addCompareOutput( |
| 173 | \\export fn _start() u32 { | 173 | \\pub export fn _start() u32 { |
| 174 | \\ var i: u32 = 5; | 174 | \\ var i: u32 = 5; |
| 175 | \\ i &= 6; | 175 | \\ i &= 6; |
| 176 | \\ return i; | 176 | \\ return i; |
| ... | @@ -178,7 +178,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -178,7 +178,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 178 | , "4\n"); | 178 | , "4\n"); |
| 179 | 179 | ||
| 180 | case.addCompareOutput( | 180 | case.addCompareOutput( |
| 181 | \\export fn _start() u32 { | 181 | \\pub export fn _start() u32 { |
| 182 | \\ var i: u32 = 5; | 182 | \\ var i: u32 = 5; |
| 183 | \\ i |= 6; | 183 | \\ i |= 6; |
| 184 | \\ return i; | 184 | \\ return i; |
| ... | @@ -186,7 +186,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -186,7 +186,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 186 | , "7\n"); | 186 | , "7\n"); |
| 187 | 187 | ||
| 188 | case.addCompareOutput( | 188 | case.addCompareOutput( |
| 189 | \\export fn _start() u32 { | 189 | \\pub export fn _start() u32 { |
| 190 | \\ var i: u32 = 5; | 190 | \\ var i: u32 = 5; |
| 191 | \\ i ^= 6; | 191 | \\ i ^= 6; |
| 192 | \\ return i; | 192 | \\ return i; |
| ... | @@ -194,7 +194,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -194,7 +194,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 194 | , "3\n"); | 194 | , "3\n"); |
| 195 | 195 | ||
| 196 | case.addCompareOutput( | 196 | case.addCompareOutput( |
| 197 | \\export fn _start() bool { | 197 | \\pub export fn _start() bool { |
| 198 | \\ var b: bool = false; | 198 | \\ var b: bool = false; |
| 199 | \\ b = b or false; | 199 | \\ b = b or false; |
| 200 | \\ return b; | 200 | \\ return b; |
| ... | @@ -202,7 +202,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -202,7 +202,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 202 | , "0\n"); | 202 | , "0\n"); |
| 203 | 203 | ||
| 204 | case.addCompareOutput( | 204 | case.addCompareOutput( |
| 205 | \\export fn _start() bool { | 205 | \\pub export fn _start() bool { |
| 206 | \\ var b: bool = true; | 206 | \\ var b: bool = true; |
| 207 | \\ b = b or false; | 207 | \\ b = b or false; |
| 208 | \\ return b; | 208 | \\ return b; |
| ... | @@ -210,7 +210,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -210,7 +210,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 210 | , "1\n"); | 210 | , "1\n"); |
| 211 | 211 | ||
| 212 | case.addCompareOutput( | 212 | case.addCompareOutput( |
| 213 | \\export fn _start() bool { | 213 | \\pub export fn _start() bool { |
| 214 | \\ var b: bool = false; | 214 | \\ var b: bool = false; |
| 215 | \\ b = b or true; | 215 | \\ b = b or true; |
| 216 | \\ return b; | 216 | \\ return b; |
| ... | @@ -218,7 +218,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -218,7 +218,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 218 | , "1\n"); | 218 | , "1\n"); |
| 219 | 219 | ||
| 220 | case.addCompareOutput( | 220 | case.addCompareOutput( |
| 221 | \\export fn _start() bool { | 221 | \\pub export fn _start() bool { |
| 222 | \\ var b: bool = true; | 222 | \\ var b: bool = true; |
| 223 | \\ b = b or true; | 223 | \\ b = b or true; |
| 224 | \\ return b; | 224 | \\ return b; |
| ... | @@ -226,7 +226,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -226,7 +226,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 226 | , "1\n"); | 226 | , "1\n"); |
| 227 | 227 | ||
| 228 | case.addCompareOutput( | 228 | case.addCompareOutput( |
| 229 | \\export fn _start() bool { | 229 | \\pub export fn _start() bool { |
| 230 | \\ var b: bool = false; | 230 | \\ var b: bool = false; |
| 231 | \\ b = b and false; | 231 | \\ b = b and false; |
| 232 | \\ return b; | 232 | \\ return b; |
| ... | @@ -234,7 +234,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -234,7 +234,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 234 | , "0\n"); | 234 | , "0\n"); |
| 235 | 235 | ||
| 236 | case.addCompareOutput( | 236 | case.addCompareOutput( |
| 237 | \\export fn _start() bool { | 237 | \\pub export fn _start() bool { |
| 238 | \\ var b: bool = true; | 238 | \\ var b: bool = true; |
| 239 | \\ b = b and false; | 239 | \\ b = b and false; |
| 240 | \\ return b; | 240 | \\ return b; |
| ... | @@ -242,7 +242,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -242,7 +242,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 242 | , "0\n"); | 242 | , "0\n"); |
| 243 | 243 | ||
| 244 | case.addCompareOutput( | 244 | case.addCompareOutput( |
| 245 | \\export fn _start() bool { | 245 | \\pub export fn _start() bool { |
| 246 | \\ var b: bool = false; | 246 | \\ var b: bool = false; |
| 247 | \\ b = b and true; | 247 | \\ b = b and true; |
| 248 | \\ return b; | 248 | \\ return b; |
| ... | @@ -250,7 +250,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -250,7 +250,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 250 | , "0\n"); | 250 | , "0\n"); |
| 251 | 251 | ||
| 252 | case.addCompareOutput( | 252 | case.addCompareOutput( |
| 253 | \\export fn _start() bool { | 253 | \\pub export fn _start() bool { |
| 254 | \\ var b: bool = true; | 254 | \\ var b: bool = true; |
| 255 | \\ b = b and true; | 255 | \\ b = b and true; |
| 256 | \\ return b; | 256 | \\ return b; |
| ... | @@ -262,7 +262,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -262,7 +262,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 262 | var case = ctx.exe("wasm conditions", wasi); | 262 | var case = ctx.exe("wasm conditions", wasi); |
| 263 | 263 | ||
| 264 | case.addCompareOutput( | 264 | case.addCompareOutput( |
| 265 | \\export fn _start() u32 { | 265 | \\pub export fn _start() u32 { |
| 266 | \\ var i: u32 = 5; | 266 | \\ var i: u32 = 5; |
| 267 | \\ if (i > @as(u32, 4)) { | 267 | \\ if (i > @as(u32, 4)) { |
| 268 | \\ i += 10; | 268 | \\ i += 10; |
| ... | @@ -272,7 +272,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -272,7 +272,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 272 | , "15\n"); | 272 | , "15\n"); |
| 273 | 273 | ||
| 274 | case.addCompareOutput( | 274 | case.addCompareOutput( |
| 275 | \\export fn _start() u32 { | 275 | \\pub export fn _start() u32 { |
| 276 | \\ var i: u32 = 5; | 276 | \\ var i: u32 = 5; |
| 277 | \\ if (i < @as(u32, 4)) { | 277 | \\ if (i < @as(u32, 4)) { |
| 278 | \\ i += 10; | 278 | \\ i += 10; |
| ... | @@ -284,7 +284,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -284,7 +284,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 284 | , "2\n"); | 284 | , "2\n"); |
| 285 | 285 | ||
| 286 | case.addCompareOutput( | 286 | case.addCompareOutput( |
| 287 | \\export fn _start() u32 { | 287 | \\pub export fn _start() u32 { |
| 288 | \\ var i: u32 = 5; | 288 | \\ var i: u32 = 5; |
| 289 | \\ if (i < @as(u32, 4)) { | 289 | \\ if (i < @as(u32, 4)) { |
| 290 | \\ i += 10; | 290 | \\ i += 10; |
| ... | @@ -296,7 +296,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -296,7 +296,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 296 | , "20\n"); | 296 | , "20\n"); |
| 297 | 297 | ||
| 298 | case.addCompareOutput( | 298 | case.addCompareOutput( |
| 299 | \\export fn _start() u32 { | 299 | \\pub export fn _start() u32 { |
| 300 | \\ var i: u32 = 11; | 300 | \\ var i: u32 = 11; |
| 301 | \\ if (i < @as(u32, 4)) { | 301 | \\ if (i < @as(u32, 4)) { |
| 302 | \\ i += 10; | 302 | \\ i += 10; |
| ... | @@ -312,7 +312,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -312,7 +312,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 312 | , "31\n"); | 312 | , "31\n"); |
| 313 | 313 | ||
| 314 | case.addCompareOutput( | 314 | case.addCompareOutput( |
| 315 | \\export fn _start() void { | 315 | \\pub export fn _start() void { |
| 316 | \\ assert(foo(true) != @as(i32, 30)); | 316 | \\ assert(foo(true) != @as(i32, 30)); |
| 317 | \\} | 317 | \\} |
| 318 | \\ | 318 | \\ |
| ... | @@ -327,7 +327,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -327,7 +327,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 327 | , ""); | 327 | , ""); |
| 328 | 328 | ||
| 329 | case.addCompareOutput( | 329 | case.addCompareOutput( |
| 330 | \\export fn _start() void { | 330 | \\pub export fn _start() void { |
| 331 | \\ assert(foo(false) == @as(i32, 20)); | 331 | \\ assert(foo(false) == @as(i32, 20)); |
| 332 | \\ assert(foo(true) == @as(i32, 30)); | 332 | \\ assert(foo(true) == @as(i32, 30)); |
| 333 | \\} | 333 | \\} |
| ... | @@ -351,7 +351,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -351,7 +351,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 351 | var case = ctx.exe("wasm while loops", wasi); | 351 | var case = ctx.exe("wasm while loops", wasi); |
| 352 | 352 | ||
| 353 | case.addCompareOutput( | 353 | case.addCompareOutput( |
| 354 | \\export fn _start() u32 { | 354 | \\pub export fn _start() u32 { |
| 355 | \\ var i: u32 = 0; | 355 | \\ var i: u32 = 0; |
| 356 | \\ while(i < @as(u32, 5)){ | 356 | \\ while(i < @as(u32, 5)){ |
| 357 | \\ i += 1; | 357 | \\ i += 1; |
| ... | @@ -362,7 +362,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -362,7 +362,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 362 | , "5\n"); | 362 | , "5\n"); |
| 363 | 363 | ||
| 364 | case.addCompareOutput( | 364 | case.addCompareOutput( |
| 365 | \\export fn _start() u32 { | 365 | \\pub export fn _start() u32 { |
| 366 | \\ var i: u32 = 0; | 366 | \\ var i: u32 = 0; |
| 367 | \\ while(i < @as(u32, 10)){ | 367 | \\ while(i < @as(u32, 10)){ |
| 368 | \\ var x: u32 = 1; | 368 | \\ var x: u32 = 1; |
| ... | @@ -373,7 +373,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -373,7 +373,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 373 | , "10\n"); | 373 | , "10\n"); |
| 374 | 374 | ||
| 375 | case.addCompareOutput( | 375 | case.addCompareOutput( |
| 376 | \\export fn _start() u32 { | 376 | \\pub export fn _start() u32 { |
| 377 | \\ var i: u32 = 0; | 377 | \\ var i: u32 = 0; |
| 378 | \\ while(i < @as(u32, 10)){ | 378 | \\ while(i < @as(u32, 10)){ |
| 379 | \\ var x: u32 = 1; | 379 | \\ var x: u32 = 1; |
test/standalone/issue_339/test.zig+1-1| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | const StackTrace = @import("builtin").StackTrace; | 1 | const StackTrace = @import("std").builtin.StackTrace; |
| 2 | pub fn panic(msg: []const u8, stack_trace: ?*StackTrace) noreturn { | 2 | pub fn panic(msg: []const u8, stack_trace: ?*StackTrace) noreturn { |
| 3 | @breakpoint(); | 3 | @breakpoint(); |
| 4 | while (true) {} | 4 | while (true) {} |
test/tests.zig+5-5| ... | @@ -523,7 +523,7 @@ pub fn addPkgTests( | ... | @@ -523,7 +523,7 @@ pub fn addPkgTests( |
| 523 | if (skip_single_threaded and test_target.single_threaded) | 523 | if (skip_single_threaded and test_target.single_threaded) |
| 524 | continue; | 524 | continue; |
| 525 | 525 | ||
| 526 | const ArchTag = std.meta.Tag(builtin.Arch); | 526 | const ArchTag = std.meta.Tag(std.Target.Cpu.Arch); |
| 527 | if (test_target.disable_native and | 527 | if (test_target.disable_native and |
| 528 | test_target.target.getOsTag() == std.Target.current.os.tag and | 528 | test_target.target.getOsTag() == std.Target.current.os.tag and |
| 529 | test_target.target.getCpuArch() == std.Target.current.cpu.arch) | 529 | test_target.target.getCpuArch() == std.Target.current.cpu.arch) |
| ... | @@ -588,11 +588,11 @@ pub const StackTracesContext = struct { | ... | @@ -588,11 +588,11 @@ pub const StackTracesContext = struct { |
| 588 | if (config.exclude.exclude()) return; | 588 | if (config.exclude.exclude()) return; |
| 589 | } | 589 | } |
| 590 | if (@hasField(@TypeOf(config), "exclude_arch")) { | 590 | if (@hasField(@TypeOf(config), "exclude_arch")) { |
| 591 | const exclude_arch: []const builtin.Cpu.Arch = &config.exclude_arch; | 591 | const exclude_arch: []const std.Target.Cpu.Arch = &config.exclude_arch; |
| 592 | for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return; | 592 | for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return; |
| 593 | } | 593 | } |
| 594 | if (@hasField(@TypeOf(config), "exclude_os")) { | 594 | if (@hasField(@TypeOf(config), "exclude_os")) { |
| 595 | const exclude_os: []const builtin.Os.Tag = &config.exclude_os; | 595 | const exclude_os: []const std.Target.Os.Tag = &config.exclude_os; |
| 596 | for (exclude_os) |os| if (os == builtin.os.tag) return; | 596 | for (exclude_os) |os| if (os == builtin.os.tag) return; |
| 597 | } | 597 | } |
| 598 | for (self.modes) |mode| { | 598 | for (self.modes) |mode| { |
| ... | @@ -632,11 +632,11 @@ pub const StackTracesContext = struct { | ... | @@ -632,11 +632,11 @@ pub const StackTracesContext = struct { |
| 632 | if (mode_config.exclude.exclude()) return; | 632 | if (mode_config.exclude.exclude()) return; |
| 633 | } | 633 | } |
| 634 | if (@hasField(@TypeOf(mode_config), "exclude_arch")) { | 634 | if (@hasField(@TypeOf(mode_config), "exclude_arch")) { |
| 635 | const exclude_arch: []const builtin.Cpu.Arch = &mode_config.exclude_arch; | 635 | const exclude_arch: []const std.Target.Cpu.Arch = &mode_config.exclude_arch; |
| 636 | for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return; | 636 | for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return; |
| 637 | } | 637 | } |
| 638 | if (@hasField(@TypeOf(mode_config), "exclude_os")) { | 638 | if (@hasField(@TypeOf(mode_config), "exclude_os")) { |
| 639 | const exclude_os: []const builtin.Os.Tag = &mode_config.exclude_os; | 639 | const exclude_os: []const std.Target.Os.Tag = &mode_config.exclude_os; |
| 640 | for (exclude_os) |os| if (os == builtin.os.tag) return; | 640 | for (exclude_os) |os| if (os == builtin.os.tag) return; |
| 641 | } | 641 | } |
| 642 | 642 |
tools/gen_spirv_spec.zig+1-1| ... | @@ -26,7 +26,7 @@ fn render(writer: anytype, registry: g.Registry) !void { | ... | @@ -26,7 +26,7 @@ fn render(writer: anytype, registry: g.Registry) !void { |
| 26 | try writer.writeAll( | 26 | try writer.writeAll( |
| 27 | \\//! This file is auto-generated by tools/gen_spirv_spec.zig. | 27 | \\//! This file is auto-generated by tools/gen_spirv_spec.zig. |
| 28 | \\ | 28 | \\ |
| 29 | \\const Version = @import("builtin").Version; | 29 | \\const Version = @import("std").builtin.Version; |
| 30 | \\ | 30 | \\ |
| 31 | ); | 31 | ); |
| 32 | 32 |