authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-05-18 21:59:45-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-05-19 12:12:18+03:00
log1273bc277f7274683db5041d8b41d91903e3045e
tree11735aca89cbdb87ad30410763271ecfee8d902c
parent28a89b9ebc471fa65815c8061dce979d25f3e499

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

6 files changed, 60 insertions(+), 0 deletions(-)

src/clang.zig+3
...@@ -976,6 +976,9 @@ pub const VarDecl = opaque {...@@ -976,6 +976,9 @@ pub const VarDecl = opaque {
976 pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute;976 pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute;
977 extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint;977 extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint;
978978
979 pub const getCleanupAttribute = ZigClangVarDecl_getCleanupAttribute;
980 extern fn ZigClangVarDecl_getCleanupAttribute(*const VarDecl) ?*const FunctionDecl;
981
979 pub const getTypeSourceInfo_getType = ZigClangVarDecl_getTypeSourceInfo_getType;982 pub const getTypeSourceInfo_getType = ZigClangVarDecl_getTypeSourceInfo_getType;
980 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;983 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;
981};984};
src/translate_c.zig+16
...@@ -1656,6 +1656,22 @@ fn transDeclStmtOne(...@@ -1656,6 +1656,22 @@ fn transDeclStmtOne(
1656 .init = init_node,1656 .init = init_node,
1657 });1657 });
1658 try block_scope.statements.append(node);1658 try block_scope.statements.append(node);
1659
1660 const cleanup_attr = var_decl.getCleanupAttribute();
1661 if (cleanup_attr) |fn_decl| {
1662 const cleanup_fn_name = try c.str(@ptrCast(*const clang.NamedDecl, fn_decl).getName_bytes_begin());
1663 const fn_id = try Tag.identifier.create(c.arena, cleanup_fn_name);
1664
1665 const varname = try Tag.identifier.create(c.arena, mangled_name);
1666 const args = try c.arena.alloc(Node, 1);
1667 args[0] = try Tag.address_of.create(c.arena, varname);
1668
1669 const cleanup_call = try Tag.call.create(c.arena, .{ .lhs = fn_id, .args = args });
1670 const discard = try Tag.discard.create(c.arena, cleanup_call);
1671 const deferred_cleanup = try Tag.@"defer".create(c.arena, discard);
1672
1673 try block_scope.statements.append(deferred_cleanup);
1674 }
1659 },1675 },
1660 .Typedef => {1676 .Typedef => {
1661 try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));1677 try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));
src/translate_c/ast.zig+14
...@@ -67,6 +67,7 @@ pub const Node = extern union {...@@ -67,6 +67,7 @@ pub const Node = extern union {
67 @"struct",67 @"struct",
68 @"union",68 @"union",
69 @"comptime",69 @"comptime",
70 @"defer",
70 array_init,71 array_init,
71 tuple,72 tuple,
72 container_init,73 container_init,
...@@ -247,6 +248,7 @@ pub const Node = extern union {...@@ -247,6 +248,7 @@ pub const Node = extern union {
247 .std_mem_zeroes,248 .std_mem_zeroes,
248 .@"return",249 .@"return",
249 .@"comptime",250 .@"comptime",
251 .@"defer",
250 .asm_simple,252 .asm_simple,
251 .discard,253 .discard,
252 .std_math_Log2Int,254 .std_math_Log2Int,
...@@ -1020,6 +1022,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1020,6 +1022,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1020 },1022 },
1021 });1023 });
1022 },1024 },
1025 .@"defer" => {
1026 const payload = node.castTag(.@"defer").?.data;
1027 return c.addNode(.{
1028 .tag = .@"defer",
1029 .main_token = try c.addToken(.keyword_defer, "defer"),
1030 .data = .{
1031 .lhs = undefined,
1032 .rhs = try renderNode(c, payload),
1033 },
1034 });
1035 },
1023 .asm_simple => {1036 .asm_simple => {
1024 const payload = node.castTag(.asm_simple).?.data;1037 const payload = node.castTag(.asm_simple).?.data;
1025 const asm_token = try c.addToken(.keyword_asm, "asm");1038 const asm_token = try c.addToken(.keyword_asm, "asm");
...@@ -2273,6 +2286,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2273,6 +2286,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2273 .@"continue",2286 .@"continue",
2274 .@"return",2287 .@"return",
2275 .@"comptime",2288 .@"comptime",
2289 .@"defer",
2276 .asm_simple,2290 .asm_simple,
2277 .usingnamespace_builtins,2291 .usingnamespace_builtins,
2278 .while_true,2292 .while_true,
src/zig_clang.cpp+8
...@@ -1784,6 +1784,14 @@ unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self,...@@ -1784,6 +1784,14 @@ unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self,
1784 return 0;1784 return 0;
1785}1785}
17861786
1787const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttribute(const struct ZigClangVarDecl *self) {
1788 auto casted_self = reinterpret_cast<const clang::VarDecl *>(self);
1789 if (const clang::CleanupAttr *CA = casted_self->getAttr<clang::CleanupAttr>()) {
1790 return reinterpret_cast<const ZigClangFunctionDecl *>(CA->getFunctionDecl());
1791 }
1792 return nullptr;
1793}
1794
1787unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) {1795unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) {
1788 auto casted_self = reinterpret_cast<const clang::FieldDecl *>(self);1796 auto casted_self = reinterpret_cast<const clang::FieldDecl *>(self);
1789 auto casted_ctx = const_cast<clang::ASTContext *>(reinterpret_cast<const clang::ASTContext *>(ctx));1797 auto casted_ctx = const_cast<clang::ASTContext *>(reinterpret_cast<const clang::ASTContext *>(ctx));
src/zig_clang.h+1
...@@ -997,6 +997,7 @@ ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCa...@@ -997,6 +997,7 @@ ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCa
997ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self);997ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self);
998ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self);998ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self);
999ZIG_EXTERN_C const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len);999ZIG_EXTERN_C const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len);
1000ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttribute(const struct ZigClangVarDecl *self);
1000ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx);1001ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx);
1001ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);1002ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);
1002ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);1003ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);
test/run_translated_c.zig+18
...@@ -1490,4 +1490,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1490,4 +1490,22 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1490 \\ return 0;1490 \\ return 0;
1491 \\}1491 \\}
1492 , "");1492 , "");
1493
1494 cases.add("__cleanup__ attribute",
1495 \\#include <stdlib.h>
1496 \\static int cleanup_count = 0;
1497 \\void clean_up(int *final_value) {
1498 \\ if (*final_value != cleanup_count++) abort();
1499 \\}
1500 \\void doit(void) {
1501 \\ int a __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 2;
1502 \\ int b __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 1;
1503 \\ int c __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 0;
1504 \\}
1505 \\int main(void) {
1506 \\ doit();
1507 \\ if (cleanup_count != 3) abort();
1508 \\ return 0;
1509 \\}
1510 , "");
1493}1511}