| author | |
| committer | |
| log | d46446e4dfade96fe0db773ce4d8d1b7154cae92 |
| tree | b0cb2fbc5ba6cf2d800c3a3f96cd760863b63aca |
| parent | d3389eadf42417deae2d9ba01f9529be861fb998 |
| parent | ff125db53d8c18a63872ebdcdf6dd9653eb3f56b |
101 files changed, 3300 insertions(+), 2139 deletions(-)
CMakeLists.txt+1-1| ... | ... | @@ -670,7 +670,7 @@ set(ZIG_STAGE2_SOURCES |
| 670 | 670 | "${CMAKE_SOURCE_DIR}/lib/std/target/powerpc.zig" |
| 671 | 671 | "${CMAKE_SOURCE_DIR}/lib/std/target/riscv.zig" |
| 672 | 672 | "${CMAKE_SOURCE_DIR}/lib/std/target/sparc.zig" |
| 673 | "${CMAKE_SOURCE_DIR}/lib/std/target/systemz.zig" | |
| 673 | "${CMAKE_SOURCE_DIR}/lib/std/target/s390x.zig" | |
| 674 | 674 | "${CMAKE_SOURCE_DIR}/lib/std/target/wasm.zig" |
| 675 | 675 | "${CMAKE_SOURCE_DIR}/lib/std/target/x86.zig" |
| 676 | 676 | "${CMAKE_SOURCE_DIR}/lib/std/Thread.zig" |
build.zig+65-31| ... | ... | @@ -238,7 +238,15 @@ pub fn build(b: *Builder) !void { |
| 238 | 238 | exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version)); |
| 239 | 239 | |
| 240 | 240 | if (enable_llvm) { |
| 241 | const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option); | |
| 241 | const cmake_cfg = if (static_llvm) null else blk: { | |
| 242 | if (findConfigH(b, config_h_path_option)) |config_h_path| { | |
| 243 | const file_contents = fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable; | |
| 244 | break :blk parseConfigH(b, file_contents); | |
| 245 | } else { | |
| 246 | std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{}); | |
| 247 | break :blk null; | |
| 248 | } | |
| 249 | }; | |
| 242 | 250 | |
| 243 | 251 | if (is_stage1) { |
| 244 | 252 | const softfloat = b.addStaticLibrary("softfloat", null); |
| ... | ... | @@ -565,13 +573,17 @@ fn addCmakeCfgOptionsToExe( |
| 565 | 573 | exe.linkLibCpp(); |
| 566 | 574 | } else { |
| 567 | 575 | const need_cpp_includes = true; |
| 576 | const lib_suffix = switch (cfg.llvm_linkage) { | |
| 577 | .static => exe.target.staticLibSuffix()[1..], | |
| 578 | .dynamic => exe.target.dynamicLibSuffix()[1..], | |
| 579 | }; | |
| 568 | 580 | |
| 569 | 581 | // System -lc++ must be used because in this code path we are attempting to link |
| 570 | 582 | // against system-provided LLVM, Clang, LLD. |
| 571 | 583 | if (exe.target.getOsTag() == .linux) { |
| 572 | // First we try to static link against gcc libstdc++. If that doesn't work, | |
| 573 | // we fall back to -lc++ and cross our fingers. | |
| 574 | addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) { | |
| 584 | // First we try to link against gcc libstdc++. If that doesn't work, we fall | |
| 585 | // back to -lc++ and cross our fingers. | |
| 586 | addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), "", need_cpp_includes) catch |err| switch (err) { | |
| 575 | 587 | error.RequiredLibraryNotFound => { |
| 576 | 588 | exe.linkSystemLibrary("c++"); |
| 577 | 589 | }, |
| ... | ... | @@ -579,11 +591,11 @@ fn addCmakeCfgOptionsToExe( |
| 579 | 591 | }; |
| 580 | 592 | exe.linkSystemLibrary("unwind"); |
| 581 | 593 | } else if (exe.target.isFreeBSD()) { |
| 582 | try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes); | |
| 594 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes); | |
| 583 | 595 | exe.linkSystemLibrary("pthread"); |
| 584 | 596 | } else if (exe.target.getOsTag() == .openbsd) { |
| 585 | try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes); | |
| 586 | try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes); | |
| 597 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes); | |
| 598 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{lib_suffix}), null, need_cpp_includes); | |
| 587 | 599 | } else if (exe.target.isDarwin()) { |
| 588 | 600 | exe.linkSystemLibrary("c++"); |
| 589 | 601 | } |
| ... | ... | @@ -689,31 +701,53 @@ const CMakeConfig = struct { |
| 689 | 701 | |
| 690 | 702 | const max_config_h_bytes = 1 * 1024 * 1024; |
| 691 | 703 | |
| 692 | fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig { | |
| 693 | const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: { | |
| 694 | break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable; | |
| 695 | } else blk: { | |
| 696 | // TODO this should stop looking for config.h once it detects we hit the | |
| 697 | // zig source root directory. | |
| 698 | var check_dir = fs.path.dirname(b.zig_exe).?; | |
| 699 | while (true) { | |
| 700 | var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable; | |
| 701 | defer dir.close(); | |
| 702 | ||
| 703 | break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) { | |
| 704 | error.FileNotFound => { | |
| 705 | const new_check_dir = fs.path.dirname(check_dir); | |
| 706 | if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) { | |
| 707 | return null; | |
| 708 | } | |
| 709 | check_dir = new_check_dir.?; | |
| 710 | continue; | |
| 711 | }, | |
| 712 | else => unreachable, | |
| 713 | }; | |
| 714 | } else unreachable; // TODO should not need `else unreachable`. | |
| 715 | }; | |
| 704 | fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 { | |
| 705 | if (config_h_path_option) |path| { | |
| 706 | var config_h_or_err = fs.cwd().openFile(path, .{}); | |
| 707 | if (config_h_or_err) |*file| { | |
| 708 | file.close(); | |
| 709 | return path; | |
| 710 | } else |_| { | |
| 711 | std.log.err("Could not open provided config.h: \"{s}\"", .{path}); | |
| 712 | std.os.exit(1); | |
| 713 | } | |
| 714 | } | |
| 715 | ||
| 716 | var check_dir = fs.path.dirname(b.zig_exe).?; | |
| 717 | while (true) { | |
| 718 | var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable; | |
| 719 | defer dir.close(); | |
| 720 | ||
| 721 | // Check if config.h is present in dir | |
| 722 | var config_h_or_err = dir.openFile("config.h", .{}); | |
| 723 | if (config_h_or_err) |*file| { | |
| 724 | file.close(); | |
| 725 | return fs.path.join( | |
| 726 | b.allocator, | |
| 727 | &[_][]const u8{ check_dir, "config.h" }, | |
| 728 | ) catch unreachable; | |
| 729 | } else |e| switch (e) { | |
| 730 | error.FileNotFound => {}, | |
| 731 | else => unreachable, | |
| 732 | } | |
| 733 | ||
| 734 | // Check if we reached the source root by looking for .git, and bail if so | |
| 735 | var git_dir_or_err = dir.openDir(".git", .{}); | |
| 736 | if (git_dir_or_err) |*git_dir| { | |
| 737 | git_dir.close(); | |
| 738 | return null; | |
| 739 | } else |_| {} | |
| 740 | ||
| 741 | // Otherwise, continue search in the parent directory | |
| 742 | const new_check_dir = fs.path.dirname(check_dir); | |
| 743 | if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) { | |
| 744 | return null; | |
| 745 | } | |
| 746 | check_dir = new_check_dir.?; | |
| 747 | } else unreachable; // TODO should not need `else unreachable`. | |
| 748 | } | |
| 716 | 749 | |
| 750 | fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig { | |
| 717 | 751 | var ctx: CMakeConfig = .{ |
| 718 | 752 | .llvm_linkage = undefined, |
| 719 | 753 | .cmake_binary_dir = undefined, |
ci/zinc/linux_test.sh+1-2| ... | ... | @@ -63,8 +63,7 @@ stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm |
| 63 | 63 | stage3/bin/zig build test-run-translated-c -fqemu -fwasmtime -Denable-llvm |
| 64 | 64 | stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm |
| 65 | 65 | stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm |
| 66 | # https://github.com/ziglang/zig/issues/12144 | |
| 67 | stage3/bin/zig build test-cases -fqemu -fwasmtime | |
| 66 | stage3/bin/zig build test-cases -fqemu -fwasmtime -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL" | |
| 68 | 67 | stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm |
| 69 | 68 | |
| 70 | 69 | $STAGE1_ZIG build test-stack-traces -fqemu -fwasmtime |
cmake/Findllvm.cmake+7-5| ... | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | |
| 11 | 11 | |
| 12 | 12 | if(ZIG_USE_LLVM_CONFIG) |
| 13 | set(LLVM_CONFIG_ERROR_MESSAGES "") | |
| 13 | 14 | while(1) |
| 14 | 15 | unset(LLVM_CONFIG_EXE CACHE) |
| 15 | 16 | find_program(LLVM_CONFIG_EXE |
| ... | ... | @@ -21,7 +22,8 @@ if(ZIG_USE_LLVM_CONFIG) |
| 21 | 22 | "C:/Libraries/llvm-15.0.0/bin") |
| 22 | 23 | |
| 23 | 24 | if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND") |
| 24 | if (DEFINED LLVM_CONFIG_ERROR_MESSAGE) | |
| 25 | if (NOT LLVM_CONFIG_ERROR_MESSAGES STREQUAL "") | |
| 26 | list(JOIN LLVM_CONFIG_ERROR_MESSAGES "\n" LLVM_CONFIG_ERROR_MESSAGE) | |
| 25 | 27 | message(FATAL_ERROR ${LLVM_CONFIG_ERROR_MESSAGE}) |
| 26 | 28 | else() |
| 27 | 29 | message(FATAL_ERROR "unable to find llvm-config") |
| ... | ... | @@ -37,7 +39,7 @@ if(ZIG_USE_LLVM_CONFIG) |
| 37 | 39 | get_filename_component(LLVM_CONFIG_DIR "${LLVM_CONFIG_EXE}" DIRECTORY) |
| 38 | 40 | if("${LLVM_CONFIG_VERSION}" VERSION_LESS 15 OR "${LLVM_CONFIG_VERSION}" VERSION_EQUAL 16 OR "${LLVM_CONFIG_VERSION}" VERSION_GREATER 16) |
| 39 | 41 | # Save the error message, in case this is the last llvm-config we find |
| 40 | set(LLVM_CONFIG_ERROR_MESSAGE "expected LLVM 15.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") | |
| 42 | list(APPEND LLVM_CONFIG_ERROR_MESSAGES "expected LLVM 15.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") | |
| 41 | 43 | |
| 42 | 44 | # Ignore this directory and try the search again |
| 43 | 45 | list(APPEND CMAKE_IGNORE_PATH "${LLVM_CONFIG_DIR}") |
| ... | ... | @@ -61,9 +63,9 @@ if(ZIG_USE_LLVM_CONFIG) |
| 61 | 63 | if (LLVM_CONFIG_ERROR) |
| 62 | 64 | # Save the error message, in case this is the last llvm-config we find |
| 63 | 65 | if (ZIG_SHARED_LLVM) |
| 64 | set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library") | |
| 66 | list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library") | |
| 65 | 67 | else() |
| 66 | set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library") | |
| 68 | list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library") | |
| 67 | 69 | endif() |
| 68 | 70 | |
| 69 | 71 | # Ignore this directory and try the search again |
| ... | ... | @@ -81,7 +83,7 @@ if(ZIG_USE_LLVM_CONFIG) |
| 81 | 83 | list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index) |
| 82 | 84 | if (${_index} EQUAL -1) |
| 83 | 85 | # Save the error message, in case this is the last llvm-config we find |
| 84 | set(LLVM_CONFIG_ERROR_MESSAGE "LLVM (according to ${LLVM_CONFIG_EXE}) is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.") | |
| 86 | list(APPEND LLVM_CONFIG_ERROR_MESSAGES "LLVM (according to ${LLVM_CONFIG_EXE}) is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.") | |
| 85 | 87 | |
| 86 | 88 | # Ignore this directory and try the search again |
| 87 | 89 | list(APPEND CMAKE_IGNORE_PATH "${LLVM_CONFIG_DIR}") |
lib/std/debug.zig+2| ... | ... | @@ -1784,6 +1784,7 @@ pub fn updateSegfaultHandler(act: ?*const os.Sigaction) error{OperationNotSuppor |
| 1784 | 1784 | try os.sigaction(os.SIG.SEGV, act, null); |
| 1785 | 1785 | try os.sigaction(os.SIG.ILL, act, null); |
| 1786 | 1786 | try os.sigaction(os.SIG.BUS, act, null); |
| 1787 | try os.sigaction(os.SIG.FPE, act, null); | |
| 1787 | 1788 | } |
| 1788 | 1789 | |
| 1789 | 1790 | /// Attaches a global SIGSEGV handler which calls @panic("segmentation fault"); |
| ... | ... | @@ -1845,6 +1846,7 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any |
| 1845 | 1846 | os.SIG.SEGV => stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), |
| 1846 | 1847 | os.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}), |
| 1847 | 1848 | os.SIG.BUS => stderr.print("Bus error at address 0x{x}\n", .{addr}), |
| 1849 | os.SIG.FPE => stderr.print("Arithmetic exception at address 0x{x}\n", .{addr}), | |
| 1848 | 1850 | else => unreachable, |
| 1849 | 1851 | } catch os.abort(); |
| 1850 | 1852 | } |
lib/std/os.zig+2| ... | ... | @@ -4244,6 +4244,7 @@ pub const INotifyAddWatchError = error{ |
| 4244 | 4244 | SystemResources, |
| 4245 | 4245 | UserResourceLimitReached, |
| 4246 | 4246 | NotDir, |
| 4247 | WatchAlreadyExists, | |
| 4247 | 4248 | } || UnexpectedError; |
| 4248 | 4249 | |
| 4249 | 4250 | /// add a watch to an initialized inotify instance |
| ... | ... | @@ -4266,6 +4267,7 @@ pub fn inotify_add_watchZ(inotify_fd: i32, pathname: [*:0]const u8, mask: u32) I |
| 4266 | 4267 | .NOMEM => return error.SystemResources, |
| 4267 | 4268 | .NOSPC => return error.UserResourceLimitReached, |
| 4268 | 4269 | .NOTDIR => return error.NotDir, |
| 4270 | .EXIST => return error.WatchAlreadyExists, | |
| 4269 | 4271 | else => |err| return unexpectedErrno(err), |
| 4270 | 4272 | } |
| 4271 | 4273 | } |
lib/std/os/linux.zig+1| ... | ... | @@ -2976,6 +2976,7 @@ pub const IN = struct { |
| 2976 | 2976 | pub const ONLYDIR = 0x01000000; |
| 2977 | 2977 | pub const DONT_FOLLOW = 0x02000000; |
| 2978 | 2978 | pub const EXCL_UNLINK = 0x04000000; |
| 2979 | pub const MASK_CREATE = 0x10000000; | |
| 2979 | 2980 | pub const MASK_ADD = 0x20000000; |
| 2980 | 2981 | |
| 2981 | 2982 | pub const ISDIR = 0x40000000; |
lib/std/target.zig+5-5| ... | ... | @@ -453,7 +453,7 @@ pub const Target = struct { |
| 453 | 453 | pub const riscv = @import("target/riscv.zig"); |
| 454 | 454 | pub const sparc = @import("target/sparc.zig"); |
| 455 | 455 | pub const spirv = @import("target/spirv.zig"); |
| 456 | pub const systemz = @import("target/systemz.zig"); | |
| 456 | pub const s390x = @import("target/s390x.zig"); | |
| 457 | 457 | pub const ve = @import("target/ve.zig"); |
| 458 | 458 | pub const wasm = @import("target/wasm.zig"); |
| 459 | 459 | pub const x86 = @import("target/x86.zig"); |
| ... | ... | @@ -1178,7 +1178,7 @@ pub const Target = struct { |
| 1178 | 1178 | .amdgcn => "amdgpu", |
| 1179 | 1179 | .riscv32, .riscv64 => "riscv", |
| 1180 | 1180 | .sparc, .sparc64, .sparcel => "sparc", |
| 1181 | .s390x => "systemz", | |
| 1181 | .s390x => "s390x", | |
| 1182 | 1182 | .i386, .x86_64 => "x86", |
| 1183 | 1183 | .nvptx, .nvptx64 => "nvptx", |
| 1184 | 1184 | .wasm32, .wasm64 => "wasm", |
| ... | ... | @@ -1202,7 +1202,7 @@ pub const Target = struct { |
| 1202 | 1202 | .riscv32, .riscv64 => &riscv.all_features, |
| 1203 | 1203 | .sparc, .sparc64, .sparcel => &sparc.all_features, |
| 1204 | 1204 | .spirv32, .spirv64 => &spirv.all_features, |
| 1205 | .s390x => &systemz.all_features, | |
| 1205 | .s390x => &s390x.all_features, | |
| 1206 | 1206 | .i386, .x86_64 => &x86.all_features, |
| 1207 | 1207 | .nvptx, .nvptx64 => &nvptx.all_features, |
| 1208 | 1208 | .ve => &ve.all_features, |
| ... | ... | @@ -1226,7 +1226,7 @@ pub const Target = struct { |
| 1226 | 1226 | .amdgcn => comptime allCpusFromDecls(amdgpu.cpu), |
| 1227 | 1227 | .riscv32, .riscv64 => comptime allCpusFromDecls(riscv.cpu), |
| 1228 | 1228 | .sparc, .sparc64, .sparcel => comptime allCpusFromDecls(sparc.cpu), |
| 1229 | .s390x => comptime allCpusFromDecls(systemz.cpu), | |
| 1229 | .s390x => comptime allCpusFromDecls(s390x.cpu), | |
| 1230 | 1230 | .i386, .x86_64 => comptime allCpusFromDecls(x86.cpu), |
| 1231 | 1231 | .nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu), |
| 1232 | 1232 | .ve => comptime allCpusFromDecls(ve.cpu), |
| ... | ... | @@ -1287,7 +1287,7 @@ pub const Target = struct { |
| 1287 | 1287 | .riscv64 => &riscv.cpu.generic_rv64, |
| 1288 | 1288 | .sparc, .sparcel => &sparc.cpu.generic, |
| 1289 | 1289 | .sparc64 => &sparc.cpu.v9, // 64-bit SPARC needs v9 as the baseline |
| 1290 | .s390x => &systemz.cpu.generic, | |
| 1290 | .s390x => &s390x.cpu.generic, | |
| 1291 | 1291 | .i386 => &x86.cpu.i386, |
| 1292 | 1292 | .x86_64 => &x86.cpu.x86_64, |
| 1293 | 1293 | .nvptx, .nvptx64 => &nvptx.cpu.sm_20, |
lib/std/target/s390x.zig created+621| ... | ... | @@ -0,0 +1,621 @@ |
| 1 | //! This file is auto-generated by tools/update_cpu_features.zig. | |
| 2 | ||
| 3 | const std = @import("../std.zig"); | |
| 4 | const CpuFeature = std.Target.Cpu.Feature; | |
| 5 | const CpuModel = std.Target.Cpu.Model; | |
| 6 | ||
| 7 | pub const Feature = enum { | |
| 8 | bear_enhancement, | |
| 9 | deflate_conversion, | |
| 10 | dfp_packed_conversion, | |
| 11 | dfp_zoned_conversion, | |
| 12 | distinct_ops, | |
| 13 | enhanced_dat_2, | |
| 14 | enhanced_sort, | |
| 15 | execution_hint, | |
| 16 | fast_serialization, | |
| 17 | fp_extension, | |
| 18 | guarded_storage, | |
| 19 | high_word, | |
| 20 | insert_reference_bits_multiple, | |
| 21 | interlocked_access1, | |
| 22 | load_and_trap, | |
| 23 | load_and_zero_rightmost_byte, | |
| 24 | load_store_on_cond, | |
| 25 | load_store_on_cond_2, | |
| 26 | message_security_assist_extension3, | |
| 27 | message_security_assist_extension4, | |
| 28 | message_security_assist_extension5, | |
| 29 | message_security_assist_extension7, | |
| 30 | message_security_assist_extension8, | |
| 31 | message_security_assist_extension9, | |
| 32 | miscellaneous_extensions, | |
| 33 | miscellaneous_extensions_2, | |
| 34 | miscellaneous_extensions_3, | |
| 35 | nnp_assist, | |
| 36 | population_count, | |
| 37 | processor_activity_instrumentation, | |
| 38 | processor_assist, | |
| 39 | reset_dat_protection, | |
| 40 | reset_reference_bits_multiple, | |
| 41 | soft_float, | |
| 42 | transactional_execution, | |
| 43 | vector, | |
| 44 | vector_enhancements_1, | |
| 45 | vector_enhancements_2, | |
| 46 | vector_packed_decimal, | |
| 47 | vector_packed_decimal_enhancement, | |
| 48 | vector_packed_decimal_enhancement_2, | |
| 49 | }; | |
| 50 | ||
| 51 | pub const featureSet = CpuFeature.feature_set_fns(Feature).featureSet; | |
| 52 | pub const featureSetHas = CpuFeature.feature_set_fns(Feature).featureSetHas; | |
| 53 | pub const featureSetHasAny = CpuFeature.feature_set_fns(Feature).featureSetHasAny; | |
| 54 | pub const featureSetHasAll = CpuFeature.feature_set_fns(Feature).featureSetHasAll; | |
| 55 | ||
| 56 | pub const all_features = blk: { | |
| 57 | const len = @typeInfo(Feature).Enum.fields.len; | |
| 58 | std.debug.assert(len <= CpuFeature.Set.needed_bit_count); | |
| 59 | var result: [len]CpuFeature = undefined; | |
| 60 | result[@enumToInt(Feature.bear_enhancement)] = .{ | |
| 61 | .llvm_name = "bear-enhancement", | |
| 62 | .description = "Assume that the BEAR-enhancement facility is installed", | |
| 63 | .dependencies = featureSet(&[_]Feature{}), | |
| 64 | }; | |
| 65 | result[@enumToInt(Feature.deflate_conversion)] = .{ | |
| 66 | .llvm_name = "deflate-conversion", | |
| 67 | .description = "Assume that the deflate-conversion facility is installed", | |
| 68 | .dependencies = featureSet(&[_]Feature{}), | |
| 69 | }; | |
| 70 | result[@enumToInt(Feature.dfp_packed_conversion)] = .{ | |
| 71 | .llvm_name = "dfp-packed-conversion", | |
| 72 | .description = "Assume that the DFP packed-conversion facility is installed", | |
| 73 | .dependencies = featureSet(&[_]Feature{}), | |
| 74 | }; | |
| 75 | result[@enumToInt(Feature.dfp_zoned_conversion)] = .{ | |
| 76 | .llvm_name = "dfp-zoned-conversion", | |
| 77 | .description = "Assume that the DFP zoned-conversion facility is installed", | |
| 78 | .dependencies = featureSet(&[_]Feature{}), | |
| 79 | }; | |
| 80 | result[@enumToInt(Feature.distinct_ops)] = .{ | |
| 81 | .llvm_name = "distinct-ops", | |
| 82 | .description = "Assume that the distinct-operands facility is installed", | |
| 83 | .dependencies = featureSet(&[_]Feature{}), | |
| 84 | }; | |
| 85 | result[@enumToInt(Feature.enhanced_dat_2)] = .{ | |
| 86 | .llvm_name = "enhanced-dat-2", | |
| 87 | .description = "Assume that the enhanced-DAT facility 2 is installed", | |
| 88 | .dependencies = featureSet(&[_]Feature{}), | |
| 89 | }; | |
| 90 | result[@enumToInt(Feature.enhanced_sort)] = .{ | |
| 91 | .llvm_name = "enhanced-sort", | |
| 92 | .description = "Assume that the enhanced-sort facility is installed", | |
| 93 | .dependencies = featureSet(&[_]Feature{}), | |
| 94 | }; | |
| 95 | result[@enumToInt(Feature.execution_hint)] = .{ | |
| 96 | .llvm_name = "execution-hint", | |
| 97 | .description = "Assume that the execution-hint facility is installed", | |
| 98 | .dependencies = featureSet(&[_]Feature{}), | |
| 99 | }; | |
| 100 | result[@enumToInt(Feature.fast_serialization)] = .{ | |
| 101 | .llvm_name = "fast-serialization", | |
| 102 | .description = "Assume that the fast-serialization facility is installed", | |
| 103 | .dependencies = featureSet(&[_]Feature{}), | |
| 104 | }; | |
| 105 | result[@enumToInt(Feature.fp_extension)] = .{ | |
| 106 | .llvm_name = "fp-extension", | |
| 107 | .description = "Assume that the floating-point extension facility is installed", | |
| 108 | .dependencies = featureSet(&[_]Feature{}), | |
| 109 | }; | |
| 110 | result[@enumToInt(Feature.guarded_storage)] = .{ | |
| 111 | .llvm_name = "guarded-storage", | |
| 112 | .description = "Assume that the guarded-storage facility is installed", | |
| 113 | .dependencies = featureSet(&[_]Feature{}), | |
| 114 | }; | |
| 115 | result[@enumToInt(Feature.high_word)] = .{ | |
| 116 | .llvm_name = "high-word", | |
| 117 | .description = "Assume that the high-word facility is installed", | |
| 118 | .dependencies = featureSet(&[_]Feature{}), | |
| 119 | }; | |
| 120 | result[@enumToInt(Feature.insert_reference_bits_multiple)] = .{ | |
| 121 | .llvm_name = "insert-reference-bits-multiple", | |
| 122 | .description = "Assume that the insert-reference-bits-multiple facility is installed", | |
| 123 | .dependencies = featureSet(&[_]Feature{}), | |
| 124 | }; | |
| 125 | result[@enumToInt(Feature.interlocked_access1)] = .{ | |
| 126 | .llvm_name = "interlocked-access1", | |
| 127 | .description = "Assume that interlocked-access facility 1 is installed", | |
| 128 | .dependencies = featureSet(&[_]Feature{}), | |
| 129 | }; | |
| 130 | result[@enumToInt(Feature.load_and_trap)] = .{ | |
| 131 | .llvm_name = "load-and-trap", | |
| 132 | .description = "Assume that the load-and-trap facility is installed", | |
| 133 | .dependencies = featureSet(&[_]Feature{}), | |
| 134 | }; | |
| 135 | result[@enumToInt(Feature.load_and_zero_rightmost_byte)] = .{ | |
| 136 | .llvm_name = "load-and-zero-rightmost-byte", | |
| 137 | .description = "Assume that the load-and-zero-rightmost-byte facility is installed", | |
| 138 | .dependencies = featureSet(&[_]Feature{}), | |
| 139 | }; | |
| 140 | result[@enumToInt(Feature.load_store_on_cond)] = .{ | |
| 141 | .llvm_name = "load-store-on-cond", | |
| 142 | .description = "Assume that the load/store-on-condition facility is installed", | |
| 143 | .dependencies = featureSet(&[_]Feature{}), | |
| 144 | }; | |
| 145 | result[@enumToInt(Feature.load_store_on_cond_2)] = .{ | |
| 146 | .llvm_name = "load-store-on-cond-2", | |
| 147 | .description = "Assume that the load/store-on-condition facility 2 is installed", | |
| 148 | .dependencies = featureSet(&[_]Feature{}), | |
| 149 | }; | |
| 150 | result[@enumToInt(Feature.message_security_assist_extension3)] = .{ | |
| 151 | .llvm_name = "message-security-assist-extension3", | |
| 152 | .description = "Assume that the message-security-assist extension facility 3 is installed", | |
| 153 | .dependencies = featureSet(&[_]Feature{}), | |
| 154 | }; | |
| 155 | result[@enumToInt(Feature.message_security_assist_extension4)] = .{ | |
| 156 | .llvm_name = "message-security-assist-extension4", | |
| 157 | .description = "Assume that the message-security-assist extension facility 4 is installed", | |
| 158 | .dependencies = featureSet(&[_]Feature{}), | |
| 159 | }; | |
| 160 | result[@enumToInt(Feature.message_security_assist_extension5)] = .{ | |
| 161 | .llvm_name = "message-security-assist-extension5", | |
| 162 | .description = "Assume that the message-security-assist extension facility 5 is installed", | |
| 163 | .dependencies = featureSet(&[_]Feature{}), | |
| 164 | }; | |
| 165 | result[@enumToInt(Feature.message_security_assist_extension7)] = .{ | |
| 166 | .llvm_name = "message-security-assist-extension7", | |
| 167 | .description = "Assume that the message-security-assist extension facility 7 is installed", | |
| 168 | .dependencies = featureSet(&[_]Feature{}), | |
| 169 | }; | |
| 170 | result[@enumToInt(Feature.message_security_assist_extension8)] = .{ | |
| 171 | .llvm_name = "message-security-assist-extension8", | |
| 172 | .description = "Assume that the message-security-assist extension facility 8 is installed", | |
| 173 | .dependencies = featureSet(&[_]Feature{}), | |
| 174 | }; | |
| 175 | result[@enumToInt(Feature.message_security_assist_extension9)] = .{ | |
| 176 | .llvm_name = "message-security-assist-extension9", | |
| 177 | .description = "Assume that the message-security-assist extension facility 9 is installed", | |
| 178 | .dependencies = featureSet(&[_]Feature{}), | |
| 179 | }; | |
| 180 | result[@enumToInt(Feature.miscellaneous_extensions)] = .{ | |
| 181 | .llvm_name = "miscellaneous-extensions", | |
| 182 | .description = "Assume that the miscellaneous-extensions facility is installed", | |
| 183 | .dependencies = featureSet(&[_]Feature{}), | |
| 184 | }; | |
| 185 | result[@enumToInt(Feature.miscellaneous_extensions_2)] = .{ | |
| 186 | .llvm_name = "miscellaneous-extensions-2", | |
| 187 | .description = "Assume that the miscellaneous-extensions facility 2 is installed", | |
| 188 | .dependencies = featureSet(&[_]Feature{}), | |
| 189 | }; | |
| 190 | result[@enumToInt(Feature.miscellaneous_extensions_3)] = .{ | |
| 191 | .llvm_name = "miscellaneous-extensions-3", | |
| 192 | .description = "Assume that the miscellaneous-extensions facility 3 is installed", | |
| 193 | .dependencies = featureSet(&[_]Feature{}), | |
| 194 | }; | |
| 195 | result[@enumToInt(Feature.nnp_assist)] = .{ | |
| 196 | .llvm_name = "nnp-assist", | |
| 197 | .description = "Assume that the NNP-assist facility is installed", | |
| 198 | .dependencies = featureSet(&[_]Feature{}), | |
| 199 | }; | |
| 200 | result[@enumToInt(Feature.population_count)] = .{ | |
| 201 | .llvm_name = "population-count", | |
| 202 | .description = "Assume that the population-count facility is installed", | |
| 203 | .dependencies = featureSet(&[_]Feature{}), | |
| 204 | }; | |
| 205 | result[@enumToInt(Feature.processor_activity_instrumentation)] = .{ | |
| 206 | .llvm_name = "processor-activity-instrumentation", | |
| 207 | .description = "Assume that the processor-activity-instrumentation facility is installed", | |
| 208 | .dependencies = featureSet(&[_]Feature{}), | |
| 209 | }; | |
| 210 | result[@enumToInt(Feature.processor_assist)] = .{ | |
| 211 | .llvm_name = "processor-assist", | |
| 212 | .description = "Assume that the processor-assist facility is installed", | |
| 213 | .dependencies = featureSet(&[_]Feature{}), | |
| 214 | }; | |
| 215 | result[@enumToInt(Feature.reset_dat_protection)] = .{ | |
| 216 | .llvm_name = "reset-dat-protection", | |
| 217 | .description = "Assume that the reset-DAT-protection facility is installed", | |
| 218 | .dependencies = featureSet(&[_]Feature{}), | |
| 219 | }; | |
| 220 | result[@enumToInt(Feature.reset_reference_bits_multiple)] = .{ | |
| 221 | .llvm_name = "reset-reference-bits-multiple", | |
| 222 | .description = "Assume that the reset-reference-bits-multiple facility is installed", | |
| 223 | .dependencies = featureSet(&[_]Feature{}), | |
| 224 | }; | |
| 225 | result[@enumToInt(Feature.soft_float)] = .{ | |
| 226 | .llvm_name = "soft-float", | |
| 227 | .description = "Use software emulation for floating point", | |
| 228 | .dependencies = featureSet(&[_]Feature{}), | |
| 229 | }; | |
| 230 | result[@enumToInt(Feature.transactional_execution)] = .{ | |
| 231 | .llvm_name = "transactional-execution", | |
| 232 | .description = "Assume that the transactional-execution facility is installed", | |
| 233 | .dependencies = featureSet(&[_]Feature{}), | |
| 234 | }; | |
| 235 | result[@enumToInt(Feature.vector)] = .{ | |
| 236 | .llvm_name = "vector", | |
| 237 | .description = "Assume that the vectory facility is installed", | |
| 238 | .dependencies = featureSet(&[_]Feature{}), | |
| 239 | }; | |
| 240 | result[@enumToInt(Feature.vector_enhancements_1)] = .{ | |
| 241 | .llvm_name = "vector-enhancements-1", | |
| 242 | .description = "Assume that the vector enhancements facility 1 is installed", | |
| 243 | .dependencies = featureSet(&[_]Feature{}), | |
| 244 | }; | |
| 245 | result[@enumToInt(Feature.vector_enhancements_2)] = .{ | |
| 246 | .llvm_name = "vector-enhancements-2", | |
| 247 | .description = "Assume that the vector enhancements facility 2 is installed", | |
| 248 | .dependencies = featureSet(&[_]Feature{}), | |
| 249 | }; | |
| 250 | result[@enumToInt(Feature.vector_packed_decimal)] = .{ | |
| 251 | .llvm_name = "vector-packed-decimal", | |
| 252 | .description = "Assume that the vector packed decimal facility is installed", | |
| 253 | .dependencies = featureSet(&[_]Feature{}), | |
| 254 | }; | |
| 255 | result[@enumToInt(Feature.vector_packed_decimal_enhancement)] = .{ | |
| 256 | .llvm_name = "vector-packed-decimal-enhancement", | |
| 257 | .description = "Assume that the vector packed decimal enhancement facility is installed", | |
| 258 | .dependencies = featureSet(&[_]Feature{}), | |
| 259 | }; | |
| 260 | result[@enumToInt(Feature.vector_packed_decimal_enhancement_2)] = .{ | |
| 261 | .llvm_name = "vector-packed-decimal-enhancement-2", | |
| 262 | .description = "Assume that the vector packed decimal enhancement facility 2 is installed", | |
| 263 | .dependencies = featureSet(&[_]Feature{}), | |
| 264 | }; | |
| 265 | const ti = @typeInfo(Feature); | |
| 266 | for (result) |*elem, i| { | |
| 267 | elem.index = i; | |
| 268 | elem.name = ti.Enum.fields[i].name; | |
| 269 | } | |
| 270 | break :blk result; | |
| 271 | }; | |
| 272 | ||
| 273 | pub const cpu = struct { | |
| 274 | pub const arch10 = CpuModel{ | |
| 275 | .name = "arch10", | |
| 276 | .llvm_name = "arch10", | |
| 277 | .features = featureSet(&[_]Feature{ | |
| 278 | .dfp_zoned_conversion, | |
| 279 | .distinct_ops, | |
| 280 | .enhanced_dat_2, | |
| 281 | .execution_hint, | |
| 282 | .fast_serialization, | |
| 283 | .fp_extension, | |
| 284 | .high_word, | |
| 285 | .interlocked_access1, | |
| 286 | .load_and_trap, | |
| 287 | .load_store_on_cond, | |
| 288 | .message_security_assist_extension3, | |
| 289 | .message_security_assist_extension4, | |
| 290 | .miscellaneous_extensions, | |
| 291 | .population_count, | |
| 292 | .processor_assist, | |
| 293 | .reset_reference_bits_multiple, | |
| 294 | .transactional_execution, | |
| 295 | }), | |
| 296 | }; | |
| 297 | pub const arch11 = CpuModel{ | |
| 298 | .name = "arch11", | |
| 299 | .llvm_name = "arch11", | |
| 300 | .features = featureSet(&[_]Feature{ | |
| 301 | .dfp_packed_conversion, | |
| 302 | .dfp_zoned_conversion, | |
| 303 | .distinct_ops, | |
| 304 | .enhanced_dat_2, | |
| 305 | .execution_hint, | |
| 306 | .fast_serialization, | |
| 307 | .fp_extension, | |
| 308 | .high_word, | |
| 309 | .interlocked_access1, | |
| 310 | .load_and_trap, | |
| 311 | .load_and_zero_rightmost_byte, | |
| 312 | .load_store_on_cond, | |
| 313 | .load_store_on_cond_2, | |
| 314 | .message_security_assist_extension3, | |
| 315 | .message_security_assist_extension4, | |
| 316 | .message_security_assist_extension5, | |
| 317 | .miscellaneous_extensions, | |
| 318 | .population_count, | |
| 319 | .processor_assist, | |
| 320 | .reset_reference_bits_multiple, | |
| 321 | .transactional_execution, | |
| 322 | .vector, | |
| 323 | }), | |
| 324 | }; | |
| 325 | pub const arch12 = CpuModel{ | |
| 326 | .name = "arch12", | |
| 327 | .llvm_name = "arch12", | |
| 328 | .features = featureSet(&[_]Feature{ | |
| 329 | .dfp_packed_conversion, | |
| 330 | .dfp_zoned_conversion, | |
| 331 | .distinct_ops, | |
| 332 | .enhanced_dat_2, | |
| 333 | .execution_hint, | |
| 334 | .fast_serialization, | |
| 335 | .fp_extension, | |
| 336 | .guarded_storage, | |
| 337 | .high_word, | |
| 338 | .insert_reference_bits_multiple, | |
| 339 | .interlocked_access1, | |
| 340 | .load_and_trap, | |
| 341 | .load_and_zero_rightmost_byte, | |
| 342 | .load_store_on_cond, | |
| 343 | .load_store_on_cond_2, | |
| 344 | .message_security_assist_extension3, | |
| 345 | .message_security_assist_extension4, | |
| 346 | .message_security_assist_extension5, | |
| 347 | .message_security_assist_extension7, | |
| 348 | .message_security_assist_extension8, | |
| 349 | .miscellaneous_extensions, | |
| 350 | .miscellaneous_extensions_2, | |
| 351 | .population_count, | |
| 352 | .processor_assist, | |
| 353 | .reset_reference_bits_multiple, | |
| 354 | .transactional_execution, | |
| 355 | .vector, | |
| 356 | .vector_enhancements_1, | |
| 357 | .vector_packed_decimal, | |
| 358 | }), | |
| 359 | }; | |
| 360 | pub const arch13 = CpuModel{ | |
| 361 | .name = "arch13", | |
| 362 | .llvm_name = "arch13", | |
| 363 | .features = featureSet(&[_]Feature{ | |
| 364 | .deflate_conversion, | |
| 365 | .dfp_packed_conversion, | |
| 366 | .dfp_zoned_conversion, | |
| 367 | .distinct_ops, | |
| 368 | .enhanced_dat_2, | |
| 369 | .enhanced_sort, | |
| 370 | .execution_hint, | |
| 371 | .fast_serialization, | |
| 372 | .fp_extension, | |
| 373 | .guarded_storage, | |
| 374 | .high_word, | |
| 375 | .insert_reference_bits_multiple, | |
| 376 | .interlocked_access1, | |
| 377 | .load_and_trap, | |
| 378 | .load_and_zero_rightmost_byte, | |
| 379 | .load_store_on_cond, | |
| 380 | .load_store_on_cond_2, | |
| 381 | .message_security_assist_extension3, | |
| 382 | .message_security_assist_extension4, | |
| 383 | .message_security_assist_extension5, | |
| 384 | .message_security_assist_extension7, | |
| 385 | .message_security_assist_extension8, | |
| 386 | .message_security_assist_extension9, | |
| 387 | .miscellaneous_extensions, | |
| 388 | .miscellaneous_extensions_2, | |
| 389 | .miscellaneous_extensions_3, | |
| 390 | .population_count, | |
| 391 | .processor_assist, | |
| 392 | .reset_reference_bits_multiple, | |
| 393 | .transactional_execution, | |
| 394 | .vector, | |
| 395 | .vector_enhancements_1, | |
| 396 | .vector_enhancements_2, | |
| 397 | .vector_packed_decimal, | |
| 398 | .vector_packed_decimal_enhancement, | |
| 399 | }), | |
| 400 | }; | |
| 401 | pub const arch14 = CpuModel{ | |
| 402 | .name = "arch14", | |
| 403 | .llvm_name = "arch14", | |
| 404 | .features = featureSet(&[_]Feature{ | |
| 405 | .bear_enhancement, | |
| 406 | .deflate_conversion, | |
| 407 | .dfp_packed_conversion, | |
| 408 | .dfp_zoned_conversion, | |
| 409 | .distinct_ops, | |
| 410 | .enhanced_dat_2, | |
| 411 | .enhanced_sort, | |
| 412 | .execution_hint, | |
| 413 | .fast_serialization, | |
| 414 | .fp_extension, | |
| 415 | .guarded_storage, | |
| 416 | .high_word, | |
| 417 | .insert_reference_bits_multiple, | |
| 418 | .interlocked_access1, | |
| 419 | .load_and_trap, | |
| 420 | .load_and_zero_rightmost_byte, | |
| 421 | .load_store_on_cond, | |
| 422 | .load_store_on_cond_2, | |
| 423 | .message_security_assist_extension3, | |
| 424 | .message_security_assist_extension4, | |
| 425 | .message_security_assist_extension5, | |
| 426 | .message_security_assist_extension7, | |
| 427 | .message_security_assist_extension8, | |
| 428 | .message_security_assist_extension9, | |
| 429 | .miscellaneous_extensions, | |
| 430 | .miscellaneous_extensions_2, | |
| 431 | .miscellaneous_extensions_3, | |
| 432 | .nnp_assist, | |
| 433 | .population_count, | |
| 434 | .processor_activity_instrumentation, | |
| 435 | .processor_assist, | |
| 436 | .reset_dat_protection, | |
| 437 | .reset_reference_bits_multiple, | |
| 438 | .transactional_execution, | |
| 439 | .vector, | |
| 440 | .vector_enhancements_1, | |
| 441 | .vector_enhancements_2, | |
| 442 | .vector_packed_decimal, | |
| 443 | .vector_packed_decimal_enhancement, | |
| 444 | .vector_packed_decimal_enhancement_2, | |
| 445 | }), | |
| 446 | }; | |
| 447 | pub const arch8 = CpuModel{ | |
| 448 | .name = "arch8", | |
| 449 | .llvm_name = "arch8", | |
| 450 | .features = featureSet(&[_]Feature{}), | |
| 451 | }; | |
| 452 | pub const arch9 = CpuModel{ | |
| 453 | .name = "arch9", | |
| 454 | .llvm_name = "arch9", | |
| 455 | .features = featureSet(&[_]Feature{ | |
| 456 | .distinct_ops, | |
| 457 | .fast_serialization, | |
| 458 | .fp_extension, | |
| 459 | .high_word, | |
| 460 | .interlocked_access1, | |
| 461 | .load_store_on_cond, | |
| 462 | .message_security_assist_extension3, | |
| 463 | .message_security_assist_extension4, | |
| 464 | .population_count, | |
| 465 | .reset_reference_bits_multiple, | |
| 466 | }), | |
| 467 | }; | |
| 468 | pub const generic = CpuModel{ | |
| 469 | .name = "generic", | |
| 470 | .llvm_name = "generic", | |
| 471 | .features = featureSet(&[_]Feature{}), | |
| 472 | }; | |
| 473 | pub const z10 = CpuModel{ | |
| 474 | .name = "z10", | |
| 475 | .llvm_name = "z10", | |
| 476 | .features = featureSet(&[_]Feature{}), | |
| 477 | }; | |
| 478 | pub const z13 = CpuModel{ | |
| 479 | .name = "z13", | |
| 480 | .llvm_name = "z13", | |
| 481 | .features = featureSet(&[_]Feature{ | |
| 482 | .dfp_packed_conversion, | |
| 483 | .dfp_zoned_conversion, | |
| 484 | .distinct_ops, | |
| 485 | .enhanced_dat_2, | |
| 486 | .execution_hint, | |
| 487 | .fast_serialization, | |
| 488 | .fp_extension, | |
| 489 | .high_word, | |
| 490 | .interlocked_access1, | |
| 491 | .load_and_trap, | |
| 492 | .load_and_zero_rightmost_byte, | |
| 493 | .load_store_on_cond, | |
| 494 | .load_store_on_cond_2, | |
| 495 | .message_security_assist_extension3, | |
| 496 | .message_security_assist_extension4, | |
| 497 | .message_security_assist_extension5, | |
| 498 | .miscellaneous_extensions, | |
| 499 | .population_count, | |
| 500 | .processor_assist, | |
| 501 | .reset_reference_bits_multiple, | |
| 502 | .transactional_execution, | |
| 503 | .vector, | |
| 504 | }), | |
| 505 | }; | |
| 506 | pub const z14 = CpuModel{ | |
| 507 | .name = "z14", | |
| 508 | .llvm_name = "z14", | |
| 509 | .features = featureSet(&[_]Feature{ | |
| 510 | .dfp_packed_conversion, | |
| 511 | .dfp_zoned_conversion, | |
| 512 | .distinct_ops, | |
| 513 | .enhanced_dat_2, | |
| 514 | .execution_hint, | |
| 515 | .fast_serialization, | |
| 516 | .fp_extension, | |
| 517 | .guarded_storage, | |
| 518 | .high_word, | |
| 519 | .insert_reference_bits_multiple, | |
| 520 | .interlocked_access1, | |
| 521 | .load_and_trap, | |
| 522 | .load_and_zero_rightmost_byte, | |
| 523 | .load_store_on_cond, | |
| 524 | .load_store_on_cond_2, | |
| 525 | .message_security_assist_extension3, | |
| 526 | .message_security_assist_extension4, | |
| 527 | .message_security_assist_extension5, | |
| 528 | .message_security_assist_extension7, | |
| 529 | .message_security_assist_extension8, | |
| 530 | .miscellaneous_extensions, | |
| 531 | .miscellaneous_extensions_2, | |
| 532 | .population_count, | |
| 533 | .processor_assist, | |
| 534 | .reset_reference_bits_multiple, | |
| 535 | .transactional_execution, | |
| 536 | .vector, | |
| 537 | .vector_enhancements_1, | |
| 538 | .vector_packed_decimal, | |
| 539 | }), | |
| 540 | }; | |
| 541 | pub const z15 = CpuModel{ | |
| 542 | .name = "z15", | |
| 543 | .llvm_name = "z15", | |
| 544 | .features = featureSet(&[_]Feature{ | |
| 545 | .deflate_conversion, | |
| 546 | .dfp_packed_conversion, | |
| 547 | .dfp_zoned_conversion, | |
| 548 | .distinct_ops, | |
| 549 | .enhanced_dat_2, | |
| 550 | .enhanced_sort, | |
| 551 | .execution_hint, | |
| 552 | .fast_serialization, | |
| 553 | .fp_extension, | |
| 554 | .guarded_storage, | |
| 555 | .high_word, | |
| 556 | .insert_reference_bits_multiple, | |
| 557 | .interlocked_access1, | |
| 558 | .load_and_trap, | |
| 559 | .load_and_zero_rightmost_byte, | |
| 560 | .load_store_on_cond, | |
| 561 | .load_store_on_cond_2, | |
| 562 | .message_security_assist_extension3, | |
| 563 | .message_security_assist_extension4, | |
| 564 | .message_security_assist_extension5, | |
| 565 | .message_security_assist_extension7, | |
| 566 | .message_security_assist_extension8, | |
| 567 | .message_security_assist_extension9, | |
| 568 | .miscellaneous_extensions, | |
| 569 | .miscellaneous_extensions_2, | |
| 570 | .miscellaneous_extensions_3, | |
| 571 | .population_count, | |
| 572 | .processor_assist, | |
| 573 | .reset_reference_bits_multiple, | |
| 574 | .transactional_execution, | |
| 575 | .vector, | |
| 576 | .vector_enhancements_1, | |
| 577 | .vector_enhancements_2, | |
| 578 | .vector_packed_decimal, | |
| 579 | .vector_packed_decimal_enhancement, | |
| 580 | }), | |
| 581 | }; | |
| 582 | pub const z196 = CpuModel{ | |
| 583 | .name = "z196", | |
| 584 | .llvm_name = "z196", | |
| 585 | .features = featureSet(&[_]Feature{ | |
| 586 | .distinct_ops, | |
| 587 | .fast_serialization, | |
| 588 | .fp_extension, | |
| 589 | .high_word, | |
| 590 | .interlocked_access1, | |
| 591 | .load_store_on_cond, | |
| 592 | .message_security_assist_extension3, | |
| 593 | .message_security_assist_extension4, | |
| 594 | .population_count, | |
| 595 | .reset_reference_bits_multiple, | |
| 596 | }), | |
| 597 | }; | |
| 598 | pub const zEC12 = CpuModel{ | |
| 599 | .name = "zEC12", | |
| 600 | .llvm_name = "zEC12", | |
| 601 | .features = featureSet(&[_]Feature{ | |
| 602 | .dfp_zoned_conversion, | |
| 603 | .distinct_ops, | |
| 604 | .enhanced_dat_2, | |
| 605 | .execution_hint, | |
| 606 | .fast_serialization, | |
| 607 | .fp_extension, | |
| 608 | .high_word, | |
| 609 | .interlocked_access1, | |
| 610 | .load_and_trap, | |
| 611 | .load_store_on_cond, | |
| 612 | .message_security_assist_extension3, | |
| 613 | .message_security_assist_extension4, | |
| 614 | .miscellaneous_extensions, | |
| 615 | .population_count, | |
| 616 | .processor_assist, | |
| 617 | .reset_reference_bits_multiple, | |
| 618 | .transactional_execution, | |
| 619 | }), | |
| 620 | }; | |
| 621 | }; |
lib/std/target/systemz.zig deleted-621| ... | ... | @@ -1,621 +0,0 @@ |
| 1 | //! This file is auto-generated by tools/update_cpu_features.zig. | |
| 2 | ||
| 3 | const std = @import("../std.zig"); | |
| 4 | const CpuFeature = std.Target.Cpu.Feature; | |
| 5 | const CpuModel = std.Target.Cpu.Model; | |
| 6 | ||
| 7 | pub const Feature = enum { | |
| 8 | bear_enhancement, | |
| 9 | deflate_conversion, | |
| 10 | dfp_packed_conversion, | |
| 11 | dfp_zoned_conversion, | |
| 12 | distinct_ops, | |
| 13 | enhanced_dat_2, | |
| 14 | enhanced_sort, | |
| 15 | execution_hint, | |
| 16 | fast_serialization, | |
| 17 | fp_extension, | |
| 18 | guarded_storage, | |
| 19 | high_word, | |
| 20 | insert_reference_bits_multiple, | |
| 21 | interlocked_access1, | |
| 22 | load_and_trap, | |
| 23 | load_and_zero_rightmost_byte, | |
| 24 | load_store_on_cond, | |
| 25 | load_store_on_cond_2, | |
| 26 | message_security_assist_extension3, | |
| 27 | message_security_assist_extension4, | |
| 28 | message_security_assist_extension5, | |
| 29 | message_security_assist_extension7, | |
| 30 | message_security_assist_extension8, | |
| 31 | message_security_assist_extension9, | |
| 32 | miscellaneous_extensions, | |
| 33 | miscellaneous_extensions_2, | |
| 34 | miscellaneous_extensions_3, | |
| 35 | nnp_assist, | |
| 36 | population_count, | |
| 37 | processor_activity_instrumentation, | |
| 38 | processor_assist, | |
| 39 | reset_dat_protection, | |
| 40 | reset_reference_bits_multiple, | |
| 41 | soft_float, | |
| 42 | transactional_execution, | |
| 43 | vector, | |
| 44 | vector_enhancements_1, | |
| 45 | vector_enhancements_2, | |
| 46 | vector_packed_decimal, | |
| 47 | vector_packed_decimal_enhancement, | |
| 48 | vector_packed_decimal_enhancement_2, | |
| 49 | }; | |
| 50 | ||
| 51 | pub const featureSet = CpuFeature.feature_set_fns(Feature).featureSet; | |
| 52 | pub const featureSetHas = CpuFeature.feature_set_fns(Feature).featureSetHas; | |
| 53 | pub const featureSetHasAny = CpuFeature.feature_set_fns(Feature).featureSetHasAny; | |
| 54 | pub const featureSetHasAll = CpuFeature.feature_set_fns(Feature).featureSetHasAll; | |
| 55 | ||
| 56 | pub const all_features = blk: { | |
| 57 | const len = @typeInfo(Feature).Enum.fields.len; | |
| 58 | std.debug.assert(len <= CpuFeature.Set.needed_bit_count); | |
| 59 | var result: [len]CpuFeature = undefined; | |
| 60 | result[@enumToInt(Feature.bear_enhancement)] = .{ | |
| 61 | .llvm_name = "bear-enhancement", | |
| 62 | .description = "Assume that the BEAR-enhancement facility is installed", | |
| 63 | .dependencies = featureSet(&[_]Feature{}), | |
| 64 | }; | |
| 65 | result[@enumToInt(Feature.deflate_conversion)] = .{ | |
| 66 | .llvm_name = "deflate-conversion", | |
| 67 | .description = "Assume that the deflate-conversion facility is installed", | |
| 68 | .dependencies = featureSet(&[_]Feature{}), | |
| 69 | }; | |
| 70 | result[@enumToInt(Feature.dfp_packed_conversion)] = .{ | |
| 71 | .llvm_name = "dfp-packed-conversion", | |
| 72 | .description = "Assume that the DFP packed-conversion facility is installed", | |
| 73 | .dependencies = featureSet(&[_]Feature{}), | |
| 74 | }; | |
| 75 | result[@enumToInt(Feature.dfp_zoned_conversion)] = .{ | |
| 76 | .llvm_name = "dfp-zoned-conversion", | |
| 77 | .description = "Assume that the DFP zoned-conversion facility is installed", | |
| 78 | .dependencies = featureSet(&[_]Feature{}), | |
| 79 | }; | |
| 80 | result[@enumToInt(Feature.distinct_ops)] = .{ | |
| 81 | .llvm_name = "distinct-ops", | |
| 82 | .description = "Assume that the distinct-operands facility is installed", | |
| 83 | .dependencies = featureSet(&[_]Feature{}), | |
| 84 | }; | |
| 85 | result[@enumToInt(Feature.enhanced_dat_2)] = .{ | |
| 86 | .llvm_name = "enhanced-dat-2", | |
| 87 | .description = "Assume that the enhanced-DAT facility 2 is installed", | |
| 88 | .dependencies = featureSet(&[_]Feature{}), | |
| 89 | }; | |
| 90 | result[@enumToInt(Feature.enhanced_sort)] = .{ | |
| 91 | .llvm_name = "enhanced-sort", | |
| 92 | .description = "Assume that the enhanced-sort facility is installed", | |
| 93 | .dependencies = featureSet(&[_]Feature{}), | |
| 94 | }; | |
| 95 | result[@enumToInt(Feature.execution_hint)] = .{ | |
| 96 | .llvm_name = "execution-hint", | |
| 97 | .description = "Assume that the execution-hint facility is installed", | |
| 98 | .dependencies = featureSet(&[_]Feature{}), | |
| 99 | }; | |
| 100 | result[@enumToInt(Feature.fast_serialization)] = .{ | |
| 101 | .llvm_name = "fast-serialization", | |
| 102 | .description = "Assume that the fast-serialization facility is installed", | |
| 103 | .dependencies = featureSet(&[_]Feature{}), | |
| 104 | }; | |
| 105 | result[@enumToInt(Feature.fp_extension)] = .{ | |
| 106 | .llvm_name = "fp-extension", | |
| 107 | .description = "Assume that the floating-point extension facility is installed", | |
| 108 | .dependencies = featureSet(&[_]Feature{}), | |
| 109 | }; | |
| 110 | result[@enumToInt(Feature.guarded_storage)] = .{ | |
| 111 | .llvm_name = "guarded-storage", | |
| 112 | .description = "Assume that the guarded-storage facility is installed", | |
| 113 | .dependencies = featureSet(&[_]Feature{}), | |
| 114 | }; | |
| 115 | result[@enumToInt(Feature.high_word)] = .{ | |
| 116 | .llvm_name = "high-word", | |
| 117 | .description = "Assume that the high-word facility is installed", | |
| 118 | .dependencies = featureSet(&[_]Feature{}), | |
| 119 | }; | |
| 120 | result[@enumToInt(Feature.insert_reference_bits_multiple)] = .{ | |
| 121 | .llvm_name = "insert-reference-bits-multiple", | |
| 122 | .description = "Assume that the insert-reference-bits-multiple facility is installed", | |
| 123 | .dependencies = featureSet(&[_]Feature{}), | |
| 124 | }; | |
| 125 | result[@enumToInt(Feature.interlocked_access1)] = .{ | |
| 126 | .llvm_name = "interlocked-access1", | |
| 127 | .description = "Assume that interlocked-access facility 1 is installed", | |
| 128 | .dependencies = featureSet(&[_]Feature{}), | |
| 129 | }; | |
| 130 | result[@enumToInt(Feature.load_and_trap)] = .{ | |
| 131 | .llvm_name = "load-and-trap", | |
| 132 | .description = "Assume that the load-and-trap facility is installed", | |
| 133 | .dependencies = featureSet(&[_]Feature{}), | |
| 134 | }; | |
| 135 | result[@enumToInt(Feature.load_and_zero_rightmost_byte)] = .{ | |
| 136 | .llvm_name = "load-and-zero-rightmost-byte", | |
| 137 | .description = "Assume that the load-and-zero-rightmost-byte facility is installed", | |
| 138 | .dependencies = featureSet(&[_]Feature{}), | |
| 139 | }; | |
| 140 | result[@enumToInt(Feature.load_store_on_cond)] = .{ | |
| 141 | .llvm_name = "load-store-on-cond", | |
| 142 | .description = "Assume that the load/store-on-condition facility is installed", | |
| 143 | .dependencies = featureSet(&[_]Feature{}), | |
| 144 | }; | |
| 145 | result[@enumToInt(Feature.load_store_on_cond_2)] = .{ | |
| 146 | .llvm_name = "load-store-on-cond-2", | |
| 147 | .description = "Assume that the load/store-on-condition facility 2 is installed", | |
| 148 | .dependencies = featureSet(&[_]Feature{}), | |
| 149 | }; | |
| 150 | result[@enumToInt(Feature.message_security_assist_extension3)] = .{ | |
| 151 | .llvm_name = "message-security-assist-extension3", | |
| 152 | .description = "Assume that the message-security-assist extension facility 3 is installed", | |
| 153 | .dependencies = featureSet(&[_]Feature{}), | |
| 154 | }; | |
| 155 | result[@enumToInt(Feature.message_security_assist_extension4)] = .{ | |
| 156 | .llvm_name = "message-security-assist-extension4", | |
| 157 | .description = "Assume that the message-security-assist extension facility 4 is installed", | |
| 158 | .dependencies = featureSet(&[_]Feature{}), | |
| 159 | }; | |
| 160 | result[@enumToInt(Feature.message_security_assist_extension5)] = .{ | |
| 161 | .llvm_name = "message-security-assist-extension5", | |
| 162 | .description = "Assume that the message-security-assist extension facility 5 is installed", | |
| 163 | .dependencies = featureSet(&[_]Feature{}), | |
| 164 | }; | |
| 165 | result[@enumToInt(Feature.message_security_assist_extension7)] = .{ | |
| 166 | .llvm_name = "message-security-assist-extension7", | |
| 167 | .description = "Assume that the message-security-assist extension facility 7 is installed", | |
| 168 | .dependencies = featureSet(&[_]Feature{}), | |
| 169 | }; | |
| 170 | result[@enumToInt(Feature.message_security_assist_extension8)] = .{ | |
| 171 | .llvm_name = "message-security-assist-extension8", | |
| 172 | .description = "Assume that the message-security-assist extension facility 8 is installed", | |
| 173 | .dependencies = featureSet(&[_]Feature{}), | |
| 174 | }; | |
| 175 | result[@enumToInt(Feature.message_security_assist_extension9)] = .{ | |
| 176 | .llvm_name = "message-security-assist-extension9", | |
| 177 | .description = "Assume that the message-security-assist extension facility 9 is installed", | |
| 178 | .dependencies = featureSet(&[_]Feature{}), | |
| 179 | }; | |
| 180 | result[@enumToInt(Feature.miscellaneous_extensions)] = .{ | |
| 181 | .llvm_name = "miscellaneous-extensions", | |
| 182 | .description = "Assume that the miscellaneous-extensions facility is installed", | |
| 183 | .dependencies = featureSet(&[_]Feature{}), | |
| 184 | }; | |
| 185 | result[@enumToInt(Feature.miscellaneous_extensions_2)] = .{ | |
| 186 | .llvm_name = "miscellaneous-extensions-2", | |
| 187 | .description = "Assume that the miscellaneous-extensions facility 2 is installed", | |
| 188 | .dependencies = featureSet(&[_]Feature{}), | |
| 189 | }; | |
| 190 | result[@enumToInt(Feature.miscellaneous_extensions_3)] = .{ | |
| 191 | .llvm_name = "miscellaneous-extensions-3", | |
| 192 | .description = "Assume that the miscellaneous-extensions facility 3 is installed", | |
| 193 | .dependencies = featureSet(&[_]Feature{}), | |
| 194 | }; | |
| 195 | result[@enumToInt(Feature.nnp_assist)] = .{ | |
| 196 | .llvm_name = "nnp-assist", | |
| 197 | .description = "Assume that the NNP-assist facility is installed", | |
| 198 | .dependencies = featureSet(&[_]Feature{}), | |
| 199 | }; | |
| 200 | result[@enumToInt(Feature.population_count)] = .{ | |
| 201 | .llvm_name = "population-count", | |
| 202 | .description = "Assume that the population-count facility is installed", | |
| 203 | .dependencies = featureSet(&[_]Feature{}), | |
| 204 | }; | |
| 205 | result[@enumToInt(Feature.processor_activity_instrumentation)] = .{ | |
| 206 | .llvm_name = "processor-activity-instrumentation", | |
| 207 | .description = "Assume that the processor-activity-instrumentation facility is installed", | |
| 208 | .dependencies = featureSet(&[_]Feature{}), | |
| 209 | }; | |
| 210 | result[@enumToInt(Feature.processor_assist)] = .{ | |
| 211 | .llvm_name = "processor-assist", | |
| 212 | .description = "Assume that the processor-assist facility is installed", | |
| 213 | .dependencies = featureSet(&[_]Feature{}), | |
| 214 | }; | |
| 215 | result[@enumToInt(Feature.reset_dat_protection)] = .{ | |
| 216 | .llvm_name = "reset-dat-protection", | |
| 217 | .description = "Assume that the reset-DAT-protection facility is installed", | |
| 218 | .dependencies = featureSet(&[_]Feature{}), | |
| 219 | }; | |
| 220 | result[@enumToInt(Feature.reset_reference_bits_multiple)] = .{ | |
| 221 | .llvm_name = "reset-reference-bits-multiple", | |
| 222 | .description = "Assume that the reset-reference-bits-multiple facility is installed", | |
| 223 | .dependencies = featureSet(&[_]Feature{}), | |
| 224 | }; | |
| 225 | result[@enumToInt(Feature.soft_float)] = .{ | |
| 226 | .llvm_name = "soft-float", | |
| 227 | .description = "Use software emulation for floating point", | |
| 228 | .dependencies = featureSet(&[_]Feature{}), | |
| 229 | }; | |
| 230 | result[@enumToInt(Feature.transactional_execution)] = .{ | |
| 231 | .llvm_name = "transactional-execution", | |
| 232 | .description = "Assume that the transactional-execution facility is installed", | |
| 233 | .dependencies = featureSet(&[_]Feature{}), | |
| 234 | }; | |
| 235 | result[@enumToInt(Feature.vector)] = .{ | |
| 236 | .llvm_name = "vector", | |
| 237 | .description = "Assume that the vectory facility is installed", | |
| 238 | .dependencies = featureSet(&[_]Feature{}), | |
| 239 | }; | |
| 240 | result[@enumToInt(Feature.vector_enhancements_1)] = .{ | |
| 241 | .llvm_name = "vector-enhancements-1", | |
| 242 | .description = "Assume that the vector enhancements facility 1 is installed", | |
| 243 | .dependencies = featureSet(&[_]Feature{}), | |
| 244 | }; | |
| 245 | result[@enumToInt(Feature.vector_enhancements_2)] = .{ | |
| 246 | .llvm_name = "vector-enhancements-2", | |
| 247 | .description = "Assume that the vector enhancements facility 2 is installed", | |
| 248 | .dependencies = featureSet(&[_]Feature{}), | |
| 249 | }; | |
| 250 | result[@enumToInt(Feature.vector_packed_decimal)] = .{ | |
| 251 | .llvm_name = "vector-packed-decimal", | |
| 252 | .description = "Assume that the vector packed decimal facility is installed", | |
| 253 | .dependencies = featureSet(&[_]Feature{}), | |
| 254 | }; | |
| 255 | result[@enumToInt(Feature.vector_packed_decimal_enhancement)] = .{ | |
| 256 | .llvm_name = "vector-packed-decimal-enhancement", | |
| 257 | .description = "Assume that the vector packed decimal enhancement facility is installed", | |
| 258 | .dependencies = featureSet(&[_]Feature{}), | |
| 259 | }; | |
| 260 | result[@enumToInt(Feature.vector_packed_decimal_enhancement_2)] = .{ | |
| 261 | .llvm_name = "vector-packed-decimal-enhancement-2", | |
| 262 | .description = "Assume that the vector packed decimal enhancement facility 2 is installed", | |
| 263 | .dependencies = featureSet(&[_]Feature{}), | |
| 264 | }; | |
| 265 | const ti = @typeInfo(Feature); | |
| 266 | for (result) |*elem, i| { | |
| 267 | elem.index = i; | |
| 268 | elem.name = ti.Enum.fields[i].name; | |
| 269 | } | |
| 270 | break :blk result; | |
| 271 | }; | |
| 272 | ||
| 273 | pub const cpu = struct { | |
| 274 | pub const arch10 = CpuModel{ | |
| 275 | .name = "arch10", | |
| 276 | .llvm_name = "arch10", | |
| 277 | .features = featureSet(&[_]Feature{ | |
| 278 | .dfp_zoned_conversion, | |
| 279 | .distinct_ops, | |
| 280 | .enhanced_dat_2, | |
| 281 | .execution_hint, | |
| 282 | .fast_serialization, | |
| 283 | .fp_extension, | |
| 284 | .high_word, | |
| 285 | .interlocked_access1, | |
| 286 | .load_and_trap, | |
| 287 | .load_store_on_cond, | |
| 288 | .message_security_assist_extension3, | |
| 289 | .message_security_assist_extension4, | |
| 290 | .miscellaneous_extensions, | |
| 291 | .population_count, | |
| 292 | .processor_assist, | |
| 293 | .reset_reference_bits_multiple, | |
| 294 | .transactional_execution, | |
| 295 | }), | |
| 296 | }; | |
| 297 | pub const arch11 = CpuModel{ | |
| 298 | .name = "arch11", | |
| 299 | .llvm_name = "arch11", | |
| 300 | .features = featureSet(&[_]Feature{ | |
| 301 | .dfp_packed_conversion, | |
| 302 | .dfp_zoned_conversion, | |
| 303 | .distinct_ops, | |
| 304 | .enhanced_dat_2, | |
| 305 | .execution_hint, | |
| 306 | .fast_serialization, | |
| 307 | .fp_extension, | |
| 308 | .high_word, | |
| 309 | .interlocked_access1, | |
| 310 | .load_and_trap, | |
| 311 | .load_and_zero_rightmost_byte, | |
| 312 | .load_store_on_cond, | |
| 313 | .load_store_on_cond_2, | |
| 314 | .message_security_assist_extension3, | |
| 315 | .message_security_assist_extension4, | |
| 316 | .message_security_assist_extension5, | |
| 317 | .miscellaneous_extensions, | |
| 318 | .population_count, | |
| 319 | .processor_assist, | |
| 320 | .reset_reference_bits_multiple, | |
| 321 | .transactional_execution, | |
| 322 | .vector, | |
| 323 | }), | |
| 324 | }; | |
| 325 | pub const arch12 = CpuModel{ | |
| 326 | .name = "arch12", | |
| 327 | .llvm_name = "arch12", | |
| 328 | .features = featureSet(&[_]Feature{ | |
| 329 | .dfp_packed_conversion, | |
| 330 | .dfp_zoned_conversion, | |
| 331 | .distinct_ops, | |
| 332 | .enhanced_dat_2, | |
| 333 | .execution_hint, | |
| 334 | .fast_serialization, | |
| 335 | .fp_extension, | |
| 336 | .guarded_storage, | |
| 337 | .high_word, | |
| 338 | .insert_reference_bits_multiple, | |
| 339 | .interlocked_access1, | |
| 340 | .load_and_trap, | |
| 341 | .load_and_zero_rightmost_byte, | |
| 342 | .load_store_on_cond, | |
| 343 | .load_store_on_cond_2, | |
| 344 | .message_security_assist_extension3, | |
| 345 | .message_security_assist_extension4, | |
| 346 | .message_security_assist_extension5, | |
| 347 | .message_security_assist_extension7, | |
| 348 | .message_security_assist_extension8, | |
| 349 | .miscellaneous_extensions, | |
| 350 | .miscellaneous_extensions_2, | |
| 351 | .population_count, | |
| 352 | .processor_assist, | |
| 353 | .reset_reference_bits_multiple, | |
| 354 | .transactional_execution, | |
| 355 | .vector, | |
| 356 | .vector_enhancements_1, | |
| 357 | .vector_packed_decimal, | |
| 358 | }), | |
| 359 | }; | |
| 360 | pub const arch13 = CpuModel{ | |
| 361 | .name = "arch13", | |
| 362 | .llvm_name = "arch13", | |
| 363 | .features = featureSet(&[_]Feature{ | |
| 364 | .deflate_conversion, | |
| 365 | .dfp_packed_conversion, | |
| 366 | .dfp_zoned_conversion, | |
| 367 | .distinct_ops, | |
| 368 | .enhanced_dat_2, | |
| 369 | .enhanced_sort, | |
| 370 | .execution_hint, | |
| 371 | .fast_serialization, | |
| 372 | .fp_extension, | |
| 373 | .guarded_storage, | |
| 374 | .high_word, | |
| 375 | .insert_reference_bits_multiple, | |
| 376 | .interlocked_access1, | |
| 377 | .load_and_trap, | |
| 378 | .load_and_zero_rightmost_byte, | |
| 379 | .load_store_on_cond, | |
| 380 | .load_store_on_cond_2, | |
| 381 | .message_security_assist_extension3, | |
| 382 | .message_security_assist_extension4, | |
| 383 | .message_security_assist_extension5, | |
| 384 | .message_security_assist_extension7, | |
| 385 | .message_security_assist_extension8, | |
| 386 | .message_security_assist_extension9, | |
| 387 | .miscellaneous_extensions, | |
| 388 | .miscellaneous_extensions_2, | |
| 389 | .miscellaneous_extensions_3, | |
| 390 | .population_count, | |
| 391 | .processor_assist, | |
| 392 | .reset_reference_bits_multiple, | |
| 393 | .transactional_execution, | |
| 394 | .vector, | |
| 395 | .vector_enhancements_1, | |
| 396 | .vector_enhancements_2, | |
| 397 | .vector_packed_decimal, | |
| 398 | .vector_packed_decimal_enhancement, | |
| 399 | }), | |
| 400 | }; | |
| 401 | pub const arch14 = CpuModel{ | |
| 402 | .name = "arch14", | |
| 403 | .llvm_name = "arch14", | |
| 404 | .features = featureSet(&[_]Feature{ | |
| 405 | .bear_enhancement, | |
| 406 | .deflate_conversion, | |
| 407 | .dfp_packed_conversion, | |
| 408 | .dfp_zoned_conversion, | |
| 409 | .distinct_ops, | |
| 410 | .enhanced_dat_2, | |
| 411 | .enhanced_sort, | |
| 412 | .execution_hint, | |
| 413 | .fast_serialization, | |
| 414 | .fp_extension, | |
| 415 | .guarded_storage, | |
| 416 | .high_word, | |
| 417 | .insert_reference_bits_multiple, | |
| 418 | .interlocked_access1, | |
| 419 | .load_and_trap, | |
| 420 | .load_and_zero_rightmost_byte, | |
| 421 | .load_store_on_cond, | |
| 422 | .load_store_on_cond_2, | |
| 423 | .message_security_assist_extension3, | |
| 424 | .message_security_assist_extension4, | |
| 425 | .message_security_assist_extension5, | |
| 426 | .message_security_assist_extension7, | |
| 427 | .message_security_assist_extension8, | |
| 428 | .message_security_assist_extension9, | |
| 429 | .miscellaneous_extensions, | |
| 430 | .miscellaneous_extensions_2, | |
| 431 | .miscellaneous_extensions_3, | |
| 432 | .nnp_assist, | |
| 433 | .population_count, | |
| 434 | .processor_activity_instrumentation, | |
| 435 | .processor_assist, | |
| 436 | .reset_dat_protection, | |
| 437 | .reset_reference_bits_multiple, | |
| 438 | .transactional_execution, | |
| 439 | .vector, | |
| 440 | .vector_enhancements_1, | |
| 441 | .vector_enhancements_2, | |
| 442 | .vector_packed_decimal, | |
| 443 | .vector_packed_decimal_enhancement, | |
| 444 | .vector_packed_decimal_enhancement_2, | |
| 445 | }), | |
| 446 | }; | |
| 447 | pub const arch8 = CpuModel{ | |
| 448 | .name = "arch8", | |
| 449 | .llvm_name = "arch8", | |
| 450 | .features = featureSet(&[_]Feature{}), | |
| 451 | }; | |
| 452 | pub const arch9 = CpuModel{ | |
| 453 | .name = "arch9", | |
| 454 | .llvm_name = "arch9", | |
| 455 | .features = featureSet(&[_]Feature{ | |
| 456 | .distinct_ops, | |
| 457 | .fast_serialization, | |
| 458 | .fp_extension, | |
| 459 | .high_word, | |
| 460 | .interlocked_access1, | |
| 461 | .load_store_on_cond, | |
| 462 | .message_security_assist_extension3, | |
| 463 | .message_security_assist_extension4, | |
| 464 | .population_count, | |
| 465 | .reset_reference_bits_multiple, | |
| 466 | }), | |
| 467 | }; | |
| 468 | pub const generic = CpuModel{ | |
| 469 | .name = "generic", | |
| 470 | .llvm_name = "generic", | |
| 471 | .features = featureSet(&[_]Feature{}), | |
| 472 | }; | |
| 473 | pub const z10 = CpuModel{ | |
| 474 | .name = "z10", | |
| 475 | .llvm_name = "z10", | |
| 476 | .features = featureSet(&[_]Feature{}), | |
| 477 | }; | |
| 478 | pub const z13 = CpuModel{ | |
| 479 | .name = "z13", | |
| 480 | .llvm_name = "z13", | |
| 481 | .features = featureSet(&[_]Feature{ | |
| 482 | .dfp_packed_conversion, | |
| 483 | .dfp_zoned_conversion, | |
| 484 | .distinct_ops, | |
| 485 | .enhanced_dat_2, | |
| 486 | .execution_hint, | |
| 487 | .fast_serialization, | |
| 488 | .fp_extension, | |
| 489 | .high_word, | |
| 490 | .interlocked_access1, | |
| 491 | .load_and_trap, | |
| 492 | .load_and_zero_rightmost_byte, | |
| 493 | .load_store_on_cond, | |
| 494 | .load_store_on_cond_2, | |
| 495 | .message_security_assist_extension3, | |
| 496 | .message_security_assist_extension4, | |
| 497 | .message_security_assist_extension5, | |
| 498 | .miscellaneous_extensions, | |
| 499 | .population_count, | |
| 500 | .processor_assist, | |
| 501 | .reset_reference_bits_multiple, | |
| 502 | .transactional_execution, | |
| 503 | .vector, | |
| 504 | }), | |
| 505 | }; | |
| 506 | pub const z14 = CpuModel{ | |
| 507 | .name = "z14", | |
| 508 | .llvm_name = "z14", | |
| 509 | .features = featureSet(&[_]Feature{ | |
| 510 | .dfp_packed_conversion, | |
| 511 | .dfp_zoned_conversion, | |
| 512 | .distinct_ops, | |
| 513 | .enhanced_dat_2, | |
| 514 | .execution_hint, | |
| 515 | .fast_serialization, | |
| 516 | .fp_extension, | |
| 517 | .guarded_storage, | |
| 518 | .high_word, | |
| 519 | .insert_reference_bits_multiple, | |
| 520 | .interlocked_access1, | |
| 521 | .load_and_trap, | |
| 522 | .load_and_zero_rightmost_byte, | |
| 523 | .load_store_on_cond, | |
| 524 | .load_store_on_cond_2, | |
| 525 | .message_security_assist_extension3, | |
| 526 | .message_security_assist_extension4, | |
| 527 | .message_security_assist_extension5, | |
| 528 | .message_security_assist_extension7, | |
| 529 | .message_security_assist_extension8, | |
| 530 | .miscellaneous_extensions, | |
| 531 | .miscellaneous_extensions_2, | |
| 532 | .population_count, | |
| 533 | .processor_assist, | |
| 534 | .reset_reference_bits_multiple, | |
| 535 | .transactional_execution, | |
| 536 | .vector, | |
| 537 | .vector_enhancements_1, | |
| 538 | .vector_packed_decimal, | |
| 539 | }), | |
| 540 | }; | |
| 541 | pub const z15 = CpuModel{ | |
| 542 | .name = "z15", | |
| 543 | .llvm_name = "z15", | |
| 544 | .features = featureSet(&[_]Feature{ | |
| 545 | .deflate_conversion, | |
| 546 | .dfp_packed_conversion, | |
| 547 | .dfp_zoned_conversion, | |
| 548 | .distinct_ops, | |
| 549 | .enhanced_dat_2, | |
| 550 | .enhanced_sort, | |
| 551 | .execution_hint, | |
| 552 | .fast_serialization, | |
| 553 | .fp_extension, | |
| 554 | .guarded_storage, | |
| 555 | .high_word, | |
| 556 | .insert_reference_bits_multiple, | |
| 557 | .interlocked_access1, | |
| 558 | .load_and_trap, | |
| 559 | .load_and_zero_rightmost_byte, | |
| 560 | .load_store_on_cond, | |
| 561 | .load_store_on_cond_2, | |
| 562 | .message_security_assist_extension3, | |
| 563 | .message_security_assist_extension4, | |
| 564 | .message_security_assist_extension5, | |
| 565 | .message_security_assist_extension7, | |
| 566 | .message_security_assist_extension8, | |
| 567 | .message_security_assist_extension9, | |
| 568 | .miscellaneous_extensions, | |
| 569 | .miscellaneous_extensions_2, | |
| 570 | .miscellaneous_extensions_3, | |
| 571 | .population_count, | |
| 572 | .processor_assist, | |
| 573 | .reset_reference_bits_multiple, | |
| 574 | .transactional_execution, | |
| 575 | .vector, | |
| 576 | .vector_enhancements_1, | |
| 577 | .vector_enhancements_2, | |
| 578 | .vector_packed_decimal, | |
| 579 | .vector_packed_decimal_enhancement, | |
| 580 | }), | |
| 581 | }; | |
| 582 | pub const z196 = CpuModel{ | |
| 583 | .name = "z196", | |
| 584 | .llvm_name = "z196", | |
| 585 | .features = featureSet(&[_]Feature{ | |
| 586 | .distinct_ops, | |
| 587 | .fast_serialization, | |
| 588 | .fp_extension, | |
| 589 | .high_word, | |
| 590 | .interlocked_access1, | |
| 591 | .load_store_on_cond, | |
| 592 | .message_security_assist_extension3, | |
| 593 | .message_security_assist_extension4, | |
| 594 | .population_count, | |
| 595 | .reset_reference_bits_multiple, | |
| 596 | }), | |
| 597 | }; | |
| 598 | pub const zEC12 = CpuModel{ | |
| 599 | .name = "zEC12", | |
| 600 | .llvm_name = "zEC12", | |
| 601 | .features = featureSet(&[_]Feature{ | |
| 602 | .dfp_zoned_conversion, | |
| 603 | .distinct_ops, | |
| 604 | .enhanced_dat_2, | |
| 605 | .execution_hint, | |
| 606 | .fast_serialization, | |
| 607 | .fp_extension, | |
| 608 | .high_word, | |
| 609 | .interlocked_access1, | |
| 610 | .load_and_trap, | |
| 611 | .load_store_on_cond, | |
| 612 | .message_security_assist_extension3, | |
| 613 | .message_security_assist_extension4, | |
| 614 | .miscellaneous_extensions, | |
| 615 | .population_count, | |
| 616 | .processor_assist, | |
| 617 | .reset_reference_bits_multiple, | |
| 618 | .transactional_execution, | |
| 619 | }), | |
| 620 | }; | |
| 621 | }; |
lib/std/zig/parse.zig+1-1| ... | ... | @@ -3257,7 +3257,7 @@ const Parser = struct { |
| 3257 | 3257 | if (p.eatToken(.ellipsis2)) |_| { |
| 3258 | 3258 | const end_expr = try p.parseExpr(); |
| 3259 | 3259 | if (p.eatToken(.colon)) |_| { |
| 3260 | const sentinel = try p.parseExpr(); | |
| 3260 | const sentinel = try p.expectExpr(); | |
| 3261 | 3261 | _ = try p.expectToken(.r_bracket); |
| 3262 | 3262 | return p.addNode(.{ |
| 3263 | 3263 | .tag = .slice_sentinel, |
lib/std/zig/parser_test.zig+8| ... | ... | @@ -5118,6 +5118,14 @@ test "zig fmt: while continue expr" { |
| 5118 | 5118 | }); |
| 5119 | 5119 | } |
| 5120 | 5120 | |
| 5121 | test "zig fmt: error for missing sentinel value in sentinel slice" { | |
| 5122 | try testError( | |
| 5123 | \\const foo = foo[0..:]; | |
| 5124 | , &[_]Error{ | |
| 5125 | .expected_expr, | |
| 5126 | }); | |
| 5127 | } | |
| 5128 | ||
| 5121 | 5129 | test "zig fmt: error for invalid bit range" { |
| 5122 | 5130 | try testError( |
| 5123 | 5131 | \\var x: []align(0:0:0)u8 = bar; |
src/Air.zig+3-2| ... | ... | @@ -111,8 +111,9 @@ pub const Inst = struct { |
| 111 | 111 | div_floor, |
| 112 | 112 | /// Same as `div_floor` with optimized float mode. |
| 113 | 113 | div_floor_optimized, |
| 114 | /// Integer or float division. Guaranteed no remainder. | |
| 115 | /// For integers, wrapping is undefined behavior. | |
| 114 | /// Integer or float division. | |
| 115 | /// If a remainder would be produced, undefined behavior occurs. | |
| 116 | /// For integers, overflow is undefined behavior. | |
| 116 | 117 | /// Both operands are guaranteed to be the same type, and the result type |
| 117 | 118 | /// is the same as both operands. |
| 118 | 119 | /// Uses the `bin_op` field. |
src/AstGen.zig+8-1| ... | ... | @@ -1349,7 +1349,10 @@ fn arrayInitExpr( |
| 1349 | 1349 | } |
| 1350 | 1350 | } |
| 1351 | 1351 | const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); |
| 1352 | _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, array_init.ast.type_expr); | |
| 1352 | _ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{ | |
| 1353 | .ty = array_type_inst, | |
| 1354 | .init_count = @intCast(u32, array_init.ast.elements.len), | |
| 1355 | }); | |
| 1353 | 1356 | break :inst .{ |
| 1354 | 1357 | .array = array_type_inst, |
| 1355 | 1358 | .elem = .none, |
| ... | ... | @@ -1940,6 +1943,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) |
| 1940 | 1943 | .break_inline |
| 1941 | 1944 | else |
| 1942 | 1945 | .@"break"; |
| 1946 | if (break_tag == .break_inline) { | |
| 1947 | _ = try parent_gz.addNode(.check_comptime_control_flow, node); | |
| 1948 | } | |
| 1943 | 1949 | _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); |
| 1944 | 1950 | return Zir.Inst.Ref.unreachable_value; |
| 1945 | 1951 | }, |
| ... | ... | @@ -2473,6 +2479,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2473 | 2479 | .repeat_inline, |
| 2474 | 2480 | .panic, |
| 2475 | 2481 | .panic_comptime, |
| 2482 | .check_comptime_control_flow, | |
| 2476 | 2483 | => { |
| 2477 | 2484 | noreturn_src_node = statement; |
| 2478 | 2485 | break :b true; |
src/Compilation.zig-17| ... | ... | @@ -1494,31 +1494,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1494 | 1494 | ); |
| 1495 | 1495 | errdefer test_pkg.destroy(gpa); |
| 1496 | 1496 | |
| 1497 | try test_pkg.add(gpa, "builtin", builtin_pkg); | |
| 1498 | try test_pkg.add(gpa, "root", test_pkg); | |
| 1499 | try test_pkg.add(gpa, "std", std_pkg); | |
| 1500 | ||
| 1501 | 1497 | break :root_pkg test_pkg; |
| 1502 | 1498 | } else main_pkg; |
| 1503 | 1499 | errdefer if (options.is_test) root_pkg.destroy(gpa); |
| 1504 | 1500 | |
| 1505 | var other_pkg_iter = main_pkg.table.valueIterator(); | |
| 1506 | while (other_pkg_iter.next()) |pkg| { | |
| 1507 | try pkg.*.add(gpa, "builtin", builtin_pkg); | |
| 1508 | try pkg.*.add(gpa, "std", std_pkg); | |
| 1509 | } | |
| 1510 | ||
| 1511 | 1501 | try main_pkg.addAndAdopt(gpa, "builtin", builtin_pkg); |
| 1512 | 1502 | try main_pkg.add(gpa, "root", root_pkg); |
| 1513 | 1503 | try main_pkg.addAndAdopt(gpa, "std", std_pkg); |
| 1514 | 1504 | |
| 1515 | try std_pkg.add(gpa, "builtin", builtin_pkg); | |
| 1516 | try std_pkg.add(gpa, "root", root_pkg); | |
| 1517 | try std_pkg.add(gpa, "std", std_pkg); | |
| 1518 | ||
| 1519 | try builtin_pkg.add(gpa, "std", std_pkg); | |
| 1520 | try builtin_pkg.add(gpa, "builtin", builtin_pkg); | |
| 1521 | ||
| 1522 | 1505 | const main_pkg_in_std = m: { |
| 1523 | 1506 | const std_path = try std.fs.path.resolve(arena, &[_][]const u8{ |
| 1524 | 1507 | std_pkg.root_src_directory.path orelse ".", |
src/Module.zig+30| ... | ... | @@ -2283,6 +2283,8 @@ pub const SrcLoc = struct { |
| 2283 | 2283 | .@"while" => tree.whileFull(node).ast.cond_expr, |
| 2284 | 2284 | .for_simple => tree.forSimple(node).ast.cond_expr, |
| 2285 | 2285 | .@"for" => tree.forFull(node).ast.cond_expr, |
| 2286 | .@"orelse" => node, | |
| 2287 | .@"catch" => node, | |
| 2286 | 2288 | else => unreachable, |
| 2287 | 2289 | }; |
| 2288 | 2290 | return nodeToSpan(tree, src_node); |
| ... | ... | @@ -2726,6 +2728,21 @@ pub const SrcLoc = struct { |
| 2726 | 2728 | }; |
| 2727 | 2729 | return nodeToSpan(tree, full.ast.value_expr); |
| 2728 | 2730 | }, |
| 2731 | .node_offset_init_ty => |node_off| { | |
| 2732 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2733 | const node_tags = tree.nodes.items(.tag); | |
| 2734 | const parent_node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2735 | ||
| 2736 | var buf: [2]Ast.Node.Index = undefined; | |
| 2737 | const full: Ast.full.ArrayInit = switch (node_tags[parent_node]) { | |
| 2738 | .array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], parent_node), | |
| 2739 | .array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, parent_node), | |
| 2740 | .array_init_dot, .array_init_dot_comma => tree.arrayInitDot(parent_node), | |
| 2741 | .array_init, .array_init_comma => tree.arrayInit(parent_node), | |
| 2742 | else => unreachable, | |
| 2743 | }; | |
| 2744 | return nodeToSpan(tree, full.ast.type_expr); | |
| 2745 | }, | |
| 2729 | 2746 | } |
| 2730 | 2747 | } |
| 2731 | 2748 | |
| ... | ... | @@ -3046,6 +3063,9 @@ pub const LazySrcLoc = union(enum) { |
| 3046 | 3063 | /// The source location points to the default value of a field. |
| 3047 | 3064 | /// The Decl is determined contextually. |
| 3048 | 3065 | node_offset_field_default: i32, |
| 3066 | /// The source location points to the type of an array or struct initializer. | |
| 3067 | /// The Decl is determined contextually. | |
| 3068 | node_offset_init_ty: i32, | |
| 3049 | 3069 | |
| 3050 | 3070 | pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; |
| 3051 | 3071 | |
| ... | ... | @@ -3124,6 +3144,7 @@ pub const LazySrcLoc = union(enum) { |
| 3124 | 3144 | .node_offset_ptr_hostsize, |
| 3125 | 3145 | .node_offset_container_tag, |
| 3126 | 3146 | .node_offset_field_default, |
| 3147 | .node_offset_init_ty, | |
| 3127 | 3148 | => .{ |
| 3128 | 3149 | .file_scope = decl.getFileScope(), |
| 3129 | 3150 | .parent_decl_node = decl.src_node, |
| ... | ... | @@ -4673,6 +4694,15 @@ pub fn importFile( |
| 4673 | 4694 | cur_file: *File, |
| 4674 | 4695 | import_string: []const u8, |
| 4675 | 4696 | ) !ImportFileResult { |
| 4697 | if (std.mem.eql(u8, import_string, "std")) { | |
| 4698 | return mod.importPkg(mod.main_pkg.table.get("std").?); | |
| 4699 | } | |
| 4700 | if (std.mem.eql(u8, import_string, "builtin")) { | |
| 4701 | return mod.importPkg(mod.main_pkg.table.get("builtin").?); | |
| 4702 | } | |
| 4703 | if (std.mem.eql(u8, import_string, "root")) { | |
| 4704 | return mod.importPkg(mod.root_pkg); | |
| 4705 | } | |
| 4676 | 4706 | if (cur_file.pkg.table.get(import_string)) |pkg| { |
| 4677 | 4707 | return mod.importPkg(pkg); |
| 4678 | 4708 | } |
src/Sema.zig+1328-553| ... | ... | @@ -875,10 +875,6 @@ fn analyzeBodyInner( |
| 875 | 875 | .add => try sema.zirArithmetic(block, inst, .add), |
| 876 | 876 | .addwrap => try sema.zirArithmetic(block, inst, .addwrap), |
| 877 | 877 | .add_sat => try sema.zirArithmetic(block, inst, .add_sat), |
| 878 | .div => try sema.zirArithmetic(block, inst, .div), | |
| 879 | .div_exact => try sema.zirArithmetic(block, inst, .div_exact), | |
| 880 | .div_floor => try sema.zirArithmetic(block, inst, .div_floor), | |
| 881 | .div_trunc => try sema.zirArithmetic(block, inst, .div_trunc), | |
| 882 | 878 | .mod_rem => try sema.zirArithmetic(block, inst, .mod_rem), |
| 883 | 879 | .mod => try sema.zirArithmetic(block, inst, .mod), |
| 884 | 880 | .rem => try sema.zirArithmetic(block, inst, .rem), |
| ... | ... | @@ -889,6 +885,11 @@ fn analyzeBodyInner( |
| 889 | 885 | .subwrap => try sema.zirArithmetic(block, inst, .subwrap), |
| 890 | 886 | .sub_sat => try sema.zirArithmetic(block, inst, .sub_sat), |
| 891 | 887 | |
| 888 | .div => try sema.zirDiv(block, inst), | |
| 889 | .div_exact => try sema.zirDivExact(block, inst), | |
| 890 | .div_floor => try sema.zirDivFloor(block, inst), | |
| 891 | .div_trunc => try sema.zirDivTrunc(block, inst), | |
| 892 | ||
| 892 | 893 | .maximum => try sema.zirMinMax(block, inst, .max), |
| 893 | 894 | .minimum => try sema.zirMinMax(block, inst, .min), |
| 894 | 895 | |
| ... | ... | @@ -1146,6 +1147,24 @@ fn analyzeBodyInner( |
| 1146 | 1147 | i += 1; |
| 1147 | 1148 | continue; |
| 1148 | 1149 | }, |
| 1150 | .check_comptime_control_flow => { | |
| 1151 | if (!block.is_comptime) { | |
| 1152 | if (block.runtime_cond orelse block.runtime_loop) |runtime_src| { | |
| 1153 | const inst_data = sema.code.instructions.items(.data)[inst].node; | |
| 1154 | const src = LazySrcLoc.nodeOffset(inst_data); | |
| 1155 | const msg = msg: { | |
| 1156 | const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{}); | |
| 1157 | errdefer msg.destroy(sema.gpa); | |
| 1158 | ||
| 1159 | try sema.errNote(block, runtime_src, msg, "runtime control flow here", .{}); | |
| 1160 | break :msg msg; | |
| 1161 | }; | |
| 1162 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 1163 | } | |
| 1164 | } | |
| 1165 | i += 1; | |
| 1166 | continue; | |
| 1167 | }, | |
| 1149 | 1168 | |
| 1150 | 1169 | // Special case instructions to handle comptime control flow. |
| 1151 | 1170 | .@"break" => { |
| ... | ... | @@ -3475,19 +3494,43 @@ fn validateArrayInitTy( |
| 3475 | 3494 | block: *Block, |
| 3476 | 3495 | inst: Zir.Inst.Index, |
| 3477 | 3496 | ) CompileError!void { |
| 3478 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 3497 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 3479 | 3498 | const src = inst_data.src(); |
| 3480 | const ty = try sema.resolveType(block, src, inst_data.operand); | |
| 3499 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; | |
| 3500 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; | |
| 3501 | const ty = try sema.resolveType(block, ty_src, extra.ty); | |
| 3481 | 3502 | |
| 3482 | 3503 | switch (ty.zigTypeTag()) { |
| 3483 | .Array, .Vector => return, | |
| 3504 | .Array => { | |
| 3505 | const array_len = ty.arrayLen(); | |
| 3506 | if (extra.init_count != array_len) { | |
| 3507 | return sema.fail(block, src, "expected {d} array elements; found {d}", .{ | |
| 3508 | array_len, extra.init_count, | |
| 3509 | }); | |
| 3510 | } | |
| 3511 | return; | |
| 3512 | }, | |
| 3513 | .Vector => { | |
| 3514 | const array_len = ty.arrayLen(); | |
| 3515 | if (extra.init_count != array_len) { | |
| 3516 | return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ | |
| 3517 | array_len, extra.init_count, | |
| 3518 | }); | |
| 3519 | } | |
| 3520 | return; | |
| 3521 | }, | |
| 3484 | 3522 | .Struct => if (ty.isTuple()) { |
| 3485 | // TODO validate element count | |
| 3523 | const array_len = ty.arrayLen(); | |
| 3524 | if (extra.init_count > array_len) { | |
| 3525 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ | |
| 3526 | array_len, extra.init_count, | |
| 3527 | }); | |
| 3528 | } | |
| 3486 | 3529 | return; |
| 3487 | 3530 | }, |
| 3488 | 3531 | else => {}, |
| 3489 | 3532 | } |
| 3490 | return sema.failWithArrayInitNotSupported(block, src, ty); | |
| 3533 | return sema.failWithArrayInitNotSupported(block, ty_src, ty); | |
| 3491 | 3534 | } |
| 3492 | 3535 | |
| 3493 | 3536 | fn validateStructInitTy( |
| ... | ... | @@ -3723,6 +3766,15 @@ fn validateStructInit( |
| 3723 | 3766 | |
| 3724 | 3767 | const default_val = struct_ty.structFieldDefaultValue(i); |
| 3725 | 3768 | if (default_val.tag() == .unreachable_value) { |
| 3769 | if (struct_ty.isTuple()) { | |
| 3770 | const template = "missing tuple field with index {d}"; | |
| 3771 | if (root_msg) |msg| { | |
| 3772 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 3773 | } else { | |
| 3774 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | |
| 3775 | } | |
| 3776 | continue; | |
| 3777 | } | |
| 3726 | 3778 | const field_name = struct_ty.structFieldName(i); |
| 3727 | 3779 | const template = "missing struct field: {s}"; |
| 3728 | 3780 | const args = .{field_name}; |
| ... | ... | @@ -3735,7 +3787,10 @@ fn validateStructInit( |
| 3735 | 3787 | } |
| 3736 | 3788 | |
| 3737 | 3789 | const field_src = init_src; // TODO better source location |
| 3738 | const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | |
| 3790 | const default_field_ptr = if (struct_ty.isTuple()) | |
| 3791 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) | |
| 3792 | else | |
| 3793 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | |
| 3739 | 3794 | const field_ty = sema.typeOf(default_field_ptr).childType(); |
| 3740 | 3795 | const init = try sema.addConstant(field_ty, default_val); |
| 3741 | 3796 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| ... | ... | @@ -3850,6 +3905,15 @@ fn validateStructInit( |
| 3850 | 3905 | |
| 3851 | 3906 | const default_val = struct_ty.structFieldDefaultValue(i); |
| 3852 | 3907 | if (default_val.tag() == .unreachable_value) { |
| 3908 | if (struct_ty.isTuple()) { | |
| 3909 | const template = "missing tuple field with index {d}"; | |
| 3910 | if (root_msg) |msg| { | |
| 3911 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 3912 | } else { | |
| 3913 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | |
| 3914 | } | |
| 3915 | continue; | |
| 3916 | } | |
| 3853 | 3917 | const field_name = struct_ty.structFieldName(i); |
| 3854 | 3918 | const template = "missing struct field: {s}"; |
| 3855 | 3919 | const args = .{field_name}; |
| ... | ... | @@ -3893,7 +3957,10 @@ fn validateStructInit( |
| 3893 | 3957 | if (field_ptr != 0) continue; |
| 3894 | 3958 | |
| 3895 | 3959 | const field_src = init_src; // TODO better source location |
| 3896 | const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | |
| 3960 | const default_field_ptr = if (struct_ty.isTuple()) | |
| 3961 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) | |
| 3962 | else | |
| 3963 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | |
| 3897 | 3964 | const field_ty = sema.typeOf(default_field_ptr).childType(); |
| 3898 | 3965 | const init = try sema.addConstant(field_ty, field_values[i]); |
| 3899 | 3966 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| ... | ... | @@ -3916,15 +3983,24 @@ fn zirValidateArrayInit( |
| 3916 | 3983 | const array_ty = sema.typeOf(array_ptr).childType(); |
| 3917 | 3984 | const array_len = array_ty.arrayLen(); |
| 3918 | 3985 | |
| 3919 | if (instrs.len != array_len) { | |
| 3920 | if (array_ty.zigTypeTag() == .Array) { | |
| 3921 | return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{ | |
| 3922 | array_len, instrs.len, | |
| 3923 | }); | |
| 3924 | } else { | |
| 3925 | return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{ | |
| 3926 | array_len, instrs.len, | |
| 3927 | }); | |
| 3986 | if (instrs.len != array_len and array_ty.isTuple()) { | |
| 3987 | const struct_obj = array_ty.castTag(.tuple).?.data; | |
| 3988 | var root_msg: ?*Module.ErrorMsg = null; | |
| 3989 | for (struct_obj.values) |default_val, i| { | |
| 3990 | if (i < instrs.len) continue; | |
| 3991 | ||
| 3992 | if (default_val.tag() == .unreachable_value) { | |
| 3993 | const template = "missing tuple field with index {d}"; | |
| 3994 | if (root_msg) |msg| { | |
| 3995 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 3996 | } else { | |
| 3997 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | |
| 3998 | } | |
| 3999 | } | |
| 4000 | } | |
| 4001 | ||
| 4002 | if (root_msg) |msg| { | |
| 4003 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 3928 | 4004 | } |
| 3929 | 4005 | } |
| 3930 | 4006 | |
| ... | ... | @@ -3977,10 +4053,17 @@ fn zirValidateArrayInit( |
| 3977 | 4053 | } |
| 3978 | 4054 | first_block_index = @minimum(first_block_index, block_index); |
| 3979 | 4055 | |
| 3980 | // Array has one possible value, so value is always comptime-known | |
| 3981 | if (opt_opv) |opv| { | |
| 3982 | element_vals[i] = opv; | |
| 3983 | continue; | |
| 4056 | if (array_ty.isTuple()) { | |
| 4057 | if (array_ty.structFieldValueComptime(i)) |opv| { | |
| 4058 | element_vals[i] = opv; | |
| 4059 | continue; | |
| 4060 | } | |
| 4061 | } else { | |
| 4062 | // Array has one possible value, so value is always comptime-known | |
| 4063 | if (opt_opv) |opv| { | |
| 4064 | element_vals[i] = opv; | |
| 4065 | continue; | |
| 4066 | } | |
| 3984 | 4067 | } |
| 3985 | 4068 | |
| 3986 | 4069 | // If the next instructon is a store with a comptime operand, this element |
| ... | ... | @@ -4674,10 +4757,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 4674 | 4757 | error.OutOfMemory => return error.OutOfMemory, |
| 4675 | 4758 | else => unreachable, // we pass null for root_src_dir_path |
| 4676 | 4759 | }; |
| 4677 | const std_pkg = mod.main_pkg.table.get("std").?; | |
| 4678 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; | |
| 4679 | try c_import_pkg.add(sema.gpa, "builtin", builtin_pkg); | |
| 4680 | try c_import_pkg.add(sema.gpa, "std", std_pkg); | |
| 4681 | 4760 | |
| 4682 | 4761 | const result = mod.importPkg(c_import_pkg) catch |err| |
| 4683 | 4762 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| ... | ... | @@ -10842,177 +10921,807 @@ fn zirArithmetic( |
| 10842 | 10921 | return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src); |
| 10843 | 10922 | } |
| 10844 | 10923 | |
| 10845 | fn zirOverflowArithmetic( | |
| 10846 | sema: *Sema, | |
| 10847 | block: *Block, | |
| 10848 | extended: Zir.Inst.Extended.InstData, | |
| 10849 | zir_tag: Zir.Inst.Extended, | |
| 10850 | ) CompileError!Air.Inst.Ref { | |
| 10851 | const tracy = trace(@src()); | |
| 10852 | defer tracy.end(); | |
| 10853 | ||
| 10854 | const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; | |
| 10855 | const src = LazySrcLoc.nodeOffset(extra.node); | |
| 10856 | ||
| 10857 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 10858 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | |
| 10859 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; | |
| 10860 | ||
| 10924 | fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10925 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 10926 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 10927 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 10928 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 10929 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 10861 | 10930 | const lhs = try sema.resolveInst(extra.lhs); |
| 10862 | 10931 | const rhs = try sema.resolveInst(extra.rhs); |
| 10863 | const ptr = try sema.resolveInst(extra.ptr); | |
| 10864 | ||
| 10865 | 10932 | const lhs_ty = sema.typeOf(lhs); |
| 10866 | 10933 | const rhs_ty = sema.typeOf(rhs); |
| 10867 | const mod = sema.mod; | |
| 10868 | const target = mod.getTarget(); | |
| 10869 | ||
| 10870 | // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen. | |
| 10934 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 10935 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 10871 | 10936 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 10872 | const dest_ty = lhs_ty; | |
| 10873 | if (dest_ty.scalarType().zigTypeTag() != .Int) { | |
| 10874 | return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); | |
| 10875 | } | |
| 10937 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div); | |
| 10876 | 10938 | |
| 10877 | const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); | |
| 10878 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); | |
| 10939 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | |
| 10940 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | |
| 10941 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, | |
| 10942 | }); | |
| 10879 | 10943 | |
| 10880 | const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); | |
| 10881 | const ov_ty = tuple_ty.tupleFields().types[1]; | |
| 10882 | // TODO: Remove and use `ov_ty` instead. | |
| 10883 | // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`. | |
| 10884 | const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.@"bool") else Type.@"bool"; | |
| 10944 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | |
| 10945 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | |
| 10885 | 10946 | |
| 10886 | const result: struct { | |
| 10887 | /// TODO: Rename to `overflow_bit` and make of type `u1`. | |
| 10888 | overflowed: Air.Inst.Ref, | |
| 10889 | wrapped: Air.Inst.Ref, | |
| 10890 | } = result: { | |
| 10891 | switch (zir_tag) { | |
| 10892 | .add_with_overflow => { | |
| 10893 | // If either of the arguments is zero, `false` is returned and the other is stored | |
| 10894 | // to the result, even if it is undefined.. | |
| 10895 | // Otherwise, if either of the argument is undefined, undefined is returned. | |
| 10896 | if (maybe_lhs_val) |lhs_val| { | |
| 10897 | if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 10898 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 10899 | } | |
| 10900 | } | |
| 10901 | if (maybe_rhs_val) |rhs_val| { | |
| 10902 | if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 10903 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10904 | } | |
| 10905 | } | |
| 10906 | if (maybe_lhs_val) |lhs_val| { | |
| 10907 | if (maybe_rhs_val) |rhs_val| { | |
| 10908 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 10909 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 10910 | } | |
| 10947 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 10948 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 10949 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 10911 | 10950 | |
| 10912 | const result = try sema.intAddWithOverflow(block, src, lhs_val, rhs_val, dest_ty); | |
| 10913 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 10914 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 10915 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 10916 | } | |
| 10917 | } | |
| 10918 | }, | |
| 10919 | .sub_with_overflow => { | |
| 10920 | // If the rhs is zero, then the result is lhs and no overflow occured. | |
| 10921 | // Otherwise, if either result is undefined, both results are undefined. | |
| 10922 | if (maybe_rhs_val) |rhs_val| { | |
| 10923 | if (rhs_val.isUndef()) { | |
| 10924 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 10925 | } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 10926 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10927 | } else if (maybe_lhs_val) |lhs_val| { | |
| 10928 | if (lhs_val.isUndef()) { | |
| 10929 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 10930 | } | |
| 10951 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | |
| 10931 | 10952 | |
| 10932 | const result = try sema.intSubWithOverflow(block, src, lhs_val, rhs_val, dest_ty); | |
| 10933 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 10934 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 10935 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 10953 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); | |
| 10954 | ||
| 10955 | const mod = sema.mod; | |
| 10956 | const target = mod.getTarget(); | |
| 10957 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | |
| 10958 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | |
| 10959 | ||
| 10960 | // TODO: emit compile error when .div is used on integers and there would be an | |
| 10961 | // ambiguous result between div_floor and div_trunc. | |
| 10962 | ||
| 10963 | // For integers: | |
| 10964 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 10965 | // If the rhs is zero, compile error for division by zero. | |
| 10966 | // If the rhs is undefined, compile error because there is a possible | |
| 10967 | // value (zero) for which the division would be illegal behavior. | |
| 10968 | // If the lhs is undefined: | |
| 10969 | // * if lhs type is signed: | |
| 10970 | // * if rhs is comptime-known and not -1, result is undefined | |
| 10971 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 10972 | // possible value (-min_int / -1) for which division would be | |
| 10973 | // illegal behavior. | |
| 10974 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 10975 | // | |
| 10976 | // For floats: | |
| 10977 | // If the rhs is zero: | |
| 10978 | // * comptime_float: compile error for division by zero. | |
| 10979 | // * other float type: | |
| 10980 | // * if the lhs is zero: QNaN | |
| 10981 | // * otherwise: +Inf or -Inf depending on lhs sign | |
| 10982 | // If the rhs is undefined: | |
| 10983 | // * comptime_float: compile error because there is a possible | |
| 10984 | // value (zero) for which the division would be illegal behavior. | |
| 10985 | // * other float type: result is undefined | |
| 10986 | // If the lhs is undefined, result is undefined. | |
| 10987 | switch (scalar_tag) { | |
| 10988 | .Int, .ComptimeInt, .ComptimeFloat => { | |
| 10989 | if (maybe_lhs_val) |lhs_val| { | |
| 10990 | if (!lhs_val.isUndef()) { | |
| 10991 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 10992 | return sema.addConstant(resolved_type, Value.zero); | |
| 10936 | 10993 | } |
| 10937 | 10994 | } |
| 10938 | }, | |
| 10939 | .mul_with_overflow => { | |
| 10940 | // If either of the arguments is zero, the result is zero and no overflow occured. | |
| 10941 | // If either of the arguments is one, the result is the other and no overflow occured. | |
| 10942 | // Otherwise, if either of the arguments is undefined, both results are undefined. | |
| 10943 | if (maybe_lhs_val) |lhs_val| { | |
| 10944 | if (!lhs_val.isUndef()) { | |
| 10945 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 10946 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10947 | } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) { | |
| 10948 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 10949 | } | |
| 10950 | } | |
| 10995 | } | |
| 10996 | if (maybe_rhs_val) |rhs_val| { | |
| 10997 | if (rhs_val.isUndef()) { | |
| 10998 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 10951 | 10999 | } |
| 10952 | ||
| 10953 | if (maybe_rhs_val) |rhs_val| { | |
| 10954 | if (!rhs_val.isUndef()) { | |
| 10955 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 10956 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 10957 | } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) { | |
| 10958 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10959 | } | |
| 10960 | } | |
| 11000 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11001 | return sema.failWithDivideByZero(block, rhs_src); | |
| 10961 | 11002 | } |
| 11003 | // TODO: if the RHS is one, return the LHS directly | |
| 11004 | } | |
| 11005 | }, | |
| 11006 | else => {}, | |
| 11007 | } | |
| 10962 | 11008 | |
| 10963 | if (maybe_lhs_val) |lhs_val| { | |
| 11009 | const runtime_src = rs: { | |
| 11010 | if (maybe_lhs_val) |lhs_val| { | |
| 11011 | if (lhs_val.isUndef()) { | |
| 11012 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 10964 | 11013 | if (maybe_rhs_val) |rhs_val| { |
| 10965 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 10966 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11014 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11015 | return sema.addConstUndef(resolved_type); | |
| 10967 | 11016 | } |
| 10968 | ||
| 10969 | const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 10970 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 10971 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 10972 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 10973 | } | |
| 10974 | } | |
| 10975 | }, | |
| 10976 | .shl_with_overflow => { | |
| 10977 | // If lhs is zero, the result is zero and no overflow occurred. | |
| 10978 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. | |
| 10979 | // Oterhwise if either of the arguments is undefined, both results are undefined. | |
| 10980 | if (maybe_lhs_val) |lhs_val| { | |
| 10981 | if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 10982 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10983 | 11017 | } |
| 11018 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 10984 | 11019 | } |
| 10985 | if (maybe_rhs_val) |rhs_val| { | |
| 10986 | if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 10987 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 10988 | } | |
| 10989 | } | |
| 10990 | if (maybe_lhs_val) |lhs_val| { | |
| 10991 | if (maybe_rhs_val) |rhs_val| { | |
| 10992 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 10993 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 10994 | } | |
| 11020 | return sema.addConstUndef(resolved_type); | |
| 11021 | } | |
| 10995 | 11022 | |
| 10996 | const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 10997 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 10998 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 10999 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 11000 | } | |
| 11023 | if (maybe_rhs_val) |rhs_val| { | |
| 11024 | if (is_int) { | |
| 11025 | return sema.addConstant( | |
| 11026 | resolved_type, | |
| 11027 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11028 | ); | |
| 11029 | } else { | |
| 11030 | return sema.addConstant( | |
| 11031 | resolved_type, | |
| 11032 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11033 | ); | |
| 11001 | 11034 | } |
| 11002 | }, | |
| 11003 | else => unreachable, | |
| 11035 | } else { | |
| 11036 | break :rs rhs_src; | |
| 11037 | } | |
| 11038 | } else { | |
| 11039 | break :rs lhs_src; | |
| 11004 | 11040 | } |
| 11041 | }; | |
| 11005 | 11042 | |
| 11006 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | |
| 11007 | .add_with_overflow => .add_with_overflow, | |
| 11008 | .mul_with_overflow => .mul_with_overflow, | |
| 11009 | .sub_with_overflow => .sub_with_overflow, | |
| 11010 | .shl_with_overflow => .shl_with_overflow, | |
| 11011 | else => unreachable, | |
| 11012 | }; | |
| 11013 | ||
| 11014 | const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src; | |
| 11015 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11043 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11044 | ||
| 11045 | if (block.wantSafety()) { | |
| 11046 | try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); | |
| 11047 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); | |
| 11048 | } | |
| 11049 | ||
| 11050 | const air_tag = if (is_int) Air.Inst.Tag.div_trunc else switch (block.float_mode) { | |
| 11051 | .Optimized => Air.Inst.Tag.div_float_optimized, | |
| 11052 | .Strict => Air.Inst.Tag.div_float, | |
| 11053 | }; | |
| 11054 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); | |
| 11055 | } | |
| 11056 | ||
| 11057 | fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 11058 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 11059 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 11060 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 11061 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 11062 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 11063 | const lhs = try sema.resolveInst(extra.lhs); | |
| 11064 | const rhs = try sema.resolveInst(extra.rhs); | |
| 11065 | const lhs_ty = sema.typeOf(lhs); | |
| 11066 | const rhs_ty = sema.typeOf(rhs); | |
| 11067 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 11068 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 11069 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | |
| 11070 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_exact); | |
| 11071 | ||
| 11072 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | |
| 11073 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | |
| 11074 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, | |
| 11075 | }); | |
| 11076 | ||
| 11077 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | |
| 11078 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | |
| 11079 | ||
| 11080 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 11081 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 11082 | ||
| 11083 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | |
| 11084 | ||
| 11085 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); | |
| 11086 | ||
| 11087 | const mod = sema.mod; | |
| 11088 | const target = mod.getTarget(); | |
| 11089 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | |
| 11090 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | |
| 11091 | ||
| 11092 | const runtime_src = rs: { | |
| 11093 | // For integers: | |
| 11094 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11095 | // If the rhs is zero, compile error for division by zero. | |
| 11096 | // If the rhs is undefined, compile error because there is a possible | |
| 11097 | // value (zero) for which the division would be illegal behavior. | |
| 11098 | // If the lhs is undefined, compile error because there is a possible | |
| 11099 | // value for which the division would result in a remainder. | |
| 11100 | // TODO: emit runtime safety for if there is a remainder | |
| 11101 | // TODO: emit runtime safety for division by zero | |
| 11102 | // | |
| 11103 | // For floats: | |
| 11104 | // If the rhs is zero, compile error for division by zero. | |
| 11105 | // If the rhs is undefined, compile error because there is a possible | |
| 11106 | // value (zero) for which the division would be illegal behavior. | |
| 11107 | // If the lhs is undefined, compile error because there is a possible | |
| 11108 | // value for which the division would result in a remainder. | |
| 11109 | if (maybe_lhs_val) |lhs_val| { | |
| 11110 | if (lhs_val.isUndef()) { | |
| 11111 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11112 | } else { | |
| 11113 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11114 | return sema.addConstant(resolved_type, Value.zero); | |
| 11115 | } | |
| 11116 | } | |
| 11117 | } | |
| 11118 | if (maybe_rhs_val) |rhs_val| { | |
| 11119 | if (rhs_val.isUndef()) { | |
| 11120 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11121 | } | |
| 11122 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11123 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11124 | } | |
| 11125 | // TODO: if the RHS is one, return the LHS directly | |
| 11126 | } | |
| 11127 | if (maybe_lhs_val) |lhs_val| { | |
| 11128 | if (maybe_rhs_val) |rhs_val| { | |
| 11129 | if (is_int) { | |
| 11130 | // TODO: emit compile error if there is a remainder | |
| 11131 | return sema.addConstant( | |
| 11132 | resolved_type, | |
| 11133 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11134 | ); | |
| 11135 | } else { | |
| 11136 | // TODO: emit compile error if there is a remainder | |
| 11137 | return sema.addConstant( | |
| 11138 | resolved_type, | |
| 11139 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11140 | ); | |
| 11141 | } | |
| 11142 | } else break :rs rhs_src; | |
| 11143 | } else break :rs lhs_src; | |
| 11144 | }; | |
| 11145 | ||
| 11146 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11147 | ||
| 11148 | // Depending on whether safety is enabled, we will have a slightly different strategy | |
| 11149 | // here. The `div_exact` AIR instruction causes undefined behavior if a remainder | |
| 11150 | // is produced, so in the safety check case, it cannot be used. Instead we do a | |
| 11151 | // div_trunc and check for remainder. | |
| 11152 | ||
| 11153 | if (block.wantSafety()) { | |
| 11154 | try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); | |
| 11155 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); | |
| 11156 | ||
| 11157 | const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs); | |
| 11158 | const ok = if (!is_int) ok: { | |
| 11159 | const floored = try block.addUnOp(.floor, result); | |
| 11160 | ||
| 11161 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 11162 | const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type)); | |
| 11163 | break :ok try block.addInst(.{ | |
| 11164 | .tag = switch (block.float_mode) { | |
| 11165 | .Strict => .reduce, | |
| 11166 | .Optimized => .reduce_optimized, | |
| 11167 | }, | |
| 11168 | .data = .{ .reduce = .{ | |
| 11169 | .operand = eql, | |
| 11170 | .operation = .And, | |
| 11171 | } }, | |
| 11172 | }); | |
| 11173 | } else { | |
| 11174 | const is_in_range = try block.addBinOp(switch (block.float_mode) { | |
| 11175 | .Strict => .cmp_eq, | |
| 11176 | .Optimized => .cmp_eq_optimized, | |
| 11177 | }, result, floored); | |
| 11178 | break :ok is_in_range; | |
| 11179 | } | |
| 11180 | } else ok: { | |
| 11181 | const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); | |
| 11182 | ||
| 11183 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 11184 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 11185 | const zero = try sema.addConstant(resolved_type, zero_val); | |
| 11186 | const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type)); | |
| 11187 | break :ok try block.addInst(.{ | |
| 11188 | .tag = .reduce, | |
| 11189 | .data = .{ .reduce = .{ | |
| 11190 | .operand = eql, | |
| 11191 | .operation = .And, | |
| 11192 | } }, | |
| 11193 | }); | |
| 11194 | } else { | |
| 11195 | const zero = try sema.addConstant(resolved_type, Value.zero); | |
| 11196 | const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); | |
| 11197 | break :ok is_in_range; | |
| 11198 | } | |
| 11199 | }; | |
| 11200 | try sema.addSafetyCheck(block, ok, .exact_division_remainder); | |
| 11201 | return result; | |
| 11202 | } | |
| 11203 | ||
| 11204 | return block.addBinOp(airTag(block, is_int, .div_exact, .div_exact_optimized), casted_lhs, casted_rhs); | |
| 11205 | } | |
| 11206 | ||
| 11207 | fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 11208 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 11209 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 11210 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 11211 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 11212 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 11213 | const lhs = try sema.resolveInst(extra.lhs); | |
| 11214 | const rhs = try sema.resolveInst(extra.rhs); | |
| 11215 | const lhs_ty = sema.typeOf(lhs); | |
| 11216 | const rhs_ty = sema.typeOf(rhs); | |
| 11217 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 11218 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 11219 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | |
| 11220 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_floor); | |
| 11221 | ||
| 11222 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | |
| 11223 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | |
| 11224 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, | |
| 11225 | }); | |
| 11226 | ||
| 11227 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | |
| 11228 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | |
| 11229 | ||
| 11230 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 11231 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 11232 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 11233 | ||
| 11234 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | |
| 11235 | ||
| 11236 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); | |
| 11237 | ||
| 11238 | const mod = sema.mod; | |
| 11239 | const target = mod.getTarget(); | |
| 11240 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | |
| 11241 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | |
| 11242 | ||
| 11243 | const runtime_src = rs: { | |
| 11244 | // For integers: | |
| 11245 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11246 | // If the rhs is zero, compile error for division by zero. | |
| 11247 | // If the rhs is undefined, compile error because there is a possible | |
| 11248 | // value (zero) for which the division would be illegal behavior. | |
| 11249 | // If the lhs is undefined: | |
| 11250 | // * if lhs type is signed: | |
| 11251 | // * if rhs is comptime-known and not -1, result is undefined | |
| 11252 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 11253 | // possible value (-min_int / -1) for which division would be | |
| 11254 | // illegal behavior. | |
| 11255 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 11256 | // TODO: emit runtime safety for division by zero | |
| 11257 | // | |
| 11258 | // For floats: | |
| 11259 | // If the rhs is zero, compile error for division by zero. | |
| 11260 | // If the rhs is undefined, compile error because there is a possible | |
| 11261 | // value (zero) for which the division would be illegal behavior. | |
| 11262 | // If the lhs is undefined, result is undefined. | |
| 11263 | if (maybe_lhs_val) |lhs_val| { | |
| 11264 | if (!lhs_val.isUndef()) { | |
| 11265 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11266 | return sema.addConstant(resolved_type, Value.zero); | |
| 11267 | } | |
| 11268 | } | |
| 11269 | } | |
| 11270 | if (maybe_rhs_val) |rhs_val| { | |
| 11271 | if (rhs_val.isUndef()) { | |
| 11272 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11273 | } | |
| 11274 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11275 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11276 | } | |
| 11277 | // TODO: if the RHS is one, return the LHS directly | |
| 11278 | } | |
| 11279 | if (maybe_lhs_val) |lhs_val| { | |
| 11280 | if (lhs_val.isUndef()) { | |
| 11281 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 11282 | if (maybe_rhs_val) |rhs_val| { | |
| 11283 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11284 | return sema.addConstUndef(resolved_type); | |
| 11285 | } | |
| 11286 | } | |
| 11287 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11288 | } | |
| 11289 | return sema.addConstUndef(resolved_type); | |
| 11290 | } | |
| 11291 | ||
| 11292 | if (maybe_rhs_val) |rhs_val| { | |
| 11293 | if (is_int) { | |
| 11294 | return sema.addConstant( | |
| 11295 | resolved_type, | |
| 11296 | try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, target), | |
| 11297 | ); | |
| 11298 | } else { | |
| 11299 | return sema.addConstant( | |
| 11300 | resolved_type, | |
| 11301 | try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target), | |
| 11302 | ); | |
| 11303 | } | |
| 11304 | } else break :rs rhs_src; | |
| 11305 | } else break :rs lhs_src; | |
| 11306 | }; | |
| 11307 | ||
| 11308 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11309 | ||
| 11310 | if (block.wantSafety()) { | |
| 11311 | try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); | |
| 11312 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); | |
| 11313 | } | |
| 11314 | ||
| 11315 | return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs); | |
| 11316 | } | |
| 11317 | ||
| 11318 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 11319 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 11320 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | |
| 11321 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | |
| 11322 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | |
| 11323 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | |
| 11324 | const lhs = try sema.resolveInst(extra.lhs); | |
| 11325 | const rhs = try sema.resolveInst(extra.rhs); | |
| 11326 | const lhs_ty = sema.typeOf(lhs); | |
| 11327 | const rhs_ty = sema.typeOf(rhs); | |
| 11328 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | |
| 11329 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | |
| 11330 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | |
| 11331 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .div_trunc); | |
| 11332 | ||
| 11333 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | |
| 11334 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | |
| 11335 | .override = &[_]LazySrcLoc{ lhs_src, rhs_src }, | |
| 11336 | }); | |
| 11337 | ||
| 11338 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | |
| 11339 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | |
| 11340 | ||
| 11341 | const lhs_scalar_ty = lhs_ty.scalarType(); | |
| 11342 | const rhs_scalar_ty = rhs_ty.scalarType(); | |
| 11343 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | |
| 11344 | ||
| 11345 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | |
| 11346 | ||
| 11347 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); | |
| 11348 | ||
| 11349 | const mod = sema.mod; | |
| 11350 | const target = mod.getTarget(); | |
| 11351 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | |
| 11352 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | |
| 11353 | ||
| 11354 | const runtime_src = rs: { | |
| 11355 | // For integers: | |
| 11356 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11357 | // If the rhs is zero, compile error for division by zero. | |
| 11358 | // If the rhs is undefined, compile error because there is a possible | |
| 11359 | // value (zero) for which the division would be illegal behavior. | |
| 11360 | // If the lhs is undefined: | |
| 11361 | // * if lhs type is signed: | |
| 11362 | // * if rhs is comptime-known and not -1, result is undefined | |
| 11363 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 11364 | // possible value (-min_int / -1) for which division would be | |
| 11365 | // illegal behavior. | |
| 11366 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 11367 | // TODO: emit runtime safety for division by zero | |
| 11368 | // | |
| 11369 | // For floats: | |
| 11370 | // If the rhs is zero, compile error for division by zero. | |
| 11371 | // If the rhs is undefined, compile error because there is a possible | |
| 11372 | // value (zero) for which the division would be illegal behavior. | |
| 11373 | // If the lhs is undefined, result is undefined. | |
| 11374 | if (maybe_lhs_val) |lhs_val| { | |
| 11375 | if (!lhs_val.isUndef()) { | |
| 11376 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11377 | return sema.addConstant(resolved_type, Value.zero); | |
| 11378 | } | |
| 11379 | } | |
| 11380 | } | |
| 11381 | if (maybe_rhs_val) |rhs_val| { | |
| 11382 | if (rhs_val.isUndef()) { | |
| 11383 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11384 | } | |
| 11385 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11386 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11387 | } | |
| 11388 | } | |
| 11389 | if (maybe_lhs_val) |lhs_val| { | |
| 11390 | if (lhs_val.isUndef()) { | |
| 11391 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 11392 | if (maybe_rhs_val) |rhs_val| { | |
| 11393 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11394 | return sema.addConstUndef(resolved_type); | |
| 11395 | } | |
| 11396 | } | |
| 11397 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11398 | } | |
| 11399 | return sema.addConstUndef(resolved_type); | |
| 11400 | } | |
| 11401 | ||
| 11402 | if (maybe_rhs_val) |rhs_val| { | |
| 11403 | if (is_int) { | |
| 11404 | return sema.addConstant( | |
| 11405 | resolved_type, | |
| 11406 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11407 | ); | |
| 11408 | } else { | |
| 11409 | return sema.addConstant( | |
| 11410 | resolved_type, | |
| 11411 | try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target), | |
| 11412 | ); | |
| 11413 | } | |
| 11414 | } else break :rs rhs_src; | |
| 11415 | } else break :rs lhs_src; | |
| 11416 | }; | |
| 11417 | ||
| 11418 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11419 | ||
| 11420 | if (block.wantSafety()) { | |
| 11421 | try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); | |
| 11422 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); | |
| 11423 | } | |
| 11424 | ||
| 11425 | return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs); | |
| 11426 | } | |
| 11427 | ||
| 11428 | fn addDivIntOverflowSafety( | |
| 11429 | sema: *Sema, | |
| 11430 | block: *Block, | |
| 11431 | resolved_type: Type, | |
| 11432 | lhs_scalar_ty: Type, | |
| 11433 | maybe_lhs_val: ?Value, | |
| 11434 | maybe_rhs_val: ?Value, | |
| 11435 | casted_lhs: Air.Inst.Ref, | |
| 11436 | casted_rhs: Air.Inst.Ref, | |
| 11437 | is_int: bool, | |
| 11438 | ) CompileError!void { | |
| 11439 | if (!is_int) return; | |
| 11440 | ||
| 11441 | // If the LHS is unsigned, it cannot cause overflow. | |
| 11442 | if (!lhs_scalar_ty.isSignedInt()) return; | |
| 11443 | ||
| 11444 | const mod = sema.mod; | |
| 11445 | const target = mod.getTarget(); | |
| 11446 | ||
| 11447 | // If the LHS is widened to a larger integer type, no overflow is possible. | |
| 11448 | if (lhs_scalar_ty.intInfo(target).bits < resolved_type.intInfo(target).bits) { | |
| 11449 | return; | |
| 11450 | } | |
| 11451 | ||
| 11452 | const min_int = try resolved_type.minInt(sema.arena, target); | |
| 11453 | const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1); | |
| 11454 | const neg_one = if (resolved_type.zigTypeTag() == .Vector) | |
| 11455 | try Value.Tag.repeated.create(sema.arena, neg_one_scalar) | |
| 11456 | else | |
| 11457 | neg_one_scalar; | |
| 11458 | ||
| 11459 | // If the LHS is comptime-known to be not equal to the min int, | |
| 11460 | // no overflow is possible. | |
| 11461 | if (maybe_lhs_val) |lhs_val| { | |
| 11462 | if (!lhs_val.compare(.eq, min_int, resolved_type, mod)) return; | |
| 11463 | } | |
| 11464 | ||
| 11465 | // If the RHS is comptime-known to not be equal to -1, no overflow is possible. | |
| 11466 | if (maybe_rhs_val) |rhs_val| { | |
| 11467 | if (!rhs_val.compare(.eq, neg_one, resolved_type, mod)) return; | |
| 11468 | } | |
| 11469 | ||
| 11470 | var ok: Air.Inst.Ref = .none; | |
| 11471 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 11472 | const vector_ty_ref = try sema.addType(resolved_type); | |
| 11473 | if (maybe_lhs_val == null) { | |
| 11474 | const min_int_ref = try sema.addConstant(resolved_type, min_int); | |
| 11475 | ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq, vector_ty_ref); | |
| 11476 | } | |
| 11477 | if (maybe_rhs_val == null) { | |
| 11478 | const neg_one_ref = try sema.addConstant(resolved_type, neg_one); | |
| 11479 | const rhs_ok = try block.addCmpVector(casted_rhs, neg_one_ref, .neq, vector_ty_ref); | |
| 11480 | if (ok == .none) { | |
| 11481 | ok = rhs_ok; | |
| 11482 | } else { | |
| 11483 | ok = try block.addBinOp(.bool_or, ok, rhs_ok); | |
| 11484 | } | |
| 11485 | } | |
| 11486 | assert(ok != .none); | |
| 11487 | ok = try block.addInst(.{ | |
| 11488 | .tag = .reduce, | |
| 11489 | .data = .{ .reduce = .{ | |
| 11490 | .operand = ok, | |
| 11491 | .operation = .And, | |
| 11492 | } }, | |
| 11493 | }); | |
| 11494 | } else { | |
| 11495 | if (maybe_lhs_val == null) { | |
| 11496 | const min_int_ref = try sema.addConstant(resolved_type, min_int); | |
| 11497 | ok = try block.addBinOp(.cmp_neq, casted_lhs, min_int_ref); | |
| 11498 | } | |
| 11499 | if (maybe_rhs_val == null) { | |
| 11500 | const neg_one_ref = try sema.addConstant(resolved_type, neg_one); | |
| 11501 | const rhs_ok = try block.addBinOp(.cmp_neq, casted_rhs, neg_one_ref); | |
| 11502 | if (ok == .none) { | |
| 11503 | ok = rhs_ok; | |
| 11504 | } else { | |
| 11505 | ok = try block.addBinOp(.bool_or, ok, rhs_ok); | |
| 11506 | } | |
| 11507 | } | |
| 11508 | assert(ok != .none); | |
| 11509 | } | |
| 11510 | try sema.addSafetyCheck(block, ok, .integer_overflow); | |
| 11511 | } | |
| 11512 | ||
| 11513 | fn addDivByZeroSafety( | |
| 11514 | sema: *Sema, | |
| 11515 | block: *Block, | |
| 11516 | resolved_type: Type, | |
| 11517 | maybe_rhs_val: ?Value, | |
| 11518 | casted_rhs: Air.Inst.Ref, | |
| 11519 | is_int: bool, | |
| 11520 | ) CompileError!void { | |
| 11521 | // Strict IEEE floats have well-defined division by zero. | |
| 11522 | if (!is_int and block.float_mode == .Strict) return; | |
| 11523 | ||
| 11524 | // If rhs was comptime-known to be zero a compile error would have been | |
| 11525 | // emitted above. | |
| 11526 | if (maybe_rhs_val != null) return; | |
| 11527 | ||
| 11528 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { | |
| 11529 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 11530 | const zero = try sema.addConstant(resolved_type, zero_val); | |
| 11531 | const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type)); | |
| 11532 | break :ok try block.addInst(.{ | |
| 11533 | .tag = if (is_int) .reduce else .reduce_optimized, | |
| 11534 | .data = .{ .reduce = .{ | |
| 11535 | .operand = ok, | |
| 11536 | .operation = .And, | |
| 11537 | } }, | |
| 11538 | }); | |
| 11539 | } else ok: { | |
| 11540 | const zero = try sema.addConstant(resolved_type, Value.zero); | |
| 11541 | break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); | |
| 11542 | }; | |
| 11543 | try sema.addSafetyCheck(block, ok, .divide_by_zero); | |
| 11544 | } | |
| 11545 | ||
| 11546 | fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag { | |
| 11547 | if (is_int) return normal; | |
| 11548 | return switch (block.float_mode) { | |
| 11549 | .Strict => normal, | |
| 11550 | .Optimized => optimized, | |
| 11551 | }; | |
| 11552 | } | |
| 11553 | ||
| 11554 | fn zirOverflowArithmetic( | |
| 11555 | sema: *Sema, | |
| 11556 | block: *Block, | |
| 11557 | extended: Zir.Inst.Extended.InstData, | |
| 11558 | zir_tag: Zir.Inst.Extended, | |
| 11559 | ) CompileError!Air.Inst.Ref { | |
| 11560 | const tracy = trace(@src()); | |
| 11561 | defer tracy.end(); | |
| 11562 | ||
| 11563 | const extra = sema.code.extraData(Zir.Inst.OverflowArithmetic, extended.operand).data; | |
| 11564 | const src = LazySrcLoc.nodeOffset(extra.node); | |
| 11565 | ||
| 11566 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 11567 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | |
| 11568 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node }; | |
| 11569 | ||
| 11570 | const lhs = try sema.resolveInst(extra.lhs); | |
| 11571 | const rhs = try sema.resolveInst(extra.rhs); | |
| 11572 | const ptr = try sema.resolveInst(extra.ptr); | |
| 11573 | ||
| 11574 | const lhs_ty = sema.typeOf(lhs); | |
| 11575 | const rhs_ty = sema.typeOf(rhs); | |
| 11576 | const mod = sema.mod; | |
| 11577 | const target = mod.getTarget(); | |
| 11578 | ||
| 11579 | // Note, the types of lhs/rhs (also for shifting)/ptr are already correct as ensured by astgen. | |
| 11580 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | |
| 11581 | const dest_ty = lhs_ty; | |
| 11582 | if (dest_ty.scalarType().zigTypeTag() != .Int) { | |
| 11583 | return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); | |
| 11584 | } | |
| 11585 | ||
| 11586 | const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); | |
| 11587 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); | |
| 11588 | ||
| 11589 | const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); | |
| 11590 | const ov_ty = tuple_ty.tupleFields().types[1]; | |
| 11591 | // TODO: Remove and use `ov_ty` instead. | |
| 11592 | // This is a temporary type used until overflow arithmetic properly returns `u1` instead of `bool`. | |
| 11593 | const overflowed_ty = if (dest_ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, dest_ty.vectorLen(), Type.@"bool") else Type.@"bool"; | |
| 11594 | ||
| 11595 | const result: struct { | |
| 11596 | /// TODO: Rename to `overflow_bit` and make of type `u1`. | |
| 11597 | overflowed: Air.Inst.Ref, | |
| 11598 | wrapped: Air.Inst.Ref, | |
| 11599 | } = result: { | |
| 11600 | switch (zir_tag) { | |
| 11601 | .add_with_overflow => { | |
| 11602 | // If either of the arguments is zero, `false` is returned and the other is stored | |
| 11603 | // to the result, even if it is undefined.. | |
| 11604 | // Otherwise, if either of the argument is undefined, undefined is returned. | |
| 11605 | if (maybe_lhs_val) |lhs_val| { | |
| 11606 | if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 11607 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 11608 | } | |
| 11609 | } | |
| 11610 | if (maybe_rhs_val) |rhs_val| { | |
| 11611 | if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 11612 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11613 | } | |
| 11614 | } | |
| 11615 | if (maybe_lhs_val) |lhs_val| { | |
| 11616 | if (maybe_rhs_val) |rhs_val| { | |
| 11617 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 11618 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11619 | } | |
| 11620 | ||
| 11621 | const result = try sema.intAddWithOverflow(block, src, lhs_val, rhs_val, dest_ty); | |
| 11622 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 11623 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 11624 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 11625 | } | |
| 11626 | } | |
| 11627 | }, | |
| 11628 | .sub_with_overflow => { | |
| 11629 | // If the rhs is zero, then the result is lhs and no overflow occured. | |
| 11630 | // Otherwise, if either result is undefined, both results are undefined. | |
| 11631 | if (maybe_rhs_val) |rhs_val| { | |
| 11632 | if (rhs_val.isUndef()) { | |
| 11633 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11634 | } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11635 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11636 | } else if (maybe_lhs_val) |lhs_val| { | |
| 11637 | if (lhs_val.isUndef()) { | |
| 11638 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11639 | } | |
| 11640 | ||
| 11641 | const result = try sema.intSubWithOverflow(block, src, lhs_val, rhs_val, dest_ty); | |
| 11642 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 11643 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 11644 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 11645 | } | |
| 11646 | } | |
| 11647 | }, | |
| 11648 | .mul_with_overflow => { | |
| 11649 | // If either of the arguments is zero, the result is zero and no overflow occured. | |
| 11650 | // If either of the arguments is one, the result is the other and no overflow occured. | |
| 11651 | // Otherwise, if either of the arguments is undefined, both results are undefined. | |
| 11652 | if (maybe_lhs_val) |lhs_val| { | |
| 11653 | if (!lhs_val.isUndef()) { | |
| 11654 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11655 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11656 | } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) { | |
| 11657 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 11658 | } | |
| 11659 | } | |
| 11660 | } | |
| 11661 | ||
| 11662 | if (maybe_rhs_val) |rhs_val| { | |
| 11663 | if (!rhs_val.isUndef()) { | |
| 11664 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11665 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs }; | |
| 11666 | } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) { | |
| 11667 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11668 | } | |
| 11669 | } | |
| 11670 | } | |
| 11671 | ||
| 11672 | if (maybe_lhs_val) |lhs_val| { | |
| 11673 | if (maybe_rhs_val) |rhs_val| { | |
| 11674 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 11675 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11676 | } | |
| 11677 | ||
| 11678 | const result = try lhs_val.intMulWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 11679 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 11680 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 11681 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 11682 | } | |
| 11683 | } | |
| 11684 | }, | |
| 11685 | .shl_with_overflow => { | |
| 11686 | // If lhs is zero, the result is zero and no overflow occurred. | |
| 11687 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. | |
| 11688 | // Oterhwise if either of the arguments is undefined, both results are undefined. | |
| 11689 | if (maybe_lhs_val) |lhs_val| { | |
| 11690 | if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 11691 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11692 | } | |
| 11693 | } | |
| 11694 | if (maybe_rhs_val) |rhs_val| { | |
| 11695 | if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | |
| 11696 | break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs }; | |
| 11697 | } | |
| 11698 | } | |
| 11699 | if (maybe_lhs_val) |lhs_val| { | |
| 11700 | if (maybe_rhs_val) |rhs_val| { | |
| 11701 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | |
| 11702 | break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) }; | |
| 11703 | } | |
| 11704 | ||
| 11705 | const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, target); | |
| 11706 | const overflowed = try sema.addConstant(overflowed_ty, result.overflowed); | |
| 11707 | const wrapped = try sema.addConstant(dest_ty, result.wrapped_result); | |
| 11708 | break :result .{ .overflowed = overflowed, .wrapped = wrapped }; | |
| 11709 | } | |
| 11710 | } | |
| 11711 | }, | |
| 11712 | else => unreachable, | |
| 11713 | } | |
| 11714 | ||
| 11715 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | |
| 11716 | .add_with_overflow => .add_with_overflow, | |
| 11717 | .mul_with_overflow => .mul_with_overflow, | |
| 11718 | .sub_with_overflow => .sub_with_overflow, | |
| 11719 | .shl_with_overflow => .shl_with_overflow, | |
| 11720 | else => unreachable, | |
| 11721 | }; | |
| 11722 | ||
| 11723 | const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src; | |
| 11724 | try sema.requireRuntimeBlock(block, src, runtime_src); | |
| 11016 | 11725 | |
| 11017 | 11726 | const tuple = try block.addInst(.{ |
| 11018 | 11727 | .tag = air_tag, |
| ... | ... | @@ -11108,13 +11817,8 @@ fn analyzeArithmetic( |
| 11108 | 11817 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); |
| 11109 | 11818 | |
| 11110 | 11819 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 11111 | const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; | |
| 11112 | 11820 | |
| 11113 | if (!is_int and !(is_float and floatOpAllowed(zir_tag))) { | |
| 11114 | return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ | |
| 11115 | @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag), | |
| 11116 | }); | |
| 11117 | } | |
| 11821 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag); | |
| 11118 | 11822 | |
| 11119 | 11823 | const mod = sema.mod; |
| 11120 | 11824 | const target = mod.getTarget(); |
| ... | ... | @@ -11321,277 +12025,6 @@ fn analyzeArithmetic( |
| 11321 | 12025 | } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat }; |
| 11322 | 12026 | } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat }; |
| 11323 | 12027 | }, |
| 11324 | .div => { | |
| 11325 | // TODO: emit compile error when .div is used on integers and there would be an | |
| 11326 | // ambiguous result between div_floor and div_trunc. | |
| 11327 | ||
| 11328 | // For integers: | |
| 11329 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11330 | // If the rhs is zero, compile error for division by zero. | |
| 11331 | // If the rhs is undefined, compile error because there is a possible | |
| 11332 | // value (zero) for which the division would be illegal behavior. | |
| 11333 | // If the lhs is undefined: | |
| 11334 | // * if lhs type is signed: | |
| 11335 | // * if rhs is comptime-known and not -1, result is undefined | |
| 11336 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 11337 | // possible value (-min_int / -1) for which division would be | |
| 11338 | // illegal behavior. | |
| 11339 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 11340 | // TODO: emit runtime safety for division by zero | |
| 11341 | // | |
| 11342 | // For floats: | |
| 11343 | // If the rhs is zero: | |
| 11344 | // * comptime_float: compile error for division by zero. | |
| 11345 | // * other float type: | |
| 11346 | // * if the lhs is zero: QNaN | |
| 11347 | // * otherwise: +Inf or -Inf depending on lhs sign | |
| 11348 | // If the rhs is undefined: | |
| 11349 | // * comptime_float: compile error because there is a possible | |
| 11350 | // value (zero) for which the division would be illegal behavior. | |
| 11351 | // * other float type: result is undefined | |
| 11352 | // If the lhs is undefined, result is undefined. | |
| 11353 | switch (scalar_tag) { | |
| 11354 | .Int, .ComptimeInt, .ComptimeFloat => { | |
| 11355 | if (maybe_lhs_val) |lhs_val| { | |
| 11356 | if (!lhs_val.isUndef()) { | |
| 11357 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11358 | return sema.addConstant(resolved_type, Value.zero); | |
| 11359 | } | |
| 11360 | } | |
| 11361 | } | |
| 11362 | if (maybe_rhs_val) |rhs_val| { | |
| 11363 | if (rhs_val.isUndef()) { | |
| 11364 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11365 | } | |
| 11366 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11367 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11368 | } | |
| 11369 | } | |
| 11370 | }, | |
| 11371 | else => {}, | |
| 11372 | } | |
| 11373 | ||
| 11374 | if (maybe_lhs_val) |lhs_val| { | |
| 11375 | if (lhs_val.isUndef()) { | |
| 11376 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 11377 | if (maybe_rhs_val) |rhs_val| { | |
| 11378 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11379 | return sema.addConstUndef(resolved_type); | |
| 11380 | } | |
| 11381 | } | |
| 11382 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11383 | } | |
| 11384 | return sema.addConstUndef(resolved_type); | |
| 11385 | } | |
| 11386 | ||
| 11387 | if (maybe_rhs_val) |rhs_val| { | |
| 11388 | if (is_int) { | |
| 11389 | return sema.addConstant( | |
| 11390 | resolved_type, | |
| 11391 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11392 | ); | |
| 11393 | } else { | |
| 11394 | return sema.addConstant( | |
| 11395 | resolved_type, | |
| 11396 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11397 | ); | |
| 11398 | } | |
| 11399 | } else { | |
| 11400 | if (is_int) { | |
| 11401 | break :rs .{ .src = rhs_src, .air_tag = .div_trunc }; | |
| 11402 | } else { | |
| 11403 | break :rs .{ .src = rhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float }; | |
| 11404 | } | |
| 11405 | } | |
| 11406 | } else { | |
| 11407 | if (is_int) { | |
| 11408 | break :rs .{ .src = lhs_src, .air_tag = .div_trunc }; | |
| 11409 | } else { | |
| 11410 | break :rs .{ .src = lhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float }; | |
| 11411 | } | |
| 11412 | } | |
| 11413 | }, | |
| 11414 | .div_trunc => { | |
| 11415 | // For integers: | |
| 11416 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11417 | // If the rhs is zero, compile error for division by zero. | |
| 11418 | // If the rhs is undefined, compile error because there is a possible | |
| 11419 | // value (zero) for which the division would be illegal behavior. | |
| 11420 | // If the lhs is undefined: | |
| 11421 | // * if lhs type is signed: | |
| 11422 | // * if rhs is comptime-known and not -1, result is undefined | |
| 11423 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 11424 | // possible value (-min_int / -1) for which division would be | |
| 11425 | // illegal behavior. | |
| 11426 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 11427 | // TODO: emit runtime safety for division by zero | |
| 11428 | // | |
| 11429 | // For floats: | |
| 11430 | // If the rhs is zero, compile error for division by zero. | |
| 11431 | // If the rhs is undefined, compile error because there is a possible | |
| 11432 | // value (zero) for which the division would be illegal behavior. | |
| 11433 | // If the lhs is undefined, result is undefined. | |
| 11434 | if (maybe_lhs_val) |lhs_val| { | |
| 11435 | if (!lhs_val.isUndef()) { | |
| 11436 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11437 | return sema.addConstant(resolved_type, Value.zero); | |
| 11438 | } | |
| 11439 | } | |
| 11440 | } | |
| 11441 | if (maybe_rhs_val) |rhs_val| { | |
| 11442 | if (rhs_val.isUndef()) { | |
| 11443 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11444 | } | |
| 11445 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11446 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11447 | } | |
| 11448 | } | |
| 11449 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_trunc_optimized else .div_trunc; | |
| 11450 | if (maybe_lhs_val) |lhs_val| { | |
| 11451 | if (lhs_val.isUndef()) { | |
| 11452 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 11453 | if (maybe_rhs_val) |rhs_val| { | |
| 11454 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11455 | return sema.addConstUndef(resolved_type); | |
| 11456 | } | |
| 11457 | } | |
| 11458 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11459 | } | |
| 11460 | return sema.addConstUndef(resolved_type); | |
| 11461 | } | |
| 11462 | ||
| 11463 | if (maybe_rhs_val) |rhs_val| { | |
| 11464 | if (is_int) { | |
| 11465 | return sema.addConstant( | |
| 11466 | resolved_type, | |
| 11467 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11468 | ); | |
| 11469 | } else { | |
| 11470 | return sema.addConstant( | |
| 11471 | resolved_type, | |
| 11472 | try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target), | |
| 11473 | ); | |
| 11474 | } | |
| 11475 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11476 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11477 | }, | |
| 11478 | .div_floor => { | |
| 11479 | // For integers: | |
| 11480 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11481 | // If the rhs is zero, compile error for division by zero. | |
| 11482 | // If the rhs is undefined, compile error because there is a possible | |
| 11483 | // value (zero) for which the division would be illegal behavior. | |
| 11484 | // If the lhs is undefined: | |
| 11485 | // * if lhs type is signed: | |
| 11486 | // * if rhs is comptime-known and not -1, result is undefined | |
| 11487 | // * if rhs is -1 or runtime-known, compile error because there is a | |
| 11488 | // possible value (-min_int / -1) for which division would be | |
| 11489 | // illegal behavior. | |
| 11490 | // * if lhs type is unsigned, undef is returned regardless of rhs. | |
| 11491 | // TODO: emit runtime safety for division by zero | |
| 11492 | // | |
| 11493 | // For floats: | |
| 11494 | // If the rhs is zero, compile error for division by zero. | |
| 11495 | // If the rhs is undefined, compile error because there is a possible | |
| 11496 | // value (zero) for which the division would be illegal behavior. | |
| 11497 | // If the lhs is undefined, result is undefined. | |
| 11498 | if (maybe_lhs_val) |lhs_val| { | |
| 11499 | if (!lhs_val.isUndef()) { | |
| 11500 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11501 | return sema.addConstant(resolved_type, Value.zero); | |
| 11502 | } | |
| 11503 | } | |
| 11504 | } | |
| 11505 | if (maybe_rhs_val) |rhs_val| { | |
| 11506 | if (rhs_val.isUndef()) { | |
| 11507 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11508 | } | |
| 11509 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11510 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11511 | } | |
| 11512 | } | |
| 11513 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_floor_optimized else .div_floor; | |
| 11514 | if (maybe_lhs_val) |lhs_val| { | |
| 11515 | if (lhs_val.isUndef()) { | |
| 11516 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | |
| 11517 | if (maybe_rhs_val) |rhs_val| { | |
| 11518 | if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) { | |
| 11519 | return sema.addConstUndef(resolved_type); | |
| 11520 | } | |
| 11521 | } | |
| 11522 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11523 | } | |
| 11524 | return sema.addConstUndef(resolved_type); | |
| 11525 | } | |
| 11526 | ||
| 11527 | if (maybe_rhs_val) |rhs_val| { | |
| 11528 | if (is_int) { | |
| 11529 | return sema.addConstant( | |
| 11530 | resolved_type, | |
| 11531 | try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena, target), | |
| 11532 | ); | |
| 11533 | } else { | |
| 11534 | return sema.addConstant( | |
| 11535 | resolved_type, | |
| 11536 | try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target), | |
| 11537 | ); | |
| 11538 | } | |
| 11539 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11540 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11541 | }, | |
| 11542 | .div_exact => { | |
| 11543 | // For integers: | |
| 11544 | // If the lhs is zero, then zero is returned regardless of rhs. | |
| 11545 | // If the rhs is zero, compile error for division by zero. | |
| 11546 | // If the rhs is undefined, compile error because there is a possible | |
| 11547 | // value (zero) for which the division would be illegal behavior. | |
| 11548 | // If the lhs is undefined, compile error because there is a possible | |
| 11549 | // value for which the division would result in a remainder. | |
| 11550 | // TODO: emit runtime safety for if there is a remainder | |
| 11551 | // TODO: emit runtime safety for division by zero | |
| 11552 | // | |
| 11553 | // For floats: | |
| 11554 | // If the rhs is zero, compile error for division by zero. | |
| 11555 | // If the rhs is undefined, compile error because there is a possible | |
| 11556 | // value (zero) for which the division would be illegal behavior. | |
| 11557 | // If the lhs is undefined, compile error because there is a possible | |
| 11558 | // value for which the division would result in a remainder. | |
| 11559 | if (maybe_lhs_val) |lhs_val| { | |
| 11560 | if (lhs_val.isUndef()) { | |
| 11561 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11562 | } else { | |
| 11563 | if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11564 | return sema.addConstant(resolved_type, Value.zero); | |
| 11565 | } | |
| 11566 | } | |
| 11567 | } | |
| 11568 | if (maybe_rhs_val) |rhs_val| { | |
| 11569 | if (rhs_val.isUndef()) { | |
| 11570 | return sema.failWithUseOfUndef(block, rhs_src); | |
| 11571 | } | |
| 11572 | if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { | |
| 11573 | return sema.failWithDivideByZero(block, rhs_src); | |
| 11574 | } | |
| 11575 | } | |
| 11576 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_exact_optimized else .div_exact; | |
| 11577 | if (maybe_lhs_val) |lhs_val| { | |
| 11578 | if (maybe_rhs_val) |rhs_val| { | |
| 11579 | if (is_int) { | |
| 11580 | // TODO: emit compile error if there is a remainder | |
| 11581 | return sema.addConstant( | |
| 11582 | resolved_type, | |
| 11583 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11584 | ); | |
| 11585 | } else { | |
| 11586 | // TODO: emit compile error if there is a remainder | |
| 11587 | return sema.addConstant( | |
| 11588 | resolved_type, | |
| 11589 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), | |
| 11590 | ); | |
| 11591 | } | |
| 11592 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11593 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11594 | }, | |
| 11595 | 12028 | .mul => { |
| 11596 | 12029 | // For integers: |
| 11597 | 12030 | // If either of the operands are zero, the result is zero. |
| ... | ... | @@ -11960,38 +12393,16 @@ fn analyzeArithmetic( |
| 11960 | 12393 | .operation = .Or, |
| 11961 | 12394 | } }, |
| 11962 | 12395 | }) |
| 11963 | else | |
| 11964 | ov_bit; | |
| 11965 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); | |
| 11966 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | |
| 11967 | ||
| 11968 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); | |
| 11969 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | |
| 11970 | } | |
| 11971 | } | |
| 11972 | switch (rs.air_tag) { | |
| 11973 | // zig fmt: off | |
| 11974 | .div_float, .div_exact, .div_trunc, .div_floor, .div_float_optimized, | |
| 11975 | .div_exact_optimized, .div_trunc_optimized, .div_floor_optimized | |
| 11976 | // zig fmt: on | |
| 11977 | => if (scalar_tag == .Int or block.float_mode == .Optimized) { | |
| 11978 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { | |
| 11979 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 11980 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val); | |
| 11981 | const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type)); | |
| 11982 | break :ok try block.addInst(.{ | |
| 11983 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 11984 | .data = .{ .reduce = .{ | |
| 11985 | .operand = ok, | |
| 11986 | .operation = .And, | |
| 11987 | } }, | |
| 11988 | }); | |
| 11989 | } else ok: { | |
| 11990 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); | |
| 11991 | break :ok try block.addBinOp(if (block.float_mode == .Optimized) .cmp_neq_optimized else .cmp_neq, casted_rhs, zero); | |
| 11992 | }; | |
| 11993 | try sema.addSafetyCheck(block, ok, .divide_by_zero); | |
| 11994 | }, | |
| 12396 | else | |
| 12397 | ov_bit; | |
| 12398 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); | |
| 12399 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | |
| 12400 | ||
| 12401 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); | |
| 12402 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | |
| 12403 | } | |
| 12404 | } | |
| 12405 | switch (rs.air_tag) { | |
| 11995 | 12406 | .rem, .mod, .rem_optimized, .mod_optimized => { |
| 11996 | 12407 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { |
| 11997 | 12408 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); |
| ... | ... | @@ -12018,47 +12429,6 @@ fn analyzeArithmetic( |
| 12018 | 12429 | }, |
| 12019 | 12430 | else => {}, |
| 12020 | 12431 | } |
| 12021 | if (rs.air_tag == .div_exact or rs.air_tag == .div_exact_optimized) { | |
| 12022 | const result = try block.addBinOp(.div_exact, casted_lhs, casted_rhs); | |
| 12023 | const ok = if (scalar_tag == .Float) ok: { | |
| 12024 | const floored = try block.addUnOp(.floor, result); | |
| 12025 | ||
| 12026 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 12027 | const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type)); | |
| 12028 | break :ok try block.addInst(.{ | |
| 12029 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 12030 | .data = .{ .reduce = .{ | |
| 12031 | .operand = eql, | |
| 12032 | .operation = .And, | |
| 12033 | } }, | |
| 12034 | }); | |
| 12035 | } else { | |
| 12036 | const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, result, floored); | |
| 12037 | break :ok is_in_range; | |
| 12038 | } | |
| 12039 | } else ok: { | |
| 12040 | const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); | |
| 12041 | ||
| 12042 | if (resolved_type.zigTypeTag() == .Vector) { | |
| 12043 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | |
| 12044 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val); | |
| 12045 | const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type)); | |
| 12046 | break :ok try block.addInst(.{ | |
| 12047 | .tag = .reduce, | |
| 12048 | .data = .{ .reduce = .{ | |
| 12049 | .operand = eql, | |
| 12050 | .operation = .And, | |
| 12051 | } }, | |
| 12052 | }); | |
| 12053 | } else { | |
| 12054 | const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); | |
| 12055 | const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, remainder, zero); | |
| 12056 | break :ok is_in_range; | |
| 12057 | } | |
| 12058 | }; | |
| 12059 | try sema.addSafetyCheck(block, ok, .exact_division_remainder); | |
| 12060 | return result; | |
| 12061 | } | |
| 12062 | 12432 | } |
| 12063 | 12433 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); |
| 12064 | 12434 | } |
| ... | ... | @@ -14696,6 +15066,22 @@ fn finishStructInit( |
| 14696 | 15066 | field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); |
| 14697 | 15067 | } |
| 14698 | 15068 | } |
| 15069 | } else if (struct_ty.isTuple()) { | |
| 15070 | const struct_obj = struct_ty.castTag(.tuple).?.data; | |
| 15071 | for (struct_obj.values) |default_val, i| { | |
| 15072 | if (field_inits[i] != .none) continue; | |
| 15073 | ||
| 15074 | if (default_val.tag() == .unreachable_value) { | |
| 15075 | const template = "missing tuple field with index {d}"; | |
| 15076 | if (root_msg) |msg| { | |
| 15077 | try sema.errNote(block, init_src, msg, template, .{i}); | |
| 15078 | } else { | |
| 15079 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | |
| 15080 | } | |
| 15081 | } else { | |
| 15082 | field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); | |
| 15083 | } | |
| 15084 | } | |
| 14699 | 15085 | } else { |
| 14700 | 15086 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 14701 | 15087 | for (struct_obj.fields.values()) |field, i| { |
| ... | ... | @@ -15373,6 +15759,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15373 | 15759 | const tag_ty = type_info_ty.unionTagType().?; |
| 15374 | 15760 | const target = mod.getTarget(); |
| 15375 | 15761 | const tag_index = tag_ty.enumTagFieldIndex(union_val.tag, mod).?; |
| 15762 | if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src); | |
| 15376 | 15763 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { |
| 15377 | 15764 | .Type => return Air.Inst.Ref.type_type, |
| 15378 | 15765 | .Void => return Air.Inst.Ref.void_type, |
| ... | ... | @@ -15442,7 +15829,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15442 | 15829 | const is_allowzero_val = struct_val[6]; |
| 15443 | 15830 | const sentinel_val = struct_val[7]; |
| 15444 | 15831 | |
| 15445 | const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); // TODO: Validate this value. | |
| 15832 | if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { | |
| 15833 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | |
| 15834 | } | |
| 15835 | const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); | |
| 15446 | 15836 | |
| 15447 | 15837 | var buffer: Value.ToTypeBuffer = undefined; |
| 15448 | 15838 | const unresolved_elem_ty = child_val.toType(&buffer); |
| ... | ... | @@ -15469,6 +15859,39 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15469 | 15859 | actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; |
| 15470 | 15860 | } |
| 15471 | 15861 | |
| 15862 | if (elem_ty.zigTypeTag() == .NoReturn) { | |
| 15863 | return sema.fail(block, src, "pointer to noreturn not allowed", .{}); | |
| 15864 | } else if (elem_ty.zigTypeTag() == .Fn) { | |
| 15865 | if (ptr_size != .One) { | |
| 15866 | return sema.fail(block, src, "function pointers must be single pointers", .{}); | |
| 15867 | } | |
| 15868 | const fn_align = elem_ty.fnInfo().alignment; | |
| 15869 | if (abi_align != 0 and fn_align != 0 and | |
| 15870 | abi_align != fn_align) | |
| 15871 | { | |
| 15872 | return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); | |
| 15873 | } | |
| 15874 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { | |
| 15875 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); | |
| 15876 | } else if (ptr_size == .C) { | |
| 15877 | if (!(try sema.validateExternType(elem_ty, .other))) { | |
| 15878 | const msg = msg: { | |
| 15879 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); | |
| 15880 | errdefer msg.destroy(sema.gpa); | |
| 15881 | ||
| 15882 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 15883 | try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), elem_ty, .other); | |
| 15884 | ||
| 15885 | try sema.addDeclaredHereNote(msg, elem_ty); | |
| 15886 | break :msg msg; | |
| 15887 | }; | |
| 15888 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 15889 | } | |
| 15890 | if (elem_ty.zigTypeTag() == .Opaque) { | |
| 15891 | return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); | |
| 15892 | } | |
| 15893 | } | |
| 15894 | ||
| 15472 | 15895 | const ty = try Type.ptr(sema.arena, mod, .{ |
| 15473 | 15896 | .size = ptr_size, |
| 15474 | 15897 | .mutable = !is_const_val.toBool(), |
| ... | ... | @@ -15529,6 +15952,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15529 | 15952 | const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena); |
| 15530 | 15953 | const payload_ty = try payload_val.toType(&buffer).copy(sema.arena); |
| 15531 | 15954 | |
| 15955 | if (error_set_ty.zigTypeTag() != .ErrorSet) { | |
| 15956 | return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); | |
| 15957 | } | |
| 15958 | ||
| 15532 | 15959 | const ty = try Type.Tag.error_union.create(sema.arena, .{ |
| 15533 | 15960 | .error_set = error_set_ty, |
| 15534 | 15961 | .payload = payload_ty, |
| ... | ... | @@ -15542,7 +15969,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15542 | 15969 | const decl_index = slice_val.ptr.pointerDecl().?; |
| 15543 | 15970 | try sema.ensureDeclAnalyzed(decl_index); |
| 15544 | 15971 | const decl = mod.declPtr(decl_index); |
| 15545 | const array_val = decl.val.castTag(.aggregate).?.data; | |
| 15972 | const array_val: []Value = if (decl.val.castTag(.aggregate)) |some| some.data else &.{}; | |
| 15546 | 15973 | |
| 15547 | 15974 | var names: Module.ErrorSet.NameMap = .{}; |
| 15548 | 15975 | try names.ensureUnusedCapacity(sema.arena, array_val.len); |
| ... | ... | @@ -15554,7 +15981,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15554 | 15981 | const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod); |
| 15555 | 15982 | |
| 15556 | 15983 | const kv = try mod.getErrorValue(name_str); |
| 15557 | names.putAssumeCapacityNoClobber(kv.key, {}); | |
| 15984 | const gop = names.getOrPutAssumeCapacity(kv.key); | |
| 15985 | if (gop.found_existing) { | |
| 15986 | return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); | |
| 15987 | } | |
| 15558 | 15988 | } |
| 15559 | 15989 | |
| 15560 | 15990 | // names must be sorted |
| ... | ... | @@ -15636,13 +16066,9 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15636 | 16066 | new_decl.owns_tv = true; |
| 15637 | 16067 | errdefer mod.abortAnonDecl(new_decl_index); |
| 15638 | 16068 | |
| 15639 | // Enum tag type | |
| 15640 | var buffer: Value.ToTypeBuffer = undefined; | |
| 15641 | const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 15642 | ||
| 15643 | 16069 | enum_obj.* = .{ |
| 15644 | 16070 | .owner_decl = new_decl_index, |
| 15645 | .tag_ty = int_tag_ty, | |
| 16071 | .tag_ty = Type.@"null", | |
| 15646 | 16072 | .tag_ty_inferred = false, |
| 15647 | 16073 | .fields = .{}, |
| 15648 | 16074 | .values = .{}, |
| ... | ... | @@ -15654,6 +16080,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15654 | 16080 | }, |
| 15655 | 16081 | }; |
| 15656 | 16082 | |
| 16083 | // Enum tag type | |
| 16084 | var buffer: Value.ToTypeBuffer = undefined; | |
| 16085 | const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 16086 | ||
| 16087 | if (int_tag_ty.zigTypeTag() != .Int) { | |
| 16088 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); | |
| 16089 | } | |
| 16090 | enum_obj.tag_ty = int_tag_ty; | |
| 16091 | ||
| 15657 | 16092 | // Fields |
| 15658 | 16093 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 15659 | 16094 | if (fields_len > 0) { |
| ... | ... | @@ -15691,6 +16126,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15691 | 16126 | .mod = mod, |
| 15692 | 16127 | }); |
| 15693 | 16128 | } |
| 16129 | } else { | |
| 16130 | return sema.fail(block, src, "enums must have at least one field", .{}); | |
| 15694 | 16131 | } |
| 15695 | 16132 | |
| 15696 | 16133 | try new_decl.finalizeNewArena(&new_decl_arena); |
| ... | ... | @@ -15800,11 +16237,17 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15800 | 16237 | }; |
| 15801 | 16238 | |
| 15802 | 16239 | // Tag type |
| 16240 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; | |
| 15803 | 16241 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; |
| 15804 | 16242 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 15805 | 16243 | if (tag_type_val.optionalValue()) |payload_val| { |
| 15806 | 16244 | var buffer: Value.ToTypeBuffer = undefined; |
| 15807 | 16245 | union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); |
| 16246 | ||
| 16247 | if (union_obj.tag_ty.zigTypeTag() != .Enum) { | |
| 16248 | return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}); | |
| 16249 | } | |
| 16250 | tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); | |
| 15808 | 16251 | } else { |
| 15809 | 16252 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); |
| 15810 | 16253 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; |
| ... | ... | @@ -15836,6 +16279,19 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15836 | 16279 | set.putAssumeCapacity(field_name, {}); |
| 15837 | 16280 | } |
| 15838 | 16281 | |
| 16282 | if (tag_ty_field_names) |*names| { | |
| 16283 | const enum_has_field = names.orderedRemove(field_name); | |
| 16284 | if (!enum_has_field) { | |
| 16285 | const msg = msg: { | |
| 16286 | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); | |
| 16287 | errdefer msg.destroy(sema.gpa); | |
| 16288 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | |
| 16289 | break :msg msg; | |
| 16290 | }; | |
| 16291 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 16292 | } | |
| 16293 | } | |
| 16294 | ||
| 15839 | 16295 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 15840 | 16296 | if (gop.found_existing) { |
| 15841 | 16297 | // TODO: better source location |
| ... | ... | @@ -15848,12 +16304,108 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15848 | 16304 | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), |
| 15849 | 16305 | }; |
| 15850 | 16306 | } |
| 16307 | } else { | |
| 16308 | return sema.fail(block, src, "unions must have at least one field", .{}); | |
| 16309 | } | |
| 16310 | ||
| 16311 | if (tag_ty_field_names) |names| { | |
| 16312 | if (names.count() > 0) { | |
| 16313 | const msg = msg: { | |
| 16314 | const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); | |
| 16315 | errdefer msg.destroy(sema.gpa); | |
| 16316 | ||
| 16317 | const enum_ty = union_obj.tag_ty; | |
| 16318 | for (names.keys()) |field_name| { | |
| 16319 | const field_index = enum_ty.enumFieldIndex(field_name).?; | |
| 16320 | try sema.addFieldErrNote(block, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); | |
| 16321 | } | |
| 16322 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | |
| 16323 | break :msg msg; | |
| 16324 | }; | |
| 16325 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 16326 | } | |
| 15851 | 16327 | } |
| 15852 | 16328 | |
| 15853 | 16329 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 15854 | 16330 | return sema.analyzeDeclVal(block, src, new_decl_index); |
| 15855 | 16331 | }, |
| 15856 | .Fn => return sema.fail(block, src, "TODO: Sema.zirReify for Fn", .{}), | |
| 16332 | .Fn => { | |
| 16333 | const struct_val = union_val.val.castTag(.aggregate).?.data; | |
| 16334 | // TODO use reflection instead of magic numbers here | |
| 16335 | // calling_convention: CallingConvention, | |
| 16336 | const cc = struct_val[0].toEnum(std.builtin.CallingConvention); | |
| 16337 | // alignment: comptime_int, | |
| 16338 | const alignment_val = struct_val[1]; | |
| 16339 | // is_generic: bool, | |
| 16340 | const is_generic = struct_val[2].toBool(); | |
| 16341 | // is_var_args: bool, | |
| 16342 | const is_var_args = struct_val[3].toBool(); | |
| 16343 | // return_type: ?type, | |
| 16344 | const return_type_val = struct_val[4]; | |
| 16345 | // args: []const Param, | |
| 16346 | const args_val = struct_val[5]; | |
| 16347 | ||
| 16348 | if (is_generic) { | |
| 16349 | return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); | |
| 16350 | } | |
| 16351 | ||
| 16352 | if (is_var_args and cc != .C) { | |
| 16353 | return sema.fail(block, src, "varargs functions must have C calling convention", .{}); | |
| 16354 | } | |
| 16355 | ||
| 16356 | const alignment = @intCast(u29, alignment_val.toUnsignedInt(target)); // TODO: Validate this value. | |
| 16357 | var buf: Value.ToTypeBuffer = undefined; | |
| 16358 | ||
| 16359 | const args: []Value = if (args_val.castTag(.aggregate)) |some| some.data else &.{}; | |
| 16360 | var param_types = try sema.arena.alloc(Type, args.len); | |
| 16361 | var comptime_params = try sema.arena.alloc(bool, args.len); | |
| 16362 | var noalias_bits: u32 = 0; | |
| 16363 | for (args) |arg, i| { | |
| 16364 | const arg_val = arg.castTag(.aggregate).?.data; | |
| 16365 | // TODO use reflection instead of magic numbers here | |
| 16366 | // is_generic: bool, | |
| 16367 | const arg_is_generic = arg_val[0].toBool(); | |
| 16368 | // is_noalias: bool, | |
| 16369 | const arg_is_noalias = arg_val[1].toBool(); | |
| 16370 | // arg_type: ?type, | |
| 16371 | const param_type_val = arg_val[2]; | |
| 16372 | ||
| 16373 | if (arg_is_generic) { | |
| 16374 | return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); | |
| 16375 | } | |
| 16376 | ||
| 16377 | if (arg_is_noalias) { | |
| 16378 | noalias_bits = @as(u32, 1) << (std.math.cast(u5, i) orelse | |
| 16379 | return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); | |
| 16380 | } | |
| 16381 | ||
| 16382 | const param_type = param_type_val.optionalValue() orelse | |
| 16383 | return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); | |
| 16384 | ||
| 16385 | param_types[i] = try param_type.toType(&buf).copy(sema.arena); | |
| 16386 | } | |
| 16387 | ||
| 16388 | const return_type = return_type_val.optionalValue() orelse | |
| 16389 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); | |
| 16390 | ||
| 16391 | var fn_info = Type.Payload.Function.Data{ | |
| 16392 | .param_types = param_types, | |
| 16393 | .comptime_params = comptime_params.ptr, | |
| 16394 | .noalias_bits = noalias_bits, | |
| 16395 | .return_type = try return_type.toType(&buf).copy(sema.arena), | |
| 16396 | .alignment = alignment, | |
| 16397 | .cc = cc, | |
| 16398 | .is_var_args = is_var_args, | |
| 16399 | .is_generic = false, | |
| 16400 | .align_is_generic = false, | |
| 16401 | .cc_is_generic = false, | |
| 16402 | .section_is_generic = false, | |
| 16403 | .addrspace_is_generic = false, | |
| 16404 | }; | |
| 16405 | ||
| 16406 | const ty = try Type.Tag.function.create(sema.arena, fn_info); | |
| 16407 | return sema.addType(ty); | |
| 16408 | }, | |
| 15857 | 16409 | .BoundFn => @panic("TODO delete BoundFn from the language"), |
| 15858 | 16410 | .Frame => @panic("TODO implement https://github.com/ziglang/zig/issues/10710"), |
| 15859 | 16411 | } |
| ... | ... | @@ -15996,6 +16548,11 @@ fn reifyStruct( |
| 15996 | 16548 | // alignment: comptime_int, |
| 15997 | 16549 | const alignment_val = field_struct_val[4]; |
| 15998 | 16550 | |
| 16551 | if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { | |
| 16552 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | |
| 16553 | } | |
| 16554 | const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); | |
| 16555 | ||
| 15999 | 16556 | const field_name = try name_val.toAllocatedBytes( |
| 16000 | 16557 | Type.initTag(.const_slice_u8), |
| 16001 | 16558 | new_decl_arena_allocator, |
| ... | ... | @@ -16019,7 +16576,7 @@ fn reifyStruct( |
| 16019 | 16576 | var buffer: Value.ToTypeBuffer = undefined; |
| 16020 | 16577 | gop.value_ptr.* = .{ |
| 16021 | 16578 | .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), |
| 16022 | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), | |
| 16579 | .abi_align = abi_align, | |
| 16023 | 16580 | .default_val = default_val, |
| 16024 | 16581 | .is_comptime = is_comptime_val.toBool(), |
| 16025 | 16582 | .offset = undefined, |
| ... | ... | @@ -16710,6 +17267,46 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr |
| 16710 | 17267 | } |
| 16711 | 17268 | } |
| 16712 | 17269 | |
| 17270 | fn checkInvalidPtrArithmetic( | |
| 17271 | sema: *Sema, | |
| 17272 | block: *Block, | |
| 17273 | src: LazySrcLoc, | |
| 17274 | ty: Type, | |
| 17275 | zir_tag: Zir.Inst.Tag, | |
| 17276 | ) CompileError!void { | |
| 17277 | switch (try ty.zigTypeTagOrPoison()) { | |
| 17278 | .Pointer => switch (ty.ptrSize()) { | |
| 17279 | .One, .Slice => return, | |
| 17280 | .Many, .C => return sema.fail( | |
| 17281 | block, | |
| 17282 | src, | |
| 17283 | "invalid pointer arithmetic operand: '{s}''", | |
| 17284 | .{@tagName(zir_tag)}, | |
| 17285 | ), | |
| 17286 | }, | |
| 17287 | else => return, | |
| 17288 | } | |
| 17289 | } | |
| 17290 | ||
| 17291 | fn checkArithmeticOp( | |
| 17292 | sema: *Sema, | |
| 17293 | block: *Block, | |
| 17294 | src: LazySrcLoc, | |
| 17295 | scalar_tag: std.builtin.TypeId, | |
| 17296 | lhs_zig_ty_tag: std.builtin.TypeId, | |
| 17297 | rhs_zig_ty_tag: std.builtin.TypeId, | |
| 17298 | zir_tag: Zir.Inst.Tag, | |
| 17299 | ) CompileError!void { | |
| 17300 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | |
| 17301 | const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; | |
| 17302 | ||
| 17303 | if (!is_int and !(is_float and floatOpAllowed(zir_tag))) { | |
| 17304 | return sema.fail(block, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ | |
| 17305 | @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag), | |
| 17306 | }); | |
| 17307 | } | |
| 17308 | } | |
| 17309 | ||
| 16713 | 17310 | fn checkPtrOperand( |
| 16714 | 17311 | sema: *Sema, |
| 16715 | 17312 | block: *Block, |
| ... | ... | @@ -20241,7 +20838,7 @@ fn tupleFieldVal( |
| 20241 | 20838 | return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty); |
| 20242 | 20839 | } |
| 20243 | 20840 | |
| 20244 | /// Don't forget to check for "len" before calling this. | |
| 20841 | /// Asserts that `field_name` is not "len". | |
| 20245 | 20842 | fn tupleFieldIndex( |
| 20246 | 20843 | sema: *Sema, |
| 20247 | 20844 | block: *Block, |
| ... | ... | @@ -20249,8 +20846,12 @@ fn tupleFieldIndex( |
| 20249 | 20846 | field_name: []const u8, |
| 20250 | 20847 | field_name_src: LazySrcLoc, |
| 20251 | 20848 | ) CompileError!u32 { |
| 20849 | assert(!std.mem.eql(u8, field_name, "len")); | |
| 20252 | 20850 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { |
| 20253 | 20851 | if (field_index < tuple_ty.structFieldCount()) return field_index; |
| 20852 | return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ | |
| 20853 | field_name, tuple_ty.fmt(sema.mod), | |
| 20854 | }); | |
| 20254 | 20855 | } else |_| {} |
| 20255 | 20856 | |
| 20256 | 20857 | return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{ |
| ... | ... | @@ -23927,8 +24528,7 @@ fn coerceTupleToStruct( |
| 23927 | 24528 | const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty); |
| 23928 | 24529 | |
| 23929 | 24530 | if (struct_ty.isTupleOrAnonStruct()) { |
| 23930 | // NOTE remember to handle comptime fields | |
| 23931 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{}); | |
| 24531 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); | |
| 23932 | 24532 | } |
| 23933 | 24533 | |
| 23934 | 24534 | const fields = struct_ty.structFields(); |
| ... | ... | @@ -24011,6 +24611,110 @@ fn coerceTupleToStruct( |
| 24011 | 24611 | ); |
| 24012 | 24612 | } |
| 24013 | 24613 | |
| 24614 | fn coerceTupleToTuple( | |
| 24615 | sema: *Sema, | |
| 24616 | block: *Block, | |
| 24617 | tuple_ty: Type, | |
| 24618 | inst: Air.Inst.Ref, | |
| 24619 | inst_src: LazySrcLoc, | |
| 24620 | ) !Air.Inst.Ref { | |
| 24621 | const field_count = tuple_ty.structFieldCount(); | |
| 24622 | const field_vals = try sema.arena.alloc(Value, field_count); | |
| 24623 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | |
| 24624 | mem.set(Air.Inst.Ref, field_refs, .none); | |
| 24625 | ||
| 24626 | const inst_ty = sema.typeOf(inst); | |
| 24627 | const tuple = inst_ty.tupleFields(); | |
| 24628 | var runtime_src: ?LazySrcLoc = null; | |
| 24629 | for (tuple.types) |_, i_usize| { | |
| 24630 | const i = @intCast(u32, i_usize); | |
| 24631 | const field_src = inst_src; // TODO better source location | |
| 24632 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | |
| 24633 | payload.data.names[i] | |
| 24634 | else | |
| 24635 | try std.fmt.allocPrint(sema.arena, "{d}", .{i}); | |
| 24636 | ||
| 24637 | if (mem.eql(u8, field_name, "len")) { | |
| 24638 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); | |
| 24639 | } | |
| 24640 | ||
| 24641 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); | |
| 24642 | ||
| 24643 | const field_ty = tuple_ty.structFieldType(i); | |
| 24644 | const default_val = tuple_ty.structFieldDefaultValue(i); | |
| 24645 | const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); | |
| 24646 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); | |
| 24647 | field_refs[field_index] = coerced; | |
| 24648 | if (default_val.tag() != .unreachable_value) { | |
| 24649 | const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse { | |
| 24650 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); | |
| 24651 | }; | |
| 24652 | ||
| 24653 | if (!init_val.eql(default_val, field_ty, sema.mod)) { | |
| 24654 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i); | |
| 24655 | } | |
| 24656 | } | |
| 24657 | if (runtime_src == null) { | |
| 24658 | if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { | |
| 24659 | field_vals[field_index] = field_val; | |
| 24660 | } else { | |
| 24661 | runtime_src = field_src; | |
| 24662 | } | |
| 24663 | } | |
| 24664 | } | |
| 24665 | ||
| 24666 | // Populate default field values and report errors for missing fields. | |
| 24667 | var root_msg: ?*Module.ErrorMsg = null; | |
| 24668 | ||
| 24669 | for (field_refs) |*field_ref, i| { | |
| 24670 | if (field_ref.* != .none) continue; | |
| 24671 | ||
| 24672 | const default_val = tuple_ty.structFieldDefaultValue(i); | |
| 24673 | const field_ty = tuple_ty.structFieldType(i); | |
| 24674 | ||
| 24675 | const field_src = inst_src; // TODO better source location | |
| 24676 | if (default_val.tag() == .unreachable_value) { | |
| 24677 | if (tuple_ty.isTuple()) { | |
| 24678 | const template = "missing tuple field: {d}"; | |
| 24679 | if (root_msg) |msg| { | |
| 24680 | try sema.errNote(block, field_src, msg, template, .{i}); | |
| 24681 | } else { | |
| 24682 | root_msg = try sema.errMsg(block, field_src, template, .{i}); | |
| 24683 | } | |
| 24684 | continue; | |
| 24685 | } | |
| 24686 | const template = "missing struct field: {s}"; | |
| 24687 | const args = .{tuple_ty.structFieldName(i)}; | |
| 24688 | if (root_msg) |msg| { | |
| 24689 | try sema.errNote(block, field_src, msg, template, args); | |
| 24690 | } else { | |
| 24691 | root_msg = try sema.errMsg(block, field_src, template, args); | |
| 24692 | } | |
| 24693 | continue; | |
| 24694 | } | |
| 24695 | if (runtime_src == null) { | |
| 24696 | field_vals[i] = default_val; | |
| 24697 | } else { | |
| 24698 | field_ref.* = try sema.addConstant(field_ty, default_val); | |
| 24699 | } | |
| 24700 | } | |
| 24701 | ||
| 24702 | if (root_msg) |msg| { | |
| 24703 | try sema.addDeclaredHereNote(msg, tuple_ty); | |
| 24704 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 24705 | } | |
| 24706 | ||
| 24707 | if (runtime_src) |rs| { | |
| 24708 | try sema.requireRuntimeBlock(block, inst_src, rs); | |
| 24709 | return block.addAggregateInit(tuple_ty, field_refs); | |
| 24710 | } | |
| 24711 | ||
| 24712 | return sema.addConstant( | |
| 24713 | tuple_ty, | |
| 24714 | try Value.Tag.aggregate.create(sema.arena, field_vals), | |
| 24715 | ); | |
| 24716 | } | |
| 24717 | ||
| 24014 | 24718 | fn analyzeDeclVal( |
| 24015 | 24719 | sema: *Sema, |
| 24016 | 24720 | block: *Block, |
| ... | ... | @@ -24446,7 +25150,10 @@ fn analyzeSlice( |
| 24446 | 25150 | if (!end_is_len) { |
| 24447 | 25151 | const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 24448 | 25152 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 24449 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { | |
| 25153 | if (try sema.resolveMaybeUndefVal(block, src, ptr_or_slice)) |slice_val| { | |
| 25154 | if (slice_val.isUndef()) { | |
| 25155 | return sema.fail(block, src, "slice of undefined", .{}); | |
| 25156 | } | |
| 24450 | 25157 | const has_sentinel = slice_ty.sentinel() != null; |
| 24451 | 25158 | var int_payload: Value.Payload.U64 = .{ |
| 24452 | 25159 | .base = .{ .tag = .int_u64 }, |
| ... | ... | @@ -24509,8 +25216,8 @@ fn analyzeSlice( |
| 24509 | 25216 | }; |
| 24510 | 25217 | |
| 24511 | 25218 | // requirement: start <= end |
| 24512 | if (try sema.resolveDefinedValue(block, src, end)) |end_val| { | |
| 24513 | if (try sema.resolveDefinedValue(block, src, start)) |start_val| { | |
| 25219 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { | |
| 25220 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { | |
| 24514 | 25221 | if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) { |
| 24515 | 25222 | return sema.fail( |
| 24516 | 25223 | block, |
| ... | ... | @@ -24522,6 +25229,45 @@ fn analyzeSlice( |
| 24522 | 25229 | }, |
| 24523 | 25230 | ); |
| 24524 | 25231 | } |
| 25232 | if (try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr)) |ptr_val| sentinel_check: { | |
| 25233 | const expected_sentinel = sentinel orelse break :sentinel_check; | |
| 25234 | const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; | |
| 25235 | const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; | |
| 25236 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); | |
| 25237 | ||
| 25238 | const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); | |
| 25239 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); | |
| 25240 | const actual_sentinel = switch (res) { | |
| 25241 | .runtime_load => break :sentinel_check, | |
| 25242 | .val => |v| v, | |
| 25243 | .needed_well_defined => |ty| return sema.fail( | |
| 25244 | block, | |
| 25245 | src, | |
| 25246 | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", | |
| 25247 | .{ty.fmt(sema.mod)}, | |
| 25248 | ), | |
| 25249 | .out_of_bounds => |ty| return sema.fail( | |
| 25250 | block, | |
| 25251 | end_src, | |
| 25252 | "slice end index {d} exceeds bounds of containing decl of type '{}'", | |
| 25253 | .{ end_int, ty.fmt(sema.mod) }, | |
| 25254 | ), | |
| 25255 | }; | |
| 25256 | ||
| 25257 | if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { | |
| 25258 | const msg = msg: { | |
| 25259 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); | |
| 25260 | errdefer msg.destroy(sema.gpa); | |
| 25261 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ | |
| 25262 | expected_sentinel.fmtValue(elem_ty, sema.mod), | |
| 25263 | actual_sentinel.fmtValue(elem_ty, sema.mod), | |
| 25264 | }); | |
| 25265 | ||
| 25266 | break :msg msg; | |
| 25267 | }; | |
| 25268 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 25269 | } | |
| 25270 | } | |
| 24525 | 25271 | } |
| 24526 | 25272 | } |
| 24527 | 25273 | |
| ... | ... | @@ -26884,7 +27630,8 @@ fn enumFieldSrcLoc( |
| 26884 | 27630 | .container_decl_arg_trailing, |
| 26885 | 27631 | => tree.containerDeclArg(enum_node), |
| 26886 | 27632 | |
| 26887 | else => unreachable, | |
| 27633 | // Container was constructed with `@Type`. | |
| 27634 | else => return LazySrcLoc.nodeOffset(node_offset), | |
| 26888 | 27635 | }; |
| 26889 | 27636 | var it_index: usize = 0; |
| 26890 | 27637 | for (container_decl.ast.members) |member_node| { |
| ... | ... | @@ -27161,9 +27908,36 @@ pub fn analyzeAddrspace( |
| 27161 | 27908 | /// Returns `null` if the pointer contents cannot be loaded at comptime. |
| 27162 | 27909 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { |
| 27163 | 27910 | const load_ty = ptr_ty.childType(); |
| 27911 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); | |
| 27912 | switch (res) { | |
| 27913 | .runtime_load => return null, | |
| 27914 | .val => |v| return v, | |
| 27915 | .needed_well_defined => |ty| return sema.fail( | |
| 27916 | block, | |
| 27917 | src, | |
| 27918 | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", | |
| 27919 | .{ty.fmt(sema.mod)}, | |
| 27920 | ), | |
| 27921 | .out_of_bounds => |ty| return sema.fail( | |
| 27922 | block, | |
| 27923 | src, | |
| 27924 | "dereference of '{}' exceeds bounds of containing decl of type '{}'", | |
| 27925 | .{ ptr_ty.fmt(sema.mod), ty.fmt(sema.mod) }, | |
| 27926 | ), | |
| 27927 | } | |
| 27928 | } | |
| 27929 | ||
| 27930 | const DerefResult = union(enum) { | |
| 27931 | runtime_load, | |
| 27932 | val: Value, | |
| 27933 | needed_well_defined: Type, | |
| 27934 | out_of_bounds: Type, | |
| 27935 | }; | |
| 27936 | ||
| 27937 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult { | |
| 27164 | 27938 | const target = sema.mod.getTarget(); |
| 27165 | 27939 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { |
| 27166 | error.RuntimeLoad => return null, | |
| 27940 | error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, | |
| 27167 | 27941 | else => |e| return e, |
| 27168 | 27942 | }; |
| 27169 | 27943 | |
| ... | ... | @@ -27174,39 +27948,40 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr |
| 27174 | 27948 | if (coerce_in_mem_ok) { |
| 27175 | 27949 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 27176 | 27950 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 27177 | if (deref.is_mutable) { | |
| 27951 | if (deref.is_mutable and want_mutable) { | |
| 27178 | 27952 | // The decl whose value we are obtaining here may be overwritten with |
| 27179 | 27953 | // a different value upon further semantic analysis, which would |
| 27180 | 27954 | // invalidate this memory. So we must copy here. |
| 27181 | return try tv.val.copy(sema.arena); | |
| 27955 | return DerefResult{ .val = try tv.val.copy(sema.arena) }; | |
| 27182 | 27956 | } |
| 27183 | return tv.val; | |
| 27957 | return DerefResult{ .val = tv.val }; | |
| 27184 | 27958 | } |
| 27185 | 27959 | } |
| 27186 | 27960 | |
| 27187 | 27961 | // The type is not in-memory coercible or the direct dereference failed, so it must |
| 27188 | 27962 | // be bitcast according to the pointer type we are performing the load through. |
| 27189 | if (!load_ty.hasWellDefinedLayout()) | |
| 27190 | return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{load_ty.fmt(sema.mod)}); | |
| 27963 | if (!load_ty.hasWellDefinedLayout()) { | |
| 27964 | return DerefResult{ .needed_well_defined = load_ty }; | |
| 27965 | } | |
| 27191 | 27966 | |
| 27192 | 27967 | const load_sz = try sema.typeAbiSize(block, src, load_ty); |
| 27193 | 27968 | |
| 27194 | 27969 | // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` |
| 27195 | 27970 | if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty)) |
| 27196 | return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0); | |
| 27971 | return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) }; | |
| 27197 | 27972 | |
| 27198 | 27973 | // If that fails, try to bit-cast from the largest parent value with a well-defined layout |
| 27199 | 27974 | if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(block, src, parent.tv.ty)) |
| 27200 | return try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset); | |
| 27975 | return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) }; | |
| 27201 | 27976 | |
| 27202 | 27977 | if (deref.ty_without_well_defined_layout) |bad_ty| { |
| 27203 | 27978 | // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem |
| 27204 | 27979 | // is that some type we encountered when de-referencing does not have a well-defined layout. |
| 27205 | return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{bad_ty.fmt(sema.mod)}); | |
| 27980 | return DerefResult{ .needed_well_defined = bad_ty }; | |
| 27206 | 27981 | } else { |
| 27207 | 27982 | // If all encountered types had well-defined layouts, the parent is the root decl and it just |
| 27208 | 27983 | // wasn't big enough for the load. |
| 27209 | return sema.fail(block, src, "dereference of '{}' exceeds bounds of containing decl of type '{}'", .{ ptr_ty.fmt(sema.mod), deref.parent.?.tv.ty.fmt(sema.mod) }); | |
| 27984 | return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; | |
| 27210 | 27985 | } |
| 27211 | 27986 | } |
| 27212 | 27987 |
src/TypedValue.zig+10-4| ... | ... | @@ -73,6 +73,9 @@ pub fn print( |
| 73 | 73 | const target = mod.getTarget(); |
| 74 | 74 | var val = tv.val; |
| 75 | 75 | var ty = tv.ty; |
| 76 | if (val.isVariable(mod)) | |
| 77 | return writer.writeAll("(variable)"); | |
| 78 | ||
| 76 | 79 | while (true) switch (val.tag()) { |
| 77 | 80 | .u1_type => return writer.writeAll("u1"), |
| 78 | 81 | .u8_type => return writer.writeAll("u8"), |
| ... | ... | @@ -155,9 +158,12 @@ pub fn print( |
| 155 | 158 | } |
| 156 | 159 | try print(.{ |
| 157 | 160 | .ty = ty.structFieldType(i), |
| 158 | .val = ty.structFieldValueComptime(i) orelse b: { | |
| 159 | const vals = val.castTag(.aggregate).?.data; | |
| 160 | break :b vals[i]; | |
| 161 | .val = switch (ty.containerLayout()) { | |
| 162 | .Packed => val.castTag(.aggregate).?.data[i], | |
| 163 | else => ty.structFieldValueComptime(i) orelse b: { | |
| 164 | const vals = val.castTag(.aggregate).?.data; | |
| 165 | break :b vals[i]; | |
| 166 | }, | |
| 161 | 167 | }, |
| 162 | 168 | }, writer, level - 1, mod); |
| 163 | 169 | } |
| ... | ... | @@ -241,7 +247,7 @@ pub fn print( |
| 241 | 247 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, |
| 242 | 248 | }), |
| 243 | 249 | .extern_fn => return writer.writeAll("(extern function)"), |
| 244 | .variable => return writer.writeAll("(variable)"), | |
| 250 | .variable => unreachable, | |
| 245 | 251 | .decl_ref_mut => { |
| 246 | 252 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; |
| 247 | 253 | const decl = mod.declPtr(decl_index); |
src/Zir.zig+12-1| ... | ... | @@ -280,6 +280,9 @@ pub const Inst = struct { |
| 280 | 280 | /// break instruction in a block, and the target block is the parent. |
| 281 | 281 | /// Uses the `break` union field. |
| 282 | 282 | break_inline, |
| 283 | /// Checks that comptime control flow does not happen inside a runtime block. | |
| 284 | /// Uses the `node` union field. | |
| 285 | check_comptime_control_flow, | |
| 283 | 286 | /// Function call. |
| 284 | 287 | /// Uses the `pl_node` union field with payload `Call`. |
| 285 | 288 | /// AST node is the function call. |
| ... | ... | @@ -1266,6 +1269,7 @@ pub const Inst = struct { |
| 1266 | 1269 | .repeat_inline, |
| 1267 | 1270 | .panic, |
| 1268 | 1271 | .panic_comptime, |
| 1272 | .check_comptime_control_flow, | |
| 1269 | 1273 | => true, |
| 1270 | 1274 | }; |
| 1271 | 1275 | } |
| ... | ... | @@ -1315,6 +1319,7 @@ pub const Inst = struct { |
| 1315 | 1319 | .set_runtime_safety, |
| 1316 | 1320 | .memcpy, |
| 1317 | 1321 | .memset, |
| 1322 | .check_comptime_control_flow, | |
| 1318 | 1323 | => true, |
| 1319 | 1324 | |
| 1320 | 1325 | .param, |
| ... | ... | @@ -1595,6 +1600,7 @@ pub const Inst = struct { |
| 1595 | 1600 | .bool_br_or = .bool_br, |
| 1596 | 1601 | .@"break" = .@"break", |
| 1597 | 1602 | .break_inline = .@"break", |
| 1603 | .check_comptime_control_flow = .node, | |
| 1598 | 1604 | .call = .pl_node, |
| 1599 | 1605 | .cmp_lt = .pl_node, |
| 1600 | 1606 | .cmp_lte = .pl_node, |
| ... | ... | @@ -1703,7 +1709,7 @@ pub const Inst = struct { |
| 1703 | 1709 | .switch_capture_multi_ref = .switch_capture, |
| 1704 | 1710 | .array_base_ptr = .un_node, |
| 1705 | 1711 | .field_base_ptr = .un_node, |
| 1706 | .validate_array_init_ty = .un_node, | |
| 1712 | .validate_array_init_ty = .pl_node, | |
| 1707 | 1713 | .validate_struct_init_ty = .un_node, |
| 1708 | 1714 | .validate_struct_init = .pl_node, |
| 1709 | 1715 | .validate_struct_init_comptime = .pl_node, |
| ... | ... | @@ -3537,6 +3543,11 @@ pub const Inst = struct { |
| 3537 | 3543 | line: u32, |
| 3538 | 3544 | column: u32, |
| 3539 | 3545 | }; |
| 3546 | ||
| 3547 | pub const ArrayInit = struct { | |
| 3548 | ty: Ref, | |
| 3549 | init_count: u32, | |
| 3550 | }; | |
| 3540 | 3551 | }; |
| 3541 | 3552 | |
| 3542 | 3553 | pub const SpecialProng = enum { none, @"else", under }; |
src/arch/arm/CodeGen.zig+34-27| ... | ... | @@ -4300,17 +4300,6 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4300 | 4300 | ); |
| 4301 | 4301 | defer self.gpa.free(liveness.deaths); |
| 4302 | 4302 | |
| 4303 | // If the condition dies here in this switch instruction, process | |
| 4304 | // that death now instead of later as this has an effect on | |
| 4305 | // whether it needs to be spilled in the branches | |
| 4306 | if (self.liveness.operandDies(inst, 0)) { | |
| 4307 | const op_int = @enumToInt(pl_op.operand); | |
| 4308 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | |
| 4309 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | |
| 4310 | self.processDeath(op_index); | |
| 4311 | } | |
| 4312 | } | |
| 4313 | ||
| 4314 | 4303 | var extra_index: usize = switch_br.end; |
| 4315 | 4304 | var case_i: u32 = 0; |
| 4316 | 4305 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| ... | ... | @@ -4320,21 +4309,43 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4320 | 4309 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 4321 | 4310 | extra_index = case.end + items.len + case_body.len; |
| 4322 | 4311 | |
| 4323 | var relocs = try self.gpa.alloc(u32, items.len); | |
| 4324 | defer self.gpa.free(relocs); | |
| 4325 | ||
| 4326 | if (items.len == 1) { | |
| 4312 | // For every item, we compare it to condition and branch into | |
| 4313 | // the prong if they are equal. After we compared to all | |
| 4314 | // items, we branch into the next prong (or if no other prongs | |
| 4315 | // exist out of the switch statement). | |
| 4316 | // | |
| 4317 | // cmp condition, item1 | |
| 4318 | // beq prong | |
| 4319 | // cmp condition, item2 | |
| 4320 | // beq prong | |
| 4321 | // cmp condition, item3 | |
| 4322 | // beq prong | |
| 4323 | // b out | |
| 4324 | // prong: ... | |
| 4325 | // ... | |
| 4326 | // out: ... | |
| 4327 | const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len); | |
| 4328 | defer self.gpa.free(branch_into_prong_relocs); | |
| 4329 | ||
| 4330 | for (items) |item, idx| { | |
| 4327 | 4331 | const condition = try self.resolveInst(pl_op.operand); |
| 4328 | const item = try self.resolveInst(items[0]); | |
| 4332 | const item_mcv = try self.resolveInst(item); | |
| 4329 | 4333 | |
| 4330 | 4334 | const operands: BinOpOperands = .{ .mcv = .{ |
| 4331 | 4335 | .lhs = condition, |
| 4332 | .rhs = item, | |
| 4336 | .rhs = item_mcv, | |
| 4333 | 4337 | } }; |
| 4334 | const cmp_result = try self.cmp(operands, condition_ty, .eq); | |
| 4335 | relocs[0] = try self.condBr(cmp_result); | |
| 4336 | } else { | |
| 4337 | return self.fail("TODO switch with multiple items", .{}); | |
| 4338 | const cmp_result = try self.cmp(operands, condition_ty, .neq); | |
| 4339 | branch_into_prong_relocs[idx] = try self.condBr(cmp_result); | |
| 4340 | } | |
| 4341 | ||
| 4342 | const branch_away_from_prong_reloc = try self.addInst(.{ | |
| 4343 | .tag = .b, | |
| 4344 | .data = .{ .inst = undefined }, // populated later through performReloc | |
| 4345 | }); | |
| 4346 | ||
| 4347 | for (branch_into_prong_relocs) |reloc| { | |
| 4348 | try self.performReloc(reloc); | |
| 4338 | 4349 | } |
| 4339 | 4350 | |
| 4340 | 4351 | // Capture the state of register and stack allocation state so that we can revert to it. |
| ... | ... | @@ -4369,9 +4380,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4369 | 4380 | self.next_stack_offset = parent_next_stack_offset; |
| 4370 | 4381 | self.register_manager.free_registers = parent_free_registers; |
| 4371 | 4382 | |
| 4372 | for (relocs) |reloc| { | |
| 4373 | try self.performReloc(reloc); | |
| 4374 | } | |
| 4383 | try self.performReloc(branch_away_from_prong_reloc); | |
| 4375 | 4384 | } |
| 4376 | 4385 | |
| 4377 | 4386 | if (switch_br.data.else_body_len > 0) { |
| ... | ... | @@ -4414,9 +4423,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4414 | 4423 | // in airCondBr. |
| 4415 | 4424 | } |
| 4416 | 4425 | |
| 4417 | // We already took care of pl_op.operand earlier, so we're going | |
| 4418 | // to pass .none here | |
| 4419 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | |
| 4426 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); | |
| 4420 | 4427 | } |
| 4421 | 4428 | |
| 4422 | 4429 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
src/arch/wasm/CodeGen.zig+2-2| ... | ... | @@ -603,7 +603,7 @@ stack_alignment: u32 = 16, |
| 603 | 603 | |
| 604 | 604 | const InnerError = error{ |
| 605 | 605 | OutOfMemory, |
| 606 | /// An error occured when trying to lower AIR to MIR. | |
| 606 | /// An error occurred when trying to lower AIR to MIR. | |
| 607 | 607 | CodegenFail, |
| 608 | 608 | /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed |
| 609 | 609 | AnalysisFail, |
| ... | ... | @@ -4410,7 +4410,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4410 | 4410 | } |
| 4411 | 4411 | |
| 4412 | 4412 | // We store the bit if it's overflowed or not in this. As it's zero-initialized |
| 4413 | // we only need to update it if an overflow (or underflow) occured. | |
| 4413 | // we only need to update it if an overflow (or underflow) occurred. | |
| 4414 | 4414 | const overflow_bit = try self.allocLocal(Type.initTag(.u1)); |
| 4415 | 4415 | const int_info = lhs_ty.intInfo(self.target); |
| 4416 | 4416 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
src/clang.zig+3| ... | ... | @@ -1913,3 +1913,6 @@ extern fn ZigClangLoadFromCommandLine( |
| 1913 | 1913 | errors_len: *usize, |
| 1914 | 1914 | resources_path: [*:0]const u8, |
| 1915 | 1915 | ) ?*ASTUnit; |
| 1916 | ||
| 1917 | pub const isLLVMUsingSeparateLibcxx = ZigClangIsLLVMUsingSeparateLibcxx; | |
| 1918 | extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool; |
src/codegen/llvm.zig+109-32| ... | ... | @@ -5491,22 +5491,26 @@ pub const FuncGen = struct { |
| 5491 | 5491 | defer arena_allocator.deinit(); |
| 5492 | 5492 | const arena = arena_allocator.allocator(); |
| 5493 | 5493 | |
| 5494 | const return_count: u8 = for (outputs) |output| { | |
| 5495 | if (output == .none) break 1; | |
| 5496 | } else 0; | |
| 5497 | const llvm_params_len = inputs.len + outputs.len - return_count; | |
| 5498 | const llvm_param_types = try arena.alloc(*const llvm.Type, llvm_params_len); | |
| 5499 | const llvm_param_values = try arena.alloc(*const llvm.Value, llvm_params_len); | |
| 5500 | const llvm_param_attrs = try arena.alloc(bool, llvm_params_len); | |
| 5494 | // The exact number of return / parameter values depends on which output values | |
| 5495 | // are passed by reference as indirect outputs (determined below). | |
| 5496 | const max_return_count = outputs.len; | |
| 5497 | const llvm_ret_types = try arena.alloc(*const llvm.Type, max_return_count); | |
| 5498 | const llvm_ret_indirect = try arena.alloc(bool, max_return_count); | |
| 5499 | ||
| 5500 | const max_param_count = inputs.len + outputs.len; | |
| 5501 | const llvm_param_types = try arena.alloc(*const llvm.Type, max_param_count); | |
| 5502 | const llvm_param_values = try arena.alloc(*const llvm.Value, max_param_count); | |
| 5503 | const llvm_param_attrs = try arena.alloc(bool, max_param_count); | |
| 5501 | 5504 | const target = self.dg.module.getTarget(); |
| 5502 | 5505 | |
| 5506 | var llvm_ret_i: usize = 0; | |
| 5503 | 5507 | var llvm_param_i: usize = 0; |
| 5504 | var total_i: usize = 0; | |
| 5508 | var total_i: u16 = 0; | |
| 5505 | 5509 | |
| 5506 | var name_map: std.StringArrayHashMapUnmanaged(void) = .{}; | |
| 5507 | try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len); | |
| 5510 | var name_map: std.StringArrayHashMapUnmanaged(u16) = .{}; | |
| 5511 | try name_map.ensureUnusedCapacity(arena, max_param_count); | |
| 5508 | 5512 | |
| 5509 | for (outputs) |output| { | |
| 5513 | for (outputs) |output, i| { | |
| 5510 | 5514 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 5511 | 5515 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 5512 | 5516 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| ... | ... | @@ -5519,15 +5523,30 @@ pub const FuncGen = struct { |
| 5519 | 5523 | llvm_constraints.appendAssumeCapacity(','); |
| 5520 | 5524 | } |
| 5521 | 5525 | llvm_constraints.appendAssumeCapacity('='); |
| 5526 | ||
| 5527 | // Pass any non-return outputs indirectly, if the constraint accepts a memory location | |
| 5528 | llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint); | |
| 5522 | 5529 | if (output != .none) { |
| 5523 | 5530 | try llvm_constraints.ensureUnusedCapacity(self.gpa, llvm_constraints.capacity + 1); |
| 5524 | llvm_constraints.appendAssumeCapacity('*'); | |
| 5525 | ||
| 5526 | 5531 | const output_inst = try self.resolveInst(output); |
| 5527 | llvm_param_values[llvm_param_i] = output_inst; | |
| 5528 | llvm_param_types[llvm_param_i] = output_inst.typeOf(); | |
| 5529 | llvm_param_attrs[llvm_param_i] = true; | |
| 5530 | llvm_param_i += 1; | |
| 5532 | ||
| 5533 | if (llvm_ret_indirect[i]) { | |
| 5534 | // Pass the result by reference as an indirect output (e.g. "=*m") | |
| 5535 | llvm_constraints.appendAssumeCapacity('*'); | |
| 5536 | ||
| 5537 | llvm_param_values[llvm_param_i] = output_inst; | |
| 5538 | llvm_param_types[llvm_param_i] = output_inst.typeOf(); | |
| 5539 | llvm_param_attrs[llvm_param_i] = true; | |
| 5540 | llvm_param_i += 1; | |
| 5541 | } else { | |
| 5542 | // Pass the result directly (e.g. "=r") | |
| 5543 | llvm_ret_types[llvm_ret_i] = output_inst.typeOf().getElementType(); | |
| 5544 | llvm_ret_i += 1; | |
| 5545 | } | |
| 5546 | } else { | |
| 5547 | const ret_ty = self.air.typeOfIndex(inst); | |
| 5548 | llvm_ret_types[llvm_ret_i] = try self.dg.lowerType(ret_ty); | |
| 5549 | llvm_ret_i += 1; | |
| 5531 | 5550 | } |
| 5532 | 5551 | |
| 5533 | 5552 | // LLVM uses commas internally to separate different constraints, |
| ... | ... | @@ -5536,13 +5555,16 @@ pub const FuncGen = struct { |
| 5536 | 5555 | // to GCC's inline assembly. |
| 5537 | 5556 | // http://llvm.org/docs/LangRef.html#constraint-codes |
| 5538 | 5557 | for (constraint[1..]) |byte| { |
| 5539 | llvm_constraints.appendAssumeCapacity(switch (byte) { | |
| 5540 | ',' => '|', | |
| 5541 | else => byte, | |
| 5542 | }); | |
| 5558 | switch (byte) { | |
| 5559 | ',' => llvm_constraints.appendAssumeCapacity('|'), | |
| 5560 | '*' => {}, // Indirect outputs are handled above | |
| 5561 | else => llvm_constraints.appendAssumeCapacity(byte), | |
| 5562 | } | |
| 5543 | 5563 | } |
| 5544 | 5564 | |
| 5545 | name_map.putAssumeCapacityNoClobber(name, {}); | |
| 5565 | if (!std.mem.eql(u8, name, "_")) { | |
| 5566 | name_map.putAssumeCapacityNoClobber(name, total_i); | |
| 5567 | } | |
| 5546 | 5568 | total_i += 1; |
| 5547 | 5569 | } |
| 5548 | 5570 | |
| ... | ... | @@ -5594,7 +5616,7 @@ pub const FuncGen = struct { |
| 5594 | 5616 | } |
| 5595 | 5617 | |
| 5596 | 5618 | if (!std.mem.eql(u8, name, "_")) { |
| 5597 | name_map.putAssumeCapacityNoClobber(name, {}); | |
| 5619 | name_map.putAssumeCapacityNoClobber(name, total_i); | |
| 5598 | 5620 | } |
| 5599 | 5621 | |
| 5600 | 5622 | // In the case of indirect inputs, LLVM requires the callsite to have |
| ... | ... | @@ -5625,6 +5647,11 @@ pub const FuncGen = struct { |
| 5625 | 5647 | } |
| 5626 | 5648 | } |
| 5627 | 5649 | |
| 5650 | // We have finished scanning through all inputs/outputs, so the number of | |
| 5651 | // parameters and return values is known. | |
| 5652 | const param_count = llvm_param_i; | |
| 5653 | const return_count = llvm_ret_i; | |
| 5654 | ||
| 5628 | 5655 | // For some targets, Clang unconditionally adds some clobbers to all inline assembly. |
| 5629 | 5656 | // While this is probably not strictly necessary, if we don't follow Clang's lead |
| 5630 | 5657 | // here then we may risk tripping LLVM bugs since anything not used by Clang tends |
| ... | ... | @@ -5682,7 +5709,7 @@ pub const FuncGen = struct { |
| 5682 | 5709 | const name = asm_source[name_start..i]; |
| 5683 | 5710 | state = .start; |
| 5684 | 5711 | |
| 5685 | const index = name_map.getIndex(name) orelse { | |
| 5712 | const index = name_map.get(name) orelse { | |
| 5686 | 5713 | // we should validate the assembly in Sema; by now it is too late |
| 5687 | 5714 | return self.todo("unknown input or output name: '{s}'", .{name}); |
| 5688 | 5715 | }; |
| ... | ... | @@ -5693,12 +5720,20 @@ pub const FuncGen = struct { |
| 5693 | 5720 | } |
| 5694 | 5721 | } |
| 5695 | 5722 | |
| 5696 | const ret_ty = self.air.typeOfIndex(inst); | |
| 5697 | const ret_llvm_ty = try self.dg.lowerType(ret_ty); | |
| 5723 | const ret_llvm_ty = switch (return_count) { | |
| 5724 | 0 => self.context.voidType(), | |
| 5725 | 1 => llvm_ret_types[0], | |
| 5726 | else => self.context.structType( | |
| 5727 | llvm_ret_types.ptr, | |
| 5728 | @intCast(c_uint, return_count), | |
| 5729 | .False, | |
| 5730 | ), | |
| 5731 | }; | |
| 5732 | ||
| 5698 | 5733 | const llvm_fn_ty = llvm.functionType( |
| 5699 | 5734 | ret_llvm_ty, |
| 5700 | 5735 | llvm_param_types.ptr, |
| 5701 | @intCast(c_uint, llvm_param_types.len), | |
| 5736 | @intCast(c_uint, param_count), | |
| 5702 | 5737 | .False, |
| 5703 | 5738 | ); |
| 5704 | 5739 | const asm_fn = llvm.getInlineAsm( |
| ... | ... | @@ -5715,18 +5750,40 @@ pub const FuncGen = struct { |
| 5715 | 5750 | const call = self.builder.buildCall( |
| 5716 | 5751 | asm_fn, |
| 5717 | 5752 | llvm_param_values.ptr, |
| 5718 | @intCast(c_uint, llvm_param_values.len), | |
| 5753 | @intCast(c_uint, param_count), | |
| 5719 | 5754 | .C, |
| 5720 | 5755 | .Auto, |
| 5721 | 5756 | "", |
| 5722 | 5757 | ); |
| 5723 | for (llvm_param_attrs) |need_elem_ty, i| { | |
| 5758 | for (llvm_param_attrs[0..param_count]) |need_elem_ty, i| { | |
| 5724 | 5759 | if (need_elem_ty) { |
| 5725 | 5760 | const elem_ty = llvm_param_types[i].getElementType(); |
| 5726 | 5761 | llvm.setCallElemTypeAttr(call, i, elem_ty); |
| 5727 | 5762 | } |
| 5728 | 5763 | } |
| 5729 | return call; | |
| 5764 | ||
| 5765 | var ret_val = call; | |
| 5766 | llvm_ret_i = 0; | |
| 5767 | for (outputs) |output, i| { | |
| 5768 | if (llvm_ret_indirect[i]) continue; | |
| 5769 | ||
| 5770 | const output_value = if (return_count > 1) b: { | |
| 5771 | break :b self.builder.buildExtractValue(call, @intCast(c_uint, llvm_ret_i), ""); | |
| 5772 | } else call; | |
| 5773 | ||
| 5774 | if (output != .none) { | |
| 5775 | const output_ptr = try self.resolveInst(output); | |
| 5776 | const output_ptr_ty = self.air.typeOf(output); | |
| 5777 | ||
| 5778 | const store_inst = self.builder.buildStore(output_value, output_ptr); | |
| 5779 | store_inst.setAlignment(output_ptr_ty.ptrAlignment(target)); | |
| 5780 | } else { | |
| 5781 | ret_val = output_value; | |
| 5782 | } | |
| 5783 | llvm_ret_i += 1; | |
| 5784 | } | |
| 5785 | ||
| 5786 | return ret_val; | |
| 5730 | 5787 | } |
| 5731 | 5788 | |
| 5732 | 5789 | fn airIsNonNull( |
| ... | ... | @@ -9709,10 +9766,30 @@ fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u1 { |
| 9709 | 9766 | return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target)); |
| 9710 | 9767 | } |
| 9711 | 9768 | |
| 9769 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location | |
| 9770 | /// | |
| 9771 | /// See also TargetInfo::validateOutputConstraint, AArch64TargetInfo::validateAsmConstraint, etc. in Clang | |
| 9712 | 9772 | fn constraintAllowsMemory(constraint: []const u8) bool { |
| 9713 | return constraint[0] == 'm'; | |
| 9773 | // TODO: This implementation is woefully incomplete. | |
| 9774 | for (constraint) |byte| { | |
| 9775 | switch (byte) { | |
| 9776 | '=', '*', ',', '&' => {}, | |
| 9777 | 'm', 'o', 'X', 'g' => return true, | |
| 9778 | else => {}, | |
| 9779 | } | |
| 9780 | } else return false; | |
| 9714 | 9781 | } |
| 9715 | 9782 | |
| 9783 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a register | |
| 9784 | /// | |
| 9785 | /// See also TargetInfo::validateOutputConstraint, AArch64TargetInfo::validateAsmConstraint, etc. in Clang | |
| 9716 | 9786 | fn constraintAllowsRegister(constraint: []const u8) bool { |
| 9717 | return constraint[0] != 'm'; | |
| 9787 | // TODO: This implementation is woefully incomplete. | |
| 9788 | for (constraint) |byte| { | |
| 9789 | switch (byte) { | |
| 9790 | '=', '*', ',', '&' => {}, | |
| 9791 | 'm', 'o' => {}, | |
| 9792 | else => return true, | |
| 9793 | } | |
| 9794 | } else return false; | |
| 9718 | 9795 | } |
src/link/Elf.zig+9| ... | ... | @@ -1592,6 +1592,15 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1592 | 1592 | } |
| 1593 | 1593 | } |
| 1594 | 1594 | } |
| 1595 | for (self.base.options.objects) |obj| { | |
| 1596 | if (Compilation.classifyFileExt(obj.path) == .shared_library) { | |
| 1597 | const lib_dir_path = std.fs.path.dirname(obj.path).?; | |
| 1598 | if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) { | |
| 1599 | try argv.append("-rpath"); | |
| 1600 | try argv.append(lib_dir_path); | |
| 1601 | } | |
| 1602 | } | |
| 1603 | } | |
| 1595 | 1604 | } |
| 1596 | 1605 | |
| 1597 | 1606 | for (self.base.options.lib_dirs) |lib_dir| { |
src/main.zig+24-1| ... | ... | @@ -174,6 +174,17 @@ pub fn main() anyerror!void { |
| 174 | 174 | return mainArgs(gpa, arena, args); |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | /// Check that LLVM and Clang have been linked properly so that they are using the same | |
| 178 | /// libc++ and can safely share objects with pointers to static variables in libc++ | |
| 179 | fn verifyLibcxxCorrectlyLinked() void { | |
| 180 | if (build_options.have_llvm and ZigClangIsLLVMUsingSeparateLibcxx()) { | |
| 181 | fatal( | |
| 182 | \\Zig was built/linked incorrectly: LLVM and Clang have separate copies of libc++ | |
| 183 | \\ If you are dynamically linking LLVM, make sure you dynamically link libc++ too | |
| 184 | , .{}); | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 177 | 188 | pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 178 | 189 | if (args.len <= 1) { |
| 179 | 190 | std.log.info("{s}", .{usage}); |
| ... | ... | @@ -261,8 +272,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi |
| 261 | 272 | const stdout = io.getStdOut().writer(); |
| 262 | 273 | return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target); |
| 263 | 274 | } else if (mem.eql(u8, cmd, "version")) { |
| 264 | return std.io.getStdOut().writeAll(build_options.version ++ "\n"); | |
| 275 | try std.io.getStdOut().writeAll(build_options.version ++ "\n"); | |
| 276 | // Check libc++ linkage to make sure Zig was built correctly, but only for "env" and "version" | |
| 277 | // to avoid affecting the startup time for build-critical commands (check takes about ~10 μs) | |
| 278 | return verifyLibcxxCorrectlyLinked(); | |
| 265 | 279 | } else if (mem.eql(u8, cmd, "env")) { |
| 280 | verifyLibcxxCorrectlyLinked(); | |
| 266 | 281 | return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); |
| 267 | 282 | } else if (mem.eql(u8, cmd, "zen")) { |
| 268 | 283 | return io.getStdOut().writeAll(info_zen); |
| ... | ... | @@ -858,6 +873,12 @@ fn buildOutputType( |
| 858 | 873 | ) catch |err| { |
| 859 | 874 | fatal("Failed to add package at path {s}: {s}", .{ pkg_path.?, @errorName(err) }); |
| 860 | 875 | }; |
| 876 | ||
| 877 | if (mem.eql(u8, pkg_name.?, "std") or mem.eql(u8, pkg_name.?, "root") or mem.eql(u8, pkg_name.?, "builtin")) { | |
| 878 | fatal("unable to add package '{s}' -> '{s}': conflicts with builtin package", .{ pkg_name.?, pkg_path.? }); | |
| 879 | } else if (cur_pkg.table.get(pkg_name.?)) |prev| { | |
| 880 | fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name.?, pkg_path.?, prev.root_src_path }); | |
| 881 | } | |
| 861 | 882 | try cur_pkg.addAndAdopt(gpa, pkg_name.?, new_cur_pkg); |
| 862 | 883 | cur_pkg = new_cur_pkg; |
| 863 | 884 | } else if (mem.eql(u8, arg, "--pkg-end")) { |
| ... | ... | @@ -4481,6 +4502,8 @@ pub const info_zen = |
| 4481 | 4502 | \\ |
| 4482 | 4503 | ; |
| 4483 | 4504 | |
| 4505 | extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool; | |
| 4506 | ||
| 4484 | 4507 | extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4485 | 4508 | extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 4486 | 4509 |
src/print_zir.zig+14-1| ... | ... | @@ -229,7 +229,6 @@ const Writer = struct { |
| 229 | 229 | .switch_cond_ref, |
| 230 | 230 | .array_base_ptr, |
| 231 | 231 | .field_base_ptr, |
| 232 | .validate_array_init_ty, | |
| 233 | 232 | .validate_struct_init_ty, |
| 234 | 233 | .make_ptr_const, |
| 235 | 234 | .validate_deref, |
| ... | ... | @@ -246,6 +245,7 @@ const Writer = struct { |
| 246 | 245 | .bool_br_or, |
| 247 | 246 | => try self.writeBoolBr(stream, inst), |
| 248 | 247 | |
| 248 | .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst), | |
| 249 | 249 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 250 | 250 | .param_type => try self.writeParamType(stream, inst), |
| 251 | 251 | .ptr_type => try self.writePtrType(stream, inst), |
| ... | ... | @@ -409,6 +409,7 @@ const Writer = struct { |
| 409 | 409 | .alloc_inferred_comptime_mut, |
| 410 | 410 | .ret_ptr, |
| 411 | 411 | .ret_type, |
| 412 | .check_comptime_control_flow, | |
| 412 | 413 | => try self.writeNode(stream, inst), |
| 413 | 414 | |
| 414 | 415 | .error_value, |
| ... | ... | @@ -576,6 +577,18 @@ const Writer = struct { |
| 576 | 577 | try self.writeSrc(stream, inst_data.src()); |
| 577 | 578 | } |
| 578 | 579 | |
| 580 | fn writeValidateArrayInitTy( | |
| 581 | self: *Writer, | |
| 582 | stream: anytype, | |
| 583 | inst: Zir.Inst.Index, | |
| 584 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | |
| 585 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | |
| 586 | const extra = self.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; | |
| 587 | try self.writeInstRef(stream, extra.ty); | |
| 588 | try stream.print(", {d}) ", .{extra.init_count}); | |
| 589 | try self.writeSrc(stream, inst_data.src()); | |
| 590 | } | |
| 591 | ||
| 579 | 592 | fn writeArrayTypeSentinel( |
| 580 | 593 | self: *Writer, |
| 581 | 594 | stream: anytype, |
src/stage1/parser.hpp-2| ... | ... | @@ -14,8 +14,6 @@ |
| 14 | 14 | |
| 15 | 15 | AstNode * ast_parse(Buf *buf, ZigType *owner, ErrColor err_color); |
| 16 | 16 | |
| 17 | void ast_print(AstNode *node, int indent); | |
| 18 | ||
| 19 | 17 | void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); |
| 20 | 18 | |
| 21 | 19 | Buf *node_identifier_buf(AstNode *node); |
src/translate_c.zig+22-8| ... | ... | @@ -2688,16 +2688,26 @@ fn transInitListExprVector( |
| 2688 | 2688 | ) TransError!Node { |
| 2689 | 2689 | _ = ty; |
| 2690 | 2690 | const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr)); |
| 2691 | const vector_type = try transQualType(c, scope, qt, loc); | |
| 2691 | const vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(qt)); | |
| 2692 | ||
| 2692 | 2693 | const init_count = expr.getNumInits(); |
| 2694 | const num_elements = vector_ty.getNumElements(); | |
| 2695 | const element_qt = vector_ty.getElementType(); | |
| 2693 | 2696 | |
| 2694 | 2697 | if (init_count == 0) { |
| 2695 | return Tag.container_init.create(c.arena, .{ | |
| 2696 | .lhs = vector_type, | |
| 2697 | .inits = try c.arena.alloc(ast.Payload.ContainerInit.Initializer, 0), | |
| 2698 | const zero_node = try Tag.as.create(c.arena, .{ | |
| 2699 | .lhs = try transQualType(c, scope, element_qt, loc), | |
| 2700 | .rhs = Tag.zero_literal.init(), | |
| 2701 | }); | |
| 2702 | ||
| 2703 | return Tag.vector_zero_init.create(c.arena, .{ | |
| 2704 | .lhs = try transCreateNodeNumber(c, num_elements, .int), | |
| 2705 | .rhs = zero_node, | |
| 2698 | 2706 | }); |
| 2699 | 2707 | } |
| 2700 | 2708 | |
| 2709 | const vector_type = try transQualType(c, scope, qt, loc); | |
| 2710 | ||
| 2701 | 2711 | var block_scope = try Scope.Block.init(c, scope, true); |
| 2702 | 2712 | defer block_scope.deinit(); |
| 2703 | 2713 | |
| ... | ... | @@ -2716,11 +2726,15 @@ fn transInitListExprVector( |
| 2716 | 2726 | try block_scope.statements.append(tmp_decl_node); |
| 2717 | 2727 | } |
| 2718 | 2728 | |
| 2719 | const init_list = try c.arena.alloc(Node, init_count); | |
| 2729 | const init_list = try c.arena.alloc(Node, num_elements); | |
| 2720 | 2730 | for (init_list) |*init, init_index| { |
| 2721 | const tmp_decl = block_scope.statements.items[init_index]; | |
| 2722 | const name = tmp_decl.castTag(.var_simple).?.data.name; | |
| 2723 | init.* = try Tag.identifier.create(c.arena, name); | |
| 2731 | if (init_index < init_count) { | |
| 2732 | const tmp_decl = block_scope.statements.items[init_index]; | |
| 2733 | const name = tmp_decl.castTag(.var_simple).?.data.name; | |
| 2734 | init.* = try Tag.identifier.create(c.arena, name); | |
| 2735 | } else { | |
| 2736 | init.* = Tag.undefined_literal.init(); | |
| 2737 | } | |
| 2724 | 2738 | } |
| 2725 | 2739 | |
| 2726 | 2740 | const array_init = try Tag.array_init.create(c.arena, .{ |
src/translate_c/ast.zig+8| ... | ... | @@ -154,6 +154,8 @@ pub const Node = extern union { |
| 154 | 154 | div_exact, |
| 155 | 155 | /// @offsetOf(lhs, rhs) |
| 156 | 156 | offset_of, |
| 157 | /// @splat(lhs, rhs) | |
| 158 | vector_zero_init, | |
| 157 | 159 | /// @shuffle(type, a, b, mask) |
| 158 | 160 | shuffle, |
| 159 | 161 | |
| ... | ... | @@ -328,6 +330,7 @@ pub const Node = extern union { |
| 328 | 330 | .div_exact, |
| 329 | 331 | .offset_of, |
| 330 | 332 | .helpers_cast, |
| 333 | .vector_zero_init, | |
| 331 | 334 | => Payload.BinOp, |
| 332 | 335 | |
| 333 | 336 | .integer_literal, |
| ... | ... | @@ -1829,6 +1832,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1829 | 1832 | const type_expr = try renderNode(c, payload.cond); |
| 1830 | 1833 | return renderArrayInit(c, type_expr, payload.cases); |
| 1831 | 1834 | }, |
| 1835 | .vector_zero_init => { | |
| 1836 | const payload = node.castTag(.vector_zero_init).?.data; | |
| 1837 | return renderBuiltinCall(c, "@splat", &.{ payload.lhs, payload.rhs }); | |
| 1838 | }, | |
| 1832 | 1839 | .field_access => { |
| 1833 | 1840 | const payload = node.castTag(.field_access).?.data; |
| 1834 | 1841 | const lhs = try renderNodeGrouped(c, payload.lhs); |
| ... | ... | @@ -2305,6 +2312,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2305 | 2312 | .@"struct", |
| 2306 | 2313 | .@"union", |
| 2307 | 2314 | .array_init, |
| 2315 | .vector_zero_init, | |
| 2308 | 2316 | .tuple, |
| 2309 | 2317 | .container_init, |
| 2310 | 2318 | .container_init_dot, |
src/type.zig+13-3| ... | ... | @@ -5201,10 +5201,20 @@ pub const Type = extern union { |
| 5201 | 5201 | }; |
| 5202 | 5202 | } |
| 5203 | 5203 | |
| 5204 | // Works for vectors and vectors of integers. | |
| 5205 | pub fn minInt(ty: Type, arena: Allocator, target: Target) !Value { | |
| 5206 | const scalar = try minIntScalar(ty.scalarType(), arena, target); | |
| 5207 | if (ty.zigTypeTag() == .Vector) { | |
| 5208 | return Value.Tag.repeated.create(arena, scalar); | |
| 5209 | } else { | |
| 5210 | return scalar; | |
| 5211 | } | |
| 5212 | } | |
| 5213 | ||
| 5204 | 5214 | /// Asserts that self.zigTypeTag() == .Int. |
| 5205 | pub fn minInt(self: Type, arena: Allocator, target: Target) !Value { | |
| 5206 | assert(self.zigTypeTag() == .Int); | |
| 5207 | const info = self.intInfo(target); | |
| 5215 | pub fn minIntScalar(ty: Type, arena: Allocator, target: Target) !Value { | |
| 5216 | assert(ty.zigTypeTag() == .Int); | |
| 5217 | const info = ty.intInfo(target); | |
| 5208 | 5218 | |
| 5209 | 5219 | if (info.signedness == .unsigned) { |
| 5210 | 5220 | return Value.zero; |
src/value.zig+36-15| ... | ... | @@ -2292,25 +2292,13 @@ pub const Value = extern union { |
| 2292 | 2292 | } |
| 2293 | 2293 | }, |
| 2294 | 2294 | .Struct => { |
| 2295 | if (ty.isTupleOrAnonStruct()) { | |
| 2296 | const fields = ty.tupleFields(); | |
| 2297 | for (fields.values) |field_val, i| { | |
| 2298 | field_val.hash(fields.types[i], hasher, mod); | |
| 2299 | } | |
| 2300 | return; | |
| 2301 | } | |
| 2302 | const fields = ty.structFields().values(); | |
| 2303 | if (fields.len == 0) return; | |
| 2304 | 2295 | switch (val.tag()) { |
| 2305 | .empty_struct_value => { | |
| 2306 | for (fields) |field| { | |
| 2307 | field.default_val.hash(field.ty, hasher, mod); | |
| 2308 | } | |
| 2309 | }, | |
| 2296 | .empty_struct_value => {}, | |
| 2310 | 2297 | .aggregate => { |
| 2311 | 2298 | const field_values = val.castTag(.aggregate).?.data; |
| 2312 | 2299 | for (field_values) |field_val, i| { |
| 2313 | field_val.hash(fields[i].ty, hasher, mod); | |
| 2300 | const field_ty = ty.structFieldType(i); | |
| 2301 | field_val.hash(field_ty, hasher, mod); | |
| 2314 | 2302 | } |
| 2315 | 2303 | }, |
| 2316 | 2304 | else => unreachable, |
| ... | ... | @@ -2664,6 +2652,26 @@ pub const Value = extern union { |
| 2664 | 2652 | } |
| 2665 | 2653 | } |
| 2666 | 2654 | |
| 2655 | /// Returns true if a Value is backed by a variable | |
| 2656 | pub fn isVariable( | |
| 2657 | val: Value, | |
| 2658 | mod: *Module, | |
| 2659 | ) bool { | |
| 2660 | return switch (val.tag()) { | |
| 2661 | .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), | |
| 2662 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), | |
| 2663 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), | |
| 2664 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), | |
| 2665 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2666 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2667 | .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isVariable(mod), | |
| 2668 | .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isVariable(mod), | |
| 2669 | ||
| 2670 | .variable => true, | |
| 2671 | else => false, | |
| 2672 | }; | |
| 2673 | } | |
| 2674 | ||
| 2667 | 2675 | // Asserts that the provided start/end are in-bounds. |
| 2668 | 2676 | pub fn sliceArray( |
| 2669 | 2677 | val: Value, |
| ... | ... | @@ -2778,6 +2786,19 @@ pub const Value = extern union { |
| 2778 | 2786 | return self.isUndef(); |
| 2779 | 2787 | } |
| 2780 | 2788 | |
| 2789 | /// Returns true if any value contained in `self` is undefined. | |
| 2790 | /// TODO: check for cases such as array that is not marked undef but all the element | |
| 2791 | /// values are marked undef, or struct that is not marked undef but all fields are marked | |
| 2792 | /// undef, etc. | |
| 2793 | pub fn anyUndef(self: Value) bool { | |
| 2794 | if (self.castTag(.aggregate)) |aggregate| { | |
| 2795 | for (aggregate.data) |val| { | |
| 2796 | if (val.anyUndef()) return true; | |
| 2797 | } | |
| 2798 | } | |
| 2799 | return self.isUndef(); | |
| 2800 | } | |
| 2801 | ||
| 2781 | 2802 | /// Asserts the value is not undefined and not unreachable. |
| 2782 | 2803 | /// Integer value 0 is considered null because of C pointers. |
| 2783 | 2804 | pub fn isNull(self: Value) bool { |
src/zig_clang.cpp+28| ... | ... | @@ -3432,3 +3432,31 @@ const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct Zi |
| 3432 | 3432 | const llvm::APSInt *result = &casted->getInitVal(); |
| 3433 | 3433 | return reinterpret_cast<const ZigClangAPSInt *>(result); |
| 3434 | 3434 | } |
| 3435 | ||
| 3436 | // Get a pointer to a static variable in libc++ from LLVM and make sure that | |
| 3437 | // it matches our own. | |
| 3438 | // | |
| 3439 | // This check is needed because if static/dynamic linking is mixed incorrectly, | |
| 3440 | // it's possible for Clang and LLVM to end up with duplicate "copies" of libc++. | |
| 3441 | // | |
| 3442 | // This is not benign: Static variables are not shared, so equality comparisons | |
| 3443 | // that depend on pointers to static variables will fail. One such failure is | |
| 3444 | // std::generic_category(), which causes POSIX error codes to compare as unequal | |
| 3445 | // when passed between LLVM and Clang. | |
| 3446 | // | |
| 3447 | // See also: https://github.com/ziglang/zig/issues/11168 | |
| 3448 | bool ZigClangIsLLVMUsingSeparateLibcxx() { | |
| 3449 | ||
| 3450 | // Temporarily create an InMemoryFileSystem, so that we can perform a file | |
| 3451 | // lookup that is guaranteed to fail. | |
| 3452 | auto FS = new llvm::vfs::InMemoryFileSystem(true); | |
| 3453 | auto StatusOrErr = FS->status("foo.txt"); | |
| 3454 | delete FS; | |
| 3455 | ||
| 3456 | // This should return a POSIX (generic_category) error code, but if LLVM has | |
| 3457 | // its own copy of libc++ this will actually be a separate category instance. | |
| 3458 | assert(!StatusOrErr); | |
| 3459 | auto EC = StatusOrErr.getError(); | |
| 3460 | return EC.category() != std::generic_category(); | |
| 3461 | } | |
| 3462 |
src/zig_clang.h+1| ... | ... | @@ -1418,4 +1418,5 @@ ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const |
| 1418 | 1418 | ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *); |
| 1419 | 1419 | |
| 1420 | 1420 | ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *); |
| 1421 | ZIG_EXTERN_C bool ZigClangIsLLVMUsingSeparateLibcxx(); | |
| 1421 | 1422 | #endif |
test/behavior/switch.zig-9| ... | ... | @@ -53,7 +53,6 @@ test "implicit comptime switch" { |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | test "switch on enum" { |
| 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 57 | 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 58 | 57 | |
| 59 | 58 | const fruit = Fruit.Orange; |
| ... | ... | @@ -73,7 +72,6 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void { |
| 73 | 72 | } |
| 74 | 73 | |
| 75 | 74 | test "switch statement" { |
| 76 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 77 | 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 78 | 76 | |
| 79 | 77 | try nonConstSwitch(SwitchStatementFoo.C); |
| ... | ... | @@ -91,7 +89,6 @@ const SwitchStatementFoo = enum { A, B, C, D }; |
| 91 | 89 | |
| 92 | 90 | test "switch with multiple expressions" { |
| 93 | 91 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 94 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 95 | 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 96 | 93 | |
| 97 | 94 | const x = switch (returnsFive()) { |
| ... | ... | @@ -120,7 +117,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool { |
| 120 | 117 | } |
| 121 | 118 | |
| 122 | 119 | test "switching on booleans" { |
| 123 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 124 | 120 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 125 | 121 | |
| 126 | 122 | try testSwitchOnBools(); |
| ... | ... | @@ -218,7 +214,6 @@ fn poll() void { |
| 218 | 214 | } |
| 219 | 215 | |
| 220 | 216 | test "switch on global mutable var isn't constant-folded" { |
| 221 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 222 | 217 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 223 | 218 | |
| 224 | 219 | while (state < 2) { |
| ... | ... | @@ -278,7 +273,6 @@ fn testSwitchEnumPtrCapture() !void { |
| 278 | 273 | |
| 279 | 274 | test "switch handles all cases of number" { |
| 280 | 275 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 281 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 282 | 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 283 | 277 | |
| 284 | 278 | try testSwitchHandleAllCases(); |
| ... | ... | @@ -370,7 +364,6 @@ test "anon enum literal used in switch on union enum" { |
| 370 | 364 | } |
| 371 | 365 | |
| 372 | 366 | test "switch all prongs unreachable" { |
| 373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 374 | 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 375 | 368 | |
| 376 | 369 | try testAllProngsUnreachable(); |
| ... | ... | @@ -582,7 +575,6 @@ test "switch on pointer type" { |
| 582 | 575 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 583 | 576 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 584 | 577 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 586 | 578 | |
| 587 | 579 | const S = struct { |
| 588 | 580 | const X = struct { |
| ... | ... | @@ -674,7 +666,6 @@ test "capture of integer forwards the switch condition directly" { |
| 674 | 666 | } |
| 675 | 667 | |
| 676 | 668 | test "enum value without tag name used as switch item" { |
| 677 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 678 | 669 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 679 | 670 | |
| 680 | 671 | const E = enum(u32) { |
test/behavior/tuple.zig+35| ... | ... | @@ -255,3 +255,38 @@ test "initializing anon struct with mixed comptime-runtime fields" { |
| 255 | 255 | var a: T = .{ .foo = -1234, .bar = x + 1 }; |
| 256 | 256 | _ = a; |
| 257 | 257 | } |
| 258 | ||
| 259 | test "tuple in tuple passed to generic function" { | |
| 260 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 261 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 263 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 264 | ||
| 265 | const S = struct { | |
| 266 | fn pair(x: f32, y: f32) std.meta.Tuple(&.{ f32, f32 }) { | |
| 267 | return .{ x, y }; | |
| 268 | } | |
| 269 | ||
| 270 | fn foo(x: anytype) !void { | |
| 271 | try expect(x[0][0] == 1.5); | |
| 272 | try expect(x[0][1] == 2.5); | |
| 273 | } | |
| 274 | }; | |
| 275 | const x = comptime S.pair(1.5, 2.5); | |
| 276 | try S.foo(.{x}); | |
| 277 | } | |
| 278 | ||
| 279 | test "coerce tuple to tuple" { | |
| 280 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 281 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 283 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 284 | ||
| 285 | const T = std.meta.Tuple(&.{u8}); | |
| 286 | const S = struct { | |
| 287 | fn foo(x: T) !void { | |
| 288 | try expect(x[0] == 123); | |
| 289 | } | |
| 290 | }; | |
| 291 | try S.foo(.{123}); | |
| 292 | } |
test/cases/compile_errors/comptime_continue_inside_runtime_catch.zig created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | export fn entry() void { | |
| 2 | const ints = [_]u8{ 1, 2 }; | |
| 3 | inline for (ints) |_| { | |
| 4 | bad() catch continue; | |
| 5 | } | |
| 6 | } | |
| 7 | fn bad() !void { | |
| 8 | return error.Bad; | |
| 9 | } | |
| 10 | ||
| 11 | // error | |
| 12 | // backend=stage2 | |
| 13 | // target=native | |
| 14 | // | |
| 15 | // :4:21: error: comptime control flow inside runtime block | |
| 16 | // :4:15: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_if_bool.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p == 11) continue; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :5:22: error: comptime control flow inside runtime block | |
| 15 | // :5:15: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_if_error.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: anyerror!i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p) |_| continue else |_| {} | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :5:20: error: comptime control flow inside runtime block | |
| 15 | // :5:13: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_if_optional.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: ?i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p) |_| continue; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :5:20: error: comptime control flow inside runtime block | |
| 15 | // :5:13: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_orelse.zig created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | export fn entry() void { | |
| 2 | const ints = [_]u8{ 1, 2 }; | |
| 3 | inline for (ints) |_| { | |
| 4 | bad() orelse continue; | |
| 5 | } | |
| 6 | } | |
| 7 | fn bad() ?void { | |
| 8 | return null; | |
| 9 | } | |
| 10 | ||
| 11 | // error | |
| 12 | // backend=stage2 | |
| 13 | // target=native | |
| 14 | // | |
| 15 | // :4:22: error: comptime control flow inside runtime block | |
| 16 | // :4:15: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_switch.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | switch (p) { | |
| 6 | 11 => continue, | |
| 7 | else => {}, | |
| 8 | } | |
| 9 | q = false; | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :6:19: error: comptime control flow inside runtime block | |
| 18 | // :5:17: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_while_bool.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p == 11) continue :outer; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :5:25: error: comptime control flow inside runtime block | |
| 15 | // :5:18: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_while_error.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: anyerror!usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p) |_| { | |
| 6 | continue :outer; | |
| 7 | } else |_| {} | |
| 8 | q = false; | |
| 9 | } | |
| 10 | } | |
| 11 | ||
| 12 | // error | |
| 13 | // backend=stage2 | |
| 14 | // target=native | |
| 15 | // | |
| 16 | // :6:13: error: comptime control flow inside runtime block | |
| 17 | // :5:16: note: runtime control flow here |
test/cases/compile_errors/comptime_continue_inside_runtime_while_optional.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: ?usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p) |_| continue :outer; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :5:23: error: comptime control flow inside runtime block | |
| 15 | // :5:16: note: runtime control flow here |
test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig created+74| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..3 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..3 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..3 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..3 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..3 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..3 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..3 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage2 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: value in memory does not match slice sentinel | |
| 62 | // :4:29: note: expected '0', found '100' | |
| 63 | // :12:29: error: value in memory does not match slice sentinel | |
| 64 | // :12:29: note: expected '0', found '100' | |
| 65 | // :20:29: error: value in memory does not match slice sentinel | |
| 66 | // :20:29: note: expected '0', found '100' | |
| 67 | // :28:29: error: value in memory does not match slice sentinel | |
| 68 | // :28:29: note: expected '0', found '100' | |
| 69 | // :36:29: error: value in memory does not match slice sentinel | |
| 70 | // :36:29: note: expected '0', found '100' | |
| 71 | // :44:29: error: value in memory does not match slice sentinel | |
| 72 | // :44:29: note: expected '0', found '100' | |
| 73 | // :52:29: error: value in memory does not match slice sentinel | |
| 74 | // :52:29: note: expected '0', found '100' |
test/cases/compile_errors/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig created+74| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..3 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..3 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..3 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..3 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..3 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..3 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..3 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage2 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: value in memory does not match slice sentinel | |
| 62 | // :4:29: note: expected '0', found '100' | |
| 63 | // :12:29: error: value in memory does not match slice sentinel | |
| 64 | // :12:29: note: expected '0', found '100' | |
| 65 | // :20:29: error: value in memory does not match slice sentinel | |
| 66 | // :20:29: note: expected '0', found '100' | |
| 67 | // :28:29: error: value in memory does not match slice sentinel | |
| 68 | // :28:29: note: expected '0', found '100' | |
| 69 | // :36:29: error: value in memory does not match slice sentinel | |
| 70 | // :36:29: note: expected '0', found '100' | |
| 71 | // :44:29: error: value in memory does not match slice sentinel | |
| 72 | // :44:29: note: expected '0', found '100' | |
| 73 | // :52:29: error: value in memory does not match slice sentinel | |
| 74 | // :52:29: note: expected '0', found '100' |
test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig created+74| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..14 :255]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..14 :255]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..14 :255]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..14 :255]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..14 :255]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..14 :255]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..14 :255]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage2 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: value in memory does not match slice sentinel | |
| 62 | // :4:29: note: expected '255', found '0' | |
| 63 | // :12:29: error: value in memory does not match slice sentinel | |
| 64 | // :12:29: note: expected '255', found '0' | |
| 65 | // :20:29: error: value in memory does not match slice sentinel | |
| 66 | // :20:29: note: expected '255', found '0' | |
| 67 | // :28:29: error: value in memory does not match slice sentinel | |
| 68 | // :28:29: note: expected '255', found '0' | |
| 69 | // :36:29: error: value in memory does not match slice sentinel | |
| 70 | // :36:29: note: expected '255', found '0' | |
| 71 | // :44:29: error: value in memory does not match slice sentinel | |
| 72 | // :44:29: note: expected '255', found '0' | |
| 73 | // :52:29: error: value in memory does not match slice sentinel | |
| 74 | // :52:29: note: expected '255', found '0' |
test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_terminated.zig created+67| ... | ... | @@ -0,0 +1,67 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..15 :1]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..15 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..15 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..15 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..15 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..15 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..15 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage2 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 62 | // :12:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 63 | // :20:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 64 | // :28:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 65 | // :36:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 66 | // :44:33: error: slice end index 15 exceeds bounds of containing decl of type '[14:0]u8' | |
| 67 | // :52:33: error: end index 15 out of bounds for slice of length 14 |
test/cases/compile_errors/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig created+67| ... | ... | @@ -0,0 +1,67 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..14 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..14 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..14 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..14 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..14 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..14 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..14 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage2 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 62 | // :12:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 63 | // :20:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 64 | // :28:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 65 | // :36:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 66 | // :44:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' | |
| 67 | // :52:33: error: slice end index 14 exceeds bounds of containing decl of type '[14]u8' |
test/cases/compile_errors/comptime_slice_of_an_undefined_slice.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | comptime { | |
| 2 | var a: []u8 = undefined; | |
| 3 | var b = a[0..10]; | |
| 4 | _ = b; | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :3:14: error: slice of undefined |
test/cases/compile_errors/method_call_with_first_arg_type_wrong_container.zig+3-3| ... | ... | @@ -3,14 +3,14 @@ pub const List = struct { |
| 3 | 3 | allocator: *Allocator, |
| 4 | 4 | |
| 5 | 5 | pub fn init(allocator: *Allocator) List { |
| 6 | return List { | |
| 6 | return List{ | |
| 7 | 7 | .len = 0, |
| 8 | 8 | .allocator = allocator, |
| 9 | 9 | }; |
| 10 | 10 | } |
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | pub var global_allocator = Allocator { | |
| 13 | pub var global_allocator = Allocator{ | |
| 14 | 14 | .field = 1234, |
| 15 | 15 | }; |
| 16 | 16 | |
| ... | ... | @@ -28,4 +28,4 @@ export fn foo() void { |
| 28 | 28 | // target=native |
| 29 | 29 | // |
| 30 | 30 | // :23:6: error: no field or member function named 'init' in 'tmp.List' |
| 31 | // :1:14: note: struct declared here | |
| 31 | // :1:18: note: struct declared here |
test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = true, | |
| 6 | .is_var_args = false, | |
| 7 | .return_type = u0, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :1:13: error: Type.Fn.is_generic must be false for @Type |
test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = false, | |
| 6 | .is_var_args = true, | |
| 7 | .return_type = u0, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :1:13: error: varargs functions must have C calling convention |
test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = false, | |
| 6 | .is_var_args = false, | |
| 7 | .return_type = null, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :1:13: error: Type.Fn.return_type must be non-null for @Type |
test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = bool, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = false, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage2 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // :1:13: error: Type.Enum.tag_type must be an integer type |
test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = undefined, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = false, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage2 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // :1:13: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u1, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = true, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage2 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // :1:13: error: enums must have at least one field |
test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u2, | |
| 5 | .fields = &.{ | |
| 6 | .{ .name = "signed", .value = 0 }, | |
| 7 | .{ .name = "unsigned", .value = 1 }, | |
| 8 | .{ .name = "arst", .value = 2 }, | |
| 9 | }, | |
| 10 | .decls = &.{}, | |
| 11 | .is_exhaustive = true, | |
| 12 | }, | |
| 13 | }); | |
| 14 | const Tagged = @Type(.{ | |
| 15 | .Union = .{ | |
| 16 | .layout = .Auto, | |
| 17 | .tag_type = Tag, | |
| 18 | .fields = &.{ | |
| 19 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | |
| 20 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | |
| 21 | }, | |
| 22 | .decls = &.{}, | |
| 23 | }, | |
| 24 | }); | |
| 25 | export fn entry() void { | |
| 26 | var tagged = Tagged{ .signed = -1 }; | |
| 27 | tagged = .{ .unsigned = 1 }; | |
| 28 | } | |
| 29 | ||
| 30 | // error | |
| 31 | // backend=stage2 | |
| 32 | // target=native | |
| 33 | // | |
| 34 | // :14:16: error: enum field(s) missing in union | |
| 35 | // :1:13: note: field 'arst' missing, declared here | |
| 36 | // :1:13: note: enum declared here |
test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u1, | |
| 5 | .fields = &.{ | |
| 6 | .{ .name = "signed", .value = 0 }, | |
| 7 | .{ .name = "unsigned", .value = 1 }, | |
| 8 | }, | |
| 9 | .decls = &.{}, | |
| 10 | .is_exhaustive = true, | |
| 11 | }, | |
| 12 | }); | |
| 13 | const Tagged = @Type(.{ | |
| 14 | .Union = .{ | |
| 15 | .layout = .Auto, | |
| 16 | .tag_type = Tag, | |
| 17 | .fields = &.{ | |
| 18 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | |
| 19 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | |
| 20 | .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, | |
| 21 | }, | |
| 22 | .decls = &.{}, | |
| 23 | }, | |
| 24 | }); | |
| 25 | export fn entry() void { | |
| 26 | var tagged = Tagged{ .signed = -1 }; | |
| 27 | tagged = .{ .unsigned = 1 }; | |
| 28 | } | |
| 29 | ||
| 30 | // error | |
| 31 | // backend=stage2 | |
| 32 | // target=native | |
| 33 | // | |
| 34 | // :13:16: error: no field named 'arst' in enum 'tmp.Tag__enum_264' | |
| 35 | // :1:13: note: enum declared here |
test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const Untagged = @Type(.{ | |
| 2 | .Union = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = null, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | }, | |
| 8 | }); | |
| 9 | export fn entry() void { | |
| 10 | _ = Untagged{}; | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :1:18: error: unions must have at least one field |
test/cases/compile_errors/reify_type_union_payload_is_undefined.zig created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Struct = undefined, | |
| 3 | }); | |
| 4 | comptime { _ = Foo; } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage2 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :1:13: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/reify_type_with_Type.Int.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | const builtin = @import("std").builtin; | |
| 2 | export fn entry() void { | |
| 3 | _ = @Type(builtin.Type.Int{ | |
| 4 | .signedness = .signed, | |
| 5 | .bits = 8, | |
| 6 | }); | |
| 7 | } | |
| 8 | ||
| 9 | // error | |
| 10 | // backend=stage2 | |
| 11 | // target=native | |
| 12 | // | |
| 13 | // :3:31: error: expected type 'builtin.Type', found 'builtin.Type.Int' | |
| 14 | // :?:?: note: struct declared here | |
| 15 | // :?:?: note: union declared here |
test/cases/compile_errors/reify_type_with_undefined.zig created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | comptime { | |
| 2 | _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); | |
| 3 | } | |
| 4 | comptime { | |
| 5 | _ = @Type(.{ | |
| 6 | .Struct = .{ | |
| 7 | .fields = undefined, | |
| 8 | .decls = undefined, | |
| 9 | .is_tuple = false, | |
| 10 | .layout = .Auto, | |
| 11 | }, | |
| 12 | }); | |
| 13 | } | |
| 14 | ||
| 15 | // error | |
| 16 | // backend=stage2 | |
| 17 | // target=native | |
| 18 | // | |
| 19 | // :2:9: error: use of undefined value here causes undefined behavior | |
| 20 | // :5:9: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_catch.zig deleted-16| ... | ... | @@ -1,16 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | const ints = [_]u8{ 1, 2 }; | |
| 3 | inline for (ints) |_| { | |
| 4 | bad() catch continue; | |
| 5 | } | |
| 6 | } | |
| 7 | fn bad() !void { | |
| 8 | return error.Bad; | |
| 9 | } | |
| 10 | ||
| 11 | // error | |
| 12 | // backend=stage1 | |
| 13 | // target=native | |
| 14 | // | |
| 15 | // tmp.zig:4:21: error: comptime control flow inside runtime block | |
| 16 | // tmp.zig:4:15: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_bool.zig deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p == 11) continue; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:5:22: error: comptime control flow inside runtime block | |
| 15 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_error.zig deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: anyerror!i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p) |_| continue else |_| {} | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:5:20: error: comptime control flow inside runtime block | |
| 15 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_if_optional.zig deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: ?i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | if (p) |_| continue; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:5:20: error: comptime control flow inside runtime block | |
| 15 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_switch.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: i32 = undefined; | |
| 3 | comptime var q = true; | |
| 4 | inline while (q) { | |
| 5 | switch (p) { | |
| 6 | 11 => continue, | |
| 7 | else => {}, | |
| 8 | } | |
| 9 | q = false; | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage1 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // tmp.zig:6:19: error: comptime control flow inside runtime block | |
| 18 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_bool.zig deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p == 11) continue :outer; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:5:25: error: comptime control flow inside runtime block | |
| 15 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_error.zig deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: anyerror!usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p) |_| { | |
| 6 | continue :outer; | |
| 7 | } else |_| {} | |
| 8 | q = false; | |
| 9 | } | |
| 10 | } | |
| 11 | ||
| 12 | // error | |
| 13 | // backend=stage1 | |
| 14 | // target=native | |
| 15 | // | |
| 16 | // tmp.zig:6:13: error: comptime control flow inside runtime block | |
| 17 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_continue_inside_runtime_while_optional.zig deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var p: ?usize = undefined; | |
| 3 | comptime var q = true; | |
| 4 | outer: inline while (q) { | |
| 5 | while (p) |_| continue :outer; | |
| 6 | q = false; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:5:23: error: comptime control flow inside runtime block | |
| 15 | // tmp.zig:5:9: note: runtime block created here |
test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_terminated.zig deleted-67| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..3 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..3 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..3 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..3 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..3 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..3 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..3 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage1 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: slice-sentinel does not match memory at target index | |
| 62 | // :12:29: error: slice-sentinel does not match memory at target index | |
| 63 | // :20:29: error: slice-sentinel does not match memory at target index | |
| 64 | // :28:29: error: slice-sentinel does not match memory at target index | |
| 65 | // :36:29: error: slice-sentinel does not match memory at target index | |
| 66 | // :44:29: error: slice-sentinel does not match memory at target index | |
| 67 | // :52:29: error: slice-sentinel does not match memory at target index |
test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_memory_at_target_index_unterminated.zig deleted-67| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..3 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..3 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..3 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..3 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..3 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..3 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..3 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage1 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: slice-sentinel does not match memory at target index | |
| 62 | // :12:29: error: slice-sentinel does not match memory at target index | |
| 63 | // :20:29: error: slice-sentinel does not match memory at target index | |
| 64 | // :28:29: error: slice-sentinel does not match memory at target index | |
| 65 | // :36:29: error: slice-sentinel does not match memory at target index | |
| 66 | // :44:29: error: slice-sentinel does not match memory at target index | |
| 67 | // :52:29: error: slice-sentinel does not match memory at target index |
test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_does_not_match_target-sentinel.zig deleted-67| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..14 :255]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..14 :255]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..14 :255]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..14 :255]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..14 :255]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..14 :255]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..14 :255]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage1 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: slice-sentinel does not match target-sentinel | |
| 62 | // :12:29: error: slice-sentinel does not match target-sentinel | |
| 63 | // :20:29: error: slice-sentinel does not match target-sentinel | |
| 64 | // :28:29: error: slice-sentinel does not match target-sentinel | |
| 65 | // :36:29: error: slice-sentinel does not match target-sentinel | |
| 66 | // :44:29: error: slice-sentinel does not match target-sentinel | |
| 67 | // :52:29: error: slice-sentinel does not match target-sentinel |
test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_terminated.zig deleted-67| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..15 :1]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..15 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..15 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..15 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..15 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..15 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..15 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage1 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: out of bounds slice | |
| 62 | // :12:29: error: out of bounds slice | |
| 63 | // :20:29: error: out of bounds slice | |
| 64 | // :28:29: error: out of bounds slice | |
| 65 | // :36:29: error: out of bounds slice | |
| 66 | // :44:29: error: out of bounds slice | |
| 67 | // :52:29: error: out of bounds slice |
test/cases/compile_errors/stage1/obj/comptime_slice-sentinel_is_out_of_bounds_unterminated.zig deleted-67| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | export fn foo_array() void { | |
| 2 | comptime { | |
| 3 | var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 4 | const slice = target[0..14 :0]; | |
| 5 | _ = slice; | |
| 6 | } | |
| 7 | } | |
| 8 | export fn foo_ptr_array() void { | |
| 9 | comptime { | |
| 10 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 11 | var target = &buf; | |
| 12 | const slice = target[0..14 :0]; | |
| 13 | _ = slice; | |
| 14 | } | |
| 15 | } | |
| 16 | export fn foo_vector_ConstPtrSpecialBaseArray() void { | |
| 17 | comptime { | |
| 18 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 19 | var target: [*]u8 = &buf; | |
| 20 | const slice = target[0..14 :0]; | |
| 21 | _ = slice; | |
| 22 | } | |
| 23 | } | |
| 24 | export fn foo_vector_ConstPtrSpecialRef() void { | |
| 25 | comptime { | |
| 26 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 27 | var target: [*]u8 = @ptrCast([*]u8, &buf); | |
| 28 | const slice = target[0..14 :0]; | |
| 29 | _ = slice; | |
| 30 | } | |
| 31 | } | |
| 32 | export fn foo_cvector_ConstPtrSpecialBaseArray() void { | |
| 33 | comptime { | |
| 34 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 35 | var target: [*c]u8 = &buf; | |
| 36 | const slice = target[0..14 :0]; | |
| 37 | _ = slice; | |
| 38 | } | |
| 39 | } | |
| 40 | export fn foo_cvector_ConstPtrSpecialRef() void { | |
| 41 | comptime { | |
| 42 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 43 | var target: [*c]u8 = @ptrCast([*c]u8, &buf); | |
| 44 | const slice = target[0..14 :0]; | |
| 45 | _ = slice; | |
| 46 | } | |
| 47 | } | |
| 48 | export fn foo_slice() void { | |
| 49 | comptime { | |
| 50 | var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10; | |
| 51 | var target: []u8 = &buf; | |
| 52 | const slice = target[0..14 :0]; | |
| 53 | _ = slice; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | // error | |
| 58 | // backend=stage1 | |
| 59 | // target=native | |
| 60 | // | |
| 61 | // :4:29: error: slice-sentinel is out of bounds | |
| 62 | // :12:29: error: slice-sentinel is out of bounds | |
| 63 | // :20:29: error: slice-sentinel is out of bounds | |
| 64 | // :28:29: error: slice-sentinel is out of bounds | |
| 65 | // :36:29: error: slice-sentinel is out of bounds | |
| 66 | // :44:29: error: slice-sentinel is out of bounds | |
| 67 | // :52:29: error: slice-sentinel is out of bounds |
test/cases/compile_errors/stage1/obj/comptime_slice_of_an_undefined_slice.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | comptime { | |
| 2 | var a: []u8 = undefined; | |
| 3 | var b = a[0..10]; | |
| 4 | _ = b; | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage1 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // tmp.zig:3:14: error: slice of undefined |
test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_generic_true.zig deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = true, | |
| 6 | .is_var_args = false, | |
| 7 | .return_type = u0, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage1 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // tmp.zig:1:20: error: Type.Fn.is_generic must be false for @Type |
test/cases/compile_errors/stage1/obj/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = false, | |
| 6 | .is_var_args = true, | |
| 7 | .return_type = u0, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage1 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // tmp.zig:1:20: error: varargs functions must have C calling convention |
test/cases/compile_errors/stage1/obj/reify_type.Fn_with_return_type_null.zig deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Fn = .{ | |
| 3 | .calling_convention = .Unspecified, | |
| 4 | .alignment = 0, | |
| 5 | .is_generic = false, | |
| 6 | .is_var_args = false, | |
| 7 | .return_type = null, | |
| 8 | .args = &.{}, | |
| 9 | }, | |
| 10 | }); | |
| 11 | comptime { _ = Foo; } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage1 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // tmp.zig:1:20: error: Type.Fn.return_type must be non-null for @Type |
test/cases/compile_errors/stage1/obj/reify_type.Pointer_with_invalid_address_space.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | _ = @Type(.{ .Pointer = .{ | |
| 3 | .size = .One, | |
| 4 | .is_const = false, | |
| 5 | .is_volatile = false, | |
| 6 | .alignment = 1, | |
| 7 | .address_space = .gs, | |
| 8 | .child = u8, | |
| 9 | .is_allowzero = false, | |
| 10 | .sentinel = null, | |
| 11 | }}); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic |
test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = bool, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = false, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:1:20: error: Type.Enum.tag_type must be an integer type, not 'bool' |
test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = undefined, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = false, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:1:20: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/stage1/obj/reify_type_for_exhaustive_enum_with_zero_fields.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u1, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | .is_exhaustive = true, | |
| 8 | }, | |
| 9 | }); | |
| 10 | export fn entry() void { | |
| 11 | _ = @intToEnum(Tag, 0); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:1:20: error: enums must have 1 or more fields |
test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_enum_field.zig deleted-34| ... | ... | @@ -1,34 +0,0 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u2, | |
| 5 | .fields = &.{ | |
| 6 | .{ .name = "signed", .value = 0 }, | |
| 7 | .{ .name = "unsigned", .value = 1 }, | |
| 8 | .{ .name = "arst", .value = 2 }, | |
| 9 | }, | |
| 10 | .decls = &.{}, | |
| 11 | .is_exhaustive = true, | |
| 12 | }, | |
| 13 | }); | |
| 14 | const Tagged = @Type(.{ | |
| 15 | .Union = .{ | |
| 16 | .layout = .Auto, | |
| 17 | .tag_type = Tag, | |
| 18 | .fields = &.{ | |
| 19 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | |
| 20 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | |
| 21 | }, | |
| 22 | .decls = &.{}, | |
| 23 | }, | |
| 24 | }); | |
| 25 | export fn entry() void { | |
| 26 | var tagged = Tagged{ .signed = -1 }; | |
| 27 | tagged = .{ .unsigned = 1 }; | |
| 28 | } | |
| 29 | ||
| 30 | // error | |
| 31 | // backend=stage1 | |
| 32 | // target=native | |
| 33 | // | |
| 34 | // tmp.zig:14:23: error: enum field missing: 'arst' |
test/cases/compile_errors/stage1/obj/reify_type_for_tagged_union_with_extra_union_field.zig deleted-35| ... | ... | @@ -1,35 +0,0 @@ |
| 1 | const Tag = @Type(.{ | |
| 2 | .Enum = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = u1, | |
| 5 | .fields = &.{ | |
| 6 | .{ .name = "signed", .value = 0 }, | |
| 7 | .{ .name = "unsigned", .value = 1 }, | |
| 8 | }, | |
| 9 | .decls = &.{}, | |
| 10 | .is_exhaustive = true, | |
| 11 | }, | |
| 12 | }); | |
| 13 | const Tagged = @Type(.{ | |
| 14 | .Union = .{ | |
| 15 | .layout = .Auto, | |
| 16 | .tag_type = Tag, | |
| 17 | .fields = &.{ | |
| 18 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | |
| 19 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | |
| 20 | .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, | |
| 21 | }, | |
| 22 | .decls = &.{}, | |
| 23 | }, | |
| 24 | }); | |
| 25 | export fn entry() void { | |
| 26 | var tagged = Tagged{ .signed = -1 }; | |
| 27 | tagged = .{ .unsigned = 1 }; | |
| 28 | } | |
| 29 | ||
| 30 | // error | |
| 31 | // backend=stage1 | |
| 32 | // target=native | |
| 33 | // | |
| 34 | // tmp.zig:13:23: error: enum field not found: 'arst' | |
| 35 | // tmp.zig:1:20: note: enum declared here |
test/cases/compile_errors/stage1/obj/reify_type_for_union_with_zero_fields.zig deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | const Untagged = @Type(.{ | |
| 2 | .Union = .{ | |
| 3 | .layout = .Auto, | |
| 4 | .tag_type = null, | |
| 5 | .fields = &.{}, | |
| 6 | .decls = &.{}, | |
| 7 | }, | |
| 8 | }); | |
| 9 | export fn entry() void { | |
| 10 | _ = Untagged{}; | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage1 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // tmp.zig:1:25: error: unions must have 1 or more fields |
test/cases/compile_errors/stage1/obj/reify_type_union_payload_is_undefined.zig deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | const Foo = @Type(.{ | |
| 2 | .Struct = undefined, | |
| 3 | }); | |
| 4 | comptime { _ = Foo; } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage1 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // tmp.zig:1:20: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/stage1/obj/reify_type_with_Type.Int.zig deleted-13| ... | ... | @@ -1,13 +0,0 @@ |
| 1 | const builtin = @import("std").builtin; | |
| 2 | export fn entry() void { | |
| 3 | _ = @Type(builtin.Type.Int{ | |
| 4 | .signedness = .signed, | |
| 5 | .bits = 8, | |
| 6 | }); | |
| 7 | } | |
| 8 | ||
| 9 | // error | |
| 10 | // backend=stage1 | |
| 11 | // target=native | |
| 12 | // | |
| 13 | // tmp.zig:3:31: error: expected type 'std.builtin.Type', found 'std.builtin.Type.Int' |
test/cases/compile_errors/stage1/obj/reify_type_with_non-constant_expression.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | const builtin = @import("std").builtin; | |
| 2 | var globalTypeInfo : builtin.Type = undefined; | |
| 3 | export fn entry() void { | |
| 4 | _ = @Type(globalTypeInfo); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage1 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // tmp.zig:4:15: error: unable to evaluate constant expression |
test/cases/compile_errors/stage1/obj/reify_type_with_undefined.zig deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | comptime { | |
| 2 | _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); | |
| 3 | } | |
| 4 | comptime { | |
| 5 | _ = @Type(.{ | |
| 6 | .Struct = .{ | |
| 7 | .fields = undefined, | |
| 8 | .decls = undefined, | |
| 9 | .is_tuple = false, | |
| 10 | .layout = .Auto, | |
| 11 | }, | |
| 12 | }); | |
| 13 | } | |
| 14 | ||
| 15 | // error | |
| 16 | // backend=stage1 | |
| 17 | // target=native | |
| 18 | // | |
| 19 | // tmp.zig:2:16: error: use of undefined value here causes undefined behavior | |
| 20 | // tmp.zig:5:16: error: use of undefined value here causes undefined behavior |
test/cases/compile_errors/stage1/reify_type.Pointer_with_invalid_address_space.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | export fn entry() void { | |
| 2 | _ = @Type(.{ .Pointer = .{ | |
| 3 | .size = .One, | |
| 4 | .is_const = false, | |
| 5 | .is_volatile = false, | |
| 6 | .alignment = 1, | |
| 7 | .address_space = .gs, | |
| 8 | .child = u8, | |
| 9 | .is_allowzero = false, | |
| 10 | .sentinel = null, | |
| 11 | }}); | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic |
test/cases/compile_errors/stage1/reify_type_with_non-constant_expression.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | const builtin = @import("std").builtin; | |
| 2 | var globalTypeInfo : builtin.Type = undefined; | |
| 3 | export fn entry() void { | |
| 4 | _ = @Type(globalTypeInfo); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage1 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // tmp.zig:4:15: error: unable to evaluate constant expression |
test/cases/compile_errors/stage1/test/type_mismatch_with_tuple_concatenation.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | var x = .{}; | |
| 3 | x = x ++ .{ 1, 2, 3 }; | |
| 4 | } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage1 | |
| 8 | // target=native | |
| 9 | // is_test=1 | |
| 10 | // | |
| 11 | // tmp.zig:3:11: error: expected type 'struct:2:14', found 'struct:3:11' |
test/cases/compile_errors/tuple_init_edge_cases.zig created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | pub export fn entry1() void { | |
| 2 | const T = @TypeOf(.{ 123, 3 }); | |
| 3 | var b = T{ .@"1" = 3 }; _ = b; | |
| 4 | var c = T{ 123, 3 }; _ = c; | |
| 5 | var d = T{}; _ = d; | |
| 6 | } | |
| 7 | pub export fn entry2() void { | |
| 8 | var a: u32 = 2; | |
| 9 | const T = @TypeOf(.{ 123, a }); | |
| 10 | var b = T{ .@"1" = 3 }; _ = b; | |
| 11 | var c = T{ 123, 3 }; _ = c; | |
| 12 | var d = T{}; _ = d; | |
| 13 | } | |
| 14 | pub export fn entry3() void { | |
| 15 | var a: u32 = 2; | |
| 16 | const T = @TypeOf(.{ 123, a }); | |
| 17 | var b = T{ .@"0" = 123 }; _ = b; | |
| 18 | } | |
| 19 | comptime { | |
| 20 | var a: u32 = 2; | |
| 21 | const T = @TypeOf(.{ 123, a }); | |
| 22 | var b = T{ .@"0" = 123 }; _ = b; | |
| 23 | var c = T{ 123, 2 }; _ = c; | |
| 24 | var d = T{}; _ = d; | |
| 25 | } | |
| 26 | pub export fn entry4() void { | |
| 27 | var a: u32 = 2; | |
| 28 | const T = @TypeOf(.{ 123, a }); | |
| 29 | var b = T{ 123, 4, 5 }; _ = b; | |
| 30 | } | |
| 31 | pub export fn entry5() void { | |
| 32 | var a: u32 = 2; | |
| 33 | const T = @TypeOf(.{ 123, a }); | |
| 34 | var b = T{ .@"0" = 123, .@"2" = 123, .@"1" = 123 }; _ = b; | |
| 35 | } | |
| 36 | ||
| 37 | // error | |
| 38 | // backend=stage2 | |
| 39 | // target=native | |
| 40 | // | |
| 41 | // :12:14: error: missing tuple field with index 1 | |
| 42 | // :17:14: error: missing tuple field with index 1 | |
| 43 | // :29:14: error: expected at most 2 tuple fields; found 3 | |
| 44 | // :34:30: error: index '2' out of bounds of tuple 'tuple{comptime comptime_int = 123, u32}' |
test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | export fn entry() void { | |
| 2 | var x = .{}; | |
| 3 | x = x ++ .{ 1, 2, 3 }; | |
| 4 | } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage2 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :3:11: error: index '0' out of bounds of tuple '@TypeOf(.{})' |
test/cases/compile_errors/wrong_size_to_an_array_literal.zig+1-1| ... | ... | @@ -7,4 +7,4 @@ comptime { |
| 7 | 7 | // backend=stage2 |
| 8 | 8 | // target=native |
| 9 | 9 | // |
| 10 | // :2:31: error: index 2 outside array of length 2 | |
| 10 | // :2:24: error: expected 2 array elements; found 3 |
test/cases/llvm/shift_right_plus_left.0.zig deleted-12| ... | ... | @@ -1,12 +0,0 @@ |
| 1 | pub fn main() void { | |
| 2 | var i: u32 = 16; | |
| 3 | assert(i >> 1, 8); | |
| 4 | } | |
| 5 | fn assert(a: u32, b: u32) void { | |
| 6 | if (a != b) unreachable; | |
| 7 | } | |
| 8 | ||
| 9 | // run | |
| 10 | // backend=llvm | |
| 11 | // target=x86_64-linux,x86_64-macos | |
| 12 | // |
test/cases/llvm/shift_right_plus_left.1.zig deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | pub fn main() void { | |
| 2 | var i: u32 = 16; | |
| 3 | assert(i << 1, 32); | |
| 4 | } | |
| 5 | fn assert(a: u32, b: u32) void { | |
| 6 | if (a != b) unreachable; | |
| 7 | } | |
| 8 | ||
| 9 | // run | |
| 10 | // |
test/run_translated_c.zig+22-22| ... | ... | @@ -1322,28 +1322,28 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1322 | 1322 | \\} |
| 1323 | 1323 | , ""); |
| 1324 | 1324 | |
| 1325 | if (@import("builtin").zig_backend == .stage1) { | |
| 1326 | // https://github.com/ziglang/zig/issues/12264 | |
| 1327 | cases.add("basic vector expressions", | |
| 1328 | \\#include <stdlib.h> | |
| 1329 | \\#include <stdint.h> | |
| 1330 | \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); | |
| 1331 | \\int main(int argc, char**argv) { | |
| 1332 | \\ __v8hi uninitialized; | |
| 1333 | \\ __v8hi empty_init = {}; | |
| 1334 | \\ __v8hi partial_init = {0, 1, 2, 3}; | |
| 1335 | \\ | |
| 1336 | \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; | |
| 1337 | \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; | |
| 1338 | \\ | |
| 1339 | \\ __v8hi sum = a + b; | |
| 1340 | \\ for (int i = 0; i < 8; i++) { | |
| 1341 | \\ if (sum[i] != a[i] + b[i]) abort(); | |
| 1342 | \\ } | |
| 1343 | \\ return 0; | |
| 1344 | \\} | |
| 1345 | , ""); | |
| 1346 | } | |
| 1325 | cases.add("basic vector expressions", | |
| 1326 | \\#include <stdlib.h> | |
| 1327 | \\#include <stdint.h> | |
| 1328 | \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); | |
| 1329 | \\int main(int argc, char**argv) { | |
| 1330 | \\ __v8hi uninitialized; | |
| 1331 | \\ __v8hi empty_init = {}; | |
| 1332 | \\ for (int i = 0; i < 8; i++) { | |
| 1333 | \\ if (empty_init[i] != 0) abort(); | |
| 1334 | \\ } | |
| 1335 | \\ __v8hi partial_init = {0, 1, 2, 3}; | |
| 1336 | \\ | |
| 1337 | \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; | |
| 1338 | \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; | |
| 1339 | \\ | |
| 1340 | \\ __v8hi sum = a + b; | |
| 1341 | \\ for (int i = 0; i < 8; i++) { | |
| 1342 | \\ if (sum[i] != a[i] + b[i]) abort(); | |
| 1343 | \\ } | |
| 1344 | \\ return 0; | |
| 1345 | \\} | |
| 1346 | , ""); | |
| 1347 | 1347 | |
| 1348 | 1348 | cases.add("__builtin_shufflevector", |
| 1349 | 1349 | \\#include <stdlib.h> |
tools/update_cpu_features.zig+1-1| ... | ... | @@ -793,7 +793,7 @@ const llvm_targets = [_]LlvmTarget{ |
| 793 | 793 | .td_name = "Sparc.td", |
| 794 | 794 | }, |
| 795 | 795 | .{ |
| 796 | .zig_name = "systemz", | |
| 796 | .zig_name = "s390x", | |
| 797 | 797 | .llvm_name = "SystemZ", |
| 798 | 798 | .td_name = "SystemZ.td", |
| 799 | 799 | }, |