Author: Sirraide
Date: 2026-07-10T04:55:40+02:00
New Revision: 10b965f0788ac4cf9a2c9ebd6c65d433aad19729

URL: 
https://github.com/llvm/llvm-project/commit/10b965f0788ac4cf9a2c9ebd6c65d433aad19729
DIFF: 
https://github.com/llvm/llvm-project/commit/10b965f0788ac4cf9a2c9ebd6c65d433aad19729.diff

LOG: [Clang] ASTUnit should use the CompilerInstance's CodeGenOptions (#195338)

Currently, `ASTUnit::LoadFromCompilerInvocation()` just calls the
constructor of `ASTUnit`, which default-constructs a `CodeGenOptions`
instance. The options from the `CompilerInstance` are never actually
saved in the `ASTUnit`. As a result, serialising the `ASTUnit` ends up
serialising the default-constructed `CodeGenOptions` rather than the
_actual_ `CodeGenOptions`.

This is problematic if you attempt to do the following:
1. Call e.g. `buildASTFromCodeWithArgs()` to build an `ASTUnit`
2. Serialise that `ASTUnit`.
3. Call e.g. `buildASTFromCodeWithArgs()` again with the exact same
arguments and add use the first `ASTUnit` as a PCH using `-include-pch`.

This causes Clang to error because the `CodeGenOptions` we deserialised
for the first `ASTUnit` (the default-constructed ones) are incompatible
with the `CodeGenOptions` implicitly created for the second TU (which
were created by the `CompilerInstance` and potentially modified due to
command-line argument parsing)... despite the fact that we basically
just attempted to build two TUs with the same arguments.

To fix this, copy the `CodeGenOptions` from the `CompilerInstance` into
the `ASTUnit`.

Added: 
    

Modified: 
    clang/lib/Frontend/ASTUnit.cpp
    clang/unittests/Frontend/ASTUnitTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 2974cf2660184..75e4f7772f47c 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -1679,6 +1679,7 @@ std::unique_ptr<ASTUnit> 
ASTUnit::LoadFromCompilerInvocation(
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  *AST->CodeGenOpts = CI->getCodeGenOpts();
   AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->OnlyLocalDecls = OnlyLocalDecls;

diff  --git a/clang/unittests/Frontend/ASTUnitTest.cpp 
b/clang/unittests/Frontend/ASTUnitTest.cpp
index bf9e4e184b5db..08dcd80a414ef 100644
--- a/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -38,13 +38,15 @@ class ASTUnitTest : public ::testing::Test {
   std::shared_ptr<CompilerInvocation> CInvok;
   std::shared_ptr<PCHContainerOperations> PCHContainerOps;
 
-  std::unique_ptr<ASTUnit> createASTUnit(bool isVolatile) {
+  std::unique_ptr<ASTUnit>
+  createASTUnit(bool isVolatile, ArrayRef<const char *> ExtraArgs = {}) {
     EXPECT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "cpp", FD,
                                                     InputFileName));
     input_file = std::make_unique<ToolOutputFile>(InputFileName, FD);
     input_file->os() << "";
 
-    const char *Args[] = {"clang", "-xc++", InputFileName.c_str()};
+    SmallVector<const char *> Args{"clang", "-xc++", InputFileName.c_str()};
+    append_range(Args, ExtraArgs);
 
     auto VFS = llvm::vfs::getRealFileSystem();
     Diags = CompilerInstance::createDiagnostics(*VFS, *DiagOpts);
@@ -109,6 +111,42 @@ TEST_F(ASTUnitTest, 
SaveLoadPreservesLangOptionsInPrintingPolicy) {
   EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams);
 }
 
+TEST_F(ASTUnitTest, SaveLoadPreservesCodeGenOptions) {
+  // Check that the CodeGenOptions are preserved when saving and loading an
+  // ASTUnit from a file.
+
+  {
+    std::unique_ptr<ASTUnit> AST = createASTUnit(false);
+    if (!AST)
+      FAIL() << "failed to create ASTUnit";
+    EXPECT_EQ(AST->getCodeGenOpts().OptimizationLevel, 0u);
+  }
+
+  std::unique_ptr<ASTUnit> AST = createASTUnit(false, {"-O3"});
+  if (!AST)
+    FAIL() << "failed to create ASTUnit";
+  EXPECT_EQ(AST->getCodeGenOpts().OptimizationLevel, 3u);
+
+  llvm::SmallString<256> ASTFileName;
+  ASSERT_FALSE(
+      llvm::sys::fs::createTemporaryFile("ast-unit", "ast", FD, ASTFileName));
+  ToolOutputFile ast_file(ASTFileName, FD);
+  AST->Save(ASTFileName.str());
+
+  EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));
+  HeaderSearchOptions HSOpts;
+
+  std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+      ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything,
+      llvm::vfs::getRealFileSystem(), DiagOpts, Diags, FileSystemOptions(),
+      HSOpts);
+
+  if (!AU)
+    FAIL() << "failed to load ASTUnit";
+
+  EXPECT_EQ(AU->getCodeGenOpts().OptimizationLevel, 3u);
+}
+
 TEST_F(ASTUnitTest, GetBufferForFileMemoryMapping) {
   std::unique_ptr<ASTUnit> AST = createASTUnit(true);
 


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to