From 3fd8ac092e88ac4bc604afcdd3fcb33249dba967 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 20 May 2021 14:08:57 +0200 Subject: [PATCH] stage2: 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. --- lib/std/zig/ast.zig | 10 +++++++--- src/AstGen.zig | 46 +++++++++++++++++++++++++++++++-------------- src/Zir.zig | 13 +++++++++++++ 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index f55defce81..523f171f44 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1833,7 +1833,7 @@ pub const Tree = struct { var result: full.FnProto = .{ .ast = info, .visib_token = null, - .extern_export_token = null, + .extern_export_inline_token = null, .lib_name = null, .name_token = null, .lparen = undefined, @@ -1842,7 +1842,11 @@ pub const Tree = struct { while (i > 0) { i -= 1; switch (token_tags[i]) { - .keyword_extern, .keyword_export => result.extern_export_token = i, + .keyword_extern, + .keyword_export, + .keyword_inline, + .keyword_noinline, + => result.extern_export_inline_token = i, .keyword_pub => result.visib_token = i, .string_literal => result.lib_name = i, else => break, @@ -2123,7 +2127,7 @@ pub const full = struct { pub const FnProto = struct { visib_token: ?TokenIndex, - extern_export_token: ?TokenIndex, + extern_export_inline_token: ?TokenIndex, lib_name: ?TokenIndex, name_token: ?TokenIndex, lparen: TokenIndex, diff --git a/src/AstGen.zig b/src/AstGen.zig index 8798c98021..547d608625 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -995,7 +995,7 @@ fn fnProtoExpr( const token_tags = tree.tokens.items(.tag); const is_extern = blk: { - const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; + const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; break :blk token_tags[maybe_extern_token] == .keyword_extern; }; assert(!is_extern); @@ -2735,15 +2735,20 @@ fn fnDecl( }; defer decl_gz.instructions.deinit(gpa); + // TODO: support noinline const is_pub = fn_proto.visib_token != null; const is_export = blk: { - const maybe_export_token = fn_proto.extern_export_token orelse break :blk false; + const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; break :blk token_tags[maybe_export_token] == .keyword_export; }; const is_extern = blk: { - const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; + const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; break :blk token_tags[maybe_extern_token] == .keyword_extern; }; + const has_inline_keyword = blk: { + const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; + break :blk token_tags[maybe_inline_token] == .keyword_inline; + }; const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr); }; @@ -2812,17 +2817,30 @@ fn fnDecl( fn_proto.ast.return_type, ); - const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) - try AstGen.expr( - &decl_gz, - &decl_gz.base, - .{ .ty = .calling_convention_type }, - fn_proto.ast.callconv_expr, - ) - else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269 - Zir.Inst.Ref.calling_convention_c - else - Zir.Inst.Ref.none; + const cc: Zir.Inst.Ref = blk: { + if (fn_proto.ast.callconv_expr != 0) { + if (has_inline_keyword) { + return astgen.failNode( + fn_proto.ast.callconv_expr, + "explicit callconv incompatible with inline keyword", + .{}, + ); + } + break :blk try AstGen.expr( + &decl_gz, + &decl_gz.base, + .{ .ty = .calling_convention_type }, + fn_proto.ast.callconv_expr, + ); + } else if (is_extern) { + // note: https://github.com/ziglang/zig/issues/5269 + break :blk .calling_convention_c; + } else if (has_inline_keyword) { + break :blk .calling_convention_inline; + } else { + break :blk .none; + } + }; const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { if (!is_extern) { diff --git a/src/Zir.zig b/src/Zir.zig index 73f8e3e43b..9270325de8 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -1687,6 +1687,8 @@ pub const Inst = struct { one_usize, /// `std.builtin.CallingConvention.C` calling_convention_c, + /// `std.builtin.CallingConvention.Inline` + calling_convention_inline, _, @@ -1954,6 +1956,10 @@ pub const Inst = struct { .ty = Type.initTag(.calling_convention), .val = .{ .ptr_otherwise = &calling_convention_c_payload.base }, }, + .calling_convention_inline = .{ + .ty = Type.initTag(.calling_convention), + .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base }, + }, }); }; @@ -1964,6 +1970,13 @@ pub const Inst = struct { .data = @enumToInt(std.builtin.CallingConvention.C), }; + /// We would like this to be const but `Value` wants a mutable pointer for + /// its payload field. Nothing should mutate this though. + var calling_convention_inline_payload: Value.Payload.U32 = .{ + .base = .{ .tag = .enum_field_index }, + .data = @enumToInt(std.builtin.CallingConvention.Inline), + }; + /// All instructions have an 8-byte payload, which is contained within /// this union. `Tag` determines which union field is active, as well as /// how to interpret the data within.