diff --git a/doc/docgen.zig b/doc/docgen.zig index eee4c45369..6ce5902dcc 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -786,6 +786,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok .Keyword_for, .Keyword_if, .Keyword_inline, + .Keyword_noinline, .Keyword_nakedcc, .Keyword_noalias, .Keyword_or, diff --git a/src/all_types.hpp b/src/all_types.hpp index 03559ccf12..f1ecfe2be7 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -603,6 +603,12 @@ enum CallingConvention { CallingConventionAsync, }; +enum FnInline { + FnInlineAuto, + FnInlineAlways, + FnInlineNever, +}; + struct AstNodeFnProto { VisibMod visib_mod; Buf *name; @@ -612,7 +618,7 @@ struct AstNodeFnProto { bool is_var_args; bool is_extern; bool is_export; - bool is_inline; + FnInline fn_inline; CallingConvention cc; AstNode *fn_def_node; // populated if this is an extern declaration @@ -1453,12 +1459,6 @@ enum FnAnalState { FnAnalStateInvalid, }; -enum FnInline { - FnInlineAuto, - FnInlineAlways, - FnInlineNever, -}; - struct GlobalExport { Buf name; GlobalLinkageId linkage; diff --git a/src/analyze.cpp b/src/analyze.cpp index e1d6b59ddf..87758df3e1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3066,8 +3066,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; - ZigFn *fn_entry = create_fn_raw(g, inline_value); + ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline); fn_entry->proto_node = proto_node; fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 54a659f7b1..fedd46a48b 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -124,8 +124,13 @@ static const char *export_string(bool is_export) { // zig_unreachable(); //} -static const char *inline_string(bool is_inline) { - return is_inline ? "inline " : ""; +static const char *inline_string(FnInline fn_inline) { + switch (fn_inline) { + case FnInlineAlways: return "inline "; + case FnInlineNever: return "noinline "; + case FnInlineAuto: return ""; + } + zig_unreachable(); } static const char *const_or_var_string(bool is_const) { @@ -436,7 +441,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *export_str = export_string(node->data.fn_proto.is_export); - const char *inline_str = inline_string(node->data.fn_proto.is_inline); + const char *inline_str = inline_string(node->data.fn_proto.fn_inline); fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { print_symbol(ar, node->data.fn_proto.name); diff --git a/src/parser.cpp b/src/parser.cpp index 21bbc4d246..ba8757e4ae 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -578,7 +578,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { } // TopLevelDecl -// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) +// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) // / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl // / KEYWORD_use Expr SEMICOLON static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { @@ -587,12 +587,14 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { first = eat_token_if(pc, TokenIdKeywordExtern); if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordInline); + if (first == nullptr) + first = eat_token_if(pc, TokenIdKeywordNoInline); if (first != nullptr) { Token *lib_name = nullptr; if (first->id == TokenIdKeywordExtern) lib_name = eat_token_if(pc, TokenIdStringLiteral); - if (first->id != TokenIdKeywordInline) { + if (first->id != TokenIdKeywordInline && first->id != TokenIdKeywordNoInline) { Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { @@ -623,8 +625,19 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { fn_proto->data.fn_proto.visib_mod = visib_mod; fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; - fn_proto->data.fn_proto.is_inline = first->id == TokenIdKeywordInline; + switch (first->id) { + case TokenIdKeywordInline: + fn_proto->data.fn_proto.fn_inline = FnInlineAlways; + break; + case TokenIdKeywordNoInline: + fn_proto->data.fn_proto.fn_inline = FnInlineNever; + break; + default: + fn_proto->data.fn_proto.fn_inline = FnInlineAuto; + break; + } fn_proto->data.fn_proto.lib_name = token_buf(lib_name); + AstNode *res = fn_proto; if (body != nullptr) { res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 9c9effcb10..8ef320331a 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -130,6 +130,7 @@ static const struct ZigKeyword zig_keywords[] = { {"for", TokenIdKeywordFor}, {"if", TokenIdKeywordIf}, {"inline", TokenIdKeywordInline}, + {"noinline", TokenIdKeywordNoInline}, {"nakedcc", TokenIdKeywordNakedCC}, {"noalias", TokenIdKeywordNoAlias}, {"null", TokenIdKeywordNull}, @@ -1551,6 +1552,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordFor: return "for"; case TokenIdKeywordIf: return "if"; case TokenIdKeywordInline: return "inline"; + case TokenIdKeywordNoInline: return "noinline"; case TokenIdKeywordNakedCC: return "nakedcc"; case TokenIdKeywordNoAlias: return "noalias"; case TokenIdKeywordNull: return "null"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index ce62f5dc87..70d828b39d 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -74,6 +74,7 @@ enum TokenId { TokenIdKeywordFor, TokenIdKeywordIf, TokenIdKeywordInline, + TokenIdKeywordNoInline, TokenIdKeywordLinkSection, TokenIdKeywordNakedCC, TokenIdKeywordNoAlias, diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 69c70958e5..eb59110783 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -432,7 +432,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); fn_proto->data.fn_proto.visib_mod = c->visib_mod; fn_proto->data.fn_proto.name = fn_name; - fn_proto->data.fn_proto.is_inline = true; + fn_proto->data.fn_proto.fn_inline = FnInlineAlways; fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? fn_def->data.fn_def.fn_proto = fn_proto; diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 0511b6dce0..4ffcdc9622 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -201,7 +201,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* } /// TopLevelDecl -/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) +/// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) /// / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl /// / KEYWORD_usingnamespace Expr SEMICOLON fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { @@ -213,6 +213,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node break :blk token; } if (eatToken(it, .Keyword_inline)) |token| break :blk token; + if (eatToken(it, .Keyword_noinline)) |token| break :blk token; break :blk null; }; @@ -232,7 +233,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (extern_export_inline_token) |token| { - if (tree.tokens.at(token).id == .Keyword_inline) { + if (tree.tokens.at(token).id == .Keyword_inline or + tree.tokens.at(token).id == .Keyword_noinline) { putBackToken(it, token); return null; } diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 821ead9db5..c1fa399f09 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1677,14 +1677,17 @@ test "zig fmt: functions" { \\extern "c" fn puts(s: *const u8) c_int; \\export fn puts(s: *const u8) c_int; \\inline fn puts(s: *const u8) c_int; + \\noinline fn puts(s: *const u8) c_int; \\pub extern fn puts(s: *const u8) c_int; \\pub extern "c" fn puts(s: *const u8) c_int; \\pub export fn puts(s: *const u8) c_int; \\pub inline fn puts(s: *const u8) c_int; + \\pub noinline fn puts(s: *const u8) c_int; \\pub extern fn puts(s: *const u8) align(2 + 2) c_int; \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int; \\pub export fn puts(s: *const u8) align(2 + 2) c_int; \\pub inline fn puts(s: *const u8) align(2 + 2) c_int; + \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int; \\ ); } diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 4d4ceb07db..204121f64c 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -36,6 +36,7 @@ pub const Token = struct { Keyword{ .bytes = "for", .id = Id.Keyword_for }, Keyword{ .bytes = "if", .id = Id.Keyword_if }, Keyword{ .bytes = "inline", .id = Id.Keyword_inline }, + Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline }, Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc }, Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias }, Keyword{ .bytes = "null", .id = Id.Keyword_null }, @@ -166,6 +167,7 @@ pub const Token = struct { Keyword_for, Keyword_if, Keyword_inline, + Keyword_noinline, Keyword_nakedcc, Keyword_noalias, Keyword_null,