mirror of
https://github.com/ziglang/zig.git
synced 2026-01-28 10:15:24 +00:00
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
This commit is contained in:
parent
8592c5cdac
commit
cba7e8a4e9
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user