translate-c: add support for __cleanup__ attribute

Use a `defer` statement to implement the C __cleanup__ attribute.

See https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
This commit is contained in:
Evan Haas 2021-05-18 21:59:45 -07:00 committed by Veikka Tuominen
parent 28a89b9ebc
commit 1273bc277f
6 changed files with 60 additions and 0 deletions

View File

@ -976,6 +976,9 @@ pub const VarDecl = opaque {
pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute;
extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint;
pub const getCleanupAttribute = ZigClangVarDecl_getCleanupAttribute;
extern fn ZigClangVarDecl_getCleanupAttribute(*const VarDecl) ?*const FunctionDecl;
pub const getTypeSourceInfo_getType = ZigClangVarDecl_getTypeSourceInfo_getType;
extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;
};

View File

@ -1656,6 +1656,22 @@ fn transDeclStmtOne(
.init = init_node,
});
try block_scope.statements.append(node);
const cleanup_attr = var_decl.getCleanupAttribute();
if (cleanup_attr) |fn_decl| {
const cleanup_fn_name = try c.str(@ptrCast(*const clang.NamedDecl, fn_decl).getName_bytes_begin());
const fn_id = try Tag.identifier.create(c.arena, cleanup_fn_name);
const varname = try Tag.identifier.create(c.arena, mangled_name);
const args = try c.arena.alloc(Node, 1);
args[0] = try Tag.address_of.create(c.arena, varname);
const cleanup_call = try Tag.call.create(c.arena, .{ .lhs = fn_id, .args = args });
const discard = try Tag.discard.create(c.arena, cleanup_call);
const deferred_cleanup = try Tag.@"defer".create(c.arena, discard);
try block_scope.statements.append(deferred_cleanup);
}
},
.Typedef => {
try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));

View File

@ -67,6 +67,7 @@ pub const Node = extern union {
@"struct",
@"union",
@"comptime",
@"defer",
array_init,
tuple,
container_init,
@ -247,6 +248,7 @@ pub const Node = extern union {
.std_mem_zeroes,
.@"return",
.@"comptime",
.@"defer",
.asm_simple,
.discard,
.std_math_Log2Int,
@ -1020,6 +1022,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
},
});
},
.@"defer" => {
const payload = node.castTag(.@"defer").?.data;
return c.addNode(.{
.tag = .@"defer",
.main_token = try c.addToken(.keyword_defer, "defer"),
.data = .{
.lhs = undefined,
.rhs = try renderNode(c, payload),
},
});
},
.asm_simple => {
const payload = node.castTag(.asm_simple).?.data;
const asm_token = try c.addToken(.keyword_asm, "asm");
@ -2273,6 +2286,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.@"continue",
.@"return",
.@"comptime",
.@"defer",
.asm_simple,
.usingnamespace_builtins,
.while_true,

View File

@ -1784,6 +1784,14 @@ unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self,
return 0;
}
const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttribute(const struct ZigClangVarDecl *self) {
auto casted_self = reinterpret_cast<const clang::VarDecl *>(self);
if (const clang::CleanupAttr *CA = casted_self->getAttr<clang::CleanupAttr>()) {
return reinterpret_cast<const ZigClangFunctionDecl *>(CA->getFunctionDecl());
}
return nullptr;
}
unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) {
auto casted_self = reinterpret_cast<const clang::FieldDecl *>(self);
auto casted_ctx = const_cast<clang::ASTContext *>(reinterpret_cast<const clang::ASTContext *>(ctx));

View File

@ -997,6 +997,7 @@ ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCa
ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self);
ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self);
ZIG_EXTERN_C const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len);
ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttribute(const struct ZigClangVarDecl *self);
ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx);
ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);
ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);

View File

@ -1490,4 +1490,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
cases.add("__cleanup__ attribute",
\\#include <stdlib.h>
\\static int cleanup_count = 0;
\\void clean_up(int *final_value) {
\\ if (*final_value != cleanup_count++) abort();
\\}
\\void doit(void) {
\\ int a __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 2;
\\ int b __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 1;
\\ int c __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 0;
\\}
\\int main(void) {
\\ doit();
\\ if (cleanup_count != 3) abort();
\\ return 0;
\\}
, "");
}