Commit d949180ab0
Changed files (6)
src
test
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);
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;
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,
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<const clang::FunctionDecl *>(self);
+ return casted->hasAttr<clang::AlwaysInlineAttr>();
+}
+
const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) {
auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {
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 *);
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;