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 {...@@ -536,6 +536,9 @@ pub const FunctionDecl = opaque {
536 pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified;536 pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified;
537 extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool;537 extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool;
538538
539 pub const hasAlwaysInlineAttr = ZigClangFunctionDecl_hasAlwaysInlineAttr;
540 extern fn ZigClangFunctionDecl_hasAlwaysInlineAttr(*const FunctionDecl) bool;
541
539 pub const isDefined = ZigClangFunctionDecl_isDefined;542 pub const isDefined = ZigClangFunctionDecl_isDefined;
540 extern fn ZigClangFunctionDecl_isDefined(*const FunctionDecl) bool;543 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 {...@@ -575,12 +575,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
575 const fn_decl_loc = fn_decl.getLocation();575 const fn_decl_loc = fn_decl.getLocation();
576 const has_body = fn_decl.hasBody();576 const has_body = fn_decl.hasBody();
577 const storage_class = fn_decl.getStorageClass();577 const storage_class = fn_decl.getStorageClass();
578 const is_always_inline = has_body and fn_decl.hasAlwaysInlineAttr();
578 var decl_ctx = FnDeclContext{579 var decl_ctx = FnDeclContext{
579 .fn_name = fn_name,580 .fn_name = fn_name,
580 .has_body = has_body,581 .has_body = has_body,
581 .storage_class = storage_class,582 .storage_class = storage_class,
583 .is_always_inline = is_always_inline,
582 .is_export = switch (storage_class) {584 .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(),
584 .Extern, .Static => false,586 .Extern, .Static => false,
585 .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),587 .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
586 .Auto => unreachable, // Not legal on functions588 .Auto => unreachable, // Not legal on functions
...@@ -615,6 +617,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -615,6 +617,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
615 decl_ctx.has_body = false;617 decl_ctx.has_body = false;
616 decl_ctx.storage_class = .Extern;618 decl_ctx.storage_class = .Extern;
617 decl_ctx.is_export = false;619 decl_ctx.is_export = false;
620 decl_ctx.is_always_inline = false;
618 try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to extern", .{});621 try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to extern", .{});
619 }622 }
620 break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {623 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 {...@@ -653,6 +656,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
653 const param_name = param.name orelse {656 const param_name = param.name orelse {
654 proto_node.data.is_extern = true;657 proto_node.data.is_extern = true;
655 proto_node.data.is_export = false;658 proto_node.data.is_export = false;
659 proto_node.data.is_inline = false;
656 try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});660 try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
657 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));661 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
658 };662 };
...@@ -685,6 +689,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -685,6 +689,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
685 => {689 => {
686 proto_node.data.is_extern = true;690 proto_node.data.is_extern = true;
687 proto_node.data.is_export = false;691 proto_node.data.is_export = false;
692 proto_node.data.is_inline = false;
688 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});693 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
689 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));694 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
690 },695 },
...@@ -704,6 +709,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -704,6 +709,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
704 => {709 => {
705 proto_node.data.is_extern = true;710 proto_node.data.is_extern = true;
706 proto_node.data.is_export = false;711 proto_node.data.is_export = false;
712 proto_node.data.is_inline = false;
707 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{});713 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{});
708 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));714 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
709 },715 },
...@@ -974,6 +980,7 @@ fn buildFlexibleArrayFn(...@@ -974,6 +980,7 @@ fn buildFlexibleArrayFn(
974 .is_pub = true,980 .is_pub = true,
975 .is_extern = false,981 .is_extern = false,
976 .is_export = false,982 .is_export = false,
983 .is_inline = false,
977 .is_var_args = false,984 .is_var_args = false,
978 .name = field_name,985 .name = field_name,
979 .linksection_string = null,986 .linksection_string = null,
...@@ -4821,6 +4828,7 @@ const FnDeclContext = struct {...@@ -4821,6 +4828,7 @@ const FnDeclContext = struct {
4821 fn_name: []const u8,4828 fn_name: []const u8,
4822 has_body: bool,4829 has_body: bool,
4823 storage_class: clang.StorageClass,4830 storage_class: clang.StorageClass,
4831 is_always_inline: bool,
4824 is_export: bool,4832 is_export: bool,
4825};4833};
48264834
...@@ -4871,7 +4879,7 @@ fn transFnNoProto(...@@ -4871,7 +4879,7 @@ fn transFnNoProto(
4871 is_pub: bool,4879 is_pub: bool,
4872) !*ast.Payload.Func {4880) !*ast.Payload.Func {
4873 const cc = try transCC(c, fn_ty, source_loc);4881 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;
4875 return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);4883 return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
4876}4884}
48774885
...@@ -4888,9 +4896,9 @@ fn finishTransFnProto(...@@ -4888,9 +4896,9 @@ fn finishTransFnProto(
4888) !*ast.Payload.Func {4896) !*ast.Payload.Func {
4889 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;4897 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
4890 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;4898 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;
4891 const scope = &c.global_scope.base;4900 const scope = &c.global_scope.base;
48924901
4893 // TODO check for always_inline attribute
4894 // TODO check for align attribute4902 // TODO check for align attribute
48954903
4896 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);4904 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
...@@ -4934,7 +4942,7 @@ fn finishTransFnProto(...@@ -4934,7 +4942,7 @@ fn finishTransFnProto(
49344942
4935 const alignment = if (fn_decl) |decl| zigAlignment(decl.getAlignedAttribute(c.clang_context)) else null;4943 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
4939 const return_type_node = blk: {4947 const return_type_node = blk: {
4940 if (fn_ty.getNoReturnAttr()) {4948 if (fn_ty.getNoReturnAttr()) {
...@@ -4963,6 +4971,7 @@ fn finishTransFnProto(...@@ -4963,6 +4971,7 @@ fn finishTransFnProto(
4963 .is_pub = is_pub,4971 .is_pub = is_pub,
4964 .is_extern = is_extern,4972 .is_extern = is_extern,
4965 .is_export = is_export,4973 .is_export = is_export,
4974 .is_inline = is_inline,
4966 .is_var_args = is_var_args,4975 .is_var_args = is_var_args,
4967 .name = name,4976 .name = name,
4968 .linksection_string = linksection_string,4977 .linksection_string = linksection_string,
src/translate_c/ast.zig+2
...@@ -540,6 +540,7 @@ pub const Payload = struct {...@@ -540,6 +540,7 @@ pub const Payload = struct {
540 is_pub: bool,540 is_pub: bool,
541 is_extern: bool,541 is_extern: bool,
542 is_export: bool,542 is_export: bool,
543 is_inline: bool,
543 is_var_args: bool,544 is_var_args: bool,
544 name: ?[]const u8,545 name: ?[]const u8,
545 linksection_string: ?[]const u8,546 linksection_string: ?[]const u8,
...@@ -2614,6 +2615,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {...@@ -2614,6 +2615,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
2614 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");2615 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
2615 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");2616 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
2616 if (payload.is_export) _ = try c.addToken(.keyword_export, "export");2617 if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
2618 if (payload.is_inline) _ = try c.addToken(.keyword_inline, "inline");
2617 const fn_token = try c.addToken(.keyword_fn, "fn");2619 const fn_token = try c.addToken(.keyword_fn, "fn");
2618 if (payload.name) |some| _ = try c.addIdentifier(some);2620 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...@@ -2120,6 +2120,11 @@ bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *s
2120 return casted->isInlineSpecified();2120 return casted->isInlineSpecified();
2121}2121}
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
2123const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) {2128const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) {
2124 auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);2129 auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
2125 if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {2130 if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {
src/zig_clang.h+1
...@@ -1111,6 +1111,7 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefi...@@ -1111,6 +1111,7 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefi
1111ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *);1111ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *);
1112ZIG_EXTERN_C bool ZigClangFunctionDecl_doesThisDeclarationHaveABody(const struct ZigClangFunctionDecl *);1112ZIG_EXTERN_C bool ZigClangFunctionDecl_doesThisDeclarationHaveABody(const struct ZigClangFunctionDecl *);
1113ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *);1113ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *);
1114ZIG_EXTERN_C bool ZigClangFunctionDecl_hasAlwaysInlineAttr(const struct ZigClangFunctionDecl *);
1114ZIG_EXTERN_C bool ZigClangFunctionDecl_isDefined(const struct ZigClangFunctionDecl *);1115ZIG_EXTERN_C bool ZigClangFunctionDecl_isDefined(const struct ZigClangFunctionDecl *);
1115ZIG_EXTERN_C const struct ZigClangFunctionDecl* ZigClangFunctionDecl_getDefinition(const struct ZigClangFunctionDecl *);1116ZIG_EXTERN_C const struct ZigClangFunctionDecl* ZigClangFunctionDecl_getDefinition(const struct ZigClangFunctionDecl *);
1116ZIG_EXTERN_C const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *, size_t *);1117ZIG_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 {...@@ -849,6 +849,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
849 \\pub extern fn foo() noreturn;849 \\pub extern fn foo() noreturn;
850 });850 });
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
852 cases.add("add, sub, mul, div, rem",862 cases.add("add, sub, mul, div, rem",
853 \\int s() {863 \\int s() {
854 \\ int a, b, c;864 \\ int a, b, c;