Commit 76e7959a90

Veikka Tuominen <git@vexu.eu>
2022-07-12 23:35:09
Sema: explain why comptime is needed
1 parent 195c3cd
src/Module.zig
@@ -4065,18 +4065,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
         var wip_captures = try WipCaptureScope.init(gpa, new_decl_arena_allocator, null);
         defer wip_captures.deinit();
 
-        var block_scope: Sema.Block = .{
-            .parent = null,
-            .sema = &sema,
-            .src_decl = new_decl_index,
-            .namespace = &struct_obj.namespace,
-            .wip_capture_scope = wip_captures.scope,
-            .instructions = .{},
-            .inlining = null,
-            .is_comptime = true,
-        };
-        defer block_scope.instructions.deinit(gpa);
-
         if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| {
             try wip_captures.finalize();
             new_decl.analysis = .complete;
@@ -4185,7 +4173,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
     const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand;
     try wip_captures.finalize();
     const src = LazySrcLoc.nodeOffset(0);
-    const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
+    const decl_tv = try sema.resolveInstValue(&block_scope, .unneeded, result_ref, undefined);
     const decl_align: u32 = blk: {
         const align_ref = decl.zirAlignRef();
         if (align_ref == .none) break :blk 0;
@@ -4194,7 +4182,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
     const decl_linksection: ?[*:0]const u8 = blk: {
         const linksection_ref = decl.zirLinksectionRef();
         if (linksection_ref == .none) break :blk null;
-        const bytes = try sema.resolveConstString(&block_scope, src, linksection_ref);
+        const bytes = try sema.resolveConstString(&block_scope, src, linksection_ref, "linksection must be comptime known");
         break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr;
     };
     const target = sema.mod.getTarget();
src/Sema.zig
@@ -892,7 +892,7 @@ fn analyzeBodyInner(
             .shl_sat   => try sema.zirShl(block, inst, .shl_sat),
 
             .ret_ptr  => try sema.zirRetPtr(block, inst),
-            .ret_type => try sema.zirRetType(block, inst),
+            .ret_type => try sema.addType(sema.fn_ret_ty),
 
             // Instructions that we know to *always* be noreturn based solely on their tag.
             // These functions match the return type of analyzeBody so that we can
@@ -1173,7 +1173,7 @@ fn analyzeBodyInner(
                 } else {
                     const src_node = sema.code.instructions.items(.data)[inst].node;
                     const src = LazySrcLoc.nodeOffset(src_node);
-                    try sema.requireRuntimeBlock(block, src);
+                    try sema.requireFunctionBlock(block, src);
                     break always_noreturn;
                 }
             },
@@ -1303,7 +1303,7 @@ fn analyzeBodyInner(
                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
-                const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
+                const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");
                 const inline_body = if (cond.val.toBool()) then_body else else_body;
                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
                     break always_noreturn;
@@ -1319,7 +1319,7 @@ fn analyzeBodyInner(
                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
                 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
                 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
-                const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
+                const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");
                 const inline_body = if (cond.val.toBool()) then_body else else_body;
                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
                     break always_noreturn;
@@ -1339,7 +1339,7 @@ fn analyzeBodyInner(
                 const err_union = try sema.resolveInst(extra.data.operand);
                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
                 assert(is_non_err != .none);
-                const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
+                const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known");
                 if (is_non_err_tv.val.toBool()) {
                     const err_union_ty = sema.typeOf(err_union);
                     break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
@@ -1395,7 +1395,7 @@ fn analyzeBodyInner(
                 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
                 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
                 assert(is_non_err != .none);
-                const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err);
+                const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime known");
                 if (is_non_err_tv.val.toBool()) {
                     break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
                 }
@@ -1478,11 +1478,12 @@ fn resolveConstBool(
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
+    reason: []const u8,
 ) !bool {
     const air_inst = try sema.resolveInst(zir_ref);
     const wanted_type = Type.bool;
     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
-    const val = try sema.resolveConstValue(block, src, coerced_inst);
+    const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
     return val.toBool();
 }
 
@@ -1491,11 +1492,12 @@ pub fn resolveConstString(
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
+    reason: []const u8,
 ) ![]u8 {
     const air_inst = try sema.resolveInst(zir_ref);
     const wanted_type = Type.initTag(.const_slice_u8);
     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
-    const val = try sema.resolveConstValue(block, src, coerced_inst);
+    const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
     return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod);
 }
 
@@ -1514,7 +1516,7 @@ fn analyzeAsType(
 ) !Type {
     const wanted_type = Type.initTag(.@"type");
     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
-    const val = try sema.resolveConstValue(block, src, coerced_inst);
+    const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime known");
     var buffer: Value.ToTypeBuffer = undefined;
     const ty = val.toType(&buffer);
     return ty.copy(sema.arena);
@@ -1567,12 +1569,13 @@ fn resolveValue(
     block: *Block,
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
+    reason: []const u8,
 ) CompileError!Value {
     if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
         if (val.tag() == .generic_poison) return error.GenericPoison;
         return val;
     }
-    return sema.failWithNeededComptime(block, src);
+    return sema.failWithNeededComptime(block, src, reason);
 }
 
 /// Value Tag `variable` will cause a compile error.
@@ -1582,15 +1585,16 @@ fn resolveConstMaybeUndefVal(
     block: *Block,
     src: LazySrcLoc,
     inst: Air.Inst.Ref,
+    reason: []const u8,
 ) CompileError!Value {
     if (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) |val| {
         switch (val.tag()) {
-            .variable => return sema.failWithNeededComptime(block, src),
+            .variable => return sema.failWithNeededComptime(block, src, reason),
             .generic_poison => return error.GenericPoison,
             else => return val,
         }
     }
-    return sema.failWithNeededComptime(block, src);
+    return sema.failWithNeededComptime(block, src, reason);
 }
 
 /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
@@ -1600,16 +1604,17 @@ fn resolveConstValue(
     block: *Block,
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
+    reason: []const u8,
 ) CompileError!Value {
     if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
         switch (val.tag()) {
             .undef => return sema.failWithUseOfUndef(block, src),
-            .variable => return sema.failWithNeededComptime(block, src),
+            .variable => return sema.failWithNeededComptime(block, src, reason),
             .generic_poison => return error.GenericPoison,
             else => return val,
         }
     }
-    return sema.failWithNeededComptime(block, src);
+    return sema.failWithNeededComptime(block, src, reason);
 }
 
 /// Value Tag `variable` causes this function to return `null`.
@@ -1697,8 +1702,15 @@ fn resolveMaybeUndefValAllowVariables(
     }
 }
 
-fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
-    return sema.fail(block, src, "unable to resolve comptime value", .{});
+fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError {
+    const msg = msg: {
+        const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{});
+        errdefer msg.destroy(sema.gpa);
+
+        try sema.errNote(block, src, msg, "{s}", .{reason});
+        break :msg msg;
+    };
+    return sema.failWithOwnedErrorMsg(block, msg);
 }
 
 fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
@@ -1870,7 +1882,7 @@ fn analyzeAsAlign(
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
 ) !u32 {
-    const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty);
+    const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, "alignment must be comptime known");
     const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
     if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
     if (!std.math.isPowerOfTwo(alignment)) {
@@ -1897,9 +1909,10 @@ fn resolveInt(
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
     dest_ty: Type,
+    reason: []const u8,
 ) !u64 {
     const air_ref = try sema.resolveInst(zir_ref);
-    return analyzeAsInt(sema, block, src, air_ref, dest_ty);
+    return analyzeAsInt(sema, block, src, air_ref, dest_ty, reason);
 }
 
 fn analyzeAsInt(
@@ -1908,9 +1921,10 @@ fn analyzeAsInt(
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
     dest_ty: Type,
+    reason: []const u8,
 ) !u64 {
     const coerced = try sema.coerce(block, dest_ty, air_ref, src);
-    const val = try sema.resolveConstValue(block, src, coerced);
+    const val = try sema.resolveConstValue(block, src, coerced, reason);
     const target = sema.mod.getTarget();
     return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
 }
@@ -1922,9 +1936,10 @@ pub fn resolveInstConst(
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
+    reason: []const u8,
 ) CompileError!TypedValue {
     const air_ref = try sema.resolveInst(zir_ref);
-    const val = try sema.resolveConstValue(block, src, air_ref);
+    const val = try sema.resolveConstValue(block, src, air_ref, reason);
     return TypedValue{
         .ty = sema.typeOf(air_ref),
         .val = val,
@@ -1938,9 +1953,10 @@ pub fn resolveInstValue(
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
+    reason: []const u8,
 ) CompileError!TypedValue {
     const air_ref = try sema.resolveInst(zir_ref);
-    const val = try sema.resolveValue(block, src, air_ref);
+    const val = try sema.resolveValue(block, src, air_ref, reason);
     return TypedValue{
         .ty = sema.typeOf(air_ref),
         .val = val,
@@ -1974,7 +1990,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
                     defer trash_block.instructions.deinit(sema.gpa);
                     const operand = try trash_block.addBitCast(pointee_ty, .void_value);
 
-                    try sema.requireRuntimeBlock(block, src);
+                    try sema.requireFunctionBlock(block, src);
                     const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
                         .pointee_type = pointee_ty,
                         .@"align" = inferred_alloc.alignment,
@@ -2259,7 +2275,7 @@ fn createAnonymousDeclTypeNamed(
                     const arg = sema.inst_map.get(zir_inst).?;
                     // The comptime call code in analyzeCall already did this, so we're
                     // just repeating it here and it's guaranteed to work.
-                    const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg) catch unreachable;
+                    const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, undefined) catch unreachable;
 
                     if (arg_i != 0) try buf.appendSlice(",");
                     try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
@@ -2515,7 +2531,7 @@ fn zirEnumDecl(
             // TODO: if we need to report an error here, use a source location
             // that points to this default value expression rather than the struct.
             // But only resolve the source location if we need to emit a compile error.
-            const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val;
+            const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;
             last_tag_val = tag_val;
             const copied_tag_val = try tag_val.copy(new_decl_arena_allocator);
             enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
@@ -2738,7 +2754,6 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
 
     const inst_data = sema.code.instructions.items(.data)[inst].node;
     const src = LazySrcLoc.nodeOffset(inst_data);
-    try sema.requireFunctionBlock(block, src);
 
     if (block.is_comptime or try sema.typeRequiresComptime(block, src, sema.fn_ret_ty)) {
         const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty);
@@ -2770,16 +2785,6 @@ fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
     return sema.analyzeRef(block, inst_data.src(), operand);
 }
 
-fn zirRetType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
-    const tracy = trace(@src());
-    defer tracy.end();
-
-    const inst_data = sema.code.instructions.items(.data)[inst].node;
-    const src = LazySrcLoc.nodeOffset(inst_data);
-    try sema.requireFunctionBlock(block, src);
-    return sema.addType(sema.fn_ret_ty);
-}
-
 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
     const tracy = trace(@src());
     defer tracy.end();
@@ -2925,7 +2930,7 @@ fn zirAllocExtended(
             try sema.validateVarType(block, ty_src, var_ty, false);
         }
         const target = sema.mod.getTarget();
-        try sema.requireRuntimeBlock(block, src);
+        try sema.requireFunctionBlock(block, src);
         try sema.resolveTypeLayout(block, src, var_ty);
         const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
             .pointee_type = var_ty,
@@ -3024,7 +3029,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
         return sema.addConstant(const_ptr_ty, val);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireFunctionBlock(block, src);
     return block.addBitCast(const_ptr_ty, alloc);
 }
 
@@ -3061,7 +3066,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
         .pointee_type = var_ty,
         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
     });
-    try sema.requireRuntimeBlock(block, var_decl_src);
+    try sema.requireFunctionBlock(block, var_decl_src);
     try sema.queueFullTypeResolution(var_ty);
     return block.addTy(.alloc, ptr_type);
 }
@@ -3083,7 +3088,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         .pointee_type = var_ty,
         .@"addrspace" = target_util.defaultAddressSpace(target, .local),
     });
-    try sema.requireRuntimeBlock(block, var_decl_src);
+    try sema.requireFunctionBlock(block, var_decl_src);
     try sema.queueFullTypeResolution(var_ty);
     return block.addTy(.alloc, ptr_type);
 }
@@ -3272,7 +3277,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
                 return;
             }
 
-            try sema.requireRuntimeBlock(block, src);
+            try sema.requireFunctionBlock(block, src);
             try sema.queueFullTypeResolution(final_elem_ty);
 
             // Change it to a normal alloc.
@@ -3593,7 +3598,7 @@ fn validateUnionInit(
         return;
     }
 
-    try sema.requireRuntimeBlock(block, init_src);
+    try sema.requireFunctionBlock(block, init_src);
     const new_tag = try sema.addConstant(union_obj.tag_ty, tag_val);
     _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
 }
@@ -3859,7 +3864,7 @@ fn zirValidateArrayInit(
         // any ZIR instructions at comptime; we need to do that here.
         if (array_ty.sentinel()) |sentinel_val| {
             const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);
-            const sentinel_ptr = try sema.elemPtrArray(block, init_src, array_ptr, init_src, array_len_ref, true);
+            const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true);
             const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val);
             try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
         }
@@ -4207,10 +4212,8 @@ fn storeToInferredAllocComptime(
     const operand_ty = sema.typeOf(operand);
     // There will be only one store_to_inferred_ptr because we are running at comptime.
     // The alloc will turn into a Decl.
-    if (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) |operand_val| {
-        if (operand_val.tag() == .variable) {
-            return sema.failWithNeededComptime(block, src);
-        }
+    if (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) |operand_val| store: {
+        if (operand_val.tag() == .variable) break :store;
         var anon_decl = try block.startAnonDecl(src);
         defer anon_decl.deinit();
         iac.data.decl_index = try anon_decl.finish(
@@ -4219,15 +4222,15 @@ fn storeToInferredAllocComptime(
             iac.data.alignment,
         );
         return;
-    } else {
-        return sema.failWithNeededComptime(block, src);
     }
+
+    return sema.failWithNeededComptime(block, src, "value being stored to a comptime variable must be comptime known");
 }
 
 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
-    const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32));
+    const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32, "eval branch quota must be comptime known"));
     sema.branch_quota = @maximum(sema.branch_quota, quota);
 }
 
@@ -4282,7 +4285,7 @@ fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     var param_index = inst_data.param_index;
 
     const fn_ty = if (callee_ty.tag() == .bound_fn) fn_ty: {
-        const bound_fn_val = try sema.resolveConstValue(block, callee_src, callee);
+        const bound_fn_val = try sema.resolveConstValue(block, .unneeded, callee, undefined);
         const bound_fn = bound_fn_val.castTag(.bound_fn).?.data;
         const fn_ty = sema.typeOf(bound_fn.func_inst);
         param_index += 1;
@@ -4417,7 +4420,7 @@ fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
-    const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
+    const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, "compile error string must be comptime known");
     return sema.fail(block, src, "{s}", .{msg});
 }
 
@@ -4466,7 +4469,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo
     if (block.is_comptime or force_comptime) {
         return sema.fail(block, src, "encountered @panic at comptime", .{});
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireFunctionBlock(block, src);
     return sema.panicWithMsg(block, src, msg_inst);
 }
 
@@ -4854,7 +4857,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
     const src = inst_data.src();
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
-    const operand = try sema.resolveInstConst(block, operand_src, extra.operand);
+    const operand = try sema.resolveInstConst(block, operand_src, extra.operand, "export target must be comptime known");
     const options = try sema.resolveExportOptions(block, options_src, extra.options);
     const decl_index = switch (operand.val.tag()) {
         .function => operand.val.castTag(.function).?.data.owner_decl,
@@ -4989,7 +4992,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
 fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
-    const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand);
+    const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setCold must be comptime known");
     const func = sema.func orelse return; // does nothing outside a function
     func.is_cold = is_cold;
 }
@@ -4997,7 +5000,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
-    const float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode");
+    const float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known");
     switch (float_mode) {
         .Strict => return,
         .Optimized => {
@@ -5009,7 +5012,7 @@ fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
-    block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand);
+    block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, "operand to @setRuntimeSafety must be comptime known");
 }
 
 fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
@@ -5017,7 +5020,7 @@ fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) Co
 
     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
     const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
-    const order = try sema.resolveAtomicOrder(block, order_src, extra.operand);
+    const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, "atomic order of @fence must be comptime known");
 
     if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) {
         return sema.fail(block, order_src, "atomic ordering must be Acquire or stricter", .{});
@@ -5292,7 +5295,7 @@ fn zirCall(
 
     // Desugar bound functions here
     if (func_type.tag() == .bound_fn) {
-        const bound_func = try sema.resolveValue(block, func_src, func);
+        const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
         const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
         func = bound_data.func_inst;
         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1);
@@ -5489,7 +5492,8 @@ fn analyzeCall(
     }
 
     const result: Air.Inst.Ref = if (is_inline_call) res: {
-        const func_val = try sema.resolveConstValue(block, func_src, func);
+        // TODO explain why function is being called at comptime
+        const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");
         const module_fn = switch (func_val.tag()) {
             .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
             .function => func_val.castTag(.function).?.data,
@@ -5606,7 +5610,8 @@ fn analyzeCall(
                 try sema.inst_map.putNoClobber(gpa, inst, casted_arg);
 
                 if (is_comptime_call) {
-                    const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, casted_arg);
+                    // TODO explain why function is being called at comptime
+                    const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");
                     switch (arg_val.tag()) {
                         .generic_poison, .generic_poison_type => {
                             // This function is currently evaluated as part of an as-of-yet unresolvable
@@ -5638,7 +5643,8 @@ fn analyzeCall(
 
                 if (is_comptime_call) {
                     const arg_src = call_src; // TODO: better source location
-                    const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, uncasted_arg);
+                    // TODO explain why function is being called at comptime
+                    const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");
                     switch (arg_val.tag()) {
                         .generic_poison, .generic_poison_type => {
                             // This function is currently evaluated as part of an as-of-yet unresolvable
@@ -5764,7 +5770,7 @@ fn analyzeCall(
             }
 
             if (should_memoize and is_comptime_call) {
-                const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result);
+                const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, undefined);
 
                 // TODO: check whether any external comptime memory was mutated by the
                 // comptime function call. If so, then do not memoize the call here.
@@ -5795,7 +5801,7 @@ fn analyzeCall(
         break :res res2;
     } else res: {
         assert(!func_ty_info.is_generic);
-        try sema.requireRuntimeBlock(block, call_src);
+        try sema.requireFunctionBlock(block, call_src);
 
         const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
         for (uncasted_args) |uncasted_arg, i| {
@@ -5849,7 +5855,7 @@ fn instantiateGenericCall(
     const mod = sema.mod;
     const gpa = sema.gpa;
 
-    const func_val = try sema.resolveConstValue(block, func_src, func);
+    const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime known");
     const module_fn = switch (func_val.tag()) {
         .function => func_val.castTag(.function).?.data,
         .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
@@ -5902,7 +5908,7 @@ fn instantiateGenericCall(
             if (is_comptime) {
                 const arg_src = call_src; // TODO better source location
                 const arg_ty = sema.typeOf(uncasted_args[i]);
-                const arg_val = try sema.resolveValue(block, arg_src, uncasted_args[i]);
+                const arg_val = try sema.resolveValue(block, arg_src, uncasted_args[i], "parameter is comptime");
                 try sema.resolveLazyValue(block, arg_src, arg_val);
                 arg_val.hash(arg_ty, &hasher, mod);
                 if (is_anytype) {
@@ -6066,12 +6072,12 @@ fn instantiateGenericCall(
                     const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
                     child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
                 } else {
-                    return sema.failWithNeededComptime(block, arg_src);
+                    return sema.failWithNeededComptime(block, arg_src, "parameter is comptime");
                 }
             } else if (is_anytype) {
                 const arg_ty = sema.typeOf(arg);
                 if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) {
-                    const arg_val = try sema.resolveConstValue(block, arg_src, arg);
+                    const arg_val = try sema.resolveConstValue(block, arg_src, arg, "type of anytype parameter requires comptime");
                     const child_arg = try child_sema.addConstant(arg_ty, arg_val);
                     child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
                 } else {
@@ -6093,7 +6099,7 @@ fn instantiateGenericCall(
             }
             return err;
         };
-        const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst) catch unreachable;
+        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);
@@ -6195,7 +6201,7 @@ fn instantiateGenericCall(
     const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
 
     // Make a runtime call to the new function, making sure to omit the comptime args.
-    try sema.requireRuntimeBlock(block, call_src);
+    try sema.requireFunctionBlock(block, call_src);
 
     const comptime_args = callee.comptime_args.?;
     const new_fn_info = mod.declPtr(callee.owner_decl).ty.fnInfo();
@@ -6314,7 +6320,7 @@ fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
     const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
-    const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32);
+    const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime known");
     const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs);
     try sema.checkVectorElemType(block, elem_type_src, elem_type);
     const vector_type = try Type.Tag.vector.create(sema.arena, .{
@@ -6332,7 +6338,7 @@ fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
-    const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize);
+    const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, "array length must be comptime known");
     const elem_type = try sema.resolveType(block, elem_src, extra.rhs);
     const array_ty = try Type.array(sema.arena, len, null, elem_type, sema.mod);
 
@@ -6348,11 +6354,11 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
     const len_src: LazySrcLoc = .{ .node_offset_array_type_len = inst_data.src_node };
     const sentinel_src: LazySrcLoc = .{ .node_offset_array_type_sentinel = inst_data.src_node };
     const elem_src: LazySrcLoc = .{ .node_offset_array_type_elem = inst_data.src_node };
-    const len = try sema.resolveInt(block, len_src, extra.len, Type.usize);
+    const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, "array length must be comptime known");
     const elem_type = try sema.resolveType(block, elem_src, extra.elem_type);
     const uncasted_sentinel = try sema.resolveInst(extra.sentinel);
     const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
-    const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel);
+    const sentinel_val = try sema.resolveConstValue(block, sentinel_src, sentinel, "array sentinel value must be comptime known");
     const array_ty = try Type.array(sema.arena, len, sentinel_val, elem_type, sema.mod);
 
     return sema.addType(array_ty);
@@ -6452,7 +6458,7 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     return block.addBitCast(result_ty, operand);
 }
 
@@ -6478,7 +6484,7 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
         };
         return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base));
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     if (block.wantSafety()) {
         const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
         try sema.addSafetyCheck(block, is_lt_len, .invalid_error_code);
@@ -6598,7 +6604,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         return sema.addConstant(int_tag_ty, try val.copy(sema.arena));
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     return block.addBitCast(int_tag_ty, enum_tag);
 }
 
@@ -6645,7 +6651,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         return sema.addConstant(dest_ty, int_val);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     // TODO insert safety check to make sure the value matches an enum value
     return block.addTyOp(.intcast, dest_ty, operand);
 }
@@ -6696,7 +6702,7 @@ fn analyzeOptionalPayloadPtr(
                 // If the pointer resulting from this function was stored at comptime,
                 // the optional non-null bit would be set that way. But in this case,
                 // we need to emit a runtime instruction to do it.
-                try sema.requireRuntimeBlock(block, src);
+                try sema.requireFunctionBlock(block, src);
                 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
             }
             return sema.addConstant(
@@ -6722,7 +6728,7 @@ fn analyzeOptionalPayloadPtr(
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     if (safety_check and block.wantSafety()) {
         const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
@@ -6778,7 +6784,7 @@ fn zirOptionalPayload(
         return sema.addConstant(result_ty, val);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     if (safety_check and block.wantSafety()) {
         const is_non_null = try block.addUnOp(.is_non_null, operand);
         try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
@@ -6827,7 +6833,7 @@ fn analyzeErrUnionPayload(
         return sema.addConstant(payload_ty, data);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
 
     // If the error set has no fields then no safety check is needed.
     if (safety_check and block.wantSafety() and
@@ -6887,7 +6893,7 @@ fn analyzeErrUnionPayloadPtr(
                 // If the pointer resulting from this function was stored at comptime,
                 // the error union error code would be set that way. But in this case,
                 // we need to emit a runtime instruction to do it.
-                try sema.requireRuntimeBlock(block, src);
+                try sema.requireRuntimeBlock(block, src, null);
                 _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
             }
             return sema.addConstant(
@@ -6913,7 +6919,7 @@ fn analyzeErrUnionPayloadPtr(
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
 
     // If the error set has no fields then no safety check is needed.
     if (safety_check and block.wantSafety() and
@@ -6951,7 +6957,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
         return sema.addConstant(result_ty, val);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addTyOp(.unwrap_errunion_err, result_ty, operand);
 }
 
@@ -6981,7 +6987,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addTyOp(.unwrap_errunion_err_ptr, result_ty, operand);
 }
 
@@ -7037,7 +7043,7 @@ fn zirFunc(
             const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
             extra_index += ret_ty_body.len;
 
-            const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type);
+            const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime known");
             var buffer: Value.ToTypeBuffer = undefined;
             break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
         },
@@ -7085,6 +7091,7 @@ fn resolveGenericBody(
     body: []const Zir.Inst.Index,
     func_inst: Zir.Inst.Index,
     dest_ty: Type,
+    reason: []const u8,
 ) !Value {
     assert(body.len != 0);
 
@@ -7098,7 +7105,7 @@ fn resolveGenericBody(
         }
         const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
         const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
-        const val = sema.resolveConstValue(block, src, result) catch |err| break :err err;
+        const val = sema.resolveConstValue(block, src, result, reason) catch |err| break :err err;
         return val;
     };
     switch (err) {
@@ -7629,7 +7636,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
         return sema.addConstant(Type.usize, ptr_val);
     }
-    try sema.requireRuntimeBlock(block, ptr_src);
+    try sema.requireRuntimeBlock(block, ptr_src, ptr_src);
     return block.addUnOp(.ptrtoint, ptr);
 }
 
@@ -7681,7 +7688,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
     const object = try sema.resolveInst(extra.lhs);
-    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
     return sema.fieldVal(block, src, object, field_name, field_name_src);
 }
 
@@ -7694,7 +7701,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
     const object_ptr = try sema.resolveInst(extra.lhs);
-    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
     return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
 }
 
@@ -7706,7 +7713,7 @@ fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended
     const src = LazySrcLoc.nodeOffset(extra.node);
     const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
     const object_ptr = try sema.resolveInst(extra.lhs);
-    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime known");
     return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
 }
 
@@ -7722,12 +7729,13 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
     const operand = try sema.resolveInst(extra.rhs);
 
-    return sema.intCast(block, dest_ty, dest_ty_src, operand, operand_src, true);
+    return sema.intCast(block, inst_data.src(), dest_ty, dest_ty_src, operand, operand_src, true);
 }
 
 fn intCast(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     dest_ty: Type,
     dest_ty_src: LazySrcLoc,
     operand: Air.Inst.Ref,
@@ -7750,7 +7758,7 @@ fn intCast(
     if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
         // requirement: intCast(u0, input) iff input == 0
         if (runtime_safety and block.wantSafety()) {
-            try sema.requireRuntimeBlock(block, operand_src);
+            try sema.requireRuntimeBlock(block, src, operand_src);
             const target = sema.mod.getTarget();
             const wanted_info = dest_scalar_ty.intInfo(target);
             const wanted_bits = wanted_info.bits;
@@ -7765,7 +7773,7 @@ fn intCast(
         return sema.addConstant(dest_ty, opv);
     }
 
-    try sema.requireRuntimeBlock(block, operand_src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     if (runtime_safety and block.wantSafety()) {
         const target = sema.mod.getTarget();
         const actual_info = operand_scalar_ty.intInfo(target);
@@ -7972,7 +7980,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     if (dst_bits >= src_bits) {
         return sema.coerce(block, dest_ty, operand, operand_src);
     }
-    try sema.requireRuntimeBlock(block, operand_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
     return block.addTyOp(.fptrunc, dest_ty, operand);
 }
 
@@ -8141,7 +8149,7 @@ fn zirSwitchCapture(
 
             const first_item = try sema.resolveInst(items[0]);
             // Previous switch validation ensured this will succeed
-            const first_item_val = sema.resolveConstValue(block, .unneeded, first_item) catch unreachable;
+            const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable;
 
             const first_field_index = @intCast(u32, enum_ty.enumTagFieldIndex(first_item_val, sema.mod).?);
             const first_field = union_obj.fields.values()[first_field_index];
@@ -8149,7 +8157,7 @@ fn zirSwitchCapture(
             for (items[1..]) |item| {
                 const item_ref = try sema.resolveInst(item);
                 // Previous switch validation ensured this will succeed
-                const item_val = sema.resolveConstValue(block, .unneeded, item_ref) catch unreachable;
+                const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
 
                 const field_index = enum_ty.enumTagFieldIndex(item_val, sema.mod).?;
                 const field = union_obj.fields.values()[field_index];
@@ -8186,7 +8194,7 @@ fn zirSwitchCapture(
                         }),
                     );
                 }
-                try sema.requireRuntimeBlock(block, operand_src);
+                try sema.requireRuntimeBlock(block, operand_src, null);
                 return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
             }
 
@@ -8196,7 +8204,7 @@ fn zirSwitchCapture(
                     operand_val.castTag(.@"union").?.data.val,
                 );
             }
-            try sema.requireRuntimeBlock(block, operand_src);
+            try sema.requireRuntimeBlock(block, operand_src, null);
             return block.addStructFieldVal(operand, first_field_index, first_field.ty);
         },
         .ErrorSet => {
@@ -8206,7 +8214,7 @@ fn zirSwitchCapture(
                 for (items) |item| {
                     const item_ref = try sema.resolveInst(item);
                     // Previous switch validation ensured this will succeed
-                    const item_val = sema.resolveConstValue(block, .unneeded, item_ref) catch unreachable;
+                    const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
                     names.putAssumeCapacityNoClobber(
                         item_val.getError().?,
                         {},
@@ -8220,7 +8228,7 @@ fn zirSwitchCapture(
             } else {
                 const item_ref = try sema.resolveInst(items[0]);
                 // Previous switch validation ensured this will succeed
-                const item_val = sema.resolveConstValue(block, .unneeded, item_ref) catch unreachable;
+                const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
 
                 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
                 return sema.bitCast(block, item_ty, operand, operand_src);
@@ -8924,7 +8932,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
 
                 const item = try sema.resolveInst(item_ref);
                 // Validation above ensured these will succeed.
-                const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
+                const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable;
                 if (operand_val.eql(item_val, operand_ty, sema.mod)) {
                     return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
                 }
@@ -8946,7 +8954,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
                 for (items) |item_ref| {
                     const item = try sema.resolveInst(item_ref);
                     // Validation above ensured these will succeed.
-                    const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
+                    const item_val = sema.resolveConstValue(&child_block, .unneeded, item, undefined) catch unreachable;
                     if (operand_val.eql(item_val, operand_ty, sema.mod)) {
                         return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
                     }
@@ -8960,8 +8968,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
                     extra_index += 1;
 
                     // Validation above ensured these will succeed.
-                    const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable;
-                    const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable;
+                    const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, undefined) catch unreachable;
+                    const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, undefined) catch unreachable;
                     if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
                         (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty)))
                     {
@@ -8982,7 +8990,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
         return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
 
     const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *
         @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2;
@@ -9271,14 +9279,14 @@ fn resolveSwitchItemVal(
     // Constructing a LazySrcLoc is costly because we only have the switch AST node.
     // Only if we know for sure we need to report a compile error do we resolve the
     // full source locations.
-    if (sema.resolveConstValue(block, .unneeded, item)) |val| {
+    if (sema.resolveConstValue(block, .unneeded, item, undefined)) |val| {
         return TypedValue{ .ty = item_ty, .val = val };
     } else |err| switch (err) {
         error.NeededSourceLocation => {
             const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand);
             return TypedValue{
                 .ty = item_ty,
-                .val = try sema.resolveConstValue(block, src, item),
+                .val = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime known"),
             };
         },
         else => |e| return e,
@@ -9464,7 +9472,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
-    const field_name = try sema.resolveConstString(block, name_src, extra.rhs);
+    const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime known");
     const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty);
 
     const has_field = hf: {
@@ -9506,7 +9514,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
-    const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
+    const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime known");
 
     try checkNamespaceType(sema, block, lhs_src, container_type);
 
@@ -9553,7 +9561,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     const mod = sema.mod;
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
-    const name = try sema.resolveConstString(block, operand_src, inst_data.operand);
+    const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime known");
 
     const embed_file = mod.embedFile(block.getFileScope(), name) catch |err| switch (err) {
         error.ImportOutsidePkgPath => {
@@ -9707,13 +9715,13 @@ fn zirShl(
                 try lhs_ty.maxInt(sema.arena, target),
             );
             const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src);
-            break :rhs try sema.intCast(block, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
+            break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
         } else {
             break :rhs rhs;
         }
     } else rhs;
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (block.wantSafety()) {
         const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
             .shl_exact => .shl_with_overflow,
@@ -9824,7 +9832,7 @@ fn zirShr(
         }
     } else rhs_src;
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addBinOp(air_tag, lhs, rhs);
 }
 
@@ -9883,7 +9891,7 @@ fn zirBitwise(
         }
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addBinOp(air_tag, casted_lhs, casted_rhs);
 }
 
@@ -9927,7 +9935,7 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addTyOp(.not, operand_type, operand);
 }
 
@@ -9940,6 +9948,7 @@ fn analyzeTupleCat(
 ) CompileError!Air.Inst.Ref {
     const lhs_ty = sema.typeOf(lhs);
     const rhs_ty = sema.typeOf(rhs);
+    const src = LazySrcLoc.nodeOffset(src_node);
     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
 
@@ -9987,7 +9996,7 @@ fn analyzeTupleCat(
         return sema.addConstant(tuple_ty, tuple_val);
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
     for (lhs_tuple.types) |_, i| {
@@ -10050,8 +10059,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
-                const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted);
-                const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted);
+                const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known");
+                const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known");
                 if (try sema.valuesEqual(block, src, lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) {
                     break :s lhs_sent_casted_val;
                 } else {
@@ -10059,14 +10068,14 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 }
             } else {
                 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
-                const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted);
+                const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted, "array sentinel value must be comptime known");
                 break :s lhs_sent_casted_val;
             }
         } else {
             if (rhs_info.sentinel) |rhs_sent_val| {
                 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
                 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
-                const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted);
+                const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted, "array sentinel value must be comptime known");
                 break :s rhs_sent_casted_val;
             } else {
                 break :s null;
@@ -10121,7 +10130,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         } else break :rs rhs_src;
     } else lhs_src;
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     if (ptr_addrspace) |ptr_as| {
         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
@@ -10187,7 +10196,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
                 // has a sentinel, and this code should compute the length based
                 // on the sentinel value.
                 .Slice, .Many => {
-                    const val = try sema.resolveConstValue(block, src, operand);
+                    const val = try sema.resolveConstValue(block, src, operand, "slice value being concatenated must be comptime known");
                     return Type.ArrayInfo{
                         .elem_type = ptr_info.pointee_type,
                         .sentinel = ptr_info.sentinel,
@@ -10216,6 +10225,7 @@ fn analyzeTupleMul(
 ) CompileError!Air.Inst.Ref {
     const operand_ty = sema.typeOf(operand);
     const operand_tuple = operand_ty.tupleFields();
+    const src = LazySrcLoc.nodeOffset(src_node);
     const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
 
@@ -10259,7 +10269,7 @@ fn analyzeTupleMul(
         return sema.addConstant(tuple_ty, tuple_val);
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len);
     for (operand_tuple.types) |_, i| {
@@ -10287,7 +10297,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
 
     // In `**` rhs must be comptime-known, but lhs can be runtime-known
-    const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize);
+    const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime known");
 
     if (lhs_ty.isTuple()) {
         return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);
@@ -10338,7 +10348,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
     }
 
-    try sema.requireRuntimeBlock(block, lhs_src);
+    try sema.requireRuntimeBlock(block, src, lhs_src);
 
     if (ptr_addrspace) |ptr_as| {
         const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
@@ -10412,7 +10422,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
             const target = sema.mod.getTarget();
             return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
         }
-        try sema.requireRuntimeBlock(block, rhs_src);
+        try sema.requireRuntimeBlock(block, src, null);
         return block.addUnOp(.neg, rhs);
     }
 
@@ -10636,7 +10646,8 @@ fn zirOverflowArithmetic(
             else => unreachable,
         };
 
-        try sema.requireRuntimeBlock(block, src);
+        const runtime_src = if (maybe_lhs_val == null) lhs_src else rhs_src;
+        try sema.requireRuntimeBlock(block, src, runtime_src);
 
         const tuple = try block.addInst(.{
             .tag = air_tag,
@@ -11543,7 +11554,7 @@ fn analyzeArithmetic(
         }
     };
 
-    try sema.requireRuntimeBlock(block, rs.src);
+    try sema.requireRuntimeBlock(block, src, rs.src);
     if (block.wantSafety()) {
         if (scalar_tag == .Int) {
             const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
@@ -11667,7 +11678,7 @@ fn analyzePtrArithmetic(
         } else break :rs ptr_src;
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, op_src, runtime_src);
     return block.addInst(.{
         .tag = air_tag,
         .data = .{ .ty_pl = .{
@@ -11686,7 +11697,7 @@ fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.In
 
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
-    const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
+    const ptr_src = src; // TODO better source location
     const ptr = try sema.resolveInst(inst_data.operand);
     return sema.analyzeLoad(block, src, ptr, ptr_src);
 }
@@ -11734,7 +11745,7 @@ fn zirAsm(
     }
 
     if (block.is_comptime) {
-        try sema.requireRuntimeBlock(block, src);
+        try sema.requireRuntimeBlock(block, src, null);
     }
 
     var extra_i = extra.end;
@@ -11896,10 +11907,10 @@ fn zirCmpEq(
     }
 
     if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) {
-        return sema.analyzeCmpUnionTag(block, lhs, lhs_src, rhs, rhs_src, op);
+        return sema.analyzeCmpUnionTag(block, src, lhs, lhs_src, rhs, rhs_src, op);
     }
     if (rhs_ty_tag == .Union and (lhs_ty_tag == .EnumLiteral or lhs_ty_tag == .Enum)) {
-        return sema.analyzeCmpUnionTag(block, rhs, rhs_src, lhs, lhs_src, op);
+        return sema.analyzeCmpUnionTag(block, src, rhs, rhs_src, lhs, lhs_src, op);
     }
 
     if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
@@ -11926,7 +11937,7 @@ fn zirCmpEq(
                 break :src lhs_src;
             }
         };
-        try sema.requireRuntimeBlock(block, runtime_src);
+        try sema.requireRuntimeBlock(block, src, runtime_src);
         return block.addBinOp(air_tag, lhs, rhs);
     }
     if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
@@ -11944,6 +11955,7 @@ fn zirCmpEq(
 fn analyzeCmpUnionTag(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     un: Air.Inst.Ref,
     un_src: LazySrcLoc,
     tag: Air.Inst.Ref,
@@ -11965,7 +11977,7 @@ fn analyzeCmpUnionTag(
     const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
     const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
 
-    return sema.cmpSelf(block, coerced_union, coerced_tag, op, un_src, tag_src);
+    return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
 }
 
 /// Only called for non-equality operators. See also `zirCmpEq`.
@@ -12021,7 +12033,7 @@ fn analyzeCmp(
     }
     const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
     const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
-    return sema.cmpSelf(block, casted_lhs, casted_rhs, op, lhs_src, rhs_src);
+    return sema.cmpSelf(block, src, casted_lhs, casted_rhs, op, lhs_src, rhs_src);
 }
 
 fn compareOperatorName(comp: std.math.CompareOperator) []const u8 {
@@ -12038,6 +12050,7 @@ fn compareOperatorName(comp: std.math.CompareOperator) []const u8 {
 fn cmpSelf(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     casted_lhs: Air.Inst.Ref,
     casted_rhs: Air.Inst.Ref,
     op: std.math.CompareOperator,
@@ -12065,7 +12078,7 @@ fn cmpSelf(
             } else {
                 if (resolved_type.zigTypeTag() == .Bool) {
                     // We can lower bool eq/neq more efficiently.
-                    return sema.runtimeBoolCmp(block, op, casted_rhs, lhs_val.toBool(), rhs_src);
+                    return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
                 }
                 break :src rhs_src;
             }
@@ -12075,13 +12088,13 @@ fn cmpSelf(
             if (resolved_type.zigTypeTag() == .Bool) {
                 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
                     if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
-                    return sema.runtimeBoolCmp(block, op, casted_lhs, rhs_val.toBool(), lhs_src);
+                    return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
                 }
             }
             break :src lhs_src;
         }
     };
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (resolved_type.zigTypeTag() == .Vector) {
         const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
         const result_ty_ref = try sema.addType(result_ty);
@@ -12098,13 +12111,14 @@ fn cmpSelf(
 fn runtimeBoolCmp(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     op: std.math.CompareOperator,
     lhs: Air.Inst.Ref,
     rhs: bool,
     runtime_src: LazySrcLoc,
 ) CompileError!Air.Inst.Ref {
     if ((op == .neq) == rhs) {
-        try sema.requireRuntimeBlock(block, runtime_src);
+        try sema.requireRuntimeBlock(block, src, runtime_src);
         return block.addTyOp(.not, Type.bool, lhs);
     } else {
         return lhs;
@@ -12226,7 +12240,7 @@ fn zirRetAddr(
     extended: Zir.Inst.Extended.InstData,
 ) CompileError!Air.Inst.Ref {
     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return try block.addNoOp(.ret_addr);
 }
 
@@ -12236,7 +12250,7 @@ fn zirFrameAddress(
     extended: Zir.Inst.Extended.InstData,
 ) CompileError!Air.Inst.Ref {
     const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return try block.addNoOp(.frame_addr);
 }
 
@@ -13305,7 +13319,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
         else
             Air.Inst.Ref.bool_true;
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addTyOp(.not, Type.bool, operand);
 }
 
@@ -13690,7 +13704,7 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
     if (block.is_comptime or inst_data.force_comptime) {
         return sema.fail(block, src, "reached unreachable code", .{});
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireFunctionBlock(block, src);
     // TODO Add compile error for @optimizeFor occurring too late in a scope.
     try block.addUnreachable(src, true);
     return always_noreturn;
@@ -13752,7 +13766,6 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
         const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
         return sema.analyzeRet(block, operand, src);
     }
-    try sema.requireRuntimeBlock(block, src);
     _ = try block.addUnOp(.ret_load, ret_ptr);
     return always_noreturn;
 }
@@ -13874,14 +13887,14 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const sentinel = if (inst_data.flags.has_sentinel) blk: {
         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
         extra_i += 1;
-        break :blk (try sema.resolveInstConst(block, sentinel_src, ref)).val;
+        break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime known")).val;
     } else null;
 
     const abi_align: u32 = if (inst_data.flags.has_align) blk: {
         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
         extra_i += 1;
         const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src);
-        const val = try sema.resolveConstValue(block, align_src, coerced);
+        const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime known");
         // Check if this happens to be the lazy alignment of our element type, in
         // which case we can make this 0 without resolving it.
         if (val.castTag(.lazy_align)) |payload| {
@@ -13902,14 +13915,14 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const bit_offset = if (inst_data.flags.has_bit_range) blk: {
         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
         extra_i += 1;
-        const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16);
+        const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, "pointer bit-offset must be comptime known");
         break :blk @intCast(u16, bit_offset);
     } else 0;
 
     const host_size: u16 = if (inst_data.flags.has_bit_range) blk: {
         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
         extra_i += 1;
-        const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16);
+        const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, "pointer host size must be comptime known");
         break :blk @intCast(u16, host_size);
     } else 0;
 
@@ -14014,7 +14027,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
     const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
     const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
-    const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime known");
     const init = try sema.resolveInst(extra.init);
     return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
 }
@@ -14041,7 +14054,7 @@ fn unionInit(
         }));
     }
 
-    try sema.requireRuntimeBlock(block, init_src);
+    try sema.requireRuntimeBlock(block, init_src, null);
     _ = union_ty_src;
     try sema.queueFullTypeResolution(union_ty);
     return block.addUnionInit(union_ty, field_index, init);
@@ -14146,7 +14159,7 @@ fn zirStructInit(
             return alloc;
         }
 
-        try sema.requireRuntimeBlock(block, src);
+        try sema.requireRuntimeBlock(block, src, null);
         try sema.queueFullTypeResolution(resolved_ty);
         return block.addUnionInit(resolved_ty, field_index, init_inst);
     } else if (resolved_ty.isAnonStruct()) {
@@ -14251,7 +14264,7 @@ fn finishStructInit(
         return alloc;
     }
 
-    try sema.requireRuntimeBlock(block, dest_src);
+    try sema.requireRuntimeBlock(block, dest_src, null);
     try sema.queueFullTypeResolution(struct_ty);
     return block.addAggregateInit(struct_ty, field_inits);
 }
@@ -14301,7 +14314,7 @@ fn zirStructInitAnon(
         return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     if (is_ref) {
         const target = sema.mod.getTarget();
@@ -14393,7 +14406,7 @@ fn zirArrayInit(
         return sema.addConstantMaybeRef(block, src, array_ty, array_val, is_ref);
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     try sema.queueFullTypeResolution(array_ty);
 
     if (is_ref) {
@@ -14479,7 +14492,7 @@ fn zirArrayInitAnon(
         return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref);
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     if (is_ref) {
         const target = sema.mod.getTarget();
@@ -14538,7 +14551,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
     const ty_src = inst_data.src();
     const field_src = inst_data.src();
     const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
-    const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime known");
     return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
 }
 
@@ -14728,7 +14741,7 @@ fn zirUnaryMath(
                 );
             }
 
-            try sema.requireRuntimeBlock(block, operand_src);
+            try sema.requireRuntimeBlock(block, operand_src, null);
             return block.addUnOp(air_tag, operand);
         },
         .ComptimeFloat, .Float => {
@@ -14739,7 +14752,7 @@ fn zirUnaryMath(
                 return sema.addConstant(operand_ty, result_val);
             }
 
-            try sema.requireRuntimeBlock(block, operand_src);
+            try sema.requireRuntimeBlock(block, operand_src, null);
             return block.addUnOp(air_tag, operand);
         },
         else => unreachable,
@@ -14757,7 +14770,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     try sema.resolveTypeLayout(block, operand_src, operand_ty);
     const enum_ty = switch (operand_ty.zigTypeTag()) {
         .EnumLiteral => {
-            const val = try sema.resolveConstValue(block, operand_src, operand);
+            const val = try sema.resolveConstValue(block, .unneeded, operand, undefined);
             const bytes = val.castTag(.enum_literal).?.data;
             return sema.addStrLit(block, bytes);
         },
@@ -14809,7 +14822,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
     const uncasted_operand = try sema.resolveInst(inst_data.operand);
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
-    const val = try sema.resolveConstValue(block, operand_src, type_info);
+    const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
     const union_val = val.cast(Value.Payload.Union).?.data;
     const tag_ty = type_info_ty.unionTagType().?;
     const target = mod.getTarget();
@@ -15493,10 +15506,10 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
         const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
         return sema.addConstant(dest_ty, result_val);
     } else if (dest_ty.zigTypeTag() == .ComptimeInt) {
-        return sema.failWithNeededComptime(block, operand_src);
+        return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime known");
     }
 
-    try sema.requireRuntimeBlock(block, operand_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
     return block.addTyOp(.float_to_int, dest_ty, operand);
 }
 
@@ -15517,10 +15530,10 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
         const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
         return sema.addConstant(dest_ty, result_val);
     } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
-        return sema.failWithNeededComptime(block, operand_src);
+        return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known");
     }
 
-    try sema.requireRuntimeBlock(block, operand_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
     return block.addTyOp(.int_to_float, dest_ty, operand);
 }
 
@@ -15556,7 +15569,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         return sema.addConstant(type_res, Value.initPayload(&val_payload.base));
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     if (block.wantSafety()) {
         if (!type_res.isAllowzeroPtr()) {
             const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
@@ -15653,7 +15666,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
         return sema.addConstant(dest_ty, val);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     if (block.wantSafety() and !dest_ty.isAnyError()) {
         const err_int_inst = try block.addBitCast(Type.u16, operand);
         // TODO: Output a switch instead of chained OR's.
@@ -15808,7 +15821,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         );
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, operand_src);
     return block.addTyOp(.trunc, dest_ty, operand);
 }
 
@@ -15851,6 +15864,7 @@ fn zirBitCount(
     comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
 ) CompileError!Air.Inst.Ref {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const operand = try sema.resolveInst(inst_data.operand);
     const operand_ty = sema.typeOf(operand);
@@ -15883,7 +15897,7 @@ fn zirBitCount(
                     try Value.Tag.aggregate.create(sema.arena, elems),
                 );
             } else {
-                try sema.requireRuntimeBlock(block, operand_src);
+                try sema.requireRuntimeBlock(block, src, operand_src);
                 return block.addTyOp(air_tag, result_ty, operand);
             }
         },
@@ -15892,7 +15906,7 @@ fn zirBitCount(
                 if (val.isUndef()) return sema.addConstUndef(result_scalar_ty);
                 return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target));
             } else {
-                try sema.requireRuntimeBlock(block, operand_src);
+                try sema.requireRuntimeBlock(block, src, operand_src);
                 return block.addTyOp(air_tag, result_scalar_ty, operand);
             }
         },
@@ -15902,6 +15916,7 @@ fn zirBitCount(
 
 fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
     const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const operand = try sema.resolveInst(inst_data.operand);
@@ -15930,7 +15945,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 return sema.addConstant(operand_ty, result_val);
             } else operand_src;
 
-            try sema.requireRuntimeBlock(block, runtime_src);
+            try sema.requireRuntimeBlock(block, src, runtime_src);
             return block.addTyOp(.byte_swap, operand_ty, operand);
         },
         .Vector => {
@@ -15951,7 +15966,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
                 );
             } else operand_src;
 
-            try sema.requireRuntimeBlock(block, runtime_src);
+            try sema.requireRuntimeBlock(block, src, runtime_src);
             return block.addTyOp(.byte_swap, operand_ty, operand);
         },
         else => unreachable,
@@ -15960,6 +15975,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
 
 fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
     const operand = try sema.resolveInst(inst_data.operand);
     const operand_ty = sema.typeOf(operand);
@@ -15978,7 +15994,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
                 return sema.addConstant(operand_ty, result_val);
             } else operand_src;
 
-            try sema.requireRuntimeBlock(block, runtime_src);
+            try sema.requireRuntimeBlock(block, src, runtime_src);
             return block.addTyOp(.bit_reverse, operand_ty, operand);
         },
         .Vector => {
@@ -15999,7 +16015,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
                 );
             } else operand_src;
 
-            try sema.requireRuntimeBlock(block, runtime_src);
+            try sema.requireRuntimeBlock(block, src, runtime_src);
             return block.addTyOp(.bit_reverse, operand_ty, operand);
         },
         else => unreachable,
@@ -16026,7 +16042,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
 
     const ty = try sema.resolveType(block, lhs_src, extra.lhs);
-    const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
+    const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime known");
     const target = sema.mod.getTarget();
 
     try sema.resolveTypeLayout(block, lhs_src, ty);
@@ -16447,19 +16463,19 @@ fn resolveExportOptions(
     const options = try sema.coerce(block, export_options_ty, air_ref, src);
 
     const name_operand = try sema.fieldVal(block, src, options, "name", src);
-    const name_val = try sema.resolveConstValue(block, src, name_operand);
+    const name_val = try sema.resolveConstValue(block, src, name_operand, "name of exported value must be comptime known");
     const name_ty = Type.initTag(.const_slice_u8);
     const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod);
 
     const linkage_operand = try sema.fieldVal(block, src, options, "linkage", src);
-    const linkage_val = try sema.resolveConstValue(block, src, linkage_operand);
+    const linkage_val = try sema.resolveConstValue(block, src, linkage_operand, "linkage of exported value must be comptime known");
     const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage);
 
     const section = try sema.fieldVal(block, src, options, "section", src);
-    const section_val = try sema.resolveConstValue(block, src, section);
+    const section_val = try sema.resolveConstValue(block, src, section, "linksection of exported value must be comptime known");
 
     const visibility_operand = try sema.fieldVal(block, src, options, "visibility", src);
-    const visibility_val = try sema.resolveConstValue(block, src, visibility_operand);
+    const visibility_val = try sema.resolveConstValue(block, src, visibility_operand, "visibility of exported value must be comptime known");
     const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility);
 
     if (name.len < 1) {
@@ -16490,11 +16506,12 @@ fn resolveBuiltinEnum(
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
     comptime name: []const u8,
+    reason: []const u8,
 ) CompileError!@field(std.builtin, name) {
     const ty = try sema.getBuiltinType(block, src, name);
     const air_ref = try sema.resolveInst(zir_ref);
     const coerced = try sema.coerce(block, ty, air_ref, src);
-    const val = try sema.resolveConstValue(block, src, coerced);
+    const val = try sema.resolveConstValue(block, src, coerced, reason);
     return val.toEnum(@field(std.builtin, name));
 }
 
@@ -16503,8 +16520,9 @@ fn resolveAtomicOrder(
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
+    reason: []const u8,
 ) CompileError!std.builtin.AtomicOrder {
-    return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicOrder");
+    return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicOrder", reason);
 }
 
 fn resolveAtomicRmwOp(
@@ -16513,7 +16531,7 @@ fn resolveAtomicRmwOp(
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
 ) CompileError!std.builtin.AtomicRmwOp {
-    return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicRmwOp");
+    return resolveBuiltinEnum(sema, block, src, zir_ref, "AtomicRmwOp", "@atomicRmW operation must be comptime known");
 }
 
 fn zirCmpxchg(
@@ -16546,8 +16564,8 @@ fn zirCmpxchg(
     const uncasted_ptr = try sema.resolveInst(extra.ptr);
     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
     const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src);
-    const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order);
-    const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order);
+    const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, "atomic order of cmpxchg success must be comptime known");
+    const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, "atomic order of cmpxchg failure must be comptime known");
 
     if (@enumToInt(success_order) < @enumToInt(std.builtin.AtomicOrder.Monotonic)) {
         return sema.fail(block, success_order_src, "success atomic ordering must be Monotonic or stricter", .{});
@@ -16592,7 +16610,7 @@ fn zirCmpxchg(
     const flags: u32 = @as(u32, @enumToInt(success_order)) |
         (@as(u32, @enumToInt(failure_order)) << 3);
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addInst(.{
         .tag = air_tag,
         .data = .{ .ty_pl = .{
@@ -16612,7 +16630,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
     const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
     const scalar_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
-    const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32));
+    const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector splat destination length must be comptime known"));
     const scalar = try sema.resolveInst(extra.rhs);
     const scalar_ty = sema.typeOf(scalar);
     try sema.checkVectorElemType(block, scalar_src, scalar_ty);
@@ -16629,7 +16647,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
         );
     }
 
-    try sema.requireRuntimeBlock(block, scalar_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src);
     return block.addTyOp(.splat, vector_ty, scalar);
 }
 
@@ -16638,7 +16656,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
     const op_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
-    const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp");
+    const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime known");
     const operand = try sema.resolveInst(extra.rhs);
     const operand_ty = sema.typeOf(operand);
     const target = sema.mod.getTarget();
@@ -16693,7 +16711,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
         return sema.addConstant(scalar_ty, accum);
     }
 
-    try sema.requireRuntimeBlock(block, operand_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
     return block.addInst(.{
         .tag = .reduce,
         .data = .{ .reduce = .{
@@ -16725,7 +16743,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
         .elem_type = Type.@"i32",
     });
     mask = try sema.coerce(block, mask_ty, mask, mask_src);
-    const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask);
+    const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime known");
     return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len));
 }
 
@@ -16897,6 +16915,7 @@ fn analyzeShuffle(
 fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
     const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data;
 
+    const src = LazySrcLoc.nodeOffset(extra.node);
     const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
     const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
     const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = extra.node };
@@ -16968,7 +16987,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
         break :rs pred_src;
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addInst(.{
         .tag = .select,
         .data = .{ .pl_op = .{
@@ -16992,7 +17011,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
     const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
     const uncasted_ptr = try sema.resolveInst(extra.ptr);
     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
-    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
+    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicLoad must be comptime known");
 
     switch (order) {
         .Release, .AcqRel => {
@@ -17016,7 +17035,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
         }
     }
 
-    try sema.requireRuntimeBlock(block, ptr_src);
+    try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
     return block.addInst(.{
         .tag = .atomic_load,
         .data = .{ .atomic_load = .{
@@ -17056,7 +17075,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         },
         else => {},
     }
-    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
+    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicRmW must be comptime known");
 
     if (order == .Unordered) {
         return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be Unordered", .{});
@@ -17097,7 +17116,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
 
     const flags: u32 = @as(u32, @enumToInt(order)) | (@as(u32, @enumToInt(op)) << 3);
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addInst(.{
         .tag = .atomic_rmw,
         .data = .{ .pl_op = .{
@@ -17124,7 +17143,7 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
     const elem_ty = sema.typeOf(operand);
     const uncasted_ptr = try sema.resolveInst(extra.ptr);
     const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
-    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
+    const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, "atomic order of @atomicStore must be comptime known");
 
     const air_tag: Air.Inst.Tag = switch (order) {
         .Acquire, .AcqRel => {
@@ -17196,7 +17215,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
         break :rs mulend1_src;
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addInst(.{
         .tag = .mul_add,
         .data = .{ .pl_op = .{
@@ -17229,10 +17248,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
         const coerced_options = try sema.coerce(block, call_options_ty, options, options_src);
 
         const modifier = try sema.fieldVal(block, options_src, coerced_options, "modifier", options_src);
-        const modifier_val = try sema.resolveConstValue(block, options_src, modifier);
+        const modifier_val = try sema.resolveConstValue(block, options_src, modifier, "call modifier must be comptime known");
 
         const stack = try sema.fieldVal(block, options_src, coerced_options, "stack", options_src);
-        const stack_val = try sema.resolveConstValue(block, options_src, stack);
+        const stack_val = try sema.resolveConstValue(block, options_src, stack, "call stack value must be comptime known");
 
         if (!stack_val.isNull()) {
             return sema.fail(block, options_src, "TODO: implement @call with stack", .{});
@@ -17293,7 +17312,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
 
     // Desugar bound functions here
     if (sema.typeOf(func).tag() == .bound_fn) {
-        const bound_func = try sema.resolveValue(block, func_src, func);
+        const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
         const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
         func = bound_data.func_inst;
         resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
@@ -17320,7 +17339,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
     const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
 
     const struct_ty = try sema.resolveType(block, ty_src, extra.parent_type);
-    const field_name = try sema.resolveConstString(block, name_src, extra.field_name);
+    const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime known");
     const field_ptr = try sema.resolveInst(extra.field_ptr);
     const field_ptr_ty = sema.typeOf(field_ptr);
 
@@ -17385,7 +17404,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
         return sema.addConstant(result_ptr, payload.data.container_ptr);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, ptr_src);
     return block.addInst(.{
         .tag = .field_parent_ptr,
         .data = .{ .ty_pl = .{
@@ -17466,7 +17485,7 @@ fn analyzeMinMax(
         break :rs lhs_src;
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     return block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
 }
 
@@ -17514,7 +17533,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
         } else break :rs src_src;
     } else dest_src;
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     _ = try block.addInst(.{
         .tag = .memcpy,
         .data = .{ .pl_op = .{
@@ -17556,7 +17575,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
         } else break :rs len_src;
     } else dest_src;
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     _ = try block.addInst(.{
         .tag = .memset,
         .data = .{ .pl_op = .{
@@ -17652,7 +17671,7 @@ fn zirVarExtended(
             uncasted_init;
 
         break :blk (try sema.resolveMaybeUndefVal(block, init_src, init)) orelse
-            return sema.failWithNeededComptime(block, init_src);
+            return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime known");
     } else Value.initTag(.unreachable_value);
 
     try sema.validateVarType(block, name_src, var_ty, small.is_extern);
@@ -17718,7 +17737,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         const body = sema.code.extra[extra_index..][0..body_len];
         extra_index += body.len;
 
-        const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29);
+        const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime known");
         if (val.tag() == .generic_poison) {
             break :blk null;
         }
@@ -17731,7 +17750,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     } else if (extra.data.bits.has_align_ref) blk: {
         const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const align_tv = sema.resolveInstConst(block, align_src, align_ref) catch |err| switch (err) {
+        const align_tv = sema.resolveInstConst(block, align_src, align_ref, "alignment must be comptime known") catch |err| switch (err) {
             error.GenericPoison => {
                 break :blk null;
             },
@@ -17752,7 +17771,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         extra_index += body.len;
 
         const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace");
-        const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty);
+        const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime known");
         if (val.tag() == .generic_poison) {
             break :blk null;
         }
@@ -17760,7 +17779,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     } else if (extra.data.bits.has_addrspace_ref) blk: {
         const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref) catch |err| switch (err) {
+        const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref, "addrespace must be comptime known") catch |err| switch (err) {
             error.GenericPoison => {
                 break :blk null;
             },
@@ -17775,7 +17794,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         const body = sema.code.extra[extra_index..][0..body_len];
         extra_index += body.len;
 
-        const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8));
+        const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8), "linksection must be comptime known");
         if (val.tag() == .generic_poison) {
             break :blk FuncLinkSection{ .generic = {} };
         }
@@ -17784,7 +17803,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     } else if (extra.data.bits.has_section_ref) blk: {
         const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const section_tv = sema.resolveInstConst(block, section_src, section_ref) catch |err| switch (err) {
+        const section_tv = sema.resolveInstConst(block, section_src, section_ref, "linksection must be comptime known") catch |err| switch (err) {
             error.GenericPoison => {
                 break :blk FuncLinkSection{ .generic = {} };
             },
@@ -17801,7 +17820,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         extra_index += body.len;
 
         const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention");
-        const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty);
+        const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime known");
         if (val.tag() == .generic_poison) {
             break :blk null;
         }
@@ -17809,7 +17828,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
     } else if (extra.data.bits.has_cc_ref) blk: {
         const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref) catch |err| switch (err) {
+        const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref, "calling convention must be comptime known") catch |err| switch (err) {
             error.GenericPoison => {
                 break :blk null;
             },
@@ -17824,14 +17843,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         const body = sema.code.extra[extra_index..][0..body_len];
         extra_index += body.len;
 
-        const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type);
+        const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime known");
         var buffer: Value.ToTypeBuffer = undefined;
         const ty = try val.toType(&buffer).copy(sema.arena);
         break :blk ty;
     } else if (extra.data.bits.has_ret_ty_ref) blk: {
         const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref) catch |err| switch (err) {
+        const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime known") catch |err| switch (err) {
             error.GenericPoison => {
                 break :blk Type.initTag(.generic_poison);
             },
@@ -17886,7 +17905,7 @@ fn zirCUndef(
     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
 
-    const name = try sema.resolveConstString(block, src, extra.operand);
+    const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime known");
     try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
     return Air.Inst.Ref.void_value;
 }
@@ -17899,7 +17918,7 @@ fn zirCInclude(
     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
     const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
 
-    const name = try sema.resolveConstString(block, src, extra.operand);
+    const name = try sema.resolveConstString(block, src, extra.operand, "path being included must be comptime known");
     try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
     return Air.Inst.Ref.void_value;
 }
@@ -17913,10 +17932,10 @@ fn zirCDefine(
     const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
     const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
 
-    const name = try sema.resolveConstString(block, name_src, extra.lhs);
+    const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime known");
     const rhs = try sema.resolveInst(extra.rhs);
     if (sema.typeOf(rhs).zigTypeTag() != .Void) {
-        const value = try sema.resolveConstString(block, val_src, extra.rhs);
+        const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime known");
         try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
     } else {
         try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
@@ -17937,8 +17956,8 @@ fn zirWasmMemorySize(
         return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
     }
 
-    const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32));
-    try sema.requireRuntimeBlock(block, builtin_src);
+    const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32, "wasm memory size index must be comptime known"));
+    try sema.requireRuntimeBlock(block, builtin_src, null);
     return block.addInst(.{
         .tag = .wasm_memory_size,
         .data = .{ .pl_op = .{
@@ -17962,10 +17981,10 @@ fn zirWasmMemoryGrow(
         return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)});
     }
 
-    const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32));
+    const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32, "wasm memory size index must be comptime known"));
     const delta = try sema.coerce(block, Type.u32, try sema.resolveInst(extra.rhs), delta_src);
 
-    try sema.requireRuntimeBlock(block, builtin_src);
+    try sema.requireRuntimeBlock(block, builtin_src, null);
     return block.addInst(.{
         .tag = .wasm_memory_grow,
         .data = .{ .pl_op = .{
@@ -17990,15 +18009,15 @@ fn zirPrefetch(
     const target = sema.mod.getTarget();
 
     const rw = try sema.fieldVal(block, opts_src, options, "rw", opts_src);
-    const rw_val = try sema.resolveConstValue(block, opts_src, rw);
+    const rw_val = try sema.resolveConstValue(block, opts_src, rw, "prefetch read/write must be comptime known");
     const rw_tag = rw_val.toEnum(std.builtin.PrefetchOptions.Rw);
 
     const locality = try sema.fieldVal(block, opts_src, options, "locality", opts_src);
-    const locality_val = try sema.resolveConstValue(block, opts_src, locality);
+    const locality_val = try sema.resolveConstValue(block, opts_src, locality, "prefetch locality must be comptime known");
     const locality_int = @intCast(u2, locality_val.toUnsignedInt(target));
 
     const cache = try sema.fieldVal(block, opts_src, options, "cache", opts_src);
-    const cache_val = try sema.resolveConstValue(block, opts_src, cache);
+    const cache_val = try sema.resolveConstValue(block, opts_src, cache, "prefetch cache must be comptime known");
     const cache_tag = cache_val.toEnum(std.builtin.PrefetchOptions.Cache);
 
     if (!block.is_comptime) {
@@ -18035,16 +18054,16 @@ fn zirBuiltinExtern(
         const options = try sema.coerce(block, extern_options_ty, options_inst, options_src);
 
         const name = try sema.fieldVal(block, options_src, options, "name", options_src);
-        const name_val = try sema.resolveConstValue(block, options_src, name);
+        const name_val = try sema.resolveConstValue(block, options_src, name, "name of the extern symbol must be comptime known");
 
         const library_name_inst = try sema.fieldVal(block, options_src, options, "library_name", options_src);
-        const library_name_val = try sema.resolveConstValue(block, options_src, library_name_inst);
+        const library_name_val = try sema.resolveConstValue(block, options_src, library_name_inst, "library in which extern symbol is must be comptime known");
 
         const linkage = try sema.fieldVal(block, options_src, options, "linkage", options_src);
-        const linkage_val = try sema.resolveConstValue(block, options_src, linkage);
+        const linkage_val = try sema.resolveConstValue(block, options_src, linkage, "linkage of the extern symbol must be comptime known");
 
         const is_thread_local = try sema.fieldVal(block, options_src, options, "is_thread_local", options_src);
-        const is_thread_local_val = try sema.resolveConstValue(block, options_src, is_thread_local);
+        const is_thread_local_val = try sema.resolveConstValue(block, options_src, is_thread_local, "threadlocality of the extern symbol must be comptime known");
 
         var library_name: ?[]const u8 = null;
         if (!library_name_val.isNull()) {
@@ -18121,19 +18140,30 @@ fn zirBuiltinExtern(
     new_decl.value_arena = arena_state;
 
     const ref = try sema.analyzeDeclRef(new_decl_index);
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addBitCast(ty, ref);
 }
 
+/// Asserts that the block is not comptime.
 fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
+    assert(!block.is_comptime);
     if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) {
         return sema.fail(block, src, "instruction illegal outside function body", .{});
     }
 }
 
-fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
+fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
     if (block.is_comptime) {
-        return sema.failWithNeededComptime(block, src);
+        const msg = msg: {
+            const msg = try sema.errMsg(block, src, "unable to evalutate comptime expression", .{});
+            errdefer msg.destroy(sema.gpa);
+
+            if (runtime_src) |some| {
+                try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{});
+            }
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(block, msg);
     }
     try sema.requireFunctionBlock(block, src);
 }
@@ -18972,7 +19002,7 @@ fn fieldPtr(
                         }),
                     );
                 }
-                try sema.requireRuntimeBlock(block, src);
+                try sema.requireRuntimeBlock(block, src, null);
 
                 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
             } else if (mem.eql(u8, field_name, "len")) {
@@ -18992,7 +19022,7 @@ fn fieldPtr(
                         }),
                     );
                 }
-                try sema.requireRuntimeBlock(block, src);
+                try sema.requireRuntimeBlock(block, src, null);
 
                 return block.addTyOp(.ptr_slice_len_ptr, result_ty, inner_ptr);
             } else {
@@ -19005,7 +19035,7 @@ fn fieldPtr(
             }
         },
         .Type => {
-            _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
+            _ = try sema.resolveConstValue(block, .unneeded, object_ptr, undefined);
             const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
             const inner = if (is_pointer_to)
                 try sema.analyzeLoad(block, src, result, object_ptr_src)
@@ -19238,7 +19268,7 @@ fn finishFieldCallBind(
         return sema.analyzeLoad(block, src, pointer, src);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
     return sema.analyzeLoad(block, src, ptr_inst, src);
 }
@@ -19425,7 +19455,7 @@ fn structFieldPtrByIndex(
         );
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty);
 }
 
@@ -19469,7 +19499,7 @@ fn structFieldVal(
                 return sema.addConstant(field.ty, field_values[field_index]);
             }
 
-            try sema.requireRuntimeBlock(block, src);
+            try sema.requireRuntimeBlock(block, src, null);
             return block.addStructFieldVal(struct_byval, field_index, field.ty);
         },
         else => unreachable,
@@ -19533,7 +19563,7 @@ fn tupleFieldValByIndex(
         return sema.addConstant(field_ty, field_values[field_index]);
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addStructFieldVal(tuple_byval, field_index, field_ty);
 }
 
@@ -19597,7 +19627,7 @@ fn unionFieldPtr(
         );
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
 }
 
@@ -19655,7 +19685,7 @@ fn unionFieldVal(
         }
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addStructFieldVal(union_byval, field_index, field.ty);
 }
 
@@ -19684,7 +19714,7 @@ fn elemPtr(
             // In all below cases, we have to deref the ptr operand to get the actual indexable pointer.
             const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
             switch (indexable_ty.ptrSize()) {
-                .Slice => return sema.elemPtrSlice(block, indexable_ptr_src, indexable, elem_index_src, elem_index),
+                .Slice => return sema.elemPtrSlice(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index),
                 .Many, .C => {
                     const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable);
                     const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
@@ -19698,19 +19728,19 @@ fn elemPtr(
                     };
                     const result_ty = try sema.elemPtrType(indexable_ty, null);
 
-                    try sema.requireRuntimeBlock(block, runtime_src);
+                    try sema.requireRuntimeBlock(block, src, runtime_src);
                     return block.addPtrElemPtr(indexable, elem_index, result_ty);
                 },
                 .One => {
                     assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
-                    return sema.elemPtrArray(block, indexable_ptr_src, indexable, elem_index_src, elem_index, init);
+                    return sema.elemPtrArray(block, src, indexable_ptr_src, indexable, elem_index_src, elem_index, init);
                 },
             }
         },
-        .Array, .Vector => return sema.elemPtrArray(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),
+        .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),
         .Struct => {
             // Tuple field access.
-            const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index);
+            const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
             const index = @intCast(u32, index_val.toUnsignedInt(target));
             return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index);
         },
@@ -19740,7 +19770,7 @@ fn elemVal(
 
     switch (indexable_ty.zigTypeTag()) {
         .Pointer => switch (indexable_ty.ptrSize()) {
-            .Slice => return sema.elemValSlice(block, indexable_src, indexable, elem_index_src, elem_index),
+            .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index),
             .Many, .C => {
                 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
                 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
@@ -19756,7 +19786,7 @@ fn elemVal(
                     break :rs indexable_src;
                 };
 
-                try sema.requireRuntimeBlock(block, runtime_src);
+                try sema.requireRuntimeBlock(block, src, runtime_src);
                 return block.addBinOp(.ptr_elem_val, indexable, elem_index);
             },
             .One => {
@@ -19765,14 +19795,14 @@ fn elemVal(
                 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
             },
         },
-        .Array => return elemValArray(sema, block, indexable_src, indexable, elem_index_src, elem_index),
+        .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index),
         .Vector => {
             // TODO: If the index is a vector, the result should be a vector.
-            return elemValArray(sema, block, indexable_src, indexable, elem_index_src, elem_index);
+            return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index);
         },
         .Struct => {
             // Tuple field access.
-            const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index);
+            const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime known");
             const index = @intCast(u32, index_val.toUnsignedInt(target));
             return tupleField(sema, block, indexable_src, indexable, elem_index_src, index);
         },
@@ -19850,7 +19880,7 @@ fn tupleFieldPtr(
 
     try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
 
-    try sema.requireRuntimeBlock(block, tuple_ptr_src);
+    try sema.requireRuntimeBlock(block, tuple_ptr_src, null);
     return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
 }
 
@@ -19890,13 +19920,14 @@ fn tupleField(
 
     try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
 
-    try sema.requireRuntimeBlock(block, tuple_src);
+    try sema.requireRuntimeBlock(block, tuple_src, null);
     return block.addStructFieldVal(tuple, field_index, field_ty);
 }
 
 fn elemValArray(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     array_src: LazySrcLoc,
     array: Air.Inst.Ref,
     elem_index_src: LazySrcLoc,
@@ -19943,7 +19974,7 @@ fn elemValArray(
     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
 
     const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (block.wantSafety()) {
         // Runtime check is only needed if unable to comptime check
         if (maybe_index_val == null) {
@@ -19958,6 +19989,7 @@ fn elemValArray(
 fn elemPtrArray(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     array_ptr_src: LazySrcLoc,
     array_ptr: Air.Inst.Ref,
     elem_index_src: LazySrcLoc,
@@ -20003,7 +20035,7 @@ fn elemPtrArray(
     }
 
     const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     // Runtime check is only needed if unable to comptime check.
     if (block.wantSafety() and offset == null) {
@@ -20018,6 +20050,7 @@ fn elemPtrArray(
 fn elemValSlice(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     slice_src: LazySrcLoc,
     slice: Air.Inst.Ref,
     elem_index_src: LazySrcLoc,
@@ -20057,7 +20090,7 @@ fn elemValSlice(
 
     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (block.wantSafety()) {
         const len_inst = if (maybe_slice_val) |slice_val|
             try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod))
@@ -20073,6 +20106,7 @@ fn elemValSlice(
 fn elemPtrSlice(
     sema: *Sema,
     block: *Block,
+    src: LazySrcLoc,
     slice_src: LazySrcLoc,
     slice: Air.Inst.Ref,
     elem_index_src: LazySrcLoc,
@@ -20113,7 +20147,7 @@ fn elemPtrSlice(
     try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src);
 
     const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (block.wantSafety()) {
         const len_inst = len: {
             if (maybe_undef_slice_val) |slice_val|
@@ -20177,7 +20211,7 @@ fn coerceExtra(
             // Keep the comptime Value representation; take the new type.
             return sema.addConstant(dest_ty, val);
         }
-        try sema.requireRuntimeBlock(block, inst_src);
+        try sema.requireRuntimeBlock(block, inst_src, null);
         return block.addBitCast(dest_ty, inst);
     }
 
@@ -20222,7 +20256,7 @@ fn coerceExtra(
 
             // Function body to function pointer.
             if (inst_ty.zigTypeTag() == .Fn) {
-                const fn_val = try sema.resolveConstValue(block, inst_src, inst);
+                const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
                 const fn_decl = fn_val.castTag(.function).?.data.owner_decl;
                 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
                 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
@@ -20489,7 +20523,7 @@ fn coerceExtra(
                     // small enough unsigned ints can get casted to large enough signed ints
                     (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
                 {
-                    try sema.requireRuntimeBlock(block, inst_src);
+                    try sema.requireRuntimeBlock(block, inst_src, null);
                     return block.addTyOp(.intcast, dest_ty, inst);
                 }
             },
@@ -20500,7 +20534,7 @@ fn coerceExtra(
         },
         .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
             .ComptimeFloat => {
-                const val = try sema.resolveConstValue(block, inst_src, inst);
+                const val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
                 const result_val = try val.floatCast(sema.arena, dest_ty, target);
                 return try sema.addConstant(dest_ty, result_val);
             },
@@ -20516,13 +20550,15 @@ fn coerceExtra(
                         );
                     }
                     return try sema.addConstant(dest_ty, result_val);
+                } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
+                    return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known");
                 }
 
                 // float widening
                 const src_bits = inst_ty.floatBits(target);
                 const dst_bits = dest_ty.floatBits(target);
                 if (dst_bits >= src_bits) {
-                    try sema.requireRuntimeBlock(block, inst_src);
+                    try sema.requireRuntimeBlock(block, inst_src, null);
                     return block.addTyOp(.fpext, dest_ty, inst);
                 }
             },
@@ -20549,7 +20585,7 @@ fn coerceExtra(
         .Enum => switch (inst_ty.zigTypeTag()) {
             .EnumLiteral => {
                 // enum literal to enum
-                const val = try sema.resolveConstValue(block, inst_src, inst);
+                const val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
                 const bytes = val.castTag(.enum_literal).?.data;
                 const field_index = dest_ty.enumFieldIndex(bytes) orelse {
                     const msg = msg: {
@@ -21712,7 +21748,12 @@ fn storePtr2(
         return;
     }
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    if (block.is_comptime) {
+        // TODO ideally this would tell why the block is comptime
+        return sema.fail(block, ptr_src, "cannot store to runtime value in comptime block", .{});
+    }
+
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     try sema.queueFullTypeResolution(elem_ty);
     if (is_ret) {
         _ = try block.addBinOp(.store, ptr, operand);
@@ -22644,7 +22685,7 @@ fn bitCast(
         const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
         return sema.addConstant(dest_ty, result_val);
     }
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     return block.addBitCast(dest_ty, inst);
 }
 
@@ -22727,7 +22768,7 @@ fn coerceArrayPtrToSlice(
         });
         return sema.addConstant(dest_ty, slice_val);
     }
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     return block.addTyOp(.array_to_slice, dest_ty, inst);
 }
 
@@ -22743,7 +22784,7 @@ fn coerceCompatiblePtrs(
         // The comptime Value representation is compatible with both types.
         return sema.addConstant(dest_ty, val);
     }
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     return sema.bitCast(block, dest_ty, inst, inst_src);
 }
 
@@ -22807,7 +22848,7 @@ fn coerceEnumToUnion(
         }));
     }
 
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
 
     if (tag_ty.isNonexhaustiveEnum()) {
         const msg = msg: {
@@ -22947,7 +22988,7 @@ fn coerceArrayLike(
             // These types share the same comptime value representation.
             return sema.addConstant(dest_ty, inst_val);
         }
-        try sema.requireRuntimeBlock(block, inst_src);
+        try sema.requireRuntimeBlock(block, inst_src, null);
         return block.addBitCast(dest_ty, inst);
     }
 
@@ -22960,8 +23001,9 @@ fn coerceArrayLike(
             Type.usize,
             try Value.Tag.int_u64.create(sema.arena, i),
         );
+        const src = inst_src; // TODO better source location
         const elem_src = inst_src; // TODO better source location
-        const elem_ref = try elemValArray(sema, block, inst_src, inst, elem_src, index_ref);
+        const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref);
         const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
         element_refs[i] = coerced;
         if (runtime_src == null) {
@@ -22974,7 +23016,7 @@ fn coerceArrayLike(
     }
 
     if (runtime_src) |rs| {
-        try sema.requireRuntimeBlock(block, rs);
+        try sema.requireRuntimeBlock(block, inst_src, rs);
         return block.addAggregateInit(dest_ty, element_refs);
     }
 
@@ -23037,7 +23079,7 @@ fn coerceTupleToArray(
     }
 
     if (runtime_src) |rs| {
-        try sema.requireRuntimeBlock(block, rs);
+        try sema.requireRuntimeBlock(block, inst_src, rs);
         return block.addAggregateInit(dest_ty, element_refs);
     }
 
@@ -23168,7 +23210,7 @@ fn coerceTupleToStruct(
     }
 
     if (runtime_src) |rs| {
-        try sema.requireRuntimeBlock(block, rs);
+        try sema.requireRuntimeBlock(block, inst_src, rs);
         return block.addAggregateInit(struct_ty, field_refs);
     }
 
@@ -23282,7 +23324,7 @@ fn analyzeRef(
         ));
     }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
     const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
         .pointee_type = operand_ty,
@@ -23326,10 +23368,12 @@ fn analyzeLoad(
         }
     }
 
-    const valid_rt = try sema.validateRunTimeType(block, src, elem_ty, false);
-    if (!valid_rt) return sema.failWithNeededComptime(block, src);
+    if (block.is_comptime) {
+        // TODO ideally this would tell why the block is comptime
+        return sema.fail(block, ptr_src, "cannot load runtime value in comptime block", .{});
+    }
 
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireFunctionBlock(block, src);
     return block.addTyOp(.load, elem_ty, ptr);
 }
 
@@ -23346,7 +23390,7 @@ fn analyzeSlicePtr(
         if (val.isUndef()) return sema.addConstUndef(result_ty);
         return sema.addConstant(result_ty, val.slicePtr());
     }
-    try sema.requireRuntimeBlock(block, slice_src);
+    try sema.requireRuntimeBlock(block, slice_src, null);
     return block.addTyOp(.slice_ptr, result_ty, slice);
 }
 
@@ -23362,7 +23406,7 @@ fn analyzeSliceLen(
         }
         return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     return block.addTyOp(.slice_len, Type.usize, slice_inst);
 }
 
@@ -23386,7 +23430,7 @@ fn analyzeIsNull(
             return Air.Inst.Ref.bool_false;
         }
     }
-    try sema.requireRuntimeBlock(block, src);
+    try sema.requireRuntimeBlock(block, src, null);
     const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
     return block.addUnOp(air_tag, operand);
 }
@@ -23476,7 +23520,7 @@ fn analyzeIsNonErr(
 ) CompileError!Air.Inst.Ref {
     const result = try sema.analyzeIsNonErrComptimeOnly(block, src, operand);
     if (result == .none) {
-        try sema.requireRuntimeBlock(block, src);
+        try sema.requireRuntimeBlock(block, src, null);
         return block.addUnOp(.is_non_err, operand);
     } else {
         return result;
@@ -23661,7 +23705,7 @@ fn analyzeSlice(
     const sentinel = s: {
         if (sentinel_opt != .none) {
             const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
-            break :s try sema.resolveConstValue(block, sentinel_src, casted);
+            break :s try sema.resolveConstValue(block, sentinel_src, casted, "slice sentinel must be comptime known");
         }
         // If we are slicing to the end of something that is sentinel-terminated
         // then the resulting slice type is also sentinel-terminated.
@@ -23738,7 +23782,14 @@ fn analyzeSlice(
         .size = .Slice,
     });
 
-    try sema.requireRuntimeBlock(block, src);
+    const runtime_src = if ((try sema.resolveMaybeUndefVal(block, ptr_src, ptr_or_slice)) == null)
+        ptr_src
+    else if ((try sema.resolveMaybeUndefVal(block, src, start)) == null)
+        start_src
+    else
+        end_src;
+
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     if (block.wantSafety()) {
         // requirement: slicing C ptr is non-null
         if (ptr_ptr_child_ty.isCPtr()) {
@@ -23846,7 +23897,7 @@ fn cmpNumeric(
     // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
     // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
     // of this function if we don't need to.
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
 
     // For floats, emit a float comparison instruction.
     const lhs_is_float = switch (lhs_ty_tag) {
@@ -24034,7 +24085,7 @@ fn cmpVector(
         }
     };
 
-    try sema.requireRuntimeBlock(block, runtime_src);
+    try sema.requireRuntimeBlock(block, src, runtime_src);
     const result_ty_inst = try sema.addType(result_ty);
     return block.addCmpVector(lhs, rhs, op, result_ty_inst);
 }
@@ -24050,7 +24101,7 @@ fn wrapOptional(
         return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val));
     }
 
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     return block.addTyOp(.wrap_optional, dest_ty, inst);
 }
 
@@ -24066,7 +24117,7 @@ fn wrapErrorUnionPayload(
     if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| {
         return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
     }
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     try sema.queueFullTypeResolution(dest_payload_ty);
     return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
 }
@@ -24122,7 +24173,7 @@ fn wrapErrorUnionSet(
         return sema.addConstant(dest_ty, val);
     }
 
-    try sema.requireRuntimeBlock(block, inst_src);
+    try sema.requireRuntimeBlock(block, inst_src, null);
     const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
     return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
 }
@@ -24140,7 +24191,7 @@ fn unionToTag(
     if (try sema.resolveMaybeUndefVal(block, un_src, un)) |un_val| {
         return sema.addConstant(enum_ty, un_val.unionTag());
     }
-    try sema.requireRuntimeBlock(block, un_src);
+    try sema.requireRuntimeBlock(block, un_src, null);
     return block.addTyOp(.get_union_tag, enum_ty, un);
 }
 
@@ -25311,7 +25362,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
                 const field = &struct_obj.fields.values()[i];
                 const coerced = try sema.coerce(&block_scope, field.ty, init, src);
                 const default_val = (try sema.resolveMaybeUndefVal(&block_scope, src, coerced)) orelse
-                    return sema.failWithNeededComptime(&block_scope, src);
+                    return sema.failWithNeededComptime(&block_scope, src, "struct field default value must be comptime known");
                 field.default_val = try default_val.copy(decl_arena_allocator);
             }
         }
@@ -25504,7 +25555,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
             if (tag_ref != .none) {
                 const tag_src = src; // TODO better source location
                 const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, tag_src);
-                const val = try sema.resolveConstValue(&block_scope, tag_src, coerced);
+                const val = try sema.resolveConstValue(&block_scope, tag_src, coerced, "enum tag value must be comptime known");
                 last_tag_val = val;
 
                 // This puts the memory into the union arena, not the enum arena, but
@@ -26247,7 +26298,7 @@ pub fn analyzeAddrspace(
     zir_ref: Zir.Inst.Ref,
     ctx: AddressSpaceContext,
 ) !std.builtin.AddressSpace {
-    const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref);
+    const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime known");
     const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
     const target = sema.mod.getTarget();
     const arch = target.cpu.arch;
test/cases/compile_errors/asm_at_compile_time.zig
@@ -14,5 +14,5 @@ fn doSomeAsm() void {
 // backend=llvm
 // target=native
 //
-// :6:5: error: unable to resolve comptime value
+// :6:5: error: unable to evalutate comptime expression
 // :2:14: note: called from here
test/cases/compile_errors/call method on bound fn referring to var instance.zig
@@ -17,4 +17,4 @@ fn bad(ok: bool) void {
 // target=native
 // backend=stage2
 //
-// :12:18: error: unable to resolve comptime value
+// :12:18: error: cannot load runtime value in comptime block
test/cases/compile_errors/int-float_conversion_to_comptime_int-float.zig
@@ -12,4 +12,6 @@ export fn bar() void {
 // target=native
 //
 // :3:35: error: unable to resolve comptime value
+// :3:35: note: value being casted to 'comptime_int' must be comptime known
 // :7:37: error: unable to resolve comptime value
+// :7:37: note: value being casted to 'comptime_float' must be comptime known
test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig
@@ -14,5 +14,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(a)); }
 // backend=stage2
 // target=native
 //
-// :6:26: error: unable to resolve comptime value
+// :6:26: error: cannot store to runtime value in comptime block
 // :4:17: note: called from here
test/cases/compile_errors/non-pure_function_returns_type.zig
@@ -21,5 +21,5 @@ export fn function_with_return_type_type() void {
 // backend=stage2
 // target=native
 //
-// :3:7: error: unable to resolve comptime value
+// :3:7: error: cannot load runtime value in comptime block
 // :16:19: note: called from here
test/cases/compile_errors/non_constant_expression_in_array_size.zig
@@ -10,5 +10,5 @@ export fn entry() usize { return @offsetOf(Foo, "y"); }
 // backend=stage2
 // target=native
 //
-// :5:25: error: unable to resolve comptime value
+// :5:25: error: cannot load runtime value in comptime block
 // :2:15: note: called from here
test/cases/x86_64-linux/assert_function.8.zig
@@ -22,3 +22,4 @@ pub fn assert(ok: bool) void {
 // error
 //
 // :3:21: error: unable to resolve comptime value
+// :3:21: note: condition in comptime branch must be comptime known
test/cases/extern_variable_has_no_type.0.zig
@@ -6,4 +6,4 @@ extern var foo: i32;
 
 // error
 //
-// :2:15: error: unable to resolve comptime value
+// :2:15: error: cannot load runtime value in comptime block
test/stage2/cbe.zig
@@ -51,8 +51,8 @@ pub fn addCases(ctx: *TestContext) !void {
             \\}
             \\var y: @import("std").builtin.CallingConvention = .C;
         , &.{
-            ":2:22: error: unable to resolve comptime value",
-            ":5:26: error: unable to resolve comptime value",
+            ":2:22: error: cannot load runtime value in comptime block",
+            ":5:26: error: cannot load runtime value in comptime block",
         });
     }