diff --git a/src/Sema.zig b/src/Sema.zig index bfefcef8e2..0066f1ad87 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6628,7 +6628,7 @@ fn checkCallArgumentCount( const fn_params_len = func_ty_info.param_types.len; const args_len = total_args - @intFromBool(member_fn); if (func_ty_info.is_var_args) { - assert(func_ty_info.cc == .C); + assert(callConvSupportsVarArgs(func_ty_info.cc)); if (total_args >= fn_params_len) return func_ty; } else if (fn_params_len == total_args) { return func_ty; @@ -8917,6 +8917,41 @@ fn handleExternLibName( return sema.gpa.dupeZ(u8, lib_name); } +/// These are calling conventions that are confirmed to work with variadic functions. +/// Any calling conventions not included here are either not yet verified to work with variadic +/// functions or there are no more other calling conventions that support variadic functions. +const calling_conventions_supporting_var_args = [_]std.builtin.CallingConvention{ + .C, +}; +fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention) bool { + return for (calling_conventions_supporting_var_args) |supported_cc| { + if (cc == supported_cc) return true; + } else false; +} +fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention) CompileError!void { + const CallingConventionsSupportingVarArgsList = struct { + pub fn format(_: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = options; + for (calling_conventions_supporting_var_args, 0..) |cc_inner, i| { + if (i != 0) + try writer.writeAll(", "); + try writer.print("'.{s}'", .{@tagName(cc_inner)}); + } + } + }; + + if (!callConvSupportsVarArgs(cc)) { + const msg = msg: { + const msg = try sema.errMsg(block, src, "variadic function does not support '.{s}' calling convention", .{@tagName(cc)}); + errdefer msg.destroy(sema.gpa); + try sema.errNote(block, src, msg, "supported calling conventions: {}", .{CallingConventionsSupportingVarArgsList{}}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(msg); + } +} + const FuncLinkSection = union(enum) { generic, default, @@ -8963,9 +8998,7 @@ fn funcCommon( if (is_generic) { return sema.fail(block, func_src, "generic function cannot be variadic", .{}); } - if (cc.? != .C) { - return sema.fail(block, cc_src, "variadic function must have 'C' calling convention", .{}); - } + try sema.checkCallConvSupportsVarArgs(block, cc_src, cc.?); } var destroy_fn_on_error = false; @@ -20325,8 +20358,8 @@ fn zirReify( const is_var_args = is_var_args_val.toBool(); const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val); - if (is_var_args and cc != .C) { - return sema.fail(block, src, "varargs functions must have C calling convention", .{}); + if (is_var_args) { + try sema.checkCallConvSupportsVarArgs(block, src, cc); } const alignment = alignment: { diff --git a/test/cases/compile_errors/invalid_variadic_function.zig b/test/cases/compile_errors/invalid_variadic_function.zig index 7652cb329a..d0b6d2c8f5 100644 --- a/test/cases/compile_errors/invalid_variadic_function.zig +++ b/test/cases/compile_errors/invalid_variadic_function.zig @@ -1,5 +1,6 @@ fn foo(...) void {} fn bar(a: anytype, ...) callconv(a) void {} +inline fn foo2(...) void {} comptime { _ = foo; @@ -7,10 +8,16 @@ comptime { comptime { _ = bar; } +comptime { + _ = foo2; +} // error // backend=stage2 // target=native // -// :1:1: error: variadic function must have 'C' calling convention +// :1:1: error: variadic function does not support '.Unspecified' calling convention +// :1:1: note: supported calling conventions: '.C' // :2:1: error: generic function cannot be variadic +// :1:1: error: variadic function does not support '.Inline' calling convention +// :1:1: note: supported calling conventions: '.C' diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig index a341435b36..678fbe3ed7 100644 --- a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig @@ -16,4 +16,5 @@ comptime { // backend=stage2 // target=native // -// :1:13: error: varargs functions must have C calling convention +// :1:13: error: variadic function does not support '.Unspecified' calling convention +// :1:13: note: supported calling conventions: '.C'