authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-03-07 22:24:50+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-12 19:07:06+02:00
loga8bd55e0853f7f80c9cd843ec54813425e4276bc
tree43c45d380722b2f9b32a650d0b4e30a8d1788ff3
parentc93e0d86187cb589d6726acd36f741f3d87a96be

translate-c: translate extern unknown-length arrays using @extern

Resolves: #14743

3 files changed, 51 insertions(+), 1 deletions(-)

src/translate_c.zig+15-1
...@@ -784,9 +784,9 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -784,9 +784,9 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
784784
785 const qual_type = var_decl.getTypeSourceInfo_getType();785 const qual_type = var_decl.getTypeSourceInfo_getType();
786 const storage_class = var_decl.getStorageClass();786 const storage_class = var_decl.getStorageClass();
787 const is_const = qual_type.isConstQualified();
788 const has_init = var_decl.hasInit();787 const has_init = var_decl.hasInit();
789 const decl_init = var_decl.getInit();788 const decl_init = var_decl.getInit();
789 var is_const = qual_type.isConstQualified();
790790
791 // In C extern variables with initializers behave like Zig exports.791 // In C extern variables with initializers behave like Zig exports.
792 // extern int foo = 2;792 // extern int foo = 2;
...@@ -843,6 +843,20 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -843,6 +843,20 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
843843
844 // std.mem.zeroes(T)844 // std.mem.zeroes(T)
845 init_node = try Tag.std_mem_zeroes.create(c.arena, type_node);845 init_node = try Tag.std_mem_zeroes.create(c.arena, type_node);
846 } else if (qual_type.getTypeClass() == .IncompleteArray) {
847 // Oh no, an extern array of unknown size! These are really fun because there's no
848 // direct equivalent in Zig. To translate correctly, we'll have to create a C-pointer
849 // to the data initialized via @extern.
850
851 const name_str = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{var_name});
852 init_node = try Tag.builtin_extern.create(c.arena, .{
853 .type = type_node,
854 .name = try Tag.string_literal.create(c.arena, name_str),
855 });
856
857 // Since this is really a pointer to the underlying data, we tweak a few properties.
858 is_extern = false;
859 is_const = true;
846 }860 }
847861
848 const linksection_string = blk: {862 const linksection_string = blk: {
src/translate_c/ast.zig+28
...@@ -158,6 +158,8 @@ pub const Node = extern union {...@@ -158,6 +158,8 @@ pub const Node = extern union {
158 vector_zero_init,158 vector_zero_init,
159 /// @shuffle(type, a, b, mask)159 /// @shuffle(type, a, b, mask)
160 shuffle,160 shuffle,
161 /// @extern(ty, .{ .name = n })
162 builtin_extern,
161163
162 /// @import("std").zig.c_translation.MacroArithmetic.<op>(lhs, rhs)164 /// @import("std").zig.c_translation.MacroArithmetic.<op>(lhs, rhs)
163 macro_arithmetic,165 macro_arithmetic,
...@@ -373,6 +375,7 @@ pub const Node = extern union {...@@ -373,6 +375,7 @@ pub const Node = extern union {
373 .field_access => Payload.FieldAccess,375 .field_access => Payload.FieldAccess,
374 .string_slice => Payload.StringSlice,376 .string_slice => Payload.StringSlice,
375 .shuffle => Payload.Shuffle,377 .shuffle => Payload.Shuffle,
378 .builtin_extern => Payload.Extern,
376 .macro_arithmetic => Payload.MacroArithmetic,379 .macro_arithmetic => Payload.MacroArithmetic,
377 };380 };
378 }381 }
...@@ -718,6 +721,14 @@ pub const Payload = struct {...@@ -718,6 +721,14 @@ pub const Payload = struct {
718 },721 },
719 };722 };
720723
724 pub const Extern = struct {
725 base: Payload,
726 data: struct {
727 type: Node,
728 name: Node,
729 },
730 };
731
721 pub const MacroArithmetic = struct {732 pub const MacroArithmetic = struct {
722 base: Payload,733 base: Payload,
723 data: struct {734 data: struct {
...@@ -1409,6 +1420,22 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1409,6 +1420,22 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1409 payload.mask_vector,1420 payload.mask_vector,
1410 });1421 });
1411 },1422 },
1423 .builtin_extern => {
1424 const payload = node.castTag(.builtin_extern).?.data;
1425
1426 var info_inits: [1]Payload.ContainerInitDot.Initializer = .{
1427 .{ .name = "name", .value = payload.name },
1428 };
1429 var info_payload: Payload.ContainerInitDot = .{
1430 .base = .{ .tag = .container_init_dot },
1431 .data = &info_inits,
1432 };
1433
1434 return renderBuiltinCall(c, "@extern", &.{
1435 payload.type,
1436 .{ .ptr_otherwise = &info_payload.base },
1437 });
1438 },
1412 .macro_arithmetic => {1439 .macro_arithmetic => {
1413 const payload = node.castTag(.macro_arithmetic).?.data;1440 const payload = node.castTag(.macro_arithmetic).?.data;
1414 const op = @tagName(payload.op);1441 const op = @tagName(payload.op);
...@@ -2348,6 +2375,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2348,6 +2375,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2348 .div_exact,2375 .div_exact,
2349 .offset_of,2376 .offset_of,
2350 .shuffle,2377 .shuffle,
2378 .builtin_extern,
2351 .static_local_var,2379 .static_local_var,
2352 .mut_str,2380 .mut_str,
2353 .macro_arithmetic,2381 .macro_arithmetic,
test/translate_c.zig+8
...@@ -3948,4 +3948,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3948,4 +3948,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3948 \\}3948 \\}
3949 });3949 });
3950 }3950 }
3951
3952 cases.add("extern array of unknown length",
3953 \\extern int foo[];
3954 , &[_][]const u8{
3955 \\const foo: [*c]c_int = @extern([*c]c_int, .{
3956 \\ .name = "foo",
3957 \\});
3958 });
3951}3959}