| author | |
| committer | |
| log | 1273bc277f7274683db5041d8b41d91903e3045e |
| tree | 11735aca89cbdb87ad30410763271ecfee8d902c |
| parent | 28a89b9ebc471fa65815c8061dce979d25f3e499 |
Use a `defer` statement to implement the C __cleanup__ attribute.
See https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html6 files changed, 60 insertions(+), 0 deletions(-)
src/clang.zig+3| ... | ... | @@ -976,6 +976,9 @@ pub const VarDecl = opaque { |
| 976 | 976 | pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute; |
| 977 | 977 | extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint; |
| 978 | 978 | |
| 979 | pub const getCleanupAttribute = ZigClangVarDecl_getCleanupAttribute; | |
| 980 | extern fn ZigClangVarDecl_getCleanupAttribute(*const VarDecl) ?*const FunctionDecl; | |
| 981 | ||
| 979 | 982 | pub const getTypeSourceInfo_getType = ZigClangVarDecl_getTypeSourceInfo_getType; |
| 980 | 983 | extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType; |
| 981 | 984 | }; |
src/translate_c.zig+16| ... | ... | @@ -1656,6 +1656,22 @@ fn transDeclStmtOne( |
| 1656 | 1656 | .init = init_node, |
| 1657 | 1657 | }); |
| 1658 | 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 | 1676 | .Typedef => { |
| 1661 | 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 | 67 | @"struct", |
| 68 | 68 | @"union", |
| 69 | 69 | @"comptime", |
| 70 | @"defer", | |
| 70 | 71 | array_init, |
| 71 | 72 | tuple, |
| 72 | 73 | container_init, |
| ... | ... | @@ -247,6 +248,7 @@ pub const Node = extern union { |
| 247 | 248 | .std_mem_zeroes, |
| 248 | 249 | .@"return", |
| 249 | 250 | .@"comptime", |
| 251 | .@"defer", | |
| 250 | 252 | .asm_simple, |
| 251 | 253 | .discard, |
| 252 | 254 | .std_math_Log2Int, |
| ... | ... | @@ -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 | 1036 | .asm_simple => { |
| 1024 | 1037 | const payload = node.castTag(.asm_simple).?.data; |
| 1025 | 1038 | const asm_token = try c.addToken(.keyword_asm, "asm"); |
| ... | ... | @@ -2273,6 +2286,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2273 | 2286 | .@"continue", |
| 2274 | 2287 | .@"return", |
| 2275 | 2288 | .@"comptime", |
| 2289 | .@"defer", | |
| 2276 | 2290 | .asm_simple, |
| 2277 | 2291 | .usingnamespace_builtins, |
| 2278 | 2292 | .while_true, |
src/zig_clang.cpp+8| ... | ... | @@ -1784,6 +1784,14 @@ unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, |
| 1784 | 1784 | return 0; |
| 1785 | 1785 | } |
| 1786 | 1786 | |
| 1787 | const 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 | ||
| 1787 | 1795 | unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) { |
| 1788 | 1796 | auto casted_self = reinterpret_cast<const clang::FieldDecl *>(self); |
| 1789 | 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 | 997 | ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self); |
| 998 | 998 | ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self); |
| 999 | 999 | ZIG_EXTERN_C const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len); |
| 1000 | ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttribute(const struct ZigClangVarDecl *self); | |
| 1000 | 1001 | ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx); |
| 1001 | 1002 | ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx); |
| 1002 | 1003 | ZIG_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 | 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 | } |