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