authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-29 19:59:55-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-29 19:59:55-05:00
logb8473ae7d333ea2750e55e712722d446076e99d9
treefb83bd2e26fb33d7f244abfe03d966b98e9a1b8d
parent648579b33060888316649b0d42cd03dd52ecf589
parentb2b1d421c35ba602ddfadf94190d956de3293c62
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13693 from Vexu/safety

Safety panic improvements & some bug fixes

17 files changed, 280 insertions(+), 101 deletions(-)

doc/langref.html.in+1-1
...@@ -3803,7 +3803,7 @@ test "switch on non-exhaustive enum" {...@@ -3803,7 +3803,7 @@ test "switch on non-exhaustive enum" {
3803 {#link|Accessing the non-active field|Wrong Union Field Access#} is3803 {#link|Accessing the non-active field|Wrong Union Field Access#} is
3804 safety-checked {#link|Undefined Behavior#}:3804 safety-checked {#link|Undefined Behavior#}:
3805 </p>3805 </p>
3806 {#code_begin|test_err|inactive union field#}3806 {#code_begin|test_err|access of union field 'float' while field 'int' is active#}
3807const Payload = union {3807const Payload = union {
3808 int: i64,3808 int: i64,
3809 float: f64,3809 float: f64,
lib/std/builtin.zig+17-3
...@@ -863,10 +863,14 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {...@@ -863,10 +863,14 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
863 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });863 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
864}864}
865865
866pub noinline fn returnError(st: *StackTrace) void {866pub fn panicStartGreaterThanEnd(start: usize, end: usize) noreturn {
867 @setCold(true);867 @setCold(true);
868 @setRuntimeSafety(false);868 std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
869 addErrRetTraceAddr(st, @returnAddress());869}
870
871pub fn panicInactiveUnionField(active: anytype, wanted: @TypeOf(active)) noreturn {
872 @setCold(true);
873 std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{ @tagName(wanted), @tagName(active) });
870}874}
871875
872pub const panic_messages = struct {876pub const panic_messages = struct {
...@@ -887,8 +891,18 @@ pub const panic_messages = struct {...@@ -887,8 +891,18 @@ pub const panic_messages = struct {
887 pub const corrupt_switch = "switch on corrupt value";891 pub const corrupt_switch = "switch on corrupt value";
888 pub const shift_rhs_too_big = "shift amount is greater than the type size";892 pub const shift_rhs_too_big = "shift amount is greater than the type size";
889 pub const invalid_enum_value = "invalid enum value";893 pub const invalid_enum_value = "invalid enum value";
894 pub const sentinel_mismatch = "sentinel mismatch";
895 pub const unwrap_error = "attempt to unwrap error";
896 pub const index_out_of_bounds = "index out of bounds";
897 pub const start_index_greater_than_end = "start index is larger than end index";
890};898};
891899
900pub noinline fn returnError(st: *StackTrace) void {
901 @setCold(true);
902 @setRuntimeSafety(false);
903 addErrRetTraceAddr(st, @returnAddress());
904}
905
892pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {906pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {
893 if (st.index < st.instruction_addresses.len)907 if (st.index < st.instruction_addresses.len)
894 st.instruction_addresses[st.index] = addr;908 st.instruction_addresses[st.index] = addr;
lib/std/zig/parse.zig+15-13
...@@ -950,13 +950,15 @@ const Parser = struct {...@@ -950,13 +950,15 @@ const Parser = struct {
950 /// / LabeledStatement950 /// / LabeledStatement
951 /// / SwitchExpr951 /// / SwitchExpr
952 /// / AssignExpr SEMICOLON952 /// / AssignExpr SEMICOLON
953 fn parseStatement(p: *Parser) Error!Node.Index {953 fn parseStatement(p: *Parser, allow_defer_var: bool) Error!Node.Index {
954 const comptime_token = p.eatToken(.keyword_comptime);954 const comptime_token = p.eatToken(.keyword_comptime);
955955
956 const var_decl = try p.parseVarDecl();956 if (allow_defer_var) {
957 if (var_decl != 0) {957 const var_decl = try p.parseVarDecl();
958 try p.expectSemicolon(.expected_semi_after_decl, true);958 if (var_decl != 0) {
959 return var_decl;959 try p.expectSemicolon(.expected_semi_after_decl, true);
960 return var_decl;
961 }
960 }962 }
961963
962 if (comptime_token) |token| {964 if (comptime_token) |token| {
...@@ -993,7 +995,7 @@ const Parser = struct {...@@ -993,7 +995,7 @@ const Parser = struct {
993 },995 },
994 });996 });
995 },997 },
996 .keyword_defer => return p.addNode(.{998 .keyword_defer => if (allow_defer_var) return p.addNode(.{
997 .tag = .@"defer",999 .tag = .@"defer",
998 .main_token = p.nextToken(),1000 .main_token = p.nextToken(),
999 .data = .{1001 .data = .{
...@@ -1001,7 +1003,7 @@ const Parser = struct {...@@ -1001,7 +1003,7 @@ const Parser = struct {
1001 .rhs = try p.expectBlockExprStatement(),1003 .rhs = try p.expectBlockExprStatement(),
1002 },1004 },
1003 }),1005 }),
1004 .keyword_errdefer => return p.addNode(.{1006 .keyword_errdefer => if (allow_defer_var) return p.addNode(.{
1005 .tag = .@"errdefer",1007 .tag = .@"errdefer",
1006 .main_token = p.nextToken(),1008 .main_token = p.nextToken(),
1007 .data = .{1009 .data = .{
...@@ -1040,8 +1042,8 @@ const Parser = struct {...@@ -1040,8 +1042,8 @@ const Parser = struct {
1040 return null_node;1042 return null_node;
1041 }1043 }
10421044
1043 fn expectStatement(p: *Parser) !Node.Index {1045 fn expectStatement(p: *Parser, allow_defer_var: bool) !Node.Index {
1044 const statement = try p.parseStatement();1046 const statement = try p.parseStatement(allow_defer_var);
1045 if (statement == 0) {1047 if (statement == 0) {
1046 return p.fail(.expected_statement);1048 return p.fail(.expected_statement);
1047 }1049 }
...@@ -1053,7 +1055,7 @@ const Parser = struct {...@@ -1053,7 +1055,7 @@ const Parser = struct {
1053 /// statement, returns 0.1055 /// statement, returns 0.
1054 fn expectStatementRecoverable(p: *Parser) Error!Node.Index {1056 fn expectStatementRecoverable(p: *Parser) Error!Node.Index {
1055 while (true) {1057 while (true) {
1056 return p.expectStatement() catch |err| switch (err) {1058 return p.expectStatement(true) catch |err| switch (err) {
1057 error.OutOfMemory => return error.OutOfMemory,1059 error.OutOfMemory => return error.OutOfMemory,
1058 error.ParseError => {1060 error.ParseError => {
1059 p.findNextStmt(); // Try to skip to the next statement.1061 p.findNextStmt(); // Try to skip to the next statement.
...@@ -1114,7 +1116,7 @@ const Parser = struct {...@@ -1114,7 +1116,7 @@ const Parser = struct {
1114 });1116 });
1115 };1117 };
1116 _ = try p.parsePayload();1118 _ = try p.parsePayload();
1117 const else_expr = try p.expectStatement();1119 const else_expr = try p.expectStatement(false);
1118 return p.addNode(.{1120 return p.addNode(.{
1119 .tag = .@"if",1121 .tag = .@"if",
1120 .main_token = if_token,1122 .main_token = if_token,
...@@ -1226,7 +1228,7 @@ const Parser = struct {...@@ -1226,7 +1228,7 @@ const Parser = struct {
1226 .lhs = array_expr,1228 .lhs = array_expr,
1227 .rhs = try p.addExtra(Node.If{1229 .rhs = try p.addExtra(Node.If{
1228 .then_expr = then_expr,1230 .then_expr = then_expr,
1229 .else_expr = try p.expectStatement(),1231 .else_expr = try p.expectStatement(false),
1230 }),1232 }),
1231 },1233 },
1232 });1234 });
...@@ -1309,7 +1311,7 @@ const Parser = struct {...@@ -1309,7 +1311,7 @@ const Parser = struct {
1309 }1311 }
1310 };1312 };
1311 _ = try p.parsePayload();1313 _ = try p.parsePayload();
1312 const else_expr = try p.expectStatement();1314 const else_expr = try p.expectStatement(false);
1313 return p.addNode(.{1315 return p.addNode(.{
1314 .tag = .@"while",1316 .tag = .@"while",
1315 .main_token = while_token,1317 .main_token = while_token,
lib/std/zig/parser_test.zig+24
...@@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {...@@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {
4233 );4233 );
4234}4234}
42354235
4236test "zig fmt: invalid else branch statement" {
4237 try testError(
4238 \\comptime {
4239 \\ if (true) {} else var a = 0;
4240 \\ if (true) {} else defer {}
4241 \\}
4242 \\comptime {
4243 \\ while (true) {} else var a = 0;
4244 \\ while (true) {} else defer {}
4245 \\}
4246 \\comptime {
4247 \\ for ("") |_| {} else var a = 0;
4248 \\ for ("") |_| {} else defer {}
4249 \\}
4250 , &[_]Error{
4251 .expected_statement,
4252 .expected_statement,
4253 .expected_statement,
4254 .expected_statement,
4255 .expected_statement,
4256 .expected_statement,
4257 });
4258}
4259
4236test "zig fmt: anytype struct field" {4260test "zig fmt: anytype struct field" {
4237 try testError(4261 try testError(
4238 \\pub const Pointer = struct {4262 \\pub const Pointer = struct {
src/AstGen.zig+1
...@@ -5070,6 +5070,7 @@ fn containerDecl(...@@ -5070,6 +5070,7 @@ fn containerDecl(
5070 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len);5070 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len);
5071 astgen.extra.appendSliceAssumeCapacity(decls_slice);5071 astgen.extra.appendSliceAssumeCapacity(decls_slice);
50725072
5073 block_scope.unstack();
5073 try gz.addNamespaceCaptures(&namespace);5074 try gz.addNamespaceCaptures(&namespace);
5074 return rvalue(gz, ri, indexToRef(decl_inst), node);5075 return rvalue(gz, ri, indexToRef(decl_inst), node);
5075 },5076 },
src/Compilation.zig+5
...@@ -101,6 +101,7 @@ debug_compile_errors: bool,...@@ -101,6 +101,7 @@ debug_compile_errors: bool,
101job_queued_compiler_rt_lib: bool = false,101job_queued_compiler_rt_lib: bool = false,
102job_queued_compiler_rt_obj: bool = false,102job_queued_compiler_rt_obj: bool = false,
103alloc_failure_occurred: bool = false,103alloc_failure_occurred: bool = false,
104formatted_panics: bool = false,
104105
105c_source_files: []const CSourceFile,106c_source_files: []const CSourceFile,
106clang_argv: []const []const u8,107clang_argv: []const []const u8,
...@@ -937,6 +938,7 @@ pub const InitOptions = struct {...@@ -937,6 +938,7 @@ pub const InitOptions = struct {
937 use_stage1: ?bool = null,938 use_stage1: ?bool = null,
938 single_threaded: ?bool = null,939 single_threaded: ?bool = null,
939 strip: ?bool = null,940 strip: ?bool = null,
941 formatted_panics: ?bool = null,
940 rdynamic: bool = false,942 rdynamic: bool = false,
941 function_sections: bool = false,943 function_sections: bool = false,
942 no_builtin: bool = false,944 no_builtin: bool = false,
...@@ -1457,6 +1459,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1457,6 +1459,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1457 .Debug => @as(u8, 0),1459 .Debug => @as(u8, 0),
1458 else => @as(u8, 3),1460 else => @as(u8, 3),
1459 };1461 };
1462 const formatted_panics = options.formatted_panics orelse (options.optimize_mode == .Debug);
14601463
1461 // We put everything into the cache hash that *cannot be modified1464 // We put everything into the cache hash that *cannot be modified
1462 // during an incremental update*. For example, one cannot change the1465 // during an incremental update*. For example, one cannot change the
...@@ -1551,6 +1554,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1551,6 +1554,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1551 hash.addOptionalBytes(options.test_name_prefix);1554 hash.addOptionalBytes(options.test_name_prefix);
1552 hash.add(options.skip_linker_dependencies);1555 hash.add(options.skip_linker_dependencies);
1553 hash.add(options.parent_compilation_link_libc);1556 hash.add(options.parent_compilation_link_libc);
1557 hash.add(formatted_panics);
15541558
1555 // In the case of incremental cache mode, this `zig_cache_artifact_directory`1559 // In the case of incremental cache mode, this `zig_cache_artifact_directory`
1556 // is computed based on a hash of non-linker inputs, and it is where all1560 // is computed based on a hash of non-linker inputs, and it is where all
...@@ -1957,6 +1961,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1957,6 +1961,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1957 .owned_link_dir = owned_link_dir,1961 .owned_link_dir = owned_link_dir,
1958 .color = options.color,1962 .color = options.color,
1959 .reference_trace = options.reference_trace,1963 .reference_trace = options.reference_trace,
1964 .formatted_panics = formatted_panics,
1960 .time_report = options.time_report,1965 .time_report = options.time_report,
1961 .stack_report = options.stack_report,1966 .stack_report = options.stack_report,
1962 .unwind_tables = unwind_tables,1967 .unwind_tables = unwind_tables,
src/Sema.zig+108-83
...@@ -667,9 +667,9 @@ pub const Block = struct {...@@ -667,9 +667,9 @@ pub const Block = struct {
667 return result_index;667 return result_index;
668 }668 }
669669
670 fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void {670 fn addUnreachable(block: *Block, safety_check: bool) !void {
671 if (safety_check and block.wantSafety()) {671 if (safety_check and block.wantSafety()) {
672 _ = try block.sema.safetyPanic(block, src, .unreach);672 try block.sema.safetyPanic(block, .unreach);
673 } else {673 } else {
674 _ = try block.addNoOp(.unreach);674 _ = try block.addNoOp(.unreach);
675 }675 }
...@@ -5003,7 +5003,8 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo...@@ -5003,7 +5003,8 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo
5003 if (block.is_comptime or force_comptime) {5003 if (block.is_comptime or force_comptime) {
5004 return sema.fail(block, src, "encountered @panic at comptime", .{});5004 return sema.fail(block, src, "encountered @panic at comptime", .{});
5005 }5005 }
5006 return sema.panicWithMsg(block, src, msg_inst);5006 try sema.panicWithMsg(block, src, msg_inst);
5007 return always_noreturn;
5007}5008}
50085009
5009fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5010fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -5390,7 +5391,8 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -5390,7 +5391,8 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
5390 const container_namespace = container_ty.getNamespace().?;5391 const container_namespace = container_ty.getNamespace().?;
53915392
5392 const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false);5393 const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false);
5393 break :index_blk maybe_index.?; // AstGen would produce error in case of unidentified name5394 break :index_blk maybe_index orelse
5395 return sema.failWithBadMemberAccess(block, container_ty, operand_src, decl_name);
5394 } else try sema.lookupIdentifier(block, operand_src, decl_name);5396 } else try sema.lookupIdentifier(block, operand_src, decl_name);
5395 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {5397 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
5396 error.NeededSourceLocation => {5398 error.NeededSourceLocation => {
...@@ -7962,7 +7964,7 @@ fn analyzeErrUnionPayload(...@@ -7962,7 +7964,7 @@ fn analyzeErrUnionPayload(
7962 if (safety_check and block.wantSafety() and7964 if (safety_check and block.wantSafety() and
7963 !err_union_ty.errorUnionSet().errorSetIsEmpty())7965 !err_union_ty.errorUnionSet().errorSetIsEmpty())
7964 {7966 {
7965 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);7967 try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err);
7966 }7968 }
79677969
7968 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);7970 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
...@@ -8047,7 +8049,7 @@ fn analyzeErrUnionPayloadPtr(...@@ -8047,7 +8049,7 @@ fn analyzeErrUnionPayloadPtr(
8047 if (safety_check and block.wantSafety() and8049 if (safety_check and block.wantSafety() and
8048 !err_union_ty.errorUnionSet().errorSetIsEmpty())8050 !err_union_ty.errorUnionSet().errorSetIsEmpty())
8049 {8051 {
8050 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);8052 try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
8051 }8053 }
80528054
8053 const air_tag: Air.Inst.Tag = if (initializing)8055 const air_tag: Air.Inst.Tag = if (initializing)
...@@ -8709,6 +8711,9 @@ fn analyzeParameter(...@@ -8709,6 +8711,9 @@ fn analyzeParameter(
8709 });8711 });
8710 errdefer msg.destroy(sema.gpa);8712 errdefer msg.destroy(sema.gpa);
87118713
8714 const src_decl = sema.mod.declPtr(block.src_decl);
8715 try sema.explainWhyTypeIsComptime(block, param_src, msg, param_src.toSrcLoc(src_decl), param.ty);
8716
8712 try sema.addDeclaredHereNote(msg, param.ty);8717 try sema.addDeclaredHereNote(msg, param.ty);
8713 break :msg msg;8718 break :msg msg;
8714 };8719 };
...@@ -9539,7 +9544,7 @@ fn zirSwitchCapture(...@@ -9539,7 +9544,7 @@ fn zirSwitchCapture(
9539 .ErrorSet => if (block.switch_else_err_ty) |some| {9544 .ErrorSet => if (block.switch_else_err_ty) |some| {
9540 return sema.bitCast(block, some, operand, operand_src);9545 return sema.bitCast(block, some, operand, operand_src);
9541 } else {9546 } else {
9542 try block.addUnreachable(operand_src, false);9547 try block.addUnreachable(false);
9543 return Air.Inst.Ref.unreachable_value;9548 return Air.Inst.Ref.unreachable_value;
9544 },9549 },
9545 else => return operand,9550 else => return operand,
...@@ -10972,7 +10977,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10972,7 +10977,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10972 // that it is unreachable.10977 // that it is unreachable.
10973 if (case_block.wantSafety()) {10978 if (case_block.wantSafety()) {
10974 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);10979 try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
10975 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);10980 try sema.safetyPanic(&case_block, .corrupt_switch);
10976 } else {10981 } else {
10977 _ = try case_block.addNoOp(.unreach);10982 _ = try case_block.addNoOp(.unreach);
10978 }10983 }
...@@ -11301,6 +11306,11 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op...@@ -11301,6 +11306,11 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
11301 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";11306 const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
11302 const src = inst_data.src();11307 const src = inst_data.src();
1130311308
11309 if (!sema.mod.comp.formatted_panics) {
11310 try sema.safetyPanic(block, .unwrap_error);
11311 return true;
11312 }
11313
11304 const panic_fn = try sema.getBuiltin("panicUnwrapError");11314 const panic_fn = try sema.getBuiltin("panicUnwrapError");
11305 const err_return_trace = try sema.getErrorReturnTrace(block);11315 const err_return_trace = try sema.getErrorReturnTrace(block);
11306 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };11316 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
...@@ -12437,7 +12447,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -12437,7 +12447,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
12437 else12447 else
12438 try sema.resolveInst(.zero);12448 try sema.resolveInst(.zero);
1243912449
12440 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src);12450 return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true);
12441}12451}
1244212452
12443fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12453fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -12460,7 +12470,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -12460,7 +12470,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
12460 else12470 else
12461 try sema.resolveInst(.zero);12471 try sema.resolveInst(.zero);
1246212472
12463 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src);12473 return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true);
12464}12474}
1246512475
12466fn zirArithmetic(12476fn zirArithmetic(
...@@ -12480,7 +12490,7 @@ fn zirArithmetic(...@@ -12480,7 +12490,7 @@ fn zirArithmetic(
12480 const lhs = try sema.resolveInst(extra.lhs);12490 const lhs = try sema.resolveInst(extra.lhs);
12481 const rhs = try sema.resolveInst(extra.rhs);12491 const rhs = try sema.resolveInst(extra.rhs);
1248212492
12483 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src);12493 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, true);
12484}12494}
1248512495
12486fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12496fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -13776,6 +13786,7 @@ fn analyzeArithmetic(...@@ -13776,6 +13786,7 @@ fn analyzeArithmetic(
13776 src: LazySrcLoc,13786 src: LazySrcLoc,
13777 lhs_src: LazySrcLoc,13787 lhs_src: LazySrcLoc,
13778 rhs_src: LazySrcLoc,13788 rhs_src: LazySrcLoc,
13789 want_safety: bool,
13779) CompileError!Air.Inst.Ref {13790) CompileError!Air.Inst.Ref {
13780 const lhs_ty = sema.typeOf(lhs);13791 const lhs_ty = sema.typeOf(lhs);
13781 const rhs_ty = sema.typeOf(rhs);13792 const rhs_ty = sema.typeOf(rhs);
...@@ -14204,7 +14215,7 @@ fn analyzeArithmetic(...@@ -14204,7 +14215,7 @@ fn analyzeArithmetic(
14204 };14215 };
1420514216
14206 try sema.requireRuntimeBlock(block, src, rs.src);14217 try sema.requireRuntimeBlock(block, src, rs.src);
14207 if (block.wantSafety()) {14218 if (block.wantSafety() and want_safety) {
14208 if (scalar_tag == .Int) {14219 if (scalar_tag == .Int) {
14209 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {14220 const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
14210 .add => .add_with_overflow,14221 .add => .add_with_overflow,
...@@ -16509,7 +16520,7 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -16509,7 +16520,7 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
16509 return sema.fail(block, src, "reached unreachable code", .{});16520 return sema.fail(block, src, "reached unreachable code", .{});
16510 }16521 }
16511 // TODO Add compile error for @optimizeFor occurring too late in a scope.16522 // TODO Add compile error for @optimizeFor occurring too late in a scope.
16512 try block.addUnreachable(src, true);16523 try block.addUnreachable(true);
16513 return always_noreturn;16524 return always_noreturn;
16514}16525}
1651516526
...@@ -17603,11 +17614,11 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17603,11 +17614,11 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
17603 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;17614 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
17604 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;17615 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
17605 const ty_src = inst_data.src();17616 const ty_src = inst_data.src();
17606 const field_src = inst_data.src();17617 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
17607 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);17618 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
17608 if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty);17619 if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty);
17609 const field_name = sema.code.nullTerminatedString(extra.name_start);17620 const field_name = sema.code.nullTerminatedString(extra.name_start);
17610 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);17621 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
17611}17622}
1761217623
17613fn fieldType(17624fn fieldType(
...@@ -22119,12 +22130,15 @@ pub const PanicId = enum {...@@ -22119,12 +22130,15 @@ pub const PanicId = enum {
22119 shr_overflow,22130 shr_overflow,
22120 divide_by_zero,22131 divide_by_zero,
22121 exact_division_remainder,22132 exact_division_remainder,
22122 /// TODO make this call `std.builtin.panicInactiveUnionField`.
22123 inactive_union_field,22133 inactive_union_field,
22124 integer_part_out_of_bounds,22134 integer_part_out_of_bounds,
22125 corrupt_switch,22135 corrupt_switch,
22126 shift_rhs_too_big,22136 shift_rhs_too_big,
22127 invalid_enum_value,22137 invalid_enum_value,
22138 sentinel_mismatch,
22139 unwrap_error,
22140 index_out_of_bounds,
22141 start_index_greater_than_end,
22128};22142};
2212922143
22130fn addSafetyCheck(22144fn addSafetyCheck(
...@@ -22149,12 +22163,7 @@ fn addSafetyCheck(...@@ -22149,12 +22163,7 @@ fn addSafetyCheck(
2214922163
22150 defer fail_block.instructions.deinit(gpa);22164 defer fail_block.instructions.deinit(gpa);
2215122165
22152 // This function doesn't actually need a src location but if22166 try sema.safetyPanic(&fail_block, panic_id);
22153 // the panic function interface ever changes passing `.unneeded` here
22154 // will cause confusing panics.
22155 const src = sema.src;
22156 _ = try sema.safetyPanic(&fail_block, src, panic_id);
22157
22158 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22167 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
22159}22168}
2216022169
...@@ -22218,7 +22227,7 @@ fn panicWithMsg(...@@ -22218,7 +22227,7 @@ fn panicWithMsg(
22218 block: *Block,22227 block: *Block,
22219 src: LazySrcLoc,22228 src: LazySrcLoc,
22220 msg_inst: Air.Inst.Ref,22229 msg_inst: Air.Inst.Ref,
22221) !Zir.Inst.Index {22230) !void {
22222 const mod = sema.mod;22231 const mod = sema.mod;
22223 const arena = sema.arena;22232 const arena = sema.arena;
2222422233
...@@ -22229,7 +22238,7 @@ fn panicWithMsg(...@@ -22229,7 +22238,7 @@ fn panicWithMsg(
22229 // TODO implement this feature in all the backends and then delete this branch22238 // TODO implement this feature in all the backends and then delete this branch
22230 _ = try block.addNoOp(.breakpoint);22239 _ = try block.addNoOp(.breakpoint);
22231 _ = try block.addNoOp(.unreach);22240 _ = try block.addNoOp(.unreach);
22232 return always_noreturn;22241 return;
22233 }22242 }
22234 const panic_fn = try sema.getBuiltin("panic");22243 const panic_fn = try sema.getBuiltin("panic");
22235 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");22244 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
...@@ -22245,19 +22254,20 @@ fn panicWithMsg(...@@ -22245,19 +22254,20 @@ fn panicWithMsg(
22245 );22254 );
22246 const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };22255 const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };
22247 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);22256 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
22248 return always_noreturn;
22249}22257}
2225022258
22251fn panicUnwrapError(22259fn panicUnwrapError(
22252 sema: *Sema,22260 sema: *Sema,
22253 parent_block: *Block,22261 parent_block: *Block,
22254 src: LazySrcLoc,
22255 operand: Air.Inst.Ref,22262 operand: Air.Inst.Ref,
22256 unwrap_err_tag: Air.Inst.Tag,22263 unwrap_err_tag: Air.Inst.Tag,
22257 is_non_err_tag: Air.Inst.Tag,22264 is_non_err_tag: Air.Inst.Tag,
22258) !void {22265) !void {
22259 assert(!parent_block.is_comptime);22266 assert(!parent_block.is_comptime);
22260 const ok = try parent_block.addUnOp(is_non_err_tag, operand);22267 const ok = try parent_block.addUnOp(is_non_err_tag, operand);
22268 if (!sema.mod.comp.formatted_panics) {
22269 return sema.addSafetyCheck(parent_block, ok, .unwrap_error);
22270 }
22261 const gpa = sema.gpa;22271 const gpa = sema.gpa;
2226222272
22263 var fail_block: Block = .{22273 var fail_block: Block = .{
...@@ -22286,7 +22296,7 @@ fn panicUnwrapError(...@@ -22286,7 +22296,7 @@ fn panicUnwrapError(
22286 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);22296 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
22287 const err_return_trace = try sema.getErrorReturnTrace(&fail_block);22297 const err_return_trace = try sema.getErrorReturnTrace(&fail_block);
22288 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };22298 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
22289 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);22299 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, &args, null);
22290 }22300 }
22291 }22301 }
22292 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22302 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
...@@ -22295,49 +22305,49 @@ fn panicUnwrapError(...@@ -22295,49 +22305,49 @@ fn panicUnwrapError(
22295fn panicIndexOutOfBounds(22305fn panicIndexOutOfBounds(
22296 sema: *Sema,22306 sema: *Sema,
22297 parent_block: *Block,22307 parent_block: *Block,
22298 src: LazySrcLoc,
22299 index: Air.Inst.Ref,22308 index: Air.Inst.Ref,
22300 len: Air.Inst.Ref,22309 len: Air.Inst.Ref,
22301 cmp_op: Air.Inst.Tag,22310 cmp_op: Air.Inst.Tag,
22302) !void {22311) !void {
22303 assert(!parent_block.is_comptime);22312 assert(!parent_block.is_comptime);
22304 const ok = try parent_block.addBinOp(cmp_op, index, len);22313 const ok = try parent_block.addBinOp(cmp_op, index, len);
22305 const gpa = sema.gpa;22314 if (!sema.mod.comp.formatted_panics) {
2230622315 return sema.addSafetyCheck(parent_block, ok, .index_out_of_bounds);
22307 var fail_block: Block = .{22316 }
22308 .parent = parent_block,22317 try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len });
22309 .sema = sema,22318}
22310 .src_decl = parent_block.src_decl,
22311 .namespace = parent_block.namespace,
22312 .wip_capture_scope = parent_block.wip_capture_scope,
22313 .instructions = .{},
22314 .inlining = parent_block.inlining,
22315 .is_comptime = false,
22316 };
22317
22318 defer fail_block.instructions.deinit(gpa);
2231922319
22320 {22320fn panicStartLargerThanEnd(
22321 const this_feature_is_implemented_in_the_backend =22321 sema: *Sema,
22322 sema.mod.comp.bin_file.options.use_llvm;22322 parent_block: *Block,
22323 start: Air.Inst.Ref,
22324 end: Air.Inst.Ref,
22325) !void {
22326 assert(!parent_block.is_comptime);
22327 const ok = try parent_block.addBinOp(.cmp_lte, start, end);
22328 if (!sema.mod.comp.formatted_panics) {
22329 return sema.addSafetyCheck(parent_block, ok, .start_index_greater_than_end);
22330 }
22331 try sema.safetyCheckFormatted(parent_block, ok, "panicStartGreaterThanEnd", &.{ start, end });
22332}
2232322333
22324 if (!this_feature_is_implemented_in_the_backend) {22334fn panicInactiveUnionField(
22325 // TODO implement this feature in all the backends and then delete this branch22335 sema: *Sema,
22326 _ = try fail_block.addNoOp(.breakpoint);22336 parent_block: *Block,
22327 _ = try fail_block.addNoOp(.unreach);22337 active_tag: Air.Inst.Ref,
22328 } else {22338 wanted_tag: Air.Inst.Ref,
22329 const panic_fn = try sema.getBuiltin("panicOutOfBounds");22339) !void {
22330 const args: [2]Air.Inst.Ref = .{ index, len };22340 assert(!parent_block.is_comptime);
22331 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);22341 const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
22332 }22342 if (!sema.mod.comp.formatted_panics) {
22343 return sema.addSafetyCheck(parent_block, ok, .inactive_union_field);
22333 }22344 }
22334 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22345 try sema.safetyCheckFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag });
22335}22346}
2233622347
22337fn panicSentinelMismatch(22348fn panicSentinelMismatch(
22338 sema: *Sema,22349 sema: *Sema,
22339 parent_block: *Block,22350 parent_block: *Block,
22340 src: LazySrcLoc,
22341 maybe_sentinel: ?Value,22351 maybe_sentinel: ?Value,
22342 sentinel_ty: Type,22352 sentinel_ty: Type,
22343 ptr: Air.Inst.Ref,22353 ptr: Air.Inst.Ref,
...@@ -22371,9 +22381,24 @@ fn panicSentinelMismatch(...@@ -22371,9 +22381,24 @@ fn panicSentinelMismatch(
22371 else {22381 else {
22372 const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");22382 const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");
22373 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };22383 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
22374 _ = try sema.analyzeCall(parent_block, panic_fn, src, src, .auto, false, &args, null);22384 _ = try sema.analyzeCall(parent_block, panic_fn, sema.src, sema.src, .auto, false, &args, null);
22375 return;22385 return;
22376 };22386 };
22387
22388 if (!sema.mod.comp.formatted_panics) {
22389 return sema.addSafetyCheck(parent_block, ok, .sentinel_mismatch);
22390 }
22391 try sema.safetyCheckFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel });
22392}
22393
22394fn safetyCheckFormatted(
22395 sema: *Sema,
22396 parent_block: *Block,
22397 ok: Air.Inst.Ref,
22398 func: []const u8,
22399 args: []const Air.Inst.Ref,
22400) CompileError!void {
22401 assert(sema.mod.comp.formatted_panics);
22377 const gpa = sema.gpa;22402 const gpa = sema.gpa;
2237822403
22379 var fail_block: Block = .{22404 var fail_block: Block = .{
...@@ -22398,9 +22423,8 @@ fn panicSentinelMismatch(...@@ -22398,9 +22423,8 @@ fn panicSentinelMismatch(
22398 _ = try fail_block.addNoOp(.breakpoint);22423 _ = try fail_block.addNoOp(.breakpoint);
22399 _ = try fail_block.addNoOp(.unreach);22424 _ = try fail_block.addNoOp(.unreach);
22400 } else {22425 } else {
22401 const panic_fn = try sema.getBuiltin("panicSentinelMismatch");22426 const panic_fn = try sema.getBuiltin(func);
22402 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };22427 _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
22403 _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
22404 }22428 }
22405 }22429 }
22406 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);22430 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
...@@ -22409,19 +22433,18 @@ fn panicSentinelMismatch(...@@ -22409,19 +22433,18 @@ fn panicSentinelMismatch(
22409fn safetyPanic(22433fn safetyPanic(
22410 sema: *Sema,22434 sema: *Sema,
22411 block: *Block,22435 block: *Block,
22412 src: LazySrcLoc,
22413 panic_id: PanicId,22436 panic_id: PanicId,
22414) CompileError!Zir.Inst.Index {22437) CompileError!void {
22415 const panic_messages_ty = try sema.getBuiltinType("panic_messages");22438 const panic_messages_ty = try sema.getBuiltinType("panic_messages");
22416 const msg_decl_index = (try sema.namespaceLookup(22439 const msg_decl_index = (try sema.namespaceLookup(
22417 block,22440 block,
22418 src,22441 sema.src,
22419 panic_messages_ty.getNamespace().?,22442 panic_messages_ty.getNamespace().?,
22420 @tagName(panic_id),22443 @tagName(panic_id),
22421 )).?;22444 )).?;
2242222445
22423 const msg_inst = try sema.analyzeDeclVal(block, src, msg_decl_index);22446 const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
22424 return sema.panicWithMsg(block, src, msg_inst);22447 try sema.panicWithMsg(block, sema.src, msg_inst);
22425}22448}
2242622449
22427fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {22450fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
...@@ -23423,8 +23446,7 @@ fn unionFieldPtr(...@@ -23423,8 +23446,7 @@ fn unionFieldPtr(
23423 // TODO would it be better if get_union_tag supported pointers to unions?23446 // TODO would it be better if get_union_tag supported pointers to unions?
23424 const union_val = try block.addTyOp(.load, union_ty, union_ptr);23447 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
23425 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);23448 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
23426 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);23449 try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
23427 try sema.addSafetyCheck(block, ok, .inactive_union_field);
23428 }23450 }
23429 if (field.ty.zigTypeTag() == .NoReturn) {23451 if (field.ty.zigTypeTag() == .NoReturn) {
23430 _ = try block.addNoOp(.unreach);23452 _ = try block.addNoOp(.unreach);
...@@ -23495,8 +23517,7 @@ fn unionFieldVal(...@@ -23495,8 +23517,7 @@ fn unionFieldVal(
23495 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);23517 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
23496 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);23518 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
23497 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);23519 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
23498 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);23520 try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
23499 try sema.addSafetyCheck(block, ok, .inactive_union_field);
23500 }23521 }
23501 if (field.ty.zigTypeTag() == .NoReturn) {23522 if (field.ty.zigTypeTag() == .NoReturn) {
23502 _ = try block.addNoOp(.unreach);23523 _ = try block.addNoOp(.unreach);
...@@ -23807,7 +23828,7 @@ fn elemValArray(...@@ -23807,7 +23828,7 @@ fn elemValArray(
23807 if (maybe_index_val == null) {23828 if (maybe_index_val == null) {
23808 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);23829 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
23809 const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt;23830 const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt;
23810 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);23831 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
23811 }23832 }
23812 }23833 }
23813 return block.addBinOp(.array_elem_val, array, elem_index);23834 return block.addBinOp(.array_elem_val, array, elem_index);
...@@ -23868,7 +23889,7 @@ fn elemPtrArray(...@@ -23868,7 +23889,7 @@ fn elemPtrArray(
23868 if (block.wantSafety() and offset == null) {23889 if (block.wantSafety() and offset == null) {
23869 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);23890 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
23870 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;23891 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
23871 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);23892 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
23872 }23893 }
2387323894
23874 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);23895 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
...@@ -23924,7 +23945,7 @@ fn elemValSlice(...@@ -23924,7 +23945,7 @@ fn elemValSlice(
23924 else23945 else
23925 try block.addTyOp(.slice_len, Type.usize, slice);23946 try block.addTyOp(.slice_len, Type.usize, slice);
23926 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;23947 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
23927 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);23948 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
23928 }23949 }
23929 try sema.queueFullTypeResolution(sema.typeOf(slice));23950 try sema.queueFullTypeResolution(sema.typeOf(slice));
23930 return block.addBinOp(.slice_elem_val, slice, elem_index);23951 return block.addBinOp(.slice_elem_val, slice, elem_index);
...@@ -23983,7 +24004,7 @@ fn elemPtrSlice(...@@ -23983,7 +24004,7 @@ fn elemPtrSlice(
23983 break :len try block.addTyOp(.slice_len, Type.usize, slice);24004 break :len try block.addTyOp(.slice_len, Type.usize, slice);
23984 };24005 };
23985 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;24006 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
23986 try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op);24007 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
23987 }24008 }
23988 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);24009 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
23989}24010}
...@@ -28028,7 +28049,11 @@ fn analyzeSlice(...@@ -28028,7 +28049,11 @@ fn analyzeSlice(
28028 }28049 }
28029 }28050 }
2803028051
28031 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);28052 if (block.wantSafety() and !block.is_comptime) {
28053 // requirement: start <= end
28054 try sema.panicStartLargerThanEnd(block, start, end);
28055 }
28056 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
28032 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);28057 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
2803328058
28034 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;28059 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
...@@ -28063,18 +28088,18 @@ fn analyzeSlice(...@@ -28063,18 +28088,18 @@ fn analyzeSlice(
28063 const actual_len = if (slice_ty.sentinel() == null)28088 const actual_len = if (slice_ty.sentinel() == null)
28064 slice_len_inst28089 slice_len_inst
28065 else28090 else
28066 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);28091 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
2806728092
28068 const actual_end = if (slice_sentinel != null)28093 const actual_end = if (slice_sentinel != null)
28069 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)28094 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
28070 else28095 else
28071 end;28096 end;
2807228097
28073 try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte);28098 try sema.panicIndexOutOfBounds(block, actual_end, actual_len, .cmp_lte);
28074 }28099 }
2807528100
28076 // requirement: result[new_len] == slice_sentinel28101 // requirement: result[new_len] == slice_sentinel
28077 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);28102 try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
28078 }28103 }
28079 return result;28104 return result;
28080 };28105 };
...@@ -28131,18 +28156,18 @@ fn analyzeSlice(...@@ -28131,18 +28156,18 @@ fn analyzeSlice(
28131 if (slice_ty.sentinel() == null) break :blk slice_len_inst;28156 if (slice_ty.sentinel() == null) break :blk slice_len_inst;
2813228157
28133 // we have to add one because slice lengths don't include the sentinel28158 // we have to add one because slice lengths don't include the sentinel
28134 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);28159 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
28135 } else null;28160 } else null;
28136 if (opt_len_inst) |len_inst| {28161 if (opt_len_inst) |len_inst| {
28137 const actual_end = if (slice_sentinel != null)28162 const actual_end = if (slice_sentinel != null)
28138 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)28163 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
28139 else28164 else
28140 end;28165 end;
28141 try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);28166 try sema.panicIndexOutOfBounds(block, actual_end, len_inst, .cmp_lte);
28142 }28167 }
2814328168
28144 // requirement: start <= end28169 // requirement: start <= end
28145 try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte);28170 try sema.panicIndexOutOfBounds(block, start, end, .cmp_lte);
28146 }28171 }
28147 const result = try block.addInst(.{28172 const result = try block.addInst(.{
28148 .tag = .slice,28173 .tag = .slice,
...@@ -28156,7 +28181,7 @@ fn analyzeSlice(...@@ -28156,7 +28181,7 @@ fn analyzeSlice(
28156 });28181 });
28157 if (block.wantSafety()) {28182 if (block.wantSafety()) {
28158 // requirement: result[new_len] == slice_sentinel28183 // requirement: result[new_len] == slice_sentinel
28159 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);28184 try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
28160 }28185 }
28161 return result;28186 return result;
28162}28187}
src/codegen/llvm.zig+15
...@@ -9228,6 +9228,21 @@ pub const FuncGen = struct {...@@ -9228,6 +9228,21 @@ pub const FuncGen = struct {
9228 const target = self.dg.module.getTarget();9228 const target = self.dg.module.getTarget();
9229 const layout = union_ty.unionGetLayout(target);9229 const layout = union_ty.unionGetLayout(target);
9230 const union_obj = union_ty.cast(Type.Payload.Union).?.data;9230 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
9231
9232 if (union_obj.layout == .Packed) {
9233 const big_bits = union_ty.bitSize(target);
9234 const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
9235 const field = union_obj.fields.values()[extra.field_index];
9236 const non_int_val = try self.resolveInst(extra.init);
9237 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
9238 const small_int_ty = self.dg.context.intType(ty_bit_size);
9239 const small_int_val = if (field.ty.isPtrAtRuntime())
9240 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
9241 else
9242 self.builder.buildBitCast(non_int_val, small_int_ty, "");
9243 return self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
9244 }
9245
9231 const tag_int = blk: {9246 const tag_int = blk: {
9232 const tag_ty = union_ty.unionTagTypeHypothetical();9247 const tag_ty = union_ty.unionTagTypeHypothetical();
9233 const union_field_name = union_obj.fields.keys()[extra.field_index];9248 const union_field_name = union_obj.fields.keys()[extra.field_index];
src/main.zig+8
...@@ -406,6 +406,8 @@ const usage_build_generic =...@@ -406,6 +406,8 @@ const usage_build_generic =
406 \\ -fno-function-sections All functions go into same section406 \\ -fno-function-sections All functions go into same section
407 \\ -fstrip Omit debug symbols407 \\ -fstrip Omit debug symbols
408 \\ -fno-strip Keep debug symbols408 \\ -fno-strip Keep debug symbols
409 \\ -fformatted-panics Enable formatted safety panics
410 \\ -fno-formatted-panics Disable formatted safety panics
409 \\ -ofmt=[mode] Override target object format411 \\ -ofmt=[mode] Override target object format
410 \\ elf Executable and Linking Format412 \\ elf Executable and Linking Format
411 \\ c C source code413 \\ c C source code
...@@ -632,6 +634,7 @@ fn buildOutputType(...@@ -632,6 +634,7 @@ fn buildOutputType(
632 var have_version = false;634 var have_version = false;
633 var compatibility_version: ?std.builtin.Version = null;635 var compatibility_version: ?std.builtin.Version = null;
634 var strip: ?bool = null;636 var strip: ?bool = null;
637 var formatted_panics: ?bool = null;
635 var function_sections = false;638 var function_sections = false;
636 var no_builtin = false;639 var no_builtin = false;
637 var watch = false;640 var watch = false;
...@@ -1242,6 +1245,10 @@ fn buildOutputType(...@@ -1242,6 +1245,10 @@ fn buildOutputType(
1242 strip = true;1245 strip = true;
1243 } else if (mem.eql(u8, arg, "-fno-strip")) {1246 } else if (mem.eql(u8, arg, "-fno-strip")) {
1244 strip = false;1247 strip = false;
1248 } else if (mem.eql(u8, arg, "-fformatted-panics")) {
1249 formatted_panics = true;
1250 } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {
1251 formatted_panics = false;
1245 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {1252 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
1246 single_threaded = true;1253 single_threaded = true;
1247 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {1254 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
...@@ -2938,6 +2945,7 @@ fn buildOutputType(...@@ -2938,6 +2945,7 @@ fn buildOutputType(
2938 .stack_size_override = stack_size_override,2945 .stack_size_override = stack_size_override,
2939 .image_base_override = image_base_override,2946 .image_base_override = image_base_override,
2940 .strip = strip,2947 .strip = strip,
2948 .formatted_panics = formatted_panics,
2941 .single_threaded = single_threaded,2949 .single_threaded = single_threaded,
2942 .function_sections = function_sections,2950 .function_sections = function_sections,
2943 .no_builtin = no_builtin,2951 .no_builtin = no_builtin,
test/behavior.zig+1
...@@ -116,6 +116,7 @@ test {...@@ -116,6 +116,7 @@ test {
116 _ = @import("behavior/bugs/13171.zig");116 _ = @import("behavior/bugs/13171.zig");
117 _ = @import("behavior/bugs/13285.zig");117 _ = @import("behavior/bugs/13285.zig");
118 _ = @import("behavior/bugs/13435.zig");118 _ = @import("behavior/bugs/13435.zig");
119 _ = @import("behavior/bugs/13664.zig");
119 _ = @import("behavior/byteswap.zig");120 _ = @import("behavior/byteswap.zig");
120 _ = @import("behavior/byval_arg_var.zig");121 _ = @import("behavior/byval_arg_var.zig");
121 _ = @import("behavior/call.zig");122 _ = @import("behavior/call.zig");
test/behavior/basic.zig+11
...@@ -1127,3 +1127,14 @@ test "pointer to zero sized global is mutable" {...@@ -1127,3 +1127,14 @@ test "pointer to zero sized global is mutable" {
1127 };1127 };
1128 try expect(@TypeOf(&S.thing) == *S.Thing);1128 try expect(@TypeOf(&S.thing) == *S.Thing);
1129}1129}
1130
1131test "returning an opaque type from a function" {
1132 const S = struct {
1133 fn foo(comptime a: u32) type {
1134 return opaque {
1135 const b = a;
1136 };
1137 }
1138 };
1139 try expect(S.foo(123).b == 123);
1140}
test/behavior/bugs/13664.zig created+27
...@@ -0,0 +1,27 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4const Fields = packed struct {
5 timestamp: u50,
6 random_bits: u13,
7};
8const ID = packed union {
9 value: u63,
10 fields: Fields,
11};
12fn value() i64 {
13 return 1341;
14}
15test {
16 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20
21 const timestamp: i64 = value();
22 const id = ID{ .fields = Fields{
23 .timestamp = @intCast(u50, timestamp),
24 .random_bits = 420,
25 } };
26 try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);
27}
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig+1
...@@ -21,4 +21,5 @@ pub export fn entry1() void {...@@ -21,4 +21,5 @@ pub export fn entry1() void {
21// target=native21// target=native
22//22//
23// :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime23// :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime
24// :3:6: note: function is generic
24// :10:34: error: parameter of type 'comptime_int' must be declared comptime25// :10:34: error: parameter of type 'comptime_int' must be declared comptime
test/cases/compile_errors/invalid_field_in_struct_value_expression.zig+12
...@@ -12,9 +12,21 @@ export fn f() void {...@@ -12,9 +12,21 @@ export fn f() void {
12 _ = a;12 _ = a;
13}13}
1414
15const Object = struct {
16 field_1: u32,
17 field_2: u32,
18};
19fn dump(_: Object) void {}
20pub export fn entry() void {
21 dump(.{ .field_1 = 123, .field_3 = 456 });
22}
23
24
15// error25// error
16// backend=stage226// backend=stage2
17// target=native27// target=native
18//28//
19// :10:10: error: no field named 'foo' in struct 'tmp.A'29// :10:10: error: no field named 'foo' in struct 'tmp.A'
20// :1:11: note: struct declared here30// :1:11: note: struct declared here
31// :21:30: error: no field named 'field_3' in struct 'tmp.Object'
32// :15:16: note: struct declared here
test/cases/compile_errors/missing_member_in_namespace_export.zig created+10
...@@ -0,0 +1,10 @@
1const S = struct {};
2comptime {
3 @export(S.foo, .{ .name = "foo" });
4}
5
6// error
7// target=native
8//
9// :3:14: error: struct 'tmp.S' has no member named 'foo'
10// :1:11: note: struct declared here
test/cases/safety/bad union field access.zig +1-1
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "access of inactive union field")) {5 if (std.mem.eql(u8, message, "access of union field 'float' while field 'int' is active")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
test/cases/safety/slice start index greater than end index.zig created+23
...@@ -0,0 +1,23 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "start index 10 is larger than end index 1")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var a: usize = 1;
13 var b: usize = 10;
14 var buf: [16]u8 = undefined;
15
16 const slice = buf[b..a];
17 _ = slice;
18 return error.TestFailed;
19}
20
21// run
22// backend=llvm
23// target=native