| 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,16 +24075,40 @@ fn coerceVarArgParam( |
| 24075 | inst: Air.Inst.Ref, | 24075 | inst: Air.Inst.Ref, |
| 24076 | inst_src: LazySrcLoc, | 24076 | inst_src: LazySrcLoc, |
| 24077 | ) !Air.Inst.Ref { | 24077 | ) !Air.Inst.Ref { |
| 24078 | const inst_ty = sema.typeOf(inst); | ||
| 24079 | if (block.is_typeof) return inst; | 24078 | if (block.is_typeof) return inst; |
| 24080 | 24079 | ||
| 24081 | switch (inst_ty.zigTypeTag()) { | 24080 | const coerced = switch (sema.typeOf(inst).zigTypeTag()) { |
| 24082 | // TODO consider casting to c_int/f64 if they fit | 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", .{}), | 24082 | .ComptimeInt, .ComptimeFloat => return sema.fail( |
| 24084 | else => {}, | 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. | 24111 | return coerced; |
| 24087 | return inst; | ||
| 24088 | } | 24112 | } |
| 24089 | 24113 | ||
| 24090 | // TODO migrate callsites to use storePtr2 instead. | 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,6 +66,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 66 | if (builtin.os.tag == .linux) { | 66 | if (builtin.os.tag == .linux) { |
| 67 | cases.addBuildFile("test/standalone/pie/build.zig", .{}); | 67 | cases.addBuildFile("test/standalone/pie/build.zig", .{}); |
| 68 | } | 68 | } |
| 69 | cases.addBuildFile("test/standalone/issue_12706/build.zig", .{}); | ||
| 69 | 70 | ||
| 70 | // Ensure the development tools are buildable. | 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 | |||