aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2023-03-07 22:24:50 +0000
committerVeikka Tuominen <git@vexu.eu>2023-03-12 19:07:06 +0200
commita8bd55e0853f7f80c9cd843ec54813425e4276bc (patch)
tree43c45d380722b2f9b32a650d0b4e30a8d1788ff3 /src
parentc93e0d86187cb589d6726acd36f741f3d87a96be (diff)
downloadzig-a8bd55e0853f7f80c9cd843ec54813425e4276bc.tar.gz
zig-a8bd55e0853f7f80c9cd843ec54813425e4276bc.zip
translate-c: translate extern unknown-length arrays using @extern
Resolves: #14743
Diffstat (limited to 'src')
-rw-r--r--src/translate_c.zig16
-rw-r--r--src/translate_c/ast.zig28
2 files changed, 43 insertions, 1 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 5b2b1c2df5..698f750afb 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -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: {
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index 81a19eb39d..688235c2d3 100644
--- a/src/translate_c/ast.zig
+++ b/src/translate_c/ast.zig
@@ -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,