Commit f81529fab1

xackus <14938807+xackus@users.noreply.github.com>
2019-12-20 20:58:29
stage2 parser: fix segfault on extern block
1 parent e06a6b9
Changed files (2)
lib/std/zig/parse.zig
@@ -303,7 +303,17 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
 fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
     const cc = parseFnCC(arena, it, tree);
     const fn_token = eatToken(it, .Keyword_fn) orelse {
-        if (cc == null) return null else return error.ParseError;
+        if (cc) |fnCC| {
+            if (fnCC == .Extern) {
+                putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl
+            } else {
+                try tree.errors.push(AstError{
+                    .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn },
+                });
+                return error.ParseError;
+            }
+        }
+        return null;
     };
     const name_token = eatToken(it, .Identifier);
     const lparen = try expectToken(it, tree, .LParen);
lib/std/zig/parser_test.zig
@@ -2714,6 +2714,13 @@ test "zig fmt: top level doc comments" {
     );
 }
 
+test "zig fmt: extern without container keyword returns error" {
+    try testError(
+        \\const container = extern {};
+        \\
+    );
+}
+
 const std = @import("std");
 const mem = std.mem;
 const warn = std.debug.warn;
@@ -2820,3 +2827,11 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
 fn testCanonical(source: []const u8) !void {
     return testTransform(source, source);
 }
+
+fn testError(source: []const u8) !void {
+    var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
+    const tree = try std.zig.parse(&fixed_allocator.allocator, source);
+    defer tree.deinit();
+
+    std.testing.expect(tree.errors.len != 0);
+}