authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-13 08:16:55-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-13 08:16:55-07:00
log7aa85691b08262b4fd63f9307e4d9cd41230e08c
tree0a94e180e3a7b908e23445524118a0e8c3754b49
parent244233da2a355cbb5b7ec2e3888c3607b91609a3
parentb6762c2473fc02e0fa71212a5556f4aed3f1942c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17504 from ziglang/fix-var-args-coercion

Sema: fix crash when coercion dest is var args

2 files changed, 61 insertions(+), 7 deletions(-)

src/Sema.zig+21-7
......@@ -4371,13 +4371,19 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
43714371 const mod = sema.mod;
43724372 const un_tok = sema.code.instructions.items(.data)[inst].un_tok;
43734373 const src = un_tok.src();
4374 const ty_operand = sema.resolveType(block, src, un_tok.operand) catch |err| switch (err) {
4375 error.GenericPoison => {
4376 // We don't actually have a type, so this will be treated as an untyped address-of operator.
4377 return;
4378 },
4374 // In case of GenericPoison, we don't actually have a type, so this will be
4375 // treated as an untyped address-of operator.
4376 if (un_tok.operand == .var_args_param_type) return;
4377 const operand_air_inst = sema.resolveInst(un_tok.operand) catch |err| switch (err) {
4378 error.GenericPoison => return,
4379 else => |e| return e,
4380 };
4381 if (operand_air_inst == .var_args_param_type) return;
4382 const ty_operand = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) {
4383 error.GenericPoison => return,
43794384 else => |e| return e,
43804385 };
4386 if (ty_operand.isGenericPoison()) return;
43814387 if (ty_operand.optEuBaseType(mod).zigTypeTag(mod) != .Pointer) {
43824388 return sema.failWithOwnedErrorMsg(block, msg: {
43834389 const msg = try sema.errMsg(block, src, "expected type '{}', found pointer", .{ty_operand.fmt(mod)});
......@@ -9846,11 +9852,19 @@ fn analyzeAs(
98469852 const mod = sema.mod;
98479853 const operand = try sema.resolveInst(zir_operand);
98489854 if (zir_dest_type == .var_args_param_type) return operand;
9849 const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) {
9855 const operand_air_inst = sema.resolveInst(zir_dest_type) catch |err| switch (err) {
9856 error.GenericPoison => return operand,
9857 else => |e| return e,
9858 };
9859 if (operand_air_inst == .var_args_param_type) return operand;
9860 const dest_ty = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) {
98509861 error.GenericPoison => return operand,
98519862 else => |e| return e,
98529863 };
9853 if (dest_ty.zigTypeTag(mod) == .NoReturn) {
9864 const dest_ty_tag = dest_ty.zigTypeTagOrPoison(mod) catch |err| switch (err) {
9865 error.GenericPoison => return operand,
9866 };
9867 if (dest_ty_tag == .NoReturn) {
98549868 return sema.fail(block, src, "cannot cast to noreturn", .{});
98559869 }
98569870 const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index|
test/behavior/var_args.zig+40
......@@ -150,6 +150,46 @@ test "simple variadic function" {
150150 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
151151 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
152152 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));
153
154 {
155 // Test type coercion of a var args argument.
156 // Originally reported at https://github.com/ziglang/zig/issues/16197
157 var runtime: bool = true;
158 var a: i32 = 1;
159 var b: i32 = 2;
160 try expect(1 == S.add(1, if (runtime) a else b));
161 }
162}
163
164test "coerce reference to var arg" {
165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
170 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
171 // https://github.com/ziglang/zig/issues/14096
172 return error.SkipZigTest;
173 }
174 if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO
175
176 const S = struct {
177 fn addPtr(count: c_int, ...) callconv(.C) c_int {
178 var ap = @cVaStart();
179 defer @cVaEnd(&ap);
180 var i: usize = 0;
181 var sum: c_int = 0;
182 while (i < count) : (i += 1) {
183 sum += @cVaArg(&ap, *c_int).*;
184 }
185 return sum;
186 }
187 };
188
189 // Originally reported at https://github.com/ziglang/zig/issues/17494
190 var a: i32 = 12;
191 var b: i32 = 34;
192 try expect(46 == S.addPtr(2, &a, &b));
153193}
154194
155195test "variadic functions" {