authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-13 20:08:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-13 20:11:35-07:00
log5529febab056c870f7b2a123b0645b5e3b1146c9
treea0e71a36908a9ab4e83e50dd5b96812561dade34
parentf011f13933b72f4d63a5f635c7646b68beee726e

stage2: implement Value.copy for structs and unions

The stage2_os hack inside `@import("builtin")` is no longer needed.

4 files changed, 70 insertions(+), 46 deletions(-)

lib/std/start.zig+1-1
...@@ -92,7 +92,7 @@ fn _start2() callconv(.Naked) noreturn {...@@ -92,7 +92,7 @@ fn _start2() callconv(.Naked) noreturn {
92}92}
9393
94fn exit2(code: usize) noreturn {94fn exit2(code: usize) noreturn {
95 switch (builtin.stage2_os) {95 switch (native_os) {
96 .linux => switch (builtin.stage2_arch) {96 .linux => switch (builtin.stage2_arch) {
97 .x86_64 => {97 .x86_64 => {
98 asm volatile ("syscall"98 asm volatile ("syscall"
src/Compilation.zig-3
...@@ -3671,8 +3671,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc...@@ -3671,8 +3671,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
3671 \\pub const zig_is_stage2 = {};3671 \\pub const zig_is_stage2 = {};
3672 \\/// Temporary until self-hosted supports the `cpu.arch` value.3672 \\/// Temporary until self-hosted supports the `cpu.arch` value.
3673 \\pub const stage2_arch: std.Target.Cpu.Arch = .{};3673 \\pub const stage2_arch: std.Target.Cpu.Arch = .{};
3674 \\/// Temporary until self-hosted supports the `os.tag` value.
3675 \\pub const stage2_os: std.Target.Os.Tag = .{};
3676 \\3674 \\
3677 \\pub const output_mode = std.builtin.OutputMode.{};3675 \\pub const output_mode = std.builtin.OutputMode.{};
3678 \\pub const link_mode = std.builtin.LinkMode.{};3676 \\pub const link_mode = std.builtin.LinkMode.{};
...@@ -3688,7 +3686,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc...@@ -3688,7 +3686,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
3688 build_options.version,3686 build_options.version,
3689 !use_stage1,3687 !use_stage1,
3690 std.zig.fmtId(@tagName(target.cpu.arch)),3688 std.zig.fmtId(@tagName(target.cpu.arch)),
3691 std.zig.fmtId(@tagName(target.os.tag)),
3692 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),3689 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
3693 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),3690 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
3694 comp.bin_file.options.is_test,3691 comp.bin_file.options.is_test,
src/Sema.zig+3-3
...@@ -6313,7 +6313,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6313,7 +6313,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6313 sema.arena,6313 sema.arena,
6314 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn),6314 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn),
6315 ),6315 ),
6316 .val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr),6316 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6317 }),6317 }),
6318 );6318 );
6319 },6319 },
...@@ -6335,7 +6335,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6335,7 +6335,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6335 sema.arena,6335 sema.arena,
6336 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Int),6336 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Int),
6337 ),6337 ),
6338 .val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr),6338 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6339 }),6339 }),
6340 );6340 );
6341 },6341 },
...@@ -6943,7 +6943,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:...@@ -6943,7 +6943,7 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:
6943 for (field_inits) |field_init, i| {6943 for (field_inits) |field_init, i| {
6944 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;6944 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;
6945 }6945 }
6946 return sema.addConstant(resolved_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));6946 return sema.addConstant(resolved_ty, try Value.Tag.@"struct".create(sema.arena, values));
6947 }6947 }
69486948
6949 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});6949 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});
src/value.zig+66-39
...@@ -344,7 +344,9 @@ pub const Value = extern union {...@@ -344,7 +344,9 @@ pub const Value = extern union {
344 return null;344 return null;
345 }345 }
346346
347 pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {347 /// It's intentional that this function is not passed a corresponding Type, so that
348 /// a Value can be copied from a Sema to a Decl prior to resolving struct/union field types.
349 pub fn copy(self: Value, arena: *Allocator) error{OutOfMemory}!Value {
348 if (self.tag_if_small_enough < Tag.no_payload_count) {350 if (self.tag_if_small_enough < Tag.no_payload_count) {
349 return Value{ .tag_if_small_enough = self.tag_if_small_enough };351 return Value{ .tag_if_small_enough = self.tag_if_small_enough };
350 } else switch (self.ptr_otherwise.tag) {352 } else switch (self.ptr_otherwise.tag) {
...@@ -421,37 +423,37 @@ pub const Value = extern union {...@@ -421,37 +423,37 @@ pub const Value = extern union {
421423
422 .ty => {424 .ty => {
423 const payload = self.castTag(.ty).?;425 const payload = self.castTag(.ty).?;
424 const new_payload = try allocator.create(Payload.Ty);426 const new_payload = try arena.create(Payload.Ty);
425 new_payload.* = .{427 new_payload.* = .{
426 .base = payload.base,428 .base = payload.base,
427 .data = try payload.data.copy(allocator),429 .data = try payload.data.copy(arena),
428 };430 };
429 return Value{ .ptr_otherwise = &new_payload.base };431 return Value{ .ptr_otherwise = &new_payload.base };
430 },432 },
431 .int_type => return self.copyPayloadShallow(allocator, Payload.IntType),433 .int_type => return self.copyPayloadShallow(arena, Payload.IntType),
432 .int_u64 => return self.copyPayloadShallow(allocator, Payload.U64),434 .int_u64 => return self.copyPayloadShallow(arena, Payload.U64),
433 .int_i64 => return self.copyPayloadShallow(allocator, Payload.I64),435 .int_i64 => return self.copyPayloadShallow(arena, Payload.I64),
434 .int_big_positive, .int_big_negative => {436 .int_big_positive, .int_big_negative => {
435 const old_payload = self.cast(Payload.BigInt).?;437 const old_payload = self.cast(Payload.BigInt).?;
436 const new_payload = try allocator.create(Payload.BigInt);438 const new_payload = try arena.create(Payload.BigInt);
437 new_payload.* = .{439 new_payload.* = .{
438 .base = .{ .tag = self.ptr_otherwise.tag },440 .base = .{ .tag = self.ptr_otherwise.tag },
439 .data = try allocator.dupe(std.math.big.Limb, old_payload.data),441 .data = try arena.dupe(std.math.big.Limb, old_payload.data),
440 };442 };
441 return Value{ .ptr_otherwise = &new_payload.base };443 return Value{ .ptr_otherwise = &new_payload.base };
442 },444 },
443 .function => return self.copyPayloadShallow(allocator, Payload.Function),445 .function => return self.copyPayloadShallow(arena, Payload.Function),
444 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),446 .extern_fn => return self.copyPayloadShallow(arena, Payload.Decl),
445 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),447 .variable => return self.copyPayloadShallow(arena, Payload.Variable),
446 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),448 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),
447 .decl_ref_mut => return self.copyPayloadShallow(allocator, Payload.DeclRefMut),449 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),
448 .elem_ptr => {450 .elem_ptr => {
449 const payload = self.castTag(.elem_ptr).?;451 const payload = self.castTag(.elem_ptr).?;
450 const new_payload = try allocator.create(Payload.ElemPtr);452 const new_payload = try arena.create(Payload.ElemPtr);
451 new_payload.* = .{453 new_payload.* = .{
452 .base = payload.base,454 .base = payload.base,
453 .data = .{455 .data = .{
454 .array_ptr = try payload.data.array_ptr.copy(allocator),456 .array_ptr = try payload.data.array_ptr.copy(arena),
455 .index = payload.data.index,457 .index = payload.data.index,
456 },458 },
457 };459 };
...@@ -459,17 +461,17 @@ pub const Value = extern union {...@@ -459,17 +461,17 @@ pub const Value = extern union {
459 },461 },
460 .field_ptr => {462 .field_ptr => {
461 const payload = self.castTag(.field_ptr).?;463 const payload = self.castTag(.field_ptr).?;
462 const new_payload = try allocator.create(Payload.FieldPtr);464 const new_payload = try arena.create(Payload.FieldPtr);
463 new_payload.* = .{465 new_payload.* = .{
464 .base = payload.base,466 .base = payload.base,
465 .data = .{467 .data = .{
466 .container_ptr = try payload.data.container_ptr.copy(allocator),468 .container_ptr = try payload.data.container_ptr.copy(arena),
467 .field_index = payload.data.field_index,469 .field_index = payload.data.field_index,
468 },470 },
469 };471 };
470 return Value{ .ptr_otherwise = &new_payload.base };472 return Value{ .ptr_otherwise = &new_payload.base };
471 },473 },
472 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),474 .bytes => return self.copyPayloadShallow(arena, Payload.Bytes),
473 .repeated,475 .repeated,
474 .eu_payload,476 .eu_payload,
475 .eu_payload_ptr,477 .eu_payload_ptr,
...@@ -477,61 +479,85 @@ pub const Value = extern union {...@@ -477,61 +479,85 @@ pub const Value = extern union {
477 .opt_payload_ptr,479 .opt_payload_ptr,
478 => {480 => {
479 const payload = self.cast(Payload.SubValue).?;481 const payload = self.cast(Payload.SubValue).?;
480 const new_payload = try allocator.create(Payload.SubValue);482 const new_payload = try arena.create(Payload.SubValue);
481 new_payload.* = .{483 new_payload.* = .{
482 .base = payload.base,484 .base = payload.base,
483 .data = try payload.data.copy(allocator),485 .data = try payload.data.copy(arena),
484 };486 };
485 return Value{ .ptr_otherwise = &new_payload.base };487 return Value{ .ptr_otherwise = &new_payload.base };
486 },488 },
487 .array => {489 .array => {
488 const payload = self.castTag(.array).?;490 const payload = self.castTag(.array).?;
489 const new_payload = try allocator.create(Payload.Array);491 const new_payload = try arena.create(Payload.Array);
490 new_payload.* = .{492 new_payload.* = .{
491 .base = payload.base,493 .base = payload.base,
492 .data = try allocator.alloc(Value, payload.data.len),494 .data = try arena.alloc(Value, payload.data.len),
493 };495 };
494 std.mem.copy(Value, new_payload.data, payload.data);496 std.mem.copy(Value, new_payload.data, payload.data);
495 return Value{ .ptr_otherwise = &new_payload.base };497 return Value{ .ptr_otherwise = &new_payload.base };
496 },498 },
497 .slice => {499 .slice => {
498 const payload = self.castTag(.slice).?;500 const payload = self.castTag(.slice).?;
499 const new_payload = try allocator.create(Payload.Slice);501 const new_payload = try arena.create(Payload.Slice);
500 new_payload.* = .{502 new_payload.* = .{
501 .base = payload.base,503 .base = payload.base,
502 .data = .{504 .data = .{
503 .ptr = try payload.data.ptr.copy(allocator),505 .ptr = try payload.data.ptr.copy(arena),
504 .len = try payload.data.len.copy(allocator),506 .len = try payload.data.len.copy(arena),
505 },507 },
506 };508 };
507 return Value{ .ptr_otherwise = &new_payload.base };509 return Value{ .ptr_otherwise = &new_payload.base };
508 },510 },
509 .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16),511 .float_16 => return self.copyPayloadShallow(arena, Payload.Float_16),
510 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),512 .float_32 => return self.copyPayloadShallow(arena, Payload.Float_32),
511 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),513 .float_64 => return self.copyPayloadShallow(arena, Payload.Float_64),
512 .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),514 .float_128 => return self.copyPayloadShallow(arena, Payload.Float_128),
513 .enum_literal => {515 .enum_literal => {
514 const payload = self.castTag(.enum_literal).?;516 const payload = self.castTag(.enum_literal).?;
515 const new_payload = try allocator.create(Payload.Bytes);517 const new_payload = try arena.create(Payload.Bytes);
516 new_payload.* = .{518 new_payload.* = .{
517 .base = payload.base,519 .base = payload.base,
518 .data = try allocator.dupe(u8, payload.data),520 .data = try arena.dupe(u8, payload.data),
521 };
522 return Value{ .ptr_otherwise = &new_payload.base };
523 },
524 .enum_field_index => return self.copyPayloadShallow(arena, Payload.U32),
525 .@"error" => return self.copyPayloadShallow(arena, Payload.Error),
526
527 .@"struct" => {
528 const old_field_values = self.castTag(.@"struct").?.data;
529 const new_payload = try arena.create(Payload.Struct);
530 new_payload.* = .{
531 .base = .{ .tag = .@"struct" },
532 .data = try arena.alloc(Value, old_field_values.len),
533 };
534 for (old_field_values) |old_field_val, i| {
535 new_payload.data[i] = try old_field_val.copy(arena);
536 }
537 return Value{ .ptr_otherwise = &new_payload.base };
538 },
539
540 .@"union" => {
541 const tag_and_val = self.castTag(.@"union").?.data;
542 const new_payload = try arena.create(Payload.Union);
543 new_payload.* = .{
544 .base = .{ .tag = .@"union" },
545 .data = .{
546 .tag = try tag_and_val.tag.copy(arena),
547 .val = try tag_and_val.val.copy(arena),
548 },
519 };549 };
520 return Value{ .ptr_otherwise = &new_payload.base };550 return Value{ .ptr_otherwise = &new_payload.base };
521 },551 },
522 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
523 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
524 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),
525 .@"union" => @panic("TODO can't copy union value without knowing the type"),
526552
527 .inferred_alloc => unreachable,553 .inferred_alloc => unreachable,
528 .inferred_alloc_comptime => unreachable,554 .inferred_alloc_comptime => unreachable,
529 }555 }
530 }556 }
531557
532 fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {558 fn copyPayloadShallow(self: Value, arena: *Allocator, comptime T: type) error{OutOfMemory}!Value {
533 const payload = self.cast(T).?;559 const payload = self.cast(T).?;
534 const new_payload = try allocator.create(T);560 const new_payload = try arena.create(T);
535 new_payload.* = payload.*;561 new_payload.* = payload.*;
536 return Value{ .ptr_otherwise = &new_payload.base };562 return Value{ .ptr_otherwise = &new_payload.base };
537 }563 }
...@@ -1932,8 +1958,9 @@ pub const Value = extern union {...@@ -1932,8 +1958,9 @@ pub const Value = extern union {
1932 pub const base_tag = Tag.@"struct";1958 pub const base_tag = Tag.@"struct";
19331959
1934 base: Payload = .{ .tag = base_tag },1960 base: Payload = .{ .tag = base_tag },
1935 /// Field values. The number and type are according to the struct type.1961 /// Field values. The types are according to the struct type.
1936 data: [*]Value,1962 /// The length is provided here so that copying a Value does not depend on the Type.
1963 data: []Value,
1937 };1964 };
19381965
1939 pub const Union = struct {1966 pub const Union = struct {