Commit 6bf193af19

Andrew Kelley <andrew@ziglang.org>
2019-06-15 18:28:21
better result location semantics with optionals and return locations
somewhere along this branch, #1901 has been fixed.
1 parent 60025a3
src/all_types.hpp
@@ -2257,7 +2257,8 @@ enum IrInstructionId {
     IrInstructionIdHandle,
     IrInstructionIdAlignOf,
     IrInstructionIdOverflowOp,
-    IrInstructionIdTestErr,
+    IrInstructionIdTestErrSrc,
+    IrInstructionIdTestErrGen,
     IrInstructionIdUnwrapErrCode,
     IrInstructionIdUnwrapErrPayload,
     IrInstructionIdErrWrapCode,
@@ -2292,6 +2293,7 @@ enum IrInstructionId {
     IrInstructionIdAlignCast,
     IrInstructionIdImplicitCast,
     IrInstructionIdResolveResult,
+    IrInstructionIdResultPtr,
     IrInstructionIdOpaqueType,
     IrInstructionIdSetAlignStack,
     IrInstructionIdArgType,
@@ -3082,10 +3084,16 @@ struct IrInstructionAlignOf {
 };
 
 // returns true if error, returns false if not error
-struct IrInstructionTestErr {
+struct IrInstructionTestErrSrc {
     IrInstruction base;
 
-    IrInstruction *value;
+    IrInstruction *base_ptr;
+};
+
+struct IrInstructionTestErrGen {
+    IrInstruction base;
+
+    IrInstruction *err_union;
 };
 
 // Takes an error union pointer, returns a pointer to the error code.
@@ -3596,6 +3604,7 @@ struct IrInstructionImplicitCast {
     ResultLoc *result_loc;
 };
 
+// This one is for writing through the result pointer.
 struct IrInstructionResolveResult {
     IrInstruction base;
 
@@ -3603,6 +3612,15 @@ struct IrInstructionResolveResult {
     IrInstruction *ty;
 };
 
+// This one is when you want to read the value of the result.
+// You have to give the value in case it is comptime.
+struct IrInstructionResultPtr {
+    IrInstruction base;
+
+    ResultLoc *result_loc;
+    IrInstruction *result;
+};
+
 struct IrInstructionPtrOfArrayToSlice {
     IrInstruction base;
 
src/codegen.cpp
@@ -1323,7 +1323,9 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
     LLVMBuildRetVoid(g->builder);
 
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     g->add_error_return_trace_addr_fn_val = fn_val;
     return fn_val;
@@ -1454,7 +1456,9 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
     LLVMBuildBr(g->builder, loop_block);
 
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     g->merge_err_ret_traces_fn_val = fn_val;
     return fn_val;
@@ -1510,7 +1514,9 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
     LLVMBuildRetVoid(g->builder);
 
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     g->return_err_fn = fn_val;
     return fn_val;
@@ -1638,7 +1644,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
     gen_panic(g, msg_slice, err_ret_trace_arg);
 
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     g->safety_crash_err_fn = fn_val;
     return fn_val;
@@ -4353,7 +4361,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
     g->cur_fn = prev_cur_fn;
     g->cur_fn_val = prev_cur_fn_val;
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     enum_type->data.enumeration.name_function = fn_val;
     return fn_val;
@@ -4880,10 +4890,10 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
     return overflow_bit;
 }
 
-static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
-    ZigType *err_union_type = instruction->value->value.type;
+static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErrGen *instruction) {
+    ZigType *err_union_type = instruction->err_union->value.type;
     ZigType *payload_type = err_union_type->data.error_union.payload_type;
-    LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
+    LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union);
 
     LLVMValueRef err_val;
     if (type_has_bits(payload_type)) {
@@ -5276,7 +5286,9 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
     g->cur_fn = prev_cur_fn;
     g->cur_fn_val = prev_cur_fn_val;
     LLVMPositionBuilderAtEnd(g->builder, prev_block);
-    LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    if (!g->strip_debug_symbols) {
+        LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
+    }
 
     g->coro_alloc_helper_fn_val = fn_val;
     return fn_val;
@@ -5549,10 +5561,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdAllocaGen:
         case IrInstructionIdImplicitCast:
         case IrInstructionIdResolveResult:
+        case IrInstructionIdResultPtr:
         case IrInstructionIdContainerInitList:
         case IrInstructionIdSliceSrc:
         case IrInstructionIdRef:
         case IrInstructionIdBitCastSrc:
+        case IrInstructionIdTestErrSrc:
             zig_unreachable();
 
         case IrInstructionIdDeclVarGen:
@@ -5635,8 +5649,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
         case IrInstructionIdOverflowOp:
             return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
-        case IrInstructionIdTestErr:
-            return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction);
+        case IrInstructionIdTestErrGen:
+            return ir_render_test_err(g, executable, (IrInstructionTestErrGen *)instruction);
         case IrInstructionIdUnwrapErrCode:
             return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
         case IrInstructionIdUnwrapErrPayload:
src/ir.cpp
@@ -756,8 +756,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) {
     return IrInstructionIdOverflowOp;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) {
-    return IrInstructionIdTestErr;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrSrc *) {
+    return IrInstructionIdTestErrSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) {
+    return IrInstructionIdTestErrGen;
 }
 
 static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {
@@ -900,6 +904,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *)
     return IrInstructionIdResolveResult;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) {
+    return IrInstructionIdResultPtr;
+}
+
 static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
     return IrInstructionIdPtrOfArrayToSlice;
 }
@@ -2418,13 +2426,26 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *source_node,
-    IrInstruction *value)
+static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+    IrInstruction *base_ptr)
 {
-    IrInstructionTestErr *instruction = ir_build_instruction<IrInstructionTestErr>(irb, scope, source_node);
-    instruction->value = value;
+    IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);
+    instruction->base_ptr = base_ptr;
 
-    ir_ref_instruction(value, irb->current_basic_block);
+    ir_ref_instruction(base_ptr, irb->current_basic_block);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_test_err_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+    IrInstruction *err_union)
+{
+    IrInstructionTestErrGen *instruction = ir_build_instruction<IrInstructionTestErrGen>(
+            &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+    instruction->base.value.type = ira->codegen->builtin_types.entry_bool;
+    instruction->err_union = err_union;
+
+    ir_ref_instruction(err_union, ira->new_irb.current_basic_block);
 
     return &instruction->base;
 }
@@ -2844,6 +2865,18 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        ResultLoc *result_loc, IrInstruction *result)
+{
+    IrInstructionResultPtr *instruction = ir_build_instruction<IrInstructionResultPtr>(irb, scope, source_node);
+    instruction->result_loc = result_loc;
+    instruction->result = result;
+
+    ir_ref_instruction(result, irb->current_basic_block);
+
+    return &instruction->base;
+}
+
 static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
 
@@ -3531,7 +3564,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
                         ir_gen_defers_for_block(irb, scope, outer_scope, false);
                     }
 
-                    IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
+                    IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base,
+                            return_value);
+                    IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr);
 
                     bool should_inline = ir_should_inline(irb->exec, scope);
                     IrInstruction *is_comptime;
@@ -3577,8 +3612,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
                 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
                 if (err_union_ptr == irb->codegen->invalid_instruction)
                     return irb->codegen->invalid_instruction;
-                IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
-                IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
+                IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr);
 
                 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
                 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
@@ -5940,8 +5974,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
                 LValPtr, nullptr);
         if (err_val_ptr == irb->codegen->invalid_instruction)
             return err_val_ptr;
-        IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
-        IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
+        IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr);
         IrBasicBlock *after_cond_block = irb->current_basic_block;
         IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
         IrInstruction *cond_br_inst;
@@ -6722,7 +6755,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
         return err_val_ptr;
 
     IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
-    IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
+    IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr);
 
     IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
     IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
@@ -7330,8 +7363,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
     if (err_union_ptr == irb->codegen->invalid_instruction)
         return irb->codegen->invalid_instruction;
 
-    IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
-    IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
+    IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr);
 
     IrInstruction *is_comptime;
     if (ir_should_inline(irb->exec, parent_scope)) {
@@ -15010,7 +15042,9 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s
         return result_loc;
     ir_assert(result_loc->value.type->id == ZigTypeIdPointer, suspend_source_instr);
     ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type;
-    if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) {
+    if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional &&
+            value_type->id != ZigTypeIdNull)
+    {
         return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, result_loc, false, true);
     } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion) {
         if (value_type->id == ZigTypeIdErrorSet) {
@@ -22190,15 +22224,34 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
     return result;
 }
 
-static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) {
-    IrInstruction *value = instruction->value->child;
-    if (type_is_invalid(value->value.type))
+static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstructionResultPtr *instruction) {
+    IrInstruction *result = instruction->result->child;
+    if (type_is_invalid(result->value.type))
+        return result;
+
+    if (instruction->result_loc->written && instruction->result_loc->resolved_loc != nullptr &&
+            !instr_is_comptime(result))
+    {
+        IrInstruction *result_ptr = instruction->result_loc->resolved_loc;
+        // Convert the pointer to the result type. They should be the same, except this will resolve
+        // inferred error sets.
+        ZigType *new_ptr_type = get_pointer_to_type(ira->codegen, result->value.type, true);
+        return ir_analyze_ptr_cast(ira, &instruction->base, result_ptr, new_ptr_type, &instruction->base, false);
+    }
+    return ir_get_ref(ira, &instruction->base, result, true, false);
+}
+
+static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) {
+    IrInstruction *base_ptr = instruction->base_ptr->child;
+    if (type_is_invalid(base_ptr->value.type))
         return ira->codegen->invalid_instruction;
 
+    IrInstruction *value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr);
     ZigType *type_entry = value->value.type;
-    if (type_is_invalid(type_entry)) {
+    if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    } else if (type_entry->id == ZigTypeIdErrorUnion) {
+
+    if (type_entry->id == ZigTypeIdErrorUnion) {
         if (instr_is_comptime(value)) {
             ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
             if (!err_union_val)
@@ -22221,10 +22274,7 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
             return ir_const_bool(ira, &instruction->base, false);
         }
 
-        IrInstruction *result = ir_build_test_err(&ira->new_irb,
-            instruction->base.scope, instruction->base.source_node, value);
-        result->value.type = ira->codegen->builtin_types.entry_bool;
-        return result;
+        return ir_build_test_err_gen(ira, &instruction->base, value);
     } else if (type_entry->id == ZigTypeIdErrorSet) {
         return ir_const_bool(ira, &instruction->base, true);
     } else {
@@ -24343,6 +24393,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
         case IrInstructionIdAllocaGen:
         case IrInstructionIdSliceGen:
         case IrInstructionIdRefGen:
+        case IrInstructionIdTestErrGen:
             zig_unreachable();
 
         case IrInstructionIdReturn:
@@ -24497,8 +24548,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
             return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
         case IrInstructionIdOverflowOp:
             return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction);
-        case IrInstructionIdTestErr:
-            return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction);
+        case IrInstructionIdTestErrSrc:
+            return ir_analyze_instruction_test_err(ira, (IrInstructionTestErrSrc *)instruction);
         case IrInstructionIdUnwrapErrCode:
             return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);
         case IrInstructionIdUnwrapErrPayload:
@@ -24543,6 +24594,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
             return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction);
         case IrInstructionIdResolveResult:
             return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);
+        case IrInstructionIdResultPtr:
+            return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction);
         case IrInstructionIdOpaqueType:
             return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
         case IrInstructionIdSetAlignStack:
@@ -24672,6 +24725,9 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
             continue;
         }
 
+        if (ira->codegen->verbose_ir) {
+            fprintf(stderr, "analyze #%zu\n", old_instruction->debug_id);
+        }
         IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction);
         if (new_instruction != nullptr) {
             ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction);
@@ -24808,7 +24864,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdReturnAddress:
         case IrInstructionIdFrameAddress:
         case IrInstructionIdHandle:
-        case IrInstructionIdTestErr:
+        case IrInstructionIdTestErrSrc:
+        case IrInstructionIdTestErrGen:
         case IrInstructionIdFnProto:
         case IrInstructionIdTestComptime:
         case IrInstructionIdPtrCastSrc:
@@ -24860,6 +24917,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdHasDecl:
         case IrInstructionIdAllocaSrc:
         case IrInstructionIdAllocaGen:
+        case IrInstructionIdResultPtr:
             return false;
 
         case IrInstructionIdAsm:
src/ir_print.cpp
@@ -961,9 +961,15 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct
     fprintf(irp->f, ")");
 }
 
-static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
+static void ir_print_test_err_src(IrPrint *irp, IrInstructionTestErrSrc *instruction) {
     fprintf(irp->f, "@testError(");
-    ir_print_other_instruction(irp, instruction->value);
+    ir_print_other_instruction(irp, instruction->base_ptr);
+    fprintf(irp->f, ")");
+}
+
+static void ir_print_test_err_gen(IrPrint *irp, IrInstructionTestErrGen *instruction) {
+    fprintf(irp->f, "@testError(");
+    ir_print_other_instruction(irp, instruction->err_union);
     fprintf(irp->f, ")");
 }
 
@@ -976,10 +982,7 @@ static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *i
 static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
     fprintf(irp->f, "ErrorUnionFieldPayload(");
     ir_print_other_instruction(irp, instruction->value);
-    fprintf(irp->f, ")");
-    if (!instruction->safety_check_on) {
-        fprintf(irp->f, " // no safety");
-    }
+    fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing);
 }
 
 static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
@@ -1301,6 +1304,14 @@ static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *in
     fprintf(irp->f, ")");
 }
 
+static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) {
+    fprintf(irp->f, "ResultPtr(");
+    ir_print_result_loc(irp, instruction->result_loc);
+    fprintf(irp->f, ",");
+    ir_print_other_instruction(irp, instruction->result);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
     fprintf(irp->f, "@OpaqueType()");
 }
@@ -1837,8 +1848,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdOverflowOp:
             ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction);
             break;
-        case IrInstructionIdTestErr:
-            ir_print_test_err(irp, (IrInstructionTestErr *)instruction);
+        case IrInstructionIdTestErrSrc:
+            ir_print_test_err_src(irp, (IrInstructionTestErrSrc *)instruction);
+            break;
+        case IrInstructionIdTestErrGen:
+            ir_print_test_err_gen(irp, (IrInstructionTestErrGen *)instruction);
             break;
         case IrInstructionIdUnwrapErrCode:
             ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction);
@@ -1939,6 +1953,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdResolveResult:
             ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction);
             break;
+        case IrInstructionIdResultPtr:
+            ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
+            break;
         case IrInstructionIdOpaqueType:
             ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
             break;
std/special/panic.zig
@@ -7,8 +7,23 @@ const builtin = @import("builtin");
 const std = @import("std");
 
 pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
-    const stderr = std.io.getStdErr() catch std.process.abort();
-    stderr.write("panic: ") catch std.process.abort();
-    stderr.write(msg) catch std.process.abort();
-    std.process.abort();
+    @setCold(true);
+    switch (builtin.os) {
+        .freestanding => {
+            while (true) {}
+        },
+        .wasi => {
+            std.debug.warn("{}", msg);
+            _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT);
+            unreachable;
+        },
+        .uefi => {
+            // TODO look into using the debug info and logging helpful messages
+            std.os.abort();
+        },
+        else => {
+            const first_trace_addr = @returnAddress();
+            std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
+        },
+    }
 }
std/special/test_runner.zig
@@ -2,34 +2,28 @@ const std = @import("std");
 const io = std.io;
 const builtin = @import("builtin");
 const test_fn_list = builtin.test_functions;
+const warn = std.debug.warn;
 
-pub fn main() void {
-    const stderr = io.getStdErr() catch std.process.abort();
-
+pub fn main() !void {
     var ok_count: usize = 0;
     var skip_count: usize = 0;
     for (test_fn_list) |test_fn, i| {
-        stderr.write("test ") catch std.process.abort();
-        stderr.write(test_fn.name) catch std.process.abort();
+        warn("{}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
 
         if (test_fn.func()) |_| {
             ok_count += 1;
-            stderr.write("...OK\n") catch std.process.abort();
+            warn("OK\n");
         } else |err| switch (err) {
             error.SkipZigTest => {
                 skip_count += 1;
-                stderr.write("...SKIP\n") catch std.process.abort();
-            },
-            else => {
-                stderr.write("error: ") catch std.process.abort();
-                stderr.write(@errorName(err)) catch std.process.abort();
-                std.process.abort();
+                warn("SKIP\n");
             },
+            else => return err,
         }
     }
     if (ok_count == test_fn_list.len) {
-        stderr.write("All tests passed.\n") catch std.process.abort();
+        warn("All tests passed.\n");
     } else {
-        stderr.write("Some tests skipped.\n") catch std.process.abort();
+        warn("{} passed; {} skipped.\n", ok_count, skip_count);
     }
 }
std/os.zig
@@ -2487,7 +2487,7 @@ pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
 /// if this happens the fix is to add the error code to the corresponding
 /// switch expression, possibly introduce a new error in the error set, and
 /// send a patch to Zig.
-pub const unexpected_error_tracing = false;
+pub const unexpected_error_tracing = builtin.mode == .Debug;
 
 pub const UnexpectedError = error{
     /// The Operating System returned an undocumented error code.
test/stage1/behavior/cast.zig
@@ -124,14 +124,14 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
     return null;
 }
 
-//test "peer type resolution: ?T and T" {
-//    expect(peerTypeTAndOptionalT(true, false).? == 0);
-//    expect(peerTypeTAndOptionalT(false, false).? == 3);
-//    comptime {
-//        expect(peerTypeTAndOptionalT(true, false).? == 0);
-//        expect(peerTypeTAndOptionalT(false, false).? == 3);
-//    }
-//}
+test "peer type resolution: ?T and T" {
+    expect(peerTypeTAndOptionalT(true, false).? == 0);
+    expect(peerTypeTAndOptionalT(false, false).? == 3);
+    comptime {
+        expect(peerTypeTAndOptionalT(true, false).? == 0);
+        expect(peerTypeTAndOptionalT(false, false).? == 3);
+    }
+}
 fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
     if (c) {
         return if (b) null else usize(0);
test/stage1/behavior/error.zig
@@ -249,48 +249,48 @@ fn intLiteral(str: []const u8) !?i64 {
     return error.T;
 }
 
-test "nested error union function call in optional unwrap" {
-    const S = struct {
-        const Foo = struct {
-            a: i32,
-        };
-
-        fn errorable() !i32 {
-            var x: Foo = (try getFoo()) orelse return error.Other;
-            return x.a;
-        }
-
-        fn errorable2() !i32 {
-            var x: Foo = (try getFoo2()) orelse return error.Other;
-            return x.a;
-        }
-
-        fn errorable3() !i32 {
-            var x: Foo = (try getFoo3()) orelse return error.Other;
-            return x.a;
-        }
-
-        fn getFoo() anyerror!?Foo {
-            return Foo{ .a = 1234 };
-        }
-
-        fn getFoo2() anyerror!?Foo {
-            return error.Failure;
-        }
-
-        fn getFoo3() anyerror!?Foo {
-            return null;
-        }
-    };
-    expect((try S.errorable()) == 1234);
-    expectError(error.Failure, S.errorable2());
-    expectError(error.Other, S.errorable3());
-    comptime {
-        expect((try S.errorable()) == 1234);
-        expectError(error.Failure, S.errorable2());
-        expectError(error.Other, S.errorable3());
-    }
-}
+//test "nested error union function call in optional unwrap" {
+//    const S = struct {
+//        const Foo = struct {
+//            a: i32,
+//        };
+//
+//        fn errorable() !i32 {
+//            var x: Foo = (try getFoo()) orelse return error.Other;
+//            return x.a;
+//        }
+//
+//        fn errorable2() !i32 {
+//            var x: Foo = (try getFoo2()) orelse return error.Other;
+//            return x.a;
+//        }
+//
+//        fn errorable3() !i32 {
+//            var x: Foo = (try getFoo3()) orelse return error.Other;
+//            return x.a;
+//        }
+//
+//        fn getFoo() anyerror!?Foo {
+//            return Foo{ .a = 1234 };
+//        }
+//
+//        fn getFoo2() anyerror!?Foo {
+//            return error.Failure;
+//        }
+//
+//        fn getFoo3() anyerror!?Foo {
+//            return null;
+//        }
+//    };
+//    expect((try S.errorable()) == 1234);
+//    expectError(error.Failure, S.errorable2());
+//    expectError(error.Other, S.errorable3());
+//    comptime {
+//        expect((try S.errorable()) == 1234);
+//        expectError(error.Failure, S.errorable2());
+//        expectError(error.Other, S.errorable3());
+//    }
+//}
 
 test "widen cast integer payload of error union function call" {
     const S = struct {
test/stage1/behavior/generics.zig
@@ -80,19 +80,19 @@ test "function with return type type" {
     expect(list2.prealloc_items.len == 8);
 }
 
-//test "generic struct" {
-//    var a1 = GenNode(i32){
-//        .value = 13,
-//        .next = null,
-//    };
-//    var b1 = GenNode(bool){
-//        .value = true,
-//        .next = null,
-//    };
-//    expect(a1.value == 13);
-//    expect(a1.value == a1.getVal());
-//    expect(b1.getVal());
-//}
+test "generic struct" {
+    var a1 = GenNode(i32){
+        .value = 13,
+        .next = null,
+    };
+    var b1 = GenNode(bool){
+        .value = true,
+        .next = null,
+    };
+    expect(a1.value == 13);
+    expect(a1.value == a1.getVal());
+    expect(b1.getVal());
+}
 fn GenNode(comptime T: type) type {
     return struct {
         value: T,
test/stage1/behavior/optional.zig
@@ -76,6 +76,5 @@ test "unwrap function call with optional pointer return value" {
         }
     };
     S.entry();
-    // TODO https://github.com/ziglang/zig/issues/1901
-    //comptime S.entry();
+    comptime S.entry();
 }
test/stage1/behavior/while.zig
@@ -82,28 +82,28 @@ test "while with else" {
     expect(got_else == 1);
 }
 
-//test "while with optional as condition" {
-//    numbers_left = 10;
-//    var sum: i32 = 0;
-//    while (getNumberOrNull()) |value| {
-//        sum += value;
-//    }
-//    expect(sum == 45);
-//}
-//
-//test "while with optional as condition with else" {
-//    numbers_left = 10;
-//    var sum: i32 = 0;
-//    var got_else: i32 = 0;
-//    while (getNumberOrNull()) |value| {
-//        sum += value;
-//        expect(got_else == 0);
-//    } else {
-//        got_else += 1;
-//    }
-//    expect(sum == 45);
-//    expect(got_else == 1);
-//}
+test "while with optional as condition" {
+    numbers_left = 10;
+    var sum: i32 = 0;
+    while (getNumberOrNull()) |value| {
+        sum += value;
+    }
+    expect(sum == 45);
+}
+
+test "while with optional as condition with else" {
+    numbers_left = 10;
+    var sum: i32 = 0;
+    var got_else: i32 = 0;
+    while (getNumberOrNull()) |value| {
+        sum += value;
+        expect(got_else == 0);
+    } else {
+        got_else += 1;
+    }
+    expect(sum == 45);
+    expect(got_else == 1);
+}
 
 test "while with error union condition" {
     numbers_left = 10;
test/stage1/behavior.zig
@@ -40,46 +40,46 @@ comptime {
     //_ = @import("behavior/bugs/920.zig");
     _ = @import("behavior/byval_arg_var.zig");
     //_ = @import("behavior/cancel.zig");
-    _ = @import("behavior/cast.zig"); // TODO
+    _ = @import("behavior/cast.zig");
     _ = @import("behavior/const_slice_child.zig");
     //_ = @import("behavior/coroutine_await_struct.zig");
     //_ = @import("behavior/coroutines.zig");
     _ = @import("behavior/defer.zig");
     _ = @import("behavior/enum.zig");
     _ = @import("behavior/enum_with_members.zig");
-    //_ = @import("behavior/error.zig");
+    _ = @import("behavior/error.zig"); // TODO
     _ = @import("behavior/eval.zig"); // TODO
     _ = @import("behavior/field_parent_ptr.zig");
     _ = @import("behavior/fn.zig");
     _ = @import("behavior/fn_in_struct_in_comptime.zig");
     _ = @import("behavior/for.zig");
-    _ = @import("behavior/generics.zig"); // TODO
+    _ = @import("behavior/generics.zig");
     _ = @import("behavior/hasdecl.zig");
     _ = @import("behavior/if.zig");
-    //_ = @import("behavior/import.zig");
+    _ = @import("behavior/import.zig");
     _ = @import("behavior/incomplete_struct_param_tld.zig");
     _ = @import("behavior/inttoptr.zig");
     _ = @import("behavior/ir_block_deps.zig");
-    //_ = @import("behavior/math.zig");
+    _ = @import("behavior/math.zig");
     _ = @import("behavior/merge_error_sets.zig");
     _ = @import("behavior/misc.zig"); // TODO
     _ = @import("behavior/namespace_depends_on_compile_var.zig");
     _ = @import("behavior/new_stack_call.zig");
     _ = @import("behavior/null.zig");
     _ = @import("behavior/optional.zig"); // TODO
-    //_ = @import("behavior/pointers.zig");
+    _ = @import("behavior/pointers.zig");
     _ = @import("behavior/popcount.zig");
     _ = @import("behavior/ptrcast.zig"); // TODO
     _ = @import("behavior/pub_enum.zig");
     _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
     _ = @import("behavior/reflection.zig");
     _ = @import("behavior/sizeof_and_typeof.zig");
-    //_ = @import("behavior/slice.zig");
+    _ = @import("behavior/slice.zig");
     _ = @import("behavior/slicetobytes.zig");
     //_ = @import("behavior/struct.zig");
     _ = @import("behavior/struct_contains_null_ptr_itself.zig");
     _ = @import("behavior/struct_contains_slice_of_itself.zig");
-    //_ = @import("behavior/switch.zig");
+    _ = @import("behavior/switch.zig");
     //_ = @import("behavior/switch_prong_err_enum.zig");
     _ = @import("behavior/switch_prong_implicit_cast.zig");
     _ = @import("behavior/syntax.zig");
@@ -87,7 +87,7 @@ comptime {
     _ = @import("behavior/truncate.zig");
     _ = @import("behavior/try.zig");
     _ = @import("behavior/type_info.zig");
-    //_ = @import("behavior/typename.zig");
+    _ = @import("behavior/typename.zig");
     _ = @import("behavior/undefined.zig");
     _ = @import("behavior/underscore.zig");
     _ = @import("behavior/union.zig");
BRANCH_TODO
@@ -4,10 +4,7 @@ Scratch pad for stuff to do before merging master
 uncomment all the behavior tests
 diff master branch to make sure
 
-restore test_runner.zig to master branch
- - also the default panic function and unexpected_error_tracing. see the commit
-   that adds this text to BRANCH_TODO file.
- - and std/specia/bootstrap.zig
+restore bootstrap.zig to master
 
 get an empty file compiling successfully (with no panic fn override)