Commit f8aecef670

Jacob Young <jacobly0@users.noreply.github.com>
2023-02-24 03:18:26
CBE: implement the future
Turns out f(...) will be supported one day.
1 parent 1f3d9f7
Changed files (2)
src
codegen
test
behavior
src/codegen/c.zig
@@ -6876,17 +6876,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
 
     const inst_ty = f.air.typeOfIndex(inst);
     const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
-
     const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
-    if (param_len == 0)
-        return f.fail("CBE: C requires at least one runtime argument for varargs functions", .{});
 
     const writer = f.object.writer();
     const local = try f.allocLocal(inst, inst_ty);
     try writer.writeAll("va_start(*(va_list *)&");
     try f.writeCValue(writer, local, .Other);
-    try writer.writeAll(", ");
-    try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
+    if (param_len > 0) {
+        try writer.writeAll(", ");
+        try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
+    }
     try writer.writeAll(");\n");
     return local;
 }
test/behavior/var_args.zig
@@ -111,6 +111,12 @@ test "simple variadic function" {
             return @cVaArg(&ap, c_int);
         }
 
+        fn compatible(_: c_int, ...) callconv(.C) c_int {
+            var ap = @cVaStart();
+            defer @cVaEnd(&ap);
+            return @cVaArg(&ap, c_int);
+        }
+
         fn add(count: c_int, ...) callconv(.C) c_int {
             var ap = @cVaStart();
             defer @cVaEnd(&ap);
@@ -123,10 +129,13 @@ test "simple variadic function" {
         }
     };
 
-    if (builtin.zig_backend != .stage2_c) { // C doesn't support varargs without a preceding runtime arg.
+    if (builtin.zig_backend != .stage2_c) {
+        // pre C23 doesn't support varargs without a preceding runtime arg.
         try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
         try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
     }
+    try std.testing.expectEqual(@as(c_int, 0), S.compatible(undefined, @as(c_int, 0)));
+    try std.testing.expectEqual(@as(c_int, 1024), S.compatible(undefined, @as(c_int, 1024)));
     try std.testing.expectEqual(@as(c_int, 0), S.add(0));
     try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
     try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));