From e6b3cb5043b189fab6417df4a6921728ea174c8f Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 16:07:13 +0200 Subject: [PATCH 1/9] Sema: detect division overflow Closes #13434 --- src/Sema.zig | 30 +++++++++++++--------- test/cases/compile_errors/div_overflow.zig | 11 ++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 test/cases/compile_errors/div_overflow.zig diff --git a/src/Sema.zig b/src/Sema.zig index f3aa861b5c..3def393dfb 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12469,10 +12469,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (maybe_rhs_val) |rhs_val| { if (is_int) { - return sema.addConstant( - resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), - ); + const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target); + var vector_index: usize = undefined; + if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) { + return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); + } + return sema.addConstant(resolved_type, res); } else { return sema.addConstant( resolved_type, @@ -12584,10 +12586,12 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (modulus_val.compareWithZero(.neq)) { return sema.fail(block, src, "exact division produced remainder", .{}); } - return sema.addConstant( - resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), - ); + const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target); + var vector_index: usize = undefined; + if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) { + return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); + } + return sema.addConstant(resolved_type, res); } else { const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target); if (modulus_val.compareWithZero(.neq)) { @@ -12862,10 +12866,12 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (maybe_rhs_val) |rhs_val| { if (is_int) { - return sema.addConstant( - resolved_type, - try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), - ); + const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target); + var vector_index: usize = undefined; + if (!(try sema.intFitsInType(block, src, res, resolved_type, &vector_index))) { + return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); + } + return sema.addConstant(resolved_type, res); } else { return sema.addConstant( resolved_type, diff --git a/test/cases/compile_errors/div_overflow.zig b/test/cases/compile_errors/div_overflow.zig new file mode 100644 index 0000000000..dd828a42fc --- /dev/null +++ b/test/cases/compile_errors/div_overflow.zig @@ -0,0 +1,11 @@ +comptime { + const a = -128; + const b: i8 = -1; + _ = a / b; +} + +// error +// backend=stage2 +// target=native +// +// :4:11: error: overflow of integer type 'i8' with value '128' From 799a558e393d1c8286e8faec2bf8930138d8b1f4 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 17:10:23 +0200 Subject: [PATCH 2/9] Sema: implement peer type resolution of function pointers and function bodies Closes #13438 --- src/Sema.zig | 12 ++++++++++++ test/behavior/cast.zig | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index 3def393dfb..a127031808 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -28769,6 +28769,13 @@ fn resolvePeerTypes( } } }, + .Fn => { + 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)) { + chosen = candidate; + chosen_i = candidate_i + 1; + continue; + } + }, else => {}, } }, @@ -28799,6 +28806,11 @@ fn resolvePeerTypes( .Vector => continue, else => {}, }, + .Fn => if (chosen_ty.isSinglePointer() and chosen_ty.isConstPtr() and chosen_ty.childType().zigTypeTag() == .Fn) { + if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(), candidate_ty, target, src, src)) { + continue; + } + }, else => {}, } diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 07d45ad3dc..0de4b6d53e 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1419,3 +1419,13 @@ test "floatToInt to zero-bit int" { var a: f32 = 0.0; comptime try std.testing.expect(@floatToInt(u0, a) == 0); } + +test "peer type resolution of function pointer and function body" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + const T = fn () u32; + const a: T = undefined; + const b: *const T = undefined; + try expect(@TypeOf(a, b) == *const fn () u32); + try expect(@TypeOf(b, a) == *const fn () u32); +} From 35afa3fd8bdc140baf9d135711833e836de04d86 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 17:47:53 +0200 Subject: [PATCH 3/9] Sema: correct condition in validateArrayInit Closes #13425 --- src/Sema.zig | 2 +- test/behavior/array.zig | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index a127031808..08aecb6097 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4380,7 +4380,7 @@ fn zirValidateArrayInit( var block_index = block.instructions.items.len - 1; while (block.instructions.items[block_index] != elem_ptr_air_inst) { if (block_index == 0) { - array_is_comptime = true; + array_is_comptime = false; continue :outer; } block_index -= 1; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 6311c4cd30..f1dcb3b95d 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -574,3 +574,25 @@ test "tuple to array handles sentinel" { }; try expect(S.b[0] == 1); } + +test "array init of container level array variable" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const S = struct { + var pair: [2]usize = .{ 1, 2 }; + noinline fn foo(x: usize, y: usize) void { + pair = [2]usize{ x, y }; + } + noinline fn bar(x: usize, y: usize) void { + var tmp: [2]usize = .{ x, y }; + pair = tmp; + } + }; + try expectEqual([2]usize{ 1, 2 }, S.pair); + S.foo(3, 4); + try expectEqual([2]usize{ 3, 4 }, S.pair); + S.bar(5, 6); + try expectEqual([2]usize{ 5, 6 }, S.pair); +} From 42db468dcb3de15426f9f8ec8da78e36155e3510 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 18:13:49 +0200 Subject: [PATCH 4/9] Sema: make method call work with optionals and error unions Closes #13414 --- src/Sema.zig | 23 ++++++++++++++++++++++- test/behavior/fn.zig | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index 08aecb6097..849b0053ac 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22833,6 +22833,7 @@ fn fieldCallBind( { const first_param_type = decl_type.fnParamType(0); const first_param_tag = first_param_type.tag(); + var opt_buf: Type.Payload.ElemType = undefined; // zig fmt: off if (first_param_tag == .var_args_param or first_param_tag == .generic_poison or ( @@ -22851,7 +22852,27 @@ fn fieldCallBind( }); return sema.addConstant(ty, value); } else if (first_param_type.eql(concrete_ty, sema.mod)) { - var deref = try sema.analyzeLoad(block, src, object_ptr, src); + const deref = try sema.analyzeLoad(block, src, object_ptr, src); + const ty = Type.Tag.bound_fn.init(); + const value = try Value.Tag.bound_fn.create(arena, .{ + .func_inst = decl_val, + .arg0_inst = deref, + }); + return sema.addConstant(ty, value); + } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .Optional and + first_param_type.optionalChild(&opt_buf).eql(concrete_ty, sema.mod)) + { + const deref = try sema.analyzeLoad(block, src, object_ptr, src); + const ty = Type.Tag.bound_fn.init(); + const value = try Value.Tag.bound_fn.create(arena, .{ + .func_inst = decl_val, + .arg0_inst = deref, + }); + return sema.addConstant(ty, value); + } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .ErrorUnion and + first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod)) + { + const deref = try sema.analyzeLoad(block, src, object_ptr, src); const ty = Type.Tag.bound_fn.init(); const value = try Value.Tag.bound_fn.create(arena, .{ .func_inst = decl_val, diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 06127aa855..eb13ccfec2 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -434,3 +434,22 @@ test "implicit cast function to function ptr" { var fnPtr2: *const fn () callconv(.C) c_int = S2.someFunctionThatReturnsAValue; try expect(fnPtr2() == 123); } + +test "method call with optional and error union first param" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + x: i32 = 1234, + + fn opt(s: ?@This()) !void { + try expect(s.?.x == 1234); + } + fn errUnion(s: anyerror!@This()) !void { + try expect((try s).x == 1234); + } + }; + var s: S = .{}; + try s.opt(); + try s.errUnion(); +} From 51b1083d66b29d110c8cf60b59052170dd34a95f Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 18:38:42 +0200 Subject: [PATCH 5/9] stage2: fix onePossibleValue of empty unions and enums Closes #13402 --- src/Sema.zig | 23 +++++++++++++---------- src/type.zig | 21 +++++++++++---------- test/behavior/empty_union.zig | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 849b0053ac..d7fce06e7f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10343,6 +10343,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); if (special.is_inline) child_block.inline_case_capture = operand; + if (empty_enum) { + return Air.Inst.Ref.void_value; + } return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); } @@ -30479,23 +30482,23 @@ pub fn typeHasOnePossibleValue( if (enum_obj.tag_ty.hasRuntimeBits()) { return null; } - if (enum_obj.fields.count() == 1) { - if (enum_obj.values.count() == 0) { + switch (enum_obj.fields.count()) { + 0 => return Value.initTag(.unreachable_value), + 1 => if (enum_obj.values.count() == 0) { return Value.zero; // auto-numbered } else { return enum_obj.values.keys()[0]; - } - } else { - return null; + }, + else => return null, } }, .enum_simple => { const resolved_ty = try sema.resolveTypeFields(block, src, ty); const enum_simple = resolved_ty.castTag(.enum_simple).?.data; - if (enum_simple.fields.count() == 1) { - return Value.zero; - } else { - return null; + switch (enum_simple.fields.count()) { + 0 => return Value.initTag(.unreachable_value), + 1 => return Value.zero, + else => return null, } }, .enum_nonexhaustive => { @@ -30512,7 +30515,7 @@ pub fn typeHasOnePossibleValue( const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse return null; const fields = union_obj.fields.values(); - if (fields.len == 0) return Value.initTag(.empty_struct_value); + if (fields.len == 0) return Value.initTag(.unreachable_value); const only_field = fields[0]; if (only_field.ty.eql(resolved_ty, sema.mod)) { const msg = try Module.ErrorMsg.create( diff --git a/src/type.zig b/src/type.zig index a12733cbcb..605e4396c0 100644 --- a/src/type.zig +++ b/src/type.zig @@ -5015,22 +5015,22 @@ pub const Type = extern union { if (enum_full.tag_ty.hasRuntimeBits()) { return null; } - if (enum_full.fields.count() == 1) { - if (enum_full.values.count() == 0) { - return Value.zero; + switch (enum_full.fields.count()) { + 0 => return Value.initTag(.unreachable_value), + 1 => if (enum_full.values.count() == 0) { + return Value.zero; // auto-numbered } else { return enum_full.values.keys()[0]; - } - } else { - return null; + }, + else => return null, } }, .enum_simple => { const enum_simple = ty.castTag(.enum_simple).?.data; - if (enum_simple.fields.count() == 1) { - return Value.zero; - } else { - return null; + switch (enum_simple.fields.count()) { + 0 => return Value.initTag(.unreachable_value), + 1 => return Value.zero, + else => return null, } }, .enum_nonexhaustive => { @@ -5044,6 +5044,7 @@ pub const Type = extern union { .@"union", .union_safety_tagged, .union_tagged => { const union_obj = ty.cast(Payload.Union).?.data; const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null; + if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value); const only_field = union_obj.fields.values()[0]; const val_val = only_field.ty.onePossibleValue() orelse return null; _ = tag_val; diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index 55dac727e8..c91fa16d0c 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -48,3 +48,21 @@ test "empty extern union" { try expect(@sizeOf(U) == 0); try expect(@alignOf(U) == 1); } + +test "empty union passed as argument" { + const U = union(enum) { + fn f(u: @This()) void { + switch (u) {} + } + }; + U.f(@as(U, undefined)); +} + +test "empty enum passed as argument" { + const E = enum { + fn f(e: @This()) void { + switch (e) {} + } + }; + E.f(@as(E, undefined)); +} From f92e7bed7b6b83b2cdfe2bfed047e3a7bcdd2116 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 18:47:52 +0200 Subject: [PATCH 6/9] stage2: bitsize of packed struct should trigger backing int ty check Closes #13398 --- src/type.zig | 12 +++++------- ...tsize_of_packed_struct_checks_backing_int_ty.zig | 13 +++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig diff --git a/src/type.zig b/src/type.zig index 605e4396c0..3dc9202917 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3574,15 +3574,13 @@ pub const Type = extern union { .u128, .i128, .f128 => return 128, .@"struct" => { - if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); - if (ty.containerLayout() != .Packed) { + const struct_obj = ty.castTag(.@"struct").?.data; + if (struct_obj.layout != .Packed) { return (try ty.abiSizeAdvanced(target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8; } - var total: u64 = 0; - for (ty.structFields().values()) |field| { - total += try bitSizeAdvanced(field.ty, target, sema_kit); - } - return total; + if (sema_kit) |sk| _ = try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); + assert(struct_obj.haveLayout()); + return try struct_obj.backing_int_ty.bitSizeAdvanced(target, sema_kit); }, .tuple, .anon_struct => { diff --git a/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig b/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig new file mode 100644 index 0000000000..774a9c3376 --- /dev/null +++ b/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig @@ -0,0 +1,13 @@ +const Foo = packed struct(u32) { + x: u1, +}; +fn bar(_: Foo) callconv(.C) void {} +pub export fn entry() void { + bar(.{ .x = 0 }); +} + +// error +// backend=stage2 +// target=native +// +// :1:27: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 1 From f96748ebc19b0c083569e7677f65fe4454c32b57 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 22:28:14 +0200 Subject: [PATCH 7/9] Sema: coerce elements of array cat Closes #13347 --- src/Sema.zig | 12 ++++++++++-- test/behavior/eval.zig | 11 +++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index d7fce06e7f..3259a0831b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11995,10 +11995,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const element_vals = try sema.arena.alloc(Value, final_len_including_sent); var elem_i: usize = 0; while (elem_i < lhs_len) : (elem_i += 1) { - element_vals[elem_i] = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i); + const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i); + const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val); + const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); + const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); + element_vals[elem_i] = coereced_elem_val; } while (elem_i < result_len) : (elem_i += 1) { - element_vals[elem_i] = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len); + const elem_val = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len); + const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val); + const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); + const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); + element_vals[elem_i] = coereced_elem_val; } if (res_sent_val) |sent_val| { element_vals[result_len] = sent_val; diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 617cc6dfd4..8a669b28f3 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -1488,3 +1488,14 @@ test "x or true is comptime-known true" { } try expect(T.x == 3); } + +test "non-optional and optional array elements concatenated" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const array = [1]u8{'A'} ++ [1]?u8{null}; + var index: usize = 0; + try expect(array[index].? == 'A'); +} From ea48f06fc2965ff2e9516c23e58a50a9db5da84b Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 4 Nov 2022 23:12:34 +0200 Subject: [PATCH 8/9] stage2: address of threadlocal variable is not comptime known Closes #13215 --- src/Sema.zig | 26 ++++++++++++++++++- src/value.zig | 23 ++++++++++++++++ ...ress_of_threadlocal_not_comptime_known.zig | 13 ++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig diff --git a/src/Sema.zig b/src/Sema.zig index 3259a0831b..e453d0d9e0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1917,6 +1917,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; const val = sema.air_values.items[ty_pl.payload]; if (val.tag() == .runtime_value) make_runtime.* = true; + if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; return val; }, .const_ty => { @@ -32086,15 +32087,36 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { const ptr_info = ptr_ty.ptrInfo().data; const elem_ty = ptr_ty.elemType2(); const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; + const target = sema.mod.getTarget(); + const parent_ty = ptr_ty.childType(); + + const vector_info: struct { + host_size: u16, + bit_offset: u16, + alignment: u32, + } = if (parent_ty.tag() == .vector) blk: { + const elem_bits = elem_ty.bitSize(target); + const is_packed = elem_bits != 0 and (elem_bits & (elem_bits - 1)) != 0; + // TODO: runtime-known index + assert(!is_packed or offset != null); + const is_packed_with_offset = is_packed and offset != null and offset.? != 0; + const target_offset = if (is_packed_with_offset) (if (target.cpu.arch.endian() == .Big) (parent_ty.vectorLen() - 1 - offset.?) else offset.?) else 0; + break :blk .{ + .host_size = if (is_packed_with_offset) @intCast(u16, parent_ty.abiSize(target)) else 0, + .bit_offset = if (is_packed_with_offset) @intCast(u16, elem_bits * target_offset) else 0, + .alignment = if (is_packed_with_offset) @intCast(u16, parent_ty.abiAlignment(target)) else 0, + }; + } else .{ .host_size = 0, .bit_offset = 0, .alignment = 0 }; + const alignment: u32 = a: { // Calculate the new pointer alignment. if (ptr_info.@"align" == 0) { + if (vector_info.alignment != 0) break :a vector_info.alignment; // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. break :a 0; } // If the addend is not a comptime-known value we can still count on // it being a multiple of the type size. - const target = sema.mod.getTarget(); const elem_size = elem_ty.abiSize(target); const addend = if (offset) |off| elem_size * off else elem_size; @@ -32111,5 +32133,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { .@"allowzero" = allow_zero, .@"volatile" = ptr_info.@"volatile", .@"align" = alignment, + .host_size = vector_info.host_size, + .bit_offset = vector_info.bit_offset, }); } diff --git a/src/value.zig b/src/value.zig index a727df5d22..792ec5068f 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2806,6 +2806,29 @@ pub const Value = extern union { }; } + pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool { + return switch (val.tag()) { + .variable => false, + else => val.isPtrToThreadLocalInner(mod), + }; + } + + fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { + return switch (val.tag()) { + .slice => val.castTag(.slice).?.data.ptr.isPtrToThreadLocalInner(mod), + .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isPtrToThreadLocalInner(mod), + .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isPtrToThreadLocalInner(mod), + .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), + .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), + .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), + .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isPtrToThreadLocalInner(mod), + .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isPtrToThreadLocalInner(mod), + + .variable => val.castTag(.variable).?.data.is_threadlocal, + else => false, + }; + } + // Asserts that the provided start/end are in-bounds. pub fn sliceArray( val: Value, diff --git a/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig new file mode 100644 index 0000000000..d2d62c82ab --- /dev/null +++ b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig @@ -0,0 +1,13 @@ +threadlocal var global: u32 = 23; +threadlocal var global_ptr: *u32 = &global; + +pub export fn entry() void { + if (global_ptr.* != 23) unreachable; +} + +// error +// backend=stage2 +// target=native +// +// :2:36: error: unable to resolve comptime value +// :2:36: note: container level variable initializers must be comptime-known From 5d28d171dffd5a03276e04ec7089593e967630df Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 5 Nov 2022 12:51:32 +0200 Subject: [PATCH 9/9] Sema: adjust result type of anyerror field access Closes #13448 --- src/Sema.zig | 10 ++++++++-- test/behavior/error.zig | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index e453d0d9e0..d9f514a6e7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22475,7 +22475,10 @@ fn fieldVal( } else (try sema.mod.getErrorValue(field_name)).key; return sema.addConstant( - try child_type.copy(arena), + if (!child_type.isAnyError()) + try child_type.copy(arena) + else + try Type.Tag.error_set_single.create(arena, name), try Value.Tag.@"error".create(arena, .{ .name = name }), ); }, @@ -22686,7 +22689,10 @@ fn fieldPtr( var anon_decl = try block.startAnonDecl(src); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( - try child_type.copy(anon_decl.arena()), + if (!child_type.isAnyError()) + try child_type.copy(anon_decl.arena()) + else + try Type.Tag.error_set_single.create(anon_decl.arena(), name), try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), 0, // default alignment )); diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 2013cbcfa3..25feb101bc 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -855,3 +855,13 @@ test "error from comptime string" { try expect(mem.eql(u8, name, @errorName(err))); } } + +test "field access of anyerror results in smaller error set" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + const E1 = @TypeOf(error.Foo); + try expect(@TypeOf(E1.Foo) == E1); + const E2 = error{ A, B, C }; + try expect(@TypeOf(E2.A) == E2); + try expect(@TypeOf(@field(anyerror, "NotFound")) == error{NotFound}); +}