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" {...@@ -813,6 +813,7 @@ test "conversion to f32" {
813test "conversion to f80" {813test "conversion to f80" {
814 if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64)814 if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64)
815 return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408815 return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408
816 if (std.debug.runtime_safety) return error.SkipZigTest;
816817
817 const intToFloat = @import("./int_to_float.zig").intToFloat;818 const intToFloat = @import("./int_to_float.zig").intToFloat;
818819
src/Air.zig+81-16
...@@ -38,11 +38,15 @@ pub const Inst = struct {...@@ -38,11 +38,15 @@ pub const Inst = struct {
38 /// is the same as both operands.38 /// is the same as both operands.
39 /// Uses the `bin_op` field.39 /// Uses the `bin_op` field.
40 add,40 add,
41 /// Same as `add` with optimized float mode.
42 add_optimized,
41 /// Integer addition. Wrapping is defined to be twos complement wrapping.43 /// Integer addition. Wrapping is defined to be twos complement wrapping.
42 /// Both operands are guaranteed to be the same type, and the result type44 /// Both operands are guaranteed to be the same type, and the result type
43 /// is the same as both operands.45 /// is the same as both operands.
44 /// Uses the `bin_op` field.46 /// Uses the `bin_op` field.
45 addwrap,47 addwrap,
48 /// Same as `addwrap` with optimized float mode.
49 addwrap_optimized,
46 /// Saturating integer addition.50 /// Saturating integer addition.
47 /// Both operands are guaranteed to be the same type, and the result type51 /// Both operands are guaranteed to be the same type, and the result type
48 /// is the same as both operands.52 /// is the same as both operands.
...@@ -53,11 +57,15 @@ pub const Inst = struct {...@@ -53,11 +57,15 @@ pub const Inst = struct {
53 /// is the same as both operands.57 /// is the same as both operands.
54 /// Uses the `bin_op` field.58 /// Uses the `bin_op` field.
55 sub,59 sub,
60 /// Same as `sub` with optimized float mode.
61 sub_optimized,
56 /// Integer subtraction. Wrapping is defined to be twos complement wrapping.62 /// Integer subtraction. Wrapping is defined to be twos complement wrapping.
57 /// Both operands are guaranteed to be the same type, and the result type63 /// Both operands are guaranteed to be the same type, and the result type
58 /// is the same as both operands.64 /// is the same as both operands.
59 /// Uses the `bin_op` field.65 /// Uses the `bin_op` field.
60 subwrap,66 subwrap,
67 /// Same as `sub` with optimized float mode.
68 subwrap_optimized,
61 /// Saturating integer subtraction.69 /// Saturating integer subtraction.
62 /// Both operands are guaranteed to be the same type, and the result type70 /// Both operands are guaranteed to be the same type, and the result type
63 /// is the same as both operands.71 /// is the same as both operands.
...@@ -68,11 +76,15 @@ pub const Inst = struct {...@@ -68,11 +76,15 @@ pub const Inst = struct {
68 /// is the same as both operands.76 /// is the same as both operands.
69 /// Uses the `bin_op` field.77 /// Uses the `bin_op` field.
70 mul,78 mul,
79 /// Same as `mul` with optimized float mode.
80 mul_optimized,
71 /// Integer multiplication. Wrapping is defined to be twos complement wrapping.81 /// Integer multiplication. Wrapping is defined to be twos complement wrapping.
72 /// Both operands are guaranteed to be the same type, and the result type82 /// Both operands are guaranteed to be the same type, and the result type
73 /// is the same as both operands.83 /// is the same as both operands.
74 /// Uses the `bin_op` field.84 /// Uses the `bin_op` field.
75 mulwrap,85 mulwrap,
86 /// Same as `mulwrap` with optimized float mode.
87 mulwrap_optimized,
76 /// Saturating integer multiplication.88 /// Saturating integer multiplication.
77 /// Both operands are guaranteed to be the same type, and the result type89 /// Both operands are guaranteed to be the same type, and the result type
78 /// is the same as both operands.90 /// is the same as both operands.
...@@ -83,32 +95,44 @@ pub const Inst = struct {...@@ -83,32 +95,44 @@ pub const Inst = struct {
83 /// is the same as both operands.95 /// is the same as both operands.
84 /// Uses the `bin_op` field.96 /// Uses the `bin_op` field.
85 div_float,97 div_float,
98 /// Same as `div_float` with optimized float mode.
99 div_float_optimized,
86 /// Truncating integer or float division. For integers, wrapping is undefined behavior.100 /// Truncating integer or float division. For integers, wrapping is undefined behavior.
87 /// Both operands are guaranteed to be the same type, and the result type101 /// Both operands are guaranteed to be the same type, and the result type
88 /// is the same as both operands.102 /// is the same as both operands.
89 /// Uses the `bin_op` field.103 /// Uses the `bin_op` field.
90 div_trunc,104 div_trunc,
105 /// Same as `div_trunc` with optimized float mode.
106 div_trunc_optimized,
91 /// Flooring integer or float division. For integers, wrapping is undefined behavior.107 /// Flooring integer or float division. For integers, wrapping is undefined behavior.
92 /// Both operands are guaranteed to be the same type, and the result type108 /// Both operands are guaranteed to be the same type, and the result type
93 /// is the same as both operands.109 /// is the same as both operands.
94 /// Uses the `bin_op` field.110 /// Uses the `bin_op` field.
95 div_floor,111 div_floor,
112 /// Same as `div_floor` with optimized float mode.
113 div_floor_optimized,
96 /// Integer or float division. Guaranteed no remainder.114 /// Integer or float division. Guaranteed no remainder.
97 /// For integers, wrapping is undefined behavior.115 /// For integers, wrapping is undefined behavior.
98 /// Both operands are guaranteed to be the same type, and the result type116 /// Both operands are guaranteed to be the same type, and the result type
99 /// is the same as both operands.117 /// is the same as both operands.
100 /// Uses the `bin_op` field.118 /// Uses the `bin_op` field.
101 div_exact,119 div_exact,
120 /// Same as `div_exact` with optimized float mode.
121 div_exact_optimized,
102 /// Integer or float remainder division.122 /// Integer or float remainder division.
103 /// Both operands are guaranteed to be the same type, and the result type123 /// Both operands are guaranteed to be the same type, and the result type
104 /// is the same as both operands.124 /// is the same as both operands.
105 /// Uses the `bin_op` field.125 /// Uses the `bin_op` field.
106 rem,126 rem,
127 /// Same as `rem` with optimized float mode.
128 rem_optimized,
107 /// Integer or float modulus division.129 /// Integer or float modulus division.
108 /// Both operands are guaranteed to be the same type, and the result type130 /// Both operands are guaranteed to be the same type, and the result type
109 /// is the same as both operands.131 /// is the same as both operands.
110 /// Uses the `bin_op` field.132 /// Uses the `bin_op` field.
111 mod,133 mod,
134 /// Same as `mod` with optimized float mode.
135 mod_optimized,
112 /// Add an offset to a pointer, returning a new pointer.136 /// Add an offset to a pointer, returning a new pointer.
113 /// The offset is in element type units, not bytes.137 /// The offset is in element type units, not bytes.
114 /// Wrapping is undefined behavior.138 /// Wrapping is undefined behavior.
...@@ -293,29 +317,45 @@ pub const Inst = struct {...@@ -293,29 +317,45 @@ pub const Inst = struct {
293 /// LHS of zero.317 /// LHS of zero.
294 /// Uses the `un_op` field.318 /// Uses the `un_op` field.
295 neg,319 neg,
320 /// Same as `neg` with optimized float mode.
321 neg_optimized,
296322
297 /// `<`. Result type is always bool.323 /// `<`. Result type is always bool.
298 /// Uses the `bin_op` field.324 /// Uses the `bin_op` field.
299 cmp_lt,325 cmp_lt,
326 /// Same as `cmp_lt` with optimized float mode.
327 cmp_lt_optimized,
300 /// `<=`. Result type is always bool.328 /// `<=`. Result type is always bool.
301 /// Uses the `bin_op` field.329 /// Uses the `bin_op` field.
302 cmp_lte,330 cmp_lte,
331 /// Same as `cmp_lte` with optimized float mode.
332 cmp_lte_optimized,
303 /// `==`. Result type is always bool.333 /// `==`. Result type is always bool.
304 /// Uses the `bin_op` field.334 /// Uses the `bin_op` field.
305 cmp_eq,335 cmp_eq,
336 /// Same as `cmp_eq` with optimized float mode.
337 cmp_eq_optimized,
306 /// `>=`. Result type is always bool.338 /// `>=`. Result type is always bool.
307 /// Uses the `bin_op` field.339 /// Uses the `bin_op` field.
308 cmp_gte,340 cmp_gte,
341 /// Same as `cmp_gte` with optimized float mode.
342 cmp_gte_optimized,
309 /// `>`. Result type is always bool.343 /// `>`. Result type is always bool.
310 /// Uses the `bin_op` field.344 /// Uses the `bin_op` field.
311 cmp_gt,345 cmp_gt,
346 /// Same as `cmp_gt` with optimized float mode.
347 cmp_gt_optimized,
312 /// `!=`. Result type is always bool.348 /// `!=`. Result type is always bool.
313 /// Uses the `bin_op` field.349 /// Uses the `bin_op` field.
314 cmp_neq,350 cmp_neq,
351 /// Same as `cmp_neq` with optimized float mode.
352 cmp_neq_optimized,
315 /// Conditional between two vectors.353 /// Conditional between two vectors.
316 /// Result type is always a vector of bools.354 /// Result type is always a vector of bools.
317 /// Uses the `ty_pl` field, payload is `VectorCmp`.355 /// Uses the `ty_pl` field, payload is `VectorCmp`.
318 cmp_vector,356 cmp_vector,
357 /// Same as `cmp_vector` with optimized float mode.
358 cmp_vector_optimized,
319359
320 /// Conditional branch.360 /// Conditional branch.
321 /// Result type is always noreturn; no instructions in a block follow this one.361 /// Result type is always noreturn; no instructions in a block follow this one.
...@@ -553,6 +593,8 @@ pub const Inst = struct {...@@ -553,6 +593,8 @@ pub const Inst = struct {
553 /// Given a float operand, return the integer with the closest mathematical meaning.593 /// Given a float operand, return the integer with the closest mathematical meaning.
554 /// Uses the `ty_op` field.594 /// Uses the `ty_op` field.
555 float_to_int,595 float_to_int,
596 /// Same as `float_to_int` with optimized float mode.
597 float_to_int_optimized,
556 /// Given an integer operand, return the float with the closest mathematical meaning.598 /// Given an integer operand, return the float with the closest mathematical meaning.
557 /// Uses the `ty_op` field.599 /// Uses the `ty_op` field.
558 int_to_float,600 int_to_float,
...@@ -564,6 +606,8 @@ pub const Inst = struct {...@@ -564,6 +606,8 @@ pub const Inst = struct {
564 /// * min, max, add, mul => integer or float606 /// * min, max, add, mul => integer or float
565 /// Uses the `reduce` field.607 /// Uses the `reduce` field.
566 reduce,608 reduce,
609 /// Same as `reduce` with optimized float mode.
610 reduce_optimized,
567 /// Given an integer, bool, float, or pointer operand, return a vector with all elements611 /// Given an integer, bool, float, or pointer operand, return a vector with all elements
568 /// equal to the scalar value.612 /// equal to the scalar value.
569 /// Uses the `ty_op` field.613 /// Uses the `ty_op` field.
...@@ -676,25 +720,25 @@ pub const Inst = struct {...@@ -676,25 +720,25 @@ pub const Inst = struct {
676 /// Sets the operand as the current error return trace,720 /// Sets the operand as the current error return trace,
677 set_err_return_trace,721 set_err_return_trace,
678722
679 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {723 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
680 return switch (op) {724 switch (op) {
681 .lt => .cmp_lt,725 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
682 .lte => .cmp_lte,726 .lte => return if (optimized) .cmp_lte_optimized else .cmp_lte,
683 .eq => .cmp_eq,727 .eq => return if (optimized) .cmp_eq_optimized else .cmp_eq,
684 .gte => .cmp_gte,728 .gte => return if (optimized) .cmp_gte_optimized else .cmp_gte,
685 .gt => .cmp_gt,729 .gt => return if (optimized) .cmp_gt_optimized else .cmp_gt,
686 .neq => .cmp_neq,730 .neq => return if (optimized) .cmp_neq_optimized else .cmp_neq,
687 };731 }
688 }732 }
689733
690 pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator {734 pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator {
691 return switch (tag) {735 return switch (tag) {
692 .cmp_lt => .lt,736 .cmp_lt, .cmp_lt_optimized => .lt,
693 .cmp_lte => .lte,737 .cmp_lte, .cmp_lte_optimized => .lte,
694 .cmp_eq => .eq,738 .cmp_eq, .cmp_eq_optimized => .eq,
695 .cmp_gte => .gte,739 .cmp_gte, .cmp_gte_optimized => .gte,
696 .cmp_gt => .gt,740 .cmp_gt, .cmp_gt_optimized => .gt,
697 .cmp_neq => .neq,741 .cmp_neq, .cmp_neq_optimized => .neq,
698 else => null,742 else => null,
699 };743 };
700 }744 }
...@@ -959,6 +1003,18 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -959,6 +1003,18 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
959 .max,1003 .max,
960 .bool_and,1004 .bool_and,
961 .bool_or,1005 .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,
962 => return air.typeOf(datas[inst].bin_op.lhs),1018 => return air.typeOf(datas[inst].bin_op.lhs),
9631019
964 .sqrt,1020 .sqrt,
...@@ -976,6 +1032,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -976,6 +1032,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
976 .round,1032 .round,
977 .trunc_float,1033 .trunc_float,
978 .neg,1034 .neg,
1035 .neg_optimized,
979 => return air.typeOf(datas[inst].un_op),1036 => return air.typeOf(datas[inst].un_op),
9801037
981 .cmp_lt,1038 .cmp_lt,
...@@ -984,6 +1041,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -984,6 +1041,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
984 .cmp_gte,1041 .cmp_gte,
985 .cmp_gt,1042 .cmp_gt,
986 .cmp_neq,1043 .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,
987 .cmp_lt_errors_len,1050 .cmp_lt_errors_len,
988 .is_null,1051 .is_null,
989 .is_non_null,1052 .is_non_null,
...@@ -1018,6 +1081,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1018,6 +1081,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1018 .union_init,1081 .union_init,
1019 .field_parent_ptr,1082 .field_parent_ptr,
1020 .cmp_vector,1083 .cmp_vector,
1084 .cmp_vector_optimized,
1021 .add_with_overflow,1085 .add_with_overflow,
1022 .sub_with_overflow,1086 .sub_with_overflow,
1023 .mul_with_overflow,1087 .mul_with_overflow,
...@@ -1054,6 +1118,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1054,6 +1118,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1054 .struct_field_ptr_index_3,1118 .struct_field_ptr_index_3,
1055 .array_to_slice,1119 .array_to_slice,
1056 .float_to_int,1120 .float_to_int,
1121 .float_to_int_optimized,
1057 .int_to_float,1122 .int_to_float,
1058 .splat,1123 .splat,
1059 .get_union_tag,1124 .get_union_tag,
...@@ -1129,7 +1194,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1129,7 +1194,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1129 return ptr_ty.elemType();1194 return ptr_ty.elemType();
1130 },1195 },
11311196
1132 .reduce => return air.typeOf(datas[inst].reduce.operand).childType(),1197 .reduce, .reduce_optimized => return air.typeOf(datas[inst].reduce.operand).childType(),
11331198
1134 .mul_add => return air.typeOf(datas[inst].pl_op.operand),1199 .mul_add => return air.typeOf(datas[inst].pl_op.operand),
1135 .select => {1200 .select => {
src/AstGen.zig+12-7
...@@ -1589,13 +1589,12 @@ fn structInitExpr(...@@ -1589,13 +1589,12 @@ fn structInitExpr(
15891589
1590 switch (rl) {1590 switch (rl) {
1591 .discard => {1591 .discard => {
1592 // TODO if a type expr is given the fields should be validated for that type
1593 if (struct_init.ast.type_expr != 0) {1592 if (struct_init.ast.type_expr != 0) {
1594 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1593 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1595 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);1594 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1596 }1595 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1597 for (struct_init.ast.fields) |field_init| {1596 } else {
1598 _ = try expr(gz, scope, .discard, field_init);1597 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
1599 }1598 }
1600 return Zir.Inst.Ref.void_value;1599 return Zir.Inst.Ref.void_value;
1601 },1600 },
...@@ -1729,7 +1728,7 @@ fn structInitExprRlPtrInner(...@@ -1729,7 +1728,7 @@ fn structInitExprRlPtrInner(
1729 for (struct_init.ast.fields) |field_init| {1728 for (struct_init.ast.fields) |field_init| {
1730 const name_token = tree.firstToken(field_init) - 2;1729 const name_token = tree.firstToken(field_init) - 2;
1731 const str_index = try astgen.identAsString(name_token);1730 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{
1733 .lhs = result_ptr,1732 .lhs = result_ptr,
1734 .field_name_start = str_index,1733 .field_name_start = str_index,
1735 });1734 });
...@@ -2287,6 +2286,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2287,6 +2286,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2287 .elem_ptr_imm,2286 .elem_ptr_imm,
2288 .elem_val_node,2287 .elem_val_node,
2289 .field_ptr,2288 .field_ptr,
2289 .field_ptr_init,
2290 .field_val,2290 .field_val,
2291 .field_call_bind,2291 .field_call_bind,
2292 .field_ptr_named,2292 .field_ptr_named,
...@@ -4213,6 +4213,12 @@ fn structDeclInner(...@@ -4213,6 +4213,12 @@ fn structDeclInner(
4213 const have_value = member.ast.value_expr != 0;4213 const have_value = member.ast.value_expr != 0;
4214 const is_comptime = member.comptime_token != null;4214 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
4216 if (!is_comptime) {4222 if (!is_comptime) {
4217 known_non_opv = known_non_opv or4223 known_non_opv = known_non_opv or
4218 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);4224 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
...@@ -6504,8 +6510,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6504,8 +6510,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6504 },6510 },
6505 .always => {6511 .always => {
6506 // Value is always an error. Emit both error defers and regular defers.6512 // 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;6513 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6508 const err_code = try gz.addUnNode(.err_union_code, result, node);
6509 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6514 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6510 try gz.addRet(rl, operand, node);6515 try gz.addRet(rl, operand, node);
6511 return Zir.Inst.Ref.unreachable_value;6516 return Zir.Inst.Ref.unreachable_value;
src/Liveness.zig+44-4
...@@ -173,6 +173,25 @@ pub fn categorizeOperand(...@@ -173,6 +173,25 @@ pub fn categorizeOperand(
173 .shr_exact,173 .shr_exact,
174 .min,174 .min,
175 .max,175 .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,
176 => {195 => {
177 const o = air_datas[inst].bin_op;196 const o = air_datas[inst].bin_op;
178 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);197 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
...@@ -239,6 +258,7 @@ pub fn categorizeOperand(...@@ -239,6 +258,7 @@ pub fn categorizeOperand(
239 .struct_field_ptr_index_3,258 .struct_field_ptr_index_3,
240 .array_to_slice,259 .array_to_slice,
241 .float_to_int,260 .float_to_int,
261 .float_to_int_optimized,
242 .int_to_float,262 .int_to_float,
243 .get_union_tag,263 .get_union_tag,
244 .clz,264 .clz,
...@@ -381,12 +401,12 @@ pub fn categorizeOperand(...@@ -381,12 +401,12 @@ pub fn categorizeOperand(
381 if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);401 if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
382 return .none;402 return .none;
383 },403 },
384 .reduce => {404 .reduce, .reduce_optimized => {
385 const reduce = air_datas[inst].reduce;405 const reduce = air_datas[inst].reduce;
386 if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);406 if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
387 return .none;407 return .none;
388 },408 },
389 .cmp_vector => {409 .cmp_vector, .cmp_vector_optimized => {
390 const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data;410 const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data;
391 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);411 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
392 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);412 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
...@@ -701,29 +721,47 @@ fn analyzeInst(...@@ -701,29 +721,47 @@ fn analyzeInst(
701721
702 switch (inst_tags[inst]) {722 switch (inst_tags[inst]) {
703 .add,723 .add,
724 .add_optimized,
704 .addwrap,725 .addwrap,
726 .addwrap_optimized,
705 .add_sat,727 .add_sat,
706 .sub,728 .sub,
729 .sub_optimized,
707 .subwrap,730 .subwrap,
731 .subwrap_optimized,
708 .sub_sat,732 .sub_sat,
709 .mul,733 .mul,
734 .mul_optimized,
710 .mulwrap,735 .mulwrap,
736 .mulwrap_optimized,
711 .mul_sat,737 .mul_sat,
712 .div_float,738 .div_float,
739 .div_float_optimized,
713 .div_trunc,740 .div_trunc,
741 .div_trunc_optimized,
714 .div_floor,742 .div_floor,
743 .div_floor_optimized,
715 .div_exact,744 .div_exact,
745 .div_exact_optimized,
716 .rem,746 .rem,
747 .rem_optimized,
717 .mod,748 .mod,
749 .mod_optimized,
718 .bit_and,750 .bit_and,
719 .bit_or,751 .bit_or,
720 .xor,752 .xor,
721 .cmp_lt,753 .cmp_lt,
754 .cmp_lt_optimized,
722 .cmp_lte,755 .cmp_lte,
756 .cmp_lte_optimized,
723 .cmp_eq,757 .cmp_eq,
758 .cmp_eq_optimized,
724 .cmp_gte,759 .cmp_gte,
760 .cmp_gte_optimized,
725 .cmp_gt,761 .cmp_gt,
762 .cmp_gt_optimized,
726 .cmp_neq,763 .cmp_neq,
764 .cmp_neq_optimized,
727 .bool_and,765 .bool_and,
728 .bool_or,766 .bool_or,
729 .store,767 .store,
...@@ -794,6 +832,7 @@ fn analyzeInst(...@@ -794,6 +832,7 @@ fn analyzeInst(
794 .struct_field_ptr_index_3,832 .struct_field_ptr_index_3,
795 .array_to_slice,833 .array_to_slice,
796 .float_to_int,834 .float_to_int,
835 .float_to_int_optimized,
797 .int_to_float,836 .int_to_float,
798 .get_union_tag,837 .get_union_tag,
799 .clz,838 .clz,
...@@ -836,6 +875,7 @@ fn analyzeInst(...@@ -836,6 +875,7 @@ fn analyzeInst(
836 .round,875 .round,
837 .trunc_float,876 .trunc_float,
838 .neg,877 .neg,
878 .neg_optimized,
839 .cmp_lt_errors_len,879 .cmp_lt_errors_len,
840 .set_err_return_trace,880 .set_err_return_trace,
841 => {881 => {
...@@ -903,11 +943,11 @@ fn analyzeInst(...@@ -903,11 +943,11 @@ fn analyzeInst(
903 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;943 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;
904 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });944 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
905 },945 },
906 .reduce => {946 .reduce, .reduce_optimized => {
907 const reduce = inst_datas[inst].reduce;947 const reduce = inst_datas[inst].reduce;
908 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });948 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
909 },949 },
910 .cmp_vector => {950 .cmp_vector, .cmp_vector_optimized => {
911 const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data;951 const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data;
912 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });952 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
913 },953 },
src/Module.zig+69-1
...@@ -787,7 +787,7 @@ pub const Decl = struct {...@@ -787,7 +787,7 @@ pub const Decl = struct {
787 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data;787 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data;
788 return &opaque_obj.namespace;788 return &opaque_obj.namespace;
789 },789 },
790 .@"union", .union_tagged => {790 .@"union", .union_safety_tagged, .union_tagged => {
791 const union_obj = ty.cast(Type.Payload.Union).?.data;791 const union_obj = ty.cast(Type.Payload.Union).?.data;
792 return &union_obj.namespace;792 return &union_obj.namespace;
793 },793 },
...@@ -2704,6 +2704,18 @@ pub const SrcLoc = struct {...@@ -2704,6 +2704,18 @@ pub const SrcLoc = struct {
2704 else => unreachable,2704 else => unreachable,
2705 }2705 }
2706 },2706 },
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 },
2707 }2719 }
2708 }2720 }
27092721
...@@ -3021,6 +3033,9 @@ pub const LazySrcLoc = union(enum) {...@@ -3021,6 +3033,9 @@ pub const LazySrcLoc = union(enum) {
3021 /// The source location points to the tag type of an union or an enum.3033 /// The source location points to the tag type of an union or an enum.
3022 /// The Decl is determined contextually.3034 /// The Decl is determined contextually.
3023 node_offset_container_tag: i32,3035 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
3025 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;3040 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
30263041
...@@ -3098,6 +3113,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3098,6 +3113,7 @@ pub const LazySrcLoc = union(enum) {
3098 .node_offset_ptr_bitoffset,3113 .node_offset_ptr_bitoffset,
3099 .node_offset_ptr_hostsize,3114 .node_offset_ptr_hostsize,
3100 .node_offset_container_tag,3115 .node_offset_container_tag,
3116 .node_offset_field_default,
3101 => .{3117 => .{
3102 .file_scope = decl.getFileScope(),3118 .file_scope = decl.getFileScope(),
3103 .parent_decl_node = decl.src_node,3119 .parent_decl_node = decl.src_node,
...@@ -5936,6 +5952,58 @@ pub fn argSrc(...@@ -5936,6 +5952,58 @@ pub fn argSrc(
5936 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i]));5952 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i]));
5937}5953}
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
5939/// Called from `performAllTheWork`, after all AstGen workers have finished,6007/// Called from `performAllTheWork`, after all AstGen workers have finished,
5940/// and before the main semantic analysis loop begins.6008/// and before the main semantic analysis loop begins.
5941pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {6009pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+470-179
...@@ -144,6 +144,9 @@ pub const Block = struct {...@@ -144,6 +144,9 @@ pub const Block = struct {
144 /// when null, it is determined by build mode, changed by @setRuntimeSafety144 /// when null, it is determined by build mode, changed by @setRuntimeSafety
145 want_safety: ?bool = null,145 want_safety: ?bool = null,
146146
147 /// What mode to generate float operations in, set by @setFloatMode
148 float_mode: std.builtin.FloatMode = .Strict,
149
147 c_import_buf: ?*std.ArrayList(u8) = null,150 c_import_buf: ?*std.ArrayList(u8) = null,
148151
149 /// type of `err` in `else => |err|`152 /// type of `err` in `else => |err|`
...@@ -206,6 +209,7 @@ pub const Block = struct {...@@ -206,6 +209,7 @@ pub const Block = struct {
206 .runtime_loop = parent.runtime_loop,209 .runtime_loop = parent.runtime_loop,
207 .runtime_index = parent.runtime_index,210 .runtime_index = parent.runtime_index,
208 .want_safety = parent.want_safety,211 .want_safety = parent.want_safety,
212 .float_mode = parent.float_mode,
209 .c_import_buf = parent.c_import_buf,213 .c_import_buf = parent.c_import_buf,
210 .switch_else_err_ty = parent.switch_else_err_ty,214 .switch_else_err_ty = parent.switch_else_err_ty,
211 };215 };
...@@ -414,7 +418,7 @@ pub const Block = struct {...@@ -414,7 +418,7 @@ pub const Block = struct {
414418
415 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 {419 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 {
416 return block.addInst(.{420 return block.addInst(.{
417 .tag = .cmp_vector,421 .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
418 .data = .{ .ty_pl = .{422 .data = .{ .ty_pl = .{
419 .ty = vector_ty,423 .ty = vector_ty,
420 .payload = try block.sema.addExtra(Air.VectorCmp{424 .payload = try block.sema.addExtra(Air.VectorCmp{
...@@ -714,10 +718,10 @@ fn analyzeBodyInner(...@@ -714,10 +718,10 @@ fn analyzeBodyInner(
714 .closure_get => try sema.zirClosureGet(block, inst),718 .closure_get => try sema.zirClosureGet(block, inst),
715 .cmp_lt => try sema.zirCmp(block, inst, .lt),719 .cmp_lt => try sema.zirCmp(block, inst, .lt),
716 .cmp_lte => try sema.zirCmp(block, inst, .lte),720 .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)),
718 .cmp_gte => try sema.zirCmp(block, inst, .gte),722 .cmp_gte => try sema.zirCmp(block, inst, .gte),
719 .cmp_gt => try sema.zirCmp(block, inst, .gt),723 .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)),
721 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),725 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
722 .decl_ref => try sema.zirDeclRef(block, inst),726 .decl_ref => try sema.zirDeclRef(block, inst),
723 .decl_val => try sema.zirDeclVal(block, inst),727 .decl_val => try sema.zirDeclVal(block, inst),
...@@ -739,7 +743,8 @@ fn analyzeBodyInner(...@@ -739,7 +743,8 @@ fn analyzeBodyInner(
739 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),743 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
740 .error_union_type => try sema.zirErrorUnionType(block, inst),744 .error_union_type => try sema.zirErrorUnionType(block, inst),
741 .error_value => try sema.zirErrorValue(block, inst),745 .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),
743 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),748 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
744 .field_val => try sema.zirFieldVal(block, inst),749 .field_val => try sema.zirFieldVal(block, inst),
745 .field_val_named => try sema.zirFieldValNamed(block, inst),750 .field_val_named => try sema.zirFieldValNamed(block, inst),
...@@ -1547,11 +1552,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)...@@ -1547,11 +1552,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
1547 const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));1552 const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));
15481553
1549 // st.instruction_addresses = &addrs;1554 // 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);
1551 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);1556 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
15521557
1553 // st.index = 0;1558 // 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);
1555 const zero = try sema.addConstant(Type.usize, Value.zero);1560 const zero = try sema.addConstant(Type.usize, Value.zero);
1556 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store);1561 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:...@@ -1784,6 +1789,24 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
1784 });1789 });
1785}1790}
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
1787/// We don't return a pointer to the new error note because the pointer1810/// We don't return a pointer to the new error note because the pointer
1788/// becomes invalid when you add another one.1811/// becomes invalid when you add another one.
1789fn errNote(1812fn errNote(
...@@ -2614,7 +2637,14 @@ fn zirUnionDecl(...@@ -2614,7 +2637,14 @@ fn zirUnionDecl(
2614 const new_decl_arena_allocator = new_decl_arena.allocator();2637 const new_decl_arena_allocator = new_decl_arena.allocator();
26152638
2616 const union_obj = try new_decl_arena_allocator.create(Module.Union);2639 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 };
2618 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);2648 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
2619 union_payload.* = .{2649 union_payload.* = .{
2620 .base = .{ .tag = type_tag },2650 .base = .{ .tag = type_tag },
...@@ -3651,7 +3681,10 @@ fn validateStructInit(...@@ -3651,7 +3681,10 @@ fn validateStructInit(
3651 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;3681 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
3652 struct_ptr_zir_ref = field_ptr_extra.lhs;3682 struct_ptr_zir_ref = field_ptr_extra.lhs;
3653 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);3683 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);
3655 if (found_fields[field_index] != 0) {3688 if (found_fields[field_index] != 0) {
3656 const other_field_ptr = found_fields[field_index];3689 const other_field_ptr = found_fields[field_index];
3657 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;3690 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
...@@ -3693,7 +3726,7 @@ fn validateStructInit(...@@ -3693,7 +3726,7 @@ fn validateStructInit(
3693 }3726 }
36943727
3695 const field_src = init_src; // TODO better source location3728 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);
3697 const field_ty = sema.typeOf(default_field_ptr).childType();3730 const field_ty = sema.typeOf(default_field_ptr).childType();
3698 const init = try sema.addConstant(field_ty, default_val);3731 const init = try sema.addConstant(field_ty, default_val);
3699 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3732 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
...@@ -3851,7 +3884,7 @@ fn validateStructInit(...@@ -3851,7 +3884,7 @@ fn validateStructInit(
3851 if (field_ptr != 0) continue;3884 if (field_ptr != 0) continue;
38523885
3853 const field_src = init_src; // TODO better source location3886 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);
3855 const field_ty = sema.typeOf(default_field_ptr).childType();3888 const field_ty = sema.typeOf(default_field_ptr).childType();
3856 const init = try sema.addConstant(field_ty, field_values[i]);3889 const init = try sema.addConstant(field_ty, field_values[i]);
3857 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);3890 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...@@ -4694,6 +4727,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
4694 .inlining = parent_block.inlining,4727 .inlining = parent_block.inlining,
4695 .is_comptime = parent_block.is_comptime,4728 .is_comptime = parent_block.is_comptime,
4696 .want_safety = parent_block.want_safety,4729 .want_safety = parent_block.want_safety,
4730 .float_mode = parent_block.float_mode,
4697 };4731 };
46984732
4699 defer child_block.instructions.deinit(gpa);4733 defer child_block.instructions.deinit(gpa);
...@@ -5031,13 +5065,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi...@@ -5031,13 +5065,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
5031fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {5065fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
5032 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;5066 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
5033 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };5067 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");5068 block.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 }
5041}5069}
50425070
5043fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5071fn 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...@@ -6786,12 +6814,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
6786 .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },6814 .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
6787 );6815 );
6788 errdefer msg.destroy(sema.gpa);6816 errdefer msg.destroy(sema.gpa);
6789 try sema.mod.errNoteNonLazy(6817 try sema.addDeclaredHereNote(msg, dest_ty);
6790 dest_ty.declSrcLoc(sema.mod),
6791 msg,
6792 "enum declared here",
6793 .{},
6794 );
6795 break :msg msg;6818 break :msg msg;
6796 };6819 };
6797 return sema.failWithOwnedErrorMsg(block, msg);6820 return sema.failWithOwnedErrorMsg(block, msg);
...@@ -7923,7 +7946,7 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -7923,7 +7946,7 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
7923 return sema.fieldVal(block, src, object, field_name, field_name_src);7946 return sema.fieldVal(block, src, object, field_name, field_name_src);
7924}7947}
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 {
7927 const tracy = trace(@src());7950 const tracy = trace(@src());
7928 defer tracy.end();7951 defer tracy.end();
79297952
...@@ -7933,7 +7956,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -7933,7 +7956,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
7933 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;7956 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
7934 const field_name = sema.code.nullTerminatedString(extra.field_name_start);7957 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
7935 const object_ptr = try sema.resolveInst(extra.lhs);7958 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);
7937}7960}
79387961
7939fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {7962fn 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...@@ -7972,7 +7995,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
7972 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;7995 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
7973 const object_ptr = try sema.resolveInst(extra.lhs);7996 const object_ptr = try sema.resolveInst(extra.lhs);
7974 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");7997 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);
7976}7999}
79778000
7978fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {8001fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
...@@ -8081,7 +8104,7 @@ fn intCast(...@@ -8081,7 +8104,7 @@ fn intCast(
8081 const ok = if (is_vector) ok: {8104 const ok = if (is_vector) ok: {
8082 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));8105 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
8083 const all_in_range = try block.addInst(.{8106 const all_in_range = try block.addInst(.{
8084 .tag = .reduce,8107 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
8085 .data = .{ .reduce = .{8108 .data = .{ .reduce = .{
8086 .operand = is_in_range,8109 .operand = is_in_range,
8087 .operation = .And,8110 .operation = .And,
...@@ -8092,12 +8115,13 @@ fn intCast(...@@ -8092,12 +8115,13 @@ fn intCast(
8092 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);8115 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
8093 break :ok is_in_range;8116 break :ok is_in_range;
8094 };8117 };
8118 // TODO negative_to_unsigned?
8095 try sema.addSafetyCheck(block, ok, .cast_truncated_data);8119 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
8096 } else {8120 } else {
8097 const ok = if (is_vector) ok: {8121 const ok = if (is_vector) ok: {
8098 const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));8122 const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
8099 const all_in_range = try block.addInst(.{8123 const all_in_range = try block.addInst(.{
8100 .tag = .reduce,8124 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
8101 .data = .{ .reduce = .{8125 .data = .{ .reduce = .{
8102 .operand = is_in_range,8126 .operand = is_in_range,
8103 .operation = .And,8127 .operation = .And,
...@@ -8116,9 +8140,9 @@ fn intCast(...@@ -8116,9 +8140,9 @@ fn intCast(
8116 const ok = if (is_vector) ok: {8140 const ok = if (is_vector) ok: {
8117 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);8141 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
8118 const zero_inst = try sema.addConstant(operand_ty, zero_val);8142 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));
8120 const all_in_range = try block.addInst(.{8144 const all_in_range = try block.addInst(.{
8121 .tag = .reduce,8145 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
8122 .data = .{ .reduce = .{8146 .data = .{ .reduce = .{
8123 .operand = is_in_range,8147 .operand = is_in_range,
8124 .operation = .And,8148 .operation = .And,
...@@ -8130,7 +8154,7 @@ fn intCast(...@@ -8130,7 +8154,7 @@ fn intCast(
8130 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);8154 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
8131 break :ok is_in_range;8155 break :ok is_in_range;
8132 };8156 };
8133 try sema.addSafetyCheck(block, ok, .cast_truncated_data);8157 try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
8134 }8158 }
8135 }8159 }
8136 return block.addTyOp(.intcast, dest_ty, operand);8160 return block.addTyOp(.intcast, dest_ty, operand);
...@@ -9379,7 +9403,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9379,7 +9403,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9379 } else {9403 } else {
9380 for (items) |item_ref| {9404 for (items) |item_ref| {
9381 const item = try sema.resolveInst(item_ref);9405 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);
9383 if (any_ok != .none) {9407 if (any_ok != .none) {
9384 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);9408 any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
9385 } else {9409 } else {
...@@ -9399,12 +9423,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9399,12 +9423,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
93999423
9400 // operand >= first and operand <= last9424 // operand >= first and operand <= last
9401 const range_first_ok = try case_block.addBinOp(9425 const range_first_ok = try case_block.addBinOp(
9402 .cmp_gte,9426 if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte,
9403 operand,9427 operand,
9404 item_first,9428 item_first,
9405 );9429 );
9406 const range_last_ok = try case_block.addBinOp(9430 const range_last_ok = try case_block.addBinOp(
9407 .cmp_lte,9431 if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte,
9408 operand,9432 operand,
9409 item_last,9433 item_last,
9410 );9434 );
...@@ -9996,40 +10020,34 @@ fn zirShl(...@@ -9996,40 +10020,34 @@ fn zirShl(
9996 } else rhs;10020 } else rhs;
999710021
9998 try sema.requireRuntimeBlock(block, src, runtime_src);10022 try sema.requireRuntimeBlock(block, src, runtime_src);
9999 if (block.wantSafety()) {10023 if (block.wantSafety() and air_tag == .shl_exact) {
10000 const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {10024 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10001 .shl_exact => .shl_with_overflow,10025 const op_ov = try block.addInst(.{
10002 else => null,10026 .tag = .shl_with_overflow,
10003 };10027 .data = .{ .ty_pl = .{
10004 if (maybe_op_ov) |op_ov_tag| {10028 .ty = try sema.addType(op_ov_tuple_ty),
10005 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);10029 .payload = try sema.addExtra(Air.Bin{
10006 const op_ov = try block.addInst(.{10030 .lhs = lhs,
10007 .tag = op_ov_tag,10031 .rhs = rhs,
10008 .data = .{ .ty_pl = .{10032 }),
10009 .ty = try sema.addType(op_ov_tuple_ty),10033 } },
10010 .payload = try sema.addExtra(Air.Bin{10034 });
10011 .lhs = lhs,10035 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10012 .rhs = rhs,10036 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10013 }),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,
10014 } },10042 } },
10015 });10043 })
10016 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);10044 else
10017 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)10045 ov_bit;
10018 try block.addInst(.{10046 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10019 .tag = .reduce,10047 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
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);
1002910048
10030 try sema.addSafetyCheck(block, no_ov, .shl_overflow);10049 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10031 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);10050 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10032 }
10033 }10051 }
10034 return block.addBinOp(air_tag, lhs, new_rhs);10052 return block.addBinOp(air_tag, lhs, new_rhs);
10035}10053}
...@@ -10107,7 +10125,23 @@ fn zirShr(...@@ -10107,7 +10125,23 @@ fn zirShr(
10107 } else rhs_src;10125 } else rhs_src;
1010810126
10109 try sema.requireRuntimeBlock(block, src, runtime_src);10127 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;
10111}10145}
1011210146
10113fn zirBitwise(10147fn zirBitwise(
...@@ -10697,7 +10731,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -10697,7 +10731,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
10697 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));10731 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
10698 }10732 }
10699 try sema.requireRuntimeBlock(block, src, null);10733 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);
10701 }10735 }
1070210736
10703 const lhs = if (rhs_ty.zigTypeTag() == .Vector)10737 const lhs = if (rhs_ty.zigTypeTag() == .Vector)
...@@ -11056,6 +11090,7 @@ fn analyzeArithmetic(...@@ -11056,6 +11090,7 @@ fn analyzeArithmetic(
11056 return casted_lhs;11090 return casted_lhs;
11057 }11091 }
11058 }11092 }
11093 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
11059 if (maybe_lhs_val) |lhs_val| {11094 if (maybe_lhs_val) |lhs_val| {
11060 if (lhs_val.isUndef()) {11095 if (lhs_val.isUndef()) {
11061 if (is_int) {11096 if (is_int) {
...@@ -11078,8 +11113,8 @@ fn analyzeArithmetic(...@@ -11078,8 +11113,8 @@ fn analyzeArithmetic(
11078 try sema.floatAdd(lhs_val, rhs_val, resolved_type),11113 try sema.floatAdd(lhs_val, rhs_val, resolved_type),
11079 );11114 );
11080 }11115 }
11081 } else break :rs .{ .src = rhs_src, .air_tag = .add };11116 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11082 } else break :rs .{ .src = lhs_src, .air_tag = .add };11117 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11083 },11118 },
11084 .addwrap => {11119 .addwrap => {
11085 // Integers only; floats are checked above.11120 // Integers only; floats are checked above.
...@@ -11090,6 +11125,7 @@ fn analyzeArithmetic(...@@ -11090,6 +11125,7 @@ fn analyzeArithmetic(
11090 return casted_rhs;11125 return casted_rhs;
11091 }11126 }
11092 }11127 }
11128 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
11093 if (maybe_rhs_val) |rhs_val| {11129 if (maybe_rhs_val) |rhs_val| {
11094 if (rhs_val.isUndef()) {11130 if (rhs_val.isUndef()) {
11095 return sema.addConstUndef(resolved_type);11131 return sema.addConstUndef(resolved_type);
...@@ -11102,8 +11138,8 @@ fn analyzeArithmetic(...@@ -11102,8 +11138,8 @@ fn analyzeArithmetic(
11102 resolved_type,11138 resolved_type,
11103 try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),11139 try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),
11104 );11140 );
11105 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };11141 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11106 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };11142 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11107 },11143 },
11108 .add_sat => {11144 .add_sat => {
11109 // Integers only; floats are checked above.11145 // Integers only; floats are checked above.
...@@ -11151,6 +11187,7 @@ fn analyzeArithmetic(...@@ -11151,6 +11187,7 @@ fn analyzeArithmetic(
11151 return casted_lhs;11187 return casted_lhs;
11152 }11188 }
11153 }11189 }
11190 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
11154 if (maybe_lhs_val) |lhs_val| {11191 if (maybe_lhs_val) |lhs_val| {
11155 if (lhs_val.isUndef()) {11192 if (lhs_val.isUndef()) {
11156 if (is_int) {11193 if (is_int) {
...@@ -11173,8 +11210,8 @@ fn analyzeArithmetic(...@@ -11173,8 +11210,8 @@ fn analyzeArithmetic(
11173 try sema.floatSub(lhs_val, rhs_val, resolved_type),11210 try sema.floatSub(lhs_val, rhs_val, resolved_type),
11174 );11211 );
11175 }11212 }
11176 } else break :rs .{ .src = rhs_src, .air_tag = .sub };11213 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11177 } else break :rs .{ .src = lhs_src, .air_tag = .sub };11214 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11178 },11215 },
11179 .subwrap => {11216 .subwrap => {
11180 // Integers only; floats are checked above.11217 // Integers only; floats are checked above.
...@@ -11188,6 +11225,7 @@ fn analyzeArithmetic(...@@ -11188,6 +11225,7 @@ fn analyzeArithmetic(
11188 return casted_lhs;11225 return casted_lhs;
11189 }11226 }
11190 }11227 }
11228 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
11191 if (maybe_lhs_val) |lhs_val| {11229 if (maybe_lhs_val) |lhs_val| {
11192 if (lhs_val.isUndef()) {11230 if (lhs_val.isUndef()) {
11193 return sema.addConstUndef(resolved_type);11231 return sema.addConstUndef(resolved_type);
...@@ -11197,8 +11235,8 @@ fn analyzeArithmetic(...@@ -11197,8 +11235,8 @@ fn analyzeArithmetic(
11197 resolved_type,11235 resolved_type,
11198 try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),11236 try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),
11199 );11237 );
11200 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };11238 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11201 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };11239 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11202 },11240 },
11203 .sub_sat => {11241 .sub_sat => {
11204 // Integers only; floats are checked above.11242 // Integers only; floats are checked above.
...@@ -11305,14 +11343,14 @@ fn analyzeArithmetic(...@@ -11305,14 +11343,14 @@ fn analyzeArithmetic(
11305 if (is_int) {11343 if (is_int) {
11306 break :rs .{ .src = rhs_src, .air_tag = .div_trunc };11344 break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
11307 } else {11345 } 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 };
11309 }11347 }
11310 }11348 }
11311 } else {11349 } else {
11312 if (is_int) {11350 if (is_int) {
11313 break :rs .{ .src = lhs_src, .air_tag = .div_trunc };11351 break :rs .{ .src = lhs_src, .air_tag = .div_trunc };
11314 } else {11352 } 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 };
11316 }11354 }
11317 }11355 }
11318 },11356 },
...@@ -11351,6 +11389,7 @@ fn analyzeArithmetic(...@@ -11351,6 +11389,7 @@ fn analyzeArithmetic(
11351 return sema.failWithDivideByZero(block, rhs_src);11389 return sema.failWithDivideByZero(block, rhs_src);
11352 }11390 }
11353 }11391 }
11392 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_trunc_optimized else .div_trunc;
11354 if (maybe_lhs_val) |lhs_val| {11393 if (maybe_lhs_val) |lhs_val| {
11355 if (lhs_val.isUndef()) {11394 if (lhs_val.isUndef()) {
11356 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {11395 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
...@@ -11376,8 +11415,8 @@ fn analyzeArithmetic(...@@ -11376,8 +11415,8 @@ fn analyzeArithmetic(
11376 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),11415 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
11377 );11416 );
11378 }11417 }
11379 } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };11418 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11380 } else break :rs .{ .src = lhs_src, .air_tag = .div_trunc };11419 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11381 },11420 },
11382 .div_floor => {11421 .div_floor => {
11383 // For integers:11422 // For integers:
...@@ -11414,6 +11453,7 @@ fn analyzeArithmetic(...@@ -11414,6 +11453,7 @@ fn analyzeArithmetic(
11414 return sema.failWithDivideByZero(block, rhs_src);11453 return sema.failWithDivideByZero(block, rhs_src);
11415 }11454 }
11416 }11455 }
11456 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_floor_optimized else .div_floor;
11417 if (maybe_lhs_val) |lhs_val| {11457 if (maybe_lhs_val) |lhs_val| {
11418 if (lhs_val.isUndef()) {11458 if (lhs_val.isUndef()) {
11419 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {11459 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
...@@ -11439,8 +11479,8 @@ fn analyzeArithmetic(...@@ -11439,8 +11479,8 @@ fn analyzeArithmetic(
11439 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),11479 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
11440 );11480 );
11441 }11481 }
11442 } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };11482 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11443 } else break :rs .{ .src = lhs_src, .air_tag = .div_floor };11483 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11444 },11484 },
11445 .div_exact => {11485 .div_exact => {
11446 // For integers:11486 // For integers:
...@@ -11476,6 +11516,7 @@ fn analyzeArithmetic(...@@ -11476,6 +11516,7 @@ fn analyzeArithmetic(
11476 return sema.failWithDivideByZero(block, rhs_src);11516 return sema.failWithDivideByZero(block, rhs_src);
11477 }11517 }
11478 }11518 }
11519 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_exact_optimized else .div_exact;
11479 if (maybe_lhs_val) |lhs_val| {11520 if (maybe_lhs_val) |lhs_val| {
11480 if (maybe_rhs_val) |rhs_val| {11521 if (maybe_rhs_val) |rhs_val| {
11481 if (is_int) {11522 if (is_int) {
...@@ -11491,8 +11532,8 @@ fn analyzeArithmetic(...@@ -11491,8 +11532,8 @@ fn analyzeArithmetic(
11491 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),11532 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
11492 );11533 );
11493 }11534 }
11494 } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };11535 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11495 } else break :rs .{ .src = lhs_src, .air_tag = .div_exact };11536 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11496 },11537 },
11497 .mul => {11538 .mul => {
11498 // For integers:11539 // For integers:
...@@ -11513,6 +11554,7 @@ fn analyzeArithmetic(...@@ -11513,6 +11554,7 @@ fn analyzeArithmetic(
11513 }11554 }
11514 }11555 }
11515 }11556 }
11557 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
11516 if (maybe_rhs_val) |rhs_val| {11558 if (maybe_rhs_val) |rhs_val| {
11517 if (rhs_val.isUndef()) {11559 if (rhs_val.isUndef()) {
11518 if (is_int) {11560 if (is_int) {
...@@ -11548,8 +11590,8 @@ fn analyzeArithmetic(...@@ -11548,8 +11590,8 @@ fn analyzeArithmetic(
11548 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),11590 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
11549 );11591 );
11550 }11592 }
11551 } else break :rs .{ .src = lhs_src, .air_tag = .mul };11593 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11552 } else break :rs .{ .src = rhs_src, .air_tag = .mul };11594 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11553 },11595 },
11554 .mulwrap => {11596 .mulwrap => {
11555 // Integers only; floats are handled above.11597 // Integers only; floats are handled above.
...@@ -11566,6 +11608,7 @@ fn analyzeArithmetic(...@@ -11566,6 +11608,7 @@ fn analyzeArithmetic(
11566 }11608 }
11567 }11609 }
11568 }11610 }
11611 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
11569 if (maybe_rhs_val) |rhs_val| {11612 if (maybe_rhs_val) |rhs_val| {
11570 if (rhs_val.isUndef()) {11613 if (rhs_val.isUndef()) {
11571 return sema.addConstUndef(resolved_type);11614 return sema.addConstUndef(resolved_type);
...@@ -11584,8 +11627,8 @@ fn analyzeArithmetic(...@@ -11584,8 +11627,8 @@ fn analyzeArithmetic(
11584 resolved_type,11627 resolved_type,
11585 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),11628 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
11586 );11629 );
11587 } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };11630 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11588 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };11631 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11589 },11632 },
11590 .mul_sat => {11633 .mul_sat => {
11591 // Integers only; floats are checked above.11634 // Integers only; floats are checked above.
...@@ -11755,6 +11798,7 @@ fn analyzeArithmetic(...@@ -11755,6 +11798,7 @@ fn analyzeArithmetic(
11755 return sema.failWithDivideByZero(block, rhs_src);11798 return sema.failWithDivideByZero(block, rhs_src);
11756 }11799 }
11757 }11800 }
11801 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .rem_optimized else .rem;
11758 if (maybe_lhs_val) |lhs_val| {11802 if (maybe_lhs_val) |lhs_val| {
11759 if (lhs_val.isUndef()) {11803 if (lhs_val.isUndef()) {
11760 return sema.addConstUndef(resolved_type);11804 return sema.addConstUndef(resolved_type);
...@@ -11764,8 +11808,8 @@ fn analyzeArithmetic(...@@ -11764,8 +11808,8 @@ fn analyzeArithmetic(
11764 resolved_type,11808 resolved_type,
11765 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),11809 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
11766 );11810 );
11767 } else break :rs .{ .src = rhs_src, .air_tag = .rem };11811 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11768 } else break :rs .{ .src = lhs_src, .air_tag = .rem };11812 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11769 },11813 },
11770 .mod => {11814 .mod => {
11771 // For integers:11815 // For integers:
...@@ -11812,6 +11856,7 @@ fn analyzeArithmetic(...@@ -11812,6 +11856,7 @@ fn analyzeArithmetic(
11812 return sema.failWithDivideByZero(block, rhs_src);11856 return sema.failWithDivideByZero(block, rhs_src);
11813 }11857 }
11814 }11858 }
11859 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mod_optimized else .mod;
11815 if (maybe_lhs_val) |lhs_val| {11860 if (maybe_lhs_val) |lhs_val| {
11816 if (lhs_val.isUndef()) {11861 if (lhs_val.isUndef()) {
11817 return sema.addConstUndef(resolved_type);11862 return sema.addConstUndef(resolved_type);
...@@ -11821,8 +11866,8 @@ fn analyzeArithmetic(...@@ -11821,8 +11866,8 @@ fn analyzeArithmetic(
11821 resolved_type,11866 resolved_type,
11822 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),11867 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
11823 );11868 );
11824 } else break :rs .{ .src = rhs_src, .air_tag = .mod };11869 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
11825 } else break :rs .{ .src = lhs_src, .air_tag = .mod };11870 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
11826 },11871 },
11827 else => unreachable,11872 else => unreachable,
11828 }11873 }
...@@ -11852,7 +11897,7 @@ fn analyzeArithmetic(...@@ -11852,7 +11897,7 @@ fn analyzeArithmetic(
11852 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);11897 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
11853 const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)11898 const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)
11854 try block.addInst(.{11899 try block.addInst(.{
11855 .tag = .reduce,11900 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
11856 .data = .{ .reduce = .{11901 .data = .{ .reduce = .{
11857 .operand = ov_bit,11902 .operand = ov_bit,
11858 .operation = .Or,11903 .operation = .Or,
...@@ -11867,6 +11912,96 @@ fn analyzeArithmetic(...@@ -11867,6 +11912,96 @@ fn analyzeArithmetic(
11867 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);11912 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
11868 }11913 }
11869 }11914 }
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 }
11870 }12005 }
11871 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);12006 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
11872}12007}
...@@ -12374,7 +12509,7 @@ fn cmpSelf(...@@ -12374,7 +12509,7 @@ fn cmpSelf(
12374 const result_ty_ref = try sema.addType(result_ty);12509 const result_ty_ref = try sema.addType(result_ty);
12375 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);12510 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
12376 }12511 }
12377 const tag = Air.Inst.Tag.fromCmpOp(op);12512 const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
12378 return block.addBinOp(tag, casted_lhs, casted_rhs);12513 return block.addBinOp(tag, casted_lhs, casted_rhs);
12379}12514}
1238012515
...@@ -14387,6 +14522,7 @@ fn zirStructInit(...@@ -14387,6 +14522,7 @@ fn zirStructInit(
14387 var field_i: u32 = 0;14522 var field_i: u32 = 0;
14388 var extra_index = extra.end;14523 var extra_index = extra.end;
1438914524
14525 const is_packed = resolved_ty.containerLayout() == .Packed;
14390 while (field_i < extra.data.fields_len) : (field_i += 1) {14526 while (field_i < extra.data.fields_len) : (field_i += 1) {
14391 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);14527 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
14392 extra_index = item.end;14528 extra_index = item.end;
...@@ -14395,7 +14531,10 @@ fn zirStructInit(...@@ -14395,7 +14531,10 @@ fn zirStructInit(
14395 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };14531 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
14396 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;14532 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
14397 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);14533 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);
14399 if (field_inits[field_index] != .none) {14538 if (field_inits[field_index] != .none) {
14400 const other_field_type = found_fields[field_index];14539 const other_field_type = found_fields[field_index];
14401 const other_field_type_data = zir_datas[other_field_type].pl_node;14540 const other_field_type_data = zir_datas[other_field_type].pl_node;
...@@ -14410,6 +14549,15 @@ fn zirStructInit(...@@ -14410,6 +14549,15 @@ fn zirStructInit(
14410 }14549 }
14411 found_fields[field_index] = item.data.field_type;14550 found_fields[field_index] = item.data.field_type;
14412 field_inits[field_index] = try sema.resolveInst(item.data.init);14551 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 };
14413 }14561 }
1441414562
14415 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);14563 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
...@@ -14445,7 +14593,7 @@ fn zirStructInit(...@@ -14445,7 +14593,7 @@ fn zirStructInit(
14445 .@"addrspace" = target_util.defaultAddressSpace(target, .local),14593 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
14446 });14594 });
14447 const alloc = try block.addTy(.alloc, alloc_ty);14595 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);
14449 try sema.storePtr(block, src, field_ptr, init_inst);14597 try sema.storePtr(block, src, field_ptr, init_inst);
14450 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);14598 const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
14451 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);14599 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
...@@ -14550,7 +14698,7 @@ fn finishStructInit(...@@ -14550,7 +14698,7 @@ fn finishStructInit(
14550 for (field_inits) |field_init, i_usize| {14698 for (field_inits) |field_init, i_usize| {
14551 const i = @intCast(u32, i_usize);14699 const i = @intCast(u32, i_usize);
14552 const field_src = dest_src;14700 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);
14554 try sema.storePtr(block, dest_src, field_ptr, field_init);14702 try sema.storePtr(block, dest_src, field_ptr, field_init);
14555 }14703 }
1455614704
...@@ -14573,22 +14721,41 @@ fn zirStructInitAnon(...@@ -14573,22 +14721,41 @@ fn zirStructInitAnon(
14573 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);14721 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
14574 const types = try sema.arena.alloc(Type, extra.data.fields_len);14722 const types = try sema.arena.alloc(Type, extra.data.fields_len);
14575 const values = try sema.arena.alloc(Value, types.len);14723 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: {14728 const opt_runtime_index = rs: {
14579 var runtime_src: ?LazySrcLoc = null;14729 var runtime_index: ?usize = null;
14580 var extra_index = extra.end;14730 var extra_index = extra.end;
14581 for (types) |*field_ty, i| {14731 for (types) |*field_ty, i| {
14582 const init_src = src; // TODO better source location
14583 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);14732 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
14584 extra_index = item.end;14733 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
14587 const init = try sema.resolveInst(item.data.init);14752 const init = try sema.resolveInst(item.data.init);
14588 field_ty.* = sema.typeOf(init);14753 field_ty.* = sema.typeOf(init);
14589 if (types[i].zigTypeTag() == .Opaque) {14754 if (types[i].zigTypeTag() == .Opaque) {
14590 const msg = msg: {14755 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", .{});
14592 errdefer msg.destroy(sema.gpa);14759 errdefer msg.destroy(sema.gpa);
1459314760
14594 try sema.addDeclaredHereNote(msg, types[i]);14761 try sema.addDeclaredHereNote(msg, types[i]);
...@@ -14596,28 +14763,37 @@ fn zirStructInitAnon(...@@ -14596,28 +14763,37 @@ fn zirStructInitAnon(
14596 };14763 };
14597 return sema.failWithOwnedErrorMsg(block, msg);14764 return sema.failWithOwnedErrorMsg(block, msg);
14598 }14765 }
14766 const init_src = src; // TODO better source location
14599 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {14767 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
14600 values[i] = init_val;14768 values[i] = init_val;
14601 } else {14769 } else {
14602 values[i] = Value.initTag(.unreachable_value);14770 values[i] = Value.initTag(.unreachable_value);
14603 runtime_src = init_src;14771 runtime_index = i;
14604 }14772 }
14605 }14773 }
14606 break :rs runtime_src;14774 break :rs runtime_index;
14607 };14775 };
1460814776
14609 const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{14777 const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{
14610 .names = names,14778 .names = try sema.arena.dupe([]const u8, fields.keys()),
14611 .types = types,14779 .types = types,
14612 .values = values,14780 .values = values,
14613 });14781 });
1461414782
14615 const runtime_src = opt_runtime_src orelse {14783 const runtime_index = opt_runtime_index orelse {
14616 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);14784 const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
14617 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);14785 return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
14618 };14786 };
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
14622 if (is_ref) {14798 if (is_ref) {
14623 const target = sema.mod.getTarget();14799 const target = sema.mod.getTarget();
...@@ -15513,13 +15689,21 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15513,13 +15689,21 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15513 if (decls_val.sliceLen(mod) > 0) {15689 if (decls_val.sliceLen(mod) > 0) {
15514 return sema.fail(block, src, "reified unions must have no decls", .{});15690 return sema.fail(block, src, "reified unions must have no decls", .{});
15515 }15691 }
15692 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
1551615693
15517 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);15694 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
15518 errdefer new_decl_arena.deinit();15695 errdefer new_decl_arena.deinit();
15519 const new_decl_arena_allocator = new_decl_arena.allocator();15696 const new_decl_arena_allocator = new_decl_arena.allocator();
1552015697
15521 const union_obj = try new_decl_arena_allocator.create(Module.Union);15698 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 };
15523 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);15707 const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
15524 union_payload.* = .{15708 union_payload.* = .{
15525 .base = .{ .tag = type_tag },15709 .base = .{ .tag = type_tag },
...@@ -15540,7 +15724,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15540,7 +15724,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15540 .fields = .{},15724 .fields = .{},
15541 .node_offset = src.node_offset.x,15725 .node_offset = src.node_offset.x,
15542 .zir_index = inst,15726 .zir_index = inst,
15543 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),15727 .layout = layout,
15544 .status = .have_field_types,15728 .status = .have_field_types,
15545 .namespace = .{15729 .namespace = .{
15546 .parent = block.namespace,15730 .parent = block.namespace,
...@@ -15550,11 +15734,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15550,11 +15734,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15550 };15734 };
1555115735
15552 // Tag type15736 // Tag type
15737 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
15553 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));15738 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| {
15555 var buffer: Value.ToTypeBuffer = undefined;15740 var buffer: Value.ToTypeBuffer = undefined;
15556 break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator);15741 union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
15557 } else try sema.generateUnionTagTypeSimple(block, fields_len, null);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
15559 // Fields15747 // Fields
15560 if (fields_len > 0) {15748 if (fields_len > 0) {
...@@ -15578,6 +15766,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15578,6 +15766,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15578 sema.mod,15766 sema.mod,
15579 );15767 );
1558015768
15769 if (enum_field_names) |set| {
15770 set.putAssumeCapacity(field_name, {});
15771 }
15772
15581 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);15773 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
15582 if (gop.found_existing) {15774 if (gop.found_existing) {
15583 // TODO: better source location15775 // TODO: better source location
...@@ -15823,7 +16015,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -15823,7 +16015,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
15823 }16015 }
1582416016
15825 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);16017 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;
15827}16028}
1582816029
15829fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16030fn 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...@@ -16154,8 +16355,6 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
16154 // TODO compile error if the result pointer is comptime known and would have an16355 // TODO compile error if the result pointer is comptime known and would have an
16155 // alignment that disagrees with the Decl's alignment.16356 // alignment that disagrees with the Decl's alignment.
1615616357
16157 // TODO insert safety check that the alignment is correct
16158
16159 const ptr_info = ptr_ty.ptrInfo().data;16358 const ptr_info = ptr_ty.ptrInfo().data;
16160 const dest_ty = try Type.ptr(sema.arena, sema.mod, .{16359 const dest_ty = try Type.ptr(sema.arena, sema.mod, .{
16161 .pointee_type = ptr_info.pointee_type,16360 .pointee_type = ptr_info.pointee_type,
...@@ -16166,6 +16365,41 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -16166,6 +16365,41 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
16166 .@"volatile" = ptr_info.@"volatile",16365 .@"volatile" = ptr_info.@"volatile",
16167 .size = ptr_info.size,16366 .size = ptr_info.size,
16168 });16367 });
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 }
16169 return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src);16403 return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src);
16170}16404}
1617116405
...@@ -17026,7 +17260,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -17026,7 +17260,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1702617260
17027 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);17261 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
17028 return block.addInst(.{17262 return block.addInst(.{
17029 .tag = .reduce,17263 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
17030 .data = .{ .reduce = .{17264 .data = .{ .reduce = .{
17031 .operand = operand,17265 .operand = operand,
17032 .operation = operation,17266 .operation = operation,
...@@ -18800,8 +19034,16 @@ pub const PanicId = enum {...@@ -18800,8 +19034,16 @@ pub const PanicId = enum {
18800 incorrect_alignment,19034 incorrect_alignment,
18801 invalid_error_code,19035 invalid_error_code,
18802 cast_truncated_data,19036 cast_truncated_data,
19037 negative_to_unsigned,
18803 integer_overflow,19038 integer_overflow,
18804 shl_overflow,19039 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,
18805};19047};
1880619048
18807fn addSafetyCheck(19049fn addSafetyCheck(
...@@ -19017,8 +19259,15 @@ fn safetyPanic(...@@ -19017,8 +19259,15 @@ fn safetyPanic(
19017 .incorrect_alignment => "incorrect alignment",19259 .incorrect_alignment => "incorrect alignment",
19018 .invalid_error_code => "invalid error code",19260 .invalid_error_code => "invalid error code",
19019 .cast_truncated_data => "integer cast truncated bits",19261 .cast_truncated_data => "integer cast truncated bits",
19262 .negative_to_unsigned => "attempt to cast negative value to unsigned integer",
19020 .integer_overflow => "integer overflow",19263 .integer_overflow => "integer overflow",
19021 .shl_overflow => "left shift overflowed bits",19264 .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",
19022 };19271 };
1902319272
19024 const msg_inst = msg_inst: {19273 const msg_inst = msg_inst: {
...@@ -19206,16 +19455,7 @@ fn fieldVal(...@@ -19206,16 +19455,7 @@ fn fieldVal(
19206 return inst;19455 return inst;
19207 }19456 }
19208 }19457 }
19209 // TODO add note: declared here19458 return sema.failWithBadMemberAccess(block, child_type, src, field_name);
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 });
19219 },19459 },
19220 else => {19460 else => {
19221 const msg = msg: {19461 const msg = msg: {
...@@ -19231,14 +19471,14 @@ fn fieldVal(...@@ -19231,14 +19471,14 @@ fn fieldVal(
19231 },19471 },
19232 .Struct => if (is_pointer_to) {19472 .Struct => if (is_pointer_to) {
19233 // Avoid loading the entire struct by fetching a pointer and loading that19473 // 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);
19235 return sema.analyzeLoad(block, src, field_ptr, object_src);19475 return sema.analyzeLoad(block, src, field_ptr, object_src);
19236 } else {19476 } else {
19237 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);19477 return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty);
19238 },19478 },
19239 .Union => if (is_pointer_to) {19479 .Union => if (is_pointer_to) {
19240 // Avoid loading the entire union by fetching a pointer and loading that19480 // 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);
19242 return sema.analyzeLoad(block, src, field_ptr, object_src);19482 return sema.analyzeLoad(block, src, field_ptr, object_src);
19243 } else {19483 } else {
19244 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);19484 return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty);
...@@ -19255,6 +19495,7 @@ fn fieldPtr(...@@ -19255,6 +19495,7 @@ fn fieldPtr(
19255 object_ptr: Air.Inst.Ref,19495 object_ptr: Air.Inst.Ref,
19256 field_name: []const u8,19496 field_name: []const u8,
19257 field_name_src: LazySrcLoc,19497 field_name_src: LazySrcLoc,
19498 initializing: bool,
19258) CompileError!Air.Inst.Ref {19499) CompileError!Air.Inst.Ref {
19259 // When editing this function, note that there is corresponding logic to be edited19500 // When editing this function, note that there is corresponding logic to be edited
19260 // in `fieldVal`. This function takes a pointer and returns a pointer.19501 // in `fieldVal`. This function takes a pointer and returns a pointer.
...@@ -19439,14 +19680,14 @@ fn fieldPtr(...@@ -19439,14 +19680,14 @@ fn fieldPtr(
19439 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)19680 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
19440 else19681 else
19441 object_ptr;19682 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);
19443 },19684 },
19444 .Union => {19685 .Union => {
19445 const inner_ptr = if (is_pointer_to)19686 const inner_ptr = if (is_pointer_to)
19446 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)19687 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
19447 else19688 else
19448 object_ptr;19689 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);
19450 },19691 },
19451 else => {},19692 else => {},
19452 }19693 }
...@@ -19556,7 +19797,13 @@ fn fieldCallBind(...@@ -19556,7 +19797,13 @@ fn fieldCallBind(
19556 else => {},19797 else => {},
19557 }19798 }
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);
19560}19807}
1956119808
19562fn finishFieldCallBind(19809fn finishFieldCallBind(
...@@ -19648,6 +19895,7 @@ fn structFieldPtr(...@@ -19648,6 +19895,7 @@ fn structFieldPtr(
19648 field_name: []const u8,19895 field_name: []const u8,
19649 field_name_src: LazySrcLoc,19896 field_name_src: LazySrcLoc,
19650 unresolved_struct_ty: Type,19897 unresolved_struct_ty: Type,
19898 initializing: bool,
19651) CompileError!Air.Inst.Ref {19899) CompileError!Air.Inst.Ref {
19652 assert(unresolved_struct_ty.zigTypeTag() == .Struct);19900 assert(unresolved_struct_ty.zigTypeTag() == .Struct);
1965319901
...@@ -19660,10 +19908,10 @@ fn structFieldPtr(...@@ -19660,10 +19908,10 @@ fn structFieldPtr(
19660 return sema.analyzeRef(block, src, len_inst);19908 return sema.analyzeRef(block, src, len_inst);
19661 }19909 }
19662 const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);19910 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);
19664 } else if (struct_ty.isAnonStruct()) {19912 } else if (struct_ty.isAnonStruct()) {
19665 const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);19913 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);
19667 }19915 }
1966819916
19669 const struct_obj = struct_ty.castTag(.@"struct").?.data;19917 const struct_obj = struct_ty.castTag(.@"struct").?.data;
...@@ -19672,7 +19920,7 @@ fn structFieldPtr(...@@ -19672,7 +19920,7 @@ fn structFieldPtr(
19672 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);19920 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
19673 const field_index = @intCast(u32, field_index_big);19921 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);
19676}19924}
1967719925
19678fn structFieldPtrByIndex(19926fn structFieldPtrByIndex(
...@@ -19683,9 +19931,10 @@ fn structFieldPtrByIndex(...@@ -19683,9 +19931,10 @@ fn structFieldPtrByIndex(
19683 field_index: u32,19931 field_index: u32,
19684 field_src: LazySrcLoc,19932 field_src: LazySrcLoc,
19685 struct_ty: Type,19933 struct_ty: Type,
19934 initializing: bool,
19686) CompileError!Air.Inst.Ref {19935) CompileError!Air.Inst.Ref {
19687 if (struct_ty.isAnonStruct()) {19936 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);
19689 }19938 }
1969019939
19691 const struct_obj = struct_ty.castTag(.@"struct").?.data;19940 const struct_obj = struct_ty.castTag(.@"struct").?.data;
...@@ -19882,6 +20131,10 @@ fn tupleFieldValByIndex(...@@ -19882,6 +20131,10 @@ fn tupleFieldValByIndex(
19882 return sema.addConstant(field_ty, field_values[field_index]);20131 return sema.addConstant(field_ty, field_values[field_index]);
19883 }20132 }
1988420133
20134 if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
20135 return sema.addConstant(field_ty, default_val);
20136 }
20137
19885 try sema.requireRuntimeBlock(block, src, null);20138 try sema.requireRuntimeBlock(block, src, null);
19886 return block.addStructFieldVal(tuple_byval, field_index, field_ty);20139 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
19887}20140}
...@@ -19894,6 +20147,7 @@ fn unionFieldPtr(...@@ -19894,6 +20147,7 @@ fn unionFieldPtr(
19894 field_name: []const u8,20147 field_name: []const u8,
19895 field_name_src: LazySrcLoc,20148 field_name_src: LazySrcLoc,
19896 unresolved_union_ty: Type,20149 unresolved_union_ty: Type,
20150 initializing: bool,
19897) CompileError!Air.Inst.Ref {20151) CompileError!Air.Inst.Ref {
19898 const arena = sema.arena;20152 const arena = sema.arena;
19899 assert(unresolved_union_ty.zigTypeTag() == .Union);20153 assert(unresolved_union_ty.zigTypeTag() == .Union);
...@@ -19909,30 +20163,32 @@ fn unionFieldPtr(...@@ -19909,30 +20163,32 @@ fn unionFieldPtr(
19909 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),20163 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
19910 });20164 });
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: {
19913 switch (union_obj.layout) {20167 switch (union_obj.layout) {
19914 .Auto => {20168 .Auto => if (!initializing) {
19915 // TODO emit the access of inactive union field error commented out below.20169 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
19916 // In order to do that, we need to first solve the problem that AstGen20170 break :ct;
19917 // emits field_ptr instructions in order to initialize union values.20171 if (union_val.isUndef()) {
19918 // In such case we need to know that the field_ptr instruction (which is20172 return sema.failWithUseOfUndef(block, src);
19919 // calling this unionFieldPtr function) is *initializing* the union,20173 }
19920 // in which case we would skip this check, and in fact we would actually20174 const tag_and_val = union_val.castTag(.@"union").?.data;
19921 // set the union tag here and the payload to undefined.20175 var field_tag_buf: Value.Payload.U32 = .{
1992220176 .base = .{ .tag = .enum_field_index },
19923 //const tag_and_val = union_val.castTag(.@"union").?.data;20177 .data = field_index,
19924 //var field_tag_buf: Value.Payload.U32 = .{20178 };
19925 // .base = .{ .tag = .enum_field_index },20179 const field_tag = Value.initPayload(&field_tag_buf.base);
19926 // .data = field_index,20180 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
19927 //};20181 if (!tag_matches) {
19928 //const field_tag = Value.initPayload(&field_tag_buf.base);20182 const msg = msg: {
19929 //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod);20183 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
19930 //if (!tag_matches) {20184 const active_field_name = union_obj.fields.keys()[active_index];
19931 // // TODO enhance this saying which one was active20185 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
19932 // // and which one was accessed, and showing where the union was declared.20186 errdefer msg.destroy(sema.gpa);
19933 // return sema.fail(block, src, "access of inactive union field", .{});20187 try sema.addDeclaredHereNote(msg, union_ty);
19934 //}20188 break :msg msg;
19935 // TODO add runtime safety check for the active tag20189 };
20190 return sema.failWithOwnedErrorMsg(block, msg);
20191 }
19936 },20192 },
19937 .Packed, .Extern => {},20193 .Packed, .Extern => {},
19938 }20194 }
...@@ -19947,6 +20203,18 @@ fn unionFieldPtr(...@@ -19947,6 +20203,18 @@ fn unionFieldPtr(
19947 }20203 }
1994820204
19949 try sema.requireRuntimeBlock(block, src, null);20205 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 }
19950 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);20218 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
19951}20219}
1995220220
...@@ -20005,6 +20273,16 @@ fn unionFieldVal(...@@ -20005,6 +20273,16 @@ fn unionFieldVal(
20005 }20273 }
2000620274
20007 try sema.requireRuntimeBlock(block, src, null);20275 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 }
20008 return block.addStructFieldVal(union_byval, field_index, field.ty);20286 return block.addStructFieldVal(union_byval, field_index, field.ty);
20009}20287}
2001020288
...@@ -20061,7 +20339,7 @@ fn elemPtr(...@@ -20061,7 +20339,7 @@ fn elemPtr(
20061 // Tuple field access.20339 // Tuple field access.
20062 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");20340 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
20063 const index = @intCast(u32, index_val.toUnsignedInt(target));20341 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);
20065 },20343 },
20066 else => unreachable,20344 else => unreachable,
20067 }20345 }
...@@ -20164,6 +20442,7 @@ fn tupleFieldPtr(...@@ -20164,6 +20442,7 @@ fn tupleFieldPtr(
20164 tuple_ptr: Air.Inst.Ref,20442 tuple_ptr: Air.Inst.Ref,
20165 field_index_src: LazySrcLoc,20443 field_index_src: LazySrcLoc,
20166 field_index: u32,20444 field_index: u32,
20445 init: bool,
20167) CompileError!Air.Inst.Ref {20446) CompileError!Air.Inst.Ref {
20168 const tuple_ptr_ty = sema.typeOf(tuple_ptr);20447 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
20169 const tuple_ty = tuple_ptr_ty.childType();20448 const tuple_ty = tuple_ptr_ty.childType();
...@@ -20197,7 +20476,17 @@ fn tupleFieldPtr(...@@ -20197,7 +20476,17 @@ fn tupleFieldPtr(
20197 );20476 );
20198 }20477 }
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
20202 try sema.requireRuntimeBlock(block, tuple_ptr_src, null);20491 try sema.requireRuntimeBlock(block, tuple_ptr_src, null);
20203 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);20492 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
...@@ -20911,16 +21200,11 @@ fn coerceExtra(...@@ -20911,16 +21200,11 @@ fn coerceExtra(
20911 const msg = try sema.errMsg(21200 const msg = try sema.errMsg(
20912 block,21201 block,
20913 inst_src,21202 inst_src,
20914 "enum '{}' has no field named '{s}'",21203 "no field named '{s}' in enum '{}'",
20915 .{ dest_ty.fmt(sema.mod), bytes },21204 .{ bytes, dest_ty.fmt(sema.mod) },
20916 );21205 );
20917 errdefer msg.destroy(sema.gpa);21206 errdefer msg.destroy(sema.gpa);
20918 try sema.mod.errNoteNonLazy(21207 try sema.addDeclaredHereNote(msg, dest_ty);
20919 dest_ty.declSrcLoc(sema.mod),
20920 msg,
20921 "enum declared here",
20922 .{},
20923 );
20924 break :msg msg;21208 break :msg msg;
20925 };21209 };
20926 return sema.failWithOwnedErrorMsg(block, msg);21210 return sema.failWithOwnedErrorMsg(block, msg);
...@@ -22131,7 +22415,7 @@ fn storePtrVal(...@@ -22131,7 +22415,7 @@ fn storePtrVal(
22131 .direct => |val_ptr| {22415 .direct => |val_ptr| {
22132 if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) {22416 if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) {
22133 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {22417 if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {
22134 // TODO add note showing where default value is provided22418 // TODO use failWithInvalidComptimeFieldStore
22135 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});22419 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
22136 }22420 }
22137 return;22421 return;
...@@ -23476,6 +23760,7 @@ fn coerceTupleToStruct(...@@ -23476,6 +23760,7 @@ fn coerceTupleToStruct(
23476 const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);23760 const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty);
2347723761
23478 if (struct_ty.isTupleOrAnonStruct()) {23762 if (struct_ty.isTupleOrAnonStruct()) {
23763 // NOTE remember to handle comptime fields
23479 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{});23764 return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{});
23480 }23765 }
2348123766
...@@ -23496,12 +23781,18 @@ fn coerceTupleToStruct(...@@ -23496,12 +23781,18 @@ fn coerceTupleToStruct(
23496 try std.fmt.allocPrint(sema.arena, "{d}", .{i});23781 try std.fmt.allocPrint(sema.arena, "{d}", .{i});
23497 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);23782 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
23498 const field = fields.values()[field_index];23783 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 }
23502 const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i);23784 const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i);
23503 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);23785 const coerced = try sema.coerce(block, field.ty, elem_ref, field_src);
23504 field_refs[field_index] = coerced;23786 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 }
23505 if (runtime_src == null) {23796 if (runtime_src == null) {
23506 if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| {23797 if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| {
23507 field_vals[field_index] = field_val;23798 field_vals[field_index] = field_val;
...@@ -24259,7 +24550,7 @@ fn cmpNumeric(...@@ -24259,7 +24550,7 @@ fn cmpNumeric(
24259 };24550 };
24260 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);24551 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
24261 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);24552 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);
24263 }24554 }
24264 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.24555 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
24265 // For mixed signed and unsigned integers, implicit cast both operands to a signed24556 // For mixed signed and unsigned integers, implicit cast both operands to a signed
...@@ -24380,7 +24671,7 @@ fn cmpNumeric(...@@ -24380,7 +24671,7 @@ fn cmpNumeric(
24380 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);24671 const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
24381 const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);24672 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);
24384}24675}
2438524676
24386/// Asserts that lhs and rhs types are both vectors.24677/// Asserts that lhs and rhs types are both vectors.
...@@ -25323,7 +25614,7 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)...@@ -25323,7 +25614,7 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
25323 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);25614 try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
25324 return ty;25615 return ty;
25325 },25616 },
25326 .@"union", .union_tagged => {25617 .@"union", .union_safety_tagged, .union_tagged => {
25327 const union_obj = ty.cast(Type.Payload.Union).?.data;25618 const union_obj = ty.cast(Type.Payload.Union).?.data;
25328 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);25619 try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
25329 return ty;25620 return ty;
...@@ -25958,7 +26249,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -25958,7 +26249,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
25958 const msg = msg: {26249 const msg = msg: {
25959 const tree = try sema.getAstTree(&block_scope);26250 const tree = try sema.getAstTree(&block_scope);
25960 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);26251 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) });
25962 errdefer msg.destroy(sema.gpa);26253 errdefer msg.destroy(sema.gpa);
25963 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);26254 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
25964 break :msg msg;26255 break :msg msg;
...@@ -26348,7 +26639,7 @@ pub fn typeHasOnePossibleValue(...@@ -26348,7 +26639,7 @@ pub fn typeHasOnePossibleValue(
26348 return null;26639 return null;
26349 }26640 }
26350 },26641 },
26351 .@"union", .union_tagged => {26642 .@"union", .union_safety_tagged, .union_tagged => {
26352 const resolved_ty = try sema.resolveTypeFields(block, src, ty);26643 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
26353 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;26644 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
26354 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse26645 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...@@ -26980,7 +27271,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
26980 }27271 }
26981 },27272 },
2698227273
26983 .@"union", .union_tagged => {27274 .@"union", .union_safety_tagged, .union_tagged => {
26984 const union_obj = ty.cast(Type.Payload.Union).?.data;27275 const union_obj = ty.cast(Type.Payload.Union).?.data;
26985 switch (union_obj.requires_comptime) {27276 switch (union_obj.requires_comptime) {
26986 .no, .wip => return false,27277 .no, .wip => return false,
src/Zir.zig+5
...@@ -410,6 +410,8 @@ pub const Inst = struct {...@@ -410,6 +410,8 @@ pub const Inst = struct {
410 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.410 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
411 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.411 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
412 field_ptr,412 field_ptr,
413 /// Same as `field_ptr` but used for struct init.
414 field_ptr_init,
413 /// Given a struct or object that contains virtual fields, returns the named field.415 /// Given a struct or object that contains virtual fields, returns the named field.
414 /// The field name is stored in string_bytes. Used by a.b syntax.416 /// The field name is stored in string_bytes. Used by a.b syntax.
415 /// This instruction also accepts a pointer.417 /// This instruction also accepts a pointer.
...@@ -1070,6 +1072,7 @@ pub const Inst = struct {...@@ -1070,6 +1072,7 @@ pub const Inst = struct {
1070 .@"export",1072 .@"export",
1071 .export_value,1073 .export_value,
1072 .field_ptr,1074 .field_ptr,
1075 .field_ptr_init,
1073 .field_val,1076 .field_val,
1074 .field_call_bind,1077 .field_call_bind,
1075 .field_ptr_named,1078 .field_ptr_named,
...@@ -1370,6 +1373,7 @@ pub const Inst = struct {...@@ -1370,6 +1373,7 @@ pub const Inst = struct {
1370 .elem_ptr_imm,1373 .elem_ptr_imm,
1371 .elem_val_node,1374 .elem_val_node,
1372 .field_ptr,1375 .field_ptr,
1376 .field_ptr_init,
1373 .field_val,1377 .field_val,
1374 .field_call_bind,1378 .field_call_bind,
1375 .field_ptr_named,1379 .field_ptr_named,
...@@ -1629,6 +1633,7 @@ pub const Inst = struct {...@@ -1629,6 +1633,7 @@ pub const Inst = struct {
1629 .@"export" = .pl_node,1633 .@"export" = .pl_node,
1630 .export_value = .pl_node,1634 .export_value = .pl_node,
1631 .field_ptr = .pl_node,1635 .field_ptr = .pl_node,
1636 .field_ptr_init = .pl_node,
1632 .field_val = .pl_node,1637 .field_val = .pl_node,
1633 .field_ptr_named = .pl_node,1638 .field_ptr_named = .pl_node,
1634 .field_val_named = .pl_node,1639 .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 {...@@ -729,6 +729,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
729 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),729 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
730 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),730 .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
732 .wasm_memory_size => unreachable,756 .wasm_memory_size => unreachable,
733 .wasm_memory_grow => unreachable,757 .wasm_memory_grow => unreachable,
734 // zig fmt: on758 // zig fmt: on
src/arch/arm/CodeGen.zig+24
...@@ -744,6 +744,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -744,6 +744,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
744 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),744 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
745 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),745 .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
747 .wasm_memory_size => unreachable,771 .wasm_memory_size => unreachable,
748 .wasm_memory_grow => unreachable,772 .wasm_memory_grow => unreachable,
749 // zig fmt: on773 // zig fmt: on
src/arch/riscv64/CodeGen.zig+24
...@@ -669,6 +669,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -669,6 +669,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),669 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
670 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),670 .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
672 .wasm_memory_size => unreachable,696 .wasm_memory_size => unreachable,
673 .wasm_memory_grow => unreachable,697 .wasm_memory_grow => unreachable,
674 // zig fmt: on698 // zig fmt: on
src/arch/sparc64/CodeGen.zig+24
...@@ -681,6 +681,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -681,6 +681,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
681 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),681 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
682 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),682 .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
684 .wasm_memory_size => unreachable,708 .wasm_memory_size => unreachable,
685 .wasm_memory_grow => unreachable,709 .wasm_memory_grow => unreachable,
686 // zig fmt: on710 // zig fmt: on
src/arch/wasm/CodeGen.zig+24
...@@ -1622,6 +1622,30 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1622,6 +1622,30 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1622 .err_return_trace,1622 .err_return_trace,
1623 .set_err_return_trace,1623 .set_err_return_trace,
1624 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1624 => |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", .{}),
1625 };1649 };
1626}1650}
16271651
src/arch/wasm/abi.zig+2-2
...@@ -77,7 +77,7 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {...@@ -77,7 +77,7 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
77 .Union => {77 .Union => {
78 const layout = ty.unionGetLayout(target);78 const layout = ty.unionGetLayout(target);
79 if (layout.payload_size == 0 and layout.tag_size != 0) {79 if (layout.payload_size == 0 and layout.tag_size != 0) {
80 return classifyType(ty.unionTagType().?, target);80 return classifyType(ty.unionTagTypeSafety().?, target);
81 }81 }
82 if (ty.unionFields().count() > 1) return memory;82 if (ty.unionFields().count() > 1) return memory;
83 return classifyType(ty.unionFields().values()[0].ty, target);83 return classifyType(ty.unionFields().values()[0].ty, target);
...@@ -111,7 +111,7 @@ pub fn scalarType(ty: Type, target: std.Target) Type {...@@ -111,7 +111,7 @@ pub fn scalarType(ty: Type, target: std.Target) Type {
111 .Union => {111 .Union => {
112 const layout = ty.unionGetLayout(target);112 const layout = ty.unionGetLayout(target);
113 if (layout.payload_size == 0 and layout.tag_size != 0) {113 if (layout.payload_size == 0 and layout.tag_size != 0) {
114 return scalarType(ty.unionTagType().?, target);114 return scalarType(ty.unionTagTypeSafety().?, target);
115 }115 }
116 std.debug.assert(ty.unionFields().count() == 1);116 std.debug.assert(ty.unionFields().count() == 1);
117 return scalarType(ty.unionFields().values()[0].ty, target);117 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 {...@@ -751,6 +751,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
751 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),751 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
752 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),752 .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
754 .wasm_memory_size => unreachable,778 .wasm_memory_size => unreachable,
755 .wasm_memory_grow => unreachable,779 .wasm_memory_grow => unreachable,
756 // zig fmt: on780 // zig fmt: on
src/codegen/c.zig+33-9
...@@ -504,7 +504,7 @@ pub const DeclGen = struct {...@@ -504,7 +504,7 @@ pub const DeclGen = struct {
504 if (field_ty.hasRuntimeBitsIgnoreComptime()) {504 if (field_ty.hasRuntimeBitsIgnoreComptime()) {
505 try writer.writeAll("&(");505 try writer.writeAll("&(");
506 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);506 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) {
508 try writer.print(")->payload.{ }", .{fmtIdent(field_name)});508 try writer.print(")->payload.{ }", .{fmtIdent(field_name)});
509 } else {509 } else {
510 try writer.print(")->{ }", .{fmtIdent(field_name)});510 try writer.print(")->{ }", .{fmtIdent(field_name)});
...@@ -842,7 +842,7 @@ pub const DeclGen = struct {...@@ -842,7 +842,7 @@ pub const DeclGen = struct {
842 try dg.renderTypecast(writer, ty);842 try dg.renderTypecast(writer, ty);
843 try writer.writeAll("){");843 try writer.writeAll("){");
844844
845 if (ty.unionTagType()) |tag_ty| {845 if (ty.unionTagTypeSafety()) |tag_ty| {
846 if (layout.tag_size != 0) {846 if (layout.tag_size != 0) {
847 try writer.writeAll(".tag = ");847 try writer.writeAll(".tag = ");
848 try dg.renderValue(writer, tag_ty, union_obj.tag, location);848 try dg.renderValue(writer, tag_ty, union_obj.tag, location);
...@@ -858,7 +858,7 @@ pub const DeclGen = struct {...@@ -858,7 +858,7 @@ pub const DeclGen = struct {
858 try writer.print(".{ } = ", .{fmtIdent(field_name)});858 try writer.print(".{ } = ", .{fmtIdent(field_name)});
859 try dg.renderValue(writer, field_ty, union_obj.val, location);859 try dg.renderValue(writer, field_ty, union_obj.val, location);
860 }860 }
861 if (ty.unionTagType()) |_| {861 if (ty.unionTagTypeSafety()) |_| {
862 try writer.writeAll("}");862 try writer.writeAll("}");
863 }863 }
864 try writer.writeAll("}");864 try writer.writeAll("}");
...@@ -1110,7 +1110,7 @@ pub const DeclGen = struct {...@@ -1110,7 +1110,7 @@ pub const DeclGen = struct {
1110 defer buffer.deinit();1110 defer buffer.deinit();
11111111
1112 try buffer.appendSlice("typedef ");1112 try buffer.appendSlice("typedef ");
1113 if (t.unionTagType()) |tag_ty| {1113 if (t.unionTagTypeSafety()) |tag_ty| {
1114 const name: CValue = .{ .bytes = "tag" };1114 const name: CValue = .{ .bytes = "tag" };
1115 try buffer.appendSlice("struct {\n ");1115 try buffer.appendSlice("struct {\n ");
1116 if (layout.tag_size != 0) {1116 if (layout.tag_size != 0) {
...@@ -1134,7 +1134,7 @@ pub const DeclGen = struct {...@@ -1134,7 +1134,7 @@ pub const DeclGen = struct {
1134 }1134 }
1135 try buffer.appendSlice("} ");1135 try buffer.appendSlice("} ");
11361136
1137 if (t.unionTagType()) |_| {1137 if (t.unionTagTypeSafety()) |_| {
1138 try buffer.appendSlice("payload;\n} ");1138 try buffer.appendSlice("payload;\n} ");
1139 }1139 }
11401140
...@@ -1928,6 +1928,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1928,6 +1928,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19281928
1929 .wasm_memory_size => try airWasmMemorySize(f, inst),1929 .wasm_memory_size => try airWasmMemorySize(f, inst),
1930 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),1930 .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", .{}),
1931 // zig fmt: on1955 // zig fmt: on
1932 };1956 };
1933 switch (result_value) {1957 switch (result_value) {
...@@ -3368,7 +3392,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -3368,7 +3392,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
3368 field_name = fields.keys()[index];3392 field_name = fields.keys()[index];
3369 field_val_ty = fields.values()[index].ty;3393 field_val_ty = fields.values()[index].ty;
3370 },3394 },
3371 .@"union", .union_tagged => {3395 .@"union", .union_safety_tagged, .union_tagged => {
3372 const fields = struct_ty.unionFields();3396 const fields = struct_ty.unionFields();
3373 field_name = fields.keys()[index];3397 field_name = fields.keys()[index];
3374 field_val_ty = fields.values()[index].ty;3398 field_val_ty = fields.values()[index].ty;
...@@ -3383,7 +3407,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -3383,7 +3407,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
3383 },3407 },
3384 else => unreachable,3408 else => unreachable,
3385 }3409 }
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
3388 const inst_ty = f.air.typeOfIndex(inst);3412 const inst_ty = f.air.typeOfIndex(inst);
3389 const local = try f.allocLocal(inst_ty, .Const);3413 const local = try f.allocLocal(inst_ty, .Const);
...@@ -3415,7 +3439,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3415,7 +3439,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3415 defer buf.deinit();3439 defer buf.deinit();
3416 const field_name = switch (struct_ty.tag()) {3440 const field_name = switch (struct_ty.tag()) {
3417 .@"struct" => struct_ty.structFields().keys()[extra.field_index],3441 .@"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],
3419 .tuple, .anon_struct => blk: {3443 .tuple, .anon_struct => blk: {
3420 const tuple = struct_ty.tupleFields();3444 const tuple = struct_ty.tupleFields();
3421 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;3445 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 {...@@ -3425,7 +3449,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3425 },3449 },
3426 else => unreachable,3450 else => unreachable,
3427 };3451 };
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
3430 const inst_ty = f.air.typeOfIndex(inst);3454 const inst_ty = f.air.typeOfIndex(inst);
3431 const local = try f.allocLocal(inst_ty, .Const);3455 const local = try f.allocLocal(inst_ty, .Const);
src/codegen/llvm.zig+97-42
...@@ -3404,7 +3404,7 @@ pub const DeclGen = struct {...@@ -3404,7 +3404,7 @@ pub const DeclGen = struct {
34043404
3405 if (layout.payload_size == 0) {3405 if (layout.payload_size == 0) {
3406 return lowerValue(dg, .{3406 return lowerValue(dg, .{
3407 .ty = tv.ty.unionTagType().?,3407 .ty = tv.ty.unionTagTypeSafety().?,
3408 .val = tag_and_val.tag,3408 .val = tag_and_val.tag,
3409 });3409 });
3410 }3410 }
...@@ -3446,7 +3446,7 @@ pub const DeclGen = struct {...@@ -3446,7 +3446,7 @@ pub const DeclGen = struct {
3446 }3446 }
3447 }3447 }
3448 const llvm_tag_value = try lowerValue(dg, .{3448 const llvm_tag_value = try lowerValue(dg, .{
3449 .ty = tv.ty.unionTagType().?,3449 .ty = tv.ty.unionTagTypeSafety().?,
3450 .val = tag_and_val.tag,3450 .val = tag_and_val.tag,
3451 });3451 });
3452 var fields: [3]*const llvm.Value = undefined;3452 var fields: [3]*const llvm.Value = undefined;
...@@ -3984,21 +3984,21 @@ pub const FuncGen = struct {...@@ -3984,21 +3984,21 @@ pub const FuncGen = struct {
3984 for (body) |inst, i| {3984 for (body) |inst, i| {
3985 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {3985 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
3986 // zig fmt: off3986 // zig fmt: off
3987 .add => try self.airAdd(inst),3987 .add => try self.airAdd(inst, false),
3988 .addwrap => try self.airAddWrap(inst),3988 .addwrap => try self.airAddWrap(inst, false),
3989 .add_sat => try self.airAddSat(inst),3989 .add_sat => try self.airAddSat(inst),
3990 .sub => try self.airSub(inst),3990 .sub => try self.airSub(inst, false),
3991 .subwrap => try self.airSubWrap(inst),3991 .subwrap => try self.airSubWrap(inst, false),
3992 .sub_sat => try self.airSubSat(inst),3992 .sub_sat => try self.airSubSat(inst),
3993 .mul => try self.airMul(inst),3993 .mul => try self.airMul(inst, false),
3994 .mulwrap => try self.airMulWrap(inst),3994 .mulwrap => try self.airMulWrap(inst, false),
3995 .mul_sat => try self.airMulSat(inst),3995 .mul_sat => try self.airMulSat(inst),
3996 .div_float => try self.airDivFloat(inst),3996 .div_float => try self.airDivFloat(inst, false),
3997 .div_trunc => try self.airDivTrunc(inst),3997 .div_trunc => try self.airDivTrunc(inst, false),
3998 .div_floor => try self.airDivFloor(inst),3998 .div_floor => try self.airDivFloor(inst, false),
3999 .div_exact => try self.airDivExact(inst),3999 .div_exact => try self.airDivExact(inst, false),
4000 .rem => try self.airRem(inst),4000 .rem => try self.airRem(inst, false),
4001 .mod => try self.airMod(inst),4001 .mod => try self.airMod(inst, false),
4002 .ptr_add => try self.airPtrAdd(inst),4002 .ptr_add => try self.airPtrAdd(inst),
4003 .ptr_sub => try self.airPtrSub(inst),4003 .ptr_sub => try self.airPtrSub(inst),
4004 .shl => try self.airShl(inst),4004 .shl => try self.airShl(inst),
...@@ -4009,6 +4009,19 @@ pub const FuncGen = struct {...@@ -4009,6 +4009,19 @@ pub const FuncGen = struct {
4009 .slice => try self.airSlice(inst),4009 .slice => try self.airSlice(inst),
4010 .mul_add => try self.airMulAdd(inst),4010 .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
4012 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),4025 .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
4013 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),4026 .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
4014 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),4027 .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
...@@ -4034,17 +4047,27 @@ pub const FuncGen = struct {...@@ -4034,17 +4047,27 @@ pub const FuncGen = struct {
4034 .ceil => try self.airUnaryOp(inst, .ceil),4047 .ceil => try self.airUnaryOp(inst, .ceil),
4035 .round => try self.airUnaryOp(inst, .round),4048 .round => try self.airUnaryOp(inst, .round),
4036 .trunc_float => try self.airUnaryOp(inst, .trunc),4049 .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),4051 .neg => try self.airNeg(inst, false),
4047 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),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
4049 .is_non_null => try self.airIsNonNull(inst, false, .NE),4072 .is_non_null => try self.airIsNonNull(inst, false, .NE),
4050 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),4073 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),
...@@ -4093,8 +4116,10 @@ pub const FuncGen = struct {...@@ -4093,8 +4116,10 @@ pub const FuncGen = struct {
4093 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),4116 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
4094 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),4117 .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
4096 .array_to_slice => try self.airArrayToSlice(inst),4122 .array_to_slice => try self.airArrayToSlice(inst),
4097 .float_to_int => try self.airFloatToInt(inst),
4098 .int_to_float => try self.airIntToFloat(inst),4123 .int_to_float => try self.airIntToFloat(inst),
4099 .cmpxchg_weak => try self.airCmpxchg(inst, true),4124 .cmpxchg_weak => try self.airCmpxchg(inst, true),
4100 .cmpxchg_strong => try self.airCmpxchg(inst, false),4125 .cmpxchg_strong => try self.airCmpxchg(inst, false),
...@@ -4115,11 +4140,13 @@ pub const FuncGen = struct {...@@ -4115,11 +4140,13 @@ pub const FuncGen = struct {
4115 .splat => try self.airSplat(inst),4140 .splat => try self.airSplat(inst),
4116 .select => try self.airSelect(inst),4141 .select => try self.airSelect(inst),
4117 .shuffle => try self.airShuffle(inst),4142 .shuffle => try self.airShuffle(inst),
4118 .reduce => try self.airReduce(inst),
4119 .aggregate_init => try self.airAggregateInit(inst),4143 .aggregate_init => try self.airAggregateInit(inst),
4120 .union_init => try self.airUnionInit(inst),4144 .union_init => try self.airUnionInit(inst),
4121 .prefetch => try self.airPrefetch(inst),4145 .prefetch => try self.airPrefetch(inst),
41224146
4147 .reduce => try self.airReduce(inst, false),
4148 .reduce_optimized => try self.airReduce(inst, true),
4149
4123 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),4150 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
4124 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),4151 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
4125 .atomic_store_release => try self.airAtomicStore(inst, .Release),4152 .atomic_store_release => try self.airAtomicStore(inst, .Release),
...@@ -4485,8 +4512,9 @@ pub const FuncGen = struct {...@@ -4485,8 +4512,9 @@ pub const FuncGen = struct {
4485 return null;4512 return null;
4486 }4513 }
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 {
4489 if (self.liveness.isUnused(inst)) return null;4516 if (self.liveness.isUnused(inst)) return null;
4517 self.builder.setFastMath(want_fast_math);
44904518
4491 const bin_op = self.air.instructions.items(.data)[inst].bin_op;4519 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
4492 const lhs = try self.resolveInst(bin_op.lhs);4520 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -4496,8 +4524,9 @@ pub const FuncGen = struct {...@@ -4496,8 +4524,9 @@ pub const FuncGen = struct {
4496 return self.cmp(lhs, rhs, operand_ty, op);4524 return self.cmp(lhs, rhs, operand_ty, op);
4497 }4525 }
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 {
4500 if (self.liveness.isUnused(inst)) return null;4528 if (self.liveness.isUnused(inst)) return null;
4529 self.builder.setFastMath(want_fast_math);
45014530
4502 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;4531 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4503 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;4532 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
...@@ -4943,10 +4972,12 @@ pub const FuncGen = struct {...@@ -4943,10 +4972,12 @@ pub const FuncGen = struct {
4943 return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, "");4972 return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, "");
4944 }4973 }
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 {
4947 if (self.liveness.isUnused(inst))4976 if (self.liveness.isUnused(inst))
4948 return null;4977 return null;
49494978
4979 self.builder.setFastMath(want_fast_math);
4980
4950 const target = self.dg.module.getTarget();4981 const target = self.dg.module.getTarget();
4951 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4982 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
49524983
...@@ -6095,8 +6126,9 @@ pub const FuncGen = struct {...@@ -6095,8 +6126,9 @@ pub const FuncGen = struct {
6095 return self.builder.buildInsertValue(partial, len, 1, "");6126 return self.builder.buildInsertValue(partial, len, 1, "");
6096 }6127 }
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 {
6099 if (self.liveness.isUnused(inst)) return null;6130 if (self.liveness.isUnused(inst)) return null;
6131 self.builder.setFastMath(want_fast_math);
61006132
6101 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6133 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6102 const lhs = try self.resolveInst(bin_op.lhs);6134 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6109,8 +6141,9 @@ pub const FuncGen = struct {...@@ -6109,8 +6141,9 @@ pub const FuncGen = struct {
6109 return self.builder.buildNUWAdd(lhs, rhs, "");6141 return self.builder.buildNUWAdd(lhs, rhs, "");
6110 }6142 }
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 {
6113 if (self.liveness.isUnused(inst)) return null;6145 if (self.liveness.isUnused(inst)) return null;
6146 self.builder.setFastMath(want_fast_math);
61146147
6115 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6148 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6116 const lhs = try self.resolveInst(bin_op.lhs);6149 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6134,8 +6167,9 @@ pub const FuncGen = struct {...@@ -6134,8 +6167,9 @@ pub const FuncGen = struct {
6134 return self.builder.buildUAddSat(lhs, rhs, "");6167 return self.builder.buildUAddSat(lhs, rhs, "");
6135 }6168 }
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 {
6138 if (self.liveness.isUnused(inst)) return null;6171 if (self.liveness.isUnused(inst)) return null;
6172 self.builder.setFastMath(want_fast_math);
61396173
6140 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6174 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6141 const lhs = try self.resolveInst(bin_op.lhs);6175 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6148,8 +6182,9 @@ pub const FuncGen = struct {...@@ -6148,8 +6182,9 @@ pub const FuncGen = struct {
6148 return self.builder.buildNUWSub(lhs, rhs, "");6182 return self.builder.buildNUWSub(lhs, rhs, "");
6149 }6183 }
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 {
6152 if (self.liveness.isUnused(inst)) return null;6186 if (self.liveness.isUnused(inst)) return null;
6187 self.builder.setFastMath(want_fast_math);
61536188
6154 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6189 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6155 const lhs = try self.resolveInst(bin_op.lhs);6190 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6172,8 +6207,9 @@ pub const FuncGen = struct {...@@ -6172,8 +6207,9 @@ pub const FuncGen = struct {
6172 return self.builder.buildUSubSat(lhs, rhs, "");6207 return self.builder.buildUSubSat(lhs, rhs, "");
6173 }6208 }
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 {
6176 if (self.liveness.isUnused(inst)) return null;6211 if (self.liveness.isUnused(inst)) return null;
6212 self.builder.setFastMath(want_fast_math);
61776213
6178 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6214 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6179 const lhs = try self.resolveInst(bin_op.lhs);6215 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6186,8 +6222,9 @@ pub const FuncGen = struct {...@@ -6186,8 +6222,9 @@ pub const FuncGen = struct {
6186 return self.builder.buildNUWMul(lhs, rhs, "");6222 return self.builder.buildNUWMul(lhs, rhs, "");
6187 }6223 }
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 {
6190 if (self.liveness.isUnused(inst)) return null;6226 if (self.liveness.isUnused(inst)) return null;
6227 self.builder.setFastMath(want_fast_math);
61916228
6192 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6229 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6193 const lhs = try self.resolveInst(bin_op.lhs);6230 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6210,8 +6247,9 @@ pub const FuncGen = struct {...@@ -6210,8 +6247,9 @@ pub const FuncGen = struct {
6210 return self.builder.buildUMulFixSat(lhs, rhs, "");6247 return self.builder.buildUMulFixSat(lhs, rhs, "");
6211 }6248 }
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 {
6214 if (self.liveness.isUnused(inst)) return null;6251 if (self.liveness.isUnused(inst)) return null;
6252 self.builder.setFastMath(want_fast_math);
62156253
6216 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6254 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6217 const lhs = try self.resolveInst(bin_op.lhs);6255 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6221,8 +6259,9 @@ pub const FuncGen = struct {...@@ -6221,8 +6259,9 @@ pub const FuncGen = struct {
6221 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });6259 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
6222 }6260 }
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 {
6225 if (self.liveness.isUnused(inst)) return null;6263 if (self.liveness.isUnused(inst)) return null;
6264 self.builder.setFastMath(want_fast_math);
62266265
6227 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6266 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6228 const lhs = try self.resolveInst(bin_op.lhs);6267 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6238,8 +6277,9 @@ pub const FuncGen = struct {...@@ -6238,8 +6277,9 @@ pub const FuncGen = struct {
6238 return self.builder.buildUDiv(lhs, rhs, "");6277 return self.builder.buildUDiv(lhs, rhs, "");
6239 }6278 }
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 {
6242 if (self.liveness.isUnused(inst)) return null;6281 if (self.liveness.isUnused(inst)) return null;
6282 self.builder.setFastMath(want_fast_math);
62436283
6244 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6284 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6245 const lhs = try self.resolveInst(bin_op.lhs);6285 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6270,8 +6310,9 @@ pub const FuncGen = struct {...@@ -6270,8 +6310,9 @@ pub const FuncGen = struct {
6270 return self.builder.buildUDiv(lhs, rhs, "");6310 return self.builder.buildUDiv(lhs, rhs, "");
6271 }6311 }
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 {
6274 if (self.liveness.isUnused(inst)) return null;6314 if (self.liveness.isUnused(inst)) return null;
6315 self.builder.setFastMath(want_fast_math);
62756316
6276 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6317 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6277 const lhs = try self.resolveInst(bin_op.lhs);6318 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6284,8 +6325,9 @@ pub const FuncGen = struct {...@@ -6284,8 +6325,9 @@ pub const FuncGen = struct {
6284 return self.builder.buildExactUDiv(lhs, rhs, "");6325 return self.builder.buildExactUDiv(lhs, rhs, "");
6285 }6326 }
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 {
6288 if (self.liveness.isUnused(inst)) return null;6329 if (self.liveness.isUnused(inst)) return null;
6330 self.builder.setFastMath(want_fast_math);
62896331
6290 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6332 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6291 const lhs = try self.resolveInst(bin_op.lhs);6333 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -6298,8 +6340,9 @@ pub const FuncGen = struct {...@@ -6298,8 +6340,9 @@ pub const FuncGen = struct {
6298 return self.builder.buildURem(lhs, rhs, "");6340 return self.builder.buildURem(lhs, rhs, "");
6299 }6341 }
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 {
6302 if (self.liveness.isUnused(inst)) return null;6344 if (self.liveness.isUnused(inst)) return null;
6345 self.builder.setFastMath(want_fast_math);
63036346
6304 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6347 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6305 const lhs = try self.resolveInst(bin_op.lhs);6348 const lhs = try self.resolveInst(bin_op.lhs);
...@@ -7613,6 +7656,17 @@ pub const FuncGen = struct {...@@ -7613,6 +7656,17 @@ pub const FuncGen = struct {
7613 return self.buildFloatOp(op, operand_ty, 1, .{operand});7656 return self.buildFloatOp(op, operand_ty, 1, .{operand});
7614 }7657 }
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
7616 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {7670 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
7617 if (self.liveness.isUnused(inst)) return null;7671 if (self.liveness.isUnused(inst)) return null;
76187672
...@@ -7927,8 +7981,9 @@ pub const FuncGen = struct {...@@ -7927,8 +7981,9 @@ pub const FuncGen = struct {
7927 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");7981 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
7928 }7982 }
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 {
7931 if (self.liveness.isUnused(inst)) return null;7985 if (self.liveness.isUnused(inst)) return null;
7986 self.builder.setFastMath(want_fast_math);
79327987
7933 const reduce = self.air.instructions.items(.data)[inst].reduce;7988 const reduce = self.air.instructions.items(.data)[inst].reduce;
7934 const operand = try self.resolveInst(reduce.operand);7989 const operand = try self.resolveInst(reduce.operand);
src/codegen/llvm/bindings.zig+3
...@@ -941,6 +941,9 @@ pub const Builder = opaque {...@@ -941,6 +941,9 @@ pub const Builder = opaque {
941941
942 pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce;942 pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce;
943 extern fn ZigLLVMBuildFPMulReduce(B: *const Builder, Acc: *const Value, Val: *const Value) *const Value;943 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;
944};947};
945948
946pub const MDString = opaque {949pub const MDString = opaque {
src/print_air.zig+22-2
...@@ -138,6 +138,24 @@ const Writer = struct {...@@ -138,6 +138,24 @@ const Writer = struct {
138 .set_union_tag,138 .set_union_tag,
139 .min,139 .min,
140 .max,140 .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,
141 => try w.writeBinOp(s, inst),159 => try w.writeBinOp(s, inst),
142160
143 .is_null,161 .is_null,
...@@ -169,6 +187,7 @@ const Writer = struct {...@@ -169,6 +187,7 @@ const Writer = struct {
169 .round,187 .round,
170 .trunc_float,188 .trunc_float,
171 .neg,189 .neg,
190 .neg_optimized,
172 .cmp_lt_errors_len,191 .cmp_lt_errors_len,
173 .set_err_return_trace,192 .set_err_return_trace,
174 => try w.writeUnOp(s, inst),193 => try w.writeUnOp(s, inst),
...@@ -216,6 +235,7 @@ const Writer = struct {...@@ -216,6 +235,7 @@ const Writer = struct {
216 .int_to_float,235 .int_to_float,
217 .splat,236 .splat,
218 .float_to_int,237 .float_to_int,
238 .float_to_int_optimized,
219 .get_union_tag,239 .get_union_tag,
220 .clz,240 .clz,
221 .ctz,241 .ctz,
...@@ -280,8 +300,8 @@ const Writer = struct {...@@ -280,8 +300,8 @@ const Writer = struct {
280 .mul_add => try w.writeMulAdd(s, inst),300 .mul_add => try w.writeMulAdd(s, inst),
281 .select => try w.writeSelect(s, inst),301 .select => try w.writeSelect(s, inst),
282 .shuffle => try w.writeShuffle(s, inst),302 .shuffle => try w.writeShuffle(s, inst),
283 .reduce => try w.writeReduce(s, inst),303 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
284 .cmp_vector => try w.writeCmpVector(s, inst),304 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
285305
286 .dbg_block_begin, .dbg_block_end => {},306 .dbg_block_begin, .dbg_block_end => {},
287 }307 }
src/print_zir.zig+1
...@@ -390,6 +390,7 @@ const Writer = struct {...@@ -390,6 +390,7 @@ const Writer = struct {
390 .switch_block => try self.writeSwitchBlock(stream, inst),390 .switch_block => try self.writeSwitchBlock(stream, inst),
391391
392 .field_ptr,392 .field_ptr,
393 .field_ptr_init,
393 .field_val,394 .field_val,
394 .field_call_bind,395 .field_call_bind,
395 => try self.writePlNodeField(stream, inst),396 => try self.writePlNodeField(stream, inst),
src/type.zig+61-28
...@@ -149,6 +149,7 @@ pub const Type = extern union {...@@ -149,6 +149,7 @@ pub const Type = extern union {
149 => return .Enum,149 => return .Enum,
150150
151 .@"union",151 .@"union",
152 .union_safety_tagged,
152 .union_tagged,153 .union_tagged,
153 .type_info,154 .type_info,
154 => return .Union,155 => return .Union,
...@@ -902,7 +903,7 @@ pub const Type = extern union {...@@ -902,7 +903,7 @@ pub const Type = extern union {
902 .reduce_op,903 .reduce_op,
903 => unreachable, // needed to resolve the type before now904 => unreachable, // needed to resolve the type before now
904905
905 .@"union", .union_tagged => {906 .@"union", .union_safety_tagged, .union_tagged => {
906 const a_union_obj = a.cast(Payload.Union).?.data;907 const a_union_obj = a.cast(Payload.Union).?.data;
907 const b_union_obj = (b.cast(Payload.Union) orelse return false).data;908 const b_union_obj = (b.cast(Payload.Union) orelse return false).data;
908 return a_union_obj == b_union_obj;909 return a_union_obj == b_union_obj;
...@@ -1210,7 +1211,7 @@ pub const Type = extern union {...@@ -1210,7 +1211,7 @@ pub const Type = extern union {
1210 .reduce_op,1211 .reduce_op,
1211 => unreachable, // needed to resolve the type before now1212 => unreachable, // needed to resolve the type before now
12121213
1213 .@"union", .union_tagged => {1214 .@"union", .union_safety_tagged, .union_tagged => {
1214 const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;1215 const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;
1215 std.hash.autoHash(hasher, std.builtin.TypeId.Union);1216 std.hash.autoHash(hasher, std.builtin.TypeId.Union);
1216 std.hash.autoHash(hasher, union_obj);1217 std.hash.autoHash(hasher, union_obj);
...@@ -1479,7 +1480,7 @@ pub const Type = extern union {...@@ -1479,7 +1480,7 @@ pub const Type = extern union {
1479 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),1480 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
1480 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),1481 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
1481 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),1482 .@"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),
1483 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),1484 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
1484 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),1485 .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
1485 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),1486 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
...@@ -1603,7 +1604,7 @@ pub const Type = extern union {...@@ -1603,7 +1604,7 @@ pub const Type = extern union {
1603 @tagName(t), struct_obj.owner_decl,1604 @tagName(t), struct_obj.owner_decl,
1604 });1605 });
1605 },1606 },
1606 .@"union", .union_tagged => {1607 .@"union", .union_safety_tagged, .union_tagged => {
1607 const union_obj = ty.cast(Payload.Union).?.data;1608 const union_obj = ty.cast(Payload.Union).?.data;
1608 return writer.print("({s} decl={d})", .{1609 return writer.print("({s} decl={d})", .{
1609 @tagName(t), union_obj.owner_decl,1610 @tagName(t), union_obj.owner_decl,
...@@ -1989,7 +1990,7 @@ pub const Type = extern union {...@@ -1989,7 +1990,7 @@ pub const Type = extern union {
1989 const decl = mod.declPtr(struct_obj.owner_decl);1990 const decl = mod.declPtr(struct_obj.owner_decl);
1990 try decl.renderFullyQualifiedName(mod, writer);1991 try decl.renderFullyQualifiedName(mod, writer);
1991 },1992 },
1992 .@"union", .union_tagged => {1993 .@"union", .union_safety_tagged, .union_tagged => {
1993 const union_obj = ty.cast(Payload.Union).?.data;1994 const union_obj = ty.cast(Payload.Union).?.data;
1994 const decl = mod.declPtr(union_obj.owner_decl);1995 const decl = mod.declPtr(union_obj.owner_decl);
1995 try decl.renderFullyQualifiedName(mod, writer);1996 try decl.renderFullyQualifiedName(mod, writer);
...@@ -2485,8 +2486,8 @@ pub const Type = extern union {...@@ -2485,8 +2486,8 @@ pub const Type = extern union {
2485 return false;2486 return false;
2486 }2487 }
2487 },2488 },
2488 .union_tagged => {2489 .union_safety_tagged, .union_tagged => {
2489 const union_obj = ty.castTag(.union_tagged).?.data;2490 const union_obj = ty.cast(Payload.Union).?.data;
2490 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {2491 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
2491 return true;2492 return true;
2492 }2493 }
...@@ -2644,7 +2645,7 @@ pub const Type = extern union {...@@ -2644,7 +2645,7 @@ pub const Type = extern union {
26442645
2645 .optional => ty.isPtrLikeOptional(),2646 .optional => ty.isPtrLikeOptional(),
2646 .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,2647 .@"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,
2648 .union_tagged => false,2649 .union_tagged => false,
2649 };2650 };
2650 }2651 }
...@@ -3050,11 +3051,10 @@ pub const Type = extern union {...@@ -3050,11 +3051,10 @@ pub const Type = extern union {
3050 },3051 },
3051 .@"union" => {3052 .@"union" => {
3052 const union_obj = ty.castTag(.@"union").?.data;3053 const union_obj = ty.castTag(.@"union").?.data;
3053 // TODO pass `true` for have_tag when unions have a safety tag
3054 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false);3054 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false);
3055 },3055 },
3056 .union_tagged => {3056 .union_safety_tagged, .union_tagged => {
3057 const union_obj = ty.castTag(.union_tagged).?.data;3057 const union_obj = ty.cast(Payload.Union).?.data;
3058 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true);3058 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true);
3059 },3059 },
30603060
...@@ -3232,11 +3232,10 @@ pub const Type = extern union {...@@ -3232,11 +3232,10 @@ pub const Type = extern union {
3232 },3232 },
3233 .@"union" => {3233 .@"union" => {
3234 const union_obj = ty.castTag(.@"union").?.data;3234 const union_obj = ty.castTag(.@"union").?.data;
3235 // TODO pass `true` for have_tag when unions have a safety tag
3236 return abiSizeAdvancedUnion(ty, target, strat, union_obj, false);3235 return abiSizeAdvancedUnion(ty, target, strat, union_obj, false);
3237 },3236 },
3238 .union_tagged => {3237 .union_safety_tagged, .union_tagged => {
3239 const union_obj = ty.castTag(.union_tagged).?.data;3238 const union_obj = ty.cast(Payload.Union).?.data;
3240 return abiSizeAdvancedUnion(ty, target, strat, union_obj, true);3239 return abiSizeAdvancedUnion(ty, target, strat, union_obj, true);
3241 },3240 },
32423241
...@@ -3526,7 +3525,7 @@ pub const Type = extern union {...@@ -3526,7 +3525,7 @@ pub const Type = extern union {
3526 return try bitSizeAdvanced(int_tag_ty, target, sema_kit);3525 return try bitSizeAdvanced(int_tag_ty, target, sema_kit);
3527 },3526 },
35283527
3529 .@"union", .union_tagged => {3528 .@"union", .union_safety_tagged, .union_tagged => {
3530 if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);3529 if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
3531 const union_obj = ty.cast(Payload.Union).?.data;3530 const union_obj = ty.cast(Payload.Union).?.data;
3532 assert(union_obj.haveFieldTypes());3531 assert(union_obj.haveFieldTypes());
...@@ -4194,6 +4193,33 @@ pub const Type = extern union {...@@ -4194,6 +4193,33 @@ pub const Type = extern union {
4194 };4193 };
4195 }4194 }
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
4197 /// Asserts the type is a union; returns the tag type, even if the tag will4223 /// Asserts the type is a union; returns the tag type, even if the tag will
4198 /// not be stored at runtime.4224 /// not be stored at runtime.
4199 pub fn unionTagTypeHypothetical(ty: Type) Type {4225 pub fn unionTagTypeHypothetical(ty: Type) Type {
...@@ -4225,8 +4251,8 @@ pub const Type = extern union {...@@ -4225,8 +4251,8 @@ pub const Type = extern union {
4225 const union_obj = ty.castTag(.@"union").?.data;4251 const union_obj = ty.castTag(.@"union").?.data;
4226 return union_obj.getLayout(target, false);4252 return union_obj.getLayout(target, false);
4227 },4253 },
4228 .union_tagged => {4254 .union_safety_tagged, .union_tagged => {
4229 const union_obj = ty.castTag(.union_tagged).?.data;4255 const union_obj = ty.cast(Payload.Union).?.data;
4230 return union_obj.getLayout(target, true);4256 return union_obj.getLayout(target, true);
4231 },4257 },
4232 else => unreachable,4258 else => unreachable,
...@@ -4238,6 +4264,7 @@ pub const Type = extern union {...@@ -4238,6 +4264,7 @@ pub const Type = extern union {
4238 .tuple, .empty_struct_literal, .anon_struct => .Auto,4264 .tuple, .empty_struct_literal, .anon_struct => .Auto,
4239 .@"struct" => ty.castTag(.@"struct").?.data.layout,4265 .@"struct" => ty.castTag(.@"struct").?.data.layout,
4240 .@"union" => ty.castTag(.@"union").?.data.layout,4266 .@"union" => ty.castTag(.@"union").?.data.layout,
4267 .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout,
4241 .union_tagged => ty.castTag(.union_tagged).?.data.layout,4268 .union_tagged => ty.castTag(.union_tagged).?.data.layout,
4242 else => unreachable,4269 else => unreachable,
4243 };4270 };
...@@ -4936,7 +4963,7 @@ pub const Type = extern union {...@@ -4936,7 +4963,7 @@ pub const Type = extern union {
4936 return null;4963 return null;
4937 }4964 }
4938 },4965 },
4939 .@"union", .union_tagged => {4966 .@"union", .union_safety_tagged, .union_tagged => {
4940 const union_obj = ty.cast(Payload.Union).?.data;4967 const union_obj = ty.cast(Payload.Union).?.data;
4941 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;4968 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
4942 const only_field = union_obj.fields.values()[0];4969 const only_field = union_obj.fields.values()[0];
...@@ -5114,7 +5141,7 @@ pub const Type = extern union {...@@ -5114,7 +5141,7 @@ pub const Type = extern union {
5114 }5141 }
5115 },5142 },
51165143
5117 .@"union", .union_tagged => {5144 .@"union", .union_safety_tagged, .union_tagged => {
5118 const union_obj = ty.cast(Type.Payload.Union).?.data;5145 const union_obj = ty.cast(Type.Payload.Union).?.data;
5119 switch (union_obj.requires_comptime) {5146 switch (union_obj.requires_comptime) {
5120 .wip, .unknown => unreachable, // This function asserts types already resolved.5147 .wip, .unknown => unreachable, // This function asserts types already resolved.
...@@ -5167,6 +5194,7 @@ pub const Type = extern union {...@@ -5167,6 +5194,7 @@ pub const Type = extern union {
5167 .empty_struct => self.castTag(.empty_struct).?.data,5194 .empty_struct => self.castTag(.empty_struct).?.data,
5168 .@"opaque" => &self.castTag(.@"opaque").?.data.namespace,5195 .@"opaque" => &self.castTag(.@"opaque").?.data.namespace,
5169 .@"union" => &self.castTag(.@"union").?.data.namespace,5196 .@"union" => &self.castTag(.@"union").?.data.namespace,
5197 .union_safety_tagged => &self.castTag(.union_safety_tagged).?.data.namespace,
5170 .union_tagged => &self.castTag(.union_tagged).?.data.namespace,5198 .union_tagged => &self.castTag(.union_tagged).?.data.namespace,
51715199
5172 else => null,5200 else => null,
...@@ -5439,7 +5467,7 @@ pub const Type = extern union {...@@ -5439,7 +5467,7 @@ pub const Type = extern union {
5439 const struct_obj = ty.castTag(.@"struct").?.data;5467 const struct_obj = ty.castTag(.@"struct").?.data;
5440 return struct_obj.fields.values()[index].ty;5468 return struct_obj.fields.values()[index].ty;
5441 },5469 },
5442 .@"union", .union_tagged => {5470 .@"union", .union_safety_tagged, .union_tagged => {
5443 const union_obj = ty.cast(Payload.Union).?.data;5471 const union_obj = ty.cast(Payload.Union).?.data;
5444 return union_obj.fields.values()[index].ty;5472 return union_obj.fields.values()[index].ty;
5445 },5473 },
...@@ -5456,7 +5484,7 @@ pub const Type = extern union {...@@ -5456,7 +5484,7 @@ pub const Type = extern union {
5456 assert(struct_obj.layout != .Packed);5484 assert(struct_obj.layout != .Packed);
5457 return struct_obj.fields.values()[index].normalAlignment(target);5485 return struct_obj.fields.values()[index].normalAlignment(target);
5458 },5486 },
5459 .@"union", .union_tagged => {5487 .@"union", .union_safety_tagged, .union_tagged => {
5460 const union_obj = ty.cast(Payload.Union).?.data;5488 const union_obj = ty.cast(Payload.Union).?.data;
5461 return union_obj.fields.values()[index].normalAlignment(target);5489 return union_obj.fields.values()[index].normalAlignment(target);
5462 },5490 },
...@@ -5619,8 +5647,8 @@ pub const Type = extern union {...@@ -5619,8 +5647,8 @@ pub const Type = extern union {
5619 },5647 },
56205648
5621 .@"union" => return 0,5649 .@"union" => return 0,
5622 .union_tagged => {5650 .union_safety_tagged, .union_tagged => {
5623 const union_obj = ty.castTag(.union_tagged).?.data;5651 const union_obj = ty.cast(Payload.Union).?.data;
5624 const layout = union_obj.getLayout(target, true);5652 const layout = union_obj.getLayout(target, true);
5625 if (layout.tag_align >= layout.payload_align) {5653 if (layout.tag_align >= layout.payload_align) {
5626 // {Tag, Payload}5654 // {Tag, Payload}
...@@ -5660,7 +5688,7 @@ pub const Type = extern union {...@@ -5660,7 +5688,7 @@ pub const Type = extern union {
5660 const error_set = ty.castTag(.error_set).?.data;5688 const error_set = ty.castTag(.error_set).?.data;
5661 return error_set.srcLoc(mod);5689 return error_set.srcLoc(mod);
5662 },5690 },
5663 .@"union", .union_tagged => {5691 .@"union", .union_safety_tagged, .union_tagged => {
5664 const union_obj = ty.cast(Payload.Union).?.data;5692 const union_obj = ty.cast(Payload.Union).?.data;
5665 return union_obj.srcLoc(mod);5693 return union_obj.srcLoc(mod);
5666 },5694 },
...@@ -5686,6 +5714,10 @@ pub const Type = extern union {...@@ -5686,6 +5714,10 @@ pub const Type = extern union {
5686 }5714 }
56875715
5688 pub fn getOwnerDecl(ty: Type) Module.Decl.Index {5716 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 {
5689 switch (ty.tag()) {5721 switch (ty.tag()) {
5690 .enum_full, .enum_nonexhaustive => {5722 .enum_full, .enum_nonexhaustive => {
5691 const enum_full = ty.cast(Payload.EnumFull).?.data;5723 const enum_full = ty.cast(Payload.EnumFull).?.data;
...@@ -5704,7 +5736,7 @@ pub const Type = extern union {...@@ -5704,7 +5736,7 @@ pub const Type = extern union {
5704 const error_set = ty.castTag(.error_set).?.data;5736 const error_set = ty.castTag(.error_set).?.data;
5705 return error_set.owner_decl;5737 return error_set.owner_decl;
5706 },5738 },
5707 .@"union", .union_tagged => {5739 .@"union", .union_safety_tagged, .union_tagged => {
5708 const union_obj = ty.cast(Payload.Union).?.data;5740 const union_obj = ty.cast(Payload.Union).?.data;
5709 return union_obj.owner_decl;5741 return union_obj.owner_decl;
5710 },5742 },
...@@ -5725,7 +5757,7 @@ pub const Type = extern union {...@@ -5725,7 +5757,7 @@ pub const Type = extern union {
5725 .type_info,5757 .type_info,
5726 => unreachable, // These need to be resolved earlier.5758 => unreachable, // These need to be resolved earlier.
57275759
5728 else => unreachable,5760 else => return null,
5729 }5761 }
5730 }5762 }
57315763
...@@ -5748,7 +5780,7 @@ pub const Type = extern union {...@@ -5748,7 +5780,7 @@ pub const Type = extern union {
5748 const error_set = ty.castTag(.error_set).?.data;5780 const error_set = ty.castTag(.error_set).?.data;
5749 return error_set.node_offset;5781 return error_set.node_offset;
5750 },5782 },
5751 .@"union", .union_tagged => {5783 .@"union", .union_safety_tagged, .union_tagged => {
5752 const union_obj = ty.cast(Payload.Union).?.data;5784 const union_obj = ty.cast(Payload.Union).?.data;
5753 return union_obj.node_offset;5785 return union_obj.node_offset;
5754 },5786 },
...@@ -5893,6 +5925,7 @@ pub const Type = extern union {...@@ -5893,6 +5925,7 @@ pub const Type = extern union {
5893 @"opaque",5925 @"opaque",
5894 @"struct",5926 @"struct",
5895 @"union",5927 @"union",
5928 union_safety_tagged,
5896 union_tagged,5929 union_tagged,
5897 enum_simple,5930 enum_simple,
5898 enum_numbered,5931 enum_numbered,
...@@ -6009,7 +6042,7 @@ pub const Type = extern union {...@@ -6009,7 +6042,7 @@ pub const Type = extern union {
6009 .error_set_single => Payload.Name,6042 .error_set_single => Payload.Name,
6010 .@"opaque" => Payload.Opaque,6043 .@"opaque" => Payload.Opaque,
6011 .@"struct" => Payload.Struct,6044 .@"struct" => Payload.Struct,
6012 .@"union", .union_tagged => Payload.Union,6045 .@"union", .union_safety_tagged, .union_tagged => Payload.Union,
6013 .enum_full, .enum_nonexhaustive => Payload.EnumFull,6046 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
6014 .enum_simple => Payload.EnumSimple,6047 .enum_simple => Payload.EnumSimple,
6015 .enum_numbered => Payload.EnumNumbered,6048 .enum_numbered => Payload.EnumNumbered,
test/behavior/align.zig+1
...@@ -222,6 +222,7 @@ fn testBytesAlign(b: u8) !void {...@@ -222,6 +222,7 @@ fn testBytesAlign(b: u8) !void {
222test "@alignCast slices" {222test "@alignCast slices" {
223 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;223 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
225226
226 var array align(4) = [_]u32{ 1, 1 };227 var array align(4) = [_]u32{ 1, 1 };
227 const slice = array[0..];228 const slice = array[0..];
test/behavior/bugs/1381.zig+2
...@@ -12,8 +12,10 @@ const A = union(enum) {...@@ -12,8 +12,10 @@ const A = union(enum) {
12};12};
1313
14test "union that needs padding bytes inside an array" {14test "union that needs padding bytes inside an array" {
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1719
18 var as = [_]A{20 var as = [_]A{
19 A{ .B = B{ .D = 1 } },21 A{ .B = B{ .D = 1 } },
test/behavior/cast.zig+3
...@@ -127,6 +127,7 @@ test "@intToFloat(f80)" {...@@ -127,6 +127,7 @@ test "@intToFloat(f80)" {
127 }127 }
128128
129 fn testIntToFloat(comptime Int: type, k: Int) !void {129 fn testIntToFloat(comptime Int: type, k: Int) !void {
130 @setRuntimeSafety(false); // TODO
130 const f = @intToFloat(f80, k);131 const f = @intToFloat(f80, k);
131 const i = @floatToInt(Int, f);132 const i = @floatToInt(Int, f);
132 try expect(i == k);133 try expect(i == k);
...@@ -151,6 +152,8 @@ test "@intToFloat(f80)" {...@@ -151,6 +152,8 @@ test "@intToFloat(f80)" {
151test "@floatToInt" {152test "@floatToInt" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO154 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
155 try testFloatToInts();158 try testFloatToInts();
156 comptime try testFloatToInts();159 comptime try testFloatToInts();
test/behavior/math.zig+1
...@@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void {...@@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void {
377}377}
378378
379test "division" {379test "division" {
380 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
381 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO383 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" {...@@ -998,6 +998,9 @@ test "tuple element initialized with fn call" {
998}998}
999999
1000test "struct with union field" {1000test "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
1001 const Value = struct {1004 const Value = struct {
1002 ref: u32 = 2,1005 ref: u32 = 2,
1003 kind: union(enum) {1006 kind: union(enum) {
test/behavior/type.zig+1-1
...@@ -412,7 +412,7 @@ test "Type.Union" {...@@ -412,7 +412,7 @@ test "Type.Union" {
412412
413 const Untagged = @Type(.{413 const Untagged = @Type(.{
414 .Union = .{414 .Union = .{
415 .layout = .Auto,415 .layout = .Extern,
416 .tag_type = null,416 .tag_type = null,
417 .fields = &.{417 .fields = &.{
418 .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },418 .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },
test/behavior/union.zig+13
...@@ -37,6 +37,7 @@ test "init union with runtime value - floats" {...@@ -37,6 +37,7 @@ test "init union with runtime value - floats" {
3737
38test "basic unions" {38test "basic unions" {
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4041
41 var foo = Foo{ .int = 1 };42 var foo = Foo{ .int = 1 };
42 try expect(foo.int == 1);43 try expect(foo.int == 1);
...@@ -430,9 +431,11 @@ const Foo1 = union(enum) {...@@ -430,9 +431,11 @@ const Foo1 = union(enum) {
430var glbl: Foo1 = undefined;431var glbl: Foo1 = undefined;
431432
432test "global union with single field is correctly initialized" {433test "global union with single field is correctly initialized" {
434 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
433 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;435 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
438 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
436439
437 glbl = Foo1{440 glbl = Foo1{
438 .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },441 .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
...@@ -473,8 +476,11 @@ test "update the tag value for zero-sized unions" {...@@ -473,8 +476,11 @@ test "update the tag value for zero-sized unions" {
473}476}
474477
475test "union initializer generates padding only if needed" {478test "union initializer generates padding only if needed" {
479 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
481 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
478484
479 const U = union(enum) {485 const U = union(enum) {
480 A: u24,486 A: u24,
...@@ -747,9 +753,11 @@ fn Setter(attr: Attribute) type {...@@ -747,9 +753,11 @@ fn Setter(attr: Attribute) type {
747}753}
748754
749test "return union init with void payload" {755test "return union init with void payload" {
756 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
750 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;757 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
751 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
752 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
760 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
753761
754 const S = struct {762 const S = struct {
755 fn entry() !void {763 fn entry() !void {
...@@ -775,6 +783,7 @@ test "@unionInit stored to a const" {...@@ -775,6 +783,7 @@ test "@unionInit stored to a const" {
775 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO783 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
776 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO784 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
778787
779 const S = struct {788 const S = struct {
780 const U = union(enum) {789 const U = union(enum) {
...@@ -937,6 +946,7 @@ test "cast from anonymous struct to union" {...@@ -937,6 +946,7 @@ test "cast from anonymous struct to union" {
937 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO946 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO947 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
949 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
940950
941 const S = struct {951 const S = struct {
942 const U = union(enum) {952 const U = union(enum) {
...@@ -969,6 +979,7 @@ test "cast from pointer to anonymous struct to pointer to union" {...@@ -969,6 +979,7 @@ test "cast from pointer to anonymous struct to pointer to union" {
969 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO979 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
970 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
971 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO981 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
982 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
972983
973 const S = struct {984 const S = struct {
974 const U = union(enum) {985 const U = union(enum) {
...@@ -1104,6 +1115,8 @@ test "union enum type gets a separate scope" {...@@ -1104,6 +1115,8 @@ test "union enum type gets a separate scope" {
11041115
1105test "global variable struct contains union initialized to non-most-aligned field" {1116test "global variable struct contains union initialized to non-most-aligned field" {
1106 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1117 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
1108 const T = struct {1121 const T = struct {
1109 const U = union(enum) {1122 const U = union(enum) {
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1
...@@ -3,3 +3,4 @@...@@ -3,3 +3,4 @@
3// target=aarch64-macos3// target=aarch64-macos
4//4//
5// :107:9: error: struct 'tmp.tmp' has no member named 'main'5// :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)); }...@@ -6,3 +6,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(x)); }
6// target=native6// target=native
7//7//
8// :1:29: error: struct 'builtin.builtin' has no member named 'bogus'8// :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)); }...@@ -8,4 +8,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
8// backend=stage28// backend=stage2
9// target=native9// target=native
10//10//
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 {...@@ -11,5 +11,5 @@ export fn entry() void {
11// backend=stage211// backend=stage2
12// target=native12// target=native
13//13//
14// :6:21: error: enum 'tmp.Foo' has no field named 'c'14// :6:21: error: no field named 'c' in enum 'tmp.Foo'
15// :1:13: note: enum declared here15// :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 {...@@ -34,5 +34,5 @@ export fn d() void {
34// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions34// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
35// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs35// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
36// :18:22: note: opaque declared here36// :18:22: note: opaque declared here
37// :24:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs37// :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs
38// :23:22: note: opaque declared here38// :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 {...@@ -13,9 +13,50 @@ pub export fn entry1() void {
13 var s: S = .{};13 var s: S = .{};
14 s.a = T{ .a = 2, .b = 2 };14 s.a = T{ .a = 2, .b = 2 };
15}15}
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
16// error53// error
17// target=native54// target=native
18// backend=stage255// backend=stage2
19//56//
20// :6:19: error: value stored in comptime field does not match the default value of the field57// :6:19: error: value stored in comptime field does not match the default value of the field
21// :14:19: error: value stored in comptime field does not match the default value of the field58// :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 {...@@ -18,4 +18,5 @@ export fn f() void {
18// backend=stage218// backend=stage2
19// target=native19// target=native
20//20//
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 {...@@ -27,4 +27,5 @@ export fn foo() void {
27// backend=llvm27// backend=llvm
28// target=native28// target=native
29//29//
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 {...@@ -16,5 +16,5 @@ export fn entry() usize {
16// error16// error
17// target=native17// target=native
18//18//
19// :10:5: error: enum 'tmp.E' has no field named 'd'19// :10:5: error: no field named 'd' in enum 'tmp.E'
20// :1:11: note: enum declared here20// :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 {...@@ -13,5 +13,4 @@ export fn entry() void {
13// backend=stage213// backend=stage2
14// target=native14// target=native
15//15//
16// :9:14: error: expected type 'type', found 'tmp.U'16// :9:8: error: use of undefined value here causes undefined behavior
17// :1:11: note: union declared here
test/cases/safety/@alignCast misaligned.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -18,5 +20,5 @@ fn foo(bytes: []u8) u32 {...@@ -18,5 +20,5 @@ fn foo(bytes: []u8) u32 {
18 return int_slice[0];20 return int_slice[0];
19}21}
20// run22// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8const Set1 = error{A, B};10const Set1 = error{A, B};
9const Set2 = error{A, C};11const Set2 = error{A, C};
...@@ -15,5 +17,5 @@ fn foo(set1: Set1) Set2 {...@@ -15,5 +17,5 @@ fn foo(set1: Set1) Set2 {
15 return @errSetCast(Set2, set1);17 return @errSetCast(Set2, set1);
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(-129.1));11 baz(bar(-129.1));
...@@ -14,5 +16,5 @@ fn bar(a: f32) i8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) i8 {
14}16}
15fn baz(_: i8) void { }17fn baz(_: i8) void { }
16// run18// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(-1.1));11 baz(bar(-1.1));
...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
14}16}
15fn baz(_: u8) void { }17fn baz(_: u8) void { }
16// run18// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(256.2));11 baz(bar(256.2));
...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
14}16}
15fn baz(_: u8) void { }17fn baz(_: u8) void { }
16// run18// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -16,5 +18,5 @@ fn bar(one: u1, not_zero: i32) void {...@@ -16,5 +18,5 @@ fn bar(one: u1, not_zero: i32) void {
16 _ = x;18 _ = x;
17}19}
18// run20// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var zero: usize = 0;11 var zero: usize = 0;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// run
15// backend=stage117// backend=llvm
16// target=native18// target=native
test/cases/safety/@intToPtr address zero to non-optional pointer.zig +5-3
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var zero: usize = 0;11 var zero: usize = 0;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// run
15// backend=stage117// backend=llvm
16// target=native18// target=native
test/cases/safety/bad union field access.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9const Foo = union {11const Foo = union {
...@@ -21,5 +23,5 @@ fn bar(f: *Foo) void {...@@ -21,5 +23,5 @@ fn bar(f: *Foo) void {
21 f.float = 12.34;23 f.float = 12.34;
22}24}
23// run25// 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 {...@@ -12,5 +12,5 @@ pub fn main() !void {
12 return error.TestFailed;12 return error.TestFailed;
13}13}
14// run14// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 bar(9999) catch {};11 bar(9999) catch {};
...@@ -13,5 +15,5 @@ fn bar(x: u16) anyerror {...@@ -13,5 +15,5 @@ fn bar(x: u16) anyerror {
13 return @intToError(x);15 return @intToError(x);
14}16}
15// run17// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
17 return @divExact(a, b);19 return @divExact(a, b);
18}20}
19// run21// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 {...@@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 {
15 return @divExact(a, b);17 return @divExact(a, b);
16}18}
17// run19// 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 {...@@ -14,5 +14,5 @@ pub fn main() !void {
14 return error.TestFailed;14 return error.TestFailed;
15}15}
16// run16// run
17// backend=stage117// backend=llvm
18// target=native18// target=native
test/cases/safety/integer addition overflow.zig +1-1
...@@ -19,5 +19,5 @@ fn add(a: u16, b: u16) u16 {...@@ -19,5 +19,5 @@ fn add(a: u16, b: u16) u16 {
19}19}
2020
21// run21// run
22// backend=stage122// backend=llvm
23// target=native23// target=native
test/cases/safety/integer division by zero - vectors.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};11 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) {...@@ -16,5 +18,5 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
16 return @divTrunc(a, b);18 return @divTrunc(a, b);
17}19}
18// run20// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 const x = div0(999, 0);11 const x = div0(999, 0);
...@@ -14,5 +16,5 @@ fn div0(a: i32, b: i32) i32 {...@@ -14,5 +16,5 @@ fn div0(a: i32, b: i32) i32 {
14 return @divTrunc(a, b);16 return @divTrunc(a, b);
15}17}
16// run18// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn mul(a: u16, b: u16) u16 {...@@ -15,5 +17,5 @@ fn mul(a: u16, b: u16) u16 {
15 return a * b;17 return a * b;
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn neg(a: i16) i16 {...@@ -15,5 +17,5 @@ fn neg(a: i16) i16 {
15 return -a;17 return -a;
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn sub(a: u16, b: u16) u16 {...@@ -15,5 +17,5 @@ fn sub(a: u16, b: u16) u16 {
15 return a - b;17 return a - b;
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var ptr: [*c]i32 = null;11 var ptr: [*c]i32 = null;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// run
15// backend=stage117// backend=llvm
16// target=native18// target=native
test/cases/safety/optional unwrap operator on null pointer.zig +5-3
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var ptr: ?*i32 = null;11 var ptr: ?*i32 = null;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// run
15// backend=stage117// backend=llvm
16// target=native18// target=native
test/cases/safety/out of bounds slice access.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 const a = [_]i32{1, 2, 3, 4};11 const a = [_]i32{1, 2, 3, 4};
...@@ -15,5 +17,5 @@ fn bar(a: []const i32) i32 {...@@ -15,5 +17,5 @@ fn bar(a: []const i32) i32 {
15}17}
16fn baz(_: i32) void { }18fn baz(_: i32) void { }
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var value: c_short = -1;11 var value: c_short = -1;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// 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 @@...@@ -1,11 +1,12 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8
9pub fn main() !void {10pub fn main() !void {
10 const x = unsigned_cast(-10);11 const x = unsigned_cast(-10);
11 if (x == 0) return error.Whatever;12 if (x == 0) return error.Whatever;
...@@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 {...@@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 {
15 return @intCast(u32, x);16 return @intCast(u32, x);
16}17}
17// run18// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shl(a: i16, b: u4) i16 {...@@ -15,5 +17,5 @@ fn shl(a: i16, b: u4) i16 {
15 return @shlExact(a, b);17 return @shlExact(a, b);
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 {...@@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 {
15 return @shrExact(a, b);17 return @shrExact(a, b);
16}18}
17// run19// 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 {...@@ -16,5 +16,5 @@ pub fn main() !void {
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// target=native
test/cases/safety/truncating vector cast.zig +1-1
...@@ -16,5 +16,5 @@ pub fn main() !void {...@@ -16,5 +16,5 @@ pub fn main() !void {
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var value: u8 = 245;11 var value: u8 = 245;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shl(a: u16, b: u4) u16 {...@@ -15,5 +17,5 @@ fn shl(a: u16, b: u4) u16 {
15 return @shlExact(a, b);17 return @shlExact(a, b);
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 {...@@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 {
15 return @shrExact(a, b);17 return @shrExact(a, b);
16}18}
17// run19// 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 {...@@ -16,5 +16,5 @@ pub fn main() !void {
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// target=native
test/cases/safety/unwrap error.zig +2-2
...@@ -15,5 +15,5 @@ fn bar() !void {...@@ -15,5 +15,5 @@ fn bar() !void {
15 return error.Whatever;15 return error.Whatever;
16}16}
17// run17// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shorten_cast(x: u8) u0 {...@@ -15,5 +17,5 @@ fn shorten_cast(x: u8) u0 {
15 return @intCast(u0, x);17 return @intCast(u0, x);
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shorten_cast(x: i32) i8 {...@@ -15,5 +17,5 @@ fn shorten_cast(x: i32) i8 {
15 return @intCast(i8, x);17 return @intCast(i8, x);
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };11 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) {...@@ -16,5 +18,5 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
16 return a + b;18 return a + b;
17}19}
18// run20// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };11 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) {...@@ -16,5 +18,5 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
16 return a * b;18 return a * b;
17}19}
18// run20// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };11 var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
...@@ -15,5 +17,5 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {...@@ -15,5 +17,5 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
15 return -a;17 return -a;
16}18}
17// run19// 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 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = 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);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };11 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) {...@@ -16,5 +18,5 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
16 return a - b;18 return a - b;
17}19}
18// run20// 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 @@...@@ -3,3 +3,4 @@
3// target=x86_64-linux3// target=x86_64-linux
4//4//
5// :107:9: error: struct 'tmp.tmp' has no member named 'main'5// :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 @@...@@ -3,3 +3,4 @@
3// target=x86_64-macos3// target=x86_64-macos
4//4//
5// :107:9: error: struct 'tmp.tmp' has no member named 'main'5// :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 {...@@ -839,7 +839,7 @@ pub fn addCases(ctx: *TestContext) !void {
839 \\ _ = x;839 \\ _ = x;
840 \\}840 \\}
841 , &.{841 , &.{
842 ":3:17: error: enum 'tmp.E' has no field named 'd'",842 ":3:17: error: no field named 'd' in enum 'tmp.E'",
843 ":1:11: note: enum declared here",843 ":1:11: note: enum declared here",
844 });844 });
845 }845 }