diff --git a/src/Sema.zig b/src/Sema.zig index af3e3700d7..2c404c476e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22368,7 +22368,10 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData try sema.requireRuntimeBlock(block, src, operand_src); const err_int_ty = try mod.errorIntType(); - if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) { + if (block.wantSafety() and !dest_ty.isAnyError(mod) and + dest_ty.toIntern() != .adhoc_inferred_error_set_type and + sema.mod.backendSupportsFeature(.error_set_has_value)) + { if (dest_tag == .ErrorUnion) { const err_code = try sema.analyzeErrUnionCode(block, operand_src, operand); const err_int = try block.addBitCast(err_int_ty, err_code); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index f01c27042b..5cbcf6b3d6 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -8694,10 +8694,10 @@ pub const FuncGen = struct { if (!result_is_ref) { return self.dg.todo("implement bitcast vector to non-ref array", .{}); } - const array_ptr = try self.buildAllocaWorkaround(inst_ty, .default); + const alignment = inst_ty.abiAlignment(mod).toLlvm(); + const array_ptr = try self.buildAllocaWorkaround(inst_ty, alignment); const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; if (bitcast_ok) { - const alignment = inst_ty.abiAlignment(mod).toLlvm(); _ = try self.wip.store(.normal, operand, array_ptr, alignment); } else { // If the ABI size of the element type is not evenly divisible by size in bits; diff --git a/src/value.zig b/src/value.zig index 1de0f66717..69ddb56b8f 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1550,6 +1550,8 @@ pub const Value = struct { }, .ptr => |ptr| switch (ptr.addr) { .eu_payload, .opt_payload => |base| Value.fromInterned(base).canMutateComptimeVarState(mod), + .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).canMutateComptimeVarState(mod), + .elem, .field => |base_index| Value.fromInterned(base_index.base).canMutateComptimeVarState(mod), else => false, }, .opt => |opt| switch (opt.val) { diff --git a/test/behavior/comptime_memory.zig b/test/behavior/comptime_memory.zig index bfeaa339b2..e56de79d9d 100644 --- a/test/behavior/comptime_memory.zig +++ b/test/behavior/comptime_memory.zig @@ -459,3 +459,77 @@ test "write empty array to end" { array[5..5].* = [_]u8{}; try testing.expectEqualStrings("hello", &array); } + +fn doublePtrTest() !void { + var a: u32 = 0; + const ptr = &a; + const double_ptr = &ptr; + setDoublePtr(double_ptr, 1); + setDoublePtr(double_ptr, 2); + setDoublePtr(double_ptr, 1); + try std.testing.expect(a == 1); +} +fn setDoublePtr(ptr: *const *const u32, value: u32) void { + setPtr(ptr.*, value); +} +fn setPtr(ptr: *const u32, value: u32) void { + const mut_ptr: *u32 = @constCast(ptr); + mut_ptr.* = value; +} +test "double pointer can mutate comptime state" { + try comptime doublePtrTest(); +} + +fn GenericIntApplier( + comptime Context: type, + comptime applyFn: fn (context: Context, arg: u32) void, +) type { + return struct { + context: Context, + + const Self = @This(); + + inline fn any(self: *const Self) IntApplier { + return .{ + .context = @ptrCast(&self.context), + .applyFn = typeErasedApplyFn, + }; + } + + fn typeErasedApplyFn(context: *const anyopaque, arg: u32) void { + const ptr: *const Context = @alignCast(@ptrCast(context)); + applyFn(ptr.*, arg); + } + }; +} +const IntApplier = struct { + context: *const anyopaque, + applyFn: *const fn (context: *const anyopaque, arg: u32) void, + + fn apply(ia: IntApplier, arg: u32) void { + ia.applyFn(ia.context, arg); + } +}; +const Accumulator = struct { + value: u32, + + const Applier = GenericIntApplier(*u32, add); + + fn applier(a: *Accumulator) Applier { + return .{ .context = &a.value }; + } + + fn add(context: *u32, arg: u32) void { + context.* += arg; + } +}; +fn fieldPtrTest() u32 { + var a: Accumulator = .{ .value = 0 }; + const applier = a.applier(); + applier.any().apply(1); + applier.any().apply(1); + return a.value; +} +test "pointer in aggregate field can mutate comptime state" { + try comptime std.testing.expect(fieldPtrTest() == 2); +} diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 1d5457fa3a..8e4dd2c091 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -1027,3 +1027,15 @@ test "generic type constructed from inferred error set of unresolved function" { }; _ = std.io.multiWriter(.{S.writer()}); } + +test "errorCast to adhoc inferred error set" { + const S = struct { + inline fn baz() !i32 { + return @errorCast(err()); + } + fn err() anyerror!i32 { + return 1234; + } + }; + try std.testing.expect((try S.baz()) == 1234); +} diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 6a38891494..ab4f89a052 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -1566,3 +1566,22 @@ test "@reduce on bool vector" { try std.testing.expect(@reduce(.And, a)); try std.testing.expect(@reduce(.And, b)); } + +test "bitcast vector to array of smaller vectors" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const u8x32 = @Vector(32, u8); + const u8x64 = @Vector(64, u8); + const S = struct { + fn doTheTest(input_vec: u8x64) !void { + try compare(@bitCast(input_vec)); + } + fn compare(chunks: [2]u8x32) !void { + try expectEqual(@as(u8x32, @splat(1)), chunks[0]); + try expectEqual(@as(u8x32, @splat(2)), chunks[1]); + } + }; + const input: u8x64 = @bitCast([2]u8x32{ @splat(1), @splat(2) }); + try S.doTheTest(input); +}