diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 3eb2d64005..2336ab2963 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -764,6 +764,7 @@ pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnu pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; pub extern fn ZigClangFunctionDecl_getCanonicalDecl(self: ?*const struct_ZigClangFunctionDecl) ?*const struct_ZigClangFunctionDecl; pub extern fn ZigClangVarDecl_getCanonicalDecl(self: ?*const struct_ZigClangVarDecl) ?*const struct_ZigClangVarDecl; +pub extern fn ZigClangVarDecl_getSectionAttribute(self: *const ZigClangVarDecl, len: *usize) ?[*]const u8; pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl; pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl; pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation; @@ -834,6 +835,7 @@ pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDec pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt; pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool; pub extern fn ZigClangFunctionDecl_isInlineSpecified(self: *const ZigClangFunctionDecl) bool; +pub extern fn ZigClangFunctionDecl_getSectionAttribute(self: *const ZigClangFunctionDecl, len: *usize) ?[*]const u8; pub extern fn ZigClangBuiltinType_getKind(self: *const struct_ZigClangBuiltinType) ZigClangBuiltinTypeKind; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index b49989732e..e4f24e4cf6 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -581,6 +581,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { return failDecl(c, var_decl_loc, checked_name, "non-extern variable has no initializer", .{}); } + const linksection_expr = blk: { + var str_len: usize = undefined; + if (ZigClangVarDecl_getSectionAttribute(var_decl, &str_len)) |str_ptr| { + _ = try appendToken(rp.c, .Keyword_linksection, "linksection"); + _ = try appendToken(rp.c, .LParen, "("); + const expr = try transCreateNodeStringLiteral( + rp.c, + try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}), + ); + _ = try appendToken(rp.c, .RParen, ")"); + + break :blk expr; + } + break :blk null; + }; + const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ .doc_comments = null, @@ -594,7 +610,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { .lib_name = null, .type_node = type_node, .align_node = null, - .section_node = null, + .section_node = linksection_expr, .init_node = init_node, .semicolon_token = try appendToken(c, .Semicolon, ";"), }; @@ -3575,6 +3591,14 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { return &node.base; } +fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node { + const node = try c.a().create(ast.Node.StringLiteral); + node.* = .{ + .token = try appendToken(c, .StringLiteral, str), + }; + return &node.base; +} + fn transCreateNodeIf(c: *Context) !*ast.Node.If { const if_tok = try appendToken(c, .Keyword_if, "if"); _ = try appendToken(c, .LParen, "("); @@ -4048,8 +4072,8 @@ fn finishTransFnProto( const noalias_tok = if (ZigClangQualType_isRestrictQualified(param_qt)) try appendToken(rp.c, .Keyword_noalias, "noalias") else null; const param_name_tok: ?ast.TokenIndex = blk: { - if (fn_decl != null) { - const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i)); + if (fn_decl) |decl| { + const param = ZigClangFunctionDecl_getParamDecl(decl, @intCast(c_uint, i)); const param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); if (param_name.len < 1) break :blk null; @@ -4100,6 +4124,24 @@ fn finishTransFnProto( const rparen_tok = try appendToken(rp.c, .RParen, ")"); + const linksection_expr = blk: { + if (fn_decl) |decl| { + var str_len: usize = undefined; + if (ZigClangFunctionDecl_getSectionAttribute(decl, &str_len)) |str_ptr| { + _ = try appendToken(rp.c, .Keyword_linksection, "linksection"); + _ = try appendToken(rp.c, .LParen, "("); + const expr = try transCreateNodeStringLiteral( + rp.c, + try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}), + ); + _ = try appendToken(rp.c, .RParen, ")"); + + break :blk expr; + } + } + break :blk null; + }; + const return_type_node = blk: { if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { break :blk try transCreateNodeIdentifier(rp.c, "noreturn"); @@ -4134,7 +4176,7 @@ fn finishTransFnProto( .body_node = null, .lib_name = null, .align_expr = null, - .section_expr = null, + .section_expr = linksection_expr, }; return fn_proto; } diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index ba25d365f7..cf839d16c8 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -1582,6 +1582,16 @@ const ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *s return reinterpret_cast(decl); } +const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len) { + auto casted = reinterpret_cast(self); + if (const clang::SectionAttr *SA = casted->getAttr()) { + llvm::StringRef str_ref = SA->getName(); + *len = str_ref.size(); + return (const char *)str_ref.bytes_begin(); + } + return nullptr; +} + const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) { const clang::RecordDecl *record_decl = reinterpret_cast(zig_record_decl); const clang::RecordDecl *definition = record_decl->getDefinition(); @@ -1696,6 +1706,16 @@ bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *s return casted->isInlineSpecified(); } +const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *self, size_t *len) { + auto casted = reinterpret_cast(self); + if (const clang::SectionAttr *SA = casted->getAttr()) { + llvm::StringRef str_ref = SA->getName(); + *len = str_ref.size(); + return (const char *)str_ref.bytes_begin(); + } + return nullptr; +} + const ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const ZigClangTypedefType *self) { auto casted = reinterpret_cast(self); const clang::TypedefNameDecl *name_decl = casted->getDecl(); diff --git a/src/zig_clang.h b/src/zig_clang.h index 734eea48b5..d5bd3e4d5b 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -858,6 +858,7 @@ ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(con ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *); 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 ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *); ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *); @@ -875,6 +876,7 @@ ZIG_EXTERN_C const struct ZigClangParmVarDecl *ZigClangFunctionDecl_getParamDecl ZIG_EXTERN_C const struct ZigClangStmt *ZigClangFunctionDecl_getBody(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C const char* ZigClangFunctionDecl_getSectionAttribute(const struct ZigClangFunctionDecl *, size_t *); ZIG_EXTERN_C bool ZigClangRecordDecl_isUnion(const struct ZigClangRecordDecl *record_decl); ZIG_EXTERN_C bool ZigClangRecordDecl_isStruct(const struct ZigClangRecordDecl *record_decl); diff --git a/test/translate_c.zig b/test/translate_c.zig index ab6dcf9f02..e9e0bb83ba 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -2,7 +2,6 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.TranslateCContext) void { - /////////////// Cases that pass for both stage1/stage2 //////////////// cases.add("simple ptrCast for casts between opaque types", \\struct opaque; \\struct opaque_2; @@ -18,6 +17,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add("linksection() attribute", + \\__attribute__ ((__section__(".data"))) + \\extern char my_array[16]; + \\__attribute__ ((__section__(".data"))) + \\void my_fn(void) { } + , &[_][]const u8{ + \\pub extern var my_array: [16]u8 linksection(".data"); + \\pub export fn my_fn() linksection(".data") void {} + }); + cases.add("simple function prototypes", \\void __attribute__((noreturn)) foo(void); \\int bar(void);