| author | |
| committer | |
| log | 569525f03e17ba32204733108a950a5170662299 |
| tree | 7a6d4daf267525bc0ca2b8fc8796c989750889d7 |
| parent | 9910bfa6d887cd28dba3ac99ac0f0acf8d6e5056 |
| signature |
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 | 714 | NodeTypeAnyTypeField, |
| 715 | 715 | }; |
| 716 | 716 | |
| 717 | enum FnInline { | |
| 718 | FnInlineAuto, | |
| 719 | FnInlineAlways, | |
| 720 | FnInlineNever, | |
| 721 | }; | |
| 722 | ||
| 717 | 723 | struct AstNodeFnProto { |
| 718 | 724 | Buf *name; |
| 719 | 725 | ZigList<AstNode *> params; |
| ... | ... | @@ -729,12 +735,16 @@ struct AstNodeFnProto { |
| 729 | 735 | AstNode *callconv_expr; |
| 730 | 736 | Buf doc_comments; |
| 731 | 737 | |
| 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 | 743 | VisibMod visib_mod; |
| 733 | 744 | bool auto_err_set; |
| 734 | 745 | bool is_var_args; |
| 735 | 746 | bool is_extern; |
| 736 | 747 | bool is_export; |
| 737 | bool is_noinline; | |
| 738 | 748 | }; |
| 739 | 749 | |
| 740 | 750 | struct AstNodeFnDef { |
src/stage1/analyze.cpp+7-1| ... | ... | @@ -1638,6 +1638,9 @@ CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { |
| 1638 | 1638 | if (fn_proto->is_extern || fn_proto->is_export) |
| 1639 | 1639 | return CallingConventionC; |
| 1640 | 1640 | |
| 1641 | if (fn_proto->fn_inline == FnInlineAlways) | |
| 1642 | return CallingConventionInline; | |
| 1643 | ||
| 1641 | 1644 | return CallingConventionUnspecified; |
| 1642 | 1645 | } |
| 1643 | 1646 | |
| ... | ... | @@ -3649,7 +3652,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { |
| 3649 | 3652 | assert(proto_node->type == NodeTypeFnProto); |
| 3650 | 3653 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 3651 | 3654 | |
| 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); | |
| 3653 | 3656 | |
| 3654 | 3657 | fn_entry->proto_node = proto_node; |
| 3655 | 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 | 3745 | |
| 3743 | 3746 | CallingConvention cc; |
| 3744 | 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 | 3751 | ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); |
| 3746 | 3752 | |
| 3747 | 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 | 123 | // zig_unreachable(); |
| 124 | 124 | //} |
| 125 | 125 | |
| 126 | static const char *inline_string(bool is_inline) { | |
| 127 | return is_inline ? "inline" : ""; | |
| 126 | static 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(); | |
| 128 | 133 | } |
| 129 | 134 | |
| 130 | 135 | static 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 | 446 | const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); |
| 442 | 447 | const char *extern_str = extern_string(node->data.fn_proto.is_extern); |
| 443 | 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 | 450 | fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); |
| 446 | 451 | if (node->data.fn_proto.name != nullptr) { |
| 447 | 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 | 693 | Token *first = eat_token_if(pc, TokenIdKeywordExport); |
| 694 | 694 | if (first == nullptr) |
| 695 | 695 | first = eat_token_if(pc, TokenIdKeywordExtern); |
| 696 | if (first == nullptr) | |
| 697 | first = eat_token_if(pc, TokenIdKeywordInline); | |
| 696 | 698 | if (first == nullptr) |
| 697 | 699 | first = eat_token_if(pc, TokenIdKeywordNoInline); |
| 698 | 700 | if (first != nullptr) { |
| ... | ... | @@ -700,7 +702,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B |
| 700 | 702 | if (first->id == TokenIdKeywordExtern) |
| 701 | 703 | lib_name = eat_token_if(pc, TokenIdStringLiteral); |
| 702 | 704 | |
| 703 | if (first->id != TokenIdKeywordNoInline) { | |
| 705 | if (first->id != TokenIdKeywordNoInline && first->id != TokenIdKeywordInline) { | |
| 704 | 706 | Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); |
| 705 | 707 | AstNode *var_decl = ast_parse_var_decl(pc); |
| 706 | 708 | if (var_decl != nullptr) { |
| ... | ... | @@ -737,8 +739,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B |
| 737 | 739 | if (!fn_proto->data.fn_proto.is_extern) |
| 738 | 740 | fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; |
| 739 | 741 | 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 | } | |
| 742 | 753 | fn_proto->data.fn_proto.lib_name = token_buf(lib_name); |
| 743 | 754 | |
| 744 | 755 | AstNode *res = fn_proto; |