diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 03:49:08 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 03:58:26 +0000 |
| commit | 5fdea7e2edd534d15eff95efb33336430d7b4872 (patch) | |
| tree | b5528d64124a8b9b299c10c9452e58d2cfbfcd6a | |
| parent | 1d2bb133b7a3540aeb81c5f9616cb366aebc919f (diff) | |
refactor(codegen): share record field default construction
copyClassValue, emitConstruct and emitStringFromCString each walked the
record fields and default-constructed those that need it. Move the loop
into a private emitFieldDefaults helper; each caller passes the same line
as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | include/cps/CodeGen.h | 1 | ||||
| -rw-r--r-- | lib/CodeGen/ConstructorGen.cc | 26 | ||||
| -rw-r--r-- | lib/CodeGen/StringValueGen.cc | 6 |
3 files changed, 15 insertions, 18 deletions
diff --git a/include/cps/CodeGen.h b/include/cps/CodeGen.h index 2d77284..7085560 100644 --- a/include/cps/CodeGen.h +++ b/include/cps/CodeGen.h @@ -90,6 +90,7 @@ class CodeGen { bool emitConstruct(const std::string &TypeName, llvm::Value *Addr, const std::vector<std::unique_ptr<ExprAST>> &Args, int Line); bool emitDefaultConstruct(const std::string &TypeName, llvm::Value *Addr, int Line); + bool emitFieldDefaults(const TypeInfo *Type, llvm::Value *Addr, int Line); struct StackObject { llvm::Value *Addr; std::string TypeName; diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc index 429138a..15d9300 100644 --- a/lib/CodeGen/ConstructorGen.cc +++ b/lib/CodeGen/ConstructorGen.cc @@ -73,12 +73,7 @@ Value *CodeGen::copyClassValue(const TypeInfo *Type, Value *Address, size_t Lifetime = registerStackObject(Storage, Type->Name, DiagnosticLine); if (Lifetime != size_t(-1)) StackObjects[Lifetime].Temporary = true; Builder->CreateStore(Types->getZeroValue(Type->Name), Storage); - for (const auto &[Name, Field] : Type->Record.Fields) { - if (typeNeedsConstruction(Field.TypeName) && - !emitDefaultConstruct(Field.TypeName, - Builder->CreateStructGEP(Type->LLVMType, Storage, Field.Index), DiagnosticLine)) - return nullptr; - } + if (!emitFieldDefaults(Type, Storage, DiagnosticLine)) return nullptr; if (!FuncGen->emitCall(*Copy, {Storage, Address})) return nullptr; activateStackObject(Lifetime); Transfers.push_back(Lifetime); @@ -109,13 +104,7 @@ bool CodeGen::emitConstruct(const std::string &TypeName, Value *Addr, SaveAndRestore<int> Location(DiagnosticLine, Line); const TypeInfo *Info = resolveType(TypeName); if (!Info) return false; - if (Info->asRecord()) { - for (const auto &[Name, Field] : Info->Record.Fields) { - if (!typeNeedsConstruction(Field.TypeName)) continue; - Value *FieldAddr = Builder->CreateStructGEP(Info->LLVMType, Addr, Field.Index); - if (!emitDefaultConstruct(Field.TypeName, FieldAddr, Line)) return false; - } - } + if (Info->asRecord() && !emitFieldDefaults(Info, Addr, Line)) return false; if (findMethod(TypeName, "NEW")) return emitMethodCall(TypeName, Addr, "NEW", Args, Line) != nullptr; if (!Args.empty()) { @@ -129,6 +118,17 @@ bool CodeGen::emitDefaultConstruct(const std::string &TypeName, Value *Addr, int return emitConstruct(TypeName, Addr, {}, Line); } +// Default-constructs, in declaration order, each field of the record at Addr +// that needs construction. +bool CodeGen::emitFieldDefaults(const TypeInfo *Type, Value *Addr, int Line) { + for (const auto &[Name, Field] : Type->Record.Fields) { + if (!typeNeedsConstruction(Field.TypeName)) continue; + Value *FieldAddr = Builder->CreateStructGEP(Type->LLVMType, Addr, Field.Index); + if (!emitDefaultConstruct(Field.TypeName, FieldAddr, Line)) return false; + } + return true; +} + Value *CodeGen::symbolAddress(const SymbolInfo &Info) { if (!Info.IsReference) return Info.Storage; return Builder->CreateLoad(PointerType::getUnqual(*TheContext), Info.Storage, "object_address"); diff --git a/lib/CodeGen/StringValueGen.cc b/lib/CodeGen/StringValueGen.cc index ce9694c..c07f9a9 100644 --- a/lib/CodeGen/StringValueGen.cc +++ b/lib/CodeGen/StringValueGen.cc @@ -29,11 +29,7 @@ Value *CodeGen::emitStringFromCString(Value *Text) { auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), Type->LLVMType, "string_value"); Builder->CreateStore(Types->getZeroValue(Type->Name), Storage); - for (const auto &[Name, Field] : Type->Record.Fields) - if (typeNeedsConstruction(Field.TypeName) && - !emitDefaultConstruct(Field.TypeName, - Builder->CreateStructGEP(Type->LLVMType, Storage, Field.Index), DiagnosticLine)) - return nullptr; + if (!emitFieldDefaults(Type, Storage, DiagnosticLine)) return nullptr; if (!FuncGen->emitCall(*Constructor, {Storage, Text})) return nullptr; // The consumer takes ownership, just as with an ordinary class result. return Builder->CreateLoad(Type->LLVMType, Storage, "string"); |
