From c4565386553ea86308a9487650d2435804893ed0 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 15 Oct 2026 02:41:11 +0000 Subject: fix(codegen): restore runtime diagnostics before throwing Reuse historical runtime messages and source-line reporting for arithmetic, array, enum, pointer and file checks while preserving anonymous exceptions. Update the manuals and subsystem guidance to describe diagnostic output. Co-Authored-By: Claude Fable 5.1 --- lib/CodeGen/RuntimeCheck.cc | 50 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'lib/CodeGen/RuntimeCheck.cc') diff --git a/lib/CodeGen/RuntimeCheck.cc b/lib/CodeGen/RuntimeCheck.cc index 2954af0..215702e 100644 --- a/lib/CodeGen/RuntimeCheck.cc +++ b/lib/CodeGen/RuntimeCheck.cc @@ -8,16 +8,46 @@ using namespace llvm; using namespace cps; -RuntimeCheck::RuntimeCheck(LLVMContext &C, IRBuilder<> &B, ExceptionHandler &EH) - : TheContext(C), Builder(B), Exceptions(EH) {} +RuntimeCheck::RuntimeCheck(Module &M, LLVMContext &C, IRBuilder<> &B, ExceptionHandler &EH) + : TheModule(M), TheContext(C), Builder(B), Exceptions(EH) { + setupExternalFunctions(); +} + +void RuntimeCheck::setupExternalFunctions() { + std::vector PrintfArgs; + PrintfArgs.push_back(PointerType::getUnqual(TheContext)); + FunctionType *PrintfType = FunctionType::get(Type::getInt32Ty(TheContext), PrintfArgs, true); + PrintfFunc = TheModule.getOrInsertFunction("printf", PrintfType); + + DivZeroMsg = Builder.CreateGlobalString("[Fatal] line %d: Division by zero\n", "err_div_zero", 0, &TheModule); + OutOfBoundsMsg = Builder.CreateGlobalString("[Fatal] line %d: Array index out of bounds\n", "err_bounds", 0, &TheModule); + EnumRangeMsg = Builder.CreateGlobalString("[Fatal] line %d: Value out of range for enum %s\n", "err_enum_range", 0, &TheModule); + NullDerefMsg = Builder.CreateGlobalString("[Fatal] line %d: Dereference of an unset pointer\n", "err_null_deref", 0, &TheModule); + ArrayArgBoundsMsg = Builder.CreateGlobalString( + "[Fatal] line %d: Array argument bounds [%lld:%lld] do not match the declared parameter bounds [%lld:%lld]\n", + "err_arr_arg_bounds", 0, &TheModule); +} + +void RuntimeCheck::emitCheck(Value *Condition, Value *Msg, int Line) { + emitCheck(Condition, Msg, {ConstantInt::get(TheContext, APInt(32, Line))}); +} -void RuntimeCheck::emitCheck(Value *Condition) { +void RuntimeCheck::emitCheck(Value *Condition, Value *Msg, ArrayRef FmtArgs) { Function *TheFunction = Builder.GetInsertBlock()->getParent(); + BasicBlock *FailBB = BasicBlock::Create(TheContext, "check_fail", TheFunction); BasicBlock *ContBB = BasicBlock::Create(TheContext, "check_cont", TheFunction); + Builder.CreateCondBr(Condition, FailBB, ContBB); + Builder.SetInsertPoint(FailBB); + std::vector PrintArgs; + PrintArgs.push_back(Msg); + PrintArgs.insert(PrintArgs.end(), FmtArgs.begin(), FmtArgs.end()); + Builder.CreateCall(PrintfFunc, PrintArgs); + Exceptions.emitThrow(); + Builder.SetInsertPoint(ContBB); } @@ -28,7 +58,7 @@ void RuntimeCheck::emitDivZeroCheck(Value *Divisor, int Line) { } else { IsZero = Builder.CreateICmpEQ(Divisor, ConstantInt::get(Divisor->getType(), 0), "is_zero"); } - emitCheck(IsZero); + emitCheck(IsZero, DivZeroMsg, Line); } void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int Line) { @@ -36,7 +66,7 @@ void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int Value *TooHigh = Builder.CreateICmpSGT(Index, Upper, "too_high"); Value *OutOfBounds = Builder.CreateOr(TooLow, TooHigh, "out_of_bounds"); - emitCheck(OutOfBounds); + emitCheck(OutOfBounds, OutOfBoundsMsg, Line); } void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount, @@ -48,14 +78,16 @@ void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount, Value *TooHigh = Builder.CreateICmpSGE(Ordinal, Hi, "enum_too_high"); Value *OutOfRange = Builder.CreateOr(TooLow, TooHigh, "enum_out_of_range"); - emitCheck(OutOfRange); + Value *NameStr = Builder.CreateGlobalString(TypeName, "enum_name", 0, &TheModule); + emitCheck(OutOfRange, EnumRangeMsg, + {ConstantInt::get(TheContext, APInt(32, Line)), NameStr}); } void RuntimeCheck::emitNullDerefCheck(Value *Ptr, int Line) { Value *IsNull = Builder.CreateICmpEQ(Ptr, ConstantPointerNull::get(PointerType::getUnqual(TheContext)), "ptr_is_null"); - emitCheck(IsNull); + emitCheck(IsNull, NullDerefMsg, Line); } void RuntimeCheck::emitArrayArgBoundsCheck(Value *ActualLower, Value *ActualUpper, @@ -67,5 +99,7 @@ void RuntimeCheck::emitArrayArgBoundsCheck(Value *ActualLower, Value *ActualUppe Value *HiDiff = Builder.CreateICmpNE(ActualUpper, DeclHi, "arg_hi_ne"); Value *Mismatch = Builder.CreateOr(LoDiff, HiDiff, "arg_bounds_ne"); - emitCheck(Mismatch); + emitCheck(Mismatch, ArrayArgBoundsMsg, + {ConstantInt::get(TheContext, APInt(32, Line)), + ActualLower, ActualUpper, DeclLo, DeclHi}); } -- cgit v1.3.1-4-g156e