From 345e3d419eafb0e234aecb4a33f37efe2afbbf53 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sun, 18 Oct 2026 08:07:50 +0000 Subject: feat(classes): add copy constructors and statement-scoped temporaries Co-Authored-By: Claude Opus 5.5 --- AGENTS/CONVENTIONS.md | 2 +- AGENTS/PITFALLS.md | 4 +++- AGENTS/SUBSYSTEMS.md | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'AGENTS') diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index fa9f12a..b8ca3e9 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -162,7 +162,7 @@ builtin result types. Returns may be any supported function result, including non-BOOLEAN comparisons/logic. emitCoercedExpr rejects implicit STRING to BOOLEAN; CASE separately requires BOOLEAN comparisons. Operators use shared argument marshalling and exception-aware calls. Member lvalues keep their original address; -rvalues are materialized and registered for the existing function-scoped cleanup. +rvalues are materialized with Alive tracking and destroyed at statement end. **Parameter modes are sticky and BYREF is procedure-only (guide ยง8.3).** In `(BYREF a : T, b : T)` the `b` is BYREF too; unannotated parameters default to diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index 820fa55..4c72a4f 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -124,7 +124,7 @@ test programs. Explicit calls do not recurse into fields or affect Alive tracking. Keyword DELETE validates an active allocation start before destroying the object and its fields, then frees memory and leaves aliases dangling; FREE skips all destruction. - DECLARE storage and shallow BYVAL copies are destroyed in reverse declaration order + DECLARE storage and BYVAL copies are destroyed in reverse declaration order at normal function exit or when unwinding leaves the frame. Arrays reverse their flat element order. Repeated DECLARE destroys its previous incarnation first. Lifetimes are function-scoped, even for declarations inside blocks. NEW rebinding @@ -178,3 +178,5 @@ Linux. WHILE accepts both the standard header without DO and the older WHILE DO form. - **Literal escapes.** C++17 escapes are decoded by the lexer. Unicode escapes encode UTF-8 in strings; CHAR Unicode escapes must be ASCII. Built-in STRING remains NUL-terminated: `"a\0b"` is observed as `"a"`. + +- **Copy limits.** Classes may define a same-class BYREF copy constructor. Classes without one, whole TYPE records containing class fields, and BYVAL arrays still copy bits; owning handles inside these aggregate copies need explicit care. Class rvalues transfer ownership when consumed; discarded results and temporary receivers are destroyed at statement end. diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index be20bc3..427fc45 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -134,8 +134,7 @@ DELETE method calls remain ordinary calls without field recursion. Keyword DELET resolves a class lvalue, validates its allocation start through MemoryHandler before any destruction, destroys it, then releases it through FREE; aliases remain dangling. Stack lifetimes use a per-function `StackObjects` list saved/restored around function -emission. DECLARE and shallow BYVAL copies share registration (the copy point is -marked), including arrays and records with class fields. Each record retains the +emission. DECLARE and BYVAL copies share ownership registration, including arrays and records with class fields. Each record retains the original address, an entry-initialized Alive flag and, for arrays, a runtime element count in an entry slot. Array buffer addresses also live in entry slots so deferred cleanup never references branch-local bound SSA values. Repeated DECLARE destroys @@ -195,3 +194,5 @@ nothing is declared or emitted eagerly. Helper bodies are built with the *shared Builder (RuntimeCheck emits through the same one), saving/restoring the insert block. **Explicit memory** (`MemoryHandler`): lazily emits internal allocation/find/release/resize helpers and a linked list of live allocation start addresses. Explicit MALLOC/REALLOC and keyword NEW allocations enter the list; STRING/ARRAY internals retain their existing ownership. `emitValidate` always calls the find helper, including for null, so keyword DELETE validates before running destructors. FREE validates non-null addresses, unlinks and frees the tracking node, releases the block and returns the original address. Zero-byte allocation returns null. REALLOC validates non-null addresses before its zero-size release path; null behaves as MALLOC. Positive-size resizing updates the node only after success, leaving the old block and record intact on failure. Node allocation precedes the user allocation; if the latter fails, its node is freed before the diagnostic and anonymous throw. Helpers use RuntimeCheck and ExceptionHandler, including source-line arguments and per-function unwind preparation. Sizes accept INTEGER and C integers and convert to native size_t. Address reuse can make stale aliases indistinguishable from current allocations; dereferences are not checked against this list. + +**Class copies and temporaries.** Callers construct BYVAL class arguments with a same-class BYREF OVERLOAD NEW; the callee's RegisterCopy hook takes ownership. emitOwnedValue constructs lvalue copies and keeps pending arguments Alive until marshalling succeeds. RETURN copies lvalues and transfers rvalues. StackObject::Temporary uses statement cleanup and deferred temporary-only cleanup before local handlers, while ordinary objects remain function-scoped. Function-result method receivers are materialized by the same path as operator receivers. -- cgit v1.3.1-4-g156e