authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-23 20:09:24-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-23 20:09:24-07:00
loga2ab9e36faded9755ecc1fe809c49140120c3c61
tree25a44861df794d1d633544d1083e67fb52376df4
parent9964324856936ba7ac99985463568079dda6e40f
parentbaf516218e227a55b59c9ae9e6c52b0f9ebd0980
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12143 from Vexu/stage2-safety

Stage2 runtime safety progress

87 files changed, 1412 insertions(+), 468 deletions(-)

lib/compiler_rt/int_to_float_test.zig+1
......@@ -813,6 +813,7 @@ test "conversion to f32" {
813813test "conversion to f80" {
814814 if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64)
815815 return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408
816 if (std.debug.runtime_safety) return error.SkipZigTest;
816817
817818 const intToFloat = @import("./int_to_float.zig").intToFloat;
818819
src/Air.zig+81-16
......@@ -38,11 +38,15 @@ pub const Inst = struct {
3838 /// is the same as both operands.
3939 /// Uses the `bin_op` field.
4040 add,
41 /// Same as `add` with optimized float mode.
42 add_optimized,
4143 /// Integer addition. Wrapping is defined to be twos complement wrapping.
4244 /// Both operands are guaranteed to be the same type, and the result type
4345 /// is the same as both operands.
4446 /// Uses the `bin_op` field.
4547 addwrap,
48 /// Same as `addwrap` with optimized float mode.
49 addwrap_optimized,
4650 /// Saturating integer addition.
4751 /// Both operands are guaranteed to be the same type, and the result type
4852 /// is the same as both operands.
......@@ -53,11 +57,15 @@ pub const Inst = struct {
5357 /// is the same as both operands.
5458 /// Uses the `bin_op` field.
5559 sub,
60 /// Same as `sub` with optimized float mode.
61 sub_optimized,
5662 /// Integer subtraction. Wrapping is defined to be twos complement wrapping.
5763 /// Both operands are guaranteed to be the same type, and the result type
5864 /// is the same as both operands.
5965 /// Uses the `bin_op` field.
6066 subwrap,
67 /// Same as `sub` with optimized float mode.
68 subwrap_optimized,
6169 /// Saturating integer subtraction.
6270 /// Both operands are guaranteed to be the same type, and the result type
6371 /// is the same as both operands.
......@@ -68,11 +76,15 @@ pub const Inst = struct {
6876 /// is the same as both operands.
6977 /// Uses the `bin_op` field.
7078 mul,
79 /// Same as `mul` with optimized float mode.
80 mul_optimized,
7181 /// Integer multiplication. Wrapping is defined to be twos complement wrapping.
7282 /// Both operands are guaranteed to be the same type, and the result type
7383 /// is the same as both operands.
7484 /// Uses the `bin_op` field.
7585 mulwrap,
86 /// Same as `mulwrap` with optimized float mode.
87 mulwrap_optimized,
7688 /// Saturating integer multiplication.
7789 /// Both operands are guaranteed to be the same type, and the result type
7890 /// is the same as both operands.
......@@ -83,32 +95,44 @@ pub const Inst = struct {
8395 /// is the same as both operands.
8496 /// Uses the `bin_op` field.
8597 div_float,
98 /// Same as `div_float` with optimized float mode.
99 div_float_optimized,
86100 /// Truncating integer or float division. For integers, wrapping is undefined behavior.
87101 /// Both operands are guaranteed to be the same type, and the result type
88102 /// is the same as both operands.
89103 /// Uses the `bin_op` field.
90104 div_trunc,
105 /// Same as `div_trunc` with optimized float mode.
106 div_trunc_optimized,
91107 /// Flooring integer or float division. For integers, wrapping is undefined behavior.
92108 /// Both operands are guaranteed to be the same type, and the result type
93109 /// is the same as both operands.
94110 /// Uses the `bin_op` field.
95111 div_floor,
112 /// Same as `div_floor` with optimized float mode.
113 div_floor_optimized,
96114 /// Integer or float division. Guaranteed no remainder.
97115 /// For integers, wrapping is undefined behavior.
98116 /// Both operands are guaranteed to be the same type, and the result type
99117 /// is the same as both operands.
100118 /// Uses the `bin_op` field.
101119 div_exact,
120 /// Same as `div_exact` with optimized float mode.
121 div_exact_optimized,
102122 /// Integer or float remainder division.
103123 /// Both operands are guaranteed to be the same type, and the result type
104124 /// is the same as both operands.
105125 /// Uses the `bin_op` field.
106126 rem,
127 /// Same as `rem` with optimized float mode.
128 rem_optimized,
107129 /// Integer or float modulus division.
108130 /// Both operands are guaranteed to be the same type, and the result type
109131 /// is the same as both operands.
110132 /// Uses the `bin_op` field.
111133 mod,
134 /// Same as `mod` with optimized float mode.
135 mod_optimized,
112136 /// Add an offset to a pointer, returning a new pointer.
113137 /// The offset is in element type units, not bytes.
114138 /// Wrapping is undefined behavior.
......@@ -293,29 +317,45 @@ pub const Inst = struct {
293317 /// LHS of zero.
294318 /// Uses the `un_op` field.
295319 neg,
320 /// Same as `neg` with optimized float mode.
321 neg_optimized,
296322
297323 /// `<`. Result type is always bool.
298324 /// Uses the `bin_op` field.
299325 cmp_lt,
326 /// Same as `cmp_lt` with optimized float mode.
327 cmp_lt_optimized,
300328 /// `<=`. Result type is always bool.
301329 /// Uses the `bin_op` field.
302330 cmp_lte,
331 /// Same as `cmp_lte` with optimized float mode.
332 cmp_lte_optimized,
303333 /// `==`. Result type is always bool.
304334 /// Uses the `bin_op` field.
305335 cmp_eq,
336 /// Same as `cmp_eq` with optimized float mode.
337 cmp_eq_optimized,
306338 /// `>=`. Result type is always bool.
307339 /// Uses the `bin_op` field.
308340 cmp_gte,
341 /// Same as `cmp_gte` with optimized float mode.
342 cmp_gte_optimized,
309343 /// `>`. Result type is always bool.
310344 /// Uses the `bin_op` field.
311345 cmp_gt,
346 /// Same as `cmp_gt` with optimized float mode.
347 cmp_gt_optimized,
312348 /// `!=`. Result type is always bool.
313349 /// Uses the `bin_op` field.
314350 cmp_neq,
351 /// Same as `cmp_neq` with optimized float mode.
352 cmp_neq_optimized,
315353 /// Conditional between two vectors.
316354 /// Result type is always a vector of bools.
317355 /// Uses the `ty_pl` field, payload is `VectorCmp`.
318356 cmp_vector,
357 /// Same as `cmp_vector` with optimized float mode.
358 cmp_vector_optimized,
319359
320360 /// Conditional branch.
321361 /// Result type is always noreturn; no instructions in a block follow this one.
......@@ -553,6 +593,8 @@ pub const Inst = struct {
553593 /// Given a float operand, return the integer with the closest mathematical meaning.
554594 /// Uses the `ty_op` field.
555595 float_to_int,
596 /// Same as `float_to_int` with optimized float mode.
597 float_to_int_optimized,
556598 /// Given an integer operand, return the float with the closest mathematical meaning.
557599 /// Uses the `ty_op` field.
558600 int_to_float,
......@@ -564,6 +606,8 @@ pub const Inst = struct {
564606 /// * min, max, add, mul => integer or float
565607 /// Uses the `reduce` field.
566608 reduce,
609 /// Same as `reduce` with optimized float mode.
610 reduce_optimized,
567611 /// Given an integer, bool, float, or pointer operand, return a vector with all elements
568612 /// equal to the scalar value.
569613 /// Uses the `ty_op` field.
......@@ -676,25 +720,25 @@ pub const Inst = struct {
676720 /// Sets the operand as the current error return trace,
677721 set_err_return_trace,
678722
679 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
680 return switch (op) {
681 .lt => .cmp_lt,
682 .lte => .cmp_lte,
683 .eq => .cmp_eq,
684 .gte => .cmp_gte,
685 .gt => .cmp_gt,
686 .neq => .cmp_neq,
687 };
723 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
724 switch (op) {
725 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
726 .lte => return if (optimized) .cmp_lte_optimized else .cmp_lte,
727 .eq => return if (optimized) .cmp_eq_optimized else .cmp_eq,
728 .gte => return if (optimized) .cmp_gte_optimized else .cmp_gte,
729 .gt => return if (optimized) .cmp_gt_optimized else .cmp_gt,
730 .neq => return if (optimized) .cmp_neq_optimized else .cmp_neq,
731 }
688732 }
689733
690734 pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator {
691735 return switch (tag) {
692 .cmp_lt => .lt,
693 .cmp_lte => .lte,
694 .cmp_eq => .eq,
695 .cmp_gte => .gte,
696 .cmp_gt => .gt,
697 .cmp_neq => .neq,
736 .cmp_lt, .cmp_lt_optimized => .lt,
737 .cmp_lte, .cmp_lte_optimized => .lte,
738 .cmp_eq, .cmp_eq_optimized => .eq,
739 .cmp_gte, .cmp_gte_optimized => .gte,
740 .cmp_gt, .cmp_gt_optimized => .gt,
741 .cmp_neq, .cmp_neq_optimized => .neq,
698742 else => null,
699743 };
700744 }
......@@ -959,6 +1003,18 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
9591003 .max,
9601004 .bool_and,
9611005 .bool_or,
1006 .add_optimized,
1007 .addwrap_optimized,
1008 .sub_optimized,
1009 .subwrap_optimized,
1010 .mul_optimized,
1011 .mulwrap_optimized,
1012 .div_float_optimized,
1013 .div_trunc_optimized,
1014 .div_floor_optimized,
1015 .div_exact_optimized,
1016 .rem_optimized,
1017 .mod_optimized,
9621018 => return air.typeOf(datas[inst].bin_op.lhs),
9631019
9641020 .sqrt,
......@@ -976,6 +1032,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
9761032 .round,
9771033 .trunc_float,
9781034 .neg,
1035 .neg_optimized,
9791036 => return air.typeOf(datas[inst].un_op),
9801037
9811038 .cmp_lt,
......@@ -984,6 +1041,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
9841041 .cmp_gte,
9851042 .cmp_gt,
9861043 .cmp_neq,
1044 .cmp_lt_optimized,
1045 .cmp_lte_optimized,
1046 .cmp_eq_optimized,
1047 .cmp_gte_optimized,
1048 .cmp_gt_optimized,
1049 .cmp_neq_optimized,
9871050 .cmp_lt_errors_len,
9881051 .is_null,
9891052 .is_non_null,
......@@ -1018,6 +1081,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
10181081 .union_init,
10191082 .field_parent_ptr,
10201083 .cmp_vector,
1084 .cmp_vector_optimized,
10211085 .add_with_overflow,
10221086 .sub_with_overflow,
10231087 .mul_with_overflow,
......@@ -1054,6 +1118,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
10541118 .struct_field_ptr_index_3,
10551119 .array_to_slice,
10561120 .float_to_int,
1121 .float_to_int_optimized,
10571122 .int_to_float,
10581123 .splat,
10591124 .get_union_tag,
......@@ -1129,7 +1194,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
11291194 return ptr_ty.elemType();
11301195 },
11311196
1132 .reduce => return air.typeOf(datas[inst].reduce.operand).childType(),
1197 .reduce, .reduce_optimized => return air.typeOf(datas[inst].reduce.operand).childType(),
11331198
11341199 .mul_add => return air.typeOf(datas[inst].pl_op.operand),
11351200 .select => {
src/AstGen.zig+12-7
......@@ -1589,13 +1589,12 @@ fn structInitExpr(
15891589
15901590 switch (rl) {
15911591 .discard => {
1592 // TODO if a type expr is given the fields should be validated for that type
15931592 if (struct_init.ast.type_expr != 0) {
15941593 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15951594 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1596 }
1597 for (struct_init.ast.fields) |field_init| {
1598 _ = try expr(gz, scope, .discard, field_init);
1595 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1596 } else {
1597 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
15991598 }
16001599 return Zir.Inst.Ref.void_value;
16011600 },
......@@ -1729,7 +1728,7 @@ fn structInitExprRlPtrInner(
17291728 for (struct_init.ast.fields) |field_init| {
17301729 const name_token = tree.firstToken(field_init) - 2;
17311730 const str_index = try astgen.identAsString(name_token);
1732 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
1731 const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{
17331732 .lhs = result_ptr,
17341733 .field_name_start = str_index,
17351734 });
......@@ -2287,6 +2286,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22872286 .elem_ptr_imm,
22882287 .elem_val_node,
22892288 .field_ptr,
2289 .field_ptr_init,
22902290 .field_val,
22912291 .field_call_bind,
22922292 .field_ptr_named,
......@@ -4213,6 +4213,12 @@ fn structDeclInner(
42134213 const have_value = member.ast.value_expr != 0;
42144214 const is_comptime = member.comptime_token != null;
42154215
4216 if (is_comptime and layout == .Packed) {
4217 return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{});
4218 } else if (is_comptime and layout == .Extern) {
4219 return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{});
4220 }
4221
42164222 if (!is_comptime) {
42174223 known_non_opv = known_non_opv or
42184224 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
......@@ -6504,8 +6510,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
65046510 },
65056511 .always => {
65066512 // Value is always an error. Emit both error defers and regular defers.
6507 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6508 const err_code = try gz.addUnNode(.err_union_code, result, node);
6513 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
65096514 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
65106515 try gz.addRet(rl, operand, node);
65116516 return Zir.Inst.Ref.unreachable_value;
src/Liveness.zig+44-4
......@@ -173,6 +173,25 @@ pub fn categorizeOperand(
173173 .shr_exact,
174174 .min,
175175 .max,
176 .add_optimized,
177 .addwrap_optimized,
178 .sub_optimized,
179 .subwrap_optimized,
180 .mul_optimized,
181 .mulwrap_optimized,
182 .div_float_optimized,
183 .div_trunc_optimized,
184 .div_floor_optimized,
185 .div_exact_optimized,
186 .rem_optimized,
187 .mod_optimized,
188 .neg_optimized,
189 .cmp_lt_optimized,
190 .cmp_lte_optimized,
191 .cmp_eq_optimized,
192 .cmp_gte_optimized,
193 .cmp_gt_optimized,
194 .cmp_neq_optimized,
176195 => {
177196 const o = air_datas[inst].bin_op;
178197 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
......@@ -239,6 +258,7 @@ pub fn categorizeOperand(
239258 .struct_field_ptr_index_3,
240259 .array_to_slice,
241260 .float_to_int,
261 .float_to_int_optimized,
242262 .int_to_float,
243263 .get_union_tag,
244264 .clz,
......@@ -381,12 +401,12 @@ pub fn categorizeOperand(
381401 if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
382402 return .none;
383403 },
384 .reduce => {
404 .reduce, .reduce_optimized => {
385405 const reduce = air_datas[inst].reduce;
386406 if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
387407 return .none;
388408 },
389 .cmp_vector => {
409 .cmp_vector, .cmp_vector_optimized => {
390410 const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data;
391411 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
392412 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
......@@ -701,29 +721,47 @@ fn analyzeInst(
701721
702722 switch (inst_tags[inst]) {
703723 .add,
724 .add_optimized,
704725 .addwrap,
726 .addwrap_optimized,
705727 .add_sat,
706728 .sub,
729 .sub_optimized,
707730 .subwrap,
731 .subwrap_optimized,
708732 .sub_sat,
709733 .mul,
734 .mul_optimized,
710735 .mulwrap,
736 .mulwrap_optimized,
711737 .mul_sat,
712738 .div_float,
739 .div_float_optimized,
713740 .div_trunc,
741 .div_trunc_optimized,
714742 .div_floor,
743 .div_floor_optimized,
715744 .div_exact,
745 .div_exact_optimized,
716746 .rem,
747 .rem_optimized,
717748 .mod,
749 .mod_optimized,
718750 .bit_and,
719751 .bit_or,
720752 .xor,
721753 .cmp_lt,
754 .cmp_lt_optimized,
722755 .cmp_lte,
756 .cmp_lte_optimized,
723757 .cmp_eq,
758 .cmp_eq_optimized,
724759 .cmp_gte,
760 .cmp_gte_optimized,
725761 .cmp_gt,
762 .cmp_gt_optimized,
726763 .cmp_neq,
764 .cmp_neq_optimized,
727765 .bool_and,
728766 .bool_or,
729767 .store,
......@@ -794,6 +832,7 @@ fn analyzeInst(
794832 .struct_field_ptr_index_3,
795833 .array_to_slice,
796834 .float_to_int,
835 .float_to_int_optimized,
797836 .int_to_float,
798837 .get_union_tag,
799838 .clz,
......@@ -836,6 +875,7 @@ fn analyzeInst(
836875 .round,
837876 .trunc_float,
838877 .neg,
878 .neg_optimized,
839879 .cmp_lt_errors_len,
840880 .set_err_return_trace,
841881 => {
......@@ -903,11 +943,11 @@ fn analyzeInst(
903943 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;
904944 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
905945 },
906 .reduce => {
946 .reduce, .reduce_optimized => {
907947 const reduce = inst_datas[inst].reduce;
908948 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
909949 },
910 .cmp_vector => {
950 .cmp_vector, .cmp_vector_optimized => {
911951 const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data;
912952 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
913953 },
src/Module.zig+69-1
......@@ -787,7 +787,7 @@ pub const Decl = struct {
787787 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data;
788788 return &opaque_obj.namespace;
789789 },
790 .@"union", .union_tagged => {
790 .@"union", .union_safety_tagged, .union_tagged => {
791791 const union_obj = ty.cast(Type.Payload.Union).?.data;
792792 return &union_obj.namespace;
793793 },
......@@ -2704,6 +2704,18 @@ pub const SrcLoc = struct {
27042704 else => unreachable,
27052705 }
27062706 },
2707 .node_offset_field_default => |node_off| {
2708 const tree = try src_loc.file_scope.getTree(gpa);
2709 const node_tags = tree.nodes.items(.tag);
2710 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
2711
2712 const full: Ast.full.ContainerField = switch (node_tags[parent_node]) {
2713 .container_field => tree.containerField(parent_node),
2714 .container_field_init => tree.containerFieldInit(parent_node),
2715 else => unreachable,
2716 };
2717 return nodeToSpan(tree, full.ast.value_expr);
2718 },
27072719 }
27082720 }
27092721
......@@ -3021,6 +3033,9 @@ pub const LazySrcLoc = union(enum) {
30213033 /// The source location points to the tag type of an union or an enum.
30223034 /// The Decl is determined contextually.
30233035 node_offset_container_tag: i32,
3036 /// The source location points to the default value of a field.
3037 /// The Decl is determined contextually.
3038 node_offset_field_default: i32,
30243039
30253040 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
30263041
......@@ -3098,6 +3113,7 @@ pub const LazySrcLoc = union(enum) {
30983113 .node_offset_ptr_bitoffset,
30993114 .node_offset_ptr_hostsize,
31003115 .node_offset_container_tag,
3116 .node_offset_field_default,
31013117 => .{
31023118 .file_scope = decl.getFileScope(),
31033119 .parent_decl_node = decl.src_node,
......@@ -5936,6 +5952,58 @@ pub fn argSrc(
59365952 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i]));
59375953}
59385954
5955pub fn initSrc(
5956 init_node_offset: i32,
5957 gpa: Allocator,
5958 decl: *Decl,
5959 init_index: usize,
5960) LazySrcLoc {
5961 @setCold(true);
5962 const tree = decl.getFileScope().getTree(gpa) catch |err| {
5963 // In this case we emit a warning + a less precise source location.
5964 log.warn("unable to load {s}: {s}", .{
5965 decl.getFileScope().sub_file_path, @errorName(err),
5966 });
5967 return LazySrcLoc.nodeOffset(0);
5968 };
5969 const node_tags = tree.nodes.items(.tag);
5970 const node = decl.relativeToNodeIndex(init_node_offset);
5971 var buf: [2]Ast.Node.Index = undefined;
5972 const full = switch (node_tags[node]) {
5973 .array_init_one, .array_init_one_comma => tree.arrayInitOne(buf[0..1], node).ast.elements,
5974 .array_init_dot_two, .array_init_dot_two_comma => tree.arrayInitDotTwo(&buf, node).ast.elements,
5975 .array_init_dot, .array_init_dot_comma => tree.arrayInitDot(node).ast.elements,
5976 .array_init, .array_init_comma => tree.arrayInit(node).ast.elements,
5977
5978 .struct_init_one, .struct_init_one_comma => tree.structInitOne(buf[0..1], node).ast.fields,
5979 .struct_init_dot_two, .struct_init_dot_two_comma => tree.structInitDotTwo(&buf, node).ast.fields,
5980 .struct_init_dot, .struct_init_dot_comma => tree.structInitDot(node).ast.fields,
5981 .struct_init, .struct_init_comma => tree.structInit(node).ast.fields,
5982 else => unreachable,
5983 };
5984 switch (node_tags[node]) {
5985 .array_init_one,
5986 .array_init_one_comma,
5987 .array_init_dot_two,
5988 .array_init_dot_two_comma,
5989 .array_init_dot,
5990 .array_init_dot_comma,
5991 .array_init,
5992 .array_init_comma,
5993 => return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full[init_index])),
5994 .struct_init_one,
5995 .struct_init_one_comma,
5996 .struct_init_dot_two,
5997 .struct_init_dot_two_comma,
5998 .struct_init_dot,
5999 .struct_init_dot_comma,
6000 .struct_init,
6001 .struct_init_comma,
6002 => return LazySrcLoc{ .node_offset_initializer = decl.nodeIndexToRelative(full[init_index]) },
6003 else => unreachable,
6004 }
6005}
6006
59396007/// Called from `performAllTheWork`, after all AstGen workers have finished,
59406008/// and before the main semantic analysis loop begins.
59416009pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+470-179
......@@ -144,6 +144,9 @@ pub const Block = struct {
144144 /// when null, it is determined by build mode, changed by @setRuntimeSafety
145145 want_safety: ?bool = null,
146146
147 /// What mode to generate float operations in, set by @setFloatMode
148 float_mode: std.builtin.FloatMode = .Strict,
149
147150 c_import_buf: ?*std.ArrayList(u8) = null,
148151
149152 /// type of `err` in `else => |err|`
......@@ -206,6 +209,7 @@ pub const Block = struct {
206209 .runtime_loop = parent.runtime_loop,
207210 .runtime_index = parent.runtime_index,
208211 .want_safety = parent.want_safety,
212 .float_mode = parent.float_mode,
209213 .c_import_buf = parent.c_import_buf,
210214 .switch_else_err_ty = parent.switch_else_err_ty,
211215 };
......@@ -414,7 +418,7 @@ pub const Block = struct {
414418
415419 fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator, vector_ty: Air.Inst.Ref) !Air.Inst.Ref {
416420 return block.addInst(.{
417 .tag = .cmp_vector,
421 .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
418422 .data = .{ .ty_pl = .{
419423 .ty = vector_ty,
420424 .payload = try block.sema.addExtra(Air.VectorCmp{
......@@ -714,10 +718,10 @@ fn analyzeBodyInner(
714718 .closure_get => try sema.zirClosureGet(block, inst),
715719 .cmp_lt => try sema.zirCmp(block, inst, .lt),
716720 .cmp_lte => try sema.zirCmp(block, inst, .lte),
717 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq),
721 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
718722 .cmp_gte => try sema.zirCmp(block, inst, .gte),
719723 .cmp_gt => try sema.zirCmp(block, inst, .gt),
720 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, .cmp_neq),
724 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),
721725 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
722726 .decl_ref => try sema.zirDeclRef(block, inst),
723727 .decl_val => try sema.zirDeclVal(block, inst),
......@@ -739,7 +743,8 @@ fn analyzeBodyInner(
739743 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
740744 .error_union_type => try sema.zirErrorUnionType(block, inst),
741745 .error_value => try sema.zirErrorValue(block, inst),
742 .field_ptr => try sema.zirFieldPtr(block, inst),
746 .field_ptr => try sema.zirFieldPtr(block, inst, false),
747 .field_ptr_init => try sema.zirFieldPtr(block, inst, true),
743748 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
744749 .field_val => try sema.zirFieldVal(block, inst),
745750 .field_val_named => try sema.zirFieldValNamed(block, inst),
......@@ -1547,11 +1552,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
15471552 const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));
15481553
15491554 // st.instruction_addresses = &addrs;
1550 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src);
1555 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true);
15511556 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
15521557
15531558 // st.index = 0;
1554 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src);
1559 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);
15551560 const zero = try sema.addConstant(Type.usize, Value.zero);
15561561 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store);
15571562
......@@ -1784,6 +1789,24 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
17841789 });
17851790}
17861791
1792fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError {
1793 const msg = msg: {
1794 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
1795 errdefer msg.destroy(sema.gpa);
1796
1797 const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg;
1798
1799 const tree = try sema.getAstTree(block);
1800 const decl = sema.mod.declPtr(decl_index);
1801 const field_src = enumFieldSrcLoc(decl, tree.*, container_ty.getNodeOffset(), field_index);
1802 const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x };
1803
1804 try sema.errNote(block, default_value_src, msg, "default value set here", .{});
1805 break :msg msg;
1806 };
1807 return sema.failWithOwnedErrorMsg(block, msg);
1808}
1809
17871810/// We don't return a pointer to the new error note because the pointer
17881811/// becomes invalid when you add another one.
17891812fn errNote(
......@@ -2614,7 +2637,14 @@ fn zirUnionDecl(
26142637 const new_decl_arena_allocator = new_decl_arena.allocator();
26152638
26162639 const union_obj = try new_decl_arena_allocator.create(Module.Union);
2617 const type_tag: Type.Tag = if (small.has_tag_type or small.auto_enum_tag) .union_tagged else .@"union";
2640 const type_tag = if (small.has_tag_type or small.auto_enum_tag)
2641 Type.Tag.union_tagged
2642 else if (small.layout != .Auto)
2643 Type.Tag.@"union"
2644 else switch (block.sema.mod.optimizeMode()) {
2645 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
2646 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
2647 };
26182648 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
26192649 union_payload.* = .{
26202650 .base = .{ .tag = type_tag },
......@@ -3651,7 +3681,10 @@ fn validateStructInit(
36513681 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
36523682 struct_ptr_zir_ref = field_ptr_extra.lhs;
36533683 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
3654 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
3684 const field_index = if (struct_ty.isTuple())
3685 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
3686 else
3687 try sema.structFieldIndex(block, struct_ty, field_name, field_src);
36553688 if (found_fields[field_index] != 0) {
36563689 const other_field_ptr = found_fields[field_index];
36573690 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
......@@ -3693,7 +3726,7 @@ fn validateStructInit(
36933726 }
36943727
36953728 const field_src = init_src; // TODO better source location
3696 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty);
3729 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
36973730 const field_ty = sema.typeOf(default_field_ptr).childType();
36983731 const init = try sema.addConstant(field_ty, default_val);
36993732 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
......@@ -3851,7 +3884,7 @@ fn validateStructInit(
38513884 if (field_ptr != 0) continue;
38523885
38533886 const field_src = init_src; // TODO better source location
3854 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty);
3887 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
38553888 const field_ty = sema.typeOf(default_field_ptr).childType();
38563889 const init = try sema.addConstant(field_ty, field_values[i]);
38573890 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
......@@ -4694,6 +4727,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
46944727 .inlining = parent_block.inlining,
46954728 .is_comptime = parent_block.is_comptime,
46964729 .want_safety = parent_block.want_safety,
4730 .float_mode = parent_block.float_mode,
46974731 };
46984732
46994733 defer child_block.instructions.deinit(gpa);
......@@ -5031,13 +5065,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
50315065fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
50325066 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
50335067 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
5034 const float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known");
5035 switch (float_mode) {
5036 .Strict => return,
5037 .Optimized => {
5038 // TODO implement optimized float mode
5039 },
5040 }
5068 block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known");
50415069}
50425070
50435071fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
......@@ -6786,12 +6814,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
67866814 .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
67876815 );
67886816 errdefer msg.destroy(sema.gpa);
6789 try sema.mod.errNoteNonLazy(
6790 dest_ty.declSrcLoc(sema.mod),
6791 msg,
6792 "enum declared here",
6793 .{},
6794 );
6817 try sema.addDeclaredHereNote(msg, dest_ty);
67956818 break :msg msg;
67966819 };
67976820 return sema.failWithOwnedErrorMsg(block, msg);
......@@ -7923,7 +7946,7 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
79237946 return sema.fieldVal(block, src, object, field_name, field_name_src);
79247947}
79257948
7926fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
7949fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref {
79277950 const tracy = trace(@src());
79287951 defer tracy.end();
79297952
......@@ -7933,7 +7956,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
79337956 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
79347957 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
79357958 const object_ptr = try sema.resolveInst(extra.lhs);
7936 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
7959 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
79377960}
79387961
79397962fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -7972,7 +7995,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
79727995 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
79737996 const object_ptr = try sema.resolveInst(extra.lhs);
79747997 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
7975 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
7998 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
79767999}
79778000
79788001fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
......@@ -8081,7 +8104,7 @@ fn intCast(
80818104 const ok = if (is_vector) ok: {
80828105 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
80838106 const all_in_range = try block.addInst(.{
8084 .tag = .reduce,
8107 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
80858108 .data = .{ .reduce = .{
80868109 .operand = is_in_range,
80878110 .operation = .And,
......@@ -8092,12 +8115,13 @@ fn intCast(
80928115 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
80938116 break :ok is_in_range;
80948117 };
8118 // TODO negative_to_unsigned?
80958119 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
80968120 } else {
80978121 const ok = if (is_vector) ok: {
80988122 const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
80998123 const all_in_range = try block.addInst(.{
8100 .tag = .reduce,
8124 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
81018125 .data = .{ .reduce = .{
81028126 .operand = is_in_range,
81038127 .operation = .And,
......@@ -8116,9 +8140,9 @@ fn intCast(
81168140 const ok = if (is_vector) ok: {
81178141 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
81188142 const zero_inst = try sema.addConstant(operand_ty, zero_val);
8119 const is_in_range = try block.addCmpVector(operand, zero_inst, .lte, try sema.addType(operand_ty));
8143 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty));
81208144 const all_in_range = try block.addInst(.{
8121 .tag = .reduce,
8145 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
81228146 .data = .{ .reduce = .{
81238147 .operand = is_in_range,
81248148 .operation = .And,
......@@ -8130,7 +8154,7 @@ fn intCast(
81308154 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
81318155 break :ok is_in_range;
81328156 };
8133 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
8157 try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
81348158 }
81358159 }
81368160 return block.addTyOp(.intcast, dest_ty, operand);
......@@ -9379,7 +9403,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
93799403 } else {
93809404 for (items) |item_ref| {
93819405 const item = try sema.resolveInst(item_ref);
9382 const cmp_ok = try case_block.addBinOp(.cmp_eq, operand, item);
9406 const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
93839407 if (any_ok != .none) {
93849408 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
93859409 } else {
......@@ -9399,12 +9423,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
93999423
94009424 // operand >= first and operand <= last
94019425 const range_first_ok = try case_block.addBinOp(
9402 .cmp_gte,
9426 if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte,
94039427 operand,
94049428 item_first,
94059429 );
94069430 const range_last_ok = try case_block.addBinOp(
9407 .cmp_lte,
9431 if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte,
94089432 operand,
94099433 item_last,
94109434 );
......@@ -9996,40 +10020,34 @@ fn zirShl(
999610020 } else rhs;
999710021
999810022 try sema.requireRuntimeBlock(block, src, runtime_src);
9999 if (block.wantSafety()) {
10000 const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
10001 .shl_exact => .shl_with_overflow,
10002 else => null,
10003 };
10004 if (maybe_op_ov) |op_ov_tag| {
10005 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10006 const op_ov = try block.addInst(.{
10007 .tag = op_ov_tag,
10008 .data = .{ .ty_pl = .{
10009 .ty = try sema.addType(op_ov_tuple_ty),
10010 .payload = try sema.addExtra(Air.Bin{
10011 .lhs = lhs,
10012 .rhs = rhs,
10013 }),
10023 if (block.wantSafety() and air_tag == .shl_exact) {
10024 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10025 const op_ov = try block.addInst(.{
10026 .tag = .shl_with_overflow,
10027 .data = .{ .ty_pl = .{
10028 .ty = try sema.addType(op_ov_tuple_ty),
10029 .payload = try sema.addExtra(Air.Bin{
10030 .lhs = lhs,
10031 .rhs = rhs,
10032 }),
10033 } },
10034 });
10035 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10036 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10037 try block.addInst(.{
10038 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10039 .data = .{ .reduce = .{
10040 .operand = ov_bit,
10041 .operation = .Or,
1001410042 } },
10015 });
10016 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10017 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10018 try block.addInst(.{
10019 .tag = .reduce,
10020 .data = .{ .reduce = .{
10021 .operand = ov_bit,
10022 .operation = .Or,
10023 } },
10024 })
10025 else
10026 ov_bit;
10027 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10028 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
10043 })
10044 else
10045 ov_bit;
10046 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10047 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
1002910048
10030 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10031 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10032 }
10049 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10050 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
1003310051 }
1003410052 return block.addBinOp(air_tag, lhs, new_rhs);
1003510053}
......@@ -10107,7 +10125,23 @@ fn zirShr(
1010710125 } else rhs_src;
1010810126
1010910127 try sema.requireRuntimeBlock(block, src, runtime_src);
10110 return block.addBinOp(air_tag, lhs, rhs);
10128 const result = try block.addBinOp(air_tag, lhs, rhs);
10129 if (block.wantSafety() and air_tag == .shr_exact) {
10130 const back = try block.addBinOp(.shl, result, rhs);
10131
10132 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10133 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
10134 break :ok try block.addInst(.{
10135 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10136 .data = .{ .reduce = .{
10137 .operand = eql,
10138 .operation = .And,
10139 } },
10140 });
10141 } else try block.addBinOp(.cmp_eq, lhs, back);
10142 try sema.addSafetyCheck(block, ok, .shr_overflow);
10143 }
10144 return result;
1011110145}
1011210146
1011310147fn zirBitwise(
......@@ -10697,7 +10731,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1069710731 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
1069810732 }
1069910733 try sema.requireRuntimeBlock(block, src, null);
10700 return block.addUnOp(.neg, rhs);
10734 return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs);
1070110735 }
1070210736
1070310737 const lhs = if (rhs_ty.zigTypeTag() == .Vector)
......@@ -11056,6 +11090,7 @@ fn analyzeArithmetic(
1105611090 return casted_lhs;
1105711091 }
1105811092 }
11093 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
1105911094 if (maybe_lhs_val) |lhs_val| {
1106011095 if (lhs_val.isUndef()) {
1106111096 if (is_int) {
......@@ -11078,8 +11113,8 @@ fn analyzeArithmetic(
1107811113 try sema.floatAdd(lhs_val, rhs_val, resolved_type),
1107911114 );
1108011115 }
11081 } else break :rs .{ .src = rhs_src, .air_tag = .add };
11082 } else break :rs .{ .src = lhs_src, .air_tag = .add };
11116 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11117 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1108311118 },
1108411119 .addwrap => {
1108511120 // Integers only; floats are checked above.
......@@ -11090,6 +11125,7 @@ fn analyzeArithmetic(
1109011125 return casted_rhs;
1109111126 }
1109211127 }
11128 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
1109311129 if (maybe_rhs_val) |rhs_val| {
1109411130 if (rhs_val.isUndef()) {
1109511131 return sema.addConstUndef(resolved_type);
......@@ -11102,8 +11138,8 @@ fn analyzeArithmetic(
1110211138 resolved_type,
1110311139 try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),
1110411140 );
11105 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
11106 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
11141 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11142 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
1110711143 },
1110811144 .add_sat => {
1110911145 // Integers only; floats are checked above.
......@@ -11151,6 +11187,7 @@ fn analyzeArithmetic(
1115111187 return casted_lhs;
1115211188 }
1115311189 }
11190 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
1115411191 if (maybe_lhs_val) |lhs_val| {
1115511192 if (lhs_val.isUndef()) {
1115611193 if (is_int) {
......@@ -11173,8 +11210,8 @@ fn analyzeArithmetic(
1117311210 try sema.floatSub(lhs_val, rhs_val, resolved_type),
1117411211 );
1117511212 }
11176 } else break :rs .{ .src = rhs_src, .air_tag = .sub };
11177 } else break :rs .{ .src = lhs_src, .air_tag = .sub };
11213 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11214 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1117811215 },
1117911216 .subwrap => {
1118011217 // Integers only; floats are checked above.
......@@ -11188,6 +11225,7 @@ fn analyzeArithmetic(
1118811225 return casted_lhs;
1118911226 }
1119011227 }
11228 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
1119111229 if (maybe_lhs_val) |lhs_val| {
1119211230 if (lhs_val.isUndef()) {
1119311231 return sema.addConstUndef(resolved_type);
......@@ -11197,8 +11235,8 @@ fn analyzeArithmetic(
1119711235 resolved_type,
1119811236 try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),
1119911237 );
11200 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
11201 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
11238 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11239 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1120211240 },
1120311241 .sub_sat => {
1120411242 // Integers only; floats are checked above.
......@@ -11305,14 +11343,14 @@ fn analyzeArithmetic(
1130511343 if (is_int) {
1130611344 break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
1130711345 } else {
11308 break :rs .{ .src = rhs_src, .air_tag = .div_float };
11346 break :rs .{ .src = rhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float };
1130911347 }
1131011348 }
1131111349 } else {
1131211350 if (is_int) {
1131311351 break :rs .{ .src = lhs_src, .air_tag = .div_trunc };
1131411352 } else {
11315 break :rs .{ .src = lhs_src, .air_tag = .div_float };
11353 break :rs .{ .src = lhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float };
1131611354 }
1131711355 }
1131811356 },
......@@ -11351,6 +11389,7 @@ fn analyzeArithmetic(
1135111389 return sema.failWithDivideByZero(block, rhs_src);
1135211390 }
1135311391 }
11392 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_trunc_optimized else .div_trunc;
1135411393 if (maybe_lhs_val) |lhs_val| {
1135511394 if (lhs_val.isUndef()) {
1135611395 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
......@@ -11376,8 +11415,8 @@ fn analyzeArithmetic(
1137611415 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
1137711416 );
1137811417 }
11379 } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
11380 } else break :rs .{ .src = lhs_src, .air_tag = .div_trunc };
11418 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11419 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1138111420 },
1138211421 .div_floor => {
1138311422 // For integers:
......@@ -11414,6 +11453,7 @@ fn analyzeArithmetic(
1141411453 return sema.failWithDivideByZero(block, rhs_src);
1141511454 }
1141611455 }
11456 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_floor_optimized else .div_floor;
1141711457 if (maybe_lhs_val) |lhs_val| {
1141811458 if (lhs_val.isUndef()) {
1141911459 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
......@@ -11439,8 +11479,8 @@ fn analyzeArithmetic(
1143911479 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
1144011480 );
1144111481 }
11442 } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };
11443 } else break :rs .{ .src = lhs_src, .air_tag = .div_floor };
11482 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11483 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1144411484 },
1144511485 .div_exact => {
1144611486 // For integers:
......@@ -11476,6 +11516,7 @@ fn analyzeArithmetic(
1147611516 return sema.failWithDivideByZero(block, rhs_src);
1147711517 }
1147811518 }
11519 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_exact_optimized else .div_exact;
1147911520 if (maybe_lhs_val) |lhs_val| {
1148011521 if (maybe_rhs_val) |rhs_val| {
1148111522 if (is_int) {
......@@ -11491,8 +11532,8 @@ fn analyzeArithmetic(
1149111532 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
1149211533 );
1149311534 }
11494 } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };
11495 } else break :rs .{ .src = lhs_src, .air_tag = .div_exact };
11535 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11536 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1149611537 },
1149711538 .mul => {
1149811539 // For integers:
......@@ -11513,6 +11554,7 @@ fn analyzeArithmetic(
1151311554 }
1151411555 }
1151511556 }
11557 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
1151611558 if (maybe_rhs_val) |rhs_val| {
1151711559 if (rhs_val.isUndef()) {
1151811560 if (is_int) {
......@@ -11548,8 +11590,8 @@ fn analyzeArithmetic(
1154811590 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
1154911591 );
1155011592 }
11551 } else break :rs .{ .src = lhs_src, .air_tag = .mul };
11552 } else break :rs .{ .src = rhs_src, .air_tag = .mul };
11593 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11594 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
1155311595 },
1155411596 .mulwrap => {
1155511597 // Integers only; floats are handled above.
......@@ -11566,6 +11608,7 @@ fn analyzeArithmetic(
1156611608 }
1156711609 }
1156811610 }
11611 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
1156911612 if (maybe_rhs_val) |rhs_val| {
1157011613 if (rhs_val.isUndef()) {
1157111614 return sema.addConstUndef(resolved_type);
......@@ -11584,8 +11627,8 @@ fn analyzeArithmetic(
1158411627 resolved_type,
1158511628 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
1158611629 );
11587 } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };
11588 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
11630 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11631 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
1158911632 },
1159011633 .mul_sat => {
1159111634 // Integers only; floats are checked above.
......@@ -11755,6 +11798,7 @@ fn analyzeArithmetic(
1175511798 return sema.failWithDivideByZero(block, rhs_src);
1175611799 }
1175711800 }
11801 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .rem_optimized else .rem;
1175811802 if (maybe_lhs_val) |lhs_val| {
1175911803 if (lhs_val.isUndef()) {
1176011804 return sema.addConstUndef(resolved_type);
......@@ -11764,8 +11808,8 @@ fn analyzeArithmetic(
1176411808 resolved_type,
1176511809 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
1176611810 );
11767 } else break :rs .{ .src = rhs_src, .air_tag = .rem };
11768 } else break :rs .{ .src = lhs_src, .air_tag = .rem };
11811 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11812 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1176911813 },
1177011814 .mod => {
1177111815 // For integers:
......@@ -11812,6 +11856,7 @@ fn analyzeArithmetic(
1181211856 return sema.failWithDivideByZero(block, rhs_src);
1181311857 }
1181411858 }
11859 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mod_optimized else .mod;
1181511860 if (maybe_lhs_val) |lhs_val| {
1181611861 if (lhs_val.isUndef()) {
1181711862 return sema.addConstUndef(resolved_type);
......@@ -11821,8 +11866,8 @@ fn analyzeArithmetic(
1182111866 resolved_type,
1182211867 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
1182311868 );
11824 } else break :rs .{ .src = rhs_src, .air_tag = .mod };
11825 } else break :rs .{ .src = lhs_src, .air_tag = .mod };
11869 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11870 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
1182611871 },
1182711872 else => unreachable,
1182811873 }
......@@ -11852,7 +11897,7 @@ fn analyzeArithmetic(
1185211897 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
1185311898 const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)
1185411899 try block.addInst(.{
11855 .tag = .reduce,
11900 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
1185611901 .data = .{ .reduce = .{
1185711902 .operand = ov_bit,
1185811903 .operation = .Or,
......@@ -11867,6 +11912,96 @@ fn analyzeArithmetic(
1186711912 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
1186811913 }
1186911914 }
11915 switch (rs.air_tag) {
11916 // zig fmt: off
11917 .div_float, .div_exact, .div_trunc, .div_floor, .div_float_optimized,
11918 .div_exact_optimized, .div_trunc_optimized, .div_floor_optimized
11919 // zig fmt: on
11920 => if (scalar_tag == .Int or block.float_mode == .Optimized) {
11921 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
11922 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11923 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11924 const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type));
11925 break :ok try block.addInst(.{
11926 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
11927 .data = .{ .reduce = .{
11928 .operand = ok,
11929 .operation = .And,
11930 } },
11931 });
11932 } else ok: {
11933 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11934 break :ok try block.addBinOp(if (block.float_mode == .Optimized) .cmp_neq_optimized else .cmp_neq, casted_rhs, zero);
11935 };
11936 try sema.addSafetyCheck(block, ok, .divide_by_zero);
11937 },
11938 .rem, .mod, .rem_optimized, .mod_optimized => {
11939 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
11940 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11941 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11942 const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type));
11943 break :ok try block.addInst(.{
11944 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
11945 .data = .{ .reduce = .{
11946 .operand = ok,
11947 .operation = .And,
11948 } },
11949 });
11950 } else ok: {
11951 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11952 const air_tag = if (scalar_tag == .Int)
11953 Air.Inst.Tag.cmp_gt
11954 else if (block.float_mode == .Optimized)
11955 Air.Inst.Tag.cmp_neq_optimized
11956 else
11957 Air.Inst.Tag.cmp_neq;
11958 break :ok try block.addBinOp(air_tag, casted_rhs, zero);
11959 };
11960 try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative);
11961 },
11962 else => {},
11963 }
11964 if (rs.air_tag == .div_exact or rs.air_tag == .div_exact_optimized) {
11965 const result = try block.addBinOp(.div_exact, casted_lhs, casted_rhs);
11966 const ok = if (scalar_tag == .Float) ok: {
11967 const floored = try block.addUnOp(.floor, result);
11968
11969 if (resolved_type.zigTypeTag() == .Vector) {
11970 const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type));
11971 break :ok try block.addInst(.{
11972 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
11973 .data = .{ .reduce = .{
11974 .operand = eql,
11975 .operation = .And,
11976 } },
11977 });
11978 } else {
11979 const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, result, floored);
11980 break :ok is_in_range;
11981 }
11982 } else ok: {
11983 const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs);
11984
11985 if (resolved_type.zigTypeTag() == .Vector) {
11986 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11987 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11988 const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type));
11989 break :ok try block.addInst(.{
11990 .tag = .reduce,
11991 .data = .{ .reduce = .{
11992 .operand = eql,
11993 .operation = .And,
11994 } },
11995 });
11996 } else {
11997 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11998 const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, remainder, zero);
11999 break :ok is_in_range;
12000 }
12001 };
12002 try sema.addSafetyCheck(block, ok, .exact_division_remainder);
12003 return result;
12004 }
1187012005 }
1187112006 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
1187212007}
......@@ -12374,7 +12509,7 @@ fn cmpSelf(
1237412509 const result_ty_ref = try sema.addType(result_ty);
1237512510 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
1237612511 }
12377 const tag = Air.Inst.Tag.fromCmpOp(op);
12512 const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
1237812513 return block.addBinOp(tag, casted_lhs, casted_rhs);
1237912514}
1238012515
......@@ -14387,6 +14522,7 @@ fn zirStructInit(
1438714522 var field_i: u32 = 0;
1438814523 var extra_index = extra.end;
1438914524
14525 const is_packed = resolved_ty.containerLayout() == .Packed;
1439014526 while (field_i < extra.data.fields_len) : (field_i += 1) {
1439114527 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
1439214528 extra_index = item.end;
......@@ -14395,7 +14531,10 @@ fn zirStructInit(
1439514531 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
1439614532 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1439714533 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
14398 const field_index = try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
14534 const field_index = if (resolved_ty.isTuple())
14535 try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
14536 else
14537 try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
1439914538 if (field_inits[field_index] != .none) {
1440014539 const other_field_type = found_fields[field_index];
1440114540 const other_field_type_data = zir_datas[other_field_type].pl_node;
......@@ -14410,6 +14549,15 @@ fn zirStructInit(
1441014549 }
1441114550 found_fields[field_index] = item.data.field_type;
1441214551 field_inits[field_index] = try sema.resolveInst(item.data.init);
14552 if (!is_packed) if (resolved_ty.structFieldValueComptime(field_index)) |default_value| {
14553 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, field_inits[field_index])) orelse {
14554 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known");
14555 };
14556
14557 if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) {
14558 return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
14559 }
14560 };
1441314561 }
1441414562
1441514563 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
......@@ -14445,7 +14593,7 @@ fn zirStructInit(
1444514593 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
1444614594 });
1444714595 const alloc = try block.addTy(.alloc, alloc_ty);
14448 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty);
14596 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
1444914597 try sema.storePtr(block, src, field_ptr, init_inst);
1445014598 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
1445114599 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
......@@ -14550,7 +14698,7 @@ fn finishStructInit(
1455014698 for (field_inits) |field_init, i_usize| {
1455114699 const i = @intCast(u32, i_usize);
1455214700 const field_src = dest_src;
14553 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty);
14701 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true);
1455414702 try sema.storePtr(block, dest_src, field_ptr, field_init);
1455514703 }
1455614704
......@@ -14573,22 +14721,41 @@ fn zirStructInitAnon(
1457314721 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
1457414722 const types = try sema.arena.alloc(Type, extra.data.fields_len);
1457514723 const values = try sema.arena.alloc(Value, types.len);
14576 const names = try sema.arena.alloc([]const u8, types.len);
14724 var fields = std.StringArrayHashMapUnmanaged(u32){};
14725 defer fields.deinit(sema.gpa);
14726 try fields.ensureUnusedCapacity(sema.gpa, types.len);
1457714727
14578 const opt_runtime_src = rs: {
14579 var runtime_src: ?LazySrcLoc = null;
14728 const opt_runtime_index = rs: {
14729 var runtime_index: ?usize = null;
1458014730 var extra_index = extra.end;
1458114731 for (types) |*field_ty, i| {
14582 const init_src = src; // TODO better source location
1458314732 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
1458414733 extra_index = item.end;
1458514734
14586 names[i] = sema.code.nullTerminatedString(item.data.field_name);
14735 const name = sema.code.nullTerminatedString(item.data.field_name);
14736 const gop = fields.getOrPutAssumeCapacity(name);
14737 if (gop.found_existing) {
14738 const msg = msg: {
14739 const decl = sema.mod.declPtr(block.src_decl);
14740 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
14741 const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
14742 errdefer msg.destroy(sema.gpa);
14743
14744 const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*);
14745 try sema.errNote(block, prev_source, msg, "other field here", .{});
14746 break :msg msg;
14747 };
14748 return sema.failWithOwnedErrorMsg(block, msg);
14749 }
14750 gop.value_ptr.* = @intCast(u32, i);
14751
1458714752 const init = try sema.resolveInst(item.data.init);
1458814753 field_ty.* = sema.typeOf(init);
1458914754 if (types[i].zigTypeTag() == .Opaque) {
1459014755 const msg = msg: {
14591 const msg = try sema.errMsg(block, init_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
14756 const decl = sema.mod.declPtr(block.src_decl);
14757 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
14758 const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
1459214759 errdefer msg.destroy(sema.gpa);
1459314760
1459414761 try sema.addDeclaredHereNote(msg, types[i]);
......@@ -14596,28 +14763,37 @@ fn zirStructInitAnon(
1459614763 };
1459714764 return sema.failWithOwnedErrorMsg(block, msg);
1459814765 }
14766 const init_src = src; // TODO better source location
1459914767 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
1460014768 values[i] = init_val;
1460114769 } else {
1460214770 values[i] = Value.initTag(.unreachable_value);
14603 runtime_src = init_src;
14771 runtime_index = i;
1460414772 }
1460514773 }
14606 break :rs runtime_src;
14774 break :rs runtime_index;
1460714775 };
1460814776
1460914777 const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{
14610 .names = names,
14778 .names = try sema.arena.dupe([]const u8, fields.keys()),
1461114779 .types = types,
1461214780 .values = values,
1461314781 });
1461414782
14615 const runtime_src = opt_runtime_src orelse {
14783 const runtime_index = opt_runtime_index orelse {
1461614784 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
1461714785 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
1461814786 };
1461914787
14620 try sema.requireRuntimeBlock(block, src, runtime_src);
14788 sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) {
14789 error.NeededSourceLocation => {
14790 const decl = sema.mod.declPtr(block.src_decl);
14791 const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index);
14792 try sema.requireRuntimeBlock(block, src, field_src);
14793 return error.AnalysisFail;
14794 },
14795 else => |e| return e,
14796 };
1462114797
1462214798 if (is_ref) {
1462314799 const target = sema.mod.getTarget();
......@@ -15513,13 +15689,21 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1551315689 if (decls_val.sliceLen(mod) > 0) {
1551415690 return sema.fail(block, src, "reified unions must have no decls", .{});
1551515691 }
15692 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
1551615693
1551715694 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
1551815695 errdefer new_decl_arena.deinit();
1551915696 const new_decl_arena_allocator = new_decl_arena.allocator();
1552015697
1552115698 const union_obj = try new_decl_arena_allocator.create(Module.Union);
15522 const type_tag: Type.Tag = if (!tag_type_val.isNull()) .union_tagged else .@"union";
15699 const type_tag = if (!tag_type_val.isNull())
15700 Type.Tag.union_tagged
15701 else if (layout != .Auto)
15702 Type.Tag.@"union"
15703 else switch (block.sema.mod.optimizeMode()) {
15704 .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
15705 .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
15706 };
1552315707 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
1552415708 union_payload.* = .{
1552515709 .base = .{ .tag = type_tag },
......@@ -15540,7 +15724,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1554015724 .fields = .{},
1554115725 .node_offset = src.node_offset.x,
1554215726 .zir_index = inst,
15543 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),
15727 .layout = layout,
1554415728 .status = .have_field_types,
1554515729 .namespace = .{
1554615730 .parent = block.namespace,
......@@ -15550,11 +15734,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1555015734 };
1555115735
1555215736 // Tag type
15737 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
1555315738 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
15554 union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: {
15739 if (tag_type_val.optionalValue()) |payload_val| {
1555515740 var buffer: Value.ToTypeBuffer = undefined;
15556 break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
15557 } else try sema.generateUnionTagTypeSimple(block, fields_len, null);
15741 union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
15742 } else {
15743 union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null);
15744 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
15745 }
1555815746
1555915747 // Fields
1556015748 if (fields_len > 0) {
......@@ -15578,6 +15766,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1557815766 sema.mod,
1557915767 );
1558015768
15769 if (enum_field_names) |set| {
15770 set.putAssumeCapacity(field_name, {});
15771 }
15772
1558115773 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
1558215774 if (gop.found_existing) {
1558315775 // TODO: better source location
......@@ -15823,7 +16015,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1582316015 }
1582416016
1582516017 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
15826 return block.addTyOp(.float_to_int, dest_ty, operand);
16018 const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
16019 if (block.wantSafety()) {
16020 const back = try block.addTyOp(.int_to_float, operand_ty, result);
16021 const diff = try block.addBinOp(.sub, operand, back);
16022 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one));
16023 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one));
16024 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
16025 try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
16026 }
16027 return result;
1582716028}
1582816029
1582916030fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -16154,8 +16355,6 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1615416355 // TODO compile error if the result pointer is comptime known and would have an
1615516356 // alignment that disagrees with the Decl's alignment.
1615616357
16157 // TODO insert safety check that the alignment is correct
16158
1615916358 const ptr_info = ptr_ty.ptrInfo().data;
1616016359 const dest_ty = try Type.ptr(sema.arena, sema.mod, .{
1616116360 .pointee_type = ptr_info.pointee_type,
......@@ -16166,6 +16365,41 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1616616365 .@"volatile" = ptr_info.@"volatile",
1616716366 .size = ptr_info.size,
1616816367 });
16368
16369 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
16370 if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| {
16371 if (addr % dest_align != 0) {
16372 return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
16373 }
16374 }
16375 return sema.addConstant(dest_ty, val);
16376 }
16377
16378 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
16379 if (block.wantSafety() and dest_align > 1) {
16380 const val_payload = try sema.arena.create(Value.Payload.U64);
16381 val_payload.* = .{
16382 .base = .{ .tag = .int_u64 },
16383 .data = dest_align - 1,
16384 };
16385 const align_minus_1 = try sema.addConstant(
16386 Type.usize,
16387 Value.initPayload(&val_payload.base),
16388 );
16389 const actual_ptr = if (ptr_ty.isSlice())
16390 try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
16391 else
16392 ptr;
16393 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
16394 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
16395 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
16396 const ok = if (ptr_ty.isSlice()) ok: {
16397 const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
16398 const len_zero = try block.addBinOp(.cmp_eq, len, try sema.addConstant(Type.usize, Value.zero));
16399 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
16400 } else is_aligned;
16401 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
16402 }
1616916403 return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src);
1617016404}
1617116405
......@@ -17026,7 +17260,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1702617260
1702717261 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
1702817262 return block.addInst(.{
17029 .tag = .reduce,
17263 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
1703017264 .data = .{ .reduce = .{
1703117265 .operand = operand,
1703217266 .operation = operation,
......@@ -18800,8 +19034,16 @@ pub const PanicId = enum {
1880019034 incorrect_alignment,
1880119035 invalid_error_code,
1880219036 cast_truncated_data,
19037 negative_to_unsigned,
1880319038 integer_overflow,
1880419039 shl_overflow,
19040 shr_overflow,
19041 divide_by_zero,
19042 remainder_division_zero_negative,
19043 exact_division_remainder,
19044 /// TODO make this call `std.builtin.panicInactiveUnionField`.
19045 inactive_union_field,
19046 integer_part_out_of_bounds,
1880519047};
1880619048
1880719049fn addSafetyCheck(
......@@ -19017,8 +19259,15 @@ fn safetyPanic(
1901719259 .incorrect_alignment => "incorrect alignment",
1901819260 .invalid_error_code => "invalid error code",
1901919261 .cast_truncated_data => "integer cast truncated bits",
19262 .negative_to_unsigned => "attempt to cast negative value to unsigned integer",
1902019263 .integer_overflow => "integer overflow",
1902119264 .shl_overflow => "left shift overflowed bits",
19265 .shr_overflow => "right shift overflowed bits",
19266 .divide_by_zero => "division by zero",
19267 .remainder_division_zero_negative => "remainder division by zero or negative value",
19268 .exact_division_remainder => "exact division produced remainder",
19269 .inactive_union_field => "access of inactive union field",
19270 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
1902219271 };
1902319272
1902419273 const msg_inst = msg_inst: {
......@@ -19206,16 +19455,7 @@ fn fieldVal(
1920619455 return inst;
1920719456 }
1920819457 }
19209 // TODO add note: declared here
19210 const kw_name = switch (child_type.zigTypeTag()) {
19211 .Struct => "struct",
19212 .Opaque => "opaque",
19213 .Union => "union",
19214 else => unreachable,
19215 };
19216 return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{
19217 kw_name, child_type.fmt(sema.mod), field_name,
19218 });
19458 return sema.failWithBadMemberAccess(block, child_type, src, field_name);
1921919459 },
1922019460 else => {
1922119461 const msg = msg: {
......@@ -19231,14 +19471,14 @@ fn fieldVal(
1923119471 },
1923219472 .Struct => if (is_pointer_to) {
1923319473 // Avoid loading the entire struct by fetching a pointer and loading that
19234 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
19474 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
1923519475 return sema.analyzeLoad(block, src, field_ptr, object_src);
1923619476 } else {
1923719477 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);
1923819478 },
1923919479 .Union => if (is_pointer_to) {
1924019480 // Avoid loading the entire union by fetching a pointer and loading that
19241 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
19481 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
1924219482 return sema.analyzeLoad(block, src, field_ptr, object_src);
1924319483 } else {
1924419484 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);
......@@ -19255,6 +19495,7 @@ fn fieldPtr(
1925519495 object_ptr: Air.Inst.Ref,
1925619496 field_name: []const u8,
1925719497 field_name_src: LazySrcLoc,
19498 initializing: bool,
1925819499) CompileError!Air.Inst.Ref {
1925919500 // When editing this function, note that there is corresponding logic to be edited
1926019501 // in `fieldVal`. This function takes a pointer and returns a pointer.
......@@ -19439,14 +19680,14 @@ fn fieldPtr(
1943919680 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
1944019681 else
1944119682 object_ptr;
19442 return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
19683 return sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
1944319684 },
1944419685 .Union => {
1944519686 const inner_ptr = if (is_pointer_to)
1944619687 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
1944719688 else
1944819689 object_ptr;
19449 return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
19690 return sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
1945019691 },
1945119692 else => {},
1945219693 }
......@@ -19556,7 +19797,13 @@ fn fieldCallBind(
1955619797 else => {},
1955719798 }
1955819799
19559 return sema.fail(block, src, "type '{}' has no field or member function named '{s}'", .{ concrete_ty.fmt(sema.mod), field_name });
19800 const msg = msg: {
19801 const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) });
19802 errdefer msg.destroy(sema.gpa);
19803 try sema.addDeclaredHereNote(msg, concrete_ty);
19804 break :msg msg;
19805 };
19806 return sema.failWithOwnedErrorMsg(block, msg);
1956019807}
1956119808
1956219809fn finishFieldCallBind(
......@@ -19648,6 +19895,7 @@ fn structFieldPtr(
1964819895 field_name: []const u8,
1964919896 field_name_src: LazySrcLoc,
1965019897 unresolved_struct_ty: Type,
19898 initializing: bool,
1965119899) CompileError!Air.Inst.Ref {
1965219900 assert(unresolved_struct_ty.zigTypeTag() == .Struct);
1965319901
......@@ -19660,10 +19908,10 @@ fn structFieldPtr(
1966019908 return sema.analyzeRef(block, src, len_inst);
1966119909 }
1966219910 const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
19663 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index);
19911 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
1966419912 } else if (struct_ty.isAnonStruct()) {
1966519913 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
19666 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index);
19914 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
1966719915 }
1966819916
1966919917 const struct_obj = struct_ty.castTag(.@"struct").?.data;
......@@ -19672,7 +19920,7 @@ fn structFieldPtr(
1967219920 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
1967319921 const field_index = @intCast(u32, field_index_big);
1967419922
19675 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty);
19923 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
1967619924}
1967719925
1967819926fn structFieldPtrByIndex(
......@@ -19683,9 +19931,10 @@ fn structFieldPtrByIndex(
1968319931 field_index: u32,
1968419932 field_src: LazySrcLoc,
1968519933 struct_ty: Type,
19934 initializing: bool,
1968619935) CompileError!Air.Inst.Ref {
1968719936 if (struct_ty.isAnonStruct()) {
19688 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index);
19937 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
1968919938 }
1969019939
1969119940 const struct_obj = struct_ty.castTag(.@"struct").?.data;
......@@ -19882,6 +20131,10 @@ fn tupleFieldValByIndex(
1988220131 return sema.addConstant(field_ty, field_values[field_index]);
1988320132 }
1988420133
20134 if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
20135 return sema.addConstant(field_ty, default_val);
20136 }
20137
1988520138 try sema.requireRuntimeBlock(block, src, null);
1988620139 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
1988720140}
......@@ -19894,6 +20147,7 @@ fn unionFieldPtr(
1989420147 field_name: []const u8,
1989520148 field_name_src: LazySrcLoc,
1989620149 unresolved_union_ty: Type,
20150 initializing: bool,
1989720151) CompileError!Air.Inst.Ref {
1989820152 const arena = sema.arena;
1989920153 assert(unresolved_union_ty.zigTypeTag() == .Union);
......@@ -19909,30 +20163,32 @@ fn unionFieldPtr(
1990920163 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
1991020164 });
1991120165
19912 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| {
20166 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
1991320167 switch (union_obj.layout) {
19914 .Auto => {
19915 // TODO emit the access of inactive union field error commented out below.
19916 // In order to do that, we need to first solve the problem that AstGen
19917 // emits field_ptr instructions in order to initialize union values.
19918 // In such case we need to know that the field_ptr instruction (which is
19919 // calling this unionFieldPtr function) is *initializing* the union,
19920 // in which case we would skip this check, and in fact we would actually
19921 // set the union tag here and the payload to undefined.
19922
19923 //const tag_and_val = union_val.castTag(.@"union").?.data;
19924 //var field_tag_buf: Value.Payload.U32 = .{
19925 // .base = .{ .tag = .enum_field_index },
19926 // .data = field_index,
19927 //};
19928 //const field_tag = Value.initPayload(&field_tag_buf.base);
19929 //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod);
19930 //if (!tag_matches) {
19931 // // TODO enhance this saying which one was active
19932 // // and which one was accessed, and showing where the union was declared.
19933 // return sema.fail(block, src, "access of inactive union field", .{});
19934 //}
19935 // TODO add runtime safety check for the active tag
20168 .Auto => if (!initializing) {
20169 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
20170 break :ct;
20171 if (union_val.isUndef()) {
20172 return sema.failWithUseOfUndef(block, src);
20173 }
20174 const tag_and_val = union_val.castTag(.@"union").?.data;
20175 var field_tag_buf: Value.Payload.U32 = .{
20176 .base = .{ .tag = .enum_field_index },
20177 .data = field_index,
20178 };
20179 const field_tag = Value.initPayload(&field_tag_buf.base);
20180 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
20181 if (!tag_matches) {
20182 const msg = msg: {
20183 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
20184 const active_field_name = union_obj.fields.keys()[active_index];
20185 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
20186 errdefer msg.destroy(sema.gpa);
20187 try sema.addDeclaredHereNote(msg, union_ty);
20188 break :msg msg;
20189 };
20190 return sema.failWithOwnedErrorMsg(block, msg);
20191 }
1993620192 },
1993720193 .Packed, .Extern => {},
1993820194 }
......@@ -19947,6 +20203,18 @@ fn unionFieldPtr(
1994720203 }
1994820204
1994920205 try sema.requireRuntimeBlock(block, src, null);
20206 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
20207 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
20208 {
20209 const enum_ty = union_ty.unionTagTypeHypothetical();
20210 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
20211 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);
20212 // TODO would it be better if get_union_tag supported pointers to unions?
20213 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
20214 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_val);
20215 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
20216 try sema.addSafetyCheck(block, ok, .inactive_union_field);
20217 }
1995020218 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
1995120219}
1995220220
......@@ -20005,6 +20273,16 @@ fn unionFieldVal(
2000520273 }
2000620274
2000720275 try sema.requireRuntimeBlock(block, src, null);
20276 if (union_obj.layout == .Auto and block.wantSafety() and
20277 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
20278 {
20279 const enum_ty = union_ty.unionTagTypeHypothetical();
20280 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
20281 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);
20282 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval);
20283 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
20284 try sema.addSafetyCheck(block, ok, .inactive_union_field);
20285 }
2000820286 return block.addStructFieldVal(union_byval, field_index, field.ty);
2000920287}
2001020288
......@@ -20061,7 +20339,7 @@ fn elemPtr(
2006120339 // Tuple field access.
2006220340 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
2006320341 const index = @intCast(u32, index_val.toUnsignedInt(target));
20064 return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index);
20342 return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
2006520343 },
2006620344 else => unreachable,
2006720345 }
......@@ -20164,6 +20442,7 @@ fn tupleFieldPtr(
2016420442 tuple_ptr: Air.Inst.Ref,
2016520443 field_index_src: LazySrcLoc,
2016620444 field_index: u32,
20445 init: bool,
2016720446) CompileError!Air.Inst.Ref {
2016820447 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
2016920448 const tuple_ty = tuple_ptr_ty.childType();
......@@ -20197,7 +20476,17 @@ fn tupleFieldPtr(
2019720476 );
2019820477 }
2019920478
20200 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
20479 if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
20480 const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{
20481 .field_ty = field_ty,
20482 .field_val = default_val,
20483 });
20484 return sema.addConstant(ptr_field_ty, val);
20485 }
20486
20487 if (!init) {
20488 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
20489 }
2020120490
2020220491 try sema.requireRuntimeBlock(block, tuple_ptr_src, null);
2020320492 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
......@@ -20911,16 +21200,11 @@ fn coerceExtra(
2091121200 const msg = try sema.errMsg(
2091221201 block,
2091321202 inst_src,
20914 "enum '{}' has no field named '{s}'",
20915 .{ dest_ty.fmt(sema.mod), bytes },
21203 "no field named '{s}' in enum '{}'",
21204 .{ bytes, dest_ty.fmt(sema.mod) },
2091621205 );
2091721206 errdefer msg.destroy(sema.gpa);
20918 try sema.mod.errNoteNonLazy(
20919 dest_ty.declSrcLoc(sema.mod),
20920 msg,
20921 "enum declared here",
20922 .{},
20923 );
21207 try sema.addDeclaredHereNote(msg, dest_ty);
2092421208 break :msg msg;
2092521209 };
2092621210 return sema.failWithOwnedErrorMsg(block, msg);
......@@ -22131,7 +22415,7 @@ fn storePtrVal(
2213122415 .direct => |val_ptr| {
2213222416 if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) {
2213322417 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {
22134 // TODO add note showing where default value is provided
22418 // TODO use failWithInvalidComptimeFieldStore
2213522419 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
2213622420 }
2213722421 return;
......@@ -23476,6 +23760,7 @@ fn coerceTupleToStruct(
2347623760 const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);
2347723761
2347823762 if (struct_ty.isTupleOrAnonStruct()) {
23763 // NOTE remember to handle comptime fields
2347923764 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{});
2348023765 }
2348123766
......@@ -23496,12 +23781,18 @@ fn coerceTupleToStruct(
2349623781 try std.fmt.allocPrint(sema.arena, "{d}", .{i});
2349723782 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
2349823783 const field = fields.values()[field_index];
23499 if (field.is_comptime) {
23500 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{});
23501 }
2350223784 const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i);
2350323785 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
2350423786 field_refs[field_index] = coerced;
23787 if (field.is_comptime) {
23788 const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse {
23789 return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known");
23790 };
23791
23792 if (!init_val.eql(field.default_val, field.ty, sema.mod)) {
23793 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, i);
23794 }
23795 }
2350523796 if (runtime_src == null) {
2350623797 if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| {
2350723798 field_vals[field_index] = field_val;
......@@ -24259,7 +24550,7 @@ fn cmpNumeric(
2425924550 };
2426024551 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
2426124552 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
24262 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
24553 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
2426324554 }
2426424555 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
2426524556 // For mixed signed and unsigned integers, implicit cast both operands to a signed
......@@ -24380,7 +24671,7 @@ fn cmpNumeric(
2438024671 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
2438124672 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
2438224673
24383 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
24674 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
2438424675}
2438524676
2438624677/// Asserts that lhs and rhs types are both vectors.
......@@ -25323,7 +25614,7 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
2532325614 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
2532425615 return ty;
2532525616 },
25326 .@"union", .union_tagged => {
25617 .@"union", .union_safety_tagged, .union_tagged => {
2532725618 const union_obj = ty.cast(Type.Payload.Union).?.data;
2532825619 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
2532925620 return ty;
......@@ -25958,7 +26249,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2595826249 const msg = msg: {
2595926250 const tree = try sema.getAstTree(&block_scope);
2596026251 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
25961 const msg = try sema.errMsg(&block_scope, field_src, "enum '{}' has no field named '{s}'", .{ union_obj.tag_ty.fmt(sema.mod), field_name });
26252 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
2596226253 errdefer msg.destroy(sema.gpa);
2596326254 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
2596426255 break :msg msg;
......@@ -26348,7 +26639,7 @@ pub fn typeHasOnePossibleValue(
2634826639 return null;
2634926640 }
2635026641 },
26351 .@"union", .union_tagged => {
26642 .@"union", .union_safety_tagged, .union_tagged => {
2635226643 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
2635326644 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
2635426645 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
......@@ -26980,7 +27271,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
2698027271 }
2698127272 },
2698227273
26983 .@"union", .union_tagged => {
27274 .@"union", .union_safety_tagged, .union_tagged => {
2698427275 const union_obj = ty.cast(Type.Payload.Union).?.data;
2698527276 switch (union_obj.requires_comptime) {
2698627277 .no, .wip => return false,
src/Zir.zig+5
......@@ -410,6 +410,8 @@ pub const Inst = struct {
410410 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
411411 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
412412 field_ptr,
413 /// Same as `field_ptr` but used for struct init.
414 field_ptr_init,
413415 /// Given a struct or object that contains virtual fields, returns the named field.
414416 /// The field name is stored in string_bytes. Used by a.b syntax.
415417 /// This instruction also accepts a pointer.
......@@ -1070,6 +1072,7 @@ pub const Inst = struct {
10701072 .@"export",
10711073 .export_value,
10721074 .field_ptr,
1075 .field_ptr_init,
10731076 .field_val,
10741077 .field_call_bind,
10751078 .field_ptr_named,
......@@ -1370,6 +1373,7 @@ pub const Inst = struct {
13701373 .elem_ptr_imm,
13711374 .elem_val_node,
13721375 .field_ptr,
1376 .field_ptr_init,
13731377 .field_val,
13741378 .field_call_bind,
13751379 .field_ptr_named,
......@@ -1629,6 +1633,7 @@ pub const Inst = struct {
16291633 .@"export" = .pl_node,
16301634 .export_value = .pl_node,
16311635 .field_ptr = .pl_node,
1636 .field_ptr_init = .pl_node,
16321637 .field_val = .pl_node,
16331638 .field_ptr_named = .pl_node,
16341639 .field_val_named = .pl_node,
src/arch/aarch64/CodeGen.zig+24
......@@ -729,6 +729,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
729729 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
730730 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
731731
732 .add_optimized,
733 .addwrap_optimized,
734 .sub_optimized,
735 .subwrap_optimized,
736 .mul_optimized,
737 .mulwrap_optimized,
738 .div_float_optimized,
739 .div_trunc_optimized,
740 .div_floor_optimized,
741 .div_exact_optimized,
742 .rem_optimized,
743 .mod_optimized,
744 .neg_optimized,
745 .cmp_lt_optimized,
746 .cmp_lte_optimized,
747 .cmp_eq_optimized,
748 .cmp_gte_optimized,
749 .cmp_gt_optimized,
750 .cmp_neq_optimized,
751 .cmp_vector_optimized,
752 .reduce_optimized,
753 .float_to_int_optimized,
754 => return self.fail("TODO implement optimized float mode", .{}),
755
732756 .wasm_memory_size => unreachable,
733757 .wasm_memory_grow => unreachable,
734758 // zig fmt: on
src/arch/arm/CodeGen.zig+24
......@@ -744,6 +744,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
744744 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
745745 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
746746
747 .add_optimized,
748 .addwrap_optimized,
749 .sub_optimized,
750 .subwrap_optimized,
751 .mul_optimized,
752 .mulwrap_optimized,
753 .div_float_optimized,
754 .div_trunc_optimized,
755 .div_floor_optimized,
756 .div_exact_optimized,
757 .rem_optimized,
758 .mod_optimized,
759 .neg_optimized,
760 .cmp_lt_optimized,
761 .cmp_lte_optimized,
762 .cmp_eq_optimized,
763 .cmp_gte_optimized,
764 .cmp_gt_optimized,
765 .cmp_neq_optimized,
766 .cmp_vector_optimized,
767 .reduce_optimized,
768 .float_to_int_optimized,
769 => return self.fail("TODO implement optimized float mode", .{}),
770
747771 .wasm_memory_size => unreachable,
748772 .wasm_memory_grow => unreachable,
749773 // zig fmt: on
src/arch/riscv64/CodeGen.zig+24
......@@ -669,6 +669,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669669 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
670670 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
671671
672 .add_optimized,
673 .addwrap_optimized,
674 .sub_optimized,
675 .subwrap_optimized,
676 .mul_optimized,
677 .mulwrap_optimized,
678 .div_float_optimized,
679 .div_trunc_optimized,
680 .div_floor_optimized,
681 .div_exact_optimized,
682 .rem_optimized,
683 .mod_optimized,
684 .neg_optimized,
685 .cmp_lt_optimized,
686 .cmp_lte_optimized,
687 .cmp_eq_optimized,
688 .cmp_gte_optimized,
689 .cmp_gt_optimized,
690 .cmp_neq_optimized,
691 .cmp_vector_optimized,
692 .reduce_optimized,
693 .float_to_int_optimized,
694 => return self.fail("TODO implement optimized float mode", .{}),
695
672696 .wasm_memory_size => unreachable,
673697 .wasm_memory_grow => unreachable,
674698 // zig fmt: on
src/arch/sparc64/CodeGen.zig+24
......@@ -681,6 +681,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
681681 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
682682 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
683683
684 .add_optimized,
685 .addwrap_optimized,
686 .sub_optimized,
687 .subwrap_optimized,
688 .mul_optimized,
689 .mulwrap_optimized,
690 .div_float_optimized,
691 .div_trunc_optimized,
692 .div_floor_optimized,
693 .div_exact_optimized,
694 .rem_optimized,
695 .mod_optimized,
696 .neg_optimized,
697 .cmp_lt_optimized,
698 .cmp_lte_optimized,
699 .cmp_eq_optimized,
700 .cmp_gte_optimized,
701 .cmp_gt_optimized,
702 .cmp_neq_optimized,
703 .cmp_vector_optimized,
704 .reduce_optimized,
705 .float_to_int_optimized,
706 => @panic("TODO implement optimized float mode"),
707
684708 .wasm_memory_size => unreachable,
685709 .wasm_memory_grow => unreachable,
686710 // zig fmt: on
src/arch/wasm/CodeGen.zig+24
......@@ -1622,6 +1622,30 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16221622 .err_return_trace,
16231623 .set_err_return_trace,
16241624 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
1625
1626 .add_optimized,
1627 .addwrap_optimized,
1628 .sub_optimized,
1629 .subwrap_optimized,
1630 .mul_optimized,
1631 .mulwrap_optimized,
1632 .div_float_optimized,
1633 .div_trunc_optimized,
1634 .div_floor_optimized,
1635 .div_exact_optimized,
1636 .rem_optimized,
1637 .mod_optimized,
1638 .neg_optimized,
1639 .cmp_lt_optimized,
1640 .cmp_lte_optimized,
1641 .cmp_eq_optimized,
1642 .cmp_gte_optimized,
1643 .cmp_gt_optimized,
1644 .cmp_neq_optimized,
1645 .cmp_vector_optimized,
1646 .reduce_optimized,
1647 .float_to_int_optimized,
1648 => return self.fail("TODO implement optimized float mode", .{}),
16251649 };
16261650}
16271651
src/arch/wasm/abi.zig+2-2
......@@ -77,7 +77,7 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
7777 .Union => {
7878 const layout = ty.unionGetLayout(target);
7979 if (layout.payload_size == 0 and layout.tag_size != 0) {
80 return classifyType(ty.unionTagType().?, target);
80 return classifyType(ty.unionTagTypeSafety().?, target);
8181 }
8282 if (ty.unionFields().count() > 1) return memory;
8383 return classifyType(ty.unionFields().values()[0].ty, target);
......@@ -111,7 +111,7 @@ pub fn scalarType(ty: Type, target: std.Target) Type {
111111 .Union => {
112112 const layout = ty.unionGetLayout(target);
113113 if (layout.payload_size == 0 and layout.tag_size != 0) {
114 return scalarType(ty.unionTagType().?, target);
114 return scalarType(ty.unionTagTypeSafety().?, target);
115115 }
116116 std.debug.assert(ty.unionFields().count() == 1);
117117 return scalarType(ty.unionFields().values()[0].ty, target);
src/arch/x86_64/CodeGen.zig+24
......@@ -751,6 +751,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
751751 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
752752 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
753753
754 .add_optimized,
755 .addwrap_optimized,
756 .sub_optimized,
757 .subwrap_optimized,
758 .mul_optimized,
759 .mulwrap_optimized,
760 .div_float_optimized,
761 .div_trunc_optimized,
762 .div_floor_optimized,
763 .div_exact_optimized,
764 .rem_optimized,
765 .mod_optimized,
766 .neg_optimized,
767 .cmp_lt_optimized,
768 .cmp_lte_optimized,
769 .cmp_eq_optimized,
770 .cmp_gte_optimized,
771 .cmp_gt_optimized,
772 .cmp_neq_optimized,
773 .cmp_vector_optimized,
774 .reduce_optimized,
775 .float_to_int_optimized,
776 => return self.fail("TODO implement optimized float mode", .{}),
777
754778 .wasm_memory_size => unreachable,
755779 .wasm_memory_grow => unreachable,
756780 // zig fmt: on
src/codegen/c.zig+33-9
......@@ -504,7 +504,7 @@ pub const DeclGen = struct {
504504 if (field_ty.hasRuntimeBitsIgnoreComptime()) {
505505 try writer.writeAll("&(");
506506 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
507 if (field_ptr.container_ty.tag() == .union_tagged) {
507 if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) {
508508 try writer.print(")->payload.{ }", .{fmtIdent(field_name)});
509509 } else {
510510 try writer.print(")->{ }", .{fmtIdent(field_name)});
......@@ -842,7 +842,7 @@ pub const DeclGen = struct {
842842 try dg.renderTypecast(writer, ty);
843843 try writer.writeAll("){");
844844
845 if (ty.unionTagType()) |tag_ty| {
845 if (ty.unionTagTypeSafety()) |tag_ty| {
846846 if (layout.tag_size != 0) {
847847 try writer.writeAll(".tag = ");
848848 try dg.renderValue(writer, tag_ty, union_obj.tag, location);
......@@ -858,7 +858,7 @@ pub const DeclGen = struct {
858858 try writer.print(".{ } = ", .{fmtIdent(field_name)});
859859 try dg.renderValue(writer, field_ty, union_obj.val, location);
860860 }
861 if (ty.unionTagType()) |_| {
861 if (ty.unionTagTypeSafety()) |_| {
862862 try writer.writeAll("}");
863863 }
864864 try writer.writeAll("}");
......@@ -1110,7 +1110,7 @@ pub const DeclGen = struct {
11101110 defer buffer.deinit();
11111111
11121112 try buffer.appendSlice("typedef ");
1113 if (t.unionTagType()) |tag_ty| {
1113 if (t.unionTagTypeSafety()) |tag_ty| {
11141114 const name: CValue = .{ .bytes = "tag" };
11151115 try buffer.appendSlice("struct {\n ");
11161116 if (layout.tag_size != 0) {
......@@ -1134,7 +1134,7 @@ pub const DeclGen = struct {
11341134 }
11351135 try buffer.appendSlice("} ");
11361136
1137 if (t.unionTagType()) |_| {
1137 if (t.unionTagTypeSafety()) |_| {
11381138 try buffer.appendSlice("payload;\n} ");
11391139 }
11401140
......@@ -1928,6 +1928,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19281928
19291929 .wasm_memory_size => try airWasmMemorySize(f, inst),
19301930 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
1931
1932 .add_optimized,
1933 .addwrap_optimized,
1934 .sub_optimized,
1935 .subwrap_optimized,
1936 .mul_optimized,
1937 .mulwrap_optimized,
1938 .div_float_optimized,
1939 .div_trunc_optimized,
1940 .div_floor_optimized,
1941 .div_exact_optimized,
1942 .rem_optimized,
1943 .mod_optimized,
1944 .neg_optimized,
1945 .cmp_lt_optimized,
1946 .cmp_lte_optimized,
1947 .cmp_eq_optimized,
1948 .cmp_gte_optimized,
1949 .cmp_gt_optimized,
1950 .cmp_neq_optimized,
1951 .cmp_vector_optimized,
1952 .reduce_optimized,
1953 .float_to_int_optimized,
1954 => return f.fail("TODO implement optimized float mode", .{}),
19311955 // zig fmt: on
19321956 };
19331957 switch (result_value) {
......@@ -3368,7 +3392,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
33683392 field_name = fields.keys()[index];
33693393 field_val_ty = fields.values()[index].ty;
33703394 },
3371 .@"union", .union_tagged => {
3395 .@"union", .union_safety_tagged, .union_tagged => {
33723396 const fields = struct_ty.unionFields();
33733397 field_name = fields.keys()[index];
33743398 field_val_ty = fields.values()[index].ty;
......@@ -3383,7 +3407,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
33833407 },
33843408 else => unreachable,
33853409 }
3386 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
3410 const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
33873411
33883412 const inst_ty = f.air.typeOfIndex(inst);
33893413 const local = try f.allocLocal(inst_ty, .Const);
......@@ -3415,7 +3439,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
34153439 defer buf.deinit();
34163440 const field_name = switch (struct_ty.tag()) {
34173441 .@"struct" => struct_ty.structFields().keys()[extra.field_index],
3418 .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
3442 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
34193443 .tuple, .anon_struct => blk: {
34203444 const tuple = struct_ty.tupleFields();
34213445 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
......@@ -3425,7 +3449,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
34253449 },
34263450 else => unreachable,
34273451 };
3428 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
3452 const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
34293453
34303454 const inst_ty = f.air.typeOfIndex(inst);
34313455 const local = try f.allocLocal(inst_ty, .Const);
src/codegen/llvm.zig+97-42
......@@ -3404,7 +3404,7 @@ pub const DeclGen = struct {
34043404
34053405 if (layout.payload_size == 0) {
34063406 return lowerValue(dg, .{
3407 .ty = tv.ty.unionTagType().?,
3407 .ty = tv.ty.unionTagTypeSafety().?,
34083408 .val = tag_and_val.tag,
34093409 });
34103410 }
......@@ -3446,7 +3446,7 @@ pub const DeclGen = struct {
34463446 }
34473447 }
34483448 const llvm_tag_value = try lowerValue(dg, .{
3449 .ty = tv.ty.unionTagType().?,
3449 .ty = tv.ty.unionTagTypeSafety().?,
34503450 .val = tag_and_val.tag,
34513451 });
34523452 var fields: [3]*const llvm.Value = undefined;
......@@ -3984,21 +3984,21 @@ pub const FuncGen = struct {
39843984 for (body) |inst, i| {
39853985 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
39863986 // zig fmt: off
3987 .add => try self.airAdd(inst),
3988 .addwrap => try self.airAddWrap(inst),
3987 .add => try self.airAdd(inst, false),
3988 .addwrap => try self.airAddWrap(inst, false),
39893989 .add_sat => try self.airAddSat(inst),
3990 .sub => try self.airSub(inst),
3991 .subwrap => try self.airSubWrap(inst),
3990 .sub => try self.airSub(inst, false),
3991 .subwrap => try self.airSubWrap(inst, false),
39923992 .sub_sat => try self.airSubSat(inst),
3993 .mul => try self.airMul(inst),
3994 .mulwrap => try self.airMulWrap(inst),
3993 .mul => try self.airMul(inst, false),
3994 .mulwrap => try self.airMulWrap(inst, false),
39953995 .mul_sat => try self.airMulSat(inst),
3996 .div_float => try self.airDivFloat(inst),
3997 .div_trunc => try self.airDivTrunc(inst),
3998 .div_floor => try self.airDivFloor(inst),
3999 .div_exact => try self.airDivExact(inst),
4000 .rem => try self.airRem(inst),
4001 .mod => try self.airMod(inst),
3996 .div_float => try self.airDivFloat(inst, false),
3997 .div_trunc => try self.airDivTrunc(inst, false),
3998 .div_floor => try self.airDivFloor(inst, false),
3999 .div_exact => try self.airDivExact(inst, false),
4000 .rem => try self.airRem(inst, false),
4001 .mod => try self.airMod(inst, false),
40024002 .ptr_add => try self.airPtrAdd(inst),
40034003 .ptr_sub => try self.airPtrSub(inst),
40044004 .shl => try self.airShl(inst),
......@@ -4009,6 +4009,19 @@ pub const FuncGen = struct {
40094009 .slice => try self.airSlice(inst),
40104010 .mul_add => try self.airMulAdd(inst),
40114011
4012 .add_optimized => try self.airAdd(inst, true),
4013 .addwrap_optimized => try self.airAddWrap(inst, true),
4014 .sub_optimized => try self.airSub(inst, true),
4015 .subwrap_optimized => try self.airSubWrap(inst, true),
4016 .mul_optimized => try self.airMul(inst, true),
4017 .mulwrap_optimized => try self.airMulWrap(inst, true),
4018 .div_float_optimized => try self.airDivFloat(inst, true),
4019 .div_trunc_optimized => try self.airDivTrunc(inst, true),
4020 .div_floor_optimized => try self.airDivFloor(inst, true),
4021 .div_exact_optimized => try self.airDivExact(inst, true),
4022 .rem_optimized => try self.airRem(inst, true),
4023 .mod_optimized => try self.airMod(inst, true),
4024
40124025 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
40134026 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
40144027 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
......@@ -4034,17 +4047,27 @@ pub const FuncGen = struct {
40344047 .ceil => try self.airUnaryOp(inst, .ceil),
40354048 .round => try self.airUnaryOp(inst, .round),
40364049 .trunc_float => try self.airUnaryOp(inst, .trunc),
4037 .neg => try self.airUnaryOp(inst, .neg),
4038
4039 .cmp_eq => try self.airCmp(inst, .eq),
4040 .cmp_gt => try self.airCmp(inst, .gt),
4041 .cmp_gte => try self.airCmp(inst, .gte),
4042 .cmp_lt => try self.airCmp(inst, .lt),
4043 .cmp_lte => try self.airCmp(inst, .lte),
4044 .cmp_neq => try self.airCmp(inst, .neq),
40454050
4046 .cmp_vector => try self.airCmpVector(inst),
4047 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
4051 .neg => try self.airNeg(inst, false),
4052 .neg_optimized => try self.airNeg(inst, true),
4053
4054 .cmp_eq => try self.airCmp(inst, .eq, false),
4055 .cmp_gt => try self.airCmp(inst, .gt, false),
4056 .cmp_gte => try self.airCmp(inst, .gte, false),
4057 .cmp_lt => try self.airCmp(inst, .lt, false),
4058 .cmp_lte => try self.airCmp(inst, .lte, false),
4059 .cmp_neq => try self.airCmp(inst, .neq, false),
4060
4061 .cmp_eq_optimized => try self.airCmp(inst, .eq, true),
4062 .cmp_gt_optimized => try self.airCmp(inst, .gt, true),
4063 .cmp_gte_optimized => try self.airCmp(inst, .gte, true),
4064 .cmp_lt_optimized => try self.airCmp(inst, .lt, true),
4065 .cmp_lte_optimized => try self.airCmp(inst, .lte, true),
4066 .cmp_neq_optimized => try self.airCmp(inst, .neq, true),
4067
4068 .cmp_vector => try self.airCmpVector(inst, false),
4069 .cmp_vector_optimized => try self.airCmpVector(inst, true),
4070 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
40484071
40494072 .is_non_null => try self.airIsNonNull(inst, false, .NE),
40504073 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),
......@@ -4093,8 +4116,10 @@ pub const FuncGen = struct {
40934116 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
40944117 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
40954118
4119 .float_to_int => try self.airFloatToInt(inst, false),
4120 .float_to_int_optimized => try self.airFloatToInt(inst, true),
4121
40964122 .array_to_slice => try self.airArrayToSlice(inst),
4097 .float_to_int => try self.airFloatToInt(inst),
40984123 .int_to_float => try self.airIntToFloat(inst),
40994124 .cmpxchg_weak => try self.airCmpxchg(inst, true),
41004125 .cmpxchg_strong => try self.airCmpxchg(inst, false),
......@@ -4115,11 +4140,13 @@ pub const FuncGen = struct {
41154140 .splat => try self.airSplat(inst),
41164141 .select => try self.airSelect(inst),
41174142 .shuffle => try self.airShuffle(inst),
4118 .reduce => try self.airReduce(inst),
41194143 .aggregate_init => try self.airAggregateInit(inst),
41204144 .union_init => try self.airUnionInit(inst),
41214145 .prefetch => try self.airPrefetch(inst),
41224146
4147 .reduce => try self.airReduce(inst, false),
4148 .reduce_optimized => try self.airReduce(inst, true),
4149
41234150 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
41244151 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
41254152 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -4485,8 +4512,9 @@ pub const FuncGen = struct {
44854512 return null;
44864513 }
44874514
4488 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator) !?*const llvm.Value {
4515 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*const llvm.Value {
44894516 if (self.liveness.isUnused(inst)) return null;
4517 self.builder.setFastMath(want_fast_math);
44904518
44914519 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
44924520 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -4496,8 +4524,9 @@ pub const FuncGen = struct {
44964524 return self.cmp(lhs, rhs, operand_ty, op);
44974525 }
44984526
4499 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4527 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
45004528 if (self.liveness.isUnused(inst)) return null;
4529 self.builder.setFastMath(want_fast_math);
45014530
45024531 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
45034532 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
......@@ -4943,10 +4972,12 @@ pub const FuncGen = struct {
49434972 return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, "");
49444973 }
49454974
4946 fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4975 fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
49474976 if (self.liveness.isUnused(inst))
49484977 return null;
49494978
4979 self.builder.setFastMath(want_fast_math);
4980
49504981 const target = self.dg.module.getTarget();
49514982 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
49524983
......@@ -6095,8 +6126,9 @@ pub const FuncGen = struct {
60956126 return self.builder.buildInsertValue(partial, len, 1, "");
60966127 }
60976128
6098 fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6129 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
60996130 if (self.liveness.isUnused(inst)) return null;
6131 self.builder.setFastMath(want_fast_math);
61006132
61016133 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61026134 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6109,8 +6141,9 @@ pub const FuncGen = struct {
61096141 return self.builder.buildNUWAdd(lhs, rhs, "");
61106142 }
61116143
6112 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6144 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
61136145 if (self.liveness.isUnused(inst)) return null;
6146 self.builder.setFastMath(want_fast_math);
61146147
61156148 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61166149 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6134,8 +6167,9 @@ pub const FuncGen = struct {
61346167 return self.builder.buildUAddSat(lhs, rhs, "");
61356168 }
61366169
6137 fn airSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6170 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
61386171 if (self.liveness.isUnused(inst)) return null;
6172 self.builder.setFastMath(want_fast_math);
61396173
61406174 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61416175 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6148,8 +6182,9 @@ pub const FuncGen = struct {
61486182 return self.builder.buildNUWSub(lhs, rhs, "");
61496183 }
61506184
6151 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6185 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
61526186 if (self.liveness.isUnused(inst)) return null;
6187 self.builder.setFastMath(want_fast_math);
61536188
61546189 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61556190 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6172,8 +6207,9 @@ pub const FuncGen = struct {
61726207 return self.builder.buildUSubSat(lhs, rhs, "");
61736208 }
61746209
6175 fn airMul(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6210 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
61766211 if (self.liveness.isUnused(inst)) return null;
6212 self.builder.setFastMath(want_fast_math);
61776213
61786214 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61796215 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6186,8 +6222,9 @@ pub const FuncGen = struct {
61866222 return self.builder.buildNUWMul(lhs, rhs, "");
61876223 }
61886224
6189 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6225 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
61906226 if (self.liveness.isUnused(inst)) return null;
6227 self.builder.setFastMath(want_fast_math);
61916228
61926229 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61936230 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6210,8 +6247,9 @@ pub const FuncGen = struct {
62106247 return self.builder.buildUMulFixSat(lhs, rhs, "");
62116248 }
62126249
6213 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6250 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
62146251 if (self.liveness.isUnused(inst)) return null;
6252 self.builder.setFastMath(want_fast_math);
62156253
62166254 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
62176255 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6221,8 +6259,9 @@ pub const FuncGen = struct {
62216259 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
62226260 }
62236261
6224 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6262 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
62256263 if (self.liveness.isUnused(inst)) return null;
6264 self.builder.setFastMath(want_fast_math);
62266265
62276266 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
62286267 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6238,8 +6277,9 @@ pub const FuncGen = struct {
62386277 return self.builder.buildUDiv(lhs, rhs, "");
62396278 }
62406279
6241 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6280 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
62426281 if (self.liveness.isUnused(inst)) return null;
6282 self.builder.setFastMath(want_fast_math);
62436283
62446284 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
62456285 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6270,8 +6310,9 @@ pub const FuncGen = struct {
62706310 return self.builder.buildUDiv(lhs, rhs, "");
62716311 }
62726312
6273 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6313 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
62746314 if (self.liveness.isUnused(inst)) return null;
6315 self.builder.setFastMath(want_fast_math);
62756316
62766317 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
62776318 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6284,8 +6325,9 @@ pub const FuncGen = struct {
62846325 return self.builder.buildExactUDiv(lhs, rhs, "");
62856326 }
62866327
6287 fn airRem(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6328 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
62886329 if (self.liveness.isUnused(inst)) return null;
6330 self.builder.setFastMath(want_fast_math);
62896331
62906332 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
62916333 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -6298,8 +6340,9 @@ pub const FuncGen = struct {
62986340 return self.builder.buildURem(lhs, rhs, "");
62996341 }
63006342
6301 fn airMod(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6343 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
63026344 if (self.liveness.isUnused(inst)) return null;
6345 self.builder.setFastMath(want_fast_math);
63036346
63046347 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
63056348 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -7613,6 +7656,17 @@ pub const FuncGen = struct {
76137656 return self.buildFloatOp(op, operand_ty, 1, .{operand});
76147657 }
76157658
7659 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
7660 if (self.liveness.isUnused(inst)) return null;
7661 self.builder.setFastMath(want_fast_math);
7662
7663 const un_op = self.air.instructions.items(.data)[inst].un_op;
7664 const operand = try self.resolveInst(un_op);
7665 const operand_ty = self.air.typeOf(un_op);
7666
7667 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
7668 }
7669
76167670 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
76177671 if (self.liveness.isUnused(inst)) return null;
76187672
......@@ -7927,8 +7981,9 @@ pub const FuncGen = struct {
79277981 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
79287982 }
79297983
7930 fn airReduce(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
7984 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
79317985 if (self.liveness.isUnused(inst)) return null;
7986 self.builder.setFastMath(want_fast_math);
79327987
79337988 const reduce = self.air.instructions.items(.data)[inst].reduce;
79347989 const operand = try self.resolveInst(reduce.operand);
src/codegen/llvm/bindings.zig+3
......@@ -941,6 +941,9 @@ pub const Builder = opaque {
941941
942942 pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce;
943943 extern fn ZigLLVMBuildFPMulReduce(B: *const Builder, Acc: *const Value, Val: *const Value) *const Value;
944
945 pub const setFastMath = ZigLLVMSetFastMath;
946 extern fn ZigLLVMSetFastMath(B: *const Builder, on_state: bool) void;
944947};
945948
946949pub const MDString = opaque {
src/print_air.zig+22-2
......@@ -138,6 +138,24 @@ const Writer = struct {
138138 .set_union_tag,
139139 .min,
140140 .max,
141 .add_optimized,
142 .addwrap_optimized,
143 .sub_optimized,
144 .subwrap_optimized,
145 .mul_optimized,
146 .mulwrap_optimized,
147 .div_float_optimized,
148 .div_trunc_optimized,
149 .div_floor_optimized,
150 .div_exact_optimized,
151 .rem_optimized,
152 .mod_optimized,
153 .cmp_lt_optimized,
154 .cmp_lte_optimized,
155 .cmp_eq_optimized,
156 .cmp_gte_optimized,
157 .cmp_gt_optimized,
158 .cmp_neq_optimized,
141159 => try w.writeBinOp(s, inst),
142160
143161 .is_null,
......@@ -169,6 +187,7 @@ const Writer = struct {
169187 .round,
170188 .trunc_float,
171189 .neg,
190 .neg_optimized,
172191 .cmp_lt_errors_len,
173192 .set_err_return_trace,
174193 => try w.writeUnOp(s, inst),
......@@ -216,6 +235,7 @@ const Writer = struct {
216235 .int_to_float,
217236 .splat,
218237 .float_to_int,
238 .float_to_int_optimized,
219239 .get_union_tag,
220240 .clz,
221241 .ctz,
......@@ -280,8 +300,8 @@ const Writer = struct {
280300 .mul_add => try w.writeMulAdd(s, inst),
281301 .select => try w.writeSelect(s, inst),
282302 .shuffle => try w.writeShuffle(s, inst),
283 .reduce => try w.writeReduce(s, inst),
284 .cmp_vector => try w.writeCmpVector(s, inst),
303 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
304 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
285305
286306 .dbg_block_begin, .dbg_block_end => {},
287307 }
src/print_zir.zig+1
......@@ -390,6 +390,7 @@ const Writer = struct {
390390 .switch_block => try self.writeSwitchBlock(stream, inst),
391391
392392 .field_ptr,
393 .field_ptr_init,
393394 .field_val,
394395 .field_call_bind,
395396 => try self.writePlNodeField(stream, inst),
src/type.zig+61-28
......@@ -149,6 +149,7 @@ pub const Type = extern union {
149149 => return .Enum,
150150
151151 .@"union",
152 .union_safety_tagged,
152153 .union_tagged,
153154 .type_info,
154155 => return .Union,
......@@ -902,7 +903,7 @@ pub const Type = extern union {
902903 .reduce_op,
903904 => unreachable, // needed to resolve the type before now
904905
905 .@"union", .union_tagged => {
906 .@"union", .union_safety_tagged, .union_tagged => {
906907 const a_union_obj = a.cast(Payload.Union).?.data;
907908 const b_union_obj = (b.cast(Payload.Union) orelse return false).data;
908909 return a_union_obj == b_union_obj;
......@@ -1210,7 +1211,7 @@ pub const Type = extern union {
12101211 .reduce_op,
12111212 => unreachable, // needed to resolve the type before now
12121213
1213 .@"union", .union_tagged => {
1214 .@"union", .union_safety_tagged, .union_tagged => {
12141215 const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;
12151216 std.hash.autoHash(hasher, std.builtin.TypeId.Union);
12161217 std.hash.autoHash(hasher, union_obj);
......@@ -1479,7 +1480,7 @@ pub const Type = extern union {
14791480 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
14801481 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
14811482 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
1482 .@"union", .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union),
1483 .@"union", .union_safety_tagged, .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union),
14831484 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
14841485 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
14851486 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
......@@ -1603,7 +1604,7 @@ pub const Type = extern union {
16031604 @tagName(t), struct_obj.owner_decl,
16041605 });
16051606 },
1606 .@"union", .union_tagged => {
1607 .@"union", .union_safety_tagged, .union_tagged => {
16071608 const union_obj = ty.cast(Payload.Union).?.data;
16081609 return writer.print("({s} decl={d})", .{
16091610 @tagName(t), union_obj.owner_decl,
......@@ -1989,7 +1990,7 @@ pub const Type = extern union {
19891990 const decl = mod.declPtr(struct_obj.owner_decl);
19901991 try decl.renderFullyQualifiedName(mod, writer);
19911992 },
1992 .@"union", .union_tagged => {
1993 .@"union", .union_safety_tagged, .union_tagged => {
19931994 const union_obj = ty.cast(Payload.Union).?.data;
19941995 const decl = mod.declPtr(union_obj.owner_decl);
19951996 try decl.renderFullyQualifiedName(mod, writer);
......@@ -2485,8 +2486,8 @@ pub const Type = extern union {
24852486 return false;
24862487 }
24872488 },
2488 .union_tagged => {
2489 const union_obj = ty.castTag(.union_tagged).?.data;
2489 .union_safety_tagged, .union_tagged => {
2490 const union_obj = ty.cast(Payload.Union).?.data;
24902491 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
24912492 return true;
24922493 }
......@@ -2644,7 +2645,7 @@ pub const Type = extern union {
26442645
26452646 .optional => ty.isPtrLikeOptional(),
26462647 .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,
2647 .@"union" => ty.castTag(.@"union").?.data.layout != .Auto,
2648 .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto,
26482649 .union_tagged => false,
26492650 };
26502651 }
......@@ -3050,11 +3051,10 @@ pub const Type = extern union {
30503051 },
30513052 .@"union" => {
30523053 const union_obj = ty.castTag(.@"union").?.data;
3053 // TODO pass `true` for have_tag when unions have a safety tag
30543054 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false);
30553055 },
3056 .union_tagged => {
3057 const union_obj = ty.castTag(.union_tagged).?.data;
3056 .union_safety_tagged, .union_tagged => {
3057 const union_obj = ty.cast(Payload.Union).?.data;
30583058 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true);
30593059 },
30603060
......@@ -3232,11 +3232,10 @@ pub const Type = extern union {
32323232 },
32333233 .@"union" => {
32343234 const union_obj = ty.castTag(.@"union").?.data;
3235 // TODO pass `true` for have_tag when unions have a safety tag
32363235 return abiSizeAdvancedUnion(ty, target, strat, union_obj, false);
32373236 },
3238 .union_tagged => {
3239 const union_obj = ty.castTag(.union_tagged).?.data;
3237 .union_safety_tagged, .union_tagged => {
3238 const union_obj = ty.cast(Payload.Union).?.data;
32403239 return abiSizeAdvancedUnion(ty, target, strat, union_obj, true);
32413240 },
32423241
......@@ -3526,7 +3525,7 @@ pub const Type = extern union {
35263525 return try bitSizeAdvanced(int_tag_ty, target, sema_kit);
35273526 },
35283527
3529 .@"union", .union_tagged => {
3528 .@"union", .union_safety_tagged, .union_tagged => {
35303529 if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
35313530 const union_obj = ty.cast(Payload.Union).?.data;
35323531 assert(union_obj.haveFieldTypes());
......@@ -4194,6 +4193,33 @@ pub const Type = extern union {
41944193 };
41954194 }
41964195
4196 /// Same as `unionTagType` but includes safety tag.
4197 /// Codegen should use this version.
4198 pub fn unionTagTypeSafety(ty: Type) ?Type {
4199 return switch (ty.tag()) {
4200 .union_safety_tagged, .union_tagged => {
4201 const union_obj = ty.cast(Payload.Union).?.data;
4202 assert(union_obj.haveFieldTypes());
4203 return union_obj.tag_ty;
4204 },
4205
4206 .atomic_order,
4207 .atomic_rmw_op,
4208 .calling_convention,
4209 .address_space,
4210 .float_mode,
4211 .reduce_op,
4212 .call_options,
4213 .prefetch_options,
4214 .export_options,
4215 .extern_options,
4216 .type_info,
4217 => unreachable, // needed to call resolveTypeFields first
4218
4219 else => null,
4220 };
4221 }
4222
41974223 /// Asserts the type is a union; returns the tag type, even if the tag will
41984224 /// not be stored at runtime.
41994225 pub fn unionTagTypeHypothetical(ty: Type) Type {
......@@ -4225,8 +4251,8 @@ pub const Type = extern union {
42254251 const union_obj = ty.castTag(.@"union").?.data;
42264252 return union_obj.getLayout(target, false);
42274253 },
4228 .union_tagged => {
4229 const union_obj = ty.castTag(.union_tagged).?.data;
4254 .union_safety_tagged, .union_tagged => {
4255 const union_obj = ty.cast(Payload.Union).?.data;
42304256 return union_obj.getLayout(target, true);
42314257 },
42324258 else => unreachable,
......@@ -4238,6 +4264,7 @@ pub const Type = extern union {
42384264 .tuple, .empty_struct_literal, .anon_struct => .Auto,
42394265 .@"struct" => ty.castTag(.@"struct").?.data.layout,
42404266 .@"union" => ty.castTag(.@"union").?.data.layout,
4267 .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout,
42414268 .union_tagged => ty.castTag(.union_tagged).?.data.layout,
42424269 else => unreachable,
42434270 };
......@@ -4936,7 +4963,7 @@ pub const Type = extern union {
49364963 return null;
49374964 }
49384965 },
4939 .@"union", .union_tagged => {
4966 .@"union", .union_safety_tagged, .union_tagged => {
49404967 const union_obj = ty.cast(Payload.Union).?.data;
49414968 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
49424969 const only_field = union_obj.fields.values()[0];
......@@ -5114,7 +5141,7 @@ pub const Type = extern union {
51145141 }
51155142 },
51165143
5117 .@"union", .union_tagged => {
5144 .@"union", .union_safety_tagged, .union_tagged => {
51185145 const union_obj = ty.cast(Type.Payload.Union).?.data;
51195146 switch (union_obj.requires_comptime) {
51205147 .wip, .unknown => unreachable, // This function asserts types already resolved.
......@@ -5167,6 +5194,7 @@ pub const Type = extern union {
51675194 .empty_struct => self.castTag(.empty_struct).?.data,
51685195 .@"opaque" => &self.castTag(.@"opaque").?.data.namespace,
51695196 .@"union" => &self.castTag(.@"union").?.data.namespace,
5197 .union_safety_tagged => &self.castTag(.union_safety_tagged).?.data.namespace,
51705198 .union_tagged => &self.castTag(.union_tagged).?.data.namespace,
51715199
51725200 else => null,
......@@ -5439,7 +5467,7 @@ pub const Type = extern union {
54395467 const struct_obj = ty.castTag(.@"struct").?.data;
54405468 return struct_obj.fields.values()[index].ty;
54415469 },
5442 .@"union", .union_tagged => {
5470 .@"union", .union_safety_tagged, .union_tagged => {
54435471 const union_obj = ty.cast(Payload.Union).?.data;
54445472 return union_obj.fields.values()[index].ty;
54455473 },
......@@ -5456,7 +5484,7 @@ pub const Type = extern union {
54565484 assert(struct_obj.layout != .Packed);
54575485 return struct_obj.fields.values()[index].normalAlignment(target);
54585486 },
5459 .@"union", .union_tagged => {
5487 .@"union", .union_safety_tagged, .union_tagged => {
54605488 const union_obj = ty.cast(Payload.Union).?.data;
54615489 return union_obj.fields.values()[index].normalAlignment(target);
54625490 },
......@@ -5619,8 +5647,8 @@ pub const Type = extern union {
56195647 },
56205648
56215649 .@"union" => return 0,
5622 .union_tagged => {
5623 const union_obj = ty.castTag(.union_tagged).?.data;
5650 .union_safety_tagged, .union_tagged => {
5651 const union_obj = ty.cast(Payload.Union).?.data;
56245652 const layout = union_obj.getLayout(target, true);
56255653 if (layout.tag_align >= layout.payload_align) {
56265654 // {Tag, Payload}
......@@ -5660,7 +5688,7 @@ pub const Type = extern union {
56605688 const error_set = ty.castTag(.error_set).?.data;
56615689 return error_set.srcLoc(mod);
56625690 },
5663 .@"union", .union_tagged => {
5691 .@"union", .union_safety_tagged, .union_tagged => {
56645692 const union_obj = ty.cast(Payload.Union).?.data;
56655693 return union_obj.srcLoc(mod);
56665694 },
......@@ -5686,6 +5714,10 @@ pub const Type = extern union {
56865714 }
56875715
56885716 pub fn getOwnerDecl(ty: Type) Module.Decl.Index {
5717 return ty.getOwnerDeclOrNull() orelse unreachable;
5718 }
5719
5720 pub fn getOwnerDeclOrNull(ty: Type) ?Module.Decl.Index {
56895721 switch (ty.tag()) {
56905722 .enum_full, .enum_nonexhaustive => {
56915723 const enum_full = ty.cast(Payload.EnumFull).?.data;
......@@ -5704,7 +5736,7 @@ pub const Type = extern union {
57045736 const error_set = ty.castTag(.error_set).?.data;
57055737 return error_set.owner_decl;
57065738 },
5707 .@"union", .union_tagged => {
5739 .@"union", .union_safety_tagged, .union_tagged => {
57085740 const union_obj = ty.cast(Payload.Union).?.data;
57095741 return union_obj.owner_decl;
57105742 },
......@@ -5725,7 +5757,7 @@ pub const Type = extern union {
57255757 .type_info,
57265758 => unreachable, // These need to be resolved earlier.
57275759
5728 else => unreachable,
5760 else => return null,
57295761 }
57305762 }
57315763
......@@ -5748,7 +5780,7 @@ pub const Type = extern union {
57485780 const error_set = ty.castTag(.error_set).?.data;
57495781 return error_set.node_offset;
57505782 },
5751 .@"union", .union_tagged => {
5783 .@"union", .union_safety_tagged, .union_tagged => {
57525784 const union_obj = ty.cast(Payload.Union).?.data;
57535785 return union_obj.node_offset;
57545786 },
......@@ -5893,6 +5925,7 @@ pub const Type = extern union {
58935925 @"opaque",
58945926 @"struct",
58955927 @"union",
5928 union_safety_tagged,
58965929 union_tagged,
58975930 enum_simple,
58985931 enum_numbered,
......@@ -6009,7 +6042,7 @@ pub const Type = extern union {
60096042 .error_set_single => Payload.Name,
60106043 .@"opaque" => Payload.Opaque,
60116044 .@"struct" => Payload.Struct,
6012 .@"union", .union_tagged => Payload.Union,
6045 .@"union", .union_safety_tagged, .union_tagged => Payload.Union,
60136046 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
60146047 .enum_simple => Payload.EnumSimple,
60156048 .enum_numbered => Payload.EnumNumbered,
test/behavior/align.zig+1
......@@ -222,6 +222,7 @@ fn testBytesAlign(b: u8) !void {
222222test "@alignCast slices" {
223223 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
224224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
225226
226227 var array align(4) = [_]u32{ 1, 1 };
227228 const slice = array[0..];
test/behavior/bugs/1381.zig+2
......@@ -12,8 +12,10 @@ const A = union(enum) {
1212};
1313
1414test "union that needs padding bytes inside an array" {
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1617 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1719
1820 var as = [_]A{
1921 A{ .B = B{ .D = 1 } },
test/behavior/cast.zig+3
......@@ -127,6 +127,7 @@ test "@intToFloat(f80)" {
127127 }
128128
129129 fn testIntToFloat(comptime Int: type, k: Int) !void {
130 @setRuntimeSafety(false); // TODO
130131 const f = @intToFloat(f80, k);
131132 const i = @floatToInt(Int, f);
132133 try expect(i == k);
......@@ -151,6 +152,8 @@ test "@intToFloat(f80)" {
151152test "@floatToInt" {
152153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
153154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
154157
155158 try testFloatToInts();
156159 comptime try testFloatToInts();
test/behavior/math.zig+1
......@@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void {
377377}
378378
379379test "division" {
380 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
380381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
381382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
382383 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/struct.zig+3
......@@ -998,6 +998,9 @@ test "tuple element initialized with fn call" {
998998}
999999
10001000test "struct with union field" {
1001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1003
10011004 const Value = struct {
10021005 ref: u32 = 2,
10031006 kind: union(enum) {
test/behavior/type.zig+1-1
......@@ -412,7 +412,7 @@ test "Type.Union" {
412412
413413 const Untagged = @Type(.{
414414 .Union = .{
415 .layout = .Auto,
415 .layout = .Extern,
416416 .tag_type = null,
417417 .fields = &.{
418418 .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },
test/behavior/union.zig+13
......@@ -37,6 +37,7 @@ test "init union with runtime value - floats" {
3737
3838test "basic unions" {
3939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4041
4142 var foo = Foo{ .int = 1 };
4243 try expect(foo.int == 1);
......@@ -430,9 +431,11 @@ const Foo1 = union(enum) {
430431var glbl: Foo1 = undefined;
431432
432433test "global union with single field is correctly initialized" {
434 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
433435 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
434436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
435437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
438 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
436439
437440 glbl = Foo1{
438441 .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
......@@ -473,8 +476,11 @@ test "update the tag value for zero-sized unions" {
473476}
474477
475478test "union initializer generates padding only if needed" {
479 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
476480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
481 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
477482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
478484
479485 const U = union(enum) {
480486 A: u24,
......@@ -747,9 +753,11 @@ fn Setter(attr: Attribute) type {
747753}
748754
749755test "return union init with void payload" {
756 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
750757 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
751758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
752759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
760 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
753761
754762 const S = struct {
755763 fn entry() !void {
......@@ -775,6 +783,7 @@ test "@unionInit stored to a const" {
775783 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
776784 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
777785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
778787
779788 const S = struct {
780789 const U = union(enum) {
......@@ -937,6 +946,7 @@ test "cast from anonymous struct to union" {
937946 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
938947 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
939948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
949 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
940950
941951 const S = struct {
942952 const U = union(enum) {
......@@ -969,6 +979,7 @@ test "cast from pointer to anonymous struct to pointer to union" {
969979 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
970980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
971981 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
982 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
972983
973984 const S = struct {
974985 const U = union(enum) {
......@@ -1104,6 +1115,8 @@ test "union enum type gets a separate scope" {
11041115
11051116test "global variable struct contains union initialized to non-most-aligned field" {
11061117 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11071120
11081121 const T = struct {
11091122 const U = union(enum) {
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1
......@@ -3,3 +3,4 @@
33// target=aarch64-macos
44//
55// :107:9: error: struct 'tmp.tmp' has no member named 'main'
6// :7:1: note: struct declared here
test/cases/compile_errors/bad_alignCast_at_comptime.zig created+11
......@@ -0,0 +1,11 @@
1comptime {
2 const ptr = @intToPtr(*align(1) i32, 0x1);
3 const aligned = @alignCast(4, ptr);
4 _ = aligned;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :3:35: error: pointer address 0x1 is not aligned to 4 bytes
test/cases/compile_errors/bogus_compile_var.zig+1
......@@ -6,3 +6,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(x)); }
66// target=native
77//
88// :1:29: error: struct 'builtin.builtin' has no member named 'bogus'
9// :1:1: note: struct declared here
test/cases/compile_errors/bogus_method_call_on_slice.zig+1-1
......@@ -8,4 +8,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
88// backend=stage2
99// target=native
1010//
11// :3:6: error: type '[]const u8' has no field or member function named 'copy'
11// :3:6: error: no field or member function named 'copy' in '[]const u8'
test/cases/compile_errors/cast_enum_literal_to_enum_but_it_doesnt_match.zig+1-1
......@@ -11,5 +11,5 @@ export fn entry() void {
1111// backend=stage2
1212// target=native
1313//
14// :6:21: error: enum 'tmp.Foo' has no field named 'c'
14// :6:21: error: no field named 'c' in enum 'tmp.Foo'
1515// :1:13: note: enum declared here
test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig+1-1
......@@ -34,5 +34,5 @@ export fn d() void {
3434// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
3535// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
3636// :18:22: note: opaque declared here
37// :24:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
37// :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs
3838// :23:22: note: opaque declared here
test/cases/compile_errors/duplicate_field_in_anonymous_struct_literal.zig created+18
......@@ -0,0 +1,18 @@
1export fn entry() void {
2 const anon = .{
3 .inner = .{
4 .a = .{
5 .something = "text",
6 },
7 .a = .{},
8 },
9 };
10 _ = anon;
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :7:16: error: duplicate field
18// :4:16: note: other field here
test/cases/compile_errors/invalid_comptime_fields.zig created+21
......@@ -0,0 +1,21 @@
1const U = union {
2 comptime a: u32 = 1,
3};
4const E = enum {
5 comptime a = 1,
6};
7const P = packed struct {
8 comptime a: u32 = 1,
9};
10const X = extern struct {
11 comptime a: u32 = 1,
12};
13
14// error
15// backend=stage2
16// target=native
17//
18// :2:5: error: union fields cannot be marked comptime
19// :5:5: error: enum fields cannot be marked comptime
20// :8:5: error: packed struct fields cannot be marked comptime
21// :11:5: error: extern struct fields cannot be marked comptime
test/cases/compile_errors/invalid_store_to_comptime_field.zig+41
......@@ -13,9 +13,50 @@ pub export fn entry1() void {
1313 var s: S = .{};
1414 s.a = T{ .a = 2, .b = 2 };
1515}
16pub export fn entry2() void {
17 var list = .{ 1, 2, 3 };
18 var list2 = @TypeOf(list){ .@"0" = 1, .@"1" = 2, .@"2" = 3 };
19 var list3 = @TypeOf(list){ 1, 2, 4 };
20 _ = list2;
21 _ = list3;
22}
23pub export fn entry3() void {
24 const U = struct {
25 comptime foo: u32 = 1,
26 bar: u32,
27 fn foo(x: @This()) void {
28 _ = x;
29 }
30 };
31 _ = U.foo(U{ .foo = 2, .bar = 2 });
32}
33pub export fn entry4() void {
34 const U = struct {
35 comptime foo: u32 = 1,
36 bar: u32,
37 fn foo(x: @This()) void {
38 _ = x;
39 }
40 };
41 _ = U.foo(.{ .foo = 2, .bar = 2 });
42}
43// pub export fn entry5() void {
44// var x: u32 = 15;
45// const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
46// const S = struct {
47// fn foo(_: T) void {}
48// };
49// _ = S.foo(.{ -1234, 5679, x });
50// }
51
52
1653// error
1754// target=native
1855// backend=stage2
1956//
2057// :6:19: error: value stored in comptime field does not match the default value of the field
2158// :14:19: error: value stored in comptime field does not match the default value of the field
59// :19:38: error: value stored in comptime field does not match the default value of the field
60// :31:19: error: value stored in comptime field does not match the default value of the field
61// :25:29: note: default value set here
62// :41:16: error: value stored in comptime field does not match the default value of the field
test/cases/compile_errors/method_call_with_first_arg_type_primitive.zig+2-1
......@@ -18,4 +18,5 @@ export fn f() void {
1818// backend=stage2
1919// target=native
2020//
21// :14:9: error: type 'tmp.Foo' has no field or member function named 'init'
21// :14:9: error: no field or member function named 'init' in 'tmp.Foo'
22// :1:13: note: struct declared here
test/cases/compile_errors/method_call_with_first_arg_type_wrong_container.zig+2-1
......@@ -27,4 +27,5 @@ export fn foo() void {
2727// backend=llvm
2828// target=native
2929//
30// :23:6: error: type 'tmp.List' has no field or member function named 'init'
30// :23:6: error: no field or member function named 'init' in 'tmp.List'
31// :1:14: note: struct declared here
test/cases/compile_errors/stage1/obj/bad_alignCast_at_comptime.zig deleted-11
......@@ -1,11 +0,0 @@
1comptime {
2 const ptr = @intToPtr(*align(1) i32, 0x1);
3 const aligned = @alignCast(4, ptr);
4 _ = aligned;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes
test/cases/compile_errors/stage1/test/duplicate_field_in_anonymous_struct_literal.zig deleted-19
......@@ -1,19 +0,0 @@
1export fn entry() void {
2 const anon = .{
3 .inner = .{
4 .a = .{
5 .something = "text",
6 },
7 .a = .{},
8 },
9 };
10 _ = anon;
11}
12
13// error
14// backend=stage1
15// target=native
16// is_test=1
17//
18// tmp.zig:7:13: error: duplicate field
19// tmp.zig:4:13: note: other field here
test/cases/compile_errors/stage2/union_extra_field.zig+1-1
......@@ -16,5 +16,5 @@ export fn entry() usize {
1616// error
1717// target=native
1818//
19// :10:5: error: enum 'tmp.E' has no field named 'd'
19// :10:5: error: no field named 'd' in enum 'tmp.E'
2020// :1:11: note: enum declared here
test/cases/compile_errors/wrong_initializer_for_union_payload_of_type_type.zig+1-2
......@@ -13,5 +13,4 @@ export fn entry() void {
1313// backend=stage2
1414// target=native
1515//
16// :9:14: error: expected type 'type', found 'tmp.U'
17// :1:11: note: union declared here
16// :9:8: error: use of undefined value here causes undefined behavior
test/cases/safety/@alignCast misaligned.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "incorrect alignment")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -18,5 +20,5 @@ fn foo(bytes: []u8) u32 {
1820 return int_slice[0];
1921}
2022// run
21// backend=stage1
22// target=native
\ No newline at end of file
23// backend=llvm
24// target=native
test/cases/safety/@errSetCast error not present in destination.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "invalid error code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810const Set1 = error{A, B};
911const Set2 = error{A, C};
......@@ -15,5 +17,5 @@ fn foo(set1: Set1) Set2 {
1517 return @errSetCast(Set2, set1);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/@floatToInt cannot fit - negative out of range.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 baz(bar(-129.1));
......@@ -14,5 +16,5 @@ fn bar(a: f32) i8 {
1416}
1517fn baz(_: i8) void { }
1618// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 baz(bar(-1.1));
......@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
1416}
1517fn baz(_: u8) void { }
1618// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/@floatToInt cannot fit - positive out of range.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 baz(bar(256.2));
......@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
1416}
1517fn baz(_: u8) void { }
1618// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/@intCast to u0.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -16,5 +18,5 @@ fn bar(one: u1, not_zero: i32) void {
1618 _ = x;
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/safety/@intToPtr address zero to non-optional byte-aligned pointer.zig +5-3
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "cast causes pointer to be null")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var zero: usize = 0;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
17// backend=llvm
1618// target=native
test/cases/safety/@intToPtr address zero to non-optional pointer.zig +5-3
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "cast causes pointer to be null")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var zero: usize = 0;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
17// backend=llvm
1618// target=native
test/cases/safety/bad union field access.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "access of inactive union field")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911const Foo = union {
......@@ -21,5 +23,5 @@ fn bar(f: *Foo) void {
2123 f.float = 12.34;
2224}
2325// run
24// backend=stage1
25// target=native
\ No newline at end of file
26// backend=llvm
27// target=native
test/cases/safety/calling panic.zig +2-2
......@@ -12,5 +12,5 @@ pub fn main() !void {
1212 return error.TestFailed;
1313}
1414// run
15// backend=stage1
16// target=native
\ No newline at end of file
15// backend=llvm
16// target=native
test/cases/safety/cast integer to global error and no code matches.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "invalid error code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 bar(9999) catch {};
......@@ -13,5 +15,5 @@ fn bar(x: u16) anyerror {
1315 return @intToError(x);
1416}
1517// run
16// backend=stage1
17// target=native
\ No newline at end of file
18// backend=llvm
19// target=native
test/cases/safety/exact division failure - vectors.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "exact division produced remainder")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
1719 return @divExact(a, b);
1820}
1921// run
20// backend=stage1
21// target=native
\ No newline at end of file
22// backend=llvm
23// target=native
test/cases/safety/exact division failure.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "exact division produced remainder")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 {
1517 return @divExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/intToPtr with misaligned address.zig +1-1
......@@ -14,5 +14,5 @@ pub fn main() !void {
1414 return error.TestFailed;
1515}
1616// run
17// backend=stage1
17// backend=llvm
1818// target=native
test/cases/safety/integer addition overflow.zig +1-1
......@@ -19,5 +19,5 @@ fn add(a: u16, b: u16) u16 {
1919}
2020
2121// run
22// backend=stage1
22// backend=llvm
2323// target=native
test/cases/safety/integer division by zero - vectors.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
......@@ -16,5 +18,5 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
1618 return @divTrunc(a, b);
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/safety/integer division by zero.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 const x = div0(999, 0);
......@@ -14,5 +16,5 @@ fn div0(a: i32, b: i32) i32 {
1416 return @divTrunc(a, b);
1517}
1618// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/integer multiplication overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn mul(a: u16, b: u16) u16 {
1517 return a * b;
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/integer negation overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn neg(a: i16) i16 {
1517 return -a;
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/integer subtraction overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn sub(a: u16, b: u16) u16 {
1517 return a - b;
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/optional unwrap operator on C pointer.zig +5-3
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "attempt to use null value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var ptr: [*c]i32 = null;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
17// backend=llvm
1618// target=native
test/cases/safety/optional unwrap operator on null pointer.zig +5-3
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "attempt to use null value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var ptr: ?*i32 = null;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
17// backend=llvm
1618// target=native
test/cases/safety/out of bounds slice access.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "attempt to index out of bound: index 4, len 4")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 const a = [_]i32{1, 2, 3, 4};
......@@ -15,5 +17,5 @@ fn bar(a: []const i32) i32 {
1517}
1618fn baz(_: i32) void { }
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/remainder division by negative number.zig created+20
......@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "remainder division by zero or negative value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = div0(999, -1);
12 _ = x;
13 return error.TestFailed;
14}
15fn div0(a: i32, b: i32) i32 {
16 return @rem(a, b);
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var value: c_short = -1;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
16// target=native
\ No newline at end of file
17// backend=llvm
18// target=native
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +6-5
......@@ -1,11 +1,12 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
8
910pub fn main() !void {
1011 const x = unsigned_cast(-10);
1112 if (x == 0) return error.Whatever;
......@@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 {
1516 return @intCast(u32, x);
1617}
1718// run
18// backend=stage1
19// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/signed shift left overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "left shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shl(a: i16, b: u4) i16 {
1517 return @shlExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/signed shift right overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "right shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 {
1517 return @shrExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/signed-unsigned vector cast.zig +1-1
......@@ -16,5 +16,5 @@ pub fn main() !void {
1616}
1717
1818// run
19// backend=stage1
19// backend=llvm
2020// target=native
test/cases/safety/truncating vector cast.zig +1-1
......@@ -16,5 +16,5 @@ pub fn main() !void {
1616}
1717
1818// run
19// backend=stage1
19// backend=llvm
2020// target=native
test/cases/safety/unreachable.zig created+15
......@@ -0,0 +1,15 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 unreachable;
12}
13// run
14// backend=llvm
15// target=native
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var value: u8 = 245;
......@@ -12,5 +14,5 @@ pub fn main() !void {
1214 return error.TestFailed;
1315}
1416// run
15// backend=stage1
16// target=native
\ No newline at end of file
17// backend=llvm
18// target=native
test/cases/safety/unsigned shift left overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "left shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shl(a: u16, b: u4) u16 {
1517 return @shlExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/unsigned shift right overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "right shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 {
1517 return @shrExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/unsigned-signed vector cast.zig +1-1
......@@ -16,5 +16,5 @@ pub fn main() !void {
1616}
1717
1818// run
19// backend=stage1
19// backend=llvm
2020// target=native
test/cases/safety/unwrap error.zig +2-2
......@@ -15,5 +15,5 @@ fn bar() !void {
1515 return error.Whatever;
1616}
1717// run
18// backend=stage1
19// target=native
\ No newline at end of file
18// backend=llvm
19// target=native
test/cases/safety/value does not fit in shortening cast - u0.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shorten_cast(x: u8) u0 {
1517 return @intCast(u0, x);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/value does not fit in shortening cast.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn shorten_cast(x: i32) i8 {
1517 return @intCast(i8, x);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/vector integer addition overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };
......@@ -16,5 +18,5 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
1618 return a + b;
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/safety/vector integer multiplication overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };
......@@ -16,5 +18,5 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
1618 return a * b;
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/safety/vector integer negation overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
......@@ -15,5 +17,5 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
1517 return -a;
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/vector integer subtraction overflow.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };
......@@ -16,5 +18,5 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
1618 return a - b;
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/x86_64-linux/hello_world_with_updates.0.zig+1
......@@ -3,3 +3,4 @@
33// target=x86_64-linux
44//
55// :107:9: error: struct 'tmp.tmp' has no member named 'main'
6// :7:1: note: struct declared here
test/cases/x86_64-macos/hello_world_with_updates.0.zig+1
......@@ -3,3 +3,4 @@
33// target=x86_64-macos
44//
55// :107:9: error: struct 'tmp.tmp' has no member named 'main'
6// :7:1: note: struct declared here
test/stage2/cbe.zig+1-1
......@@ -839,7 +839,7 @@ pub fn addCases(ctx: *TestContext) !void {
839839 \\ _ = x;
840840 \\}
841841 , &.{
842 ":3:17: error: enum 'tmp.E' has no field named 'd'",
842 ":3:17: error: no field named 'd' in enum 'tmp.E'",
843843 ":1:11: note: enum declared here",
844844 });
845845 }