Commit a5c7742ba6
Changed files (8)
src
test
behavior
src/arch/wasm/CodeGen.zig
@@ -1037,7 +1037,7 @@ fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerErro
const offset = @intCast(u32, self.code.items.len);
const atom = &self.decl.link.wasm;
const target_sym_index = decl.link.wasm.sym_index;
- markDeclAlive(decl);
+ decl.markAlive();
if (decl.ty.zigTypeTag() == .Fn) {
// We found a function pointer, so add it to our table,
// as function pointers are not allowed to be stored inside the data section,
@@ -1935,7 +1935,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
try self.emitConstant(slice.data.len, Type.usize);
} else if (val.castTag(.decl_ref)) |payload| {
const decl = payload.data;
- markDeclAlive(decl);
+ decl.markAlive();
// Function pointers use a table index, rather than a memory address
if (decl.ty.zigTypeTag() == .Fn) {
const target_sym_index = decl.link.wasm.sym_index;
@@ -2101,19 +2101,6 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
}
}
-fn markDeclAlive(decl: *Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
-}
-
fn emitUndefined(self: *Self, ty: Type) InnerError!void {
switch (ty.zigTypeTag()) {
.Int => switch (ty.intInfo(self.target).bits) {
src/codegen/c.zig
@@ -215,7 +215,7 @@ pub const DeclGen = struct {
val: Value,
decl: *Decl,
) error{ OutOfMemory, AnalysisFail }!void {
- markDeclAlive(decl);
+ decl.markAlive();
if (ty.isSlice()) {
try writer.writeByte('(');
@@ -253,19 +253,6 @@ pub const DeclGen = struct {
try dg.renderDeclName(decl, writer);
}
- fn markDeclAlive(decl: *Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
- }
-
fn renderInt128(
writer: anytype,
int_val: anytype,
src/codegen/llvm.zig
@@ -1224,7 +1224,7 @@ pub const DeclGen = struct {
.decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
.variable => {
const decl = tv.val.castTag(.variable).?.data.owner_decl;
- dg.markDeclAlive(decl);
+ decl.markAlive();
const val = try dg.resolveGlobalDecl(decl);
const llvm_var_type = try dg.llvmType(tv.ty);
const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
@@ -1373,7 +1373,7 @@ pub const DeclGen = struct {
.function => tv.val.castTag(.function).?.data.owner_decl,
else => unreachable,
};
- dg.markDeclAlive(fn_decl);
+ fn_decl.markAlive();
return dg.resolveLlvmFunction(fn_decl);
},
.ErrorSet => {
@@ -1681,7 +1681,7 @@ pub const DeclGen = struct {
ptr_val: Value,
decl: *Module.Decl,
) Error!ParentPtr {
- dg.markDeclAlive(decl);
+ decl.markAlive();
var ptr_ty_payload: Type.Payload.ElemType = .{
.base = .{ .tag = .single_mut_pointer },
.data = decl.ty,
@@ -1763,7 +1763,7 @@ pub const DeclGen = struct {
return self.lowerPtrToVoid(tv.ty);
}
- self.markDeclAlive(decl);
+ decl.markAlive();
const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
try self.resolveLlvmFunction(decl)
@@ -1774,24 +1774,6 @@ pub const DeclGen = struct {
return llvm_val.constBitCast(llvm_type);
}
- fn markDeclAlive(dg: *DeclGen, decl: *Module.Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- log.debug("{*} ({s}) marked alive by {*} ({s})", .{
- decl, decl.name,
- dg.decl, dg.decl.name,
- });
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return dg.markDeclAlive(pointee);
- }
- }
-
fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*const llvm.Value {
const target = dg.module.getTarget();
const alignment = ptr_ty.ptrAlignment(target);
src/codegen.zig
@@ -464,7 +464,7 @@ fn lowerDeclRef(
}
if (decl.analysis != .complete) return error.AnalysisFail;
- markDeclAlive(decl);
+ decl.markAlive();
const vaddr = vaddr: {
if (bin_file.cast(link.File.MachO)) |macho_file| {
break :vaddr try macho_file.getDeclVAddrWithReloc(decl, code.items.len);
@@ -484,16 +484,3 @@ fn lowerDeclRef(
return Result{ .appended = {} };
}
-
-fn markDeclAlive(decl: *Module.Decl) void {
- if (decl.alive) return;
- decl.alive = true;
-
- // This is the first time we are marking this Decl alive. We must
- // therefore recurse into its value and mark any Decl it references
- // as also alive, so that any Decl referenced does not get garbage collected.
-
- if (decl.val.pointerDecl()) |pointee| {
- return markDeclAlive(pointee);
- }
-}
src/Module.zig
@@ -783,6 +783,16 @@ pub const Decl = struct {
return decl.ty.abiAlignment(target);
}
}
+
+ pub fn markAlive(decl: *Decl) void {
+ if (decl.alive) return;
+ decl.alive = true;
+
+ // This is the first time we are marking this Decl alive. We must
+ // therefore recurse into its value and mark any Decl it references
+ // as also alive, so that any Decl referenced does not get garbage collected.
+ decl.val.markReferencedDeclsAlive();
+ }
};
/// This state is attached to every Decl when Module emit_h is non-null.
src/value.zig
@@ -1746,6 +1746,55 @@ pub const Value = extern union {
};
}
+ pub fn markReferencedDeclsAlive(val: Value) void {
+ switch (val.tag()) {
+ .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),
+ .extern_fn, .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
+ .function => return val.castTag(.function).?.data.owner_decl.markAlive(),
+ .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),
+
+ .repeated,
+ .eu_payload,
+ .eu_payload_ptr,
+ .opt_payload,
+ .opt_payload_ptr,
+ .empty_array_sentinel,
+ => return markReferencedDeclsAlive(val.cast(Payload.SubValue).?.data),
+
+ .array => {
+ for (val.cast(Payload.Array).?.data) |elem_val| {
+ markReferencedDeclsAlive(elem_val);
+ }
+ },
+ .slice => {
+ const slice = val.cast(Payload.Slice).?.data;
+ markReferencedDeclsAlive(slice.ptr);
+ markReferencedDeclsAlive(slice.len);
+ },
+
+ .elem_ptr => {
+ const elem_ptr = val.cast(Payload.ElemPtr).?.data;
+ return markReferencedDeclsAlive(elem_ptr.array_ptr);
+ },
+ .field_ptr => {
+ const field_ptr = val.cast(Payload.FieldPtr).?.data;
+ return markReferencedDeclsAlive(field_ptr.container_ptr);
+ },
+ .@"struct" => {
+ for (val.cast(Payload.Struct).?.data) |field_val| {
+ markReferencedDeclsAlive(field_val);
+ }
+ },
+ .@"union" => {
+ const data = val.cast(Payload.Union).?.data;
+ markReferencedDeclsAlive(data.tag);
+ markReferencedDeclsAlive(data.val);
+ },
+
+ else => {},
+ }
+ }
+
pub fn slicePtr(val: Value) Value {
return switch (val.tag()) {
.slice => val.castTag(.slice).?.data.ptr,
test/behavior/array_llvm.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const testing = std.testing;
const expect = testing.expect;
+const mem = std.mem;
var s_array: [8]Sub = undefined;
const Sub = struct { b: u8 };
@@ -87,3 +88,81 @@ test "array literal as argument to function" {
try S.entry(2);
comptime try S.entry(2);
}
+
+test "double nested array to const slice cast in array literal" {
+ const S = struct {
+ fn entry(two: i32) !void {
+ const cases = [_][]const []const i32{
+ &[_][]const i32{&[_]i32{1}},
+ &[_][]const i32{&[_]i32{ 2, 3 }},
+ &[_][]const i32{
+ &[_]i32{4},
+ &[_]i32{ 5, 6, 7 },
+ },
+ };
+ try check(&cases);
+
+ const cases2 = [_][]const i32{
+ &[_]i32{1},
+ &[_]i32{ two, 3 },
+ };
+ try expect(cases2.len == 2);
+ try expect(cases2[0].len == 1);
+ try expect(cases2[0][0] == 1);
+ try expect(cases2[1].len == 2);
+ try expect(cases2[1][0] == 2);
+ try expect(cases2[1][1] == 3);
+
+ const cases3 = [_][]const []const i32{
+ &[_][]const i32{&[_]i32{1}},
+ &[_][]const i32{&[_]i32{ two, 3 }},
+ &[_][]const i32{
+ &[_]i32{4},
+ &[_]i32{ 5, 6, 7 },
+ },
+ };
+ try check(&cases3);
+ }
+
+ fn check(cases: []const []const []const i32) !void {
+ try expect(cases.len == 3);
+ try expect(cases[0].len == 1);
+ try expect(cases[0][0].len == 1);
+ try expect(cases[0][0][0] == 1);
+ try expect(cases[1].len == 1);
+ try expect(cases[1][0].len == 2);
+ try expect(cases[1][0][0] == 2);
+ try expect(cases[1][0][1] == 3);
+ try expect(cases[2].len == 2);
+ try expect(cases[2][0].len == 1);
+ try expect(cases[2][0][0] == 4);
+ try expect(cases[2][1].len == 3);
+ try expect(cases[2][1][0] == 5);
+ try expect(cases[2][1][1] == 6);
+ try expect(cases[2][1][2] == 7);
+ }
+ };
+ try S.entry(2);
+ comptime try S.entry(2);
+}
+
+test "anonymous literal in array" {
+ const S = struct {
+ const Foo = struct {
+ a: usize = 2,
+ b: usize = 4,
+ };
+ fn doTheTest() !void {
+ var array: [2]Foo = .{
+ .{ .a = 3 },
+ .{ .b = 3 },
+ };
+ try expect(array[0].a == 3);
+ try expect(array[0].b == 4);
+ try expect(array[1].a == 2);
+ try expect(array[1].b == 3);
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
test/behavior/array_stage1.zig
@@ -4,84 +4,6 @@ const mem = std.mem;
const expect = testing.expect;
const expectEqual = testing.expectEqual;
-test "double nested array to const slice cast in array literal" {
- const S = struct {
- fn entry(two: i32) !void {
- const cases = [_][]const []const i32{
- &[_][]const i32{&[_]i32{1}},
- &[_][]const i32{&[_]i32{ 2, 3 }},
- &[_][]const i32{
- &[_]i32{4},
- &[_]i32{ 5, 6, 7 },
- },
- };
- try check(&cases);
-
- const cases2 = [_][]const i32{
- &[_]i32{1},
- &[_]i32{ two, 3 },
- };
- try expect(cases2.len == 2);
- try expect(cases2[0].len == 1);
- try expect(cases2[0][0] == 1);
- try expect(cases2[1].len == 2);
- try expect(cases2[1][0] == 2);
- try expect(cases2[1][1] == 3);
-
- const cases3 = [_][]const []const i32{
- &[_][]const i32{&[_]i32{1}},
- &[_][]const i32{&[_]i32{ two, 3 }},
- &[_][]const i32{
- &[_]i32{4},
- &[_]i32{ 5, 6, 7 },
- },
- };
- try check(&cases3);
- }
-
- fn check(cases: []const []const []const i32) !void {
- try expect(cases.len == 3);
- try expect(cases[0].len == 1);
- try expect(cases[0][0].len == 1);
- try expect(cases[0][0][0] == 1);
- try expect(cases[1].len == 1);
- try expect(cases[1][0].len == 2);
- try expect(cases[1][0][0] == 2);
- try expect(cases[1][0][1] == 3);
- try expect(cases[2].len == 2);
- try expect(cases[2][0].len == 1);
- try expect(cases[2][0][0] == 4);
- try expect(cases[2][1].len == 3);
- try expect(cases[2][1][0] == 5);
- try expect(cases[2][1][1] == 6);
- try expect(cases[2][1][2] == 7);
- }
- };
- try S.entry(2);
- comptime try S.entry(2);
-}
-
-test "anonymous literal in array" {
- const S = struct {
- const Foo = struct {
- a: usize = 2,
- b: usize = 4,
- };
- fn doTheTest() !void {
- var array: [2]Foo = .{
- .{ .a = 3 },
- .{ .b = 3 },
- };
- try expect(array[0].a == 3);
- try expect(array[0].b == 4);
- try expect(array[1].a == 2);
- try expect(array[1].b == 3);
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
test "access the null element of a null terminated array" {
const S = struct {
fn doTheTest() !void {
@@ -100,9 +22,9 @@ test "type deduction for array subscript expression" {
fn doTheTest() !void {
var array = [_]u8{ 0x55, 0xAA };
var v0 = true;
- try expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]);
+ try expect(@as(u8, 0xAA) == array[if (v0) 1 else 0]);
var v1 = false;
- try expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]);
+ try expect(@as(u8, 0x55) == array[if (v1) 1 else 0]);
}
};
try S.doTheTest();
@@ -119,9 +41,9 @@ test "sentinel element count towards the ABI size calculation" {
};
var x = T{};
var as_slice = mem.asBytes(&x);
- try expectEqual(@as(usize, 3), as_slice.len);
- try expectEqual(@as(u8, 0x55), as_slice[0]);
- try expectEqual(@as(u8, 0xAA), as_slice[2]);
+ try expect(@as(usize, 3) == as_slice.len);
+ try expect(@as(u8, 0x55) == as_slice[0]);
+ try expect(@as(u8, 0xAA) == as_slice[2]);
}
};
@@ -144,7 +66,7 @@ test "zero-sized array with recursive type definition" {
};
var t: S = .{ .list = .{ .s = undefined } };
- try expectEqual(@as(usize, 0), t.list.x);
+ try expect(@as(usize, 0) == t.list.x);
}
test "type coercion of anon struct literal to array" {