mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
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.
This commit is contained in:
parent
9910bfa6d8
commit
569525f03e
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -693,6 +693,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
|
||||
Token *first = eat_token_if(pc, TokenIdKeywordExport);
|
||||
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) {
|
||||
@ -700,7 +702,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user