diff options
Diffstat (limited to 'src/stage1')
| -rw-r--r-- | src/stage1/all_types.hpp | 12 | ||||
| -rw-r--r-- | src/stage1/analyze.cpp | 8 | ||||
| -rw-r--r-- | src/stage1/ast_render.cpp | 11 | ||||
| -rw-r--r-- | src/stage1/parser.cpp | 17 |
4 files changed, 40 insertions, 8 deletions
diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 9eed42f4cd..88d10e9e6a 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -714,6 +714,12 @@ enum NodeType { NodeTypeAnyTypeField, }; +enum FnInline { + FnInlineAuto, + FnInlineAlways, + FnInlineNever, +}; + struct AstNodeFnProto { Buf *name; ZigList<AstNode *> params; @@ -729,12 +735,16 @@ struct AstNodeFnProto { AstNode *callconv_expr; Buf doc_comments; + // This is set based only on the existence of a noinline or inline keyword. + // This is then resolved to an is_noinline bool and (potentially .Inline) + // calling convention in resolve_decl_fn() in analyze.cpp. + FnInline fn_inline; + VisibMod visib_mod; bool auto_err_set; bool is_var_args; bool is_extern; bool is_export; - bool is_noinline; }; struct AstNodeFnDef { diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index a87fd80613..581e34acfc 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -1638,6 +1638,9 @@ CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { if (fn_proto->is_extern || fn_proto->is_export) return CallingConventionC; + if (fn_proto->fn_inline == FnInlineAlways) + return CallingConventionInline; + return CallingConventionUnspecified; } @@ -3649,7 +3652,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - ZigFn *fn_entry = create_fn_raw(g, fn_proto->is_noinline); + ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline == FnInlineNever); fn_entry->proto_node = proto_node; 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) { CallingConvention cc; if (fn_proto->callconv_expr != nullptr) { + if (fn_proto->fn_inline == FnInlineAlways) { + add_node_error(g, fn_proto->callconv_expr, buf_sprintf("explicit callconv incompatible with inline keyword")); + } ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr, diff --git a/src/stage1/ast_render.cpp b/src/stage1/ast_render.cpp index ed53cf7ccb..75ad7267ab 100644 --- a/src/stage1/ast_render.cpp +++ b/src/stage1/ast_render.cpp @@ -123,8 +123,13 @@ static const char *export_string(bool is_export) { // zig_unreachable(); //} -static const char *inline_string(bool is_inline) { - return is_inline ? "inline" : ""; +static const char *inline_string(FnInline fn_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) { @@ -441,7 +446,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 *extern_str = extern_string(node->data.fn_proto.is_extern); const char *export_str = export_string(node->data.fn_proto.is_export); - const char *inline_str = inline_string(node->data.fn_proto.is_noinline); + 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); if (node->data.fn_proto.name != nullptr) { print_symbol(ar, node->data.fn_proto.name); diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp index 08323d3086..19cd977c71 100644 --- a/src/stage1/parser.cpp +++ b/src/stage1/parser.cpp @@ -694,13 +694,15 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordExtern); if (first == nullptr) + first = eat_token_if(pc, TokenIdKeywordInline); + if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordNoInline); if (first != nullptr) { Token *lib_name = nullptr; if (first->id == TokenIdKeywordExtern) lib_name = eat_token_if(pc, TokenIdStringLiteral); - if (first->id != TokenIdKeywordNoInline) { + if (first->id != TokenIdKeywordNoInline && first->id != TokenIdKeywordInline) { Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { @@ -737,8 +739,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B if (!fn_proto->data.fn_proto.is_extern) fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; - if (first->id == TokenIdKeywordNoInline) - fn_proto->data.fn_proto.is_noinline = true; + 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); AstNode *res = fn_proto; |
