authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-05-20 14:08:57+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-05-20 14:54:44+02:00
log3fd8ac092e88ac4bc604afcdd3fcb33249dba967
tree7e0cb16071c65746f7fcf86bdaa0f3c67eded508
parent569525f03e17ba32204733108a950a5170662299
signaturelock-open Commit is signed but in an unrecognized format.

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.

3 files changed, 52 insertions(+), 17 deletions(-)

lib/std/zig/ast.zig+7-3
...@@ -1833,7 +1833,7 @@ pub const Tree = struct {...@@ -1833,7 +1833,7 @@ pub const Tree = struct {
1833 var result: full.FnProto = .{1833 var result: full.FnProto = .{
1834 .ast = info,1834 .ast = info,
1835 .visib_token = null,1835 .visib_token = null,
1836 .extern_export_token = null,1836 .extern_export_inline_token = null,
1837 .lib_name = null,1837 .lib_name = null,
1838 .name_token = null,1838 .name_token = null,
1839 .lparen = undefined,1839 .lparen = undefined,
...@@ -1842,7 +1842,11 @@ pub const Tree = struct {...@@ -1842,7 +1842,11 @@ pub const Tree = struct {
1842 while (i > 0) {1842 while (i > 0) {
1843 i -= 1;1843 i -= 1;
1844 switch (token_tags[i]) {1844 switch (token_tags[i]) {
1845 .keyword_extern, .keyword_export => result.extern_export_token = i,1845 .keyword_extern,
1846 .keyword_export,
1847 .keyword_inline,
1848 .keyword_noinline,
1849 => result.extern_export_inline_token = i,
1846 .keyword_pub => result.visib_token = i,1850 .keyword_pub => result.visib_token = i,
1847 .string_literal => result.lib_name = i,1851 .string_literal => result.lib_name = i,
1848 else => break,1852 else => break,
...@@ -2123,7 +2127,7 @@ pub const full = struct {...@@ -2123,7 +2127,7 @@ pub const full = struct {
21232127
2124 pub const FnProto = struct {2128 pub const FnProto = struct {
2125 visib_token: ?TokenIndex,2129 visib_token: ?TokenIndex,
2126 extern_export_token: ?TokenIndex,2130 extern_export_inline_token: ?TokenIndex,
2127 lib_name: ?TokenIndex,2131 lib_name: ?TokenIndex,
2128 name_token: ?TokenIndex,2132 name_token: ?TokenIndex,
2129 lparen: TokenIndex,2133 lparen: TokenIndex,
src/AstGen.zig+32-14
...@@ -995,7 +995,7 @@ fn fnProtoExpr(...@@ -995,7 +995,7 @@ fn fnProtoExpr(
995 const token_tags = tree.tokens.items(.tag);995 const token_tags = tree.tokens.items(.tag);
996996
997 const is_extern = blk: {997 const is_extern = blk: {
998 const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false;998 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
999 break :blk token_tags[maybe_extern_token] == .keyword_extern;999 break :blk token_tags[maybe_extern_token] == .keyword_extern;
1000 };1000 };
1001 assert(!is_extern);1001 assert(!is_extern);
...@@ -2735,15 +2735,20 @@ fn fnDecl(...@@ -2735,15 +2735,20 @@ fn fnDecl(
2735 };2735 };
2736 defer decl_gz.instructions.deinit(gpa);2736 defer decl_gz.instructions.deinit(gpa);
27372737
2738 // TODO: support noinline
2738 const is_pub = fn_proto.visib_token != null;2739 const is_pub = fn_proto.visib_token != null;
2739 const is_export = blk: {2740 const is_export = blk: {
2740 const maybe_export_token = fn_proto.extern_export_token orelse break :blk false;2741 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
2741 break :blk token_tags[maybe_export_token] == .keyword_export;2742 break :blk token_tags[maybe_export_token] == .keyword_export;
2742 };2743 };
2743 const is_extern = blk: {2744 const is_extern = blk: {
2744 const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false;2745 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
2745 break :blk token_tags[maybe_extern_token] == .keyword_extern;2746 break :blk token_tags[maybe_extern_token] == .keyword_extern;
2746 };2747 };
2748 const has_inline_keyword = blk: {
2749 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
2750 break :blk token_tags[maybe_inline_token] == .keyword_inline;
2751 };
2747 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {2752 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
2748 break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr);2753 break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr);
2749 };2754 };
...@@ -2812,17 +2817,30 @@ fn fnDecl(...@@ -2812,17 +2817,30 @@ fn fnDecl(
2812 fn_proto.ast.return_type,2817 fn_proto.ast.return_type,
2813 );2818 );
28142819
2815 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)2820 const cc: Zir.Inst.Ref = blk: {
2816 try AstGen.expr(2821 if (fn_proto.ast.callconv_expr != 0) {
2817 &decl_gz,2822 if (has_inline_keyword) {
2818 &decl_gz.base,2823 return astgen.failNode(
2819 .{ .ty = .calling_convention_type },2824 fn_proto.ast.callconv_expr,
2820 fn_proto.ast.callconv_expr,2825 "explicit callconv incompatible with inline keyword",
2821 )2826 .{},
2822 else if (is_extern) // note: https://github.com/ziglang/zig/issues/52692827 );
2823 Zir.Inst.Ref.calling_convention_c2828 }
2824 else2829 break :blk try AstGen.expr(
2825 Zir.Inst.Ref.none;2830 &decl_gz,
2831 &decl_gz.base,
2832 .{ .ty = .calling_convention_type },
2833 fn_proto.ast.callconv_expr,
2834 );
2835 } else if (is_extern) {
2836 // note: https://github.com/ziglang/zig/issues/5269
2837 break :blk .calling_convention_c;
2838 } else if (has_inline_keyword) {
2839 break :blk .calling_convention_inline;
2840 } else {
2841 break :blk .none;
2842 }
2843 };
28262844
2827 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {2845 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
2828 if (!is_extern) {2846 if (!is_extern) {
src/Zir.zig+13
...@@ -1687,6 +1687,8 @@ pub const Inst = struct {...@@ -1687,6 +1687,8 @@ pub const Inst = struct {
1687 one_usize,1687 one_usize,
1688 /// `std.builtin.CallingConvention.C`1688 /// `std.builtin.CallingConvention.C`
1689 calling_convention_c,1689 calling_convention_c,
1690 /// `std.builtin.CallingConvention.Inline`
1691 calling_convention_inline,
16901692
1691 _,1693 _,
16921694
...@@ -1954,6 +1956,10 @@ pub const Inst = struct {...@@ -1954,6 +1956,10 @@ pub const Inst = struct {
1954 .ty = Type.initTag(.calling_convention),1956 .ty = Type.initTag(.calling_convention),
1955 .val = .{ .ptr_otherwise = &calling_convention_c_payload.base },1957 .val = .{ .ptr_otherwise = &calling_convention_c_payload.base },
1956 },1958 },
1959 .calling_convention_inline = .{
1960 .ty = Type.initTag(.calling_convention),
1961 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },
1962 },
1957 });1963 });
1958 };1964 };
19591965
...@@ -1964,6 +1970,13 @@ pub const Inst = struct {...@@ -1964,6 +1970,13 @@ pub const Inst = struct {
1964 .data = @enumToInt(std.builtin.CallingConvention.C),1970 .data = @enumToInt(std.builtin.CallingConvention.C),
1965 };1971 };
19661972
1973 /// We would like this to be const but `Value` wants a mutable pointer for
1974 /// its payload field. Nothing should mutate this though.
1975 var calling_convention_inline_payload: Value.Payload.U32 = .{
1976 .base = .{ .tag = .enum_field_index },
1977 .data = @enumToInt(std.builtin.CallingConvention.Inline),
1978 };
1979
1967 /// All instructions have an 8-byte payload, which is contained within1980 /// All instructions have an 8-byte payload, which is contained within
1968 /// this union. `Tag` determines which union field is active, as well as1981 /// this union. `Tag` determines which union field is active, as well as
1969 /// how to interpret the data within.1982 /// how to interpret the data within.