Add the noinline keyword for function declarations

This commit is contained in:
LemonBoy 2019-09-05 12:22:02 +02:00 committed by Andrew Kelley
parent a7fd14096c
commit fabf45f5fc
11 changed files with 46 additions and 18 deletions

View File

@ -786,6 +786,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.Keyword_for, .Keyword_for,
.Keyword_if, .Keyword_if,
.Keyword_inline, .Keyword_inline,
.Keyword_noinline,
.Keyword_nakedcc, .Keyword_nakedcc,
.Keyword_noalias, .Keyword_noalias,
.Keyword_or, .Keyword_or,

View File

@ -603,6 +603,12 @@ enum CallingConvention {
CallingConventionAsync, CallingConventionAsync,
}; };
enum FnInline {
FnInlineAuto,
FnInlineAlways,
FnInlineNever,
};
struct AstNodeFnProto { struct AstNodeFnProto {
VisibMod visib_mod; VisibMod visib_mod;
Buf *name; Buf *name;
@ -612,7 +618,7 @@ struct AstNodeFnProto {
bool is_var_args; bool is_var_args;
bool is_extern; bool is_extern;
bool is_export; bool is_export;
bool is_inline; FnInline fn_inline;
CallingConvention cc; CallingConvention cc;
AstNode *fn_def_node; AstNode *fn_def_node;
// populated if this is an extern declaration // populated if this is an extern declaration
@ -1453,12 +1459,6 @@ enum FnAnalState {
FnAnalStateInvalid, FnAnalStateInvalid,
}; };
enum FnInline {
FnInlineAuto,
FnInlineAlways,
FnInlineNever,
};
struct GlobalExport { struct GlobalExport {
Buf name; Buf name;
GlobalLinkageId linkage; GlobalLinkageId linkage;

View File

@ -3066,8 +3066,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
assert(proto_node->type == NodeTypeFnProto); assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline);
ZigFn *fn_entry = create_fn_raw(g, inline_value);
fn_entry->proto_node = proto_node; fn_entry->proto_node = proto_node;
fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr :

View File

@ -124,8 +124,13 @@ static const char *export_string(bool is_export) {
// zig_unreachable(); // zig_unreachable();
//} //}
static const char *inline_string(bool is_inline) { static const char *inline_string(FnInline fn_inline) {
return is_inline ? "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) { 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 *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 *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *export_str = export_string(node->data.fn_proto.is_export); 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); fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);
if (node->data.fn_proto.name != nullptr) { if (node->data.fn_proto.name != nullptr) {
print_symbol(ar, node->data.fn_proto.name); print_symbol(ar, node->data.fn_proto.name);

View File

@ -578,7 +578,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) {
} }
// TopLevelDecl // 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_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl
// / KEYWORD_use Expr SEMICOLON // / KEYWORD_use Expr SEMICOLON
static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { 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); first = eat_token_if(pc, TokenIdKeywordExtern);
if (first == nullptr) if (first == nullptr)
first = eat_token_if(pc, TokenIdKeywordInline); first = eat_token_if(pc, TokenIdKeywordInline);
if (first == nullptr)
first = eat_token_if(pc, TokenIdKeywordNoInline);
if (first != nullptr) { if (first != nullptr) {
Token *lib_name = nullptr; Token *lib_name = nullptr;
if (first->id == TokenIdKeywordExtern) if (first->id == TokenIdKeywordExtern)
lib_name = eat_token_if(pc, TokenIdStringLiteral); 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); Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
AstNode *var_decl = ast_parse_var_decl(pc); AstNode *var_decl = ast_parse_var_decl(pc);
if (var_decl != nullptr) { 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.visib_mod = visib_mod;
fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; 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_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); fn_proto->data.fn_proto.lib_name = token_buf(lib_name);
AstNode *res = fn_proto; AstNode *res = fn_proto;
if (body != nullptr) { if (body != nullptr) {
res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto);

View File

@ -130,6 +130,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"for", TokenIdKeywordFor}, {"for", TokenIdKeywordFor},
{"if", TokenIdKeywordIf}, {"if", TokenIdKeywordIf},
{"inline", TokenIdKeywordInline}, {"inline", TokenIdKeywordInline},
{"noinline", TokenIdKeywordNoInline},
{"nakedcc", TokenIdKeywordNakedCC}, {"nakedcc", TokenIdKeywordNakedCC},
{"noalias", TokenIdKeywordNoAlias}, {"noalias", TokenIdKeywordNoAlias},
{"null", TokenIdKeywordNull}, {"null", TokenIdKeywordNull},
@ -1551,6 +1552,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordFor: return "for"; case TokenIdKeywordFor: return "for";
case TokenIdKeywordIf: return "if"; case TokenIdKeywordIf: return "if";
case TokenIdKeywordInline: return "inline"; case TokenIdKeywordInline: return "inline";
case TokenIdKeywordNoInline: return "noinline";
case TokenIdKeywordNakedCC: return "nakedcc"; case TokenIdKeywordNakedCC: return "nakedcc";
case TokenIdKeywordNoAlias: return "noalias"; case TokenIdKeywordNoAlias: return "noalias";
case TokenIdKeywordNull: return "null"; case TokenIdKeywordNull: return "null";

View File

@ -74,6 +74,7 @@ enum TokenId {
TokenIdKeywordFor, TokenIdKeywordFor,
TokenIdKeywordIf, TokenIdKeywordIf,
TokenIdKeywordInline, TokenIdKeywordInline,
TokenIdKeywordNoInline,
TokenIdKeywordLinkSection, TokenIdKeywordLinkSection,
TokenIdKeywordNakedCC, TokenIdKeywordNakedCC,
TokenIdKeywordNoAlias, TokenIdKeywordNoAlias,

View File

@ -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); AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);
fn_proto->data.fn_proto.visib_mod = c->visib_mod; fn_proto->data.fn_proto.visib_mod = c->visib_mod;
fn_proto->data.fn_proto.name = fn_name; 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_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; fn_def->data.fn_def.fn_proto = fn_proto;

View File

@ -201,7 +201,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*
} }
/// TopLevelDecl /// 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_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl
/// / KEYWORD_usingnamespace Expr SEMICOLON /// / KEYWORD_usingnamespace Expr SEMICOLON
fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { 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; break :blk token;
} }
if (eatToken(it, .Keyword_inline)) |token| break :blk token; if (eatToken(it, .Keyword_inline)) |token| break :blk token;
if (eatToken(it, .Keyword_noinline)) |token| break :blk token;
break :blk null; break :blk null;
}; };
@ -232,7 +233,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
} }
if (extern_export_inline_token) |token| { 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); putBackToken(it, token);
return null; return null;
} }

View File

@ -1677,14 +1677,17 @@ test "zig fmt: functions" {
\\extern "c" fn puts(s: *const u8) c_int; \\extern "c" fn puts(s: *const u8) c_int;
\\export fn puts(s: *const u8) c_int; \\export fn puts(s: *const u8) c_int;
\\inline 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 fn puts(s: *const u8) c_int;
\\pub extern "c" 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 export fn puts(s: *const u8) c_int;
\\pub inline 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 fn puts(s: *const u8) align(2 + 2) c_int;
\\pub extern "c" 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 export fn puts(s: *const u8) align(2 + 2) c_int;
\\pub inline 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;
\\ \\
); );
} }

View File

@ -36,6 +36,7 @@ pub const Token = struct {
Keyword{ .bytes = "for", .id = Id.Keyword_for }, Keyword{ .bytes = "for", .id = Id.Keyword_for },
Keyword{ .bytes = "if", .id = Id.Keyword_if }, Keyword{ .bytes = "if", .id = Id.Keyword_if },
Keyword{ .bytes = "inline", .id = Id.Keyword_inline }, Keyword{ .bytes = "inline", .id = Id.Keyword_inline },
Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline },
Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc }, Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc },
Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias }, Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias },
Keyword{ .bytes = "null", .id = Id.Keyword_null }, Keyword{ .bytes = "null", .id = Id.Keyword_null },
@ -166,6 +167,7 @@ pub const Token = struct {
Keyword_for, Keyword_for,
Keyword_if, Keyword_if,
Keyword_inline, Keyword_inline,
Keyword_noinline,
Keyword_nakedcc, Keyword_nakedcc,
Keyword_noalias, Keyword_noalias,
Keyword_null, Keyword_null,