aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/RuntimeCheck.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-07-26 17:32:24 +0000
committer_ov4 <ov4@ov4.org>2026-07-26 17:32:24 +0000
commitf19f1c956780f41f1440b372187770ce0be8efed (patch)
treefe0c2fe47a2cddb1bd8bd92206d47136bfcbfd37 /lib/CodeGen/RuntimeCheck.cc
parent3366a2e0fae05d9e792169e74471c7282bf18681 (diff)
feat: user type registry and enumerated types (CIE 4.1/4.2)
- TypeSystem: TypeKinds Enum/Record/Pointer with per-kind payloads and checked accessors; two-pass registration (names first, then definitions in source order) so pointer TYPEs may forward-reference; enum-constant table owned by TypeSystem so constants stay visible inside function bodies across the Symbols save/clear/restore. Dead surface removed (Custom kind, Printable/Builtin/ReferenceLike, ElementSize, hasType, CodeGen::getNamedValue/getLLVMType). - Enums are i64 with 0-based ordinals (constexpr kEnumOrdinalBase); all type identity is by NAME. New emitCoercedExpr is the single admission gate, replacing raw coercion at assignments, array stores, BYVAL args, RETURN, IF/WHILE/REPEAT/FOR operands, file operands and builtin args; coerceValueToType now hard-errors if a user-kind target reaches it. - Binary ops with user-kind operands are intercepted ahead of ArithmeticHandler ('&'-intercept precedent): same-enum comparisons, enum +/- INTEGER (with a runtime range check, [Fatal] on overflow, the only site that can manufacture an invalid ordinal), same-name pointer =/<>; everything else is a compile error naming the operator. - OUTPUT is an exhaustive switch over TypeKind (enum prints its ordinal; record/pointer are compile errors, also covering whole-array OUTPUT); INPUT's silent %lld fallback for unknown kinds is now an explicit error. - Enum value names are globally reserved: collisions with DECLARE, array names, parameters and function names are compile errors. - RuntimeCheck: emitEnumRangeCheck + emitNullDerefCheck (used by the pointer phase) following the emitIndexCheck recipe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/RuntimeCheck.cc')
-rw-r--r--lib/CodeGen/RuntimeCheck.cc26
1 files changed, 25 insertions, 1 deletions
diff --git a/lib/CodeGen/RuntimeCheck.cc b/lib/CodeGen/RuntimeCheck.cc
index c2ced87..e6d4bf8 100644
--- a/lib/CodeGen/RuntimeCheck.cc
+++ b/lib/CodeGen/RuntimeCheck.cc
@@ -1,4 +1,5 @@
#include "cps/RuntimeCheck.h"
+#include "cps/TypeSystem.h" // kEnumOrdinalBase
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Constants.h"
@@ -24,6 +25,8 @@ void RuntimeCheck::setupExternalFunctions() {
DivZeroMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Division by zero\n", "err_div_zero", 0, &TheModule);
OutOfBoundsMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Array index out of bounds\n", "err_bounds", 0, &TheModule);
+ EnumRangeMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Value out of range for enum %s\n", "err_enum_range", 0, &TheModule);
+ NullDerefMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Dereference of an unset pointer\n", "err_null_deref", 0, &TheModule);
}
void RuntimeCheck::emitErrorAndExit(Value *Condition, Value *Msg, int Line) {
@@ -59,6 +62,27 @@ void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int
Value *TooLow = Builder.CreateICmpSLT(Index, Lower, "too_low");
Value *TooHigh = Builder.CreateICmpSGT(Index, Upper, "too_high");
Value *OutOfBounds = Builder.CreateOr(TooLow, TooHigh, "out_of_bounds");
-
+
emitErrorAndExit(OutOfBounds, OutOfBoundsMsg, Line);
}
+
+void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount,
+ const std::string &TypeName, int Line) {
+ Value *Lo = ConstantInt::get(TheContext, APInt(64, static_cast<uint64_t>(kEnumOrdinalBase), true));
+ Value *Hi = ConstantInt::get(TheContext,
+ APInt(64, static_cast<uint64_t>(kEnumOrdinalBase) + ValueCount, true));
+ Value *TooLow = Builder.CreateICmpSLT(Ordinal, Lo, "enum_too_low");
+ Value *TooHigh = Builder.CreateICmpSGE(Ordinal, Hi, "enum_too_high");
+ Value *OutOfRange = Builder.CreateOr(TooLow, TooHigh, "enum_out_of_range");
+
+ Value *NameStr = Builder.CreateGlobalStringPtr(TypeName, "enum_name", 0, &TheModule);
+ emitErrorAndExit(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");
+ emitErrorAndExit(IsNull, NullDerefMsg, Line);
+}