Skip to content

Commit 2e7d28d

Browse files
Vexuandrewrk
authored andcommitted
Sema: replace uses of toUnsignedInt with toUnsignedIntAdvanced
During semantic analysis the value may be an unresolved lazy value which makes using `toUnsignedInt` invalid. Add assertions to detect similar issues in the future. Closes #18624
1 parent 10aff67 commit 2e7d28d

File tree

4 files changed

+51
-31
lines changed

4 files changed

+51
-31
lines changed

src/Sema.zig

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,7 +3755,7 @@ fn resolveComptimeKnownAllocValue(sema: *Sema, block: *Block, alloc: Air.Inst.Re
37553755
const idx_val = (try sema.resolveValue(data.rhs)).?;
37563756
break :blk .{
37573757
data.lhs,
3758-
.{ .elem = idx_val.toUnsignedInt(mod) },
3758+
.{ .elem = try idx_val.toUnsignedIntAdvanced(sema) },
37593759
};
37603760
},
37613761
.bitcast => .{
@@ -8399,7 +8399,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
83998399
const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src);
84008400

84018401
if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
8402-
const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod));
8402+
const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntAdvanced(sema));
84038403
if (int > mod.global_error_set.count() or int == 0)
84048404
return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
84058405
return Air.internedToRef((try mod.intern(.{ .err = .{
@@ -16522,7 +16522,7 @@ fn analyzePtrArithmetic(
1652216522
// it being a multiple of the type size.
1652316523
const elem_size = Type.fromInterned(ptr_info.child).abiSize(mod);
1652416524
const addend = if (opt_off_val) |off_val| a: {
16525-
const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(mod));
16525+
const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntAdvanced(sema));
1652616526
break :a elem_size * off_int;
1652716527
} else elem_size;
1652816528

@@ -16554,7 +16554,7 @@ fn analyzePtrArithmetic(
1655416554
if (opt_off_val) |offset_val| {
1655516555
if (ptr_val.isUndef(mod)) return mod.undefRef(new_ptr_ty);
1655616556

16557-
const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(mod));
16557+
const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema));
1655816558
if (offset_int == 0) return ptr;
1655916559
if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| {
1656016560
const elem_size = Type.fromInterned(ptr_info.child).abiSize(mod);
@@ -20815,7 +20815,7 @@ fn zirReify(
2081520815
);
2081620816

2081720817
const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
20818-
const bits: u16 = @intCast(bits_val.toUnsignedInt(mod));
20818+
const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema));
2081920819
const ty = try mod.intType(signedness, bits);
2082020820
return Air.internedToRef(ty.toIntern());
2082120821
},
@@ -20830,7 +20830,7 @@ fn zirReify(
2083020830
try ip.getOrPutString(gpa, "child"),
2083120831
).?);
2083220832

20833-
const len: u32 = @intCast(len_val.toUnsignedInt(mod));
20833+
const len: u32 = @intCast(try len_val.toUnsignedIntAdvanced(sema));
2083420834
const child_ty = child_val.toType();
2083520835

2083620836
try sema.checkVectorElemType(block, src, child_ty);
@@ -20848,7 +20848,7 @@ fn zirReify(
2084820848
try ip.getOrPutString(gpa, "bits"),
2084920849
).?);
2085020850

20851-
const bits: u16 = @intCast(bits_val.toUnsignedInt(mod));
20851+
const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema));
2085220852
const ty = switch (bits) {
2085320853
16 => Type.f16,
2085420854
32 => Type.f32,
@@ -20986,7 +20986,7 @@ fn zirReify(
2098620986
try ip.getOrPutString(gpa, "sentinel"),
2098720987
).?);
2098820988

20989-
const len = len_val.toUnsignedInt(mod);
20989+
const len = try len_val.toUnsignedIntAdvanced(sema);
2099020990
const child_ty = child_val.toType();
2099120991
const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: {
2099220992
const ptr_ty = try mod.singleMutPtrType(child_ty);
@@ -21537,7 +21537,7 @@ fn zirReify(
2153721537
}
2153821538

2153921539
const alignment = alignment: {
21540-
const alignment = try sema.validateAlignAllowZero(block, src, alignment_val.toUnsignedInt(mod));
21540+
const alignment = try sema.validateAlignAllowZero(block, src, try alignment_val.toUnsignedIntAdvanced(sema));
2154121541
const default = target_util.defaultFunctionAlignment(target);
2154221542
break :alignment if (alignment == default) .none else alignment;
2154321543
};
@@ -22148,7 +22148,7 @@ fn ptrFromIntVal(
2214822148
ptr_align: Alignment,
2214922149
) !Value {
2215022150
const mod = sema.mod;
22151-
const addr = operand_val.toUnsignedInt(mod);
22151+
const addr = try operand_val.toUnsignedIntAdvanced(sema);
2215222152
if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
2215322153
return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
2215422154
if (addr != 0 and ptr_align != .none and !ptr_align.check(addr))
@@ -23878,7 +23878,8 @@ fn analyzeShuffle(
2387823878
for (0..@intCast(mask_len)) |i| {
2387923879
const elem = try mask.elemValue(sema.mod, i);
2388023880
if (elem.isUndef(mod)) continue;
23881-
const int = elem.toSignedInt(mod);
23881+
const elem_resolved = try sema.resolveLazyValue(elem);
23882+
const int = elem_resolved.toSignedInt(mod);
2388223883
var unsigned: u32 = undefined;
2388323884
var chosen: u32 = undefined;
2388423885
if (int >= 0) {
@@ -24952,7 +24953,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2495224953
var new_dest_ptr = dest_ptr;
2495324954
var new_src_ptr = src_ptr;
2495424955
if (len_val) |val| {
24955-
const len = val.toUnsignedInt(mod);
24956+
const len = try val.toUnsignedIntAdvanced(sema);
2495624957
if (len == 0) {
2495724958
// This AIR instruction guarantees length > 0 if it is comptime-known.
2495824959
return;
@@ -25257,7 +25258,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2525725258
if (val.isGenericPoison()) {
2525825259
break :blk null;
2525925260
}
25260-
const alignment = try sema.validateAlignAllowZero(block, align_src, val.toUnsignedInt(mod));
25261+
const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntAdvanced(sema));
2526125262
const default = target_util.defaultFunctionAlignment(target);
2526225263
break :blk if (alignment == default) .none else alignment;
2526325264
} else if (extra.data.bits.has_align_ref) blk: {
@@ -25271,7 +25272,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2527125272
},
2527225273
else => |e| return e,
2527325274
};
25274-
const alignment = try sema.validateAlignAllowZero(block, align_src, align_tv.val.toUnsignedInt(mod));
25275+
const alignment = try sema.validateAlignAllowZero(block, align_src, try align_tv.val.toUnsignedIntAdvanced(sema));
2527525276
const default = target_util.defaultFunctionAlignment(target);
2527625277
break :blk if (alignment == default) .none else alignment;
2527725278
} else .none;
@@ -25569,7 +25570,7 @@ fn resolvePrefetchOptions(
2556925570

2557025571
return std.builtin.PrefetchOptions{
2557125572
.rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val),
25572-
.locality = @intCast(locality_val.toUnsignedInt(mod)),
25573+
.locality = @intCast(try locality_val.toUnsignedIntAdvanced(sema)),
2557325574
.cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val),
2557425575
};
2557525576
}
@@ -27757,7 +27758,7 @@ fn elemPtr(
2775727758
const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2775827759
.needed_comptime_reason = "tuple field access index must be comptime-known",
2775927760
});
27760-
const index: u32 = @intCast(index_val.toUnsignedInt(mod));
27761+
const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2776127762
break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
2776227763
},
2776327764
else => {
@@ -27795,7 +27796,7 @@ fn elemPtrOneLayerOnly(
2779527796
const runtime_src = rs: {
2779627797
const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
2779727798
const index_val = maybe_index_val orelse break :rs elem_index_src;
27798-
const index: usize = @intCast(index_val.toUnsignedInt(mod));
27799+
const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2779927800
const result_ty = try sema.elemPtrType(indexable_ty, index);
2780027801
const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
2780127802
return Air.internedToRef(elem_ptr.toIntern());
@@ -27814,7 +27815,7 @@ fn elemPtrOneLayerOnly(
2781427815
const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2781527816
.needed_comptime_reason = "tuple field access index must be comptime-known",
2781627817
});
27817-
const index: u32 = @intCast(index_val.toUnsignedInt(mod));
27818+
const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2781827819
break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
2781927820
},
2782027821
else => unreachable, // Guaranteed by checkIndexable
@@ -27854,7 +27855,7 @@ fn elemVal(
2785427855
const runtime_src = rs: {
2785527856
const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
2785627857
const index_val = maybe_index_val orelse break :rs elem_index_src;
27857-
const index: usize = @intCast(index_val.toUnsignedInt(mod));
27858+
const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2785827859
const elem_ty = indexable_ty.elemType2(mod);
2785927860
const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
2786027861
const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
@@ -27875,7 +27876,7 @@ fn elemVal(
2787527876
if (inner_ty.zigTypeTag(mod) != .Array) break :arr_sent;
2787627877
const sentinel = inner_ty.sentinel(mod) orelse break :arr_sent;
2787727878
const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
27878-
const index = try sema.usizeCast(block, src, index_val.toUnsignedInt(mod));
27879+
const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntAdvanced(sema));
2787927880
if (index != inner_ty.arrayLen(mod)) break :arr_sent;
2788027881
return Air.internedToRef(sentinel.toIntern());
2788127882
}
@@ -27893,7 +27894,7 @@ fn elemVal(
2789327894
const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2789427895
.needed_comptime_reason = "tuple field access index must be comptime-known",
2789527896
});
27896-
const index: u32 = @intCast(index_val.toUnsignedInt(mod));
27897+
const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2789727898
return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
2789827899
},
2789927900
else => unreachable,
@@ -28059,7 +28060,7 @@ fn elemValArray(
2805928060
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
2806028061

2806128062
if (maybe_index_val) |index_val| {
28062-
const index: usize = @intCast(index_val.toUnsignedInt(mod));
28063+
const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2806328064
if (array_sent) |s| {
2806428065
if (index == array_len) {
2806528066
return Air.internedToRef(s.toIntern());
@@ -28075,7 +28076,7 @@ fn elemValArray(
2807528076
return mod.undefRef(elem_ty);
2807628077
}
2807728078
if (maybe_index_val) |index_val| {
28078-
const index: usize = @intCast(index_val.toUnsignedInt(mod));
28079+
const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2807928080
const elem_val = try array_val.elemValue(mod, index);
2808028081
return Air.internedToRef(elem_val.toIntern());
2808128082
}
@@ -28122,7 +28123,7 @@ fn elemPtrArray(
2812228123
const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr);
2812328124
// The index must not be undefined since it can be out of bounds.
2812428125
const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28125-
const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
28126+
const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema));
2812628127
if (index >= array_len_s) {
2812728128
const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
2812828129
return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
@@ -28188,7 +28189,7 @@ fn elemValSlice(
2818828189
return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
2818928190
}
2819028191
if (maybe_index_val) |index_val| {
28191-
const index: usize = @intCast(index_val.toUnsignedInt(mod));
28192+
const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
2819228193
if (index >= slice_len_s) {
2819328194
const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2819428195
return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
@@ -28234,7 +28235,7 @@ fn elemPtrSlice(
2823428235
const maybe_undef_slice_val = try sema.resolveValue(slice);
2823528236
// The index must not be undefined since it can be out of bounds.
2823628237
const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28237-
const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
28238+
const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema));
2823828239
break :o index;
2823928240
} else null;
2824028241

@@ -32931,7 +32932,7 @@ fn analyzeSlice(
3293132932
const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(mod) != .C;
3293232933

3293332934
if (opt_new_len_val) |new_len_val| {
32934-
const new_len_int = new_len_val.toUnsignedInt(mod);
32935+
const new_len_int = try new_len_val.toUnsignedIntAdvanced(sema);
3293532936

3293632937
const return_ty = try sema.ptrType(.{
3293732938
.child = (try mod.arrayType(.{
@@ -36279,6 +36280,7 @@ fn semaStructFields(
3627936280
return;
3628036281
},
3628136282
.Auto, .Extern => {
36283+
struct_type.size(ip).* = 0;
3628236284
struct_type.flagsPtr(ip).layout_resolved = true;
3628336285
return;
3628436286
},

src/type.zig

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,12 +1380,15 @@ pub const Type = struct {
13801380
},
13811381
.eager => {},
13821382
}
1383-
return switch (struct_type.layout) {
1384-
.Packed => .{
1383+
switch (struct_type.layout) {
1384+
.Packed => return .{
13851385
.scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiSize(mod),
13861386
},
1387-
.Auto, .Extern => .{ .scalar = struct_type.size(ip).* },
1388-
};
1387+
.Auto, .Extern => {
1388+
assert(struct_type.haveLayout(ip));
1389+
return .{ .scalar = struct_type.size(ip).* };
1390+
},
1391+
}
13891392
},
13901393
.anon_struct_type => |tuple| {
13911394
switch (strat) {
@@ -1411,6 +1414,7 @@ pub const Type = struct {
14111414
.eager => {},
14121415
}
14131416

1417+
assert(union_type.haveLayout(ip));
14141418
return .{ .scalar = union_type.size(ip).* };
14151419
},
14161420
.opaque_type => unreachable, // no size available

src/value.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,11 @@ pub const Value = struct {
575575
return getUnsignedInt(val, mod).?;
576576
}
577577

578+
/// Asserts the value is an integer and it fits in a u64
579+
pub fn toUnsignedIntAdvanced(val: Value, sema: *Sema) !u64 {
580+
return (try getUnsignedIntAdvanced(val, sema.mod, sema)).?;
581+
}
582+
578583
/// Asserts the value is an integer and it fits in a i64
579584
pub fn toSignedInt(val: Value, mod: *Module) i64 {
580585
return switch (val.toIntern()) {

test/behavior/sizeof_and_typeof.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
429429
try Test.doTheTest();
430430
try comptime Test.doTheTest();
431431
}
432+
433+
test "@sizeOf struct is resolved when used as operand of slicing" {
434+
const dummy = struct {};
435+
const S = struct {
436+
var buf: [1]u8 = undefined;
437+
};
438+
S.buf[@sizeOf(dummy)..][0] = 0;
439+
try expect(S.buf[0] == 0);
440+
}

0 commit comments

Comments
 (0)