aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-20 12:01:45 +0000
committer_ov4 <ov4@ov4.org>2026-10-20 12:01:45 +0000
commitbe964b4df4db9f42e0b7d615c1cbfa6cf268e646 (patch)
treed9257871558ec123e4e8437921fe6ac7b8836164 /lib
parent62b605c6c0ea13e9763c0a0115464007b13a8831 (diff)
fix(strings): preserve enclosing class lifetimes during assignment
Copy owned string fields without reconstructing or destroying their containing class, and retain rvalue ownership transfers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/ConstructorGen.cc40
1 files changed, 38 insertions, 2 deletions
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc
index ec97fca..dfdfbb5 100644
--- a/lib/CodeGen/ConstructorGen.cc
+++ b/lib/CodeGen/ConstructorGen.cc
@@ -179,10 +179,46 @@ void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const Symb
}
}
if (Info && containsString(Info)) {
+ Value *Val = emitCoercedExpr(Expr, Info);
+ if (!Val) return;
std::vector<size_t> Transfers;
- Value *Val = emitOwnedValue(Expr, Info, Transfers);
+ bool CopySource = isObjectLValue(Expr);
+ if (!CopySource) {
+ materializeOperatorReceiver(Val, Info);
+ if (typeNeedsDestruction(Info->Name)) Transfers.push_back(StackObjects.size() - 1);
+ }
+ // Default aggregate assignment replaces fields without reconstructing
+ // the enclosing class or calling its DELETE method.
+ std::function<Value *(const TypeInfo *, Value *)> Clone =
+ [&](const TypeInfo *Type, Value *Value) -> llvm::Value * {
+ if (Type->isString()) {
+ auto *Source = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
+ Type->LLVMType, "assignment_source");
+ Builder->CreateStore(Value, Source);
+ return copyClassValue(Type, Source, Transfers);
+ }
+ for (const auto &[Name, Field] : Type->Record.Fields) {
+ const auto *FieldType = resolveType(Field.TypeName);
+ if (!containsString(FieldType)) continue;
+ auto *Copy = Clone(FieldType, Builder->CreateExtractValue(Value, {Field.Index}));
+ if (!Copy) return nullptr;
+ Value = Builder->CreateInsertValue(Value, Copy, {Field.Index});
+ }
+ return Value;
+ };
+ if (CopySource) Val = Clone(Info, Val);
if (!Val) return;
- if (!emitDestroy(Info->Name, Target.Addr, DiagnosticLine)) return;
+ std::function<bool(const TypeInfo *, Value *)> Release =
+ [&](const TypeInfo *Type, Value *Address) {
+ if (Type->isString()) return emitDestroy(Type->Name, Address, DiagnosticLine);
+ for (const auto &[Name, Field] : Type->Record.Fields) {
+ const auto *FieldType = resolveType(Field.TypeName);
+ if (containsString(FieldType) && !Release(FieldType,
+ Builder->CreateStructGEP(Type->LLVMType, Address, Field.Index))) return false;
+ }
+ return true;
+ };
+ if (!Release(Info, Target.Addr)) return;
Builder->CreateStore(Val, Target.Addr);
transferObjects(Transfers);
return;