mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
Zcu: allow atomic operations on packed structs
Same validation rules as the backing integer would have.
This commit is contained in:
parent
ca752c61c0
commit
3ad81c40c0
5 changed files with 64 additions and 42 deletions
|
|
@ -23950,7 +23950,7 @@ fn checkAtomicPtrOperand(
|
|||
error.BadType => return sema.fail(
|
||||
block,
|
||||
elem_ty_src,
|
||||
"expected bool, integer, float, enum, or pointer type; found '{}'",
|
||||
"expected bool, integer, float, enum, packed struct, or pointer type; found '{}'",
|
||||
.{elem_ty.fmt(pt)},
|
||||
),
|
||||
};
|
||||
|
|
@ -24279,7 +24279,7 @@ fn zirCmpxchg(
|
|||
return sema.fail(
|
||||
block,
|
||||
elem_ty_src,
|
||||
"expected bool, integer, enum, or pointer type; found '{}'",
|
||||
"expected bool, integer, enum, packed struct, or pointer type; found '{}'",
|
||||
.{elem_ty.fmt(pt)},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
54
src/Zcu.zig
54
src/Zcu.zig
|
|
@ -3305,37 +3305,31 @@ pub fn atomicPtrAlignment(
|
|||
.spirv => @panic("TODO what should this value be?"),
|
||||
};
|
||||
|
||||
const int_ty = switch (ty.zigTypeTag(mod)) {
|
||||
.Int => ty,
|
||||
.Enum => ty.intTagType(mod),
|
||||
.Float => {
|
||||
const bit_count = ty.floatBits(target);
|
||||
if (bit_count > max_atomic_bits) {
|
||||
diags.* = .{
|
||||
.bits = bit_count,
|
||||
.max_bits = max_atomic_bits,
|
||||
};
|
||||
return error.FloatTooBig;
|
||||
}
|
||||
return .none;
|
||||
},
|
||||
.Bool => return .none,
|
||||
else => {
|
||||
if (ty.isPtrAtRuntime(mod)) return .none;
|
||||
return error.BadType;
|
||||
},
|
||||
};
|
||||
|
||||
const bit_count = int_ty.intInfo(mod).bits;
|
||||
if (bit_count > max_atomic_bits) {
|
||||
diags.* = .{
|
||||
.bits = bit_count,
|
||||
.max_bits = max_atomic_bits,
|
||||
};
|
||||
return error.IntTooBig;
|
||||
if (ty.toIntern() == .bool_type) return .none;
|
||||
if (ty.isRuntimeFloat()) {
|
||||
const bit_count = ty.floatBits(target);
|
||||
if (bit_count > max_atomic_bits) {
|
||||
diags.* = .{
|
||||
.bits = bit_count,
|
||||
.max_bits = max_atomic_bits,
|
||||
};
|
||||
return error.FloatTooBig;
|
||||
}
|
||||
return .none;
|
||||
}
|
||||
|
||||
return .none;
|
||||
if (ty.isAbiInt(mod)) {
|
||||
const bit_count = ty.intInfo(mod).bits;
|
||||
if (bit_count > max_atomic_bits) {
|
||||
diags.* = .{
|
||||
.bits = bit_count,
|
||||
.max_bits = max_atomic_bits,
|
||||
};
|
||||
return error.IntTooBig;
|
||||
}
|
||||
return .none;
|
||||
}
|
||||
if (ty.isPtrAtRuntime(mod)) return .none;
|
||||
return error.BadType;
|
||||
}
|
||||
|
||||
pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
|
||||
|
|
|
|||
|
|
@ -413,6 +413,14 @@ test "atomics with different types" {
|
|||
|
||||
try testAtomicsWithType(u0, 0, 0);
|
||||
try testAtomicsWithType(i0, 0, 0);
|
||||
|
||||
try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
|
||||
|
||||
try testAtomicsWithPackedStruct(
|
||||
packed struct { x: u7, y: u24, z: bool },
|
||||
.{ .x = 1, .y = 2, .z = true },
|
||||
.{ .x = 3, .y = 4, .z = false },
|
||||
);
|
||||
}
|
||||
|
||||
fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
|
||||
|
|
@ -426,6 +434,18 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
|
|||
try expect(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst).? == a);
|
||||
}
|
||||
|
||||
fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void {
|
||||
const BackingInt = @typeInfo(T).Struct.backing_integer.?;
|
||||
var x: T = b;
|
||||
@atomicStore(T, &x, a, .seq_cst);
|
||||
try expect(@as(BackingInt, @bitCast(x)) == @as(BackingInt, @bitCast(a)));
|
||||
try expect(@as(BackingInt, @bitCast(@atomicLoad(T, &x, .seq_cst))) == @as(BackingInt, @bitCast(a)));
|
||||
try expect(@as(BackingInt, @bitCast(@atomicRmw(T, &x, .Xchg, b, .seq_cst))) == @as(BackingInt, @bitCast(a)));
|
||||
try expect(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst) == null);
|
||||
if (@sizeOf(T) != 0)
|
||||
try expect(@as(BackingInt, @bitCast(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst).?)) == @as(BackingInt, @bitCast(a)));
|
||||
}
|
||||
|
||||
test "return @atomicStore, using it as a void value" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
|
|
|||
18
test/cases/compile_errors/atomics_with_invalid_type.zig
Normal file
18
test/cases/compile_errors/atomics_with_invalid_type.zig
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
export fn float() void {
|
||||
var x: f32 = 0;
|
||||
_ = @cmpxchgWeak(f32, &x, 1, 2, .seq_cst, .seq_cst);
|
||||
}
|
||||
|
||||
const NormalStruct = struct { x: u32 };
|
||||
export fn normalStruct() void {
|
||||
var x: NormalStruct = 0;
|
||||
_ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'
|
||||
// :8:27: error: expected type 'tmp.NormalStruct', found 'comptime_int'
|
||||
// :6:22: note: struct declared here
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
export fn entry() void {
|
||||
var x: f32 = 0;
|
||||
_ = @cmpxchgWeak(f32, &x, 1, 2, .seq_cst, .seq_cst);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:22: error: expected bool, integer, enum, or pointer type; found 'f32'
|
||||
Loading…
Add table
Reference in a new issue