translate-c: create inline fn for always_inline

This commit is contained in:
Stéphan Kochen 2021-10-19 08:28:06 +02:00 committed by Andrew Kelley
parent ed2a5081e1
commit d949180ab0
6 changed files with 34 additions and 4 deletions

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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>()) {

View file

@ -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 *);

View file

@ -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;