diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-11-16 15:46:43 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-11-20 20:25:11 +0200 |
| commit | e5a3eb9777ff165d936b0811f3825eabb8bcd6a4 (patch) | |
| tree | 15b67ec852dc6b41d1b54a1039bcdd6581aa0449 /src | |
| parent | 44f8714dfb69fac2e8c7a6a35ad9f2abe7c4513a (diff) | |
| download | zig-e5a3eb9777ff165d936b0811f3825eabb8bcd6a4.tar.gz zig-e5a3eb9777ff165d936b0811f3825eabb8bcd6a4.zip | |
Type: make `hasRuntimeBitsAdvanced` take `AbiAlignmentAdvancedStrat`
I wasn't able to create a reduced test case for this but the reasoning
can be seen in `abiAlignmentAdvancedUnion` where if `strat` was lazy
`hasRuntimeBitsAdvanced` would be given `null` instead of `sema`
which would cause eager evaluation when it is not valid or desired.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 7 | ||||
| -rw-r--r-- | src/print_zir.zig | 18 | ||||
| -rw-r--r-- | src/type.zig | 81 | ||||
| -rw-r--r-- | src/value.zig | 12 |
4 files changed, 81 insertions, 37 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index a6811d37fd..b3f1dd1bf0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -128,7 +128,7 @@ pub const Block = struct { /// Shared among all child blocks. sema: *Sema, /// The namespace to use for lookups from this source block - /// When analyzing fields, this is different from src_decl.src_namepsace. + /// When analyzing fields, this is different from src_decl.src_namespace. namespace: *Namespace, /// The AIR instructions generated for this block. instructions: std.ArrayListUnmanaged(Air.Inst.Index), @@ -31298,7 +31298,10 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { } pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { - return ty.hasRuntimeBitsAdvanced(false, sema); + return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) { + error.NeedLazy => unreachable, + else => |e| return e, + }; } fn typeAbiSize(sema: *Sema, ty: Type) !u64 { diff --git a/src/print_zir.zig b/src/print_zir.zig index f1b1068920..d434abd439 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -262,9 +262,10 @@ const Writer = struct { => try self.writeBreak(stream, inst), .array_init, .array_init_ref, + => try self.writeArrayInit(stream, inst), .array_init_anon, .array_init_anon_ref, - => try self.writeArrayInit(stream, inst), + => try self.writeArrayInitAnon(stream, inst), .slice_start => try self.writeSliceStart(stream, inst), .slice_end => try self.writeSliceEnd(stream, inst), @@ -2316,6 +2317,21 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } + fn writeArrayInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + + const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); + const args = self.code.refSlice(extra.end, extra.data.operands_len); + + try stream.writeAll("{"); + for (args) |arg, i| { + if (i != 0) try stream.writeAll(", "); + try self.writeInstRef(stream, arg); + } + try stream.writeAll("}) "); + try self.writeSrc(stream, inst_data.src()); + } + fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; diff --git a/src/type.zig b/src/type.zig index 710b2fe4a3..6afee8bc73 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2312,6 +2312,8 @@ pub const Type = extern union { } } + const RuntimeBitsError = Module.CompileError || error{NeedLazy}; + /// true if and only if the type takes up space in memory at runtime. /// There are two reasons a type will return false: /// * the type is a comptime-only type. For example, the type `type` itself. @@ -2326,8 +2328,8 @@ pub const Type = extern union { pub fn hasRuntimeBitsAdvanced( ty: Type, ignore_comptime_only: bool, - opt_sema: ?*Sema, - ) Module.CompileError!bool { + strat: AbiAlignmentAdvancedStrat, + ) RuntimeBitsError!bool { switch (ty.tag()) { .u1, .u8, @@ -2406,8 +2408,8 @@ pub const Type = extern union { return true; } else if (ty.childType().zigTypeTag() == .Fn) { return !ty.childType().fnInfo().is_generic; - } else if (opt_sema) |sema| { - return !(try sema.typeRequiresComptime(ty)); + } else if (strat == .sema) { + return !(try strat.sema.typeRequiresComptime(ty)); } else { return !comptimeOnly(ty); } @@ -2445,8 +2447,8 @@ pub const Type = extern union { } if (ignore_comptime_only) { return true; - } else if (opt_sema) |sema| { - return !(try sema.typeRequiresComptime(child_ty)); + } else if (strat == .sema) { + return !(try strat.sema.typeRequiresComptime(child_ty)); } else { return !comptimeOnly(child_ty); } @@ -2459,13 +2461,14 @@ pub const Type = extern union { // and then later if our guess was incorrect, we emit a compile error. return true; } - if (opt_sema) |sema| { - _ = try sema.resolveTypeFields(ty); + switch (strat) { + .sema => |sema| _ = try sema.resolveTypeFields(ty), + .eager => assert(struct_obj.haveFieldTypes()), + .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, } - assert(struct_obj.haveFieldTypes()); for (struct_obj.fields.values()) |field| { if (field.is_comptime) continue; - if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) + if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; } else { return false; @@ -2474,7 +2477,7 @@ pub const Type = extern union { .enum_full => { const enum_full = ty.castTag(.enum_full).?.data; - return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema); + return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat); }, .enum_simple => { const enum_simple = ty.castTag(.enum_simple).?.data; @@ -2483,17 +2486,18 @@ pub const Type = extern union { .enum_numbered, .enum_nonexhaustive => { var buffer: Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&buffer); - return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema); + return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat); }, .@"union" => { const union_obj = ty.castTag(.@"union").?.data; - if (opt_sema) |sema| { - _ = try sema.resolveTypeFields(ty); + switch (strat) { + .sema => |sema| _ = try sema.resolveTypeFields(ty), + .eager => assert(union_obj.haveFieldTypes()), + .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, } - assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) + if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; } else { return false; @@ -2501,16 +2505,17 @@ pub const Type = extern union { }, .union_safety_tagged, .union_tagged => { const union_obj = ty.cast(Payload.Union).?.data; - if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) { + if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) { return true; } - if (opt_sema) |sema| { - _ = try sema.resolveTypeFields(ty); + switch (strat) { + .sema => |sema| _ = try sema.resolveTypeFields(ty), + .eager => assert(union_obj.haveFieldTypes()), + .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, } - assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) + if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; } else { return false; @@ -2518,9 +2523,9 @@ pub const Type = extern union { }, .array, .vector => return ty.arrayLen() != 0 and - try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema), + try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat), .array_u8 => return ty.arrayLen() != 0, - .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema), + .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat), .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0, @@ -2529,7 +2534,7 @@ pub const Type = extern union { for (tuple.types) |field_ty, i| { const val = tuple.values[i]; if (val.tag() != .unreachable_value) continue; // comptime field - if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) return true; + if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; } return false; }, @@ -2665,11 +2670,11 @@ pub const Type = extern union { } pub fn hasRuntimeBits(ty: Type) bool { - return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable; + return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable; } pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool { - return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable; + return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable; } pub fn isFnOrHasRuntimeBits(ty: Type) bool { @@ -2812,12 +2817,12 @@ pub const Type = extern union { } } - const AbiAlignmentAdvanced = union(enum) { + pub const AbiAlignmentAdvanced = union(enum) { scalar: u32, val: Value, }; - const AbiAlignmentAdvancedStrat = union(enum) { + pub const AbiAlignmentAdvancedStrat = union(enum) { eager, lazy: Allocator, sema: *Sema, @@ -2971,7 +2976,10 @@ pub const Type = extern union { switch (strat) { .eager, .sema => { - if (!(try child_type.hasRuntimeBitsAdvanced(false, opt_sema))) { + if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, + else => |e| return e, + })) { return AbiAlignmentAdvanced{ .scalar = 1 }; } return child_type.abiAlignmentAdvanced(target, strat); @@ -2990,7 +2998,10 @@ pub const Type = extern union { const code_align = abiAlignment(Type.anyerror, target); switch (strat) { .eager, .sema => { - if (!(try data.payload.hasRuntimeBitsAdvanced(false, opt_sema))) { + if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, + else => |e| return e, + })) { return AbiAlignmentAdvanced{ .scalar = code_align }; } return AbiAlignmentAdvanced{ .scalar = @max( @@ -3044,7 +3055,10 @@ pub const Type = extern union { const fields = ty.structFields(); var big_align: u32 = 0; for (fields.values()) |field| { - if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue; + if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, + else => |e| return e, + })) continue; const field_align = if (field.abi_align != 0) field.abi_align @@ -3161,7 +3175,10 @@ pub const Type = extern union { var max_align: u32 = 0; if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target); for (union_obj.fields.values()) |field| { - if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue; + if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, + else => |e| return e, + })) continue; const field_align = if (field.abi_align != 0) field.abi_align diff --git a/src/value.zig b/src/value.zig index 042a960b25..59cf9046f4 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1911,7 +1911,11 @@ pub const Value = extern union { .lazy_align => { const ty = lhs.castTag(.lazy_align).?.data; - if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) { + const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; + if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => unreachable, + else => |e| return e, + }) { return .gt; } else { return .eq; @@ -1919,7 +1923,11 @@ pub const Value = extern union { }, .lazy_size => { const ty = lhs.castTag(.lazy_size).?.data; - if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) { + const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; + if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { + error.NeedLazy => unreachable, + else => |e| return e, + }) { return .gt; } else { return .eq; |
