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 {
714714 NodeTypeAnyTypeField,
715715};
716716
717enum FnInline {
718 FnInlineAuto,
719 FnInlineAlways,
720 FnInlineNever,
721};
722
717723struct AstNodeFnProto {
718724 Buf *name;
719725 ZigList<AstNode *> params;
......@@ -729,12 +735,16 @@ struct AstNodeFnProto {
729735 AstNode *callconv_expr;
730736 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
732743 VisibMod visib_mod;
733744 bool auto_err_set;
734745 bool is_var_args;
735746 bool is_extern;
736747 bool is_export;
737 bool is_noinline;
738748};
739749
740750struct AstNodeFnDef {
src/stage1/analyze.cpp+7-1
......@@ -1638,6 +1638,9 @@ CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) {
16381638 if (fn_proto->is_extern || fn_proto->is_export)
16391639 return CallingConventionC;
16401640
1641 if (fn_proto->fn_inline == FnInlineAlways)
1642 return CallingConventionInline;
1643
16411644 return CallingConventionUnspecified;
16421645}
16431646
......@@ -3649,7 +3652,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) {
36493652 assert(proto_node->type == NodeTypeFnProto);
36503653 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
36543657 fn_entry->proto_node = proto_node;
36553658 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) {
37423745
37433746 CallingConvention cc;
37443747 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 }
37453751 ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention");
37463752
37473753 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) {
123123// zig_unreachable();
124124//}
125125
126static const char *inline_string(bool is_inline) {
127 return is_inline ? "inline" : "";
126static const char *inline_string(FnInline fn_inline) {
127 switch (fn_inline) {
128 case FnInlineAlways: return "inline ";
129 case FnInlineNever: return "noinline ";
130 case FnInlineAuto: return "";
131 }
132 zig_unreachable();
128133}
129134
130135static const char *const_or_var_string(bool is_const) {
......@@ -441,7 +446,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
441446 const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
442447 const char *extern_str = extern_string(node->data.fn_proto.is_extern);
443448 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);
445450 fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);
446451 if (node->data.fn_proto.name != nullptr) {
447452 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
693693 Token *first = eat_token_if(pc, TokenIdKeywordExport);
694694 if (first == nullptr)
695695 first = eat_token_if(pc, TokenIdKeywordExtern);
696 if (first == nullptr)
697 first = eat_token_if(pc, TokenIdKeywordInline);
696698 if (first == nullptr)
697699 first = eat_token_if(pc, TokenIdKeywordNoInline);
698700 if (first != nullptr) {
......@@ -700,7 +702,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
700702 if (first->id == TokenIdKeywordExtern)
701703 lib_name = eat_token_if(pc, TokenIdStringLiteral);
702704
703 if (first->id != TokenIdKeywordNoInline) {
705 if (first->id != TokenIdKeywordNoInline && first->id != TokenIdKeywordInline) {
704706 Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal);
705707 AstNode *var_decl = ast_parse_var_decl(pc);
706708 if (var_decl != nullptr) {
......@@ -737,8 +739,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
737739 if (!fn_proto->data.fn_proto.is_extern)
738740 fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern;
739741 fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport;
740 if (first->id == TokenIdKeywordNoInline)
741 fn_proto->data.fn_proto.is_noinline = true;
742 switch (first->id) {
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 }
742753 fn_proto->data.fn_proto.lib_name = token_buf(lib_name);
743754
744755 AstNode *res = fn_proto;