Commit cba7e8a4e9

mlugg <mlugg@mlugg.co.uk>
2023-09-15 02:12:03
AstGen: do not forward result pointers through @as
The `coerce_result_ptr` instruction is highly problematic and leads to unintentional memory reinterpretation in some cases. It is more correct to simply not forward result pointers through this builtin. `coerce_result_ptr` is still used for struct and array initializations, where it can still cause issues. Eliminating this usage will be a future change. Resolves: #16991
1 parent 8592c5c
Changed files (3)
src/AstGen.zig
@@ -7526,18 +7526,8 @@ fn as(
     rhs: Ast.Node.Index,
 ) InnerError!Zir.Inst.Ref {
     const dest_type = try typeExpr(gz, scope, lhs);
-    switch (ri.rl) {
-        .none, .discard, .ref, .ty, .coerced_ty => {
-            const result = try reachableExpr(gz, scope, .{ .rl = .{ .ty = dest_type } }, rhs, node);
-            return rvalue(gz, ri, result, node);
-        },
-        .ptr => |result_ptr| {
-            return asRlPtr(gz, scope, ri, node, result_ptr.inst, rhs, dest_type);
-        },
-        .inferred_ptr => |result_ptr| {
-            return asRlPtr(gz, scope, ri, node, result_ptr, rhs, dest_type);
-        },
-    }
+    const result = try reachableExpr(gz, scope, .{ .rl = .{ .ty = dest_type } }, rhs, node);
+    return rvalue(gz, ri, result, node);
 }
 
 fn unionInit(
@@ -7562,24 +7552,6 @@ fn unionInit(
     return rvalue(gz, ri, result, node);
 }
 
-fn asRlPtr(
-    gz: *GenZir,
-    scope: *Scope,
-    ri: ResultInfo,
-    src_node: Ast.Node.Index,
-    result_ptr: Zir.Inst.Ref,
-    operand_node: Ast.Node.Index,
-    dest_type: Zir.Inst.Ref,
-) InnerError!Zir.Inst.Ref {
-    if (gz.astgen.nodes_need_rl.contains(src_node)) {
-        const casted_ptr = try gz.addPlNode(.coerce_result_ptr, src_node, Zir.Inst.Bin{ .lhs = dest_type, .rhs = result_ptr });
-        return reachableExpr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = casted_ptr } } }, operand_node, src_node);
-    } else {
-        const result = try reachableExpr(gz, scope, .{ .rl = .{ .ty = dest_type } }, operand_node, src_node);
-        return rvalue(gz, ri, result, src_node);
-    }
-}
-
 fn bitCast(
     gz: *GenZir,
     scope: *Scope,
src/AstRlAnnotate.zig
@@ -800,6 +800,8 @@ fn blockExpr(astrl: *AstRlAnnotate, parent_block: ?*Block, ri: ResultInfo, node:
 }
 
 fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, args: []const Ast.Node.Index) !bool {
+    _ = ri; // Currently, no builtin consumes its result location.
+
     const tree = astrl.tree;
     const main_tokens = tree.nodes.items(.main_token);
     const builtin_token = main_tokens[node];
@@ -818,11 +820,8 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
         },
         .as => {
             _ = try astrl.expr(args[0], block, ResultInfo.type_only);
-            const rhs_consumes_rl = try astrl.expr(args[1], block, ri);
-            if (rhs_consumes_rl) {
-                try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {});
-            }
-            return rhs_consumes_rl;
+            _ = try astrl.expr(args[1], block, ResultInfo.type_only);
+            return false;
         },
         .bit_cast => {
             _ = try astrl.expr(args[0], block, ResultInfo.none);
test/behavior/cast.zig
@@ -2502,3 +2502,21 @@ test "numeric coercions with undefined" {
     to = 42.0;
     try expectEqual(@as(f32, 42.0), to);
 }
+
+test "@as does not corrupt values with incompatible representations" {
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
+    const x: f32 = @as(f16, blk: {
+        if (false) {
+            // Trick the compiler into trying to use a result pointer if it can!
+            break :blk .{undefined};
+        }
+        break :blk 1.23;
+    });
+    try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001);
+}