Commit 59dad43de2
Changed files (5)
test
cases
compile_errors
src/Module.zig
@@ -940,6 +940,7 @@ pub const Struct = struct {
requires_comptime: PropertyBoolean = .unknown,
have_field_inits: bool = false,
is_tuple: bool,
+ assumed_runtime_bits: bool = false,
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
@@ -1205,6 +1206,7 @@ pub const Union = struct {
fully_resolved,
},
requires_comptime: PropertyBoolean = .unknown,
+ assumed_runtime_bits: bool = false,
pub const Field = struct {
/// undefined until `status` is `have_field_types` or `have_layout`.
src/Sema.zig
@@ -29237,6 +29237,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
struct_obj.status = .have_layout;
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
+
+ if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ struct_obj.srcLoc(sema.mod),
+ "struct layout depends on it having runtime bits",
+ .{},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
+ }
}
// otherwise it's a tuple; no need to resolve anything
}
@@ -29401,6 +29411,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
}
union_obj.status = .have_layout;
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
+
+ if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ union_obj.srcLoc(sema.mod),
+ "union layout depends on it having runtime bits",
+ .{},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
+ }
}
// In case of querying the ABI alignment of this struct, we will ask
src/type.zig
@@ -2459,6 +2459,7 @@ pub const Type = extern union {
if (struct_obj.status == .field_types_wip) {
// In this case, we guess that hasRuntimeBits() for this type is true,
// and then later if our guess was incorrect, we emit a compile error.
+ struct_obj.assumed_runtime_bits = true;
return true;
}
switch (strat) {
@@ -2491,6 +2492,12 @@ pub const Type = extern union {
.@"union" => {
const union_obj = ty.castTag(.@"union").?.data;
+ if (union_obj.status == .field_types_wip) {
+ // In this case, we guess that hasRuntimeBits() for this type is true,
+ // and then later if our guess was incorrect, we emit a compile error.
+ union_obj.assumed_runtime_bits = true;
+ return true;
+ }
switch (strat) {
.sema => |sema| _ = try sema.resolveTypeFields(ty),
.eager => assert(union_obj.haveFieldTypes()),
@@ -3027,8 +3034,9 @@ pub const Type = extern union {
const struct_obj = ty.castTag(.@"struct").?.data;
if (opt_sema) |sema| {
if (struct_obj.status == .field_types_wip) {
- // We'll guess "pointer-aligned" and if we guess wrong, emit
- // a compile error later.
+ // We'll guess "pointer-aligned", if the struct has an
+ // underaligned pointer field then some allocations
+ // might require explicit alignment.
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
}
_ = try sema.resolveTypeFields(ty);
@@ -3153,8 +3161,9 @@ pub const Type = extern union {
};
if (opt_sema) |sema| {
if (union_obj.status == .field_types_wip) {
- // We'll guess "pointer-aligned" and if we guess wrong, emit
- // a compile error later.
+ // We'll guess "pointer-aligned", if the union has an
+ // underaligned pointer field then some allocations
+ // might require explicit alignment.
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
}
_ = try sema.resolveTypeFields(ty);
@@ -5234,7 +5243,12 @@ pub const Type = extern union {
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
switch (struct_obj.requires_comptime) {
- .wip, .unknown => unreachable, // This function asserts types already resolved.
+ .wip, .unknown => {
+ // Return false to avoid incorrect dependency loops.
+ // This will be handled correctly once merged with
+ // `Sema.typeRequiresComptime`.
+ return false;
+ },
.no => return false,
.yes => return true,
}
@@ -5243,7 +5257,12 @@ pub const Type = extern union {
.@"union", .union_safety_tagged, .union_tagged => {
const union_obj = ty.cast(Type.Payload.Union).?.data;
switch (union_obj.requires_comptime) {
- .wip, .unknown => unreachable, // This function asserts types already resolved.
+ .wip, .unknown => {
+ // Return false to avoid incorrect dependency loops.
+ // This will be handled correctly once merged with
+ // `Sema.typeRequiresComptime`.
+ return false;
+ },
.no => return false,
.yes => return true,
}
src/value.zig
@@ -187,7 +187,7 @@ pub const Value = extern union {
bound_fn,
/// The ABI alignment of the payload type.
lazy_align,
- /// The ABI alignment of the payload type.
+ /// The ABI size of the payload type.
lazy_size,
pub const last_no_payload_tag = Tag.empty_array;
test/cases/compile_errors/invalid_dependency_on_struct_size.zig
@@ -0,0 +1,19 @@
+comptime {
+ const S = struct {
+ const Foo = struct {
+ y: Bar,
+ };
+ const Bar = struct {
+ y: if (@sizeOf(Foo) == 0) u64 else void,
+ };
+ };
+
+ _ = @sizeOf(S.Foo) + 1;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :6:21: error: struct layout depends on it having runtime bits
+// :4:13: note: while checking this field