diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 4ee3a45221..02672fbfd1 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { token_tags[parse_error.token].symbol(), }); }, + .extern_fn_body => { + return stream.writeAll("extern functions have no body"); + }, .extra_addrspace_qualifier => { return stream.writeAll("extra addrspace qualifier"); }, @@ -2447,6 +2450,7 @@ pub const Error = struct { expected_var_decl_or_fn, expected_loop_payload, expected_container, + extern_fn_body, extra_addrspace_qualifier, extra_align_qualifier, extra_allowzero_qualifier, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index a449f6ae0f..28a0c1a196 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -532,11 +532,13 @@ const Parser = struct { /// / KEYWORD_usingnamespace Expr SEMICOLON fn expectTopLevelDecl(p: *Parser) !Node.Index { const extern_export_inline_token = p.nextToken(); + var is_extern: bool = false; var expect_fn: bool = false; var expect_var_or_fn: bool = false; switch (p.token_tags[extern_export_inline_token]) { .keyword_extern => { _ = p.eatToken(.string_literal); + is_extern = true; expect_var_or_fn = true; }, .keyword_export => expect_var_or_fn = true, @@ -554,6 +556,10 @@ const Parser = struct { const fn_decl_index = try p.reserveNode(); const body_block = try p.parseBlock(); assert(body_block != 0); + if (is_extern) { + try p.warnMsg(.{ .tag = .extern_fn_body, .token = extern_export_inline_token }); + return null_node; + } return p.setNode(fn_decl_index, .{ .tag = .fn_decl, .main_token = p.nodes.items(.main_token)[fn_proto], diff --git a/src/AstGen.zig b/src/AstGen.zig index 3fd3da6bb6..509880ec95 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3147,7 +3147,7 @@ fn fnDecl( break :param indexToRef(param_inst); }; - if (param_name == 0) continue; + if (param_name == 0 or is_extern) continue; const sub_scope = try astgen.arena.create(Scope.LocalVal); sub_scope.* = .{