authorgravatar for git@stephank.nlStéphan Kochen <git@stephank.nl> 2021-10-19 08:28:06+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-20 17:58:30-04:00
logd949180ab04f550d672e20a8f9bdd6619cc3c05c
treea3dbdbc129380e3bfe1e7eed9f38864570c52802
parented2a5081e1f379cf089f7700a2818db35faadc05

translate-c: create `inline fn` for always_inline


6 files changed, 34 insertions(+), 4 deletions(-)

src/clang.zig+3
......@@ -536,6 +536,9 @@ pub const FunctionDecl = opaque {
536536 pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified;
537537 extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool;
538538
539 pub const hasAlwaysInlineAttr = ZigClangFunctionDecl_hasAlwaysInlineAttr;
540 extern fn ZigClangFunctionDecl_hasAlwaysInlineAttr(*const FunctionDecl) bool;
541
539542 pub const isDefined = ZigClangFunctionDecl_isDefined;
540543 extern fn ZigClangFunctionDecl_isDefined(*const FunctionDecl) bool;
541544
src/translate_c.zig+13-4
......@@ -575,12 +575,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
575575 const fn_decl_loc = fn_decl.getLocation();
576576 const has_body = fn_decl.hasBody();
577577 const storage_class = fn_decl.getStorageClass();
578 const is_always_inline = has_body and fn_decl.hasAlwaysInlineAttr();
578579 var decl_ctx = FnDeclContext{
579580 .fn_name = fn_name,
580581 .has_body = has_body,
581582 .storage_class = storage_class,
583 .is_always_inline = is_always_inline,
582584 .is_export = switch (storage_class) {
583 .None => has_body and !fn_decl.isInlineSpecified(),
585 .None => has_body and !is_always_inline and !fn_decl.isInlineSpecified(),
584586 .Extern, .Static => false,
585587 .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
586588 .Auto => unreachable, // Not legal on functions
......@@ -615,6 +617,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
615617 decl_ctx.has_body = false;
616618 decl_ctx.storage_class = .Extern;
617619 decl_ctx.is_export = false;
620 decl_ctx.is_always_inline = false;
618621 try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to extern", .{});
619622 }
620623 break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
......@@ -653,6 +656,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
653656 const param_name = param.name orelse {
654657 proto_node.data.is_extern = true;
655658 proto_node.data.is_export = false;
659 proto_node.data.is_inline = false;
656660 try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
657661 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
658662 };
......@@ -685,6 +689,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
685689 => {
686690 proto_node.data.is_extern = true;
687691 proto_node.data.is_export = false;
692 proto_node.data.is_inline = false;
688693 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
689694 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
690695 },
......@@ -704,6 +709,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
704709 => {
705710 proto_node.data.is_extern = true;
706711 proto_node.data.is_export = false;
712 proto_node.data.is_inline = false;
707713 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{});
708714 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
709715 },
......@@ -974,6 +980,7 @@ fn buildFlexibleArrayFn(
974980 .is_pub = true,
975981 .is_extern = false,
976982 .is_export = false,
983 .is_inline = false,
977984 .is_var_args = false,
978985 .name = field_name,
979986 .linksection_string = null,
......@@ -4821,6 +4828,7 @@ const FnDeclContext = struct {
48214828 fn_name: []const u8,
48224829 has_body: bool,
48234830 storage_class: clang.StorageClass,
4831 is_always_inline: bool,
48244832 is_export: bool,
48254833};
48264834
......@@ -4871,7 +4879,7 @@ fn transFnNoProto(
48714879 is_pub: bool,
48724880) !*ast.Payload.Func {
48734881 const cc = try transCC(c, fn_ty, source_loc);
4874 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;
4882 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static and !ctx.is_always_inline) else true;
48754883 return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
48764884}
48774885
......@@ -4888,9 +4896,9 @@ fn finishTransFnProto(
48884896) !*ast.Payload.Func {
48894897 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
48904898 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
4899 const is_inline = if (fn_decl_context) |ctx| ctx.is_always_inline else false;
48914900 const scope = &c.global_scope.base;
48924901
4893 // TODO check for always_inline attribute
48944902 // TODO check for align attribute
48954903
48964904 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
......@@ -4934,7 +4942,7 @@ fn finishTransFnProto(
49344942
49354943 const alignment = if (fn_decl) |decl| zigAlignment(decl.getAlignedAttribute(c.clang_context)) else null;
49364944
4937 const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
4945 const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .C) null else cc;
49384946
49394947 const return_type_node = blk: {
49404948 if (fn_ty.getNoReturnAttr()) {
......@@ -4963,6 +4971,7 @@ fn finishTransFnProto(
49634971 .is_pub = is_pub,
49644972 .is_extern = is_extern,
49654973 .is_export = is_export,
4974 .is_inline = is_inline,
49664975 .is_var_args = is_var_args,
49674976 .name = name,
49684977 .linksection_string = linksection_string,
src/translate_c/ast.zig+2
......@@ -540,6 +540,7 @@ pub const Payload = struct {
540540 is_pub: bool,
541541 is_extern: bool,
542542 is_export: bool,
543 is_inline: bool,
543544 is_var_args: bool,
544545 name: ?[]const u8,
545546 linksection_string: ?[]const u8,
......@@ -2614,6 +2615,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
26142615 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
26152616 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
26162617 if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
2618 if (payload.is_inline) _ = try c.addToken(.keyword_inline, "inline");
26172619 const fn_token = try c.addToken(.keyword_fn, "fn");
26182620 if (payload.name) |some| _ = try c.addIdentifier(some);
26192621
src/zig_clang.cpp+5
......@@ -2120,6 +2120,11 @@ bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *s
21202120 return casted->isInlineSpecified();
21212121}
21222122
2123bool ZigClangFunctionDecl_hasAlwaysInlineAttr(const struct ZigClangFunctionDecl *self) {
2124 auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
2125 return casted->hasAttr<clang::AlwaysInlineAttr>();
2126}
2127
21232128const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) {
21242129 auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
21252130 if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {
src/zig_clang.h+1
......@@ -1111,6 +1111,7 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefi
11111111ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *);
11121112ZIG_EXTERN_C bool ZigClangFunctionDecl_doesThisDeclarationHaveABody(const struct ZigClangFunctionDecl *);
11131113ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *);
1114ZIG_EXTERN_C bool ZigClangFunctionDecl_hasAlwaysInlineAttr(const struct ZigClangFunctionDecl *);
11141115ZIG_EXTERN_C bool ZigClangFunctionDecl_isDefined(const struct ZigClangFunctionDecl *);
11151116ZIG_EXTERN_C const struct ZigClangFunctionDecl* ZigClangFunctionDecl_getDefinition(const struct ZigClangFunctionDecl *);
11161117ZIG_EXTERN_C const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *, size_t *);
test/translate_c.zig+10
......@@ -849,6 +849,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
849849 \\pub extern fn foo() noreturn;
850850 });
851851
852 cases.add("always_inline attribute",
853 \\__attribute__((always_inline)) int foo() {
854 \\ return 5;
855 \\}
856 , &[_][]const u8{
857 \\pub inline fn foo() c_int {
858 \\ return 5;
859 \\}
860 });
861
852862 cases.add("add, sub, mul, div, rem",
853863 \\int s() {
854864 \\ int a, b, c;