authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-02 18:46:59+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-02 18:46:59+02:00
log59dad43de26a89ca72a97224a171d724dcc6ee41
tree63377949939557a1edf03c90be77508051d9354f
parent86e6acb37b242a60917f5552999d918c24fdf791

Sema: add error for failed assumption about struct having runtime bits


5 files changed, 67 insertions(+), 7 deletions(-)

src/Module.zig+2
...@@ -940,6 +940,7 @@ pub const Struct = struct {...@@ -940,6 +940,7 @@ pub const Struct = struct {
940 requires_comptime: PropertyBoolean = .unknown,940 requires_comptime: PropertyBoolean = .unknown,
941 have_field_inits: bool = false,941 have_field_inits: bool = false,
942 is_tuple: bool,942 is_tuple: bool,
943 assumed_runtime_bits: bool = false,
943944
944 pub const Fields = std.StringArrayHashMapUnmanaged(Field);945 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
945946
...@@ -1205,6 +1206,7 @@ pub const Union = struct {...@@ -1205,6 +1206,7 @@ pub const Union = struct {
1205 fully_resolved,1206 fully_resolved,
1206 },1207 },
1207 requires_comptime: PropertyBoolean = .unknown,1208 requires_comptime: PropertyBoolean = .unknown,
1209 assumed_runtime_bits: bool = false,
12081210
1209 pub const Field = struct {1211 pub const Field = struct {
1210 /// undefined until `status` is `have_field_types` or `have_layout`.1212 /// undefined until `status` is `have_field_types` or `have_layout`.
src/Sema.zig+20
...@@ -29237,6 +29237,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -29237,6 +29237,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
2923729237
29238 struct_obj.status = .have_layout;29238 struct_obj.status = .have_layout;
29239 _ = try sema.resolveTypeRequiresComptime(resolved_ty);29239 _ = try sema.resolveTypeRequiresComptime(resolved_ty);
29240
29241 if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
29242 const msg = try Module.ErrorMsg.create(
29243 sema.gpa,
29244 struct_obj.srcLoc(sema.mod),
29245 "struct layout depends on it having runtime bits",
29246 .{},
29247 );
29248 return sema.failWithOwnedErrorMsg(msg);
29249 }
29240 }29250 }
29241 // otherwise it's a tuple; no need to resolve anything29251 // otherwise it's a tuple; no need to resolve anything
29242}29252}
...@@ -29401,6 +29411,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -29401,6 +29411,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
29401 }29411 }
29402 union_obj.status = .have_layout;29412 union_obj.status = .have_layout;
29403 _ = try sema.resolveTypeRequiresComptime(resolved_ty);29413 _ = try sema.resolveTypeRequiresComptime(resolved_ty);
29414
29415 if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
29416 const msg = try Module.ErrorMsg.create(
29417 sema.gpa,
29418 union_obj.srcLoc(sema.mod),
29419 "union layout depends on it having runtime bits",
29420 .{},
29421 );
29422 return sema.failWithOwnedErrorMsg(msg);
29423 }
29404}29424}
2940529425
29406// In case of querying the ABI alignment of this struct, we will ask29426// In case of querying the ABI alignment of this struct, we will ask
src/type.zig+25-6
...@@ -2459,6 +2459,7 @@ pub const Type = extern union {...@@ -2459,6 +2459,7 @@ pub const Type = extern union {
2459 if (struct_obj.status == .field_types_wip) {2459 if (struct_obj.status == .field_types_wip) {
2460 // In this case, we guess that hasRuntimeBits() for this type is true,2460 // In this case, we guess that hasRuntimeBits() for this type is true,
2461 // and then later if our guess was incorrect, we emit a compile error.2461 // and then later if our guess was incorrect, we emit a compile error.
2462 struct_obj.assumed_runtime_bits = true;
2462 return true;2463 return true;
2463 }2464 }
2464 switch (strat) {2465 switch (strat) {
...@@ -2491,6 +2492,12 @@ pub const Type = extern union {...@@ -2491,6 +2492,12 @@ pub const Type = extern union {
24912492
2492 .@"union" => {2493 .@"union" => {
2493 const union_obj = ty.castTag(.@"union").?.data;2494 const union_obj = ty.castTag(.@"union").?.data;
2495 if (union_obj.status == .field_types_wip) {
2496 // In this case, we guess that hasRuntimeBits() for this type is true,
2497 // and then later if our guess was incorrect, we emit a compile error.
2498 union_obj.assumed_runtime_bits = true;
2499 return true;
2500 }
2494 switch (strat) {2501 switch (strat) {
2495 .sema => |sema| _ = try sema.resolveTypeFields(ty),2502 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2496 .eager => assert(union_obj.haveFieldTypes()),2503 .eager => assert(union_obj.haveFieldTypes()),
...@@ -3027,8 +3034,9 @@ pub const Type = extern union {...@@ -3027,8 +3034,9 @@ pub const Type = extern union {
3027 const struct_obj = ty.castTag(.@"struct").?.data;3034 const struct_obj = ty.castTag(.@"struct").?.data;
3028 if (opt_sema) |sema| {3035 if (opt_sema) |sema| {
3029 if (struct_obj.status == .field_types_wip) {3036 if (struct_obj.status == .field_types_wip) {
3030 // We'll guess "pointer-aligned" and if we guess wrong, emit3037 // We'll guess "pointer-aligned", if the struct has an
3031 // a compile error later.3038 // underaligned pointer field then some allocations
3039 // might require explicit alignment.
3032 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };3040 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
3033 }3041 }
3034 _ = try sema.resolveTypeFields(ty);3042 _ = try sema.resolveTypeFields(ty);
...@@ -3153,8 +3161,9 @@ pub const Type = extern union {...@@ -3153,8 +3161,9 @@ pub const Type = extern union {
3153 };3161 };
3154 if (opt_sema) |sema| {3162 if (opt_sema) |sema| {
3155 if (union_obj.status == .field_types_wip) {3163 if (union_obj.status == .field_types_wip) {
3156 // We'll guess "pointer-aligned" and if we guess wrong, emit3164 // We'll guess "pointer-aligned", if the union has an
3157 // a compile error later.3165 // underaligned pointer field then some allocations
3166 // might require explicit alignment.
3158 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };3167 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
3159 }3168 }
3160 _ = try sema.resolveTypeFields(ty);3169 _ = try sema.resolveTypeFields(ty);
...@@ -5234,7 +5243,12 @@ pub const Type = extern union {...@@ -5234,7 +5243,12 @@ pub const Type = extern union {
5234 .@"struct" => {5243 .@"struct" => {
5235 const struct_obj = ty.castTag(.@"struct").?.data;5244 const struct_obj = ty.castTag(.@"struct").?.data;
5236 switch (struct_obj.requires_comptime) {5245 switch (struct_obj.requires_comptime) {
5237 .wip, .unknown => unreachable, // This function asserts types already resolved.5246 .wip, .unknown => {
5247 // Return false to avoid incorrect dependency loops.
5248 // This will be handled correctly once merged with
5249 // `Sema.typeRequiresComptime`.
5250 return false;
5251 },
5238 .no => return false,5252 .no => return false,
5239 .yes => return true,5253 .yes => return true,
5240 }5254 }
...@@ -5243,7 +5257,12 @@ pub const Type = extern union {...@@ -5243,7 +5257,12 @@ pub const Type = extern union {
5243 .@"union", .union_safety_tagged, .union_tagged => {5257 .@"union", .union_safety_tagged, .union_tagged => {
5244 const union_obj = ty.cast(Type.Payload.Union).?.data;5258 const union_obj = ty.cast(Type.Payload.Union).?.data;
5245 switch (union_obj.requires_comptime) {5259 switch (union_obj.requires_comptime) {
5246 .wip, .unknown => unreachable, // This function asserts types already resolved.5260 .wip, .unknown => {
5261 // Return false to avoid incorrect dependency loops.
5262 // This will be handled correctly once merged with
5263 // `Sema.typeRequiresComptime`.
5264 return false;
5265 },
5247 .no => return false,5266 .no => return false,
5248 .yes => return true,5267 .yes => return true,
5249 }5268 }
src/value.zig+1-1
...@@ -187,7 +187,7 @@ pub const Value = extern union {...@@ -187,7 +187,7 @@ pub const Value = extern union {
187 bound_fn,187 bound_fn,
188 /// The ABI alignment of the payload type.188 /// The ABI alignment of the payload type.
189 lazy_align,189 lazy_align,
190 /// The ABI alignment of the payload type.190 /// The ABI size of the payload type.
191 lazy_size,191 lazy_size,
192192
193 pub const last_no_payload_tag = Tag.empty_array;193 pub const last_no_payload_tag = Tag.empty_array;
test/cases/compile_errors/invalid_dependency_on_struct_size.zig created+19
...@@ -0,0 +1,19 @@
1comptime {
2 const S = struct {
3 const Foo = struct {
4 y: Bar,
5 };
6 const Bar = struct {
7 y: if (@sizeOf(Foo) == 0) u64 else void,
8 };
9 };
10
11 _ = @sizeOf(S.Foo) + 1;
12}
13
14// error
15// backend=stage2
16// target=native
17//
18// :6:21: error: struct layout depends on it having runtime bits
19// :4:13: note: while checking this field