Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more misc stage2 fixes #11733

Merged
merged 4 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9915,7 +9915,7 @@ const GenZir = struct {
.inferred_ptr => |ptr| {
gz.rl_ty_inst = .none;
gz.rl_ptr = ptr;
gz.break_result_loc = .{ .block_ptr = gz };
gz.break_result_loc = parent_rl;
},

.block_ptr => |parent_block_scope| {
Expand Down
70 changes: 67 additions & 3 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,28 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com

if (var_is_mut) {
try sema.validateVarType(block, ty_src, final_elem_ty, false);

// The value might have been bitcasted into a comptime only
// pointer type such as `*@Type(.EnumLiteral)` so we must now
// update all the stores to not give backends invalid AIR.

var air_tags = sema.air_instructions.items(.tag);
var air_data = sema.air_instructions.items(.data);
var peer_inst_index: usize = 0;
var i = ptr_inst;
while (i < air_tags.len and peer_inst_index < peer_inst_list.len) : (i += 1) {
if (air_tags[i] != .store) continue;
if (air_data[i].bin_op.rhs == peer_inst_list[peer_inst_index]) {
peer_inst_index += 1;
_ = (try sema.resolveMaybeUndefVal(block, .unneeded, air_data[i].bin_op.rhs)) orelse continue;
const coerced_val = try sema.coerce(block, final_elem_ty, air_data[i].bin_op.rhs, .unneeded);
air_tags = sema.air_instructions.items(.tag);
air_data = sema.air_instructions.items(.data);

air_data[i].bin_op.lhs = ptr;
air_data[i].bin_op.rhs = coerced_val;
}
}
} else ct: {
// Detect if the value is comptime known. In such case, the
// last 3 AIR instructions of the block will look like this:
Expand Down Expand Up @@ -5814,8 +5836,10 @@ fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
defer tracy.end();

const bin_inst = sema.code.instructions.items(.data)[inst].bin;
const len = try sema.resolveInt(block, .unneeded, bin_inst.lhs, Type.usize);
const elem_type = try sema.resolveType(block, .unneeded, bin_inst.rhs);
const len_src = sema.src; // TODO better source location
const elem_src = sema.src; // TODO better source location
const len = try sema.resolveInt(block, len_src, bin_inst.lhs, Type.usize);
const elem_type = try sema.resolveType(block, elem_src, bin_inst.rhs);
const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod);

return sema.addType(array_ty);
Expand Down Expand Up @@ -7307,9 +7331,11 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
defer tracy.end();

const bin_inst = sema.code.instructions.items(.data)[inst].bin;
const src = sema.src; // TODO better source location
const elem_index_src = sema.src; // TODO better source location
const array = try sema.resolveInst(bin_inst.lhs);
const elem_index = try sema.resolveInst(bin_inst.rhs);
return sema.elemVal(block, sema.src, array, elem_index, sema.src);
return sema.elemVal(block, src, array, elem_index, elem_index_src);
}

fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
Expand Down Expand Up @@ -18471,6 +18497,25 @@ fn elemValArray(
}
}

const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false);
if (!valid_rt) {
const msg = msg: {
const msg = try sema.errMsg(
block,
elem_index_src,
"values of type '{}' must be comptime known, but index value is runtime known",
.{array_ty.fmt(sema.mod)},
);
errdefer msg.destroy(sema.gpa);

const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_src.toSrcLoc(src_decl), array_ty);

break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
}

const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
try sema.requireRuntimeBlock(block, runtime_src);
if (block.wantSafety()) {
Expand Down Expand Up @@ -18526,6 +18571,25 @@ fn elemPtrArray(
}
}

const valid_rt = try sema.validateRunTimeType(block, elem_index_src, array_ty.elemType2(), false);
if (!valid_rt) {
const msg = msg: {
const msg = try sema.errMsg(
block,
elem_index_src,
"values of type '{}' must be comptime known, but index value is runtime known",
.{array_ty.fmt(sema.mod)},
);
errdefer msg.destroy(sema.gpa);

const src_decl = sema.mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_ptr_src.toSrcLoc(src_decl), array_ty);

break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
}

const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
try sema.requireRuntimeBlock(block, runtime_src);
if (block.wantSafety()) {
Expand Down
1 change: 1 addition & 0 deletions test/behavior.zig
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ test {
_ = @import("behavior/bugs/11159.zig");
_ = @import("behavior/bugs/11162.zig");
_ = @import("behavior/bugs/11165.zig");
_ = @import("behavior/bugs/11179.zig");
_ = @import("behavior/bugs/11181.zig");
_ = @import("behavior/bugs/11182.zig");
_ = @import("behavior/bugs/11213.zig");
Expand Down
12 changes: 12 additions & 0 deletions test/behavior/basic.zig
Original file line number Diff line number Diff line change
Expand Up @@ -933,3 +933,15 @@ test "try in labeled block doesn't cast to wrong type" {
};
_ = s;
}

test "comptime int in switch in catch is casted to correct inferred type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;

var a: error{ A, B }!u64 = 0;
var b = a catch |err| switch (err) {
error.A => 0,
else => unreachable,
};
_ = b;
}
18 changes: 18 additions & 0 deletions test/behavior/bugs/11179.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const std = @import("std");
const Type = std.builtin.Type;

test "Tuple" {
const fields_list = fields(@TypeOf(.{}));
if (fields_list.len != 0)
@compileError("Argument count mismatch");
}

pub fn fields(comptime T: type) switch (@typeInfo(T)) {
.Struct => []const Type.StructField,
else => unreachable,
} {
return switch (@typeInfo(T)) {
.Struct => |info| info.fields,
else => unreachable,
};
}
11 changes: 11 additions & 0 deletions test/cases/compile_errors/invalid_array_elem_ty.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub fn S() type {
return struct {};
}
pub export fn entry() void {
_ = [0]S;
}

// error
// backend=stage2,llvm
//
// :4:1: error: expected type, found fn() type
31 changes: 31 additions & 0 deletions test/cases/compile_errors/runtime_indexing_comptime_array.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
fn foo() void {}
fn bar() void {}

pub export fn entry1() void {
const TestFn = fn () void;
const test_fns = [_]TestFn{ foo, bar };
for (test_fns) |testFn| {
testFn();
}
}
pub export fn entry2() void {
const TestFn = fn () void;
const test_fns = [_]TestFn{ foo, bar };
var i: usize = 0;
_ = test_fns[i];
}
pub export fn entry3() void {
const TestFn = fn () void;
const test_fns = [_]TestFn{ foo, bar };
var i: usize = 0;
_ = &test_fns[i];
}
// error
// backend=stage2,llvm
//
// :6:33: error: values of type '[2]fn() callconv(.C) void' must be comptime known, but index value is runtime known
// :6:33: note: use '*const fn() callconv(.C) void' for a function pointer type
// :13:33: error: values of type '[2]fn() callconv(.C) void' must be comptime known, but index value is runtime known
// :13:33: note: use '*const fn() callconv(.C) void' for a function pointer type
// :19:33: error: values of type '[2]fn() callconv(.C) void' must be comptime known, but index value is runtime known
// :19:33: note: use '*const fn() callconv(.C) void' for a function pointer type