| author | |
| committer | |
| log | 2cd3989cb32d97c8a60d9cf4154e049815259b46 |
| tree | 989dd82927529f4133259e26c36d1c0ef0e19a44 |
| parent | 2b92c5a23e912df56885ff10d690ff7bfd1e3f47 |
Closes #127067 files changed, 122 insertions(+), 17 deletions(-)
src/Sema.zig+30-6| ... | ... | @@ -24075,16 +24075,40 @@ fn coerceVarArgParam( |
| 24075 | 24075 | inst: Air.Inst.Ref, |
| 24076 | 24076 | inst_src: LazySrcLoc, |
| 24077 | 24077 | ) !Air.Inst.Ref { |
| 24078 | const inst_ty = sema.typeOf(inst); | |
| 24079 | 24078 | if (block.is_typeof) return inst; |
| 24080 | 24079 | |
| 24081 | switch (inst_ty.zigTypeTag()) { | |
| 24080 | const coerced = switch (sema.typeOf(inst).zigTypeTag()) { | |
| 24082 | 24081 | // TODO consider casting to c_int/f64 if they fit |
| 24083 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), | |
| 24084 | else => {}, | |
| 24082 | .ComptimeInt, .ComptimeFloat => return sema.fail( | |
| 24083 | block, | |
| 24084 | inst_src, | |
| 24085 | "integer and float literals passed variadic function must be casted to a fixed-size number type", | |
| 24086 | .{}, | |
| 24087 | ), | |
| 24088 | .Fn => blk: { | |
| 24089 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined); | |
| 24090 | const fn_decl = fn_val.pointerDecl().?; | |
| 24091 | break :blk try sema.analyzeDeclRef(fn_decl); | |
| 24092 | }, | |
| 24093 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), | |
| 24094 | else => inst, | |
| 24095 | }; | |
| 24096 | ||
| 24097 | const coerced_ty = sema.typeOf(coerced); | |
| 24098 | if (!sema.validateExternType(coerced_ty, .other)) { | |
| 24099 | const msg = msg: { | |
| 24100 | const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); | |
| 24101 | errdefer msg.destroy(sema.gpa); | |
| 24102 | ||
| 24103 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 24104 | try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other); | |
| 24105 | ||
| 24106 | try sema.addDeclaredHereNote(msg, coerced_ty); | |
| 24107 | break :msg msg; | |
| 24108 | }; | |
| 24109 | return sema.failWithOwnedErrorMsg(msg); | |
| 24085 | 24110 | } |
| 24086 | // TODO implement more of this function. | |
| 24087 | return inst; | |
| 24111 | return coerced; | |
| 24088 | 24112 | } |
| 24089 | 24113 | |
| 24090 | 24114 | // TODO migrate callsites to use storePtr2 instead. |
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :4:33: error: integer and float literals in var args function must be casted |
test/cases/compile_errors/variadic_arg_validation.zig created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | pub export fn entry1() void { | |
| 8 | var arr: [2]u8 = undefined; | |
| 9 | _ = printf("%d\n", arr); | |
| 10 | } | |
| 11 | ||
| 12 | pub export fn entry2() void { | |
| 13 | _ = printf("%d\n", @as(u48, 2)); | |
| 14 | } | |
| 15 | ||
| 16 | pub export fn entry3() void { | |
| 17 | _ = printf("%d\n", {}); | |
| 18 | } | |
| 19 | ||
| 20 | // error | |
| 21 | // backend=stage2 | |
| 22 | // target=native | |
| 23 | // | |
| 24 | // :4:33: error: integer and float literals passed variadic function must be casted to a fixed-size number type | |
| 25 | // :9:24: error: arrays must be passed by reference to variadic function | |
| 26 | // :13:24: error: cannot pass 'u48' to variadic function | |
| 27 | // :13:24: note: only integers with power of two bits are extern compatible | |
| 28 | // :17:24: error: cannot pass 'void' to variadic function | |
| 29 | // :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque' |
test/standalone.zig+1| ... | ... | @@ -66,6 +66,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 66 | 66 | if (builtin.os.tag == .linux) { |
| 67 | 67 | cases.addBuildFile("test/standalone/pie/build.zig", .{}); |
| 68 | 68 | } |
| 69 | cases.addBuildFile("test/standalone/issue_12706/build.zig", .{}); | |
| 69 | 70 | |
| 70 | 71 | // Ensure the development tools are buildable. |
| 71 | 72 |
test/standalone/issue_12706/build.zig created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const Builder = std.build.Builder; | |
| 4 | const CrossTarget = std.zig.CrossTarget; | |
| 5 | ||
| 6 | // TODO integrate this with the std.build executor API | |
| 7 | fn isRunnableTarget(t: CrossTarget) bool { | |
| 8 | if (t.isNative()) return true; | |
| 9 | ||
| 10 | return (t.getOsTag() == builtin.os.tag and | |
| 11 | t.getCpuArch() == builtin.cpu.arch); | |
| 12 | } | |
| 13 | ||
| 14 | pub fn build(b: *Builder) void { | |
| 15 | const mode = b.standardReleaseOptions(); | |
| 16 | const target = b.standardTargetOptions(.{}); | |
| 17 | ||
| 18 | const exe = b.addExecutable("main", "main.zig"); | |
| 19 | exe.setBuildMode(mode); | |
| 20 | exe.install(); | |
| 21 | ||
| 22 | const c_sources = [_][]const u8{ | |
| 23 | "test.c", | |
| 24 | }; | |
| 25 | ||
| 26 | exe.addCSourceFiles(&c_sources, &.{}); | |
| 27 | exe.linkLibC(); | |
| 28 | ||
| 29 | exe.setTarget(target); | |
| 30 | b.default_step.dependOn(&exe.step); | |
| 31 | ||
| 32 | const test_step = b.step("test", "Test the program"); | |
| 33 | if (isRunnableTarget(target)) { | |
| 34 | const run_cmd = exe.run(); | |
| 35 | test_step.dependOn(&run_cmd.step); | |
| 36 | } else { | |
| 37 | test_step.dependOn(&exe.step); | |
| 38 | } | |
| 39 | } |
test/standalone/issue_12706/main.zig created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | const std = @import("std"); | |
| 2 | extern fn testFnPtr(n: c_int, ...) void; | |
| 3 | ||
| 4 | const val: c_int = 123; | |
| 5 | ||
| 6 | fn func(a: c_int) callconv(.C) void { | |
| 7 | std.debug.assert(a == val); | |
| 8 | } | |
| 9 | ||
| 10 | pub fn main() void { | |
| 11 | testFnPtr(2, func, val); | |
| 12 | } |
test/standalone/issue_12706/test.c created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #include <stdarg.h> | |
| 2 | ||
| 3 | void testFnPtr(int n, ...) { | |
| 4 | va_list ap; | |
| 5 | va_start(ap, n); | |
| 6 | ||
| 7 | void (*fnPtr)(int) = va_arg(ap, void (*)(int)); | |
| 8 | int arg = va_arg(ap, int); | |
| 9 | fnPtr(arg); | |
| 10 | va_end(ap); | |
| 11 | } | |
| \ No newline at end of file |