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

Resolves: #14743
This commit is contained in:
mlugg 2023-03-07 22:24:50 +00:00 committed by Veikka Tuominen
parent c93e0d8618
commit a8bd55e085
3 changed files with 51 additions and 1 deletions

View File

@ -784,9 +784,9 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
const qual_type = var_decl.getTypeSourceInfo_getType();
const storage_class = var_decl.getStorageClass();
const is_const = qual_type.isConstQualified();
const has_init = var_decl.hasInit();
const decl_init = var_decl.getInit();
var is_const = qual_type.isConstQualified();
// In C extern variables with initializers behave like Zig exports.
// extern int foo = 2;
@ -843,6 +843,20 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
// std.mem.zeroes(T)
init_node = try Tag.std_mem_zeroes.create(c.arena, type_node);
} else if (qual_type.getTypeClass() == .IncompleteArray) {
// Oh no, an extern array of unknown size! These are really fun because there's no
// direct equivalent in Zig. To translate correctly, we'll have to create a C-pointer
// to the data initialized via @extern.
const name_str = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{var_name});
init_node = try Tag.builtin_extern.create(c.arena, .{
.type = type_node,
.name = try Tag.string_literal.create(c.arena, name_str),
});
// Since this is really a pointer to the underlying data, we tweak a few properties.
is_extern = false;
is_const = true;
}
const linksection_string = blk: {

View File

@ -158,6 +158,8 @@ pub const Node = extern union {
vector_zero_init,
/// @shuffle(type, a, b, mask)
shuffle,
/// @extern(ty, .{ .name = n })
builtin_extern,
/// @import("std").zig.c_translation.MacroArithmetic.<op>(lhs, rhs)
macro_arithmetic,
@ -373,6 +375,7 @@ pub const Node = extern union {
.field_access => Payload.FieldAccess,
.string_slice => Payload.StringSlice,
.shuffle => Payload.Shuffle,
.builtin_extern => Payload.Extern,
.macro_arithmetic => Payload.MacroArithmetic,
};
}
@ -718,6 +721,14 @@ pub const Payload = struct {
},
};
pub const Extern = struct {
base: Payload,
data: struct {
type: Node,
name: Node,
},
};
pub const MacroArithmetic = struct {
base: Payload,
data: struct {
@ -1409,6 +1420,22 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
payload.mask_vector,
});
},
.builtin_extern => {
const payload = node.castTag(.builtin_extern).?.data;
var info_inits: [1]Payload.ContainerInitDot.Initializer = .{
.{ .name = "name", .value = payload.name },
};
var info_payload: Payload.ContainerInitDot = .{
.base = .{ .tag = .container_init_dot },
.data = &info_inits,
};
return renderBuiltinCall(c, "@extern", &.{
payload.type,
.{ .ptr_otherwise = &info_payload.base },
});
},
.macro_arithmetic => {
const payload = node.castTag(.macro_arithmetic).?.data;
const op = @tagName(payload.op);
@ -2348,6 +2375,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.div_exact,
.offset_of,
.shuffle,
.builtin_extern,
.static_local_var,
.mut_str,
.macro_arithmetic,

View File

@ -3948,4 +3948,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
}
cases.add("extern array of unknown length",
\\extern int foo[];
, &[_][]const u8{
\\const foo: [*c]c_int = @extern([*c]c_int, .{
\\ .name = "foo",
\\});
});
}