aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Module.zig27
-rw-r--r--src/Sema.zig462
-rw-r--r--test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig22
-rw-r--r--test/cases/compile_errors/generic_instantiation_failure.zig27
-rw-r--r--test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig14
5 files changed, 331 insertions, 221 deletions
diff --git a/src/Module.zig b/src/Module.zig
index cf864f585b..9c7d3ee885 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -3540,8 +3540,8 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
if (decl.getInnerNamespace()) |namespace| {
namespace.destroyDecls(mod);
}
- decl.clearValues(mod);
}
+ decl.clearValues(mod);
decl.dependants.deinit(gpa);
decl.dependencies.deinit(gpa);
decl.clearName(gpa);
@@ -4610,9 +4610,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
// We need the memory for the Type to go into the arena for the Decl
var decl_arena = std.heap.ArenaAllocator.init(gpa);
- errdefer decl_arena.deinit();
const decl_arena_allocator = decl_arena.allocator();
+ const decl_arena_state = blk: {
+ errdefer decl_arena.deinit();
+ const s = try decl_arena_allocator.create(std.heap.ArenaAllocator.State);
+ break :blk s;
+ };
+ defer {
+ decl_arena_state.* = decl_arena.state;
+ decl.value_arena = decl_arena_state;
+ }
+
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
const analysis_arena_allocator = analysis_arena.allocator();
@@ -4681,8 +4690,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
// not the struct itself.
try sema.resolveTypeLayout(decl_tv.ty);
- const decl_arena_state = try decl_arena_allocator.create(std.heap.ArenaAllocator.State);
-
if (decl.is_usingnamespace) {
if (!decl_tv.ty.eql(Type.type, mod)) {
return sema.fail(&block_scope, ty_src, "expected type, found {}", .{
@@ -4701,8 +4708,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
decl.@"linksection" = null;
decl.has_tv = true;
decl.owns_tv = false;
- decl_arena_state.* = decl_arena.state;
- decl.value_arena = decl_arena_state;
decl.analysis = .complete;
decl.generation = mod.generation;
@@ -4723,16 +4728,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
if (decl.getFunction()) |prev_func| {
prev_is_inline = prev_func.state == .inline_only;
}
- decl.clearValues(mod);
}
+ decl.clearValues(mod);
decl.ty = try decl_tv.ty.copy(decl_arena_allocator);
decl.val = try decl_tv.val.copy(decl_arena_allocator);
// linksection, align, and addrspace were already set by Sema
decl.has_tv = true;
decl.owns_tv = owns_tv;
- decl_arena_state.* = decl_arena.state;
- decl.value_arena = decl_arena_state;
decl.analysis = .complete;
decl.generation = mod.generation;
@@ -4767,8 +4770,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
var type_changed = true;
if (decl.has_tv) {
type_changed = !decl.ty.eql(decl_tv.ty, mod);
- decl.clearValues(mod);
}
+ decl.clearValues(mod);
decl.owns_tv = false;
var queue_linker_work = false;
@@ -4841,8 +4844,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
};
};
decl.has_tv = true;
- decl_arena_state.* = decl_arena.state;
- decl.value_arena = decl_arena_state;
decl.analysis = .complete;
decl.generation = mod.generation;
@@ -5447,8 +5448,8 @@ pub fn clearDecl(
if (decl.getInnerNamespace()) |namespace| {
try namespace.deleteAllDecls(mod, outdated_decls);
}
- decl.clearValues(mod);
}
+ decl.clearValues(mod);
if (decl.deletion_flag) {
decl.deletion_flag = false;
diff --git a/src/Sema.zig b/src/Sema.zig
index be51c30307..92024f7178 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -7112,7 +7112,6 @@ fn instantiateGenericCall(
const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
const callee = if (!gop.found_existing) callee: {
const new_module_func = try gpa.create(Module.Fn);
- errdefer gpa.destroy(new_module_func);
// This ensures that we can operate on the hash map before the Module.Fn
// struct is fully initialized.
@@ -7120,7 +7119,6 @@ fn instantiateGenericCall(
new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional();
new_module_func.comptime_args = null;
gop.key_ptr.* = new_module_func;
- errdefer assert(mod.monomorphed_funcs.remove(new_module_func));
try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
@@ -7128,7 +7126,6 @@ fn instantiateGenericCall(
const src_decl_index = namespace.getDeclIndex();
const src_decl = mod.declPtr(src_decl_index);
const new_decl_index = try mod.allocateNewDecl(namespace, fn_owner_decl.src_node, src_decl.src_scope);
- errdefer mod.destroyDecl(new_decl_index);
const new_decl = mod.declPtr(new_decl_index);
// TODO better names for generic function instantiations
const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
@@ -7148,223 +7145,59 @@ fn instantiateGenericCall(
new_decl.generation = mod.generation;
namespace.anon_decls.putAssumeCapacityNoClobber(new_decl_index, {});
- errdefer assert(namespace.anon_decls.orderedRemove(new_decl_index));
// The generic function Decl is guaranteed to be the first dependency
// of each of its instantiations.
assert(new_decl.dependencies.keys().len == 0);
try mod.declareDeclDependency(new_decl_index, module_fn.owner_decl);
- // Resolving the new function type below will possibly declare more decl dependencies
- // and so we remove them all here in case of error.
- errdefer {
- for (new_decl.dependencies.keys()) |dep_index| {
- const dep = mod.declPtr(dep_index);
- dep.removeDependant(new_decl_index);
- }
- }
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
const new_decl_arena_allocator = new_decl_arena.allocator();
- // Re-run the block that creates the function, with the comptime parameters
- // pre-populated inside `inst_map`. This causes `param_comptime` and
- // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
- // new, monomorphized function, with the comptime parameters elided.
- var child_sema: Sema = .{
- .mod = mod,
- .gpa = gpa,
- .arena = sema.arena,
- .perm_arena = new_decl_arena_allocator,
- .code = fn_zir,
- .owner_decl = new_decl,
- .owner_decl_index = new_decl_index,
- .func = null,
- .fn_ret_ty = Type.void,
- .owner_func = null,
- .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
- .comptime_args_fn_inst = module_fn.zir_body_inst,
- .preallocated_new_func = new_module_func,
- .is_generic_instantiation = true,
- .branch_quota = sema.branch_quota,
- .branch_count = sema.branch_count,
- };
- defer child_sema.deinit();
-
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
- defer wip_captures.deinit();
-
- var child_block: Block = .{
- .parent = null,
- .sema = &child_sema,
- .src_decl = new_decl_index,
- .namespace = namespace,
- .wip_capture_scope = wip_captures.scope,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer {
- child_block.instructions.deinit(gpa);
- child_block.params.deinit(gpa);
- }
-
- try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
-
- var arg_i: usize = 0;
- for (fn_info.param_body) |inst| {
- var is_comptime = false;
- var is_anytype = false;
- switch (zir_tags[inst]) {
- .param => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
- },
- .param_comptime => {
- is_comptime = true;
- },
- .param_anytype => {
- is_anytype = true;
- is_comptime = func_ty_info.paramIsComptime(arg_i);
- },
- .param_anytype_comptime => {
- is_anytype = true;
- is_comptime = true;
- },
- else => continue,
- }
- const arg = uncasted_args[arg_i];
- if (is_comptime) {
- const arg_val = (try sema.resolveMaybeUndefVal(arg)).?;
- const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
- child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
- } else if (is_anytype) {
- const arg_ty = sema.typeOf(arg);
- if (try sema.typeRequiresComptime(arg_ty)) {
- const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) {
- error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src);
- _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known");
- unreachable;
- },
- else => |e| return e,
- };
- const child_arg = try child_sema.addConstant(arg_ty, arg_val);
- child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+ const new_func = sema.resolveGenericInstantiationType(
+ block,
+ new_decl_arena_allocator,
+ fn_zir,
+ new_decl,
+ new_decl_index,
+ uncasted_args,
+ module_fn,
+ new_module_func,
+ namespace,
+ func_ty_info,
+ call_src,
+ bound_arg_src,
+ ) catch |err| switch (err) {
+ error.GenericPoison, error.ComptimeReturn => {
+ new_decl_arena.deinit();
+ // Resolving the new function type below will possibly declare more decl dependencies
+ // and so we remove them all here in case of error.
+ for (new_decl.dependencies.keys()) |dep_index| {
+ const dep = mod.declPtr(dep_index);
+ dep.removeDependant(new_decl_index);
+ }
+ assert(namespace.anon_decls.orderedRemove(new_decl_index));
+ mod.destroyDecl(new_decl_index);
+ assert(mod.monomorphed_funcs.remove(new_module_func));
+ gpa.destroy(new_module_func);
+ return err;
+ },
+ else => {
+ {
+ errdefer new_decl_arena.deinit();
+ try new_decl.finalizeNewArena(&new_decl_arena);
+ }
+ // TODO look up the compile error that happened here and attach a note to it
+ // pointing here, at the generic instantiation callsite.
+ if (sema.owner_func) |owner_func| {
+ owner_func.state = .dependency_failure;
} else {
- // We insert into the map an instruction which is runtime-known
- // but has the type of the argument.
- const child_arg = try child_block.addInst(.{
- .tag = .arg,
- .data = .{ .arg = .{
- .ty = try child_sema.addType(arg_ty),
- .src_index = @intCast(u32, arg_i),
- } },
- });
- child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+ sema.owner_decl.analysis = .dependency_failure;
}
- }
- arg_i += 1;
- }
-
- // Save the error trace as our first action in the function.
- // If this is unnecessary after all, Liveness will clean it up for us.
- const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
- child_sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
- child_block.error_return_trace_index = error_return_trace_index;
-
- const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| {
- if (err == error.GenericPoison) return error.GenericPoison;
- // TODO look up the compile error that happened here and attach a note to it
- // pointing here, at the generic instantiation callsite.
- if (sema.owner_func) |owner_func| {
- owner_func.state = .dependency_failure;
- } else {
- sema.owner_decl.analysis = .dependency_failure;
- }
- return err;
+ return err;
+ },
};
- const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, "") catch unreachable;
- const new_func = new_func_val.castTag(.function).?.data;
- errdefer new_func.deinit(gpa);
- assert(new_func == new_module_func);
-
- arg_i = 0;
- for (fn_info.param_body) |inst| {
- var is_comptime = false;
- switch (zir_tags[inst]) {
- .param => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
- },
- .param_comptime => {
- is_comptime = true;
- },
- .param_anytype => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
- },
- .param_anytype_comptime => {
- is_comptime = true;
- },
- else => continue,
- }
-
- // We populate the Type here regardless because it is needed by
- // `GenericCallAdapter.eql` as well as function body analysis.
- // Whether it is anytype is communicated by `isAnytypeParam`.
- const arg = child_sema.inst_map.get(inst).?;
- const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
-
- if (try sema.typeRequiresComptime(copied_arg_ty)) {
- is_comptime = true;
- }
-
- if (is_comptime) {
- const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;
- child_sema.comptime_args[arg_i] = .{
- .ty = copied_arg_ty,
- .val = try arg_val.copy(new_decl_arena_allocator),
- };
- } else {
- child_sema.comptime_args[arg_i] = .{
- .ty = copied_arg_ty,
- .val = Value.initTag(.generic_poison),
- };
- }
-
- arg_i += 1;
- }
-
- try wip_captures.finalize();
-
- // Populate the Decl ty/val with the function and its type.
- new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator);
- // If the call evaluated to a return type that requires comptime, never mind
- // our generic instantiation. Instead we need to perform a comptime call.
- const new_fn_info = new_decl.ty.fnInfo();
- if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
- return error.ComptimeReturn;
- }
- // Similarly, if the call evaluated to a generic type we need to instead
- // call it inline.
- if (new_fn_info.is_generic or new_fn_info.cc == .Inline) {
- return error.GenericPoison;
- }
-
- new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func);
- new_decl.@"align" = 0;
- new_decl.has_tv = true;
- new_decl.owns_tv = true;
- new_decl.analysis = .complete;
-
- log.debug("generic function '{s}' instantiated with type {}", .{
- new_decl.name, new_decl.ty.fmtDebug(),
- });
-
- // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
- // will be populated, ensuring it will have `analyzeBody` called with the ZIR
- // parameters mapped appropriately.
- try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
- try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
+ errdefer new_decl_arena.deinit();
try new_decl.finalizeNewArena(&new_decl_arena);
break :callee new_func;
@@ -7444,6 +7277,218 @@ fn instantiateGenericCall(
return result;
}
+fn resolveGenericInstantiationType(
+ sema: *Sema,
+ block: *Block,
+ new_decl_arena_allocator: Allocator,
+ fn_zir: Zir,
+ new_decl: *Decl,
+ new_decl_index: Decl.Index,
+ uncasted_args: []const Air.Inst.Ref,
+ module_fn: *Module.Fn,
+ new_module_func: *Module.Fn,
+ namespace: *Namespace,
+ func_ty_info: Type.Payload.Function.Data,
+ call_src: LazySrcLoc,
+ bound_arg_src: ?LazySrcLoc,
+) !*Module.Fn {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+
+ const zir_tags = fn_zir.instructions.items(.tag);
+ const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
+
+ // Re-run the block that creates the function, with the comptime parameters
+ // pre-populated inside `inst_map`. This causes `param_comptime` and
+ // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
+ // new, monomorphized function, with the comptime parameters elided.
+ var child_sema: Sema = .{
+ .mod = mod,
+ .gpa = gpa,
+ .arena = sema.arena,
+ .perm_arena = new_decl_arena_allocator,
+ .code = fn_zir,
+ .owner_decl = new_decl,
+ .owner_decl_index = new_decl_index,
+ .func = null,
+ .fn_ret_ty = Type.void,
+ .owner_func = null,
+ .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
+ .comptime_args_fn_inst = module_fn.zir_body_inst,
+ .preallocated_new_func = new_module_func,
+ .is_generic_instantiation = true,
+ .branch_quota = sema.branch_quota,
+ .branch_count = sema.branch_count,
+ };
+ defer child_sema.deinit();
+
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
+ defer wip_captures.deinit();
+
+ var child_block: Block = .{
+ .parent = null,
+ .sema = &child_sema,
+ .src_decl = new_decl_index,
+ .namespace = namespace,
+ .wip_capture_scope = wip_captures.scope,
+ .instructions = .{},
+ .inlining = null,
+ .is_comptime = true,
+ };
+ defer {
+ child_block.instructions.deinit(gpa);
+ child_block.params.deinit(gpa);
+ }
+
+ try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
+
+ var arg_i: usize = 0;
+ for (fn_info.param_body) |inst| {
+ var is_comptime = false;
+ var is_anytype = false;
+ switch (zir_tags[inst]) {
+ .param => {
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_comptime => {
+ is_comptime = true;
+ },
+ .param_anytype => {
+ is_anytype = true;
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_anytype_comptime => {
+ is_anytype = true;
+ is_comptime = true;
+ },
+ else => continue,
+ }
+ const arg = uncasted_args[arg_i];
+ if (is_comptime) {
+ const arg_val = (try sema.resolveMaybeUndefVal(arg)).?;
+ const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
+ child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+ } else if (is_anytype) {
+ const arg_ty = sema.typeOf(arg);
+ if (try sema.typeRequiresComptime(arg_ty)) {
+ const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) {
+ error.NeededSourceLocation => {
+ const decl = sema.mod.declPtr(block.src_decl);
+ const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src);
+ _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known");
+ unreachable;
+ },
+ else => |e| return e,
+ };
+ const child_arg = try child_sema.addConstant(arg_ty, arg_val);
+ child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+ } else {
+ // We insert into the map an instruction which is runtime-known
+ // but has the type of the argument.
+ const child_arg = try child_block.addInst(.{
+ .tag = .arg,
+ .data = .{ .arg = .{
+ .ty = try child_sema.addType(arg_ty),
+ .src_index = @intCast(u32, arg_i),
+ } },
+ });
+ child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
+ }
+ }
+ arg_i += 1;
+ }
+
+ // Save the error trace as our first action in the function.
+ // If this is unnecessary after all, Liveness will clean it up for us.
+ const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
+ child_sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
+ child_block.error_return_trace_index = error_return_trace_index;
+
+ const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);
+ const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable;
+ const new_func = new_func_val.castTag(.function).?.data;
+ errdefer new_func.deinit(gpa);
+ assert(new_func == new_module_func);
+
+ arg_i = 0;
+ for (fn_info.param_body) |inst| {
+ var is_comptime = false;
+ switch (zir_tags[inst]) {
+ .param => {
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_comptime => {
+ is_comptime = true;
+ },
+ .param_anytype => {
+ is_comptime = func_ty_info.paramIsComptime(arg_i);
+ },
+ .param_anytype_comptime => {
+ is_comptime = true;
+ },
+ else => continue,
+ }
+
+ // We populate the Type here regardless because it is needed by
+ // `GenericCallAdapter.eql` as well as function body analysis.
+ // Whether it is anytype is communicated by `isAnytypeParam`.
+ const arg = child_sema.inst_map.get(inst).?;
+ const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
+
+ if (try sema.typeRequiresComptime(copied_arg_ty)) {
+ is_comptime = true;
+ }
+
+ if (is_comptime) {
+ const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;
+ child_sema.comptime_args[arg_i] = .{
+ .ty = copied_arg_ty,
+ .val = try arg_val.copy(new_decl_arena_allocator),
+ };
+ } else {
+ child_sema.comptime_args[arg_i] = .{
+ .ty = copied_arg_ty,
+ .val = Value.initTag(.generic_poison),
+ };
+ }
+
+ arg_i += 1;
+ }
+
+ try wip_captures.finalize();
+
+ // Populate the Decl ty/val with the function and its type.
+ new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator);
+ // If the call evaluated to a return type that requires comptime, never mind
+ // our generic instantiation. Instead we need to perform a comptime call.
+ const new_fn_info = new_decl.ty.fnInfo();
+ if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
+ return error.ComptimeReturn;
+ }
+ // Similarly, if the call evaluated to a generic type we need to instead
+ // call it inline.
+ if (new_fn_info.is_generic or new_fn_info.cc == .Inline) {
+ return error.GenericPoison;
+ }
+
+ new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func);
+ new_decl.@"align" = 0;
+ new_decl.has_tv = true;
+ new_decl.owns_tv = true;
+ new_decl.analysis = .complete;
+
+ log.debug("generic function '{s}' instantiated with type {}", .{
+ new_decl.name, new_decl.ty.fmtDebug(),
+ });
+
+ // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
+ // will be populated, ensuring it will have `analyzeBody` called with the ZIR
+ // parameters mapped appropriately.
+ try mod.comp.bin_file.allocateDeclIndexes(new_decl_index);
+ try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
+ return new_func;
+}
+
fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
if (!ty.isSimpleTuple()) return;
const tuple = ty.tupleFields();
@@ -11506,6 +11551,7 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I
.dbg_block_begin,
.dbg_block_end,
.dbg_stmt,
+ .save_err_ret_index,
=> {},
.@"unreachable" => break inst,
else => return,
diff --git a/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig b/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig
new file mode 100644
index 0000000000..2b61f45a31
--- /dev/null
+++ b/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig
@@ -0,0 +1,22 @@
+const std = @import("std");
+const Version = std.SemanticVersion;
+const print = @import("std").debug.print;
+
+fn readVersion() Version {
+ const version_file = "foo";
+ const len = std.mem.indexOfAny(u8, version_file, " \n") orelse version_file.len;
+ const version_string = version_file[0..len];
+ return Version.parse(version_string) catch unreachable;
+}
+
+const version: Version = readVersion();
+pub export fn entry() void {
+ print("Version {}.{}.{}+{?s}\n", .{ version.major, version.minor, version.patch, version.build });
+}
+
+// error
+// backend=llvm
+// target=native
+//
+// :9:48: error: caught unexpected error 'InvalidVersion'
+// :12:37: note: called from here
diff --git a/test/cases/compile_errors/generic_instantiation_failure.zig b/test/cases/compile_errors/generic_instantiation_failure.zig
new file mode 100644
index 0000000000..42e4c4e8c8
--- /dev/null
+++ b/test/cases/compile_errors/generic_instantiation_failure.zig
@@ -0,0 +1,27 @@
+fn List(comptime Head: type, comptime Tail: type) type {
+ return union {
+ const Self = @This();
+ head: Head,
+ tail: Tail,
+
+ fn AppendReturnType(comptime item: anytype) type {
+ return List(Head, List(@TypeOf(item), void));
+ }
+ };
+}
+
+fn makeList(item: anytype) List(@TypeOf(item), void) {
+ return List(@TypeOf(item), void){ .head = item };
+}
+
+pub export fn entry() void {
+ @TypeOf(makeList(42)).AppendReturnType(64);
+}
+
+// error
+// backend=llvm
+// target=native
+//
+// :18:43: error: value of type 'type' ignored
+// :18:43: note: all non-void values must be used
+// :18:43: note: this error can be suppressed by assigning the value to '_'
diff --git a/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig b/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig
new file mode 100644
index 0000000000..3146c38604
--- /dev/null
+++ b/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig
@@ -0,0 +1,14 @@
+const std = @import("std");
+
+pub export fn entry() void {
+ var ohnoes: *usize = undefined;
+ _ = sliceAsBytes(ohnoes);
+}
+fn sliceAsBytes(slice: anytype) std.meta.trait.isPtrTo(.Array)(@TypeOf(slice)) {}
+
+
+// error
+// backend=llvm
+// target=native
+//
+// :7:63: error: expected type 'type', found 'bool'