| 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,6 +714,12 @@ enum NodeType { |
| 714 | NodeTypeAnyTypeField, | 714 | NodeTypeAnyTypeField, |
| 715 | }; | 715 | }; |
| 716 | 716 | ||
| 717 | enum FnInline { | ||
| 718 | FnInlineAuto, | ||
| 719 | FnInlineAlways, | ||
| 720 | FnInlineNever, | ||
| 721 | }; | ||
| 722 | |||
| 717 | struct AstNodeFnProto { | 723 | struct 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; |
| 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 | 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 | }; |
| 739 | 749 | ||
| 740 | struct AstNodeFnDef { | 750 | struct 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; |
| 1640 | 1640 | ||
| 1641 | if (fn_proto->fn_inline == FnInlineAlways) | ||
| 1642 | return CallingConventionInline; | ||
| 1643 | |||
| 1641 | return CallingConventionUnspecified; | 1644 | return CallingConventionUnspecified; |
| 1642 | } | 1645 | } |
| 1643 | 1646 | ||
| ... | @@ -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; |
| 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 | 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) { |
| 3742 | 3745 | ||
| 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"); |
| 3746 | 3752 | ||
| 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 | //} |
| 125 | 125 | ||
| 126 | static const char *inline_string(bool is_inline) { | 126 | static 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 | } |
| 129 | 134 | ||
| 130 | static const char *const_or_var_string(bool is_const) { | 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,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); |
| 702 | 704 | ||
| 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); |
| 743 | 754 | ||
| 744 | AstNode *res = fn_proto; | 755 | AstNode *res = fn_proto; |