Commit 21932a0ef2

LemonBoy <thatlemon@gmail.com>
2020-02-05 20:31:18
Fix edge case in cast between fn with varargs
* Prevent the next_param_index to become greater than the param_count one as it's expected by every other function. * Fix a typo in a error message. Closes #4381
1 parent b022db1
Changed files (3)
src/ir.cpp
@@ -11864,7 +11864,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
         }
         assert(wanted_type->data.fn.is_generic ||
                 wanted_type->data.fn.fn_type_id.next_param_index  == wanted_type->data.fn.fn_type_id.param_count);
-        for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.next_param_index; i += 1) {
+        for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.param_count; i += 1) {
             // note it's reversed for parameters
             FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
             FnTypeParamInfo *expected_param_info = &wanted_type->data.fn.fn_type_id.param_info[i];
@@ -30285,7 +30285,7 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La
         if (param_is_var_args) {
             if (fn_type_id.cc == CallingConventionC) {
                 fn_type_id.param_count = fn_type_id.next_param_index;
-                continue;
+                break;
             } else if (fn_type_id.cc == CallingConventionUnspecified) {
                 return get_generic_fn_type(ira->codegen, &fn_type_id);
             } else {
src/parser.cpp
@@ -806,7 +806,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
         if (param_decl->data.param_decl.is_var_args)
             res->data.fn_proto.is_var_args = true;
         if (i != params.length - 1 && res->data.fn_proto.is_var_args)
-            ast_error(pc, first, "Function prototype have varargs as a none last paramter.");
+            ast_error(pc, first, "Function prototype have varargs as a none last parameter.");
     }
     return res;
 }
test/compile_errors.zig
@@ -3,6 +3,17 @@ const builtin = @import("builtin");
 const Target = @import("std").Target;
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.addTest("type mismatch in C prototype with varargs",
+        \\const fn_ty = ?fn ([*c]u8, ...) callconv(.C) void;
+        \\extern fn fn_decl(fmt: [*:0]u8, ...) void;
+        \\
+        \\export fn main() void {
+        \\    const x: fn_ty = fn_decl;
+        \\}
+    , &[_][]const u8{
+        "tmp.zig:5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'",
+    });
+
     cases.addTest("dependency loop in top-level decl with @TypeInfo",
         \\export const foo = @typeInfo(@This());
     , &[_][]const u8{