authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-07 14:17:26+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 13:52:37-07:00
log6ea3d3e19fce2317e8d7e60a78307f16f2538d72
treebe0d8fd8353e7bef9295f59bf86042fc4c2f7935
parent6a94bcbbc6fdd4cd33981f924a7bd27773889e53

Merge pull request #13446 from Vexu/stage2-fixes

Stage2 bug fixes

12 files changed, 275 insertions(+), 46 deletions(-)

src/Sema.zig+109-29
...@@ -1917,6 +1917,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(...@@ -1917,6 +1917,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
1917 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;1917 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
1918 const val = sema.air_values.items[ty_pl.payload];1918 const val = sema.air_values.items[ty_pl.payload];
1919 if (val.tag() == .runtime_value) make_runtime.* = true;1919 if (val.tag() == .runtime_value) make_runtime.* = true;
1920 if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
1920 return val;1921 return val;
1921 },1922 },
1922 .const_ty => {1923 .const_ty => {
...@@ -4380,7 +4381,7 @@ fn zirValidateArrayInit(...@@ -4380,7 +4381,7 @@ fn zirValidateArrayInit(
4380 var block_index = block.instructions.items.len - 1;4381 var block_index = block.instructions.items.len - 1;
4381 while (block.instructions.items[block_index] != elem_ptr_air_inst) {4382 while (block.instructions.items[block_index] != elem_ptr_air_inst) {
4382 if (block_index == 0) {4383 if (block_index == 0) {
4383 array_is_comptime = true;4384 array_is_comptime = false;
4384 continue :outer;4385 continue :outer;
4385 }4386 }
4386 block_index -= 1;4387 block_index -= 1;
...@@ -10343,6 +10344,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10343,6 +10344,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10343 }10344 }
10344 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);10345 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
10345 if (special.is_inline) child_block.inline_case_capture = operand;10346 if (special.is_inline) child_block.inline_case_capture = operand;
10347 if (empty_enum) {
10348 return Air.Inst.Ref.void_value;
10349 }
10346 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);10350 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
10347 }10351 }
1034810352
...@@ -11992,10 +11996,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11992,10 +11996,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
11992 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);11996 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
11993 var elem_i: usize = 0;11997 var elem_i: usize = 0;
11994 while (elem_i < lhs_len) : (elem_i += 1) {11998 while (elem_i < lhs_len) : (elem_i += 1) {
11995 element_vals[elem_i] = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i);11999 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i);
12000 const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val);
12001 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
12002 const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
12003 element_vals[elem_i] = coereced_elem_val;
11996 }12004 }
11997 while (elem_i < result_len) : (elem_i += 1) {12005 while (elem_i < result_len) : (elem_i += 1) {
11998 element_vals[elem_i] = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len);12006 const elem_val = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len);
12007 const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val);
12008 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
12009 const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
12010 element_vals[elem_i] = coereced_elem_val;
11999 }12011 }
12000 if (res_sent_val) |sent_val| {12012 if (res_sent_val) |sent_val| {
12001 element_vals[result_len] = sent_val;12013 element_vals[result_len] = sent_val;
...@@ -12469,10 +12481,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -12469,10 +12481,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1246912481
12470 if (maybe_rhs_val) |rhs_val| {12482 if (maybe_rhs_val) |rhs_val| {
12471 if (is_int) {12483 if (is_int) {
12472 return sema.addConstant(12484 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target);
12473 resolved_type,12485 var vector_index: usize = undefined;
12474 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),12486 if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) {
12475 );12487 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
12488 }
12489 return sema.addConstant(resolved_type, res);
12476 } else {12490 } else {
12477 return sema.addConstant(12491 return sema.addConstant(
12478 resolved_type,12492 resolved_type,
...@@ -12584,10 +12598,12 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12584,10 +12598,12 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12584 if (modulus_val.compareWithZero(.neq)) {12598 if (modulus_val.compareWithZero(.neq)) {
12585 return sema.fail(block, src, "exact division produced remainder", .{});12599 return sema.fail(block, src, "exact division produced remainder", .{});
12586 }12600 }
12587 return sema.addConstant(12601 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target);
12588 resolved_type,12602 var vector_index: usize = undefined;
12589 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),12603 if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) {
12590 );12604 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
12605 }
12606 return sema.addConstant(resolved_type, res);
12591 } else {12607 } else {
12592 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);12608 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);
12593 if (modulus_val.compareWithZero(.neq)) {12609 if (modulus_val.compareWithZero(.neq)) {
...@@ -12862,10 +12878,12 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12862,10 +12878,12 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1286212878
12863 if (maybe_rhs_val) |rhs_val| {12879 if (maybe_rhs_val) |rhs_val| {
12864 if (is_int) {12880 if (is_int) {
12865 return sema.addConstant(12881 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target);
12866 resolved_type,12882 var vector_index: usize = undefined;
12867 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),12883 if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) {
12868 );12884 return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
12885 }
12886 return sema.addConstant(resolved_type, res);
12869 } else {12887 } else {
12870 return sema.addConstant(12888 return sema.addConstant(
12871 resolved_type,12889 resolved_type,
...@@ -22457,7 +22475,10 @@ fn fieldVal(...@@ -22457,7 +22475,10 @@ fn fieldVal(
22457 } else (try sema.mod.getErrorValue(field_name)).key;22475 } else (try sema.mod.getErrorValue(field_name)).key;
2245822476
22459 return sema.addConstant(22477 return sema.addConstant(
22460 try child_type.copy(arena),22478 if (!child_type.isAnyError())
22479 try child_type.copy(arena)
22480 else
22481 try Type.Tag.error_set_single.create(arena, name),
22461 try Value.Tag.@"error".create(arena, .{ .name = name }),22482 try Value.Tag.@"error".create(arena, .{ .name = name }),
22462 );22483 );
22463 },22484 },
...@@ -22668,7 +22689,10 @@ fn fieldPtr(...@@ -22668,7 +22689,10 @@ fn fieldPtr(
22668 var anon_decl = try block.startAnonDecl(src);22689 var anon_decl = try block.startAnonDecl(src);
22669 defer anon_decl.deinit();22690 defer anon_decl.deinit();
22670 return sema.analyzeDeclRef(try anon_decl.finish(22691 return sema.analyzeDeclRef(try anon_decl.finish(
22671 try child_type.copy(anon_decl.arena()),22692 if (!child_type.isAnyError())
22693 try child_type.copy(anon_decl.arena())
22694 else
22695 try Type.Tag.error_set_single.create(anon_decl.arena(), name),
22672 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),22696 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
22673 0, // default alignment22697 0, // default alignment
22674 ));22698 ));
...@@ -22827,6 +22851,7 @@ fn fieldCallBind(...@@ -22827,6 +22851,7 @@ fn fieldCallBind(
22827 {22851 {
22828 const first_param_type = decl_type.fnParamType(0);22852 const first_param_type = decl_type.fnParamType(0);
22829 const first_param_tag = first_param_type.tag();22853 const first_param_tag = first_param_type.tag();
22854 var opt_buf: Type.Payload.ElemType = undefined;
22830 // zig fmt: off22855 // zig fmt: off
22831 if (first_param_tag == .var_args_param or22856 if (first_param_tag == .var_args_param or
22832 first_param_tag == .generic_poison or (22857 first_param_tag == .generic_poison or (
...@@ -22845,7 +22870,27 @@ fn fieldCallBind(...@@ -22845,7 +22870,27 @@ fn fieldCallBind(
22845 });22870 });
22846 return sema.addConstant(ty, value);22871 return sema.addConstant(ty, value);
22847 } else if (first_param_type.eql(concrete_ty, sema.mod)) {22872 } else if (first_param_type.eql(concrete_ty, sema.mod)) {
22848 var deref = try sema.analyzeLoad(block, src, object_ptr, src);22873 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
22874 const ty = Type.Tag.bound_fn.init();
22875 const value = try Value.Tag.bound_fn.create(arena, .{
22876 .func_inst = decl_val,
22877 .arg0_inst = deref,
22878 });
22879 return sema.addConstant(ty, value);
22880 } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .Optional and
22881 first_param_type.optionalChild(&opt_buf).eql(concrete_ty, sema.mod))
22882 {
22883 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
22884 const ty = Type.Tag.bound_fn.init();
22885 const value = try Value.Tag.bound_fn.create(arena, .{
22886 .func_inst = decl_val,
22887 .arg0_inst = deref,
22888 });
22889 return sema.addConstant(ty, value);
22890 } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .ErrorUnion and
22891 first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
22892 {
22893 const deref = try sema.analyzeLoad(block, src, object_ptr, src);
22849 const ty = Type.Tag.bound_fn.init();22894 const ty = Type.Tag.bound_fn.init();
22850 const value = try Value.Tag.bound_fn.create(arena, .{22895 const value = try Value.Tag.bound_fn.create(arena, .{
22851 .func_inst = decl_val,22896 .func_inst = decl_val,
...@@ -28763,6 +28808,13 @@ fn resolvePeerTypes(...@@ -28763,6 +28808,13 @@ fn resolvePeerTypes(
28763 }28808 }
28764 }28809 }
28765 },28810 },
28811 .Fn => {
28812 if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag() == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) {
28813 chosen = candidate;
28814 chosen_i = candidate_i + 1;
28815 continue;
28816 }
28817 },
28766 else => {},28818 else => {},
28767 }28819 }
28768 },28820 },
...@@ -28793,6 +28845,11 @@ fn resolvePeerTypes(...@@ -28793,6 +28845,11 @@ fn resolvePeerTypes(
28793 .Vector => continue,28845 .Vector => continue,
28794 else => {},28846 else => {},
28795 },28847 },
28848 .Fn => if (chosen_ty.isSinglePointer() and chosen_ty.isConstPtr() and chosen_ty.childType().zigTypeTag() == .Fn) {
28849 if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(), candidate_ty, target, src, src)) {
28850 continue;
28851 }
28852 },
28796 else => {},28853 else => {},
28797 }28854 }
2879828855
...@@ -30440,23 +30497,23 @@ pub fn typeHasOnePossibleValue(...@@ -30440,23 +30497,23 @@ pub fn typeHasOnePossibleValue(
30440 if (enum_obj.tag_ty.hasRuntimeBits()) {30497 if (enum_obj.tag_ty.hasRuntimeBits()) {
30441 return null;30498 return null;
30442 }30499 }
30443 if (enum_obj.fields.count() == 1) {30500 switch (enum_obj.fields.count()) {
30444 if (enum_obj.values.count() == 0) {30501 0 => return Value.initTag(.unreachable_value),
30502 1 => if (enum_obj.values.count() == 0) {
30445 return Value.zero; // auto-numbered30503 return Value.zero; // auto-numbered
30446 } else {30504 } else {
30447 return enum_obj.values.keys()[0];30505 return enum_obj.values.keys()[0];
30448 }30506 },
30449 } else {30507 else => return null,
30450 return null;
30451 }30508 }
30452 },30509 },
30453 .enum_simple => {30510 .enum_simple => {
30454 const resolved_ty = try sema.resolveTypeFields(block, src, ty);30511 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
30455 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;30512 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
30456 if (enum_simple.fields.count() == 1) {30513 switch (enum_simple.fields.count()) {
30457 return Value.zero;30514 0 => return Value.initTag(.unreachable_value),
30458 } else {30515 1 => return Value.zero,
30459 return null;30516 else => return null,
30460 }30517 }
30461 },30518 },
30462 .enum_nonexhaustive => {30519 .enum_nonexhaustive => {
...@@ -30473,7 +30530,7 @@ pub fn typeHasOnePossibleValue(...@@ -30473,7 +30530,7 @@ pub fn typeHasOnePossibleValue(
30473 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse30530 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
30474 return null;30531 return null;
30475 const fields = union_obj.fields.values();30532 const fields = union_obj.fields.values();
30476 if (fields.len == 0) return Value.initTag(.empty_struct_value);30533 if (fields.len == 0) return Value.initTag(.unreachable_value);
30477 const only_field = fields[0];30534 const only_field = fields[0];
30478 if (only_field.ty.eql(resolved_ty, sema.mod)) {30535 if (only_field.ty.eql(resolved_ty, sema.mod)) {
30479 const msg = try Module.ErrorMsg.create(30536 const msg = try Module.ErrorMsg.create(
...@@ -32036,15 +32093,36 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -32036,15 +32093,36 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
32036 const ptr_info = ptr_ty.ptrInfo().data;32093 const ptr_info = ptr_ty.ptrInfo().data;
32037 const elem_ty = ptr_ty.elemType2();32094 const elem_ty = ptr_ty.elemType2();
32038 const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;32095 const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;
32096 const target = sema.mod.getTarget();
32097 const parent_ty = ptr_ty.childType();
32098
32099 const vector_info: struct {
32100 host_size: u16,
32101 bit_offset: u16,
32102 alignment: u32,
32103 } = if (parent_ty.tag() == .vector) blk: {
32104 const elem_bits = elem_ty.bitSize(target);
32105 const is_packed = elem_bits != 0 and (elem_bits & (elem_bits - 1)) != 0;
32106 // TODO: runtime-known index
32107 assert(!is_packed or offset != null);
32108 const is_packed_with_offset = is_packed and offset != null and offset.? != 0;
32109 const target_offset = if (is_packed_with_offset) (if (target.cpu.arch.endian() == .Big) (parent_ty.vectorLen() - 1 - offset.?) else offset.?) else 0;
32110 break :blk .{
32111 .host_size = if (is_packed_with_offset) @intCast(u16, parent_ty.abiSize(target)) else 0,
32112 .bit_offset = if (is_packed_with_offset) @intCast(u16, elem_bits * target_offset) else 0,
32113 .alignment = if (is_packed_with_offset) @intCast(u16, parent_ty.abiAlignment(target)) else 0,
32114 };
32115 } else .{ .host_size = 0, .bit_offset = 0, .alignment = 0 };
32116
32039 const alignment: u32 = a: {32117 const alignment: u32 = a: {
32040 // Calculate the new pointer alignment.32118 // Calculate the new pointer alignment.
32041 if (ptr_info.@"align" == 0) {32119 if (ptr_info.@"align" == 0) {
32120 if (vector_info.alignment != 0) break :a vector_info.alignment;
32042 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.32121 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
32043 break :a 0;32122 break :a 0;
32044 }32123 }
32045 // If the addend is not a comptime-known value we can still count on32124 // If the addend is not a comptime-known value we can still count on
32046 // it being a multiple of the type size.32125 // it being a multiple of the type size.
32047 const target = sema.mod.getTarget();
32048 const elem_size = elem_ty.abiSize(target);32126 const elem_size = elem_ty.abiSize(target);
32049 const addend = if (offset) |off| elem_size * off else elem_size;32127 const addend = if (offset) |off| elem_size * off else elem_size;
3205032128
...@@ -32061,5 +32139,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -32061,5 +32139,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
32061 .@"allowzero" = allow_zero,32139 .@"allowzero" = allow_zero,
32062 .@"volatile" = ptr_info.@"volatile",32140 .@"volatile" = ptr_info.@"volatile",
32063 .@"align" = alignment,32141 .@"align" = alignment,
32142 .host_size = vector_info.host_size,
32143 .bit_offset = vector_info.bit_offset,
32064 });32144 });
32065}32145}
src/type.zig+16-17
...@@ -3574,15 +3574,13 @@ pub const Type = extern union {...@@ -3574,15 +3574,13 @@ pub const Type = extern union {
3574 .u128, .i128, .f128 => return 128,3574 .u128, .i128, .f128 => return 128,
35753575
3576 .@"struct" => {3576 .@"struct" => {
3577 if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);3577 const struct_obj = ty.castTag(.@"struct").?.data;
3578 if (ty.containerLayout() != .Packed) {3578 if (struct_obj.layout != .Packed) {
3579 return (try ty.abiSizeAdvanced(target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8;3579 return (try ty.abiSizeAdvanced(target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8;
3580 }3580 }
3581 var total: u64 = 0;3581 if (sema_kit) |sk| _ = try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
3582 for (ty.structFields().values()) |field| {3582 assert(struct_obj.haveLayout());
3583 total += try bitSizeAdvanced(field.ty, target, sema_kit);3583 return try struct_obj.backing_int_ty.bitSizeAdvanced(target, sema_kit);
3584 }
3585 return total;
3586 },3584 },
35873585
3588 .tuple, .anon_struct => {3586 .tuple, .anon_struct => {
...@@ -5015,22 +5013,22 @@ pub const Type = extern union {...@@ -5015,22 +5013,22 @@ pub const Type = extern union {
5015 if (enum_full.tag_ty.hasRuntimeBits()) {5013 if (enum_full.tag_ty.hasRuntimeBits()) {
5016 return null;5014 return null;
5017 }5015 }
5018 if (enum_full.fields.count() == 1) {5016 switch (enum_full.fields.count()) {
5019 if (enum_full.values.count() == 0) {5017 0 => return Value.initTag(.unreachable_value),
5020 return Value.zero;5018 1 => if (enum_full.values.count() == 0) {
5019 return Value.zero; // auto-numbered
5021 } else {5020 } else {
5022 return enum_full.values.keys()[0];5021 return enum_full.values.keys()[0];
5023 }5022 },
5024 } else {5023 else => return null,
5025 return null;
5026 }5024 }
5027 },5025 },
5028 .enum_simple => {5026 .enum_simple => {
5029 const enum_simple = ty.castTag(.enum_simple).?.data;5027 const enum_simple = ty.castTag(.enum_simple).?.data;
5030 if (enum_simple.fields.count() == 1) {5028 switch (enum_simple.fields.count()) {
5031 return Value.zero;5029 0 => return Value.initTag(.unreachable_value),
5032 } else {5030 1 => return Value.zero,
5033 return null;5031 else => return null,
5034 }5032 }
5035 },5033 },
5036 .enum_nonexhaustive => {5034 .enum_nonexhaustive => {
...@@ -5044,6 +5042,7 @@ pub const Type = extern union {...@@ -5044,6 +5042,7 @@ pub const Type = extern union {
5044 .@"union", .union_safety_tagged, .union_tagged => {5042 .@"union", .union_safety_tagged, .union_tagged => {
5045 const union_obj = ty.cast(Payload.Union).?.data;5043 const union_obj = ty.cast(Payload.Union).?.data;
5046 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;5044 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
5045 if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value);
5047 const only_field = union_obj.fields.values()[0];5046 const only_field = union_obj.fields.values()[0];
5048 const val_val = only_field.ty.onePossibleValue() orelse return null;5047 const val_val = only_field.ty.onePossibleValue() orelse return null;
5049 _ = tag_val;5048 _ = tag_val;
src/value.zig+23
...@@ -2806,6 +2806,29 @@ pub const Value = extern union {...@@ -2806,6 +2806,29 @@ pub const Value = extern union {
2806 };2806 };
2807 }2807 }
28082808
2809 pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
2810 return switch (val.tag()) {
2811 .variable => false,
2812 else => val.isPtrToThreadLocalInner(mod),
2813 };
2814 }
2815
2816 fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool {
2817 return switch (val.tag()) {
2818 .slice => val.castTag(.slice).?.data.ptr.isPtrToThreadLocalInner(mod),
2819 .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isPtrToThreadLocalInner(mod),
2820 .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isPtrToThreadLocalInner(mod),
2821 .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod),
2822 .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod),
2823 .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod),
2824 .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isPtrToThreadLocalInner(mod),
2825 .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isPtrToThreadLocalInner(mod),
2826
2827 .variable => val.castTag(.variable).?.data.is_threadlocal,
2828 else => false,
2829 };
2830 }
2831
2809 // Asserts that the provided start/end are in-bounds.2832 // Asserts that the provided start/end are in-bounds.
2810 pub fn sliceArray(2833 pub fn sliceArray(
2811 val: Value,2834 val: Value,
test/behavior/array.zig+22
...@@ -574,3 +574,25 @@ test "tuple to array handles sentinel" {...@@ -574,3 +574,25 @@ test "tuple to array handles sentinel" {
574 };574 };
575 try expect(S.b[0] == 1);575 try expect(S.b[0] == 1);
576}576}
577
578test "array init of container level array variable" {
579 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
582
583 const S = struct {
584 var pair: [2]usize = .{ 1, 2 };
585 noinline fn foo(x: usize, y: usize) void {
586 pair = [2]usize{ x, y };
587 }
588 noinline fn bar(x: usize, y: usize) void {
589 var tmp: [2]usize = .{ x, y };
590 pair = tmp;
591 }
592 };
593 try expectEqual([2]usize{ 1, 2 }, S.pair);
594 S.foo(3, 4);
595 try expectEqual([2]usize{ 3, 4 }, S.pair);
596 S.bar(5, 6);
597 try expectEqual([2]usize{ 5, 6 }, S.pair);
598}
test/behavior/cast.zig+10
...@@ -1419,3 +1419,13 @@ test "floatToInt to zero-bit int" {...@@ -1419,3 +1419,13 @@ test "floatToInt to zero-bit int" {
1419 var a: f32 = 0.0;1419 var a: f32 = 0.0;
1420 comptime try std.testing.expect(@floatToInt(u0, a) == 0);1420 comptime try std.testing.expect(@floatToInt(u0, a) == 0);
1421}1421}
1422
1423test "peer type resolution of function pointer and function body" {
1424 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1425
1426 const T = fn () u32;
1427 const a: T = undefined;
1428 const b: *const T = undefined;
1429 try expect(@TypeOf(a, b) == *const fn () u32);
1430 try expect(@TypeOf(b, a) == *const fn () u32);
1431}
test/behavior/empty_union.zig+18
...@@ -48,3 +48,21 @@ test "empty extern union" {...@@ -48,3 +48,21 @@ test "empty extern union" {
48 try expect(@sizeOf(U) == 0);48 try expect(@sizeOf(U) == 0);
49 try expect(@alignOf(U) == 1);49 try expect(@alignOf(U) == 1);
50}50}
51
52test "empty union passed as argument" {
53 const U = union(enum) {
54 fn f(u: @This()) void {
55 switch (u) {}
56 }
57 };
58 U.f(@as(U, undefined));
59}
60
61test "empty enum passed as argument" {
62 const E = enum {
63 fn f(e: @This()) void {
64 switch (e) {}
65 }
66 };
67 E.f(@as(E, undefined));
68}
test/behavior/error.zig+10
...@@ -855,3 +855,13 @@ test "error from comptime string" {...@@ -855,3 +855,13 @@ test "error from comptime string" {
855 try expect(mem.eql(u8, name, @errorName(err)));855 try expect(mem.eql(u8, name, @errorName(err)));
856 }856 }
857}857}
858
859test "field access of anyerror results in smaller error set" {
860 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
861
862 const E1 = @TypeOf(error.Foo);
863 try expect(@TypeOf(E1.Foo) == E1);
864 const E2 = error{ A, B, C };
865 try expect(@TypeOf(E2.A) == E2);
866 try expect(@TypeOf(@field(anyerror, "NotFound")) == error{NotFound});
867}
test/behavior/eval.zig+11
...@@ -1488,3 +1488,14 @@ test "x or true is comptime-known true" {...@@ -1488,3 +1488,14 @@ test "x or true is comptime-known true" {
1488 }1488 }
1489 try expect(T.x == 3);1489 try expect(T.x == 3);
1490}1490}
1491
1492test "non-optional and optional array elements concatenated" {
1493 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1495 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1496 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1497
1498 const array = [1]u8{'A'} ++ [1]?u8{null};
1499 var index: usize = 0;
1500 try expect(array[index].? == 'A');
1501}
test/behavior/fn.zig+19
...@@ -434,3 +434,22 @@ test "implicit cast function to function ptr" {...@@ -434,3 +434,22 @@ test "implicit cast function to function ptr" {
434 var fnPtr2: *const fn () callconv(.C) c_int = S2.someFunctionThatReturnsAValue;434 var fnPtr2: *const fn () callconv(.C) c_int = S2.someFunctionThatReturnsAValue;
435 try expect(fnPtr2() == 123);435 try expect(fnPtr2() == 123);
436}436}
437
438test "method call with optional and error union first param" {
439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
441
442 const S = struct {
443 x: i32 = 1234,
444
445 fn opt(s: ?@This()) !void {
446 try expect(s.?.x == 1234);
447 }
448 fn errUnion(s: anyerror!@This()) !void {
449 try expect((try s).x == 1234);
450 }
451 };
452 var s: S = .{};
453 try s.opt();
454 try s.errUnion();
455}
test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig created+13
...@@ -0,0 +1,13 @@
1threadlocal var global: u32 = 23;
2threadlocal var global_ptr: *u32 = &global;
3
4pub export fn entry() void {
5 if (global_ptr.* != 23) unreachable;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:36: error: unable to resolve comptime value
13// :2:36: note: container level variable initializers must be comptime-known
test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig created+13
...@@ -0,0 +1,13 @@
1const Foo = packed struct(u32) {
2 x: u1,
3};
4fn bar(_: Foo) callconv(.C) void {}
5pub export fn entry() void {
6 bar(.{ .x = 0 });
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :1:27: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 1
test/cases/compile_errors/div_overflow.zig created+11
...@@ -0,0 +1,11 @@
1comptime {
2 const a = -128;
3 const b: i8 = -1;
4 _ = a / b;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :4:11: error: overflow of integer type 'i8' with value '128'