Commit ff0a15bb7a

Matthew Borkowski <matthew.h.borkowski@gmail.com>
2021-05-30 08:24:44
parse.zig: make `parseParamDeclList` check for nonfinal varargs
1 parent 8bf04c3
Changed files (3)
lib/std/zig/ast.zig
@@ -297,6 +297,9 @@ pub const Tree = struct {
             .unattached_doc_comment => {
                 return stream.writeAll("unattached documentation comment");
             },
+            .varargs_nonfinal => {
+                return stream.writeAll("function prototype has parameter after varargs");
+            },
 
             .expected_token => {
                 const found_tag = token_tags[parse_error.token];
@@ -2414,6 +2417,7 @@ pub const Error = struct {
         invalid_token,
         same_line_doc_comment,
         unattached_doc_comment,
+        varargs_nonfinal,
 
         /// `expected_tag` is populated.
         expected_token,
lib/std/zig/parse.zig
@@ -3553,11 +3553,15 @@ const Parser = struct {
         _ = try p.expectToken(.l_paren);
         const scratch_top = p.scratch.items.len;
         defer p.scratch.shrinkRetainingCapacity(scratch_top);
+        var varargs: union(enum){ none, seen, nonfinal: TokenIndex } = .none;
         while (true) {
             if (p.eatToken(.r_paren)) |_| break;
+            if (varargs == .seen) varargs = .{ .nonfinal = p.tok_i };
             const param = try p.expectParamDecl();
             if (param != 0) {
                 try p.scratch.append(p.gpa, param);
+            } else if (p.token_tags[p.tok_i - 1] == .ellipsis3) {
+                if (varargs == .none) varargs = .seen;
             }
             switch (p.token_tags[p.nextToken()]) {
                 .comma => {},
@@ -3574,6 +3578,9 @@ const Parser = struct {
                 },
             }
         }
+        if (varargs == .nonfinal) {
+            try p.warnMsg(.{ .tag = .varargs_nonfinal, .token = varargs.nonfinal });
+        }
         const params = p.scratch.items[scratch_top..];
         return switch (params.len) {
             0 => SmallSpan { .zero_or_one = 0 },
lib/std/zig/parser_test.zig
@@ -5171,6 +5171,18 @@ test "recovery: missing while rbrace" {
     });
 }
 
+test "recovery: nonfinal varargs" {
+    try testError(
+        \\extern fn f(a: u32, ..., b: u32) void;
+        \\extern fn g(a: u32, ..., b: anytype) void;
+        \\extern fn h(a: u32, ..., ...) void;
+    , &[_]Error{
+        .varargs_nonfinal,
+        .varargs_nonfinal,
+        .varargs_nonfinal,
+    });
+}
+
 const std = @import("std");
 const mem = std.mem;
 const print = std.debug.print;