| author | |
| committer | |
| log | a2ab9e36faded9755ecc1fe809c49140120c3c61 |
| tree | 25a44861df794d1d633544d1083e67fb52376df4 |
| parent | 9964324856936ba7ac99985463568079dda6e40f |
| parent | baf516218e227a55b59c9ae9e6c52b0f9ebd0980 |
| signature |
Stage2 runtime safety progress87 files changed, 1412 insertions(+), 468 deletions(-)
lib/compiler_rt/int_to_float_test.zig+1| ... | ... | @@ -813,6 +813,7 @@ test "conversion to f32" { |
| 813 | 813 | test "conversion to f80" { |
| 814 | 814 | if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64) |
| 815 | 815 | return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408 |
| 816 | if (std.debug.runtime_safety) return error.SkipZigTest; | |
| 816 | 817 | |
| 817 | 818 | const intToFloat = @import("./int_to_float.zig").intToFloat; |
| 818 | 819 |
src/Air.zig+81-16| ... | ... | @@ -38,11 +38,15 @@ pub const Inst = struct { |
| 38 | 38 | /// is the same as both operands. |
| 39 | 39 | /// Uses the `bin_op` field. |
| 40 | 40 | add, |
| 41 | /// Same as `add` with optimized float mode. | |
| 42 | add_optimized, | |
| 41 | 43 | /// Integer addition. Wrapping is defined to be twos complement wrapping. |
| 42 | 44 | /// Both operands are guaranteed to be the same type, and the result type |
| 43 | 45 | /// is the same as both operands. |
| 44 | 46 | /// Uses the `bin_op` field. |
| 45 | 47 | addwrap, |
| 48 | /// Same as `addwrap` with optimized float mode. | |
| 49 | addwrap_optimized, | |
| 46 | 50 | /// Saturating integer addition. |
| 47 | 51 | /// Both operands are guaranteed to be the same type, and the result type |
| 48 | 52 | /// is the same as both operands. |
| ... | ... | @@ -53,11 +57,15 @@ pub const Inst = struct { |
| 53 | 57 | /// is the same as both operands. |
| 54 | 58 | /// Uses the `bin_op` field. |
| 55 | 59 | sub, |
| 60 | /// Same as `sub` with optimized float mode. | |
| 61 | sub_optimized, | |
| 56 | 62 | /// Integer subtraction. Wrapping is defined to be twos complement wrapping. |
| 57 | 63 | /// Both operands are guaranteed to be the same type, and the result type |
| 58 | 64 | /// is the same as both operands. |
| 59 | 65 | /// Uses the `bin_op` field. |
| 60 | 66 | subwrap, |
| 67 | /// Same as `sub` with optimized float mode. | |
| 68 | subwrap_optimized, | |
| 61 | 69 | /// Saturating integer subtraction. |
| 62 | 70 | /// Both operands are guaranteed to be the same type, and the result type |
| 63 | 71 | /// is the same as both operands. |
| ... | ... | @@ -68,11 +76,15 @@ pub const Inst = struct { |
| 68 | 76 | /// is the same as both operands. |
| 69 | 77 | /// Uses the `bin_op` field. |
| 70 | 78 | mul, |
| 79 | /// Same as `mul` with optimized float mode. | |
| 80 | mul_optimized, | |
| 71 | 81 | /// Integer multiplication. Wrapping is defined to be twos complement wrapping. |
| 72 | 82 | /// Both operands are guaranteed to be the same type, and the result type |
| 73 | 83 | /// is the same as both operands. |
| 74 | 84 | /// Uses the `bin_op` field. |
| 75 | 85 | mulwrap, |
| 86 | /// Same as `mulwrap` with optimized float mode. | |
| 87 | mulwrap_optimized, | |
| 76 | 88 | /// Saturating integer multiplication. |
| 77 | 89 | /// Both operands are guaranteed to be the same type, and the result type |
| 78 | 90 | /// is the same as both operands. |
| ... | ... | @@ -83,32 +95,44 @@ pub const Inst = struct { |
| 83 | 95 | /// is the same as both operands. |
| 84 | 96 | /// Uses the `bin_op` field. |
| 85 | 97 | div_float, |
| 98 | /// Same as `div_float` with optimized float mode. | |
| 99 | div_float_optimized, | |
| 86 | 100 | /// Truncating integer or float division. For integers, wrapping is undefined behavior. |
| 87 | 101 | /// Both operands are guaranteed to be the same type, and the result type |
| 88 | 102 | /// is the same as both operands. |
| 89 | 103 | /// Uses the `bin_op` field. |
| 90 | 104 | div_trunc, |
| 105 | /// Same as `div_trunc` with optimized float mode. | |
| 106 | div_trunc_optimized, | |
| 91 | 107 | /// Flooring integer or float division. For integers, wrapping is undefined behavior. |
| 92 | 108 | /// Both operands are guaranteed to be the same type, and the result type |
| 93 | 109 | /// is the same as both operands. |
| 94 | 110 | /// Uses the `bin_op` field. |
| 95 | 111 | div_floor, |
| 112 | /// Same as `div_floor` with optimized float mode. | |
| 113 | div_floor_optimized, | |
| 96 | 114 | /// Integer or float division. Guaranteed no remainder. |
| 97 | 115 | /// For integers, wrapping is undefined behavior. |
| 98 | 116 | /// Both operands are guaranteed to be the same type, and the result type |
| 99 | 117 | /// is the same as both operands. |
| 100 | 118 | /// Uses the `bin_op` field. |
| 101 | 119 | div_exact, |
| 120 | /// Same as `div_exact` with optimized float mode. | |
| 121 | div_exact_optimized, | |
| 102 | 122 | /// Integer or float remainder division. |
| 103 | 123 | /// Both operands are guaranteed to be the same type, and the result type |
| 104 | 124 | /// is the same as both operands. |
| 105 | 125 | /// Uses the `bin_op` field. |
| 106 | 126 | rem, |
| 127 | /// Same as `rem` with optimized float mode. | |
| 128 | rem_optimized, | |
| 107 | 129 | /// Integer or float modulus division. |
| 108 | 130 | /// Both operands are guaranteed to be the same type, and the result type |
| 109 | 131 | /// is the same as both operands. |
| 110 | 132 | /// Uses the `bin_op` field. |
| 111 | 133 | mod, |
| 134 | /// Same as `mod` with optimized float mode. | |
| 135 | mod_optimized, | |
| 112 | 136 | /// Add an offset to a pointer, returning a new pointer. |
| 113 | 137 | /// The offset is in element type units, not bytes. |
| 114 | 138 | /// Wrapping is undefined behavior. |
| ... | ... | @@ -293,29 +317,45 @@ pub const Inst = struct { |
| 293 | 317 | /// LHS of zero. |
| 294 | 318 | /// Uses the `un_op` field. |
| 295 | 319 | neg, |
| 320 | /// Same as `neg` with optimized float mode. | |
| 321 | neg_optimized, | |
| 296 | 322 | |
| 297 | 323 | /// `<`. Result type is always bool. |
| 298 | 324 | /// Uses the `bin_op` field. |
| 299 | 325 | cmp_lt, |
| 326 | /// Same as `cmp_lt` with optimized float mode. | |
| 327 | cmp_lt_optimized, | |
| 300 | 328 | /// `<=`. Result type is always bool. |
| 301 | 329 | /// Uses the `bin_op` field. |
| 302 | 330 | cmp_lte, |
| 331 | /// Same as `cmp_lte` with optimized float mode. | |
| 332 | cmp_lte_optimized, | |
| 303 | 333 | /// `==`. Result type is always bool. |
| 304 | 334 | /// Uses the `bin_op` field. |
| 305 | 335 | cmp_eq, |
| 336 | /// Same as `cmp_eq` with optimized float mode. | |
| 337 | cmp_eq_optimized, | |
| 306 | 338 | /// `>=`. Result type is always bool. |
| 307 | 339 | /// Uses the `bin_op` field. |
| 308 | 340 | cmp_gte, |
| 341 | /// Same as `cmp_gte` with optimized float mode. | |
| 342 | cmp_gte_optimized, | |
| 309 | 343 | /// `>`. Result type is always bool. |
| 310 | 344 | /// Uses the `bin_op` field. |
| 311 | 345 | cmp_gt, |
| 346 | /// Same as `cmp_gt` with optimized float mode. | |
| 347 | cmp_gt_optimized, | |
| 312 | 348 | /// `!=`. Result type is always bool. |
| 313 | 349 | /// Uses the `bin_op` field. |
| 314 | 350 | cmp_neq, |
| 351 | /// Same as `cmp_neq` with optimized float mode. | |
| 352 | cmp_neq_optimized, | |
| 315 | 353 | /// Conditional between two vectors. |
| 316 | 354 | /// Result type is always a vector of bools. |
| 317 | 355 | /// Uses the `ty_pl` field, payload is `VectorCmp`. |
| 318 | 356 | cmp_vector, |
| 357 | /// Same as `cmp_vector` with optimized float mode. | |
| 358 | cmp_vector_optimized, | |
| 319 | 359 | |
| 320 | 360 | /// Conditional branch. |
| 321 | 361 | /// Result type is always noreturn; no instructions in a block follow this one. |
| ... | ... | @@ -553,6 +593,8 @@ pub const Inst = struct { |
| 553 | 593 | /// Given a float operand, return the integer with the closest mathematical meaning. |
| 554 | 594 | /// Uses the `ty_op` field. |
| 555 | 595 | float_to_int, |
| 596 | /// Same as `float_to_int` with optimized float mode. | |
| 597 | float_to_int_optimized, | |
| 556 | 598 | /// Given an integer operand, return the float with the closest mathematical meaning. |
| 557 | 599 | /// Uses the `ty_op` field. |
| 558 | 600 | int_to_float, |
| ... | ... | @@ -564,6 +606,8 @@ pub const Inst = struct { |
| 564 | 606 | /// * min, max, add, mul => integer or float |
| 565 | 607 | /// Uses the `reduce` field. |
| 566 | 608 | reduce, |
| 609 | /// Same as `reduce` with optimized float mode. | |
| 610 | reduce_optimized, | |
| 567 | 611 | /// Given an integer, bool, float, or pointer operand, return a vector with all elements |
| 568 | 612 | /// equal to the scalar value. |
| 569 | 613 | /// Uses the `ty_op` field. |
| ... | ... | @@ -676,25 +720,25 @@ pub const Inst = struct { |
| 676 | 720 | /// Sets the operand as the current error return trace, |
| 677 | 721 | set_err_return_trace, |
| 678 | 722 | |
| 679 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { | |
| 680 | return switch (op) { | |
| 681 | .lt => .cmp_lt, | |
| 682 | .lte => .cmp_lte, | |
| 683 | .eq => .cmp_eq, | |
| 684 | .gte => .cmp_gte, | |
| 685 | .gt => .cmp_gt, | |
| 686 | .neq => .cmp_neq, | |
| 687 | }; | |
| 723 | pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { | |
| 724 | switch (op) { | |
| 725 | .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt, | |
| 726 | .lte => return if (optimized) .cmp_lte_optimized else .cmp_lte, | |
| 727 | .eq => return if (optimized) .cmp_eq_optimized else .cmp_eq, | |
| 728 | .gte => return if (optimized) .cmp_gte_optimized else .cmp_gte, | |
| 729 | .gt => return if (optimized) .cmp_gt_optimized else .cmp_gt, | |
| 730 | .neq => return if (optimized) .cmp_neq_optimized else .cmp_neq, | |
| 731 | } | |
| 688 | 732 | } |
| 689 | 733 | |
| 690 | 734 | pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator { |
| 691 | 735 | return switch (tag) { |
| 692 | .cmp_lt => .lt, | |
| 693 | .cmp_lte => .lte, | |
| 694 | .cmp_eq => .eq, | |
| 695 | .cmp_gte => .gte, | |
| 696 | .cmp_gt => .gt, | |
| 697 | .cmp_neq => .neq, | |
| 736 | .cmp_lt, .cmp_lt_optimized => .lt, | |
| 737 | .cmp_lte, .cmp_lte_optimized => .lte, | |
| 738 | .cmp_eq, .cmp_eq_optimized => .eq, | |
| 739 | .cmp_gte, .cmp_gte_optimized => .gte, | |
| 740 | .cmp_gt, .cmp_gt_optimized => .gt, | |
| 741 | .cmp_neq, .cmp_neq_optimized => .neq, | |
| 698 | 742 | else => null, |
| 699 | 743 | }; |
| 700 | 744 | } |
| ... | ... | @@ -959,6 +1003,18 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 959 | 1003 | .max, |
| 960 | 1004 | .bool_and, |
| 961 | 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 | 1018 | => return air.typeOf(datas[inst].bin_op.lhs), |
| 963 | 1019 | |
| 964 | 1020 | .sqrt, |
| ... | ... | @@ -976,6 +1032,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 976 | 1032 | .round, |
| 977 | 1033 | .trunc_float, |
| 978 | 1034 | .neg, |
| 1035 | .neg_optimized, | |
| 979 | 1036 | => return air.typeOf(datas[inst].un_op), |
| 980 | 1037 | |
| 981 | 1038 | .cmp_lt, |
| ... | ... | @@ -984,6 +1041,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 984 | 1041 | .cmp_gte, |
| 985 | 1042 | .cmp_gt, |
| 986 | 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 | 1050 | .cmp_lt_errors_len, |
| 988 | 1051 | .is_null, |
| 989 | 1052 | .is_non_null, |
| ... | ... | @@ -1018,6 +1081,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1018 | 1081 | .union_init, |
| 1019 | 1082 | .field_parent_ptr, |
| 1020 | 1083 | .cmp_vector, |
| 1084 | .cmp_vector_optimized, | |
| 1021 | 1085 | .add_with_overflow, |
| 1022 | 1086 | .sub_with_overflow, |
| 1023 | 1087 | .mul_with_overflow, |
| ... | ... | @@ -1054,6 +1118,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1054 | 1118 | .struct_field_ptr_index_3, |
| 1055 | 1119 | .array_to_slice, |
| 1056 | 1120 | .float_to_int, |
| 1121 | .float_to_int_optimized, | |
| 1057 | 1122 | .int_to_float, |
| 1058 | 1123 | .splat, |
| 1059 | 1124 | .get_union_tag, |
| ... | ... | @@ -1129,7 +1194,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1129 | 1194 | return ptr_ty.elemType(); |
| 1130 | 1195 | }, |
| 1131 | 1196 | |
| 1132 | .reduce => return air.typeOf(datas[inst].reduce.operand).childType(), | |
| 1197 | .reduce, .reduce_optimized => return air.typeOf(datas[inst].reduce.operand).childType(), | |
| 1133 | 1198 | |
| 1134 | 1199 | .mul_add => return air.typeOf(datas[inst].pl_op.operand), |
| 1135 | 1200 | .select => { |
src/AstGen.zig+12-7| ... | ... | @@ -1589,13 +1589,12 @@ fn structInitExpr( |
| 1589 | 1589 | |
| 1590 | 1590 | switch (rl) { |
| 1591 | 1591 | .discard => { |
| 1592 | // TODO if a type expr is given the fields should be validated for that type | |
| 1593 | 1592 | if (struct_init.ast.type_expr != 0) { |
| 1594 | 1593 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1595 | 1594 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| 1596 | } | |
| 1597 | for (struct_init.ast.fields) |field_init| { | |
| 1598 | _ = try expr(gz, scope, .discard, field_init); | |
| 1595 | _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); | |
| 1596 | } else { | |
| 1597 | _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); | |
| 1599 | 1598 | } |
| 1600 | 1599 | return Zir.Inst.Ref.void_value; |
| 1601 | 1600 | }, |
| ... | ... | @@ -1729,7 +1728,7 @@ fn structInitExprRlPtrInner( |
| 1729 | 1728 | for (struct_init.ast.fields) |field_init| { |
| 1730 | 1729 | const name_token = tree.firstToken(field_init) - 2; |
| 1731 | 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 | 1732 | .lhs = result_ptr, |
| 1734 | 1733 | .field_name_start = str_index, |
| 1735 | 1734 | }); |
| ... | ... | @@ -2287,6 +2286,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2287 | 2286 | .elem_ptr_imm, |
| 2288 | 2287 | .elem_val_node, |
| 2289 | 2288 | .field_ptr, |
| 2289 | .field_ptr_init, | |
| 2290 | 2290 | .field_val, |
| 2291 | 2291 | .field_call_bind, |
| 2292 | 2292 | .field_ptr_named, |
| ... | ... | @@ -4213,6 +4213,12 @@ fn structDeclInner( |
| 4213 | 4213 | const have_value = member.ast.value_expr != 0; |
| 4214 | 4214 | const is_comptime = member.comptime_token != null; |
| 4215 | 4215 | |
| 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 | 4222 | if (!is_comptime) { |
| 4217 | 4223 | known_non_opv = known_non_opv or |
| 4218 | 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 | 6510 | }, |
| 6505 | 6511 | .always => { |
| 6506 | 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; | |
| 6508 | const err_code = try gz.addUnNode(.err_union_code, result, node); | |
| 6513 | const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; | |
| 6509 | 6514 | try genDefers(gz, defer_outer, scope, .{ .both = err_code }); |
| 6510 | 6515 | try gz.addRet(rl, operand, node); |
| 6511 | 6516 | return Zir.Inst.Ref.unreachable_value; |
src/Liveness.zig+44-4| ... | ... | @@ -173,6 +173,25 @@ pub fn categorizeOperand( |
| 173 | 173 | .shr_exact, |
| 174 | 174 | .min, |
| 175 | 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 | 196 | const o = air_datas[inst].bin_op; |
| 178 | 197 | if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| ... | ... | @@ -239,6 +258,7 @@ pub fn categorizeOperand( |
| 239 | 258 | .struct_field_ptr_index_3, |
| 240 | 259 | .array_to_slice, |
| 241 | 260 | .float_to_int, |
| 261 | .float_to_int_optimized, | |
| 242 | 262 | .int_to_float, |
| 243 | 263 | .get_union_tag, |
| 244 | 264 | .clz, |
| ... | ... | @@ -381,12 +401,12 @@ pub fn categorizeOperand( |
| 381 | 401 | if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); |
| 382 | 402 | return .none; |
| 383 | 403 | }, |
| 384 | .reduce => { | |
| 404 | .reduce, .reduce_optimized => { | |
| 385 | 405 | const reduce = air_datas[inst].reduce; |
| 386 | 406 | if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| 387 | 407 | return .none; |
| 388 | 408 | }, |
| 389 | .cmp_vector => { | |
| 409 | .cmp_vector, .cmp_vector_optimized => { | |
| 390 | 410 | const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data; |
| 391 | 411 | if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| 392 | 412 | if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); |
| ... | ... | @@ -701,29 +721,47 @@ fn analyzeInst( |
| 701 | 721 | |
| 702 | 722 | switch (inst_tags[inst]) { |
| 703 | 723 | .add, |
| 724 | .add_optimized, | |
| 704 | 725 | .addwrap, |
| 726 | .addwrap_optimized, | |
| 705 | 727 | .add_sat, |
| 706 | 728 | .sub, |
| 729 | .sub_optimized, | |
| 707 | 730 | .subwrap, |
| 731 | .subwrap_optimized, | |
| 708 | 732 | .sub_sat, |
| 709 | 733 | .mul, |
| 734 | .mul_optimized, | |
| 710 | 735 | .mulwrap, |
| 736 | .mulwrap_optimized, | |
| 711 | 737 | .mul_sat, |
| 712 | 738 | .div_float, |
| 739 | .div_float_optimized, | |
| 713 | 740 | .div_trunc, |
| 741 | .div_trunc_optimized, | |
| 714 | 742 | .div_floor, |
| 743 | .div_floor_optimized, | |
| 715 | 744 | .div_exact, |
| 745 | .div_exact_optimized, | |
| 716 | 746 | .rem, |
| 747 | .rem_optimized, | |
| 717 | 748 | .mod, |
| 749 | .mod_optimized, | |
| 718 | 750 | .bit_and, |
| 719 | 751 | .bit_or, |
| 720 | 752 | .xor, |
| 721 | 753 | .cmp_lt, |
| 754 | .cmp_lt_optimized, | |
| 722 | 755 | .cmp_lte, |
| 756 | .cmp_lte_optimized, | |
| 723 | 757 | .cmp_eq, |
| 758 | .cmp_eq_optimized, | |
| 724 | 759 | .cmp_gte, |
| 760 | .cmp_gte_optimized, | |
| 725 | 761 | .cmp_gt, |
| 762 | .cmp_gt_optimized, | |
| 726 | 763 | .cmp_neq, |
| 764 | .cmp_neq_optimized, | |
| 727 | 765 | .bool_and, |
| 728 | 766 | .bool_or, |
| 729 | 767 | .store, |
| ... | ... | @@ -794,6 +832,7 @@ fn analyzeInst( |
| 794 | 832 | .struct_field_ptr_index_3, |
| 795 | 833 | .array_to_slice, |
| 796 | 834 | .float_to_int, |
| 835 | .float_to_int_optimized, | |
| 797 | 836 | .int_to_float, |
| 798 | 837 | .get_union_tag, |
| 799 | 838 | .clz, |
| ... | ... | @@ -836,6 +875,7 @@ fn analyzeInst( |
| 836 | 875 | .round, |
| 837 | 876 | .trunc_float, |
| 838 | 877 | .neg, |
| 878 | .neg_optimized, | |
| 839 | 879 | .cmp_lt_errors_len, |
| 840 | 880 | .set_err_return_trace, |
| 841 | 881 | => { |
| ... | ... | @@ -903,11 +943,11 @@ fn analyzeInst( |
| 903 | 943 | const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data; |
| 904 | 944 | return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none }); |
| 905 | 945 | }, |
| 906 | .reduce => { | |
| 946 | .reduce, .reduce_optimized => { | |
| 907 | 947 | const reduce = inst_datas[inst].reduce; |
| 908 | 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 | 951 | const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data; |
| 912 | 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 | 787 | const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; |
| 788 | 788 | return &opaque_obj.namespace; |
| 789 | 789 | }, |
| 790 | .@"union", .union_tagged => { | |
| 790 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 791 | 791 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 792 | 792 | return &union_obj.namespace; |
| 793 | 793 | }, |
| ... | ... | @@ -2704,6 +2704,18 @@ pub const SrcLoc = struct { |
| 2704 | 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 | } |
| 2709 | 2721 | |
| ... | ... | @@ -3021,6 +3033,9 @@ pub const LazySrcLoc = union(enum) { |
| 3021 | 3033 | /// The source location points to the tag type of an union or an enum. |
| 3022 | 3034 | /// The Decl is determined contextually. |
| 3023 | 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, | |
| 3024 | 3039 | |
| 3025 | 3040 | pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; |
| 3026 | 3041 | |
| ... | ... | @@ -3098,6 +3113,7 @@ pub const LazySrcLoc = union(enum) { |
| 3098 | 3113 | .node_offset_ptr_bitoffset, |
| 3099 | 3114 | .node_offset_ptr_hostsize, |
| 3100 | 3115 | .node_offset_container_tag, |
| 3116 | .node_offset_field_default, | |
| 3101 | 3117 | => .{ |
| 3102 | 3118 | .file_scope = decl.getFileScope(), |
| 3103 | 3119 | .parent_decl_node = decl.src_node, |
| ... | ... | @@ -5936,6 +5952,58 @@ pub fn argSrc( |
| 5936 | 5952 | return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(full.ast.params[arg_i])); |
| 5937 | 5953 | } |
| 5938 | 5954 | |
| 5955 | pub 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 | 6007 | /// Called from `performAllTheWork`, after all AstGen workers have finished, |
| 5940 | 6008 | /// and before the main semantic analysis loop begins. |
| 5941 | 6009 | pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
src/Sema.zig+470-179| ... | ... | @@ -144,6 +144,9 @@ pub const Block = struct { |
| 144 | 144 | /// when null, it is determined by build mode, changed by @setRuntimeSafety |
| 145 | 145 | want_safety: ?bool = null, |
| 146 | 146 | |
| 147 | /// What mode to generate float operations in, set by @setFloatMode | |
| 148 | float_mode: std.builtin.FloatMode = .Strict, | |
| 149 | ||
| 147 | 150 | c_import_buf: ?*std.ArrayList(u8) = null, |
| 148 | 151 | |
| 149 | 152 | /// type of `err` in `else => |err|` |
| ... | ... | @@ -206,6 +209,7 @@ pub const Block = struct { |
| 206 | 209 | .runtime_loop = parent.runtime_loop, |
| 207 | 210 | .runtime_index = parent.runtime_index, |
| 208 | 211 | .want_safety = parent.want_safety, |
| 212 | .float_mode = parent.float_mode, | |
| 209 | 213 | .c_import_buf = parent.c_import_buf, |
| 210 | 214 | .switch_else_err_ty = parent.switch_else_err_ty, |
| 211 | 215 | }; |
| ... | ... | @@ -414,7 +418,7 @@ pub const Block = struct { |
| 414 | 418 | |
| 415 | 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 | 420 | return block.addInst(.{ |
| 417 | .tag = .cmp_vector, | |
| 421 | .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, | |
| 418 | 422 | .data = .{ .ty_pl = .{ |
| 419 | 423 | .ty = vector_ty, |
| 420 | 424 | .payload = try block.sema.addExtra(Air.VectorCmp{ |
| ... | ... | @@ -714,10 +718,10 @@ fn analyzeBodyInner( |
| 714 | 718 | .closure_get => try sema.zirClosureGet(block, inst), |
| 715 | 719 | .cmp_lt => try sema.zirCmp(block, inst, .lt), |
| 716 | 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 | 722 | .cmp_gte => try sema.zirCmp(block, inst, .gte), |
| 719 | 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 | 725 | .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), |
| 722 | 726 | .decl_ref => try sema.zirDeclRef(block, inst), |
| 723 | 727 | .decl_val => try sema.zirDeclVal(block, inst), |
| ... | ... | @@ -739,7 +743,8 @@ fn analyzeBodyInner( |
| 739 | 743 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), |
| 740 | 744 | .error_union_type => try sema.zirErrorUnionType(block, inst), |
| 741 | 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 | 748 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 744 | 749 | .field_val => try sema.zirFieldVal(block, inst), |
| 745 | 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 | 1552 | const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty)); |
| 1548 | 1553 | |
| 1549 | 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 | 1556 | try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); |
| 1552 | 1557 | |
| 1553 | 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 | 1560 | const zero = try sema.addConstant(Type.usize, Value.zero); |
| 1556 | 1561 | try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store); |
| 1557 | 1562 | |
| ... | ... | @@ -1784,6 +1789,24 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: |
| 1784 | 1789 | }); |
| 1785 | 1790 | } |
| 1786 | 1791 | |
| 1792 | fn 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 | 1810 | /// We don't return a pointer to the new error note because the pointer |
| 1788 | 1811 | /// becomes invalid when you add another one. |
| 1789 | 1812 | fn errNote( |
| ... | ... | @@ -2614,7 +2637,14 @@ fn zirUnionDecl( |
| 2614 | 2637 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 2615 | 2638 | |
| 2616 | 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 | 2648 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); |
| 2619 | 2649 | union_payload.* = .{ |
| 2620 | 2650 | .base = .{ .tag = type_tag }, |
| ... | ... | @@ -3651,7 +3681,10 @@ fn validateStructInit( |
| 3651 | 3681 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 3652 | 3682 | struct_ptr_zir_ref = field_ptr_extra.lhs; |
| 3653 | 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 | 3688 | if (found_fields[field_index] != 0) { |
| 3656 | 3689 | const other_field_ptr = found_fields[field_index]; |
| 3657 | 3690 | const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node; |
| ... | ... | @@ -3693,7 +3726,7 @@ fn validateStructInit( |
| 3693 | 3726 | } |
| 3694 | 3727 | |
| 3695 | 3728 | 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 | 3730 | const field_ty = sema.typeOf(default_field_ptr).childType(); |
| 3698 | 3731 | const init = try sema.addConstant(field_ty, default_val); |
| 3699 | 3732 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| ... | ... | @@ -3851,7 +3884,7 @@ fn validateStructInit( |
| 3851 | 3884 | if (field_ptr != 0) continue; |
| 3852 | 3885 | |
| 3853 | 3886 | 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 | 3888 | const field_ty = sema.typeOf(default_field_ptr).childType(); |
| 3856 | 3889 | const init = try sema.addConstant(field_ty, field_values[i]); |
| 3857 | 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 | 4727 | .inlining = parent_block.inlining, |
| 4695 | 4728 | .is_comptime = parent_block.is_comptime, |
| 4696 | 4729 | .want_safety = parent_block.want_safety, |
| 4730 | .float_mode = parent_block.float_mode, | |
| 4697 | 4731 | }; |
| 4698 | 4732 | |
| 4699 | 4733 | defer child_block.instructions.deinit(gpa); |
| ... | ... | @@ -5031,13 +5065,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi |
| 5031 | 5065 | fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 5032 | 5066 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 5033 | 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"); | |
| 5035 | switch (float_mode) { | |
| 5036 | .Strict => return, | |
| 5037 | .Optimized => { | |
| 5038 | // TODO implement optimized float mode | |
| 5039 | }, | |
| 5040 | } | |
| 5068 | block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known"); | |
| 5041 | 5069 | } |
| 5042 | 5070 | |
| 5043 | 5071 | fn 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 | 6814 | .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) }, |
| 6787 | 6815 | ); |
| 6788 | 6816 | errdefer msg.destroy(sema.gpa); |
| 6789 | try sema.mod.errNoteNonLazy( | |
| 6790 | dest_ty.declSrcLoc(sema.mod), | |
| 6791 | msg, | |
| 6792 | "enum declared here", | |
| 6793 | .{}, | |
| 6794 | ); | |
| 6817 | try sema.addDeclaredHereNote(msg, dest_ty); | |
| 6795 | 6818 | break :msg msg; |
| 6796 | 6819 | }; |
| 6797 | 6820 | return sema.failWithOwnedErrorMsg(block, msg); |
| ... | ... | @@ -7923,7 +7946,7 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 7923 | 7946 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 7924 | 7947 | } |
| 7925 | 7948 | |
| 7926 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 7949 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref { | |
| 7927 | 7950 | const tracy = trace(@src()); |
| 7928 | 7951 | defer tracy.end(); |
| 7929 | 7952 | |
| ... | ... | @@ -7933,7 +7956,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 7933 | 7956 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 7934 | 7957 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); |
| 7935 | 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 | } |
| 7938 | 7961 | |
| 7939 | 7962 | fn 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 | 7995 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 7973 | 7996 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 7974 | 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 | } |
| 7977 | 8000 | |
| 7978 | 8001 | fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8081,7 +8104,7 @@ fn intCast( |
| 8081 | 8104 | const ok = if (is_vector) ok: { |
| 8082 | 8105 | const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty)); |
| 8083 | 8106 | const all_in_range = try block.addInst(.{ |
| 8084 | .tag = .reduce, | |
| 8107 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 8085 | 8108 | .data = .{ .reduce = .{ |
| 8086 | 8109 | .operand = is_in_range, |
| 8087 | 8110 | .operation = .And, |
| ... | ... | @@ -8092,12 +8115,13 @@ fn intCast( |
| 8092 | 8115 | const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); |
| 8093 | 8116 | break :ok is_in_range; |
| 8094 | 8117 | }; |
| 8118 | // TODO negative_to_unsigned? | |
| 8095 | 8119 | try sema.addSafetyCheck(block, ok, .cast_truncated_data); |
| 8096 | 8120 | } else { |
| 8097 | 8121 | const ok = if (is_vector) ok: { |
| 8098 | 8122 | const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty)); |
| 8099 | 8123 | const all_in_range = try block.addInst(.{ |
| 8100 | .tag = .reduce, | |
| 8124 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 8101 | 8125 | .data = .{ .reduce = .{ |
| 8102 | 8126 | .operand = is_in_range, |
| 8103 | 8127 | .operation = .And, |
| ... | ... | @@ -8116,9 +8140,9 @@ fn intCast( |
| 8116 | 8140 | const ok = if (is_vector) ok: { |
| 8117 | 8141 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); |
| 8118 | 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 | 8144 | const all_in_range = try block.addInst(.{ |
| 8121 | .tag = .reduce, | |
| 8145 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 8122 | 8146 | .data = .{ .reduce = .{ |
| 8123 | 8147 | .operand = is_in_range, |
| 8124 | 8148 | .operation = .And, |
| ... | ... | @@ -8130,7 +8154,7 @@ fn intCast( |
| 8130 | 8154 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 8131 | 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 | 8160 | return block.addTyOp(.intcast, dest_ty, operand); |
| ... | ... | @@ -9379,7 +9403,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9379 | 9403 | } else { |
| 9380 | 9404 | for (items) |item_ref| { |
| 9381 | 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 | 9407 | if (any_ok != .none) { |
| 9384 | 9408 | any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); |
| 9385 | 9409 | } else { |
| ... | ... | @@ -9399,12 +9423,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9399 | 9423 | |
| 9400 | 9424 | // operand >= first and operand <= last |
| 9401 | 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 | 9427 | operand, |
| 9404 | 9428 | item_first, |
| 9405 | 9429 | ); |
| 9406 | 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 | 9432 | operand, |
| 9409 | 9433 | item_last, |
| 9410 | 9434 | ); |
| ... | ... | @@ -9996,40 +10020,34 @@ fn zirShl( |
| 9996 | 10020 | } else rhs; |
| 9997 | 10021 | |
| 9998 | 10022 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 9999 | if (block.wantSafety()) { | |
| 10000 | const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) { | |
| 10001 | .shl_exact => .shl_with_overflow, | |
| 10002 | else => null, | |
| 10003 | }; | |
| 10004 | if (maybe_op_ov) |op_ov_tag| { | |
| 10005 | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); | |
| 10006 | const op_ov = try block.addInst(.{ | |
| 10007 | .tag = op_ov_tag, | |
| 10008 | .data = .{ .ty_pl = .{ | |
| 10009 | .ty = try sema.addType(op_ov_tuple_ty), | |
| 10010 | .payload = try sema.addExtra(Air.Bin{ | |
| 10011 | .lhs = lhs, | |
| 10012 | .rhs = rhs, | |
| 10013 | }), | |
| 10023 | if (block.wantSafety() and air_tag == .shl_exact) { | |
| 10024 | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); | |
| 10025 | const op_ov = try block.addInst(.{ | |
| 10026 | .tag = .shl_with_overflow, | |
| 10027 | .data = .{ .ty_pl = .{ | |
| 10028 | .ty = try sema.addType(op_ov_tuple_ty), | |
| 10029 | .payload = try sema.addExtra(Air.Bin{ | |
| 10030 | .lhs = lhs, | |
| 10031 | .rhs = rhs, | |
| 10032 | }), | |
| 10033 | } }, | |
| 10034 | }); | |
| 10035 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); | |
| 10036 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) | |
| 10037 | try block.addInst(.{ | |
| 10038 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 10039 | .data = .{ .reduce = .{ | |
| 10040 | .operand = ov_bit, | |
| 10041 | .operation = .Or, | |
| 10014 | 10042 | } }, |
| 10015 | }); | |
| 10016 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); | |
| 10017 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) | |
| 10018 | try block.addInst(.{ | |
| 10019 | .tag = .reduce, | |
| 10020 | .data = .{ .reduce = .{ | |
| 10021 | .operand = ov_bit, | |
| 10022 | .operation = .Or, | |
| 10023 | } }, | |
| 10024 | }) | |
| 10025 | else | |
| 10026 | ov_bit; | |
| 10027 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); | |
| 10028 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | |
| 10043 | }) | |
| 10044 | else | |
| 10045 | ov_bit; | |
| 10046 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); | |
| 10047 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | |
| 10029 | 10048 | |
| 10030 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); | |
| 10031 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | |
| 10032 | } | |
| 10049 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); | |
| 10050 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | |
| 10033 | 10051 | } |
| 10034 | 10052 | return block.addBinOp(air_tag, lhs, new_rhs); |
| 10035 | 10053 | } |
| ... | ... | @@ -10107,7 +10125,23 @@ fn zirShr( |
| 10107 | 10125 | } else rhs_src; |
| 10108 | 10126 | |
| 10109 | 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 | } |
| 10112 | 10146 | |
| 10113 | 10147 | fn zirBitwise( |
| ... | ... | @@ -10697,7 +10731,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 10697 | 10731 | return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target)); |
| 10698 | 10732 | } |
| 10699 | 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 | } |
| 10702 | 10736 | |
| 10703 | 10737 | const lhs = if (rhs_ty.zigTypeTag() == .Vector) |
| ... | ... | @@ -11056,6 +11090,7 @@ fn analyzeArithmetic( |
| 11056 | 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 | 11094 | if (maybe_lhs_val) |lhs_val| { |
| 11060 | 11095 | if (lhs_val.isUndef()) { |
| 11061 | 11096 | if (is_int) { |
| ... | ... | @@ -11078,8 +11113,8 @@ fn analyzeArithmetic( |
| 11078 | 11113 | try sema.floatAdd(lhs_val, rhs_val, resolved_type), |
| 11079 | 11114 | ); |
| 11080 | 11115 | } |
| 11081 | } else break :rs .{ .src = rhs_src, .air_tag = .add }; | |
| 11082 | } else break :rs .{ .src = lhs_src, .air_tag = .add }; | |
| 11116 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11117 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11083 | 11118 | }, |
| 11084 | 11119 | .addwrap => { |
| 11085 | 11120 | // Integers only; floats are checked above. |
| ... | ... | @@ -11090,6 +11125,7 @@ fn analyzeArithmetic( |
| 11090 | 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 | 11129 | if (maybe_rhs_val) |rhs_val| { |
| 11094 | 11130 | if (rhs_val.isUndef()) { |
| 11095 | 11131 | return sema.addConstUndef(resolved_type); |
| ... | ... | @@ -11102,8 +11138,8 @@ fn analyzeArithmetic( |
| 11102 | 11138 | resolved_type, |
| 11103 | 11139 | try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type), |
| 11104 | 11140 | ); |
| 11105 | } else break :rs .{ .src = lhs_src, .air_tag = .addwrap }; | |
| 11106 | } else break :rs .{ .src = rhs_src, .air_tag = .addwrap }; | |
| 11141 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11142 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11107 | 11143 | }, |
| 11108 | 11144 | .add_sat => { |
| 11109 | 11145 | // Integers only; floats are checked above. |
| ... | ... | @@ -11151,6 +11187,7 @@ fn analyzeArithmetic( |
| 11151 | 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 | 11191 | if (maybe_lhs_val) |lhs_val| { |
| 11155 | 11192 | if (lhs_val.isUndef()) { |
| 11156 | 11193 | if (is_int) { |
| ... | ... | @@ -11173,8 +11210,8 @@ fn analyzeArithmetic( |
| 11173 | 11210 | try sema.floatSub(lhs_val, rhs_val, resolved_type), |
| 11174 | 11211 | ); |
| 11175 | 11212 | } |
| 11176 | } else break :rs .{ .src = rhs_src, .air_tag = .sub }; | |
| 11177 | } else break :rs .{ .src = lhs_src, .air_tag = .sub }; | |
| 11213 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11214 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11178 | 11215 | }, |
| 11179 | 11216 | .subwrap => { |
| 11180 | 11217 | // Integers only; floats are checked above. |
| ... | ... | @@ -11188,6 +11225,7 @@ fn analyzeArithmetic( |
| 11188 | 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 | 11229 | if (maybe_lhs_val) |lhs_val| { |
| 11192 | 11230 | if (lhs_val.isUndef()) { |
| 11193 | 11231 | return sema.addConstUndef(resolved_type); |
| ... | ... | @@ -11197,8 +11235,8 @@ fn analyzeArithmetic( |
| 11197 | 11235 | resolved_type, |
| 11198 | 11236 | try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type), |
| 11199 | 11237 | ); |
| 11200 | } else break :rs .{ .src = rhs_src, .air_tag = .subwrap }; | |
| 11201 | } else break :rs .{ .src = lhs_src, .air_tag = .subwrap }; | |
| 11238 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11239 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11202 | 11240 | }, |
| 11203 | 11241 | .sub_sat => { |
| 11204 | 11242 | // Integers only; floats are checked above. |
| ... | ... | @@ -11305,14 +11343,14 @@ fn analyzeArithmetic( |
| 11305 | 11343 | if (is_int) { |
| 11306 | 11344 | break :rs .{ .src = rhs_src, .air_tag = .div_trunc }; |
| 11307 | 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 | 11349 | } else { |
| 11312 | 11350 | if (is_int) { |
| 11313 | 11351 | break :rs .{ .src = lhs_src, .air_tag = .div_trunc }; |
| 11314 | 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 | 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 | 11393 | if (maybe_lhs_val) |lhs_val| { |
| 11355 | 11394 | if (lhs_val.isUndef()) { |
| 11356 | 11395 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { |
| ... | ... | @@ -11376,8 +11415,8 @@ fn analyzeArithmetic( |
| 11376 | 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 }; | |
| 11380 | } else break :rs .{ .src = lhs_src, .air_tag = .div_trunc }; | |
| 11418 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11419 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11381 | 11420 | }, |
| 11382 | 11421 | .div_floor => { |
| 11383 | 11422 | // For integers: |
| ... | ... | @@ -11414,6 +11453,7 @@ fn analyzeArithmetic( |
| 11414 | 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 | 11457 | if (maybe_lhs_val) |lhs_val| { |
| 11418 | 11458 | if (lhs_val.isUndef()) { |
| 11419 | 11459 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { |
| ... | ... | @@ -11439,8 +11479,8 @@ fn analyzeArithmetic( |
| 11439 | 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 }; | |
| 11443 | } else break :rs .{ .src = lhs_src, .air_tag = .div_floor }; | |
| 11482 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11483 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11444 | 11484 | }, |
| 11445 | 11485 | .div_exact => { |
| 11446 | 11486 | // For integers: |
| ... | ... | @@ -11476,6 +11516,7 @@ fn analyzeArithmetic( |
| 11476 | 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 | 11520 | if (maybe_lhs_val) |lhs_val| { |
| 11480 | 11521 | if (maybe_rhs_val) |rhs_val| { |
| 11481 | 11522 | if (is_int) { |
| ... | ... | @@ -11491,8 +11532,8 @@ fn analyzeArithmetic( |
| 11491 | 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 }; | |
| 11495 | } else break :rs .{ .src = lhs_src, .air_tag = .div_exact }; | |
| 11535 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11536 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11496 | 11537 | }, |
| 11497 | 11538 | .mul => { |
| 11498 | 11539 | // For integers: |
| ... | ... | @@ -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 | 11558 | if (maybe_rhs_val) |rhs_val| { |
| 11517 | 11559 | if (rhs_val.isUndef()) { |
| 11518 | 11560 | if (is_int) { |
| ... | ... | @@ -11548,8 +11590,8 @@ fn analyzeArithmetic( |
| 11548 | 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 }; | |
| 11552 | } else break :rs .{ .src = rhs_src, .air_tag = .mul }; | |
| 11593 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11594 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11553 | 11595 | }, |
| 11554 | 11596 | .mulwrap => { |
| 11555 | 11597 | // Integers only; floats are handled above. |
| ... | ... | @@ -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 | 11612 | if (maybe_rhs_val) |rhs_val| { |
| 11570 | 11613 | if (rhs_val.isUndef()) { |
| 11571 | 11614 | return sema.addConstUndef(resolved_type); |
| ... | ... | @@ -11584,8 +11627,8 @@ fn analyzeArithmetic( |
| 11584 | 11627 | resolved_type, |
| 11585 | 11628 | try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target), |
| 11586 | 11629 | ); |
| 11587 | } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap }; | |
| 11588 | } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap }; | |
| 11630 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11631 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11589 | 11632 | }, |
| 11590 | 11633 | .mul_sat => { |
| 11591 | 11634 | // Integers only; floats are checked above. |
| ... | ... | @@ -11755,6 +11798,7 @@ fn analyzeArithmetic( |
| 11755 | 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 | 11802 | if (maybe_lhs_val) |lhs_val| { |
| 11759 | 11803 | if (lhs_val.isUndef()) { |
| 11760 | 11804 | return sema.addConstUndef(resolved_type); |
| ... | ... | @@ -11764,8 +11808,8 @@ fn analyzeArithmetic( |
| 11764 | 11808 | resolved_type, |
| 11765 | 11809 | try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), |
| 11766 | 11810 | ); |
| 11767 | } else break :rs .{ .src = rhs_src, .air_tag = .rem }; | |
| 11768 | } else break :rs .{ .src = lhs_src, .air_tag = .rem }; | |
| 11811 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11812 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11769 | 11813 | }, |
| 11770 | 11814 | .mod => { |
| 11771 | 11815 | // For integers: |
| ... | ... | @@ -11812,6 +11856,7 @@ fn analyzeArithmetic( |
| 11812 | 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 | 11860 | if (maybe_lhs_val) |lhs_val| { |
| 11816 | 11861 | if (lhs_val.isUndef()) { |
| 11817 | 11862 | return sema.addConstUndef(resolved_type); |
| ... | ... | @@ -11821,8 +11866,8 @@ fn analyzeArithmetic( |
| 11821 | 11866 | resolved_type, |
| 11822 | 11867 | try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target), |
| 11823 | 11868 | ); |
| 11824 | } else break :rs .{ .src = rhs_src, .air_tag = .mod }; | |
| 11825 | } else break :rs .{ .src = lhs_src, .air_tag = .mod }; | |
| 11869 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | |
| 11870 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | |
| 11826 | 11871 | }, |
| 11827 | 11872 | else => unreachable, |
| 11828 | 11873 | } |
| ... | ... | @@ -11852,7 +11897,7 @@ fn analyzeArithmetic( |
| 11852 | 11897 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 11853 | 11898 | const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector) |
| 11854 | 11899 | try block.addInst(.{ |
| 11855 | .tag = .reduce, | |
| 11900 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 11856 | 11901 | .data = .{ .reduce = .{ |
| 11857 | 11902 | .operand = ov_bit, |
| 11858 | 11903 | .operation = .Or, |
| ... | ... | @@ -11867,6 +11912,96 @@ fn analyzeArithmetic( |
| 11867 | 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 | 12006 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); |
| 11872 | 12007 | } |
| ... | ... | @@ -12374,7 +12509,7 @@ fn cmpSelf( |
| 12374 | 12509 | const result_ty_ref = try sema.addType(result_ty); |
| 12375 | 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 | 12513 | return block.addBinOp(tag, casted_lhs, casted_rhs); |
| 12379 | 12514 | } |
| 12380 | 12515 | |
| ... | ... | @@ -14387,6 +14522,7 @@ fn zirStructInit( |
| 14387 | 14522 | var field_i: u32 = 0; |
| 14388 | 14523 | var extra_index = extra.end; |
| 14389 | 14524 | |
| 14525 | const is_packed = resolved_ty.containerLayout() == .Packed; | |
| 14390 | 14526 | while (field_i < extra.data.fields_len) : (field_i += 1) { |
| 14391 | 14527 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); |
| 14392 | 14528 | extra_index = item.end; |
| ... | ... | @@ -14395,7 +14531,10 @@ fn zirStructInit( |
| 14395 | 14531 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; |
| 14396 | 14532 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 14397 | 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 | 14538 | if (field_inits[field_index] != .none) { |
| 14400 | 14539 | const other_field_type = found_fields[field_index]; |
| 14401 | 14540 | const other_field_type_data = zir_datas[other_field_type].pl_node; |
| ... | ... | @@ -14410,6 +14549,15 @@ fn zirStructInit( |
| 14410 | 14549 | } |
| 14411 | 14550 | found_fields[field_index] = item.data.field_type; |
| 14412 | 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 | } |
| 14414 | 14562 | |
| 14415 | 14563 | return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); |
| ... | ... | @@ -14445,7 +14593,7 @@ fn zirStructInit( |
| 14445 | 14593 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 14446 | 14594 | }); |
| 14447 | 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 | 14597 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 14450 | 14598 | const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val); |
| 14451 | 14599 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); |
| ... | ... | @@ -14550,7 +14698,7 @@ fn finishStructInit( |
| 14550 | 14698 | for (field_inits) |field_init, i_usize| { |
| 14551 | 14699 | const i = @intCast(u32, i_usize); |
| 14552 | 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 | 14702 | try sema.storePtr(block, dest_src, field_ptr, field_init); |
| 14555 | 14703 | } |
| 14556 | 14704 | |
| ... | ... | @@ -14573,22 +14721,41 @@ fn zirStructInitAnon( |
| 14573 | 14721 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); |
| 14574 | 14722 | const types = try sema.arena.alloc(Type, extra.data.fields_len); |
| 14575 | 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); | |
| 14577 | 14727 | |
| 14578 | const opt_runtime_src = rs: { | |
| 14579 | var runtime_src: ?LazySrcLoc = null; | |
| 14728 | const opt_runtime_index = rs: { | |
| 14729 | var runtime_index: ?usize = null; | |
| 14580 | 14730 | var extra_index = extra.end; |
| 14581 | 14731 | for (types) |*field_ty, i| { |
| 14582 | const init_src = src; // TODO better source location | |
| 14583 | 14732 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 14584 | 14733 | extra_index = item.end; |
| 14585 | 14734 | |
| 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 | 14752 | const init = try sema.resolveInst(item.data.init); |
| 14588 | 14753 | field_ty.* = sema.typeOf(init); |
| 14589 | 14754 | if (types[i].zigTypeTag() == .Opaque) { |
| 14590 | 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 | 14759 | errdefer msg.destroy(sema.gpa); |
| 14593 | 14760 | |
| 14594 | 14761 | try sema.addDeclaredHereNote(msg, types[i]); |
| ... | ... | @@ -14596,28 +14763,37 @@ fn zirStructInitAnon( |
| 14596 | 14763 | }; |
| 14597 | 14764 | return sema.failWithOwnedErrorMsg(block, msg); |
| 14598 | 14765 | } |
| 14766 | const init_src = src; // TODO better source location | |
| 14599 | 14767 | if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { |
| 14600 | 14768 | values[i] = init_val; |
| 14601 | 14769 | } else { |
| 14602 | 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 | }; |
| 14608 | 14776 | |
| 14609 | 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 | 14779 | .types = types, |
| 14612 | 14780 | .values = values, |
| 14613 | 14781 | }); |
| 14614 | 14782 | |
| 14615 | const runtime_src = opt_runtime_src orelse { | |
| 14783 | const runtime_index = opt_runtime_index orelse { | |
| 14616 | 14784 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); |
| 14617 | 14785 | return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref); |
| 14618 | 14786 | }; |
| 14619 | 14787 | |
| 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 | }; | |
| 14621 | 14797 | |
| 14622 | 14798 | if (is_ref) { |
| 14623 | 14799 | const target = sema.mod.getTarget(); |
| ... | ... | @@ -15513,13 +15689,21 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15513 | 15689 | if (decls_val.sliceLen(mod) > 0) { |
| 15514 | 15690 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 15515 | 15691 | } |
| 15692 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | |
| 15516 | 15693 | |
| 15517 | 15694 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 15518 | 15695 | errdefer new_decl_arena.deinit(); |
| 15519 | 15696 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 15520 | 15697 | |
| 15521 | 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 | 15707 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); |
| 15524 | 15708 | union_payload.* = .{ |
| 15525 | 15709 | .base = .{ .tag = type_tag }, |
| ... | ... | @@ -15540,7 +15724,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15540 | 15724 | .fields = .{}, |
| 15541 | 15725 | .node_offset = src.node_offset.x, |
| 15542 | 15726 | .zir_index = inst, |
| 15543 | .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout), | |
| 15727 | .layout = layout, | |
| 15544 | 15728 | .status = .have_field_types, |
| 15545 | 15729 | .namespace = .{ |
| 15546 | 15730 | .parent = block.namespace, |
| ... | ... | @@ -15550,11 +15734,15 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15550 | 15734 | }; |
| 15551 | 15735 | |
| 15552 | 15736 | // Tag type |
| 15737 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | |
| 15553 | 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 | 15740 | var buffer: Value.ToTypeBuffer = undefined; |
| 15556 | break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 15557 | } else try sema.generateUnionTagTypeSimple(block, fields_len, null); | |
| 15741 | union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | |
| 15742 | } else { | |
| 15743 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); | |
| 15744 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | |
| 15745 | } | |
| 15558 | 15746 | |
| 15559 | 15747 | // Fields |
| 15560 | 15748 | if (fields_len > 0) { |
| ... | ... | @@ -15578,6 +15766,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 15578 | 15766 | sema.mod, |
| 15579 | 15767 | ); |
| 15580 | 15768 | |
| 15769 | if (enum_field_names) |set| { | |
| 15770 | set.putAssumeCapacity(field_name, {}); | |
| 15771 | } | |
| 15772 | ||
| 15581 | 15773 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 15582 | 15774 | if (gop.found_existing) { |
| 15583 | 15775 | // TODO: better source location |
| ... | ... | @@ -15823,7 +16015,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 15823 | 16015 | } |
| 15824 | 16016 | |
| 15825 | 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 | } |
| 15828 | 16029 | |
| 15829 | 16030 | fn 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 | 16355 | // TODO compile error if the result pointer is comptime known and would have an |
| 16155 | 16356 | // alignment that disagrees with the Decl's alignment. |
| 16156 | 16357 | |
| 16157 | // TODO insert safety check that the alignment is correct | |
| 16158 | ||
| 16159 | 16358 | const ptr_info = ptr_ty.ptrInfo().data; |
| 16160 | 16359 | const dest_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 16161 | 16360 | .pointee_type = ptr_info.pointee_type, |
| ... | ... | @@ -16166,6 +16365,41 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 16166 | 16365 | .@"volatile" = ptr_info.@"volatile", |
| 16167 | 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 | 16403 | return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src); |
| 16170 | 16404 | } |
| 16171 | 16405 | |
| ... | ... | @@ -17026,7 +17260,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 17026 | 17260 | |
| 17027 | 17261 | try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); |
| 17028 | 17262 | return block.addInst(.{ |
| 17029 | .tag = .reduce, | |
| 17263 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | |
| 17030 | 17264 | .data = .{ .reduce = .{ |
| 17031 | 17265 | .operand = operand, |
| 17032 | 17266 | .operation = operation, |
| ... | ... | @@ -18800,8 +19034,16 @@ pub const PanicId = enum { |
| 18800 | 19034 | incorrect_alignment, |
| 18801 | 19035 | invalid_error_code, |
| 18802 | 19036 | cast_truncated_data, |
| 19037 | negative_to_unsigned, | |
| 18803 | 19038 | integer_overflow, |
| 18804 | 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 | }; |
| 18806 | 19048 | |
| 18807 | 19049 | fn addSafetyCheck( |
| ... | ... | @@ -19017,8 +19259,15 @@ fn safetyPanic( |
| 19017 | 19259 | .incorrect_alignment => "incorrect alignment", |
| 19018 | 19260 | .invalid_error_code => "invalid error code", |
| 19019 | 19261 | .cast_truncated_data => "integer cast truncated bits", |
| 19262 | .negative_to_unsigned => "attempt to cast negative value to unsigned integer", | |
| 19020 | 19263 | .integer_overflow => "integer overflow", |
| 19021 | 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 | }; |
| 19023 | 19272 | |
| 19024 | 19273 | const msg_inst = msg_inst: { |
| ... | ... | @@ -19206,16 +19455,7 @@ fn fieldVal( |
| 19206 | 19455 | return inst; |
| 19207 | 19456 | } |
| 19208 | 19457 | } |
| 19209 | // TODO add note: declared here | |
| 19210 | const kw_name = switch (child_type.zigTypeTag()) { | |
| 19211 | .Struct => "struct", | |
| 19212 | .Opaque => "opaque", | |
| 19213 | .Union => "union", | |
| 19214 | else => unreachable, | |
| 19215 | }; | |
| 19216 | return sema.fail(block, src, "{s} '{}' has no member named '{s}'", .{ | |
| 19217 | kw_name, child_type.fmt(sema.mod), field_name, | |
| 19218 | }); | |
| 19458 | return sema.failWithBadMemberAccess(block, child_type, src, field_name); | |
| 19219 | 19459 | }, |
| 19220 | 19460 | else => { |
| 19221 | 19461 | const msg = msg: { |
| ... | ... | @@ -19231,14 +19471,14 @@ fn fieldVal( |
| 19231 | 19471 | }, |
| 19232 | 19472 | .Struct => if (is_pointer_to) { |
| 19233 | 19473 | // 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 | 19475 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 19236 | 19476 | } else { |
| 19237 | 19477 | return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| 19238 | 19478 | }, |
| 19239 | 19479 | .Union => if (is_pointer_to) { |
| 19240 | 19480 | // 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 | 19482 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 19243 | 19483 | } else { |
| 19244 | 19484 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| ... | ... | @@ -19255,6 +19495,7 @@ fn fieldPtr( |
| 19255 | 19495 | object_ptr: Air.Inst.Ref, |
| 19256 | 19496 | field_name: []const u8, |
| 19257 | 19497 | field_name_src: LazySrcLoc, |
| 19498 | initializing: bool, | |
| 19258 | 19499 | ) CompileError!Air.Inst.Ref { |
| 19259 | 19500 | // When editing this function, note that there is corresponding logic to be edited |
| 19260 | 19501 | // in `fieldVal`. This function takes a pointer and returns a pointer. |
| ... | ... | @@ -19439,14 +19680,14 @@ fn fieldPtr( |
| 19439 | 19680 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 19440 | 19681 | else |
| 19441 | 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 | 19685 | .Union => { |
| 19445 | 19686 | const inner_ptr = if (is_pointer_to) |
| 19446 | 19687 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 19447 | 19688 | else |
| 19448 | 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 | 19692 | else => {}, |
| 19452 | 19693 | } |
| ... | ... | @@ -19556,7 +19797,13 @@ fn fieldCallBind( |
| 19556 | 19797 | else => {}, |
| 19557 | 19798 | } |
| 19558 | 19799 | |
| 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 | } |
| 19561 | 19808 | |
| 19562 | 19809 | fn finishFieldCallBind( |
| ... | ... | @@ -19648,6 +19895,7 @@ fn structFieldPtr( |
| 19648 | 19895 | field_name: []const u8, |
| 19649 | 19896 | field_name_src: LazySrcLoc, |
| 19650 | 19897 | unresolved_struct_ty: Type, |
| 19898 | initializing: bool, | |
| 19651 | 19899 | ) CompileError!Air.Inst.Ref { |
| 19652 | 19900 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); |
| 19653 | 19901 | |
| ... | ... | @@ -19660,10 +19908,10 @@ fn structFieldPtr( |
| 19660 | 19908 | return sema.analyzeRef(block, src, len_inst); |
| 19661 | 19909 | } |
| 19662 | 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 | 19912 | } else if (struct_ty.isAnonStruct()) { |
| 19665 | 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 | } |
| 19668 | 19916 | |
| 19669 | 19917 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| ... | ... | @@ -19672,7 +19920,7 @@ fn structFieldPtr( |
| 19672 | 19920 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| 19673 | 19921 | const field_index = @intCast(u32, field_index_big); |
| 19674 | 19922 | |
| 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 | } |
| 19677 | 19925 | |
| 19678 | 19926 | fn structFieldPtrByIndex( |
| ... | ... | @@ -19683,9 +19931,10 @@ fn structFieldPtrByIndex( |
| 19683 | 19931 | field_index: u32, |
| 19684 | 19932 | field_src: LazySrcLoc, |
| 19685 | 19933 | struct_ty: Type, |
| 19934 | initializing: bool, | |
| 19686 | 19935 | ) CompileError!Air.Inst.Ref { |
| 19687 | 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 | } |
| 19690 | 19939 | |
| 19691 | 19940 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| ... | ... | @@ -19882,6 +20131,10 @@ fn tupleFieldValByIndex( |
| 19882 | 20131 | return sema.addConstant(field_ty, field_values[field_index]); |
| 19883 | 20132 | } |
| 19884 | 20133 | |
| 20134 | if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { | |
| 20135 | return sema.addConstant(field_ty, default_val); | |
| 20136 | } | |
| 20137 | ||
| 19885 | 20138 | try sema.requireRuntimeBlock(block, src, null); |
| 19886 | 20139 | return block.addStructFieldVal(tuple_byval, field_index, field_ty); |
| 19887 | 20140 | } |
| ... | ... | @@ -19894,6 +20147,7 @@ fn unionFieldPtr( |
| 19894 | 20147 | field_name: []const u8, |
| 19895 | 20148 | field_name_src: LazySrcLoc, |
| 19896 | 20149 | unresolved_union_ty: Type, |
| 20150 | initializing: bool, | |
| 19897 | 20151 | ) CompileError!Air.Inst.Ref { |
| 19898 | 20152 | const arena = sema.arena; |
| 19899 | 20153 | assert(unresolved_union_ty.zigTypeTag() == .Union); |
| ... | ... | @@ -19909,30 +20163,32 @@ fn unionFieldPtr( |
| 19909 | 20163 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 19910 | 20164 | }); |
| 19911 | 20165 | |
| 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 | 20167 | switch (union_obj.layout) { |
| 19914 | .Auto => { | |
| 19915 | // TODO emit the access of inactive union field error commented out below. | |
| 19916 | // In order to do that, we need to first solve the problem that AstGen | |
| 19917 | // emits field_ptr instructions in order to initialize union values. | |
| 19918 | // In such case we need to know that the field_ptr instruction (which is | |
| 19919 | // calling this unionFieldPtr function) is *initializing* the union, | |
| 19920 | // in which case we would skip this check, and in fact we would actually | |
| 19921 | // set the union tag here and the payload to undefined. | |
| 19922 | ||
| 19923 | //const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 19924 | //var field_tag_buf: Value.Payload.U32 = .{ | |
| 19925 | // .base = .{ .tag = .enum_field_index }, | |
| 19926 | // .data = field_index, | |
| 19927 | //}; | |
| 19928 | //const field_tag = Value.initPayload(&field_tag_buf.base); | |
| 19929 | //const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod); | |
| 19930 | //if (!tag_matches) { | |
| 19931 | // // TODO enhance this saying which one was active | |
| 19932 | // // and which one was accessed, and showing where the union was declared. | |
| 19933 | // return sema.fail(block, src, "access of inactive union field", .{}); | |
| 19934 | //} | |
| 19935 | // TODO add runtime safety check for the active tag | |
| 20168 | .Auto => if (!initializing) { | |
| 20169 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse | |
| 20170 | break :ct; | |
| 20171 | if (union_val.isUndef()) { | |
| 20172 | return sema.failWithUseOfUndef(block, src); | |
| 20173 | } | |
| 20174 | const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 20175 | var field_tag_buf: Value.Payload.U32 = .{ | |
| 20176 | .base = .{ .tag = .enum_field_index }, | |
| 20177 | .data = field_index, | |
| 20178 | }; | |
| 20179 | const field_tag = Value.initPayload(&field_tag_buf.base); | |
| 20180 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | |
| 20181 | if (!tag_matches) { | |
| 20182 | const msg = msg: { | |
| 20183 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | |
| 20184 | const active_field_name = union_obj.fields.keys()[active_index]; | |
| 20185 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | |
| 20186 | errdefer msg.destroy(sema.gpa); | |
| 20187 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 20188 | break :msg msg; | |
| 20189 | }; | |
| 20190 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 20191 | } | |
| 19936 | 20192 | }, |
| 19937 | 20193 | .Packed, .Extern => {}, |
| 19938 | 20194 | } |
| ... | ... | @@ -19947,6 +20203,18 @@ fn unionFieldPtr( |
| 19947 | 20203 | } |
| 19948 | 20204 | |
| 19949 | 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 | 20218 | return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); |
| 19951 | 20219 | } |
| 19952 | 20220 | |
| ... | ... | @@ -20005,6 +20273,16 @@ fn unionFieldVal( |
| 20005 | 20273 | } |
| 20006 | 20274 | |
| 20007 | 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 | 20286 | return block.addStructFieldVal(union_byval, field_index, field.ty); |
| 20009 | 20287 | } |
| 20010 | 20288 | |
| ... | ... | @@ -20061,7 +20339,7 @@ fn elemPtr( |
| 20061 | 20339 | // Tuple field access. |
| 20062 | 20340 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known"); |
| 20063 | 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 | 20344 | else => unreachable, |
| 20067 | 20345 | } |
| ... | ... | @@ -20164,6 +20442,7 @@ fn tupleFieldPtr( |
| 20164 | 20442 | tuple_ptr: Air.Inst.Ref, |
| 20165 | 20443 | field_index_src: LazySrcLoc, |
| 20166 | 20444 | field_index: u32, |
| 20445 | init: bool, | |
| 20167 | 20446 | ) CompileError!Air.Inst.Ref { |
| 20168 | 20447 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 20169 | 20448 | const tuple_ty = tuple_ptr_ty.childType(); |
| ... | ... | @@ -20197,7 +20476,17 @@ fn tupleFieldPtr( |
| 20197 | 20476 | ); |
| 20198 | 20477 | } |
| 20199 | 20478 | |
| 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 | } | |
| 20201 | 20490 | |
| 20202 | 20491 | try sema.requireRuntimeBlock(block, tuple_ptr_src, null); |
| 20203 | 20492 | return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); |
| ... | ... | @@ -20911,16 +21200,11 @@ fn coerceExtra( |
| 20911 | 21200 | const msg = try sema.errMsg( |
| 20912 | 21201 | block, |
| 20913 | 21202 | inst_src, |
| 20914 | "enum '{}' has no field named '{s}'", | |
| 20915 | .{ dest_ty.fmt(sema.mod), bytes }, | |
| 21203 | "no field named '{s}' in enum '{}'", | |
| 21204 | .{ bytes, dest_ty.fmt(sema.mod) }, | |
| 20916 | 21205 | ); |
| 20917 | 21206 | errdefer msg.destroy(sema.gpa); |
| 20918 | try sema.mod.errNoteNonLazy( | |
| 20919 | dest_ty.declSrcLoc(sema.mod), | |
| 20920 | msg, | |
| 20921 | "enum declared here", | |
| 20922 | .{}, | |
| 20923 | ); | |
| 21207 | try sema.addDeclaredHereNote(msg, dest_ty); | |
| 20924 | 21208 | break :msg msg; |
| 20925 | 21209 | }; |
| 20926 | 21210 | return sema.failWithOwnedErrorMsg(block, msg); |
| ... | ... | @@ -22131,7 +22415,7 @@ fn storePtrVal( |
| 22131 | 22415 | .direct => |val_ptr| { |
| 22132 | 22416 | if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { |
| 22133 | 22417 | if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { |
| 22134 | // TODO add note showing where default value is provided | |
| 22418 | // TODO use failWithInvalidComptimeFieldStore | |
| 22135 | 22419 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| 22136 | 22420 | } |
| 22137 | 22421 | return; |
| ... | ... | @@ -23476,6 +23760,7 @@ fn coerceTupleToStruct( |
| 23476 | 23760 | const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty); |
| 23477 | 23761 | |
| 23478 | 23762 | if (struct_ty.isTupleOrAnonStruct()) { |
| 23763 | // NOTE remember to handle comptime fields | |
| 23479 | 23764 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{}); |
| 23480 | 23765 | } |
| 23481 | 23766 | |
| ... | ... | @@ -23496,12 +23781,18 @@ fn coerceTupleToStruct( |
| 23496 | 23781 | try std.fmt.allocPrint(sema.arena, "{d}", .{i}); |
| 23497 | 23782 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| 23498 | 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 | 23784 | const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); |
| 23503 | 23785 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); |
| 23504 | 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 | 23796 | if (runtime_src == null) { |
| 23506 | 23797 | if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { |
| 23507 | 23798 | field_vals[field_index] = field_val; |
| ... | ... | @@ -24259,7 +24550,7 @@ fn cmpNumeric( |
| 24259 | 24550 | }; |
| 24260 | 24551 | const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); |
| 24261 | 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 | 24555 | // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. |
| 24265 | 24556 | // For mixed signed and unsigned integers, implicit cast both operands to a signed |
| ... | ... | @@ -24380,7 +24671,7 @@ fn cmpNumeric( |
| 24380 | 24671 | const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); |
| 24381 | 24672 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); |
| 24382 | 24673 | |
| 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 | } |
| 24385 | 24676 | |
| 24386 | 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 | 25614 | try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj); |
| 25324 | 25615 | return ty; |
| 25325 | 25616 | }, |
| 25326 | .@"union", .union_tagged => { | |
| 25617 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 25327 | 25618 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 25328 | 25619 | try sema.resolveTypeFieldsUnion(block, src, ty, union_obj); |
| 25329 | 25620 | return ty; |
| ... | ... | @@ -25958,7 +26249,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 25958 | 26249 | const msg = msg: { |
| 25959 | 26250 | const tree = try sema.getAstTree(&block_scope); |
| 25960 | 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 | 26253 | errdefer msg.destroy(sema.gpa); |
| 25963 | 26254 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 25964 | 26255 | break :msg msg; |
| ... | ... | @@ -26348,7 +26639,7 @@ pub fn typeHasOnePossibleValue( |
| 26348 | 26639 | return null; |
| 26349 | 26640 | } |
| 26350 | 26641 | }, |
| 26351 | .@"union", .union_tagged => { | |
| 26642 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 26352 | 26643 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 26353 | 26644 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; |
| 26354 | 26645 | 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 | 27271 | } |
| 26981 | 27272 | }, |
| 26982 | 27273 | |
| 26983 | .@"union", .union_tagged => { | |
| 27274 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 26984 | 27275 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 26985 | 27276 | switch (union_obj.requires_comptime) { |
| 26986 | 27277 | .no, .wip => return false, |
src/Zir.zig+5| ... | ... | @@ -410,6 +410,8 @@ pub const Inst = struct { |
| 410 | 410 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. |
| 411 | 411 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 412 | 412 | field_ptr, |
| 413 | /// Same as `field_ptr` but used for struct init. | |
| 414 | field_ptr_init, | |
| 413 | 415 | /// Given a struct or object that contains virtual fields, returns the named field. |
| 414 | 416 | /// The field name is stored in string_bytes. Used by a.b syntax. |
| 415 | 417 | /// This instruction also accepts a pointer. |
| ... | ... | @@ -1070,6 +1072,7 @@ pub const Inst = struct { |
| 1070 | 1072 | .@"export", |
| 1071 | 1073 | .export_value, |
| 1072 | 1074 | .field_ptr, |
| 1075 | .field_ptr_init, | |
| 1073 | 1076 | .field_val, |
| 1074 | 1077 | .field_call_bind, |
| 1075 | 1078 | .field_ptr_named, |
| ... | ... | @@ -1370,6 +1373,7 @@ pub const Inst = struct { |
| 1370 | 1373 | .elem_ptr_imm, |
| 1371 | 1374 | .elem_val_node, |
| 1372 | 1375 | .field_ptr, |
| 1376 | .field_ptr_init, | |
| 1373 | 1377 | .field_val, |
| 1374 | 1378 | .field_call_bind, |
| 1375 | 1379 | .field_ptr_named, |
| ... | ... | @@ -1629,6 +1633,7 @@ pub const Inst = struct { |
| 1629 | 1633 | .@"export" = .pl_node, |
| 1630 | 1634 | .export_value = .pl_node, |
| 1631 | 1635 | .field_ptr = .pl_node, |
| 1636 | .field_ptr_init = .pl_node, | |
| 1632 | 1637 | .field_val = .pl_node, |
| 1633 | 1638 | .field_ptr_named = .pl_node, |
| 1634 | 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 | 729 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 730 | 730 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 731 | 731 | |
| 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 | 756 | .wasm_memory_size => unreachable, |
| 733 | 757 | .wasm_memory_grow => unreachable, |
| 734 | 758 | // 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 | 744 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 745 | 745 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 746 | 746 | |
| 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 | 771 | .wasm_memory_size => unreachable, |
| 748 | 772 | .wasm_memory_grow => unreachable, |
| 749 | 773 | // 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 | 669 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 670 | 670 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 671 | 671 | |
| 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 | 696 | .wasm_memory_size => unreachable, |
| 673 | 697 | .wasm_memory_grow => unreachable, |
| 674 | 698 | // 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 | 681 | .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), |
| 682 | 682 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 683 | 683 | |
| 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 | 708 | .wasm_memory_size => unreachable, |
| 685 | 709 | .wasm_memory_grow => unreachable, |
| 686 | 710 | // zig fmt: on |
src/arch/wasm/CodeGen.zig+24| ... | ... | @@ -1622,6 +1622,30 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1622 | 1622 | .err_return_trace, |
| 1623 | 1623 | .set_err_return_trace, |
| 1624 | 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 | } |
| 1627 | 1651 |
src/arch/wasm/abi.zig+2-2| ... | ... | @@ -77,7 +77,7 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 77 | 77 | .Union => { |
| 78 | 78 | const layout = ty.unionGetLayout(target); |
| 79 | 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 | 82 | if (ty.unionFields().count() > 1) return memory; |
| 83 | 83 | return classifyType(ty.unionFields().values()[0].ty, target); |
| ... | ... | @@ -111,7 +111,7 @@ pub fn scalarType(ty: Type, target: std.Target) Type { |
| 111 | 111 | .Union => { |
| 112 | 112 | const layout = ty.unionGetLayout(target); |
| 113 | 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 | 116 | std.debug.assert(ty.unionFields().count() == 1); |
| 117 | 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 | 751 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 752 | 752 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 753 | 753 | |
| 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 | 778 | .wasm_memory_size => unreachable, |
| 755 | 779 | .wasm_memory_grow => unreachable, |
| 756 | 780 | // zig fmt: on |
src/codegen/c.zig+33-9| ... | ... | @@ -504,7 +504,7 @@ pub const DeclGen = struct { |
| 504 | 504 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 505 | 505 | try writer.writeAll("&("); |
| 506 | 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 | 508 | try writer.print(")->payload.{ }", .{fmtIdent(field_name)}); |
| 509 | 509 | } else { |
| 510 | 510 | try writer.print(")->{ }", .{fmtIdent(field_name)}); |
| ... | ... | @@ -842,7 +842,7 @@ pub const DeclGen = struct { |
| 842 | 842 | try dg.renderTypecast(writer, ty); |
| 843 | 843 | try writer.writeAll("){"); |
| 844 | 844 | |
| 845 | if (ty.unionTagType()) |tag_ty| { | |
| 845 | if (ty.unionTagTypeSafety()) |tag_ty| { | |
| 846 | 846 | if (layout.tag_size != 0) { |
| 847 | 847 | try writer.writeAll(".tag = "); |
| 848 | 848 | try dg.renderValue(writer, tag_ty, union_obj.tag, location); |
| ... | ... | @@ -858,7 +858,7 @@ pub const DeclGen = struct { |
| 858 | 858 | try writer.print(".{ } = ", .{fmtIdent(field_name)}); |
| 859 | 859 | try dg.renderValue(writer, field_ty, union_obj.val, location); |
| 860 | 860 | } |
| 861 | if (ty.unionTagType()) |_| { | |
| 861 | if (ty.unionTagTypeSafety()) |_| { | |
| 862 | 862 | try writer.writeAll("}"); |
| 863 | 863 | } |
| 864 | 864 | try writer.writeAll("}"); |
| ... | ... | @@ -1110,7 +1110,7 @@ pub const DeclGen = struct { |
| 1110 | 1110 | defer buffer.deinit(); |
| 1111 | 1111 | |
| 1112 | 1112 | try buffer.appendSlice("typedef "); |
| 1113 | if (t.unionTagType()) |tag_ty| { | |
| 1113 | if (t.unionTagTypeSafety()) |tag_ty| { | |
| 1114 | 1114 | const name: CValue = .{ .bytes = "tag" }; |
| 1115 | 1115 | try buffer.appendSlice("struct {\n "); |
| 1116 | 1116 | if (layout.tag_size != 0) { |
| ... | ... | @@ -1134,7 +1134,7 @@ pub const DeclGen = struct { |
| 1134 | 1134 | } |
| 1135 | 1135 | try buffer.appendSlice("} "); |
| 1136 | 1136 | |
| 1137 | if (t.unionTagType()) |_| { | |
| 1137 | if (t.unionTagTypeSafety()) |_| { | |
| 1138 | 1138 | try buffer.appendSlice("payload;\n} "); |
| 1139 | 1139 | } |
| 1140 | 1140 | |
| ... | ... | @@ -1928,6 +1928,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1928 | 1928 | |
| 1929 | 1929 | .wasm_memory_size => try airWasmMemorySize(f, inst), |
| 1930 | 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 | 1955 | // zig fmt: on |
| 1932 | 1956 | }; |
| 1933 | 1957 | switch (result_value) { |
| ... | ... | @@ -3368,7 +3392,7 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3368 | 3392 | field_name = fields.keys()[index]; |
| 3369 | 3393 | field_val_ty = fields.values()[index].ty; |
| 3370 | 3394 | }, |
| 3371 | .@"union", .union_tagged => { | |
| 3395 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 3372 | 3396 | const fields = struct_ty.unionFields(); |
| 3373 | 3397 | field_name = fields.keys()[index]; |
| 3374 | 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 | 3407 | }, |
| 3384 | 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 ""; | |
| 3387 | 3411 | |
| 3388 | 3412 | const inst_ty = f.air.typeOfIndex(inst); |
| 3389 | 3413 | const local = try f.allocLocal(inst_ty, .Const); |
| ... | ... | @@ -3415,7 +3439,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3415 | 3439 | defer buf.deinit(); |
| 3416 | 3440 | const field_name = switch (struct_ty.tag()) { |
| 3417 | 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 | 3443 | .tuple, .anon_struct => blk: { |
| 3420 | 3444 | const tuple = struct_ty.tupleFields(); |
| 3421 | 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 | 3449 | }, |
| 3426 | 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 ""; | |
| 3429 | 3453 | |
| 3430 | 3454 | const inst_ty = f.air.typeOfIndex(inst); |
| 3431 | 3455 | const local = try f.allocLocal(inst_ty, .Const); |
src/codegen/llvm.zig+97-42| ... | ... | @@ -3404,7 +3404,7 @@ pub const DeclGen = struct { |
| 3404 | 3404 | |
| 3405 | 3405 | if (layout.payload_size == 0) { |
| 3406 | 3406 | return lowerValue(dg, .{ |
| 3407 | .ty = tv.ty.unionTagType().?, | |
| 3407 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3408 | 3408 | .val = tag_and_val.tag, |
| 3409 | 3409 | }); |
| 3410 | 3410 | } |
| ... | ... | @@ -3446,7 +3446,7 @@ pub const DeclGen = struct { |
| 3446 | 3446 | } |
| 3447 | 3447 | } |
| 3448 | 3448 | const llvm_tag_value = try lowerValue(dg, .{ |
| 3449 | .ty = tv.ty.unionTagType().?, | |
| 3449 | .ty = tv.ty.unionTagTypeSafety().?, | |
| 3450 | 3450 | .val = tag_and_val.tag, |
| 3451 | 3451 | }); |
| 3452 | 3452 | var fields: [3]*const llvm.Value = undefined; |
| ... | ... | @@ -3984,21 +3984,21 @@ pub const FuncGen = struct { |
| 3984 | 3984 | for (body) |inst, i| { |
| 3985 | 3985 | const opt_value: ?*const llvm.Value = switch (air_tags[inst]) { |
| 3986 | 3986 | // zig fmt: off |
| 3987 | .add => try self.airAdd(inst), | |
| 3988 | .addwrap => try self.airAddWrap(inst), | |
| 3987 | .add => try self.airAdd(inst, false), | |
| 3988 | .addwrap => try self.airAddWrap(inst, false), | |
| 3989 | 3989 | .add_sat => try self.airAddSat(inst), |
| 3990 | .sub => try self.airSub(inst), | |
| 3991 | .subwrap => try self.airSubWrap(inst), | |
| 3990 | .sub => try self.airSub(inst, false), | |
| 3991 | .subwrap => try self.airSubWrap(inst, false), | |
| 3992 | 3992 | .sub_sat => try self.airSubSat(inst), |
| 3993 | .mul => try self.airMul(inst), | |
| 3994 | .mulwrap => try self.airMulWrap(inst), | |
| 3993 | .mul => try self.airMul(inst, false), | |
| 3994 | .mulwrap => try self.airMulWrap(inst, false), | |
| 3995 | 3995 | .mul_sat => try self.airMulSat(inst), |
| 3996 | .div_float => try self.airDivFloat(inst), | |
| 3997 | .div_trunc => try self.airDivTrunc(inst), | |
| 3998 | .div_floor => try self.airDivFloor(inst), | |
| 3999 | .div_exact => try self.airDivExact(inst), | |
| 4000 | .rem => try self.airRem(inst), | |
| 4001 | .mod => try self.airMod(inst), | |
| 3996 | .div_float => try self.airDivFloat(inst, false), | |
| 3997 | .div_trunc => try self.airDivTrunc(inst, false), | |
| 3998 | .div_floor => try self.airDivFloor(inst, false), | |
| 3999 | .div_exact => try self.airDivExact(inst, false), | |
| 4000 | .rem => try self.airRem(inst, false), | |
| 4001 | .mod => try self.airMod(inst, false), | |
| 4002 | 4002 | .ptr_add => try self.airPtrAdd(inst), |
| 4003 | 4003 | .ptr_sub => try self.airPtrSub(inst), |
| 4004 | 4004 | .shl => try self.airShl(inst), |
| ... | ... | @@ -4009,6 +4009,19 @@ pub const FuncGen = struct { |
| 4009 | 4009 | .slice => try self.airSlice(inst), |
| 4010 | 4010 | .mul_add => try self.airMulAdd(inst), |
| 4011 | 4011 | |
| 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 | 4025 | .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), |
| 4013 | 4026 | .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"), |
| 4014 | 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 | 4047 | .ceil => try self.airUnaryOp(inst, .ceil), |
| 4035 | 4048 | .round => try self.airUnaryOp(inst, .round), |
| 4036 | 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), | |
| 4045 | 4050 | |
| 4046 | .cmp_vector => try self.airCmpVector(inst), | |
| 4047 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), | |
| 4051 | .neg => try self.airNeg(inst, false), | |
| 4052 | .neg_optimized => try self.airNeg(inst, true), | |
| 4053 | ||
| 4054 | .cmp_eq => try self.airCmp(inst, .eq, false), | |
| 4055 | .cmp_gt => try self.airCmp(inst, .gt, false), | |
| 4056 | .cmp_gte => try self.airCmp(inst, .gte, false), | |
| 4057 | .cmp_lt => try self.airCmp(inst, .lt, false), | |
| 4058 | .cmp_lte => try self.airCmp(inst, .lte, false), | |
| 4059 | .cmp_neq => try self.airCmp(inst, .neq, false), | |
| 4060 | ||
| 4061 | .cmp_eq_optimized => try self.airCmp(inst, .eq, true), | |
| 4062 | .cmp_gt_optimized => try self.airCmp(inst, .gt, true), | |
| 4063 | .cmp_gte_optimized => try self.airCmp(inst, .gte, true), | |
| 4064 | .cmp_lt_optimized => try self.airCmp(inst, .lt, true), | |
| 4065 | .cmp_lte_optimized => try self.airCmp(inst, .lte, true), | |
| 4066 | .cmp_neq_optimized => try self.airCmp(inst, .neq, true), | |
| 4067 | ||
| 4068 | .cmp_vector => try self.airCmpVector(inst, false), | |
| 4069 | .cmp_vector_optimized => try self.airCmpVector(inst, true), | |
| 4070 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), | |
| 4048 | 4071 | |
| 4049 | 4072 | .is_non_null => try self.airIsNonNull(inst, false, .NE), |
| 4050 | 4073 | .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE), |
| ... | ... | @@ -4093,8 +4116,10 @@ pub const FuncGen = struct { |
| 4093 | 4116 | .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), |
| 4094 | 4117 | .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), |
| 4095 | 4118 | |
| 4119 | .float_to_int => try self.airFloatToInt(inst, false), | |
| 4120 | .float_to_int_optimized => try self.airFloatToInt(inst, true), | |
| 4121 | ||
| 4096 | 4122 | .array_to_slice => try self.airArrayToSlice(inst), |
| 4097 | .float_to_int => try self.airFloatToInt(inst), | |
| 4098 | 4123 | .int_to_float => try self.airIntToFloat(inst), |
| 4099 | 4124 | .cmpxchg_weak => try self.airCmpxchg(inst, true), |
| 4100 | 4125 | .cmpxchg_strong => try self.airCmpxchg(inst, false), |
| ... | ... | @@ -4115,11 +4140,13 @@ pub const FuncGen = struct { |
| 4115 | 4140 | .splat => try self.airSplat(inst), |
| 4116 | 4141 | .select => try self.airSelect(inst), |
| 4117 | 4142 | .shuffle => try self.airShuffle(inst), |
| 4118 | .reduce => try self.airReduce(inst), | |
| 4119 | 4143 | .aggregate_init => try self.airAggregateInit(inst), |
| 4120 | 4144 | .union_init => try self.airUnionInit(inst), |
| 4121 | 4145 | .prefetch => try self.airPrefetch(inst), |
| 4122 | 4146 | |
| 4147 | .reduce => try self.airReduce(inst, false), | |
| 4148 | .reduce_optimized => try self.airReduce(inst, true), | |
| 4149 | ||
| 4123 | 4150 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 4124 | 4151 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| 4125 | 4152 | .atomic_store_release => try self.airAtomicStore(inst, .Release), |
| ... | ... | @@ -4485,8 +4512,9 @@ pub const FuncGen = struct { |
| 4485 | 4512 | return null; |
| 4486 | 4513 | } |
| 4487 | 4514 | |
| 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 | 4516 | if (self.liveness.isUnused(inst)) return null; |
| 4517 | self.builder.setFastMath(want_fast_math); | |
| 4490 | 4518 | |
| 4491 | 4519 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4492 | 4520 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -4496,8 +4524,9 @@ pub const FuncGen = struct { |
| 4496 | 4524 | return self.cmp(lhs, rhs, operand_ty, op); |
| 4497 | 4525 | } |
| 4498 | 4526 | |
| 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 | 4528 | if (self.liveness.isUnused(inst)) return null; |
| 4529 | self.builder.setFastMath(want_fast_math); | |
| 4501 | 4530 | |
| 4502 | 4531 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4503 | 4532 | const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| ... | ... | @@ -4943,10 +4972,12 @@ pub const FuncGen = struct { |
| 4943 | 4972 | return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4944 | 4973 | } |
| 4945 | 4974 | |
| 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 | 4976 | if (self.liveness.isUnused(inst)) |
| 4948 | 4977 | return null; |
| 4949 | 4978 | |
| 4979 | self.builder.setFastMath(want_fast_math); | |
| 4980 | ||
| 4950 | 4981 | const target = self.dg.module.getTarget(); |
| 4951 | 4982 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4952 | 4983 | |
| ... | ... | @@ -6095,8 +6126,9 @@ pub const FuncGen = struct { |
| 6095 | 6126 | return self.builder.buildInsertValue(partial, len, 1, ""); |
| 6096 | 6127 | } |
| 6097 | 6128 | |
| 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 | 6130 | if (self.liveness.isUnused(inst)) return null; |
| 6131 | self.builder.setFastMath(want_fast_math); | |
| 6100 | 6132 | |
| 6101 | 6133 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6102 | 6134 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6109,8 +6141,9 @@ pub const FuncGen = struct { |
| 6109 | 6141 | return self.builder.buildNUWAdd(lhs, rhs, ""); |
| 6110 | 6142 | } |
| 6111 | 6143 | |
| 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 | 6145 | if (self.liveness.isUnused(inst)) return null; |
| 6146 | self.builder.setFastMath(want_fast_math); | |
| 6114 | 6147 | |
| 6115 | 6148 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6116 | 6149 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6134,8 +6167,9 @@ pub const FuncGen = struct { |
| 6134 | 6167 | return self.builder.buildUAddSat(lhs, rhs, ""); |
| 6135 | 6168 | } |
| 6136 | 6169 | |
| 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 | 6171 | if (self.liveness.isUnused(inst)) return null; |
| 6172 | self.builder.setFastMath(want_fast_math); | |
| 6139 | 6173 | |
| 6140 | 6174 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6141 | 6175 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6148,8 +6182,9 @@ pub const FuncGen = struct { |
| 6148 | 6182 | return self.builder.buildNUWSub(lhs, rhs, ""); |
| 6149 | 6183 | } |
| 6150 | 6184 | |
| 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 | 6186 | if (self.liveness.isUnused(inst)) return null; |
| 6187 | self.builder.setFastMath(want_fast_math); | |
| 6153 | 6188 | |
| 6154 | 6189 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6155 | 6190 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6172,8 +6207,9 @@ pub const FuncGen = struct { |
| 6172 | 6207 | return self.builder.buildUSubSat(lhs, rhs, ""); |
| 6173 | 6208 | } |
| 6174 | 6209 | |
| 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 | 6211 | if (self.liveness.isUnused(inst)) return null; |
| 6212 | self.builder.setFastMath(want_fast_math); | |
| 6177 | 6213 | |
| 6178 | 6214 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6179 | 6215 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6186,8 +6222,9 @@ pub const FuncGen = struct { |
| 6186 | 6222 | return self.builder.buildNUWMul(lhs, rhs, ""); |
| 6187 | 6223 | } |
| 6188 | 6224 | |
| 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 | 6226 | if (self.liveness.isUnused(inst)) return null; |
| 6227 | self.builder.setFastMath(want_fast_math); | |
| 6191 | 6228 | |
| 6192 | 6229 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6193 | 6230 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6210,8 +6247,9 @@ pub const FuncGen = struct { |
| 6210 | 6247 | return self.builder.buildUMulFixSat(lhs, rhs, ""); |
| 6211 | 6248 | } |
| 6212 | 6249 | |
| 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 | 6251 | if (self.liveness.isUnused(inst)) return null; |
| 6252 | self.builder.setFastMath(want_fast_math); | |
| 6215 | 6253 | |
| 6216 | 6254 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6217 | 6255 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6221,8 +6259,9 @@ pub const FuncGen = struct { |
| 6221 | 6259 | return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 6222 | 6260 | } |
| 6223 | 6261 | |
| 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 | 6263 | if (self.liveness.isUnused(inst)) return null; |
| 6264 | self.builder.setFastMath(want_fast_math); | |
| 6226 | 6265 | |
| 6227 | 6266 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6228 | 6267 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6238,8 +6277,9 @@ pub const FuncGen = struct { |
| 6238 | 6277 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 6239 | 6278 | } |
| 6240 | 6279 | |
| 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 | 6281 | if (self.liveness.isUnused(inst)) return null; |
| 6282 | self.builder.setFastMath(want_fast_math); | |
| 6243 | 6283 | |
| 6244 | 6284 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6245 | 6285 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6270,8 +6310,9 @@ pub const FuncGen = struct { |
| 6270 | 6310 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 6271 | 6311 | } |
| 6272 | 6312 | |
| 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 | 6314 | if (self.liveness.isUnused(inst)) return null; |
| 6315 | self.builder.setFastMath(want_fast_math); | |
| 6275 | 6316 | |
| 6276 | 6317 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6277 | 6318 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6284,8 +6325,9 @@ pub const FuncGen = struct { |
| 6284 | 6325 | return self.builder.buildExactUDiv(lhs, rhs, ""); |
| 6285 | 6326 | } |
| 6286 | 6327 | |
| 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 | 6329 | if (self.liveness.isUnused(inst)) return null; |
| 6330 | self.builder.setFastMath(want_fast_math); | |
| 6289 | 6331 | |
| 6290 | 6332 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6291 | 6333 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6298,8 +6340,9 @@ pub const FuncGen = struct { |
| 6298 | 6340 | return self.builder.buildURem(lhs, rhs, ""); |
| 6299 | 6341 | } |
| 6300 | 6342 | |
| 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 | 6344 | if (self.liveness.isUnused(inst)) return null; |
| 6345 | self.builder.setFastMath(want_fast_math); | |
| 6303 | 6346 | |
| 6304 | 6347 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 6305 | 6348 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -7613,6 +7656,17 @@ pub const FuncGen = struct { |
| 7613 | 7656 | return self.buildFloatOp(op, operand_ty, 1, .{operand}); |
| 7614 | 7657 | } |
| 7615 | 7658 | |
| 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 | 7670 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value { |
| 7617 | 7671 | if (self.liveness.isUnused(inst)) return null; |
| 7618 | 7672 | |
| ... | ... | @@ -7927,8 +7981,9 @@ pub const FuncGen = struct { |
| 7927 | 7981 | return self.builder.buildShuffleVector(a, b, llvm_mask_value, ""); |
| 7928 | 7982 | } |
| 7929 | 7983 | |
| 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 | 7985 | if (self.liveness.isUnused(inst)) return null; |
| 7986 | self.builder.setFastMath(want_fast_math); | |
| 7932 | 7987 | |
| 7933 | 7988 | const reduce = self.air.instructions.items(.data)[inst].reduce; |
| 7934 | 7989 | const operand = try self.resolveInst(reduce.operand); |
src/codegen/llvm/bindings.zig+3| ... | ... | @@ -941,6 +941,9 @@ pub const Builder = opaque { |
| 941 | 941 | |
| 942 | 942 | pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce; |
| 943 | 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 | }; |
| 945 | 948 | |
| 946 | 949 | pub const MDString = opaque { |
src/print_air.zig+22-2| ... | ... | @@ -138,6 +138,24 @@ const Writer = struct { |
| 138 | 138 | .set_union_tag, |
| 139 | 139 | .min, |
| 140 | 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 | 159 | => try w.writeBinOp(s, inst), |
| 142 | 160 | |
| 143 | 161 | .is_null, |
| ... | ... | @@ -169,6 +187,7 @@ const Writer = struct { |
| 169 | 187 | .round, |
| 170 | 188 | .trunc_float, |
| 171 | 189 | .neg, |
| 190 | .neg_optimized, | |
| 172 | 191 | .cmp_lt_errors_len, |
| 173 | 192 | .set_err_return_trace, |
| 174 | 193 | => try w.writeUnOp(s, inst), |
| ... | ... | @@ -216,6 +235,7 @@ const Writer = struct { |
| 216 | 235 | .int_to_float, |
| 217 | 236 | .splat, |
| 218 | 237 | .float_to_int, |
| 238 | .float_to_int_optimized, | |
| 219 | 239 | .get_union_tag, |
| 220 | 240 | .clz, |
| 221 | 241 | .ctz, |
| ... | ... | @@ -280,8 +300,8 @@ const Writer = struct { |
| 280 | 300 | .mul_add => try w.writeMulAdd(s, inst), |
| 281 | 301 | .select => try w.writeSelect(s, inst), |
| 282 | 302 | .shuffle => try w.writeShuffle(s, inst), |
| 283 | .reduce => try w.writeReduce(s, inst), | |
| 284 | .cmp_vector => try w.writeCmpVector(s, inst), | |
| 303 | .reduce, .reduce_optimized => try w.writeReduce(s, inst), | |
| 304 | .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst), | |
| 285 | 305 | |
| 286 | 306 | .dbg_block_begin, .dbg_block_end => {}, |
| 287 | 307 | } |
src/print_zir.zig+1| ... | ... | @@ -390,6 +390,7 @@ const Writer = struct { |
| 390 | 390 | .switch_block => try self.writeSwitchBlock(stream, inst), |
| 391 | 391 | |
| 392 | 392 | .field_ptr, |
| 393 | .field_ptr_init, | |
| 393 | 394 | .field_val, |
| 394 | 395 | .field_call_bind, |
| 395 | 396 | => try self.writePlNodeField(stream, inst), |
src/type.zig+61-28| ... | ... | @@ -149,6 +149,7 @@ pub const Type = extern union { |
| 149 | 149 | => return .Enum, |
| 150 | 150 | |
| 151 | 151 | .@"union", |
| 152 | .union_safety_tagged, | |
| 152 | 153 | .union_tagged, |
| 153 | 154 | .type_info, |
| 154 | 155 | => return .Union, |
| ... | ... | @@ -902,7 +903,7 @@ pub const Type = extern union { |
| 902 | 903 | .reduce_op, |
| 903 | 904 | => unreachable, // needed to resolve the type before now |
| 904 | 905 | |
| 905 | .@"union", .union_tagged => { | |
| 906 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 906 | 907 | const a_union_obj = a.cast(Payload.Union).?.data; |
| 907 | 908 | const b_union_obj = (b.cast(Payload.Union) orelse return false).data; |
| 908 | 909 | return a_union_obj == b_union_obj; |
| ... | ... | @@ -1210,7 +1211,7 @@ pub const Type = extern union { |
| 1210 | 1211 | .reduce_op, |
| 1211 | 1212 | => unreachable, // needed to resolve the type before now |
| 1212 | 1213 | |
| 1213 | .@"union", .union_tagged => { | |
| 1214 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1214 | 1215 | const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data; |
| 1215 | 1216 | std.hash.autoHash(hasher, std.builtin.TypeId.Union); |
| 1216 | 1217 | std.hash.autoHash(hasher, union_obj); |
| ... | ... | @@ -1479,7 +1480,7 @@ pub const Type = extern union { |
| 1479 | 1480 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), |
| 1480 | 1481 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), |
| 1481 | 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 | 1484 | .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), |
| 1484 | 1485 | .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered), |
| 1485 | 1486 | .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), |
| ... | ... | @@ -1603,7 +1604,7 @@ pub const Type = extern union { |
| 1603 | 1604 | @tagName(t), struct_obj.owner_decl, |
| 1604 | 1605 | }); |
| 1605 | 1606 | }, |
| 1606 | .@"union", .union_tagged => { | |
| 1607 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1607 | 1608 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1608 | 1609 | return writer.print("({s} decl={d})", .{ |
| 1609 | 1610 | @tagName(t), union_obj.owner_decl, |
| ... | ... | @@ -1989,7 +1990,7 @@ pub const Type = extern union { |
| 1989 | 1990 | const decl = mod.declPtr(struct_obj.owner_decl); |
| 1990 | 1991 | try decl.renderFullyQualifiedName(mod, writer); |
| 1991 | 1992 | }, |
| 1992 | .@"union", .union_tagged => { | |
| 1993 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 1993 | 1994 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1994 | 1995 | const decl = mod.declPtr(union_obj.owner_decl); |
| 1995 | 1996 | try decl.renderFullyQualifiedName(mod, writer); |
| ... | ... | @@ -2485,8 +2486,8 @@ pub const Type = extern union { |
| 2485 | 2486 | return false; |
| 2486 | 2487 | } |
| 2487 | 2488 | }, |
| 2488 | .union_tagged => { | |
| 2489 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 2489 | .union_safety_tagged, .union_tagged => { | |
| 2490 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 2490 | 2491 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) { |
| 2491 | 2492 | return true; |
| 2492 | 2493 | } |
| ... | ... | @@ -2644,7 +2645,7 @@ pub const Type = extern union { |
| 2644 | 2645 | |
| 2645 | 2646 | .optional => ty.isPtrLikeOptional(), |
| 2646 | 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 | 2649 | .union_tagged => false, |
| 2649 | 2650 | }; |
| 2650 | 2651 | } |
| ... | ... | @@ -3050,11 +3051,10 @@ pub const Type = extern union { |
| 3050 | 3051 | }, |
| 3051 | 3052 | .@"union" => { |
| 3052 | 3053 | const union_obj = ty.castTag(.@"union").?.data; |
| 3053 | // TODO pass `true` for have_tag when unions have a safety tag | |
| 3054 | 3054 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); |
| 3055 | 3055 | }, |
| 3056 | .union_tagged => { | |
| 3057 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 3056 | .union_safety_tagged, .union_tagged => { | |
| 3057 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3058 | 3058 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); |
| 3059 | 3059 | }, |
| 3060 | 3060 | |
| ... | ... | @@ -3232,11 +3232,10 @@ pub const Type = extern union { |
| 3232 | 3232 | }, |
| 3233 | 3233 | .@"union" => { |
| 3234 | 3234 | const union_obj = ty.castTag(.@"union").?.data; |
| 3235 | // TODO pass `true` for have_tag when unions have a safety tag | |
| 3236 | 3235 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, false); |
| 3237 | 3236 | }, |
| 3238 | .union_tagged => { | |
| 3239 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 3237 | .union_safety_tagged, .union_tagged => { | |
| 3238 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 3240 | 3239 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, true); |
| 3241 | 3240 | }, |
| 3242 | 3241 | |
| ... | ... | @@ -3526,7 +3525,7 @@ pub const Type = extern union { |
| 3526 | 3525 | return try bitSizeAdvanced(int_tag_ty, target, sema_kit); |
| 3527 | 3526 | }, |
| 3528 | 3527 | |
| 3529 | .@"union", .union_tagged => { | |
| 3528 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 3530 | 3529 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3531 | 3530 | const union_obj = ty.cast(Payload.Union).?.data; |
| 3532 | 3531 | assert(union_obj.haveFieldTypes()); |
| ... | ... | @@ -4194,6 +4193,33 @@ pub const Type = extern union { |
| 4194 | 4193 | }; |
| 4195 | 4194 | } |
| 4196 | 4195 | |
| 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 | 4223 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 4198 | 4224 | /// not be stored at runtime. |
| 4199 | 4225 | pub fn unionTagTypeHypothetical(ty: Type) Type { |
| ... | ... | @@ -4225,8 +4251,8 @@ pub const Type = extern union { |
| 4225 | 4251 | const union_obj = ty.castTag(.@"union").?.data; |
| 4226 | 4252 | return union_obj.getLayout(target, false); |
| 4227 | 4253 | }, |
| 4228 | .union_tagged => { | |
| 4229 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 4254 | .union_safety_tagged, .union_tagged => { | |
| 4255 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 4230 | 4256 | return union_obj.getLayout(target, true); |
| 4231 | 4257 | }, |
| 4232 | 4258 | else => unreachable, |
| ... | ... | @@ -4238,6 +4264,7 @@ pub const Type = extern union { |
| 4238 | 4264 | .tuple, .empty_struct_literal, .anon_struct => .Auto, |
| 4239 | 4265 | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 4240 | 4266 | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 4267 | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, | |
| 4241 | 4268 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| 4242 | 4269 | else => unreachable, |
| 4243 | 4270 | }; |
| ... | ... | @@ -4936,7 +4963,7 @@ pub const Type = extern union { |
| 4936 | 4963 | return null; |
| 4937 | 4964 | } |
| 4938 | 4965 | }, |
| 4939 | .@"union", .union_tagged => { | |
| 4966 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 4940 | 4967 | const union_obj = ty.cast(Payload.Union).?.data; |
| 4941 | 4968 | const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null; |
| 4942 | 4969 | const only_field = union_obj.fields.values()[0]; |
| ... | ... | @@ -5114,7 +5141,7 @@ pub const Type = extern union { |
| 5114 | 5141 | } |
| 5115 | 5142 | }, |
| 5116 | 5143 | |
| 5117 | .@"union", .union_tagged => { | |
| 5144 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5118 | 5145 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 5119 | 5146 | switch (union_obj.requires_comptime) { |
| 5120 | 5147 | .wip, .unknown => unreachable, // This function asserts types already resolved. |
| ... | ... | @@ -5167,6 +5194,7 @@ pub const Type = extern union { |
| 5167 | 5194 | .empty_struct => self.castTag(.empty_struct).?.data, |
| 5168 | 5195 | .@"opaque" => &self.castTag(.@"opaque").?.data.namespace, |
| 5169 | 5196 | .@"union" => &self.castTag(.@"union").?.data.namespace, |
| 5197 | .union_safety_tagged => &self.castTag(.union_safety_tagged).?.data.namespace, | |
| 5170 | 5198 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, |
| 5171 | 5199 | |
| 5172 | 5200 | else => null, |
| ... | ... | @@ -5439,7 +5467,7 @@ pub const Type = extern union { |
| 5439 | 5467 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5440 | 5468 | return struct_obj.fields.values()[index].ty; |
| 5441 | 5469 | }, |
| 5442 | .@"union", .union_tagged => { | |
| 5470 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5443 | 5471 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5444 | 5472 | return union_obj.fields.values()[index].ty; |
| 5445 | 5473 | }, |
| ... | ... | @@ -5456,7 +5484,7 @@ pub const Type = extern union { |
| 5456 | 5484 | assert(struct_obj.layout != .Packed); |
| 5457 | 5485 | return struct_obj.fields.values()[index].normalAlignment(target); |
| 5458 | 5486 | }, |
| 5459 | .@"union", .union_tagged => { | |
| 5487 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5460 | 5488 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5461 | 5489 | return union_obj.fields.values()[index].normalAlignment(target); |
| 5462 | 5490 | }, |
| ... | ... | @@ -5619,8 +5647,8 @@ pub const Type = extern union { |
| 5619 | 5647 | }, |
| 5620 | 5648 | |
| 5621 | 5649 | .@"union" => return 0, |
| 5622 | .union_tagged => { | |
| 5623 | const union_obj = ty.castTag(.union_tagged).?.data; | |
| 5650 | .union_safety_tagged, .union_tagged => { | |
| 5651 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 5624 | 5652 | const layout = union_obj.getLayout(target, true); |
| 5625 | 5653 | if (layout.tag_align >= layout.payload_align) { |
| 5626 | 5654 | // {Tag, Payload} |
| ... | ... | @@ -5660,7 +5688,7 @@ pub const Type = extern union { |
| 5660 | 5688 | const error_set = ty.castTag(.error_set).?.data; |
| 5661 | 5689 | return error_set.srcLoc(mod); |
| 5662 | 5690 | }, |
| 5663 | .@"union", .union_tagged => { | |
| 5691 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5664 | 5692 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5665 | 5693 | return union_obj.srcLoc(mod); |
| 5666 | 5694 | }, |
| ... | ... | @@ -5686,6 +5714,10 @@ pub const Type = extern union { |
| 5686 | 5714 | } |
| 5687 | 5715 | |
| 5688 | 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 | 5721 | switch (ty.tag()) { |
| 5690 | 5722 | .enum_full, .enum_nonexhaustive => { |
| 5691 | 5723 | const enum_full = ty.cast(Payload.EnumFull).?.data; |
| ... | ... | @@ -5704,7 +5736,7 @@ pub const Type = extern union { |
| 5704 | 5736 | const error_set = ty.castTag(.error_set).?.data; |
| 5705 | 5737 | return error_set.owner_decl; |
| 5706 | 5738 | }, |
| 5707 | .@"union", .union_tagged => { | |
| 5739 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5708 | 5740 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5709 | 5741 | return union_obj.owner_decl; |
| 5710 | 5742 | }, |
| ... | ... | @@ -5725,7 +5757,7 @@ pub const Type = extern union { |
| 5725 | 5757 | .type_info, |
| 5726 | 5758 | => unreachable, // These need to be resolved earlier. |
| 5727 | 5759 | |
| 5728 | else => unreachable, | |
| 5760 | else => return null, | |
| 5729 | 5761 | } |
| 5730 | 5762 | } |
| 5731 | 5763 | |
| ... | ... | @@ -5748,7 +5780,7 @@ pub const Type = extern union { |
| 5748 | 5780 | const error_set = ty.castTag(.error_set).?.data; |
| 5749 | 5781 | return error_set.node_offset; |
| 5750 | 5782 | }, |
| 5751 | .@"union", .union_tagged => { | |
| 5783 | .@"union", .union_safety_tagged, .union_tagged => { | |
| 5752 | 5784 | const union_obj = ty.cast(Payload.Union).?.data; |
| 5753 | 5785 | return union_obj.node_offset; |
| 5754 | 5786 | }, |
| ... | ... | @@ -5893,6 +5925,7 @@ pub const Type = extern union { |
| 5893 | 5925 | @"opaque", |
| 5894 | 5926 | @"struct", |
| 5895 | 5927 | @"union", |
| 5928 | union_safety_tagged, | |
| 5896 | 5929 | union_tagged, |
| 5897 | 5930 | enum_simple, |
| 5898 | 5931 | enum_numbered, |
| ... | ... | @@ -6009,7 +6042,7 @@ pub const Type = extern union { |
| 6009 | 6042 | .error_set_single => Payload.Name, |
| 6010 | 6043 | .@"opaque" => Payload.Opaque, |
| 6011 | 6044 | .@"struct" => Payload.Struct, |
| 6012 | .@"union", .union_tagged => Payload.Union, | |
| 6045 | .@"union", .union_safety_tagged, .union_tagged => Payload.Union, | |
| 6013 | 6046 | .enum_full, .enum_nonexhaustive => Payload.EnumFull, |
| 6014 | 6047 | .enum_simple => Payload.EnumSimple, |
| 6015 | 6048 | .enum_numbered => Payload.EnumNumbered, |
test/behavior/align.zig+1| ... | ... | @@ -222,6 +222,7 @@ fn testBytesAlign(b: u8) !void { |
| 222 | 222 | test "@alignCast slices" { |
| 223 | 223 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 224 | 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 225 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 225 | 226 | |
| 226 | 227 | var array align(4) = [_]u32{ 1, 1 }; |
| 227 | 228 | const slice = array[0..]; |
test/behavior/bugs/1381.zig+2| ... | ... | @@ -12,8 +12,10 @@ const A = union(enum) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "union that needs padding bytes inside an array" { |
| 15 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 16 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 18 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 17 | 19 | |
| 18 | 20 | var as = [_]A{ |
| 19 | 21 | A{ .B = B{ .D = 1 } }, |
test/behavior/cast.zig+3| ... | ... | @@ -127,6 +127,7 @@ test "@intToFloat(f80)" { |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | fn testIntToFloat(comptime Int: type, k: Int) !void { |
| 130 | @setRuntimeSafety(false); // TODO | |
| 130 | 131 | const f = @intToFloat(f80, k); |
| 131 | 132 | const i = @floatToInt(Int, f); |
| 132 | 133 | try expect(i == k); |
| ... | ... | @@ -151,6 +152,8 @@ test "@intToFloat(f80)" { |
| 151 | 152 | test "@floatToInt" { |
| 152 | 153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 153 | 154 | 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 | |
| 154 | 157 | |
| 155 | 158 | try testFloatToInts(); |
| 156 | 159 | comptime try testFloatToInts(); |
test/behavior/math.zig+1| ... | ... | @@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void { |
| 377 | 377 | } |
| 378 | 378 | |
| 379 | 379 | test "division" { |
| 380 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 380 | 381 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 381 | 382 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 382 | 383 | 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 | 998 | } |
| 999 | 999 | |
| 1000 | 1000 | test "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 | 1004 | const Value = struct { |
| 1002 | 1005 | ref: u32 = 2, |
| 1003 | 1006 | kind: union(enum) { |
test/behavior/type.zig+1-1| ... | ... | @@ -412,7 +412,7 @@ test "Type.Union" { |
| 412 | 412 | |
| 413 | 413 | const Untagged = @Type(.{ |
| 414 | 414 | .Union = .{ |
| 415 | .layout = .Auto, | |
| 415 | .layout = .Extern, | |
| 416 | 416 | .tag_type = null, |
| 417 | 417 | .fields = &.{ |
| 418 | 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 | 37 | |
| 38 | 38 | test "basic unions" { |
| 39 | 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 40 | 41 | |
| 41 | 42 | var foo = Foo{ .int = 1 }; |
| 42 | 43 | try expect(foo.int == 1); |
| ... | ... | @@ -430,9 +431,11 @@ const Foo1 = union(enum) { |
| 430 | 431 | var glbl: Foo1 = undefined; |
| 431 | 432 | |
| 432 | 433 | test "global union with single field is correctly initialized" { |
| 434 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 433 | 435 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 434 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 435 | 437 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 438 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 436 | 439 | |
| 437 | 440 | glbl = Foo1{ |
| 438 | 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 | 476 | } |
| 474 | 477 | |
| 475 | 478 | test "union initializer generates padding only if needed" { |
| 479 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 476 | 480 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 481 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 477 | 482 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 483 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 478 | 484 | |
| 479 | 485 | const U = union(enum) { |
| 480 | 486 | A: u24, |
| ... | ... | @@ -747,9 +753,11 @@ fn Setter(attr: Attribute) type { |
| 747 | 753 | } |
| 748 | 754 | |
| 749 | 755 | test "return union init with void payload" { |
| 756 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 750 | 757 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 751 | 758 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 752 | 759 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 760 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 753 | 761 | |
| 754 | 762 | const S = struct { |
| 755 | 763 | fn entry() !void { |
| ... | ... | @@ -775,6 +783,7 @@ test "@unionInit stored to a const" { |
| 775 | 783 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 776 | 784 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 777 | 785 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 786 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 778 | 787 | |
| 779 | 788 | const S = struct { |
| 780 | 789 | const U = union(enum) { |
| ... | ... | @@ -937,6 +946,7 @@ test "cast from anonymous struct to union" { |
| 937 | 946 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 938 | 947 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 939 | 948 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 949 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 940 | 950 | |
| 941 | 951 | const S = struct { |
| 942 | 952 | const U = union(enum) { |
| ... | ... | @@ -969,6 +979,7 @@ test "cast from pointer to anonymous struct to pointer to union" { |
| 969 | 979 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 970 | 980 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 971 | 981 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 982 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 972 | 983 | |
| 973 | 984 | const S = struct { |
| 974 | 985 | const U = union(enum) { |
| ... | ... | @@ -1104,6 +1115,8 @@ test "union enum type gets a separate scope" { |
| 1104 | 1115 | |
| 1105 | 1116 | test "global variable struct contains union initialized to non-most-aligned field" { |
| 1106 | 1117 | 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 | |
| 1107 | 1120 | |
| 1108 | 1121 | const T = struct { |
| 1109 | 1122 | const U = union(enum) { |
test/cases/aarch64-macos/hello_world_with_updates.0.zig+1| ... | ... | @@ -3,3 +3,4 @@ |
| 3 | 3 | // target=aarch64-macos |
| 4 | 4 | // |
| 5 | 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 @@ |
| 1 | comptime { | |
| 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 | 6 | // target=native |
| 7 | 7 | // |
| 8 | 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 | 8 | // backend=stage2 |
| 9 | 9 | // 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 | 11 | // backend=stage2 |
| 12 | 12 | // 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 | 15 | // :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 | 34 | // :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions |
| 35 | 35 | // :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs |
| 36 | 36 | // :18:22: note: opaque declared here |
| 37 | // :24:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs | |
| 37 | // :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs | |
| 38 | 38 | // :23:22: note: opaque declared here |
test/cases/compile_errors/duplicate_field_in_anonymous_struct_literal.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | export 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 @@ |
| 1 | const U = union { | |
| 2 | comptime a: u32 = 1, | |
| 3 | }; | |
| 4 | const E = enum { | |
| 5 | comptime a = 1, | |
| 6 | }; | |
| 7 | const P = packed struct { | |
| 8 | comptime a: u32 = 1, | |
| 9 | }; | |
| 10 | const 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 | 13 | var s: S = .{}; |
| 14 | 14 | s.a = T{ .a = 2, .b = 2 }; |
| 15 | 15 | } |
| 16 | pub 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 | } | |
| 23 | pub 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 | } | |
| 33 | pub 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 | 53 | // error |
| 17 | 54 | // target=native |
| 18 | 55 | // backend=stage2 |
| 19 | 56 | // |
| 20 | 57 | // :6:19: error: value stored in comptime field does not match the default value of the field |
| 21 | 58 | // :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 | 18 | // backend=stage2 |
| 19 | 19 | // 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 | 27 | // backend=llvm |
| 28 | 28 | // 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 @@ |
| 1 | comptime { | |
| 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 @@ |
| 1 | export 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 | 16 | // error |
| 17 | 17 | // 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 | 20 | // :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 | 13 | // backend=stage2 |
| 14 | 14 | // target=native |
| 15 | 15 | // |
| 16 | // :9:14: error: expected type 'type', found 'tmp.U' | |
| 17 | // :1:11: note: union declared here | |
| 16 | // :9:8: error: use of undefined value here causes undefined behavior |
test/cases/safety/@alignCast misaligned.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -18,5 +20,5 @@ fn foo(bytes: []u8) u32 { |
| 18 | 20 | return int_slice[0]; |
| 19 | 21 | } |
| 20 | 22 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | const Set1 = error{A, B}; |
| 9 | 11 | const Set2 = error{A, C}; |
| ... | ... | @@ -15,5 +17,5 @@ fn foo(set1: Set1) Set2 { |
| 15 | 17 | return @errSetCast(Set2, set1); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(-129.1)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) i8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: i8) void { } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(-1.1)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) u8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: u8) void { } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(256.2)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) u8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: u8) void { } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -16,5 +18,5 @@ fn bar(one: u1, not_zero: i32) void { |
| 16 | 18 | _ = x; |
| 17 | 19 | } |
| 18 | 20 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | var zero: usize = 0; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // run |
| 15 | // backend=stage1 | |
| 17 | // backend=llvm | |
| 16 | 18 | // target=native |
test/cases/safety/@intToPtr address zero to non-optional pointer.zig	+5-3| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | var zero: usize = 0; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // run |
| 15 | // backend=stage1 | |
| 17 | // backend=llvm | |
| 16 | 18 | // target=native |
test/cases/safety/bad union field access.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | const Foo = union { |
| ... | ... | @@ -21,5 +23,5 @@ fn bar(f: *Foo) void { |
| 21 | 23 | f.float = 12.34; |
| 22 | 24 | } |
| 23 | 25 | // 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 | 12 | return error.TestFailed; |
| 13 | 13 | } |
| 14 | 14 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | bar(9999) catch {}; |
| ... | ... | @@ -13,5 +15,5 @@ fn bar(x: u16) anyerror { |
| 13 | 15 | return @intToError(x); |
| 14 | 16 | } |
| 15 | 17 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { |
| 17 | 19 | return @divExact(a, b); |
| 18 | 20 | } |
| 19 | 21 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 { |
| 15 | 17 | return @divExact(a, b); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 14 | return error.TestFailed; |
| 15 | 15 | } |
| 16 | 16 | // run |
| 17 | // backend=stage1 | |
| 17 | // backend=llvm | |
| 18 | 18 | // target=native |
test/cases/safety/integer addition overflow.zig	+1-1| ... | ... | @@ -19,5 +19,5 @@ fn add(a: u16, b: u16) u16 { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | // backend=stage1 | |
| 22 | // backend=llvm | |
| 23 | 23 | // target=native |
test/cases/safety/integer division by zero - vectors.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 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 | 18 | return @divTrunc(a, b); |
| 17 | 19 | } |
| 18 | 20 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | const x = div0(999, 0); |
| ... | ... | @@ -14,5 +16,5 @@ fn div0(a: i32, b: i32) i32 { |
| 14 | 16 | return @divTrunc(a, b); |
| 15 | 17 | } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn mul(a: u16, b: u16) u16 { |
| 15 | 17 | return a * b; |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn neg(a: i16) i16 { |
| 15 | 17 | return -a; |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn sub(a: u16, b: u16) u16 { |
| 15 | 17 | return a - b; |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | var ptr: [*c]i32 = null; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // run |
| 15 | // backend=stage1 | |
| 17 | // backend=llvm | |
| 16 | 18 | // target=native |
test/cases/safety/optional unwrap operator on null pointer.zig	+5-3| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | var ptr: ?*i32 = null; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // run |
| 15 | // backend=stage1 | |
| 17 | // backend=llvm | |
| 16 | 18 | // target=native |
test/cases/safety/out of bounds slice access.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | const a = [_]i32{1, 2, 3, 4}; |
| ... | ... | @@ -15,5 +17,5 @@ fn bar(a: []const i32) i32 { |
| 15 | 17 | } |
| 16 | 18 | fn baz(_: i32) void { } |
| 17 | 19 | // 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | } | |
| 10 | pub fn main() !void { | |
| 11 | const x = div0(999, -1); | |
| 12 | _ = x; | |
| 13 | return error.TestFailed; | |
| 14 | } | |
| 15 | fn 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | 10 | pub fn main() !void { |
| 9 | 11 | var value: c_short = -1; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | ||
| 9 | 10 | pub fn main() !void { |
| 10 | 11 | const x = unsigned_cast(-10); |
| 11 | 12 | if (x == 0) return error.Whatever; |
| ... | ... | @@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 { |
| 15 | 16 | return @intCast(u32, x); |
| 16 | 17 | } |
| 17 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shl(a: i16, b: u4) i16 { |
| 15 | 17 | return @shlExact(a, b); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 { |
| 15 | 17 | return @shrExact(a, b); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 16 | } |
| 17 | 17 | |
| 18 | 18 | // run |
| 19 | // backend=stage1 | |
| 19 | // backend=llvm | |
| 20 | 20 | // target=native |
test/cases/safety/truncating vector cast.zig	+1-1| ... | ... | @@ -16,5 +16,5 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | // run |
| 19 | // backend=stage1 | |
| 19 | // backend=llvm | |
| 20 | 20 | // target=native |
test/cases/safety/unreachable.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | } | |
| 10 | pub 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | var value: u8 = 245; |
| ... | ... | @@ -12,5 +14,5 @@ pub fn main() !void { |
| 12 | 14 | return error.TestFailed; |
| 13 | 15 | } |
| 14 | 16 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shl(a: u16, b: u4) u16 { |
| 15 | 17 | return @shlExact(a, b); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 { |
| 15 | 17 | return @shrExact(a, b); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 16 | } |
| 17 | 17 | |
| 18 | 18 | // run |
| 19 | // backend=stage1 | |
| 19 | // backend=llvm | |
| 20 | 20 | // target=native |
test/cases/safety/unwrap error.zig	+2-2| ... | ... | @@ -15,5 +15,5 @@ fn bar() !void { |
| 15 | 15 | return error.Whatever; |
| 16 | 16 | } |
| 17 | 17 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shorten_cast(x: u8) u0 { |
| 15 | 17 | return @intCast(u0, x); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | |
| 9 | 11 | pub fn main() !void { |
| ... | ... | @@ -15,5 +17,5 @@ fn shorten_cast(x: i32) i8 { |
| 15 | 17 | return @intCast(i8, x); |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 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 | 18 | return a + b; |
| 17 | 19 | } |
| 18 | 20 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 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 | 18 | return a * b; |
| 17 | 19 | } |
| 18 | 20 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 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 | 17 | return -a; |
| 16 | 18 | } |
| 17 | 19 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 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 | 18 | return a - b; |
| 17 | 19 | } |
| 18 | 20 | // 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 | // target=x86_64-linux |
| 4 | 4 | // |
| 5 | 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 | // target=x86_64-macos |
| 4 | 4 | // |
| 5 | 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 | 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 | 843 | ":1:11: note: enum declared here", |
| 844 | 844 | }); |
| 845 | 845 | } |