mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
translate-c: create inline fn for always_inline
This commit is contained in:
parent
ed2a5081e1
commit
d949180ab0
6 changed files with 34 additions and 4 deletions
|
|
@ -536,6 +536,9 @@ pub const FunctionDecl = opaque {
|
||||||
pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified;
|
pub const isInlineSpecified = ZigClangFunctionDecl_isInlineSpecified;
|
||||||
extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool;
|
extern fn ZigClangFunctionDecl_isInlineSpecified(*const FunctionDecl) bool;
|
||||||
|
|
||||||
|
pub const hasAlwaysInlineAttr = ZigClangFunctionDecl_hasAlwaysInlineAttr;
|
||||||
|
extern fn ZigClangFunctionDecl_hasAlwaysInlineAttr(*const FunctionDecl) bool;
|
||||||
|
|
||||||
pub const isDefined = ZigClangFunctionDecl_isDefined;
|
pub const isDefined = ZigClangFunctionDecl_isDefined;
|
||||||
extern fn ZigClangFunctionDecl_isDefined(*const FunctionDecl) bool;
|
extern fn ZigClangFunctionDecl_isDefined(*const FunctionDecl) bool;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -575,12 +575,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||||
const fn_decl_loc = fn_decl.getLocation();
|
const fn_decl_loc = fn_decl.getLocation();
|
||||||
const has_body = fn_decl.hasBody();
|
const has_body = fn_decl.hasBody();
|
||||||
const storage_class = fn_decl.getStorageClass();
|
const storage_class = fn_decl.getStorageClass();
|
||||||
|
const is_always_inline = has_body and fn_decl.hasAlwaysInlineAttr();
|
||||||
var decl_ctx = FnDeclContext{
|
var decl_ctx = FnDeclContext{
|
||||||
.fn_name = fn_name,
|
.fn_name = fn_name,
|
||||||
.has_body = has_body,
|
.has_body = has_body,
|
||||||
.storage_class = storage_class,
|
.storage_class = storage_class,
|
||||||
|
.is_always_inline = is_always_inline,
|
||||||
.is_export = switch (storage_class) {
|
.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,
|
.Extern, .Static => false,
|
||||||
.PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
|
.PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
|
||||||
.Auto => unreachable, // Not legal on functions
|
.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.has_body = false;
|
||||||
decl_ctx.storage_class = .Extern;
|
decl_ctx.storage_class = .Extern;
|
||||||
decl_ctx.is_export = false;
|
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", .{});
|
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) {
|
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 {
|
const param_name = param.name orelse {
|
||||||
proto_node.data.is_extern = true;
|
proto_node.data.is_extern = true;
|
||||||
proto_node.data.is_export = false;
|
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});
|
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));
|
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_extern = true;
|
||||||
proto_node.data.is_export = false;
|
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", .{});
|
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));
|
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_extern = true;
|
||||||
proto_node.data.is_export = false;
|
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", .{});
|
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));
|
return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
|
||||||
},
|
},
|
||||||
|
|
@ -974,6 +980,7 @@ fn buildFlexibleArrayFn(
|
||||||
.is_pub = true,
|
.is_pub = true,
|
||||||
.is_extern = false,
|
.is_extern = false,
|
||||||
.is_export = false,
|
.is_export = false,
|
||||||
|
.is_inline = false,
|
||||||
.is_var_args = false,
|
.is_var_args = false,
|
||||||
.name = field_name,
|
.name = field_name,
|
||||||
.linksection_string = null,
|
.linksection_string = null,
|
||||||
|
|
@ -4821,6 +4828,7 @@ const FnDeclContext = struct {
|
||||||
fn_name: []const u8,
|
fn_name: []const u8,
|
||||||
has_body: bool,
|
has_body: bool,
|
||||||
storage_class: clang.StorageClass,
|
storage_class: clang.StorageClass,
|
||||||
|
is_always_inline: bool,
|
||||||
is_export: bool,
|
is_export: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -4871,7 +4879,7 @@ fn transFnNoProto(
|
||||||
is_pub: bool,
|
is_pub: bool,
|
||||||
) !*ast.Payload.Func {
|
) !*ast.Payload.Func {
|
||||||
const cc = try transCC(c, fn_ty, source_loc);
|
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);
|
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 {
|
) !*ast.Payload.Func {
|
||||||
const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
|
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_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;
|
const scope = &c.global_scope.base;
|
||||||
|
|
||||||
// TODO check for always_inline attribute
|
|
||||||
// TODO check for align attribute
|
// TODO check for align attribute
|
||||||
|
|
||||||
var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
|
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 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: {
|
const return_type_node = blk: {
|
||||||
if (fn_ty.getNoReturnAttr()) {
|
if (fn_ty.getNoReturnAttr()) {
|
||||||
|
|
@ -4963,6 +4971,7 @@ fn finishTransFnProto(
|
||||||
.is_pub = is_pub,
|
.is_pub = is_pub,
|
||||||
.is_extern = is_extern,
|
.is_extern = is_extern,
|
||||||
.is_export = is_export,
|
.is_export = is_export,
|
||||||
|
.is_inline = is_inline,
|
||||||
.is_var_args = is_var_args,
|
.is_var_args = is_var_args,
|
||||||
.name = name,
|
.name = name,
|
||||||
.linksection_string = linksection_string,
|
.linksection_string = linksection_string,
|
||||||
|
|
|
||||||
|
|
@ -540,6 +540,7 @@ pub const Payload = struct {
|
||||||
is_pub: bool,
|
is_pub: bool,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
is_export: bool,
|
is_export: bool,
|
||||||
|
is_inline: bool,
|
||||||
is_var_args: bool,
|
is_var_args: bool,
|
||||||
name: ?[]const u8,
|
name: ?[]const u8,
|
||||||
linksection_string: ?[]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_pub) _ = try c.addToken(.keyword_pub, "pub");
|
||||||
if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
|
if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
|
||||||
if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
|
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");
|
const fn_token = try c.addToken(.keyword_fn, "fn");
|
||||||
if (payload.name) |some| _ = try c.addIdentifier(some);
|
if (payload.name) |some| _ = try c.addIdentifier(some);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2120,6 +2120,11 @@ bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *s
|
||||||
return casted->isInlineSpecified();
|
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) {
|
const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) {
|
||||||
auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
|
auto casted = reinterpret_cast<const clang::FunctionDecl *>(self);
|
||||||
if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {
|
if (const clang::SectionAttr *SA = casted->getAttr<clang::SectionAttr>()) {
|
||||||
|
|
|
||||||
|
|
@ -1111,6 +1111,7 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefi
|
||||||
ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *);
|
ZIG_EXTERN_C bool ZigClangFunctionDecl_isThisDeclarationADefinition(const struct ZigClangFunctionDecl *);
|
||||||
ZIG_EXTERN_C bool ZigClangFunctionDecl_doesThisDeclarationHaveABody(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_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 bool ZigClangFunctionDecl_isDefined(const struct ZigClangFunctionDecl *);
|
||||||
ZIG_EXTERN_C const struct ZigClangFunctionDecl* ZigClangFunctionDecl_getDefinition(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 *);
|
ZIG_EXTERN_C const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *, size_t *);
|
||||||
|
|
|
||||||
|
|
@ -849,6 +849,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||||
\\pub extern fn foo() noreturn;
|
\\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",
|
cases.add("add, sub, mul, div, rem",
|
||||||
\\int s() {
|
\\int s() {
|
||||||
\\ int a, b, c;
|
\\ int a, b, c;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue