[Clang] Improve CodeGenerator API a bit (#175239)

Essentially, figuring out how to use `CodeGenerator` was very confusing
to me and I figured the API could be improved a bit, so:
- the `CodeGenerator` ctor is now protected since an instance of
`CodeGenerator` that is not a `CodeGeneratorImpl` is a bit useless (and
deriving from it and implementing it yourself honestly just defeats the
point of using this to begin with);
- `ReleaseModule()` releases ownership of the module, so it should
return a `unique_ptr`;
- `CreateLLVMCodeGen()` also returns a `unique_ptr` now;
- added a `CreateLLVMCodeGen()` overload that takes a
`CompilerInstance&` and uses some of its state instead of requiring the
user to pass everything in manually; this is consistent w/ other parts
of our API, and most uses of this function in the codebase can be
refactored to use that overload instead (and a code search I did also
showed that a lot of people that use this API also just use the state
from a `CompilerInstance`).

I should have liked to replace `CreateLLVMCodeGen` w/
`CodeGenerator::Create`, but there are a lot of uses of
`CreateLLVMCodeGen()` in the wild, so the only thing we could do is keep
`CreateLLVMCodeGen()` and deprecate it, and at that point I don’t think
it’s really worth it; I added a comment to the `CodeGenerator()`
constructor declaration that points to it though.

Fixes #172169.
This commit is contained in:
Sirraide 2026-01-12 22:46:59 +01:00 committed by GitHub
parent a062249932
commit 62c97aa519
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 45 additions and 41 deletions

View File

@ -40,6 +40,7 @@ namespace clang {
class HeaderSearchOptions;
class LangOptions;
class PreprocessorOptions;
class CompilerInstance;
namespace CodeGen {
class CodeGenModule;
@ -47,12 +48,13 @@ namespace CodeGen {
}
/// The primary public interface to the Clang code generator.
///
/// This is not really an abstract interface.
class CodeGenerator : public ASTConsumer {
virtual void anchor();
protected:
/// Use CreateLLVMCodeGen() below to create an instance of this class.
CodeGenerator() = default;
/// True if we've finished generating IR. This prevents us from generating
/// additional LLVM IR after emitting output in HandleTranslationUnit. This
/// can happen when Clang plugins trigger additional AST deserialization.
@ -78,7 +80,7 @@ public:
///
/// It is illegal to call methods other than GetModule on the
/// CodeGenerator after releasing its module.
llvm::Module *ReleaseModule();
std::unique_ptr<llvm::Module> ReleaseModule();
/// Return debug info code generator.
CodeGen::CGDebugInfo *getCGDebugInfo();
@ -109,16 +111,20 @@ public:
};
/// CreateLLVMCodeGen - Create a CodeGenerator instance.
/// It is the responsibility of the caller to call delete on
/// the allocated CodeGenerator instance.
CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
///
/// Remember to call Initialize() if you plan to use this directly.
std::unique_ptr<CodeGenerator>
CreateLLVMCodeGen(const CompilerInstance &CI, llvm::StringRef ModuleName,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
std::unique_ptr<CodeGenerator>
CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO, llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
namespace CodeGen {
/// Demangle the artificial function name (\param FuncName) used to encode trap

View File

@ -118,9 +118,7 @@ BackendConsumer::BackendConsumer(CompilerInstance &CI, BackendAction Action,
: CI(CI), Diags(CI.getDiagnostics()), CodeGenOpts(CI.getCodeGenOpts()),
TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
AsmOutStream(std::move(OS)), FS(VFS), Action(Action),
Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
CI.getCodeGenOpts(), C, CoverageInfo)),
Gen(CreateLLVMCodeGen(CI, InFile, C, CoverageInfo)),
LinkModules(std::move(LinkModules)), CurLinkModule(CurLinkModule) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;

View File

@ -19,6 +19,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
@ -31,7 +32,7 @@ using namespace clang;
using namespace CodeGen;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
class CodeGeneratorImpl final : public CodeGenerator {
DiagnosticsEngine &Diags;
ASTContext *Ctx;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
@ -60,12 +61,8 @@ namespace {
};
CoverageSourceInfo *CoverageInfo;
protected:
std::unique_ptr<llvm::Module> M;
std::unique_ptr<CodeGen::CodeGenModule> Builder;
private:
SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
@ -107,8 +104,8 @@ namespace {
return Builder->getModuleDebugInfo();
}
llvm::Module *ReleaseModule() {
return M.release();
std::unique_ptr<llvm::Module> ReleaseModule() {
return std::exchange(M, nullptr);
}
const Decl *GetDeclForMangledName(StringRef MangledName) {
@ -143,6 +140,7 @@ namespace {
std::unique_ptr<CodeGenModule> OldBuilder = std::move(Builder);
assert(Ctx && "must call Initialize() before calling StartModule()");
Initialize(*Ctx);
if (OldBuilder)
@ -251,6 +249,7 @@ namespace {
// For MSVC compatibility, treat declarations of static data members with
// inline initializers as definitions.
assert(Ctx && "Initialize() not called");
if (Ctx->getTargetInfo().getCXXABI().isMicrosoft()) {
for (Decl *Member : D->decls()) {
if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
@ -341,7 +340,7 @@ llvm::Module *CodeGenerator::GetModule() {
return static_cast<CodeGeneratorImpl*>(this)->GetModule();
}
llvm::Module *CodeGenerator::ReleaseModule() {
std::unique_ptr<llvm::Module> CodeGenerator::ReleaseModule() {
return static_cast<CodeGeneratorImpl*>(this)->ReleaseModule();
}
@ -368,16 +367,26 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
}
CodeGenerator *
std::unique_ptr<CodeGenerator>
clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO, llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo) {
return new CodeGeneratorImpl(Diags, ModuleName, std::move(FS),
HeaderSearchOpts, PreprocessorOpts, CGO, C,
CoverageInfo);
return std::make_unique<CodeGeneratorImpl>(Diags, ModuleName, std::move(FS),
HeaderSearchOpts, PreprocessorOpts,
CGO, C, CoverageInfo);
}
std::unique_ptr<CodeGenerator>
clang::CreateLLVMCodeGen(const CompilerInstance &CI, StringRef ModuleName,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo) {
return CreateLLVMCodeGen(CI.getDiagnostics(), ModuleName,
CI.getVirtualFileSystemPtr(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
CI.getCodeGenOpts(), C, CoverageInfo);
}
namespace clang {

View File

@ -235,10 +235,7 @@ BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
llvm::LLVMContext &LLVMCtx) {
StringRef ModuleName("$__module");
return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
CI.getDiagnostics(), ModuleName, CI.getVirtualFileSystemPtr(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
LLVMCtx));
return CreateLLVMCodeGen(CI, ModuleName, LLVMCtx);
}
} // namespace init_convenience

View File

@ -57,10 +57,7 @@ struct TestCompiler {
compiler.createASTContext();
CG.reset(CreateLLVMCodeGen(
compiler.getDiagnostics(), "main-module",
compiler.getVirtualFileSystemPtr(), compiler.getHeaderSearchOpts(),
compiler.getPreprocessorOpts(), compiler.getCodeGenOpts(), Context));
CG = CreateLLVMCodeGen(compiler, "main-module", Context);
}
void init(const char *TestProgram,

View File

@ -880,11 +880,8 @@ ClangExpressionParser::ClangExpressionParser(
std::string module_name("$__lldb_module");
m_llvm_context = std::make_unique<LLVMContext>();
m_code_generator.reset(CreateLLVMCodeGen(
m_compiler->getDiagnostics(), module_name,
m_compiler->getVirtualFileSystemPtr(), m_compiler->getHeaderSearchOpts(),
m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(),
*m_llvm_context));
m_code_generator =
CreateLLVMCodeGen(*m_compiler, module_name, *m_llvm_context);
}
ClangExpressionParser::~ClangExpressionParser() = default;