From d949180ab04f550d672e20a8f9bdd6619cc3c05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phan=20Kochen?= Date: Tue, 19 Oct 2021 08:28:06 +0200 Subject: [PATCH] translate-c: create `inline fn` for always_inline --- src/clang.zig | 3 +++ src/translate_c.zig | 17 +++++++++++++---- src/translate_c/ast.zig | 2 ++ src/zig_clang.cpp | 5 +++++ src/zig_clang.h | 1 + test/translate_c.zig | 10 ++++++++++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/clang.zig b/src/clang.zig index 430c9093f2..8a8d794e41 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -536,6 +536,9 @@ pub const FunctionDecl = opaque { pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified; extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool; + pub const hasAlwaysInlineAttr = ZigClangFunctionDecl_hasAlwaysInlineAttr; + extern fn ZigClangFunctionDecl_hasAlwaysInlineAttr(*const FunctionDecl) bool; + pub const isDefined = ZigClangFunctionDecl_isDefined; extern fn ZigClangFunctionDecl_isDefined(*const FunctionDecl) bool; diff --git a/src/translate_c.zig b/src/translate_c.zig index e83755ad47..84e809730e 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -575,12 +575,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { const fn_decl_loc = fn_decl.getLocation(); const has_body = fn_decl.hasBody(); const storage_class = fn_decl.getStorageClass(); + const is_always_inline = has_body and fn_decl.hasAlwaysInlineAttr(); var decl_ctx = FnDeclContext{ .fn_name = fn_name, .has_body = has_body, .storage_class = storage_class, + .is_always_inline = is_always_inline, .is_export = switch (storage_class) { - .None => has_body and !fn_decl.isInlineSpecified(), + .None => has_body and !is_always_inline and !fn_decl.isInlineSpecified(), .Extern, .Static => false, .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}), .Auto => unreachable, // Not legal on functions @@ -615,6 +617,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { decl_ctx.has_body = false; decl_ctx.storage_class = .Extern; decl_ctx.is_export = false; + decl_ctx.is_always_inline = false; try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to extern", .{}); } 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 { const param_name = param.name orelse { proto_node.data.is_extern = true; proto_node.data.is_export = false; + proto_node.data.is_inline = false; try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name}); return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); }; @@ -685,6 +689,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { => { proto_node.data.is_extern = true; proto_node.data.is_export = false; + proto_node.data.is_inline = false; try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{}); return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); }, @@ -704,6 +709,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { => { proto_node.data.is_extern = true; proto_node.data.is_export = false; + proto_node.data.is_inline = false; try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{}); return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); }, @@ -974,6 +980,7 @@ fn buildFlexibleArrayFn( .is_pub = true, .is_extern = false, .is_export = false, + .is_inline = false, .is_var_args = false, .name = field_name, .linksection_string = null, @@ -4821,6 +4828,7 @@ const FnDeclContext = struct { fn_name: []const u8, has_body: bool, storage_class: clang.StorageClass, + is_always_inline: bool, is_export: bool, }; @@ -4871,7 +4879,7 @@ fn transFnNoProto( is_pub: bool, ) !*ast.Payload.Func { const cc = try transCC(c, fn_ty, source_loc); - const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true; + const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static and !ctx.is_always_inline) else true; return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); } @@ -4888,9 +4896,9 @@ fn finishTransFnProto( ) !*ast.Payload.Func { const is_export = if (fn_decl_context) |ctx| ctx.is_export else false; const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false; + const is_inline = if (fn_decl_context) |ctx| ctx.is_always_inline else false; const scope = &c.global_scope.base; - // TODO check for always_inline attribute // TODO check for align attribute var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa); @@ -4934,7 +4942,7 @@ fn finishTransFnProto( const alignment = if (fn_decl) |decl| zigAlignment(decl.getAlignedAttribute(c.clang_context)) else null; - const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc; + const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .C) null else cc; const return_type_node = blk: { if (fn_ty.getNoReturnAttr()) { @@ -4963,6 +4971,7 @@ fn finishTransFnProto( .is_pub = is_pub, .is_extern = is_extern, .is_export = is_export, + .is_inline = is_inline, .is_var_args = is_var_args, .name = name, .linksection_string = linksection_string, diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index a86ec0d414..315f22d7f2 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -540,6 +540,7 @@ pub const Payload = struct { is_pub: bool, is_extern: bool, is_export: bool, + is_inline: bool, is_var_args: bool, name: ?[]const u8, linksection_string: ?[]const u8, @@ -2614,6 +2615,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub"); if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern"); if (payload.is_export) _ = try c.addToken(.keyword_export, "export"); + if (payload.is_inline) _ = try c.addToken(.keyword_inline, "inline"); const fn_token = try c.addToken(.keyword_fn, "fn"); if (payload.name) |some| _ = try c.addIdentifier(some); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index f5b04ddd9d..deefc04c0a 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2120,6 +2120,11 @@ bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *s return casted->isInlineSpecified(); } +bool ZigClangFunctionDecl_hasAlwaysInlineAttr(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast(self); + return casted->hasAttr(); +} + const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) { auto casted = reinterpret_cast(self); if (const clang::SectionAttr *SA = casted->getAttr()) { diff --git a/src/zig_clang.h b/src/zig_clang.h index f704b50b18..af44e51cdd 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1111,6 +1111,7 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefi ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangFunctionDecl_doesThisDeclarationHaveABody(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C bool ZigClangFunctionDecl_hasAlwaysInlineAttr(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangFunctionDecl_isDefined(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C const struct ZigClangFunctionDecl* ZigClangFunctionDecl_getDefinition(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *, size_t *); diff --git a/test/translate_c.zig b/test/translate_c.zig index eb38e4e011..b63bbfc57d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -849,6 +849,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn foo() noreturn; }); + cases.add("always_inline attribute", + \\__attribute__((always_inline)) int foo() { + \\ return 5; + \\} + , &[_][]const u8{ + \\pub inline fn foo() c_int { + \\ return 5; + \\} + }); + cases.add("add, sub, mul, div, rem", \\int s() { \\ int a, b, c;