| author | |
| committer | |
| log | b6abe1dbf7b5ad14ad1b0a011f109694fd5f36a8 |
| tree | 5dc848161f3765e7af2923d67bc3b1e0eb070a83 |
| parent | d00e05f18609921c1a051a637c24e47cfa304243 |
| signature |
Documentation for this will be on the wiki shortly.
Resolves: #218426 files changed, 151 insertions(+), 67 deletions(-)
bootstrap.c+1| ... | ... | @@ -141,6 +141,7 @@ int main(int argc, char **argv) { |
| 141 | 141 | "pub const skip_non_native = false;\n" |
| 142 | 142 | "pub const force_gpa = false;\n" |
| 143 | 143 | "pub const dev = .core;\n" |
| 144 | "pub const value_interpret_mode = .direct;\n" | |
| 144 | 145 | , zig_version); |
| 145 | 146 | if (written < 100) |
| 146 | 147 | panic("unable to write to config.zig file"); |
build.zig+20| ... | ... | @@ -9,6 +9,7 @@ const fs = std.fs; |
| 9 | 9 | const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; |
| 10 | 10 | const assert = std.debug.assert; |
| 11 | 11 | const DevEnv = @import("src/dev.zig").Env; |
| 12 | const ValueInterpretMode = enum { direct, by_name }; | |
| 12 | 13 | |
| 13 | 14 | const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 }; |
| 14 | 15 | const stack_size = 46 * 1024 * 1024; |
| ... | ... | @@ -177,6 +178,7 @@ pub fn build(b: *std.Build) !void { |
| 177 | 178 | const strip = b.option(bool, "strip", "Omit debug information"); |
| 178 | 179 | const valgrind = b.option(bool, "valgrind", "Enable valgrind integration"); |
| 179 | 180 | const pie = b.option(bool, "pie", "Produce a Position Independent Executable"); |
| 181 | const value_interpret_mode = b.option(ValueInterpretMode, "value-interpret-mode", "How the compiler translates between 'std.builtin' types and its internal datastructures") orelse .direct; | |
| 180 | 182 | const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; |
| 181 | 183 | |
| 182 | 184 | const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { |
| ... | ... | @@ -234,6 +236,7 @@ pub fn build(b: *std.Build) !void { |
| 234 | 236 | exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa); |
| 235 | 237 | exe_options.addOption(bool, "force_gpa", force_gpa); |
| 236 | 238 | exe_options.addOption(DevEnv, "dev", b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full); |
| 239 | exe_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode); | |
| 237 | 240 | |
| 238 | 241 | if (link_libc) { |
| 239 | 242 | exe.root_module.link_libc = true; |
| ... | ... | @@ -620,6 +623,23 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { |
| 620 | 623 | exe_options.addOption(bool, "value_tracing", false); |
| 621 | 624 | exe_options.addOption(DevEnv, "dev", .bootstrap); |
| 622 | 625 | |
| 626 | // zig1 chooses to interpret values by name. The tradeoff is as follows: | |
| 627 | // | |
| 628 | // * We lose a small amount of performance. This is essentially irrelevant for zig1. | |
| 629 | // | |
| 630 | // * We lose the ability to perform trivial renames on certain `std.builtin` types without | |
| 631 | // zig1.wasm updates. For instance, we cannot rename an enum from PascalCase fields to | |
| 632 | // snake_case fields without an update. | |
| 633 | // | |
| 634 | // * We gain the ability to add and remove fields to and from `std.builtin` types without | |
| 635 | // zig1.wasm updates. For instance, we can add a new tag to `CallingConvention` without | |
| 636 | // an update. | |
| 637 | // | |
| 638 | // Because field renames only happen when we apply a breaking change to the language (which | |
| 639 | // is becoming progressively rarer), but tags may be added to or removed from target-dependent | |
| 640 | // types over time in response to new targets coming into use, we gain more than we lose here. | |
| 641 | exe_options.addOption(ValueInterpretMode, "value_interpret_mode", .by_name); | |
| 642 | ||
| 623 | 643 | const run_opt = b.addSystemCommand(&.{ |
| 624 | 644 | "wasm-opt", |
| 625 | 645 | "-Oz", |
src/Sema.zig+29-40| ... | ... | @@ -2713,8 +2713,18 @@ fn analyzeValueAsCallconv( |
| 2713 | 2713 | src: LazySrcLoc, |
| 2714 | 2714 | unresolved_val: Value, |
| 2715 | 2715 | ) !std.builtin.CallingConvention { |
| 2716 | return interpretBuiltinType(sema, block, src, unresolved_val, std.builtin.CallingConvention); | |
| 2717 | } | |
| 2718 | ||
| 2719 | fn interpretBuiltinType( | |
| 2720 | sema: *Sema, | |
| 2721 | block: *Block, | |
| 2722 | src: LazySrcLoc, | |
| 2723 | unresolved_val: Value, | |
| 2724 | comptime T: type, | |
| 2725 | ) !T { | |
| 2716 | 2726 | const resolved_val = try sema.resolveLazyValue(unresolved_val); |
| 2717 | return resolved_val.interpret(std.builtin.CallingConvention, sema.pt) catch |err| switch (err) { | |
| 2727 | return resolved_val.interpret(T, sema.pt) catch |err| switch (err) { | |
| 2718 | 2728 | error.OutOfMemory => |e| return e, |
| 2719 | 2729 | error.UndefinedValue => return sema.failWithUseOfUndef(block, src), |
| 2720 | 2730 | error.TypeMismatch => @panic("std.builtin is corrupt"), |
| ... | ... | @@ -21536,19 +21546,8 @@ fn zirReify( |
| 21536 | 21546 | .@"anyframe" => return sema.failWithUseOfAsync(block, src), |
| 21537 | 21547 | .enum_literal => return .enum_literal_type, |
| 21538 | 21548 | .int => { |
| 21539 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | |
| 21540 | const signedness_val = try Value.fromInterned(union_val.val).fieldValue( | |
| 21541 | pt, | |
| 21542 | struct_type.nameIndex(ip, try ip.getOrPutString(gpa, pt.tid, "signedness", .no_embedded_nulls)).?, | |
| 21543 | ); | |
| 21544 | const bits_val = try Value.fromInterned(union_val.val).fieldValue( | |
| 21545 | pt, | |
| 21546 | struct_type.nameIndex(ip, try ip.getOrPutString(gpa, pt.tid, "bits", .no_embedded_nulls)).?, | |
| 21547 | ); | |
| 21548 | ||
| 21549 | const signedness = zcu.toEnum(std.builtin.Signedness, signedness_val); | |
| 21550 | const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(pt)); | |
| 21551 | const ty = try pt.intType(signedness, bits); | |
| 21549 | const int = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Int); | |
| 21550 | const ty = try pt.intType(int.signedness, int.bits); | |
| 21552 | 21551 | return Air.internedToRef(ty.toIntern()); |
| 21553 | 21552 | }, |
| 21554 | 21553 | .vector => { |
| ... | ... | @@ -21574,20 +21573,15 @@ fn zirReify( |
| 21574 | 21573 | return Air.internedToRef(ty.toIntern()); |
| 21575 | 21574 | }, |
| 21576 | 21575 | .float => { |
| 21577 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | |
| 21578 | const bits_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | |
| 21579 | ip, | |
| 21580 | try ip.getOrPutString(gpa, pt.tid, "bits", .no_embedded_nulls), | |
| 21581 | ).?); | |
| 21576 | const float = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Float); | |
| 21582 | 21577 | |
| 21583 | const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(pt)); | |
| 21584 | const ty = switch (bits) { | |
| 21578 | const ty = switch (float.bits) { | |
| 21585 | 21579 | 16 => Type.f16, |
| 21586 | 21580 | 32 => Type.f32, |
| 21587 | 21581 | 64 => Type.f64, |
| 21588 | 21582 | 80 => Type.f80, |
| 21589 | 21583 | 128 => Type.f128, |
| 21590 | else => return sema.fail(block, src, "{}-bit float unsupported", .{bits}), | |
| 21584 | else => return sema.fail(block, src, "{}-bit float unsupported", .{float.bits}), | |
| 21591 | 21585 | }; |
| 21592 | 21586 | return Air.internedToRef(ty.toIntern()); |
| 21593 | 21587 | }, |
| ... | ... | @@ -21641,7 +21635,7 @@ fn zirReify( |
| 21641 | 21635 | try elem_ty.resolveLayout(pt); |
| 21642 | 21636 | } |
| 21643 | 21637 | |
| 21644 | const ptr_size = zcu.toEnum(std.builtin.Type.Pointer.Size, size_val); | |
| 21638 | const ptr_size = try sema.interpretBuiltinType(block, operand_src, size_val, std.builtin.Type.Pointer.Size); | |
| 21645 | 21639 | |
| 21646 | 21640 | const actual_sentinel: InternPool.Index = s: { |
| 21647 | 21641 | if (!sentinel_val.isNull(zcu)) { |
| ... | ... | @@ -21691,7 +21685,7 @@ fn zirReify( |
| 21691 | 21685 | .is_const = is_const_val.toBool(), |
| 21692 | 21686 | .is_volatile = is_volatile_val.toBool(), |
| 21693 | 21687 | .alignment = abi_align, |
| 21694 | .address_space = zcu.toEnum(std.builtin.AddressSpace, address_space_val), | |
| 21688 | .address_space = try sema.interpretBuiltinType(block, operand_src, address_space_val, std.builtin.AddressSpace), | |
| 21695 | 21689 | .is_allowzero = is_allowzero_val.toBool(), |
| 21696 | 21690 | }, |
| 21697 | 21691 | }); |
| ... | ... | @@ -21813,7 +21807,7 @@ fn zirReify( |
| 21813 | 21807 | try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls), |
| 21814 | 21808 | ).?); |
| 21815 | 21809 | |
| 21816 | const layout = zcu.toEnum(std.builtin.Type.ContainerLayout, layout_val); | |
| 21810 | const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout); | |
| 21817 | 21811 | |
| 21818 | 21812 | // Decls |
| 21819 | 21813 | if (try decls_val.sliceLen(pt) > 0) { |
| ... | ... | @@ -21929,7 +21923,7 @@ fn zirReify( |
| 21929 | 21923 | if (try decls_val.sliceLen(pt) > 0) { |
| 21930 | 21924 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 21931 | 21925 | } |
| 21932 | const layout = zcu.toEnum(std.builtin.Type.ContainerLayout, layout_val); | |
| 21926 | const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout); | |
| 21933 | 21927 | |
| 21934 | 21928 | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields }); |
| 21935 | 21929 | |
| ... | ... | @@ -24456,7 +24450,7 @@ fn resolveExportOptions( |
| 24456 | 24450 | |
| 24457 | 24451 | const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src); |
| 24458 | 24452 | const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ .simple = .export_options }); |
| 24459 | const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val); | |
| 24453 | const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage); | |
| 24460 | 24454 | |
| 24461 | 24455 | const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "section", .no_embedded_nulls), section_src); |
| 24462 | 24456 | const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .simple = .export_options }); |
| ... | ... | @@ -24467,7 +24461,7 @@ fn resolveExportOptions( |
| 24467 | 24461 | |
| 24468 | 24462 | const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src); |
| 24469 | 24463 | const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ .simple = .export_options }); |
| 24470 | const visibility = zcu.toEnum(std.builtin.SymbolVisibility, visibility_val); | |
| 24464 | const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility); | |
| 24471 | 24465 | |
| 24472 | 24466 | if (name.len < 1) { |
| 24473 | 24467 | return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); |
| ... | ... | @@ -24495,12 +24489,11 @@ fn resolveBuiltinEnum( |
| 24495 | 24489 | comptime name: Zcu.BuiltinDecl, |
| 24496 | 24490 | reason: ComptimeReason, |
| 24497 | 24491 | ) CompileError!@field(std.builtin, @tagName(name)) { |
| 24498 | const pt = sema.pt; | |
| 24499 | 24492 | const ty = try sema.getBuiltinType(src, name); |
| 24500 | 24493 | const air_ref = try sema.resolveInst(zir_ref); |
| 24501 | 24494 | const coerced = try sema.coerce(block, ty, air_ref, src); |
| 24502 | 24495 | const val = try sema.resolveConstDefinedValue(block, src, coerced, reason); |
| 24503 | return pt.zcu.toEnum(@field(std.builtin, @tagName(name)), val); | |
| 24496 | return sema.interpretBuiltinType(block, src, val, @field(std.builtin, @tagName(name))); | |
| 24504 | 24497 | } |
| 24505 | 24498 | |
| 24506 | 24499 | fn resolveAtomicOrder( |
| ... | ... | @@ -25293,7 +25286,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 25293 | 25286 | const air_ref = try sema.resolveInst(extra.modifier); |
| 25294 | 25287 | const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); |
| 25295 | 25288 | const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier }); |
| 25296 | var modifier = zcu.toEnum(std.builtin.CallModifier, modifier_val); | |
| 25289 | var modifier = try sema.interpretBuiltinType(block, modifier_src, modifier_val, std.builtin.CallModifier); | |
| 25297 | 25290 | switch (modifier) { |
| 25298 | 25291 | // These can be upgraded to comptime or nosuspend calls. |
| 25299 | 25292 | .auto, .never_tail, .no_async => { |
| ... | ... | @@ -26468,9 +26461,9 @@ fn resolvePrefetchOptions( |
| 26468 | 26461 | const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ .simple = .prefetch_options }); |
| 26469 | 26462 | |
| 26470 | 26463 | return std.builtin.PrefetchOptions{ |
| 26471 | .rw = zcu.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), | |
| 26464 | .rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw), | |
| 26472 | 26465 | .locality = @intCast(try locality_val.toUnsignedIntSema(pt)), |
| 26473 | .cache = zcu.toEnum(std.builtin.PrefetchOptions.Cache, cache_val), | |
| 26466 | .cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache), | |
| 26474 | 26467 | }; |
| 26475 | 26468 | } |
| 26476 | 26469 | |
| ... | ... | @@ -26536,7 +26529,7 @@ fn resolveExternOptions( |
| 26536 | 26529 | |
| 26537 | 26530 | const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src); |
| 26538 | 26531 | const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options }); |
| 26539 | const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val); | |
| 26532 | const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage); | |
| 26540 | 26533 | |
| 26541 | 26534 | const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src); |
| 26542 | 26535 | const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options }); |
| ... | ... | @@ -26770,9 +26763,6 @@ fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) Co |
| 26770 | 26763 | } |
| 26771 | 26764 | |
| 26772 | 26765 | fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 26773 | const pt = sema.pt; | |
| 26774 | const zcu = pt.zcu; | |
| 26775 | ||
| 26776 | 26766 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 26777 | 26767 | const uncoerced_hint = try sema.resolveInst(extra.operand); |
| 26778 | 26768 | const operand_src = block.builtinCallArgSrc(extra.node, 0); |
| ... | ... | @@ -26784,7 +26774,7 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 26784 | 26774 | // We only apply the first hint in a branch. |
| 26785 | 26775 | // This allows user-provided hints to override implicit cold hints. |
| 26786 | 26776 | if (sema.branch_hint == null) { |
| 26787 | sema.branch_hint = zcu.toEnum(std.builtin.BranchHint, hint_val); | |
| 26777 | sema.branch_hint = try sema.interpretBuiltinType(block, operand_src, hint_val, std.builtin.BranchHint); | |
| 26788 | 26778 | } |
| 26789 | 26779 | } |
| 26790 | 26780 | |
| ... | ... | @@ -37136,11 +37126,10 @@ pub fn analyzeAsAddressSpace( |
| 37136 | 37126 | ctx: AddressSpaceContext, |
| 37137 | 37127 | ) !std.builtin.AddressSpace { |
| 37138 | 37128 | const pt = sema.pt; |
| 37139 | const zcu = pt.zcu; | |
| 37140 | 37129 | const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace); |
| 37141 | 37130 | const coerced = try sema.coerce(block, addrspace_ty, air_ref, src); |
| 37142 | 37131 | const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ .simple = .@"addrspace" }); |
| 37143 | const address_space = zcu.toEnum(std.builtin.AddressSpace, addrspace_val); | |
| 37132 | const address_space = try sema.interpretBuiltinType(block, src, addrspace_val, std.builtin.AddressSpace); | |
| 37144 | 37133 | const target = pt.zcu.getTarget(); |
| 37145 | 37134 | const arch = target.cpu.arch; |
| 37146 | 37135 |
src/Value.zig+100-23| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const build_options = @import("build_options"); | |
| 3 | 4 | const Type = @import("Type.zig"); |
| 4 | 5 | const assert = std.debug.assert; |
| 5 | 6 | const BigIntConst = std.math.big.int.Const; |
| ... | ... | @@ -4531,6 +4532,20 @@ pub fn resolveLazy( |
| 4531 | 4532 | } |
| 4532 | 4533 | } |
| 4533 | 4534 | |
| 4535 | const InterpretMode = enum { | |
| 4536 | /// In this mode, types are assumed to match what the compiler was built with in terms of field | |
| 4537 | /// order, field types, etc. This improves compiler performance. However, it means that certain | |
| 4538 | /// modifications to `std.builtin` will result in compiler crashes. | |
| 4539 | direct, | |
| 4540 | /// In this mode, various details of the type are allowed to differ from what the compiler was built | |
| 4541 | /// with. Fields are matched by name rather than index; added struct fields are ignored, and removed | |
| 4542 | /// struct fields use their default value if one exists. This is slower than `.direct`, but permits | |
| 4543 | /// making certain changes to `std.builtin` (in particular reordering/adding/removing fields), so it | |
| 4544 | /// is useful when applying breaking changes. | |
| 4545 | by_name, | |
| 4546 | }; | |
| 4547 | const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_options.value_interpret_mode)); | |
| 4548 | ||
| 4534 | 4549 | /// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler. |
| 4535 | 4550 | /// This is useful for accessing `std.builtin` structures received from comptime logic. |
| 4536 | 4551 | /// `val` must be fully resolved. |
| ... | ... | @@ -4583,11 +4598,20 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe |
| 4583 | 4598 | else |
| 4584 | 4599 | null, |
| 4585 | 4600 | |
| 4586 | .@"enum" => zcu.toEnum(T, val), | |
| 4601 | .@"enum" => switch (interpret_mode) { | |
| 4602 | .direct => { | |
| 4603 | const int = val.getUnsignedInt(zcu) orelse return error.TypeMismatch; | |
| 4604 | return std.meta.intToEnum(T, int) catch error.TypeMismatch; | |
| 4605 | }, | |
| 4606 | .by_name => { | |
| 4607 | const field_index = ty.enumTagFieldIndex(val, zcu) orelse return error.TypeMismatch; | |
| 4608 | const field_name = ty.enumFieldName(field_index, zcu); | |
| 4609 | return std.meta.stringToEnum(T, field_name.toSlice(ip)) orelse error.TypeMismatch; | |
| 4610 | }, | |
| 4611 | }, | |
| 4587 | 4612 | |
| 4588 | 4613 | .@"union" => |@"union"| { |
| 4589 | const union_obj = zcu.typeToUnion(ty) orelse return error.TypeMismatch; | |
| 4590 | if (union_obj.field_types.len != @"union".fields.len) return error.TypeMismatch; | |
| 4614 | // No need to handle `interpret_mode`, because the `.@"enum"` handling already deals with it. | |
| 4591 | 4615 | const tag_val = val.unionTag(zcu) orelse return error.TypeMismatch; |
| 4592 | 4616 | const tag = try tag_val.interpret(@"union".tag_type.?, pt); |
| 4593 | 4617 | return switch (tag) { |
| ... | ... | @@ -4599,14 +4623,31 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe |
| 4599 | 4623 | }; |
| 4600 | 4624 | }, |
| 4601 | 4625 | |
| 4602 | .@"struct" => |@"struct"| { | |
| 4603 | if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch; | |
| 4604 | var result: T = undefined; | |
| 4605 | inline for (@"struct".fields, 0..) |field, field_idx| { | |
| 4606 | const field_val = try val.fieldValue(pt, field_idx); | |
| 4607 | @field(result, field.name) = try field_val.interpret(field.type, pt); | |
| 4608 | } | |
| 4609 | return result; | |
| 4626 | .@"struct" => |@"struct"| switch (interpret_mode) { | |
| 4627 | .direct => { | |
| 4628 | if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch; | |
| 4629 | var result: T = undefined; | |
| 4630 | inline for (@"struct".fields, 0..) |field, field_idx| { | |
| 4631 | const field_val = try val.fieldValue(pt, field_idx); | |
| 4632 | @field(result, field.name) = try field_val.interpret(field.type, pt); | |
| 4633 | } | |
| 4634 | return result; | |
| 4635 | }, | |
| 4636 | .by_name => { | |
| 4637 | const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch; | |
| 4638 | var result: T = undefined; | |
| 4639 | inline for (@"struct".fields) |field| { | |
| 4640 | const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls); | |
| 4641 | @field(result, field.name) = if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| f: { | |
| 4642 | const field_val = try val.fieldValue(pt, field_idx); | |
| 4643 | break :f try field_val.interpret(field.type, pt); | |
| 4644 | } else if (field.default_value) |ptr| f: { | |
| 4645 | const typed_ptr: *const field.type = @ptrCast(@alignCast(ptr)); | |
| 4646 | break :f typed_ptr.*; | |
| 4647 | } else return error.TypeMismatch; | |
| 4648 | } | |
| 4649 | return result; | |
| 4650 | }, | |
| 4610 | 4651 | }, |
| 4611 | 4652 | }; |
| 4612 | 4653 | } |
| ... | ... | @@ -4618,6 +4659,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 4618 | 4659 | const T = @TypeOf(val); |
| 4619 | 4660 | |
| 4620 | 4661 | const zcu = pt.zcu; |
| 4662 | const ip = &zcu.intern_pool; | |
| 4621 | 4663 | if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch; |
| 4622 | 4664 | |
| 4623 | 4665 | return switch (@typeInfo(T)) { |
| ... | ... | @@ -4657,9 +4699,17 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 4657 | 4699 | else |
| 4658 | 4700 | try pt.nullValue(ty), |
| 4659 | 4701 | |
| 4660 | .@"enum" => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()), | |
| 4702 | .@"enum" => switch (interpret_mode) { | |
| 4703 | .direct => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()), | |
| 4704 | .by_name => { | |
| 4705 | const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, @tagName(val), .no_embedded_nulls); | |
| 4706 | const field_idx = ty.enumFieldIndex(field_name_ip, zcu) orelse return error.TypeMismatch; | |
| 4707 | return pt.enumValueFieldIndex(ty, field_idx); | |
| 4708 | }, | |
| 4709 | }, | |
| 4661 | 4710 | |
| 4662 | 4711 | .@"union" => |@"union"| { |
| 4712 | // No need to handle `interpret_mode`, because the `.@"enum"` handling already deals with it. | |
| 4663 | 4713 | const tag: @"union".tag_type.? = val; |
| 4664 | 4714 | const tag_val = try uninterpret(tag, ty.unionTagType(zcu).?, pt); |
| 4665 | 4715 | const field_ty = ty.unionFieldType(tag_val, zcu) orelse return error.TypeMismatch; |
| ... | ... | @@ -4672,17 +4722,44 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 4672 | 4722 | }; |
| 4673 | 4723 | }, |
| 4674 | 4724 | |
| 4675 | .@"struct" => |@"struct"| { | |
| 4676 | if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch; | |
| 4677 | var field_vals: [@"struct".fields.len]InternPool.Index = undefined; | |
| 4678 | inline for (&field_vals, @"struct".fields, 0..) |*field_val, field, field_idx| { | |
| 4679 | const field_ty = ty.fieldType(field_idx, zcu); | |
| 4680 | field_val.* = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern(); | |
| 4681 | } | |
| 4682 | return .fromInterned(try pt.intern(.{ .aggregate = .{ | |
| 4683 | .ty = ty.toIntern(), | |
| 4684 | .storage = .{ .elems = &field_vals }, | |
| 4685 | } })); | |
| 4725 | .@"struct" => |@"struct"| switch (interpret_mode) { | |
| 4726 | .direct => { | |
| 4727 | if (ty.structFieldCount(zcu) != @"struct".fields.len) return error.TypeMismatch; | |
| 4728 | var field_vals: [@"struct".fields.len]InternPool.Index = undefined; | |
| 4729 | inline for (&field_vals, @"struct".fields, 0..) |*field_val, field, field_idx| { | |
| 4730 | const field_ty = ty.fieldType(field_idx, zcu); | |
| 4731 | field_val.* = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern(); | |
| 4732 | } | |
| 4733 | return .fromInterned(try pt.intern(.{ .aggregate = .{ | |
| 4734 | .ty = ty.toIntern(), | |
| 4735 | .storage = .{ .elems = &field_vals }, | |
| 4736 | } })); | |
| 4737 | }, | |
| 4738 | .by_name => { | |
| 4739 | const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch; | |
| 4740 | const want_fields_len = struct_obj.field_types.len; | |
| 4741 | const field_vals = try zcu.gpa.alloc(InternPool.Index, want_fields_len); | |
| 4742 | defer zcu.gpa.free(field_vals); | |
| 4743 | @memset(field_vals, .none); | |
| 4744 | inline for (@"struct".fields) |field| { | |
| 4745 | const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls); | |
| 4746 | if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| { | |
| 4747 | const field_ty = ty.fieldType(field_idx, zcu); | |
| 4748 | field_vals[field_idx] = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern(); | |
| 4749 | } | |
| 4750 | } | |
| 4751 | for (field_vals, 0..) |*field_val, field_idx| { | |
| 4752 | if (field_val.* == .none) { | |
| 4753 | const default_init = struct_obj.field_inits.get(ip)[field_idx]; | |
| 4754 | if (default_init == .none) return error.TypeMismatch; | |
| 4755 | field_val.* = default_init; | |
| 4756 | } | |
| 4757 | } | |
| 4758 | return .fromInterned(try pt.intern(.{ .aggregate = .{ | |
| 4759 | .ty = ty.toIntern(), | |
| 4760 | .storage = .{ .elems = field_vals }, | |
| 4761 | } })); | |
| 4762 | }, | |
| 4686 | 4763 | }, |
| 4687 | 4764 | }; |
| 4688 | 4765 | } |
src/Zcu.zig-4| ... | ... | @@ -3486,10 +3486,6 @@ pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Fu |
| 3486 | 3486 | return zcu.intern_pool.toFunc(func_index); |
| 3487 | 3487 | } |
| 3488 | 3488 | |
| 3489 | pub fn toEnum(zcu: *const Zcu, comptime E: type, val: Value) E { | |
| 3490 | return zcu.intern_pool.toEnum(E, val.toIntern()); | |
| 3491 | } | |
| 3492 | ||
| 3493 | 3489 | pub const UnionLayout = struct { |
| 3494 | 3490 | abi_size: u64, |
| 3495 | 3491 | abi_align: Alignment, |
stage1/config.zig.in+1| ... | ... | @@ -13,3 +13,4 @@ pub const value_tracing = false; |
| 13 | 13 | pub const skip_non_native = false; |
| 14 | 14 | pub const force_gpa = false; |
| 15 | 15 | pub const dev = .core; |
| 16 | pub const value_interpret_mode = .direct; |