Skip to content

Conversation

@Sirraide
Copy link
Member

@Sirraide Sirraide commented Jan 9, 2026

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.

clang-format is definitely going to complain because the indentation in ModuleBuilder.cpp is all wrong, but I don’t think we should just reformat that file. A release note for this might be nice, but I’m not sure what section it should go in (if we want one at all)

Fixes #172169.

@Sirraide Sirraide requested a review from AaronBallman January 9, 2026 20:34
@Sirraide Sirraide requested a review from JDevlieghere as a code owner January 9, 2026 20:34
@Sirraide Sirraide added the clang:as-a-library libclang and C++ API label Jan 9, 2026
@llvmbot llvmbot added lldb clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jan 9, 2026
@llvmbot
Copy link
Member

llvmbot commented Jan 9, 2026

@llvm/pr-subscribers-lldb

Author: None (Sirraide)

Changes

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.

clang-format is definitely going to complain because the indentation in ModuleBuilder.cpp is all wrong, but I don’t think we should just reformat that file. A release note for this might be nice, but I’m not sure what section it should go in (if we want one at all)

Fixes #172169.


Full diff: https://github.com/llvm/llvm-project/pull/175239.diff

6 Files Affected:

  • (modified) clang/include/clang/CodeGen/ModuleBuilder.h (+19-13)
  • (modified) clang/lib/CodeGen/CodeGenAction.cpp (+1-3)
  • (modified) clang/lib/CodeGen/ModuleBuilder.cpp (+21-12)
  • (modified) clang/tools/clang-import-test/clang-import-test.cpp (+1-4)
  • (modified) clang/unittests/CodeGen/TestCompiler.h (+1-4)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+2-5)
diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
index 4298ba06c472e..5173fd05d75d6 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -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 @@ class CodeGenerator : public ASTConsumer {
   ///
   /// 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 @@ class CodeGenerator : public ASTConsumer {
 };
 
 /// 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
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 60d6b7fa009e7..a5ef4ac9d361d 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -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;
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index 8ec8aef311656..b4885d572c294 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -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 {
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 977cec1d53157..8e83687d3e96a 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -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
 
diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h
index 9bd90609fcd29..18947584bd0b3 100644
--- a/clang/unittests/CodeGen/TestCompiler.h
+++ b/clang/unittests/CodeGen/TestCompiler.h
@@ -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,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index bae3c44e333b6..25259cd4bdcf5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -874,11 +874,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;

@llvmbot
Copy link
Member

llvmbot commented Jan 9, 2026

@llvm/pr-subscribers-clang-codegen

Author: None (Sirraide)

Changes

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&amp; 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.

clang-format is definitely going to complain because the indentation in ModuleBuilder.cpp is all wrong, but I don’t think we should just reformat that file. A release note for this might be nice, but I’m not sure what section it should go in (if we want one at all)

Fixes #172169.


Full diff: https://github.com/llvm/llvm-project/pull/175239.diff

6 Files Affected:

  • (modified) clang/include/clang/CodeGen/ModuleBuilder.h (+19-13)
  • (modified) clang/lib/CodeGen/CodeGenAction.cpp (+1-3)
  • (modified) clang/lib/CodeGen/ModuleBuilder.cpp (+21-12)
  • (modified) clang/tools/clang-import-test/clang-import-test.cpp (+1-4)
  • (modified) clang/unittests/CodeGen/TestCompiler.h (+1-4)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+2-5)
diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
index 4298ba06c472e..5173fd05d75d6 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -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 @@ class CodeGenerator : public ASTConsumer {
   ///
   /// 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 @@ class CodeGenerator : public ASTConsumer {
 };
 
 /// 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
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 60d6b7fa009e7..a5ef4ac9d361d 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -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;
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index 8ec8aef311656..b4885d572c294 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -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 {
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 977cec1d53157..8e83687d3e96a 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -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
 
diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h
index 9bd90609fcd29..18947584bd0b3 100644
--- a/clang/unittests/CodeGen/TestCompiler.h
+++ b/clang/unittests/CodeGen/TestCompiler.h
@@ -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,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index bae3c44e333b6..25259cd4bdcf5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -874,11 +874,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;

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions cpp,h -- clang/include/clang/CodeGen/ModuleBuilder.h clang/lib/CodeGen/CodeGenAction.cpp clang/lib/CodeGen/ModuleBuilder.cpp clang/tools/clang-import-test/clang-import-test.cpp clang/unittests/CodeGen/TestCompiler.h lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
index 5173fd05d..456b53b17 100644
--- a/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -42,7 +42,7 @@ namespace clang {
   class PreprocessorOptions;
   class CompilerInstance;
 
-namespace CodeGen {
+  namespace CodeGen {
   class CodeGenModule;
   class CGDebugInfo;
 }
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index b4885d572..b100d3e84 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -32,302 +32,293 @@ using namespace clang;
 using namespace CodeGen;
 
 namespace {
-  class CodeGeneratorImpl final : public CodeGenerator {
-    DiagnosticsEngine &Diags;
-    ASTContext *Ctx;
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
-    const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
-    const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
-    const CodeGenOptions &CodeGenOpts;
-
-    unsigned HandlingTopLevelDecls;
-
-    /// Use this when emitting decls to block re-entrant decl emission. It will
-    /// emit all deferred decls on scope exit. Set EmitDeferred to false if decl
-    /// emission must be deferred longer, like at the end of a tag definition.
-    struct HandlingTopLevelDeclRAII {
-      CodeGeneratorImpl &Self;
-      bool EmitDeferred;
-      HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self,
-                               bool EmitDeferred = true)
-          : Self(Self), EmitDeferred(EmitDeferred) {
-        ++Self.HandlingTopLevelDecls;
-      }
-      ~HandlingTopLevelDeclRAII() {
-        unsigned Level = --Self.HandlingTopLevelDecls;
-        if (Level == 0 && EmitDeferred)
-          Self.EmitDeferredDecls();
-      }
-    };
-
-    CoverageSourceInfo *CoverageInfo;
-    std::unique_ptr<llvm::Module> M;
-    std::unique_ptr<CodeGen::CodeGenModule> Builder;
-    SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
-
-    static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
-                                            const CodeGenOptions &CGO) {
-      if (ModuleName == "-" && !CGO.MainFileName.empty())
-        return CGO.MainFileName;
-      return ModuleName;
+class CodeGeneratorImpl final : public CodeGenerator {
+  DiagnosticsEngine &Diags;
+  ASTContext *Ctx;
+  IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
+  const HeaderSearchOptions &HeaderSearchOpts;  // Only used for debug info.
+  const PreprocessorOptions &PreprocessorOpts;  // Only used for debug info.
+  const CodeGenOptions &CodeGenOpts;
+
+  unsigned HandlingTopLevelDecls;
+
+  /// Use this when emitting decls to block re-entrant decl emission. It will
+  /// emit all deferred decls on scope exit. Set EmitDeferred to false if decl
+  /// emission must be deferred longer, like at the end of a tag definition.
+  struct HandlingTopLevelDeclRAII {
+    CodeGeneratorImpl &Self;
+    bool EmitDeferred;
+    HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self, bool EmitDeferred = true)
+        : Self(Self), EmitDeferred(EmitDeferred) {
+      ++Self.HandlingTopLevelDecls;
     }
-
-  public:
-    CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
-                      IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
-                      const HeaderSearchOptions &HSO,
-                      const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
-                      llvm::LLVMContext &C,
-                      CoverageSourceInfo *CoverageInfo = nullptr)
-        : Diags(diags), Ctx(nullptr), FS(std::move(FS)), HeaderSearchOpts(HSO),
-          PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
-          CoverageInfo(CoverageInfo),
-          M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
-      C.setDiscardValueNames(CGO.DiscardValueNames);
+    ~HandlingTopLevelDeclRAII() {
+      unsigned Level = --Self.HandlingTopLevelDecls;
+      if (Level == 0 && EmitDeferred)
+        Self.EmitDeferredDecls();
     }
+  };
 
-    ~CodeGeneratorImpl() override {
-      // There should normally not be any leftover inline method definitions.
-      assert(DeferredInlineMemberFuncDefs.empty() ||
-             Diags.hasErrorOccurred());
-    }
+  CoverageSourceInfo *CoverageInfo;
+  std::unique_ptr<llvm::Module> M;
+  std::unique_ptr<CodeGen::CodeGenModule> Builder;
+  SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
 
-    CodeGenModule &CGM() {
-      return *Builder;
-    }
+  static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
+                                          const CodeGenOptions &CGO) {
+    if (ModuleName == "-" && !CGO.MainFileName.empty())
+      return CGO.MainFileName;
+    return ModuleName;
+  }
 
-    llvm::Module *GetModule() {
-      return M.get();
-    }
+public:
+  CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
+                    IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+                    const HeaderSearchOptions &HSO,
+                    const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
+                    llvm::LLVMContext &C,
+                    CoverageSourceInfo *CoverageInfo = nullptr)
+      : Diags(diags), Ctx(nullptr), FS(std::move(FS)), HeaderSearchOpts(HSO),
+        PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
+        CoverageInfo(CoverageInfo),
+        M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
+    C.setDiscardValueNames(CGO.DiscardValueNames);
+  }
 
-    CGDebugInfo *getCGDebugInfo() {
-      return Builder->getModuleDebugInfo();
-    }
+  ~CodeGeneratorImpl() override {
+    // There should normally not be any leftover inline method definitions.
+    assert(DeferredInlineMemberFuncDefs.empty() || Diags.hasErrorOccurred());
+  }
 
-    std::unique_ptr<llvm::Module> ReleaseModule() {
-      return std::exchange(M, nullptr);
-    }
+  CodeGenModule &CGM() { return *Builder; }
 
-    const Decl *GetDeclForMangledName(StringRef MangledName) {
-      GlobalDecl Result;
-      if (!Builder->lookupRepresentativeDecl(MangledName, Result))
-        return nullptr;
-      const Decl *D = Result.getCanonicalDecl().getDecl();
-      if (auto FD = dyn_cast<FunctionDecl>(D)) {
-        if (FD->hasBody(FD))
-          return FD;
-      } else if (auto TD = dyn_cast<TagDecl>(D)) {
-        if (auto Def = TD->getDefinition())
-          return Def;
-      }
-      return D;
-    }
+  llvm::Module *GetModule() { return M.get(); }
 
-    llvm::StringRef GetMangledName(GlobalDecl GD) {
-      return Builder->getMangledName(GD);
-    }
+  CGDebugInfo *getCGDebugInfo() { return Builder->getModuleDebugInfo(); }
+
+  std::unique_ptr<llvm::Module> ReleaseModule() {
+    return std::exchange(M, nullptr);
+  }
 
-    llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
-      return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
+  const Decl *GetDeclForMangledName(StringRef MangledName) {
+    GlobalDecl Result;
+    if (!Builder->lookupRepresentativeDecl(MangledName, Result))
+      return nullptr;
+    const Decl *D = Result.getCanonicalDecl().getDecl();
+    if (auto FD = dyn_cast<FunctionDecl>(D)) {
+      if (FD->hasBody(FD))
+        return FD;
+    } else if (auto TD = dyn_cast<TagDecl>(D)) {
+      if (auto Def = TD->getDefinition())
+        return Def;
     }
+    return D;
+  }
 
-    llvm::Module *StartModule(llvm::StringRef ModuleName,
-                              llvm::LLVMContext &C) {
-      assert(!M && "Replacing existing Module?");
-      M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C));
+  llvm::StringRef GetMangledName(GlobalDecl GD) {
+    return Builder->getMangledName(GD);
+  }
 
-      IRGenFinished = false;
+  llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
+    return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
+  }
 
-      std::unique_ptr<CodeGenModule> OldBuilder = std::move(Builder);
+  llvm::Module *StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C) {
+    assert(!M && "Replacing existing Module?");
+    M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C));
 
-      assert(Ctx && "must call Initialize() before calling StartModule()");
-      Initialize(*Ctx);
+    IRGenFinished = false;
 
-      if (OldBuilder)
-        OldBuilder->moveLazyEmissionStates(Builder.get());
+    std::unique_ptr<CodeGenModule> OldBuilder = std::move(Builder);
 
-      return M.get();
-    }
+    assert(Ctx && "must call Initialize() before calling StartModule()");
+    Initialize(*Ctx);
 
-    void Initialize(ASTContext &Context) override {
-      Ctx = &Context;
-
-      M->setTargetTriple(Ctx->getTargetInfo().getTriple());
-      M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
-      const auto &SDKVersion = Ctx->getTargetInfo().getSDKVersion();
-      if (!SDKVersion.empty())
-        M->setSDKVersion(SDKVersion);
-      if (const auto *TVT = Ctx->getTargetInfo().getDarwinTargetVariantTriple())
-        M->setDarwinTargetVariantTriple(TVT->getTriple());
-      if (auto TVSDKVersion =
-              Ctx->getTargetInfo().getDarwinTargetVariantSDKVersion())
-        M->setDarwinTargetVariantSDKVersion(*TVSDKVersion);
-      Builder.reset(new CodeGen::CodeGenModule(Context, FS, HeaderSearchOpts,
-                                               PreprocessorOpts, CodeGenOpts,
-                                               *M, Diags, CoverageInfo));
-
-      for (auto &&Lib : CodeGenOpts.DependentLibraries)
-        Builder->AddDependentLib(Lib);
-      for (auto &&Opt : CodeGenOpts.LinkerOptions)
-        Builder->AppendLinkerOptions(Opt);
-    }
-
-    void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
-      if (Diags.hasErrorOccurred())
-        return;
+    if (OldBuilder)
+      OldBuilder->moveLazyEmissionStates(Builder.get());
 
-      Builder->HandleCXXStaticMemberVarInstantiation(VD);
-    }
+    return M.get();
+  }
 
-    bool HandleTopLevelDecl(DeclGroupRef DG) override {
-      // Ignore interesting decls from the AST reader after IRGen is finished.
-      if (IRGenFinished)
-        return true; // We can't CodeGen more but pass to other consumers.
+  void Initialize(ASTContext &Context) override {
+    Ctx = &Context;
+
+    M->setTargetTriple(Ctx->getTargetInfo().getTriple());
+    M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
+    const auto &SDKVersion = Ctx->getTargetInfo().getSDKVersion();
+    if (!SDKVersion.empty())
+      M->setSDKVersion(SDKVersion);
+    if (const auto *TVT = Ctx->getTargetInfo().getDarwinTargetVariantTriple())
+      M->setDarwinTargetVariantTriple(TVT->getTriple());
+    if (auto TVSDKVersion =
+            Ctx->getTargetInfo().getDarwinTargetVariantSDKVersion())
+      M->setDarwinTargetVariantSDKVersion(*TVSDKVersion);
+    Builder.reset(new CodeGen::CodeGenModule(Context, FS, HeaderSearchOpts,
+                                             PreprocessorOpts, CodeGenOpts, *M,
+                                             Diags, CoverageInfo));
+
+    for (auto &&Lib : CodeGenOpts.DependentLibraries)
+      Builder->AddDependentLib(Lib);
+    for (auto &&Opt : CodeGenOpts.LinkerOptions)
+      Builder->AppendLinkerOptions(Opt);
+  }
 
-      // FIXME: Why not return false and abort parsing?
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return true;
+  void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
+    if (Diags.hasErrorOccurred())
+      return;
 
-      HandlingTopLevelDeclRAII HandlingDecl(*this);
+    Builder->HandleCXXStaticMemberVarInstantiation(VD);
+  }
 
-      // Make sure to emit all elements of a Decl.
-      for (auto &I : DG)
-        Builder->EmitTopLevelDecl(I);
+  bool HandleTopLevelDecl(DeclGroupRef DG) override {
+    // Ignore interesting decls from the AST reader after IRGen is finished.
+    if (IRGenFinished)
+      return true; // We can't CodeGen more but pass to other consumers.
 
+    // FIXME: Why not return false and abort parsing?
+    if (Diags.hasUnrecoverableErrorOccurred())
       return true;
-    }
 
-    void EmitDeferredDecls() {
-      if (DeferredInlineMemberFuncDefs.empty())
-        return;
-
-      // Emit any deferred inline method definitions. Note that more deferred
-      // methods may be added during this loop, since ASTConsumer callbacks
-      // can be invoked if AST inspection results in declarations being added.
-      HandlingTopLevelDeclRAII HandlingDecl(*this);
-      for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
-        Builder->EmitTopLevelDecl(DeferredInlineMemberFuncDefs[I]);
-      DeferredInlineMemberFuncDefs.clear();
-    }
+    HandlingTopLevelDeclRAII HandlingDecl(*this);
 
-    void HandleInlineFunctionDefinition(FunctionDecl *D) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
-
-      assert(D->doesThisDeclarationHaveABody());
-
-      // We may want to emit this definition. However, that decision might be
-      // based on computing the linkage, and we have to defer that in case we
-      // are inside of something that will change the method's final linkage,
-      // e.g.
-      //   typedef struct {
-      //     void bar();
-      //     void foo() { bar(); }
-      //   } A;
-      DeferredInlineMemberFuncDefs.push_back(D);
-
-      // Provide some coverage mapping even for methods that aren't emitted.
-      // Don't do this for templated classes though, as they may not be
-      // instantiable.
-      if (!D->getLexicalDeclContext()->isDependentContext())
-        Builder->AddDeferredUnusedCoverageMapping(D);
-    }
+    // Make sure to emit all elements of a Decl.
+    for (auto &I : DG)
+      Builder->EmitTopLevelDecl(I);
+
+    return true;
+  }
+
+  void EmitDeferredDecls() {
+    if (DeferredInlineMemberFuncDefs.empty())
+      return;
+
+    // Emit any deferred inline method definitions. Note that more deferred
+    // methods may be added during this loop, since ASTConsumer callbacks
+    // can be invoked if AST inspection results in declarations being added.
+    HandlingTopLevelDeclRAII HandlingDecl(*this);
+    for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
+      Builder->EmitTopLevelDecl(DeferredInlineMemberFuncDefs[I]);
+    DeferredInlineMemberFuncDefs.clear();
+  }
 
-    /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
-    /// to (e.g. struct, union, enum, class) is completed. This allows the
-    /// client hack on the type, which can occur at any point in the file
-    /// (because these can be defined in declspecs).
-    void HandleTagDeclDefinition(TagDecl *D) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
-
-      // Don't allow re-entrant calls to CodeGen triggered by PCH
-      // deserialization to emit deferred decls.
-      HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
-
-      Builder->UpdateCompletedType(D);
-
-      // 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)) {
-            if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
-                Ctx->DeclMustBeEmitted(VD)) {
-              Builder->EmitGlobal(VD);
-            }
+  void HandleInlineFunctionDefinition(FunctionDecl *D) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
+
+    assert(D->doesThisDeclarationHaveABody());
+
+    // We may want to emit this definition. However, that decision might be
+    // based on computing the linkage, and we have to defer that in case we
+    // are inside of something that will change the method's final linkage,
+    // e.g.
+    //   typedef struct {
+    //     void bar();
+    //     void foo() { bar(); }
+    //   } A;
+    DeferredInlineMemberFuncDefs.push_back(D);
+
+    // Provide some coverage mapping even for methods that aren't emitted.
+    // Don't do this for templated classes though, as they may not be
+    // instantiable.
+    if (!D->getLexicalDeclContext()->isDependentContext())
+      Builder->AddDeferredUnusedCoverageMapping(D);
+  }
+
+  /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
+  /// to (e.g. struct, union, enum, class) is completed. This allows the
+  /// client hack on the type, which can occur at any point in the file
+  /// (because these can be defined in declspecs).
+  void HandleTagDeclDefinition(TagDecl *D) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
+
+    // Don't allow re-entrant calls to CodeGen triggered by PCH
+    // deserialization to emit deferred decls.
+    HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
+
+    Builder->UpdateCompletedType(D);
+
+    // 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)) {
+          if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
+              Ctx->DeclMustBeEmitted(VD)) {
+            Builder->EmitGlobal(VD);
           }
         }
       }
-      // For OpenMP emit declare reduction functions, if required.
-      if (Ctx->getLangOpts().OpenMP) {
-        for (Decl *Member : D->decls()) {
-          if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Member)) {
-            if (Ctx->DeclMustBeEmitted(DRD))
-              Builder->EmitGlobal(DRD);
-          } else if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Member)) {
-            if (Ctx->DeclMustBeEmitted(DMD))
-              Builder->EmitGlobal(DMD);
-          }
+    }
+    // For OpenMP emit declare reduction functions, if required.
+    if (Ctx->getLangOpts().OpenMP) {
+      for (Decl *Member : D->decls()) {
+        if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Member)) {
+          if (Ctx->DeclMustBeEmitted(DRD))
+            Builder->EmitGlobal(DRD);
+        } else if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Member)) {
+          if (Ctx->DeclMustBeEmitted(DMD))
+            Builder->EmitGlobal(DMD);
         }
       }
     }
+  }
 
-    void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
-
-      // Don't allow re-entrant calls to CodeGen triggered by PCH
-      // deserialization to emit deferred decls.
-      HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
+  void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
 
-      if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
-        if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
-          DI->completeRequiredType(RD);
-    }
+    // Don't allow re-entrant calls to CodeGen triggered by PCH
+    // deserialization to emit deferred decls.
+    HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
 
-    void HandleTranslationUnit(ASTContext &Ctx) override {
-      // Release the Builder when there is no error.
-      if (!Diags.hasUnrecoverableErrorOccurred() && Builder)
-        Builder->Release();
-
-      // If there are errors before or when releasing the Builder, reset
-      // the module to stop here before invoking the backend.
-      if (Diags.hasErrorOccurred()) {
-        if (Builder)
-          Builder->clear();
-        M.reset();
-      }
+    if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
+      if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+        DI->completeRequiredType(RD);
+  }
 
-      IRGenFinished = true;
+  void HandleTranslationUnit(ASTContext &Ctx) override {
+    // Release the Builder when there is no error.
+    if (!Diags.hasUnrecoverableErrorOccurred() && Builder)
+      Builder->Release();
+
+    // If there are errors before or when releasing the Builder, reset
+    // the module to stop here before invoking the backend.
+    if (Diags.hasErrorOccurred()) {
+      if (Builder)
+        Builder->clear();
+      M.reset();
     }
 
-    void AssignInheritanceModel(CXXRecordDecl *RD) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
+    IRGenFinished = true;
+  }
 
-      Builder->RefreshTypeCacheForClass(RD);
-    }
+  void AssignInheritanceModel(CXXRecordDecl *RD) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
 
-    void CompleteTentativeDefinition(VarDecl *D) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
+    Builder->RefreshTypeCacheForClass(RD);
+  }
 
-      Builder->EmitTentativeDefinition(D);
-    }
+  void CompleteTentativeDefinition(VarDecl *D) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
 
-    void CompleteExternalDeclaration(DeclaratorDecl *D) override {
-      Builder->EmitExternalDeclaration(D);
-    }
+    Builder->EmitTentativeDefinition(D);
+  }
 
-    void HandleVTable(CXXRecordDecl *RD) override {
-      if (Diags.hasUnrecoverableErrorOccurred())
-        return;
+  void CompleteExternalDeclaration(DeclaratorDecl *D) override {
+    Builder->EmitExternalDeclaration(D);
+  }
 
-      Builder->EmitVTable(RD);
-    }
-  };
+  void HandleVTable(CXXRecordDecl *RD) override {
+    if (Diags.hasUnrecoverableErrorOccurred())
+      return;
+
+    Builder->EmitVTable(RD);
+  }
+};
 }
 
 void CodeGenerator::anchor() { }

@Sirraide
Copy link
Member Author

Sirraide commented Jan 9, 2026

Oh, I also added some assertions and a comment to make sure Initialize() is called before someone attempts to use this to actually emit any code because otherwise things go horribly wrong and it’s very much not obvious what the issue is.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Sirraide Sirraide merged commit 62c97aa into llvm:main Jan 12, 2026
13 of 14 checks passed
@Sirraide Sirraide deleted the codegenerator branch January 12, 2026 21:47
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Jan 18, 2026
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 llvm#172169.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:as-a-library libclang and C++ API clang:codegen IR generation bugs: mangling, exceptions, etc. lldb

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Clang] clang::CodeGenerator’s API is hard to use correctly

3 participants