authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-05-20 14:51:11+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-05-20 14:54:44+02:00
log569525f03e17ba32204733108a950a5170662299
tree7a6d4daf267525bc0ca2b8fc8796c989750889d7
parent9910bfa6d887cd28dba3ac99ac0f0acf8d6e5056
signaturelock-open Commit is signed but in an unrecognized format.

stage1: support inline keyword on function decls

This is an alternative to callconv(.Inline). Using an inline keyword as well as an explicit callconv() is a compile error.

4 files changed, 40 insertions(+), 8 deletions(-)

src/stage1/all_types.hpp+11-1
...@@ -714,6 +714,12 @@ enum NodeType {...@@ -714,6 +714,12 @@ enum NodeType {
714 NodeTypeAnyTypeField,714 NodeTypeAnyTypeField,
715};715};
716716
717enum FnInline {
718 FnInlineAuto,
719 FnInlineAlways,
720 FnInlineNever,
721};
722
717struct AstNodeFnProto {723struct AstNodeFnProto {
718 Buf *name;724 Buf *name;
719 ZigList<AstNode *> params;725 ZigList<AstNode *> params;
...@@ -729,12 +735,16 @@ struct AstNodeFnProto {...@@ -729,12 +735,16 @@ struct AstNodeFnProto {
729 AstNode *callconv_expr;735 AstNode *callconv_expr;
730 Buf doc_comments;736 Buf doc_comments;
731737
738 // This is set based only on the existence of a noinline or inline keyword.
739 // This is then resolved to an is_noinline bool and (potentially .Inline)
740 // calling convention in resolve_decl_fn() in analyze.cpp.
741 FnInline fn_inline;
742
732 VisibMod visib_mod;743 VisibMod visib_mod;
733 bool auto_err_set;744 bool auto_err_set;
734 bool is_var_args;745 bool is_var_args;
735 bool is_extern;746 bool is_extern;
736 bool is_export;747 bool is_export;
737 bool is_noinline;
738};748};
739749
740struct AstNodeFnDef {750struct AstNodeFnDef {
src/stage1/analyze.cpp+7-1
...@@ -1638,6 +1638,9 @@ CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) {...@@ -1638,6 +1638,9 @@ CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) {
1638 if (fn_proto->is_extern || fn_proto->is_export)1638 if (fn_proto->is_extern || fn_proto->is_export)
1639 return CallingConventionC;1639 return CallingConventionC;
16401640
1641 if (fn_proto->fn_inline == FnInlineAlways)
1642 return CallingConventionInline;
1643
1641 return CallingConventionUnspecified;1644 return CallingConventionUnspecified;
1642}1645}
16431646
...@@ -3649,7 +3652,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {...@@ -3649,7 +3652,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
3649 assert(proto_node->type == NodeTypeFnProto);3652 assert(proto_node->type == NodeTypeFnProto);
3650 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;3653 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
36513654
3652 ZigFn *fn_entry = create_fn_raw(g, fn_proto->is_noinline);3655 ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline == FnInlineNever);
36533656
3654 fn_entry->proto_node = proto_node;3657 fn_entry->proto_node = proto_node;
3655 fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr :3658 fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr :
...@@ -3742,6 +3745,9 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -3742,6 +3745,9 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
37423745
3743 CallingConvention cc;3746 CallingConvention cc;
3744 if (fn_proto->callconv_expr != nullptr) {3747 if (fn_proto->callconv_expr != nullptr) {
3748 if (fn_proto->fn_inline == FnInlineAlways) {
3749 add_node_error(g, fn_proto->callconv_expr, buf_sprintf("explicit callconv incompatible with inline keyword"));
3750 }
3745 ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention");3751 ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention");
37463752
3747 ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr,3753 ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr,
src/stage1/ast_render.cpp+8-3
...@@ -123,8 +123,13 @@ static const char *export_string(bool is_export) {...@@ -123,8 +123,13 @@ static const char *export_string(bool is_export) {
123// zig_unreachable();123// zig_unreachable();
124//}124//}
125125
126static const char *inline_string(bool is_inline) {126static const char *inline_string(FnInline fn_inline) {
127 return is_inline ? "inline" : "";127 switch (fn_inline) {
128 case FnInlineAlways: return "inline ";
129 case FnInlineNever: return "noinline ";
130 case FnInlineAuto: return "";
131 }
132 zig_unreachable();
128}133}
129134
130static const char *const_or_var_string(bool is_const) {135static const char *const_or_var_string(bool is_const) {
...@@ -441,7 +446,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -441,7 +446,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
441 const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);446 const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
442 const char *extern_str = extern_string(node->data.fn_proto.is_extern);447 const char *extern_str = extern_string(node->data.fn_proto.is_extern);
443 const char *export_str = export_string(node->data.fn_proto.is_export);448 const char *export_str = export_string(node->data.fn_proto.is_export);
444 const char *inline_str = inline_string(node->data.fn_proto.is_noinline);449 const char *inline_str = inline_string(node->data.fn_proto.fn_inline);
445 fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);450 fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);
446 if (node->data.fn_proto.name != nullptr) {451 if (node->data.fn_proto.name != nullptr) {
447 print_symbol(ar, node->data.fn_proto.name);452 print_symbol(ar, node->data.fn_proto.name);
src/stage1/parser.cpp+14-3
...@@ -693,6 +693,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B...@@ -693,6 +693,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
693 Token *first = eat_token_if(pc, TokenIdKeywordExport);693 Token *first = eat_token_if(pc, TokenIdKeywordExport);
694 if (first == nullptr)694 if (first == nullptr)
695 first = eat_token_if(pc, TokenIdKeywordExtern);695 first = eat_token_if(pc, TokenIdKeywordExtern);
696 if (first == nullptr)
697 first = eat_token_if(pc, TokenIdKeywordInline);
696 if (first == nullptr)698 if (first == nullptr)
697 first = eat_token_if(pc, TokenIdKeywordNoInline);699 first = eat_token_if(pc, TokenIdKeywordNoInline);
698 if (first != nullptr) {700 if (first != nullptr) {
...@@ -700,7 +702,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B...@@ -700,7 +702,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
700 if (first->id == TokenIdKeywordExtern)702 if (first->id == TokenIdKeywordExtern)
701 lib_name = eat_token_if(pc, TokenIdStringLiteral);703 lib_name = eat_token_if(pc, TokenIdStringLiteral);
702704
703 if (first->id != TokenIdKeywordNoInline) {705 if (first->id != TokenIdKeywordNoInline && first->id != TokenIdKeywordInline) {
704 Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);706 Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
705 AstNode *var_decl = ast_parse_var_decl(pc);707 AstNode *var_decl = ast_parse_var_decl(pc);
706 if (var_decl != nullptr) {708 if (var_decl != nullptr) {
...@@ -737,8 +739,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B...@@ -737,8 +739,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
737 if (!fn_proto->data.fn_proto.is_extern)739 if (!fn_proto->data.fn_proto.is_extern)
738 fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern;740 fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern;
739 fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport;741 fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport;
740 if (first->id == TokenIdKeywordNoInline)742 switch (first->id) {
741 fn_proto->data.fn_proto.is_noinline = true;743 case TokenIdKeywordInline:
744 fn_proto->data.fn_proto.fn_inline = FnInlineAlways;
745 break;
746 case TokenIdKeywordNoInline:
747 fn_proto->data.fn_proto.fn_inline = FnInlineNever;
748 break;
749 default:
750 fn_proto->data.fn_proto.fn_inline = FnInlineAuto;
751 break;
752 }
742 fn_proto->data.fn_proto.lib_name = token_buf(lib_name);753 fn_proto->data.fn_proto.lib_name = token_buf(lib_name);
743754
744 AstNode *res = fn_proto;755 AstNode *res = fn_proto;