From 1273bc277f7274683db5041d8b41d91903e3045e Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 18 May 2021 21:59:45 -0700 Subject: [PATCH] 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 --- src/clang.zig | 3 +++ src/translate_c.zig | 16 ++++++++++++++++ src/translate_c/ast.zig | 14 ++++++++++++++ src/zig_clang.cpp | 8 ++++++++ src/zig_clang.h | 1 + test/run_translated_c.zig | 18 ++++++++++++++++++ 6 files changed, 60 insertions(+) diff --git a/src/clang.zig b/src/clang.zig index b9e152aef4..2b7d8c475d 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -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; }; diff --git a/src/translate_c.zig b/src/translate_c.zig index 2af91f992f..546a110c15 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -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)); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 1c7e7de1ac..60b1b6f93d 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -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, diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index bf6e09d8c0..de29c3cda7 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -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(self); + if (const clang::CleanupAttr *CA = casted_self->getAttr()) { + return reinterpret_cast(CA->getFunctionDecl()); + } + return nullptr; +} + unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) { auto casted_self = reinterpret_cast(self); auto casted_ctx = const_cast(reinterpret_cast(ctx)); diff --git a/src/zig_clang.h b/src/zig_clang.h index b015340c29..28996d73b7 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -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); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 250f7e67bc..aa71a86688 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1490,4 +1490,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("__cleanup__ attribute", + \\#include + \\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; + \\} + , ""); }