authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-03-09 21:34:06+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-12 18:55:23+02:00
logc93e0d86187cb589d6726acd36f741f3d87a96be
tree3e812c1fcd520086b45cc22cbc890fb24f432b57
parent948926c513befd95dc1ff90fe05329245f1c81db

Sema: @extern fixes

* There was an edge case where the arena could be destroyed twice on error: once from the arena itself and once from the decl destruction. * The type of the created decl was incorrect (it should have been the pointer child type), but it's not required anyway, so it's now just initialized to anyopaque (which more accurately reflects what's actually at that memory, since e.g. [*]T may correspond to nothing). * A runtime bitcast of the pointer was performed, meaning @extern didn't work at comptime. This is unnecessary: the decl_ref can just be initialized with the correct pointer type.

5 files changed, 84 insertions(+), 29 deletions(-)

src/Sema.zig+30-29
...@@ -22287,7 +22287,6 @@ fn zirBuiltinExtern(...@@ -22287,7 +22287,6 @@ fn zirBuiltinExtern(
22287 extended: Zir.Inst.Extended.InstData,22287 extended: Zir.Inst.Extended.InstData,
22288) CompileError!Air.Inst.Ref {22288) CompileError!Air.Inst.Ref {
22289 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;22289 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
22290 const src = LazySrcLoc.nodeOffset(extra.node);
22291 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };22290 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
22292 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };22291 const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
2229322292
...@@ -22315,39 +22314,41 @@ fn zirBuiltinExtern(...@@ -22315,39 +22314,41 @@ fn zirBuiltinExtern(
22315 const new_decl = sema.mod.declPtr(new_decl_index);22314 const new_decl = sema.mod.declPtr(new_decl_index);
22316 new_decl.name = try sema.gpa.dupeZ(u8, options.name);22315 new_decl.name = try sema.gpa.dupeZ(u8, options.name);
2231722316
22318 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);22317 {
22319 errdefer new_decl_arena.deinit();22318 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
22320 const new_decl_arena_allocator = new_decl_arena.allocator();22319 errdefer new_decl_arena.deinit();
22320 const new_decl_arena_allocator = new_decl_arena.allocator();
2232122321
22322 const new_var = try new_decl_arena_allocator.create(Module.Var);22322 const new_var = try new_decl_arena_allocator.create(Module.Var);
22323 errdefer new_decl_arena_allocator.destroy(new_var);22323 new_var.* = .{
22324 .owner_decl = sema.owner_decl_index,
22325 .init = Value.initTag(.unreachable_value),
22326 .is_extern = true,
22327 .is_mutable = false,
22328 .is_threadlocal = options.is_thread_local,
22329 .is_weak_linkage = options.linkage == .Weak,
22330 .lib_name = null,
22331 };
2232422332
22325 new_var.* = .{22333 new_decl.src_line = sema.owner_decl.src_line;
22326 .owner_decl = sema.owner_decl_index,22334 // We only access this decl through the decl_ref with the correct type created
22327 .init = Value.initTag(.unreachable_value),22335 // below, so this type doesn't matter
22328 .is_extern = true,22336 new_decl.ty = Type.Tag.init(.anyopaque);
22329 .is_mutable = false,22337 new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var);
22330 .is_threadlocal = options.is_thread_local,22338 new_decl.@"align" = 0;
22331 .is_weak_linkage = options.linkage == .Weak,22339 new_decl.@"linksection" = null;
22332 .lib_name = null,22340 new_decl.has_tv = true;
22333 };22341 new_decl.analysis = .complete;
22342 new_decl.generation = sema.mod.generation;
2233422343
22335 new_decl.src_line = sema.owner_decl.src_line;22344 try new_decl.finalizeNewArena(&new_decl_arena);
22336 new_decl.ty = try ty.copy(new_decl_arena_allocator);22345 }
22337 new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var);
22338 new_decl.@"align" = 0;
22339 new_decl.@"linksection" = null;
22340 new_decl.has_tv = true;
22341 new_decl.analysis = .complete;
22342 new_decl.generation = sema.mod.generation;
2234322346
22344 const arena_state = try new_decl_arena_allocator.create(std.heap.ArenaAllocator.State);22347 try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
22345 arena_state.* = new_decl_arena.state;22348 try sema.ensureDeclAnalyzed(new_decl_index);
22346 new_decl.value_arena = arena_state;
2234722349
22348 const ref = try sema.analyzeDeclRef(new_decl_index);22350 const ref = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);
22349 try sema.requireRuntimeBlock(block, src, null);22351 return sema.addConstant(ty, ref);
22350 return block.addBitCast(ty, ref);
22351}22352}
2235222353
22353fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {22354fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
test/standalone.zig+1
...@@ -107,6 +107,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -107,6 +107,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
107 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});107 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
108 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});108 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
109 cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});109 cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});
110 cases.addBuildFile("test/standalone/extern/build.zig", .{});
110111
111 cases.addBuildFile("test/standalone/dep_diamond/build.zig", .{});112 cases.addBuildFile("test/standalone/dep_diamond/build.zig", .{});
112 cases.addBuildFile("test/standalone/dep_triangle/build.zig", .{});113 cases.addBuildFile("test/standalone/dep_triangle/build.zig", .{});
test/standalone/extern/build.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const obj = b.addObject(.{
7 .name = "exports",
8 .root_source_file = .{ .path = "exports.zig" },
9 .target = .{},
10 .optimize = optimize,
11 });
12 const main = b.addTest(.{
13 .root_source_file = .{ .path = "main.zig" },
14 .optimize = optimize,
15 });
16 main.addObject(obj);
17
18 const test_step = b.step("test", "Test it");
19 test_step.dependOn(&main.step);
20}
test/standalone/extern/exports.zig created+12
...@@ -0,0 +1,12 @@
1var hidden: u32 = 0;
2export fn updateHidden(val: u32) void {
3 hidden = val;
4}
5export fn getHidden() u32 {
6 return hidden;
7}
8
9const T = extern struct { x: u32 };
10
11export var mut_val: f64 = 1.23;
12export const const_val: T = .{ .x = 42 };
test/standalone/extern/main.zig created+21
...@@ -0,0 +1,21 @@
1const assert = @import("std").debug.assert;
2
3const updateHidden = @extern(*const fn (u32) callconv(.C) void, .{ .name = "updateHidden" });
4const getHidden = @extern(*const fn () callconv(.C) u32, .{ .name = "getHidden" });
5
6const T = extern struct { x: u32 };
7
8test {
9 var mut_val_ptr = @extern(*f64, .{ .name = "mut_val" });
10 var const_val_ptr = @extern(*const T, .{ .name = "const_val" });
11
12 assert(getHidden() == 0);
13 updateHidden(123);
14 assert(getHidden() == 123);
15
16 assert(mut_val_ptr.* == 1.23);
17 mut_val_ptr.* = 10.0;
18 assert(mut_val_ptr.* == 10.0);
19
20 assert(const_val_ptr.x == 42);
21}