Skip to content

Conversation

@jansvoboda11
Copy link
Contributor

The DiagnosticOptions class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, CompilerInvocation owns the DiagnosticOptions instance (wrapped in llvm::IntrusiveRefCntPtr) and only exposes an accessor returning DiagnosticOptions &. One would think this gives CompilerInvocation exclusive ownership of the object, but that's not the case:

void shareOwnership(CompilerInvocation &CI) {
  llvm::IntrusiveRefCntPtr<DiagnosticOptions> CoOwner = &CI.getDiagnosticOptions();
 // ...
}

This is a perfectly valid pattern that is being actually used in the codebase.

I would like to ensure the ownership of DiagnosticOptions by CompilerInvocation is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of DiagnosticOptions across clang, clang-tools-extra and lldb to not be intrusively reference-counted.

@jansvoboda11 jansvoboda11 requested a review from cyndyishida as a code owner May 12, 2025 17:07
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra lldb clangd clang-tidy clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang-format clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:as-a-library libclang and C++ API HLSL HLSL Language Support clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html labels May 12, 2025
@llvmbot
Copy link
Member

llvmbot commented May 12, 2025

@llvm/pr-subscribers-lldb
@llvm/pr-subscribers-clangd
@llvm/pr-subscribers-clang-tools-extra
@llvm/pr-subscribers-clang-format

@llvm/pr-subscribers-clang

Author: Jan Svoboda (jansvoboda11)

Changes

The DiagnosticOptions class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, CompilerInvocation owns the DiagnosticOptions instance (wrapped in llvm::IntrusiveRefCntPtr) and only exposes an accessor returning DiagnosticOptions &amp;. One would think this gives CompilerInvocation exclusive ownership of the object, but that's not the case:

void shareOwnership(CompilerInvocation &amp;CI) {
  llvm::IntrusiveRefCntPtr&lt;DiagnosticOptions&gt; CoOwner = &amp;CI.getDiagnosticOptions();
 // ...
}

This is a perfectly valid pattern that is being actually used in the codebase.

I would like to ensure the ownership of DiagnosticOptions by CompilerInvocation is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of DiagnosticOptions across clang, clang-tools-extra and lldb to not be intrusively reference-counted.


Patch is 189.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139584.diff

134 Files Affected:

  • (modified) clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp (+2-2)
  • (modified) clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp (+3-3)
  • (modified) clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp (+3-3)
  • (modified) clang-tools-extra/clang-move/tool/ClangMove.cpp (+3-3)
  • (modified) clang-tools-extra/clang-query/Query.cpp (+1-1)
  • (modified) clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp (+3-3)
  • (modified) clang-tools-extra/clang-tidy/ClangTidy.cpp (+12-12)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp (+2-2)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h (+4-1)
  • (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h (+1)
  • (modified) clang-tools-extra/clangd/Compiler.cpp (+3-2)
  • (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-2)
  • (modified) clang-tools-extra/clangd/ParsedAST.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/Preamble.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/SystemIncludeExtractor.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp (+2-1)
  • (modified) clang-tools-extra/include-cleaner/unittests/RecordTest.cpp (+2-2)
  • (modified) clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp (+3-3)
  • (modified) clang-tools-extra/modularize/ModularizeUtilities.cpp (+2-4)
  • (modified) clang-tools-extra/modularize/ModularizeUtilities.h (+1-1)
  • (modified) clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp (+2-2)
  • (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp (+9-9)
  • (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h (+3-3)
  • (modified) clang/include/clang/Basic/Diagnostic.h (+3-3)
  • (modified) clang/include/clang/Basic/DiagnosticOptions.h (+1-3)
  • (modified) clang/include/clang/Basic/SourceManager.h (+1)
  • (modified) clang/include/clang/Frontend/ASTUnit.h (+2)
  • (modified) clang/include/clang/Frontend/CompilerInstance.h (+1-1)
  • (modified) clang/include/clang/Frontend/CompilerInvocation.h (+1-1)
  • (modified) clang/include/clang/Frontend/DiagnosticRenderer.h (+3-4)
  • (modified) clang/include/clang/Frontend/LogDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Frontend/SARIFDiagnostic.h (+1-1)
  • (modified) clang/include/clang/Frontend/SARIFDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Frontend/SerializedDiagnosticPrinter.h (+1-1)
  • (modified) clang/include/clang/Frontend/TextDiagnostic.h (+1-1)
  • (modified) clang/include/clang/Frontend/TextDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Serialization/ASTReader.h (+4-5)
  • (modified) clang/lib/Basic/Diagnostic.cpp (+5-5)
  • (modified) clang/lib/Basic/SourceManager.cpp (+2-2)
  • (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+9-9)
  • (modified) clang/lib/Frontend/ASTMerge.cpp (+4-5)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+2)
  • (modified) clang/lib/Frontend/ChainedIncludesSource.cpp (+2-2)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+13-14)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7-20)
  • (modified) clang/lib/Frontend/CreateInvocationFromCommandLine.cpp (+9-5)
  • (modified) clang/lib/Frontend/DiagnosticRenderer.cpp (+8-9)
  • (modified) clang/lib/Frontend/FrontendAction.cpp (+2-3)
  • (modified) clang/lib/Frontend/FrontendActions.cpp (+8-8)
  • (modified) clang/lib/Frontend/LogDiagnosticPrinter.cpp (+2-2)
  • (modified) clang/lib/Frontend/SARIFDiagnostic.cpp (+2-2)
  • (modified) clang/lib/Frontend/SARIFDiagnosticPrinter.cpp (+3-4)
  • (modified) clang/lib/Frontend/SerializedDiagnosticPrinter.cpp (+15-14)
  • (modified) clang/lib/Frontend/TextDiagnostic.cpp (+39-40)
  • (modified) clang/lib/Frontend/TextDiagnosticPrinter.cpp (+6-9)
  • (modified) clang/lib/Interpreter/Interpreter.cpp (+4-4)
  • (modified) clang/lib/Rewrite/HTMLRewrite.cpp (+2-2)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+12-13)
  • (modified) clang/lib/Testing/TestAST.cpp (+1-1)
  • (modified) clang/lib/Tooling/CompilationDatabase.cpp (+4-4)
  • (modified) clang/lib/Tooling/Core/Replacement.cpp (+2-2)
  • (modified) clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp (+3-3)
  • (modified) clang/lib/Tooling/Refactoring.cpp (+4-4)
  • (modified) clang/lib/Tooling/Tooling.cpp (+4-4)
  • (modified) clang/tools/c-index-test/core_main.cpp (+4-2)
  • (modified) clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp (+7-5)
  • (modified) clang/tools/clang-format/ClangFormat.cpp (+4-4)
  • (modified) clang/tools/clang-import-test/clang-import-test.cpp (+2-2)
  • (modified) clang/tools/clang-installapi/ClangInstallAPI.cpp (+4-4)
  • (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+5-4)
  • (modified) clang/tools/diagtool/ShowEnabledWarnings.cpp (+3-3)
  • (modified) clang/tools/diagtool/TreeView.cpp (+2-2)
  • (modified) clang/tools/driver/cc1_main.cpp (+2-2)
  • (modified) clang/tools/driver/cc1as_main.cpp (+4-4)
  • (modified) clang/tools/driver/cc1gen_reproducer_main.cpp (+3-3)
  • (modified) clang/tools/driver/driver.cpp (+5-6)
  • (modified) clang/tools/libclang/CIndex.cpp (+5-4)
  • (modified) clang/tools/libclang/CIndexCodeCompletion.cpp (+5-5)
  • (modified) clang/tools/libclang/CIndexDiagnostic.cpp (+8-9)
  • (modified) clang/tools/libclang/Indexing.cpp (+2-1)
  • (modified) clang/unittests/AST/ASTVectorTest.cpp (+2-1)
  • (modified) clang/unittests/AST/CommentLexer.cpp (+4-6)
  • (modified) clang/unittests/AST/CommentParser.cpp (+4-6)
  • (modified) clang/unittests/AST/CommentTextTest.cpp (+2-1)
  • (modified) clang/unittests/AST/ExternalASTSourceTest.cpp (+2-2)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+2-3)
  • (modified) clang/unittests/Analysis/MacroExpansionContextTest.cpp (+3-3)
  • (modified) clang/unittests/Analysis/UnsafeBufferUsageTest.cpp (+2-1)
  • (modified) clang/unittests/Basic/DiagnosticTest.cpp (+14-9)
  • (modified) clang/unittests/Basic/SarifTest.cpp (+3-3)
  • (modified) clang/unittests/Basic/SourceManagerTest.cpp (+4-5)
  • (modified) clang/unittests/Driver/DXCModeTest.cpp (+6-6)
  • (modified) clang/unittests/Driver/SanitizerArgsTest.cpp (+3-4)
  • (modified) clang/unittests/Driver/SimpleDiagnosticConsumer.h (+2-3)
  • (modified) clang/unittests/Driver/ToolChainTest.cpp (+36-35)
  • (modified) clang/unittests/Frontend/ASTUnitTest.cpp (+14-13)
  • (modified) clang/unittests/Frontend/CompilerInstanceTest.cpp (+6-5)
  • (modified) clang/unittests/Frontend/CompilerInvocationTest.cpp (+2-1)
  • (modified) clang/unittests/Frontend/OutputStreamTest.cpp (+6-6)
  • (modified) clang/unittests/Frontend/PCHPreambleTest.cpp (+3-1)
  • (modified) clang/unittests/Frontend/ReparseWorkingDirTest.cpp (+2-1)
  • (modified) clang/unittests/Frontend/SearchPathTest.cpp (+2-2)
  • (modified) clang/unittests/Frontend/TextDiagnosticTest.cpp (+4-4)
  • (modified) clang/unittests/Frontend/UtilsTest.cpp (+5-4)
  • (modified) clang/unittests/Interpreter/InterpreterTest.cpp (+9-6)
  • (modified) clang/unittests/Lex/HeaderSearchTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/LexerTest.cpp (+4-6)
  • (modified) clang/unittests/Lex/ModuleDeclStateTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/PPCallbacksTest.cpp (+4-4)
  • (modified) clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp (+4-6)
  • (modified) clang/unittests/Lex/PPDependencyDirectivesTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/PPMemoryAllocationsTest.cpp (+2-1)
  • (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+2-2)
  • (modified) clang/unittests/Sema/SemaNoloadLookupTest.cpp (+2-2)
  • (modified) clang/unittests/Serialization/ForceCheckFileInputTest.cpp (+4-4)
  • (modified) clang/unittests/Serialization/LoadSpecLazilyTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/ModuleCacheTest.cpp (+4-2)
  • (modified) clang/unittests/Serialization/NoCommentsTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/PreambleInNamedModulesTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/VarDeclConstantInitTest.cpp (+2-1)
  • (modified) clang/unittests/Support/TimeProfilerTest.cpp (+2-2)
  • (modified) clang/unittests/Tooling/RewriterTestContext.h (+4-5)
  • (modified) clang/unittests/Tooling/Syntax/TokensTest.cpp (+2-1)
  • (modified) clang/unittests/Tooling/Syntax/TreeTestBase.cpp (+1-1)
  • (modified) clang/unittests/Tooling/Syntax/TreeTestBase.h (+2-2)
  • (modified) clang/unittests/Tooling/ToolingTest.cpp (+4-4)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+5-5)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+1-2)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp (+13-8)
  • (modified) lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp (+1-2)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-1)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+1)
diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 68b5743c6540f..062e236d3e51f 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -96,9 +96,9 @@ int main(int argc, char **argv) {
   cl::SetVersionPrinter(printVersion);
   cl::ParseCommandLineOptions(argc, argv);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 22d26db0c11bc..2a8fe2d06d185 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -126,10 +126,10 @@ int main(int argc, const char **argv) {
   if (int Result = Tool.run(Factory.get()))
     return Result;
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager Sources(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 6e51f25a66407..746ba7bcea015 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) {
   }
 
   // Set up a new source manager for applying the resulting replacements.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
-  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
-  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts);
   SourceManager SM(Diagnostics, tool.getFiles());
   Diagnostics.setClient(&DiagnosticPrinter, false);
 
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 655ea81ee37d4..750eb952714f7 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -176,10 +176,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager SM(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
index 382aa5d6fe25e..574b64ee0f759 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
           clang::SourceRange R = BI->second.getSourceRange();
           if (R.isValid()) {
             TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
-                              &AST->getDiagnostics().getDiagnosticOptions());
+                              AST->getDiagnostics().getDiagnosticOptions());
             TD.emitDiagnostic(
                 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
                 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
index 5b77ee7b5738c..03502525417b2 100644
--- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
+++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -72,10 +72,10 @@ int main(int argc, const char **argv) {
 
   int ExitCode = Tool.run(Factory.get());
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
 
   auto &FileMgr = Tool.getFiles();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 733a53a0f5dcc..26f9afbc0880e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -97,15 +97,14 @@ class ErrorReporter {
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagOpts(new DiagnosticOptions()),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
-        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
+        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
               DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
-    DiagOpts->ShowColors = Context.getOptions().UseColor.value_or(
+    DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
         llvm::sys::Process::StandardOutHasColors());
     DiagPrinter->BeginSourceFile(LangOpts);
-    if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
+    if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
       llvm::sys::Process::UseANSIEscapeCodes(true);
     }
   }
@@ -308,7 +307,7 @@ class ErrorReporter {
 
   FileManager Files;
   LangOptions LangOpts; // FIXME: use langopts from each original file
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticConsumer *DiagPrinter;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
@@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options,
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(),
-                       llvm::makeIntrusiveRefCnt<DiagnosticOptions>(),
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
                        &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
   ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
-                       &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
+                       /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   Tool.setDiagnosticConsumer(&DiagConsumer);
 
   class ActionFactory : public FrontendActionFactory {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index b216970bfbd8c..a0253a5fd1a48 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -49,7 +49,7 @@ namespace {
 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
 public:
   ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
-                              DiagnosticOptions *DiagOpts,
+                              DiagnosticOptions &DiagOpts,
                               ClangTidyError &Error)
       : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
 
@@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
     forwardDiagnostic(Info);
   } else {
     ClangTidyDiagnosticRenderer Converter(
-        Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
+        Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
         Errors.back());
     SmallString<100> Message;
     Info.FormatDiagnostic(Message);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index d6cf6a2b2731e..bd7a1bf2c11c7 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -75,7 +75,9 @@ class ClangTidyContext {
   /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
   // FIXME: this is required initialization, and should be a constructor param.
   // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
+  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
+                            DiagnosticsEngine *DiagEngine) {
+    this->DiagOpts = std::move(DiagOpts);
     this->DiagEngine = DiagEngine;
   }
 
@@ -231,6 +233,7 @@ class ClangTidyContext {
   // Writes to Stats.
   friend class ClangTidyDiagnosticConsumer;
 
+  std::unique_ptr<DiagnosticOptions> DiagOpts = nullptr;
   DiagnosticsEngine *DiagEngine = nullptr;
   std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
 
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 03a3e8404e069..6a84704434c33 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
       InMemoryFs(new llvm::vfs::InMemoryFileSystem),
       Sources(Compiler.getSourceManager()),
       // Forward the new diagnostics to the original DiagnosticConsumer.
-      Diags(new DiagnosticIDs, new DiagnosticOptions,
+      Diags(new DiagnosticIDs, DiagOpts,
             new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
       LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
   // Add a FileSystem containing the extra files needed in place of modular
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
index a263681b3c633..c3478917ef498 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs;
 
   SourceManager &Sources;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   LangOptions LangOpts;
   HeaderSearchOptions HSOpts;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 9be0152afd2f7..8b3865c8a8e5c 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
   CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   CIOpts.CC1Args = CC1Args;
   CIOpts.RecoverOnError = true;
-  CIOpts.Diags = CompilerInstance::createDiagnostics(
-      *CIOpts.VFS, new DiagnosticOptions, &D, false);
+  DiagnosticOptions DiagOpts;
+  CIOpts.Diags =
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);
   CIOpts.ProbePrecompiled = false;
   std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
   if (!CI)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..bf77f43bd28bb 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   HSOpts.ValidateASTInputFilesContent = true;
 
   clang::clangd::IgnoreDiagnostics IgnoreDiags;
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
-                                          &IgnoreDiags,
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
                                           /*ShouldOwnClient=*/false);
 
   LangOptions LangOpts;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 3f63daaf400db..9e1f6bb977226 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
         *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
         tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
-    CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+    // The lifetime of DiagnosticOptions is managed by \c Clang.
+    CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index ba9a53db8a0dc..7b4d63ff197e7 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       });
   auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
-      CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(),
+      CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
                                           &PreambleDiagnostics,
                                           /*ShouldOwnClient=*/false);
   const Config &Cfg = Config::current();
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index 6417bf8765622..0b067e8b0b2b2 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -253,7 +253,8 @@ namespace {
 bool isValidTarget(llvm::StringRef Triple) {
   std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions);
   TargetOpts->Triple = Triple.str();
-  DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
                           new IgnoringDiagConsumer);
   llvm::IntrusiveRefCntPtr<TargetInfo> Target =
       TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index c3e484a1a79c4..75d0ff244038d 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
                                    "unreachable-code", "unused-variable",
                                    "typecheck_bool_condition",
                                    "unexpected_friend", "warn_alloca"));
-  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts,
                                       new clang::IgnoringDiagConsumer);
 
   using Diag = clang::Diagnostic;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
index 8bd40c1429012..e39b70224d97c 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
@@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) {
   for (const auto *Path : RelPaths)
     MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path));
   FileManager FM(FileSystemOptions(), MemFS);
-  DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts);
   SourceManager SM(DE, FM);
 
   for (const auto *Path : RelPaths) {
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index a10c0d5a54a95..91d2697712b6e 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) {
                  llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(),
                                                       /*BufferName=*/""));
 
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get());
+  DiagnosticOptions DiagOpts;
+  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts);
   auto Invocation = std::make_unique<CompilerInvocation>();
   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()},
                                                  *Diags, "clang"));
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index e45ea36f7938e..5223eb563e4cb 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -85,9 +85,9 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
   // For each difference, show the target point in context, like a diagnostic.
   std::string DiagBuf;
   llvm::raw_string_ostream DiagOS(DiagBuf);
-  auto *DiagOpts = new DiagnosticOptions();
-  DiagOpts->ShowLevel = 0;
-  DiagOpts->ShowNoteIncludeStack = 0;
+  DiagnosticOptions DiagOpts;
+  DiagOpts.ShowLevel = 0;
+  DiagOpts.ShowNoteIncludeStack = 0;
   TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
   auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) {
     Diag.emitDiagnostic(
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index 576e863c8a9d2..b04eb80a67717 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 12, 2025

@llvm/pr-subscribers-hlsl

Author: Jan Svoboda (jansvoboda11)

Changes

The DiagnosticOptions class is currently intrusively reference-counted, which makes reasoning about its lifetime very difficult in some cases. For example, CompilerInvocation owns the DiagnosticOptions instance (wrapped in llvm::IntrusiveRefCntPtr) and only exposes an accessor returning DiagnosticOptions &amp;. One would think this gives CompilerInvocation exclusive ownership of the object, but that's not the case:

void shareOwnership(CompilerInvocation &amp;CI) {
  llvm::IntrusiveRefCntPtr&lt;DiagnosticOptions&gt; CoOwner = &amp;CI.getDiagnosticOptions();
 // ...
}

This is a perfectly valid pattern that is being actually used in the codebase.

I would like to ensure the ownership of DiagnosticOptions by CompilerInvocation is guaranteed to be exclusive. This can be leveraged for a copy-on-write optimization later on. This PR changes usages of DiagnosticOptions across clang, clang-tools-extra and lldb to not be intrusively reference-counted.


Patch is 189.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139584.diff

134 Files Affected:

  • (modified) clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp (+2-2)
  • (modified) clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp (+3-3)
  • (modified) clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp (+3-3)
  • (modified) clang-tools-extra/clang-move/tool/ClangMove.cpp (+3-3)
  • (modified) clang-tools-extra/clang-query/Query.cpp (+1-1)
  • (modified) clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp (+3-3)
  • (modified) clang-tools-extra/clang-tidy/ClangTidy.cpp (+12-12)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp (+2-2)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h (+4-1)
  • (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h (+1)
  • (modified) clang-tools-extra/clangd/Compiler.cpp (+3-2)
  • (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+2-2)
  • (modified) clang-tools-extra/clangd/ParsedAST.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/Preamble.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/SystemIncludeExtractor.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp (+2-1)
  • (modified) clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp (+2-1)
  • (modified) clang-tools-extra/include-cleaner/unittests/RecordTest.cpp (+2-2)
  • (modified) clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp (+3-3)
  • (modified) clang-tools-extra/modularize/ModularizeUtilities.cpp (+2-4)
  • (modified) clang-tools-extra/modularize/ModularizeUtilities.h (+1-1)
  • (modified) clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp (+2-2)
  • (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp (+9-9)
  • (modified) clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h (+3-3)
  • (modified) clang/include/clang/Basic/Diagnostic.h (+3-3)
  • (modified) clang/include/clang/Basic/DiagnosticOptions.h (+1-3)
  • (modified) clang/include/clang/Basic/SourceManager.h (+1)
  • (modified) clang/include/clang/Frontend/ASTUnit.h (+2)
  • (modified) clang/include/clang/Frontend/CompilerInstance.h (+1-1)
  • (modified) clang/include/clang/Frontend/CompilerInvocation.h (+1-1)
  • (modified) clang/include/clang/Frontend/DiagnosticRenderer.h (+3-4)
  • (modified) clang/include/clang/Frontend/LogDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Frontend/SARIFDiagnostic.h (+1-1)
  • (modified) clang/include/clang/Frontend/SARIFDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Frontend/SerializedDiagnosticPrinter.h (+1-1)
  • (modified) clang/include/clang/Frontend/TextDiagnostic.h (+1-1)
  • (modified) clang/include/clang/Frontend/TextDiagnosticPrinter.h (+2-2)
  • (modified) clang/include/clang/Serialization/ASTReader.h (+4-5)
  • (modified) clang/lib/Basic/Diagnostic.cpp (+5-5)
  • (modified) clang/lib/Basic/SourceManager.cpp (+2-2)
  • (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+9-9)
  • (modified) clang/lib/Frontend/ASTMerge.cpp (+4-5)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+2)
  • (modified) clang/lib/Frontend/ChainedIncludesSource.cpp (+2-2)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+13-14)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+7-20)
  • (modified) clang/lib/Frontend/CreateInvocationFromCommandLine.cpp (+9-5)
  • (modified) clang/lib/Frontend/DiagnosticRenderer.cpp (+8-9)
  • (modified) clang/lib/Frontend/FrontendAction.cpp (+2-3)
  • (modified) clang/lib/Frontend/FrontendActions.cpp (+8-8)
  • (modified) clang/lib/Frontend/LogDiagnosticPrinter.cpp (+2-2)
  • (modified) clang/lib/Frontend/SARIFDiagnostic.cpp (+2-2)
  • (modified) clang/lib/Frontend/SARIFDiagnosticPrinter.cpp (+3-4)
  • (modified) clang/lib/Frontend/SerializedDiagnosticPrinter.cpp (+15-14)
  • (modified) clang/lib/Frontend/TextDiagnostic.cpp (+39-40)
  • (modified) clang/lib/Frontend/TextDiagnosticPrinter.cpp (+6-9)
  • (modified) clang/lib/Interpreter/Interpreter.cpp (+4-4)
  • (modified) clang/lib/Rewrite/HTMLRewrite.cpp (+2-2)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+12-13)
  • (modified) clang/lib/Testing/TestAST.cpp (+1-1)
  • (modified) clang/lib/Tooling/CompilationDatabase.cpp (+4-4)
  • (modified) clang/lib/Tooling/Core/Replacement.cpp (+2-2)
  • (modified) clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp (+3-3)
  • (modified) clang/lib/Tooling/Refactoring.cpp (+4-4)
  • (modified) clang/lib/Tooling/Tooling.cpp (+4-4)
  • (modified) clang/tools/c-index-test/core_main.cpp (+4-2)
  • (modified) clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp (+7-5)
  • (modified) clang/tools/clang-format/ClangFormat.cpp (+4-4)
  • (modified) clang/tools/clang-import-test/clang-import-test.cpp (+2-2)
  • (modified) clang/tools/clang-installapi/ClangInstallAPI.cpp (+4-4)
  • (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+5-4)
  • (modified) clang/tools/diagtool/ShowEnabledWarnings.cpp (+3-3)
  • (modified) clang/tools/diagtool/TreeView.cpp (+2-2)
  • (modified) clang/tools/driver/cc1_main.cpp (+2-2)
  • (modified) clang/tools/driver/cc1as_main.cpp (+4-4)
  • (modified) clang/tools/driver/cc1gen_reproducer_main.cpp (+3-3)
  • (modified) clang/tools/driver/driver.cpp (+5-6)
  • (modified) clang/tools/libclang/CIndex.cpp (+5-4)
  • (modified) clang/tools/libclang/CIndexCodeCompletion.cpp (+5-5)
  • (modified) clang/tools/libclang/CIndexDiagnostic.cpp (+8-9)
  • (modified) clang/tools/libclang/Indexing.cpp (+2-1)
  • (modified) clang/unittests/AST/ASTVectorTest.cpp (+2-1)
  • (modified) clang/unittests/AST/CommentLexer.cpp (+4-6)
  • (modified) clang/unittests/AST/CommentParser.cpp (+4-6)
  • (modified) clang/unittests/AST/CommentTextTest.cpp (+2-1)
  • (modified) clang/unittests/AST/ExternalASTSourceTest.cpp (+2-2)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+2-3)
  • (modified) clang/unittests/Analysis/MacroExpansionContextTest.cpp (+3-3)
  • (modified) clang/unittests/Analysis/UnsafeBufferUsageTest.cpp (+2-1)
  • (modified) clang/unittests/Basic/DiagnosticTest.cpp (+14-9)
  • (modified) clang/unittests/Basic/SarifTest.cpp (+3-3)
  • (modified) clang/unittests/Basic/SourceManagerTest.cpp (+4-5)
  • (modified) clang/unittests/Driver/DXCModeTest.cpp (+6-6)
  • (modified) clang/unittests/Driver/SanitizerArgsTest.cpp (+3-4)
  • (modified) clang/unittests/Driver/SimpleDiagnosticConsumer.h (+2-3)
  • (modified) clang/unittests/Driver/ToolChainTest.cpp (+36-35)
  • (modified) clang/unittests/Frontend/ASTUnitTest.cpp (+14-13)
  • (modified) clang/unittests/Frontend/CompilerInstanceTest.cpp (+6-5)
  • (modified) clang/unittests/Frontend/CompilerInvocationTest.cpp (+2-1)
  • (modified) clang/unittests/Frontend/OutputStreamTest.cpp (+6-6)
  • (modified) clang/unittests/Frontend/PCHPreambleTest.cpp (+3-1)
  • (modified) clang/unittests/Frontend/ReparseWorkingDirTest.cpp (+2-1)
  • (modified) clang/unittests/Frontend/SearchPathTest.cpp (+2-2)
  • (modified) clang/unittests/Frontend/TextDiagnosticTest.cpp (+4-4)
  • (modified) clang/unittests/Frontend/UtilsTest.cpp (+5-4)
  • (modified) clang/unittests/Interpreter/InterpreterTest.cpp (+9-6)
  • (modified) clang/unittests/Lex/HeaderSearchTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/LexerTest.cpp (+4-6)
  • (modified) clang/unittests/Lex/ModuleDeclStateTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/PPCallbacksTest.cpp (+4-4)
  • (modified) clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp (+4-6)
  • (modified) clang/unittests/Lex/PPDependencyDirectivesTest.cpp (+2-1)
  • (modified) clang/unittests/Lex/PPMemoryAllocationsTest.cpp (+2-1)
  • (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+2-2)
  • (modified) clang/unittests/Sema/SemaNoloadLookupTest.cpp (+2-2)
  • (modified) clang/unittests/Serialization/ForceCheckFileInputTest.cpp (+4-4)
  • (modified) clang/unittests/Serialization/LoadSpecLazilyTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/ModuleCacheTest.cpp (+4-2)
  • (modified) clang/unittests/Serialization/NoCommentsTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/PreambleInNamedModulesTest.cpp (+2-1)
  • (modified) clang/unittests/Serialization/VarDeclConstantInitTest.cpp (+2-1)
  • (modified) clang/unittests/Support/TimeProfilerTest.cpp (+2-2)
  • (modified) clang/unittests/Tooling/RewriterTestContext.h (+4-5)
  • (modified) clang/unittests/Tooling/Syntax/TokensTest.cpp (+2-1)
  • (modified) clang/unittests/Tooling/Syntax/TreeTestBase.cpp (+1-1)
  • (modified) clang/unittests/Tooling/Syntax/TreeTestBase.h (+2-2)
  • (modified) clang/unittests/Tooling/ToolingTest.cpp (+4-4)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+5-5)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (+1-2)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp (+13-8)
  • (modified) lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp (+1-2)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+2-1)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+1)
diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 68b5743c6540f..062e236d3e51f 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -96,9 +96,9 @@ int main(int argc, char **argv) {
   cl::SetVersionPrinter(printVersion);
   cl::ParseCommandLineOptions(argc, argv);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 22d26db0c11bc..2a8fe2d06d185 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -126,10 +126,10 @@ int main(int argc, const char **argv) {
   if (int Result = Tool.run(Factory.get()))
     return Result;
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager Sources(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 6e51f25a66407..746ba7bcea015 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) {
   }
 
   // Set up a new source manager for applying the resulting replacements.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
-  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
-  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts);
   SourceManager SM(Diagnostics, tool.getFiles());
   Diagnostics.setClient(&DiagnosticPrinter, false);
 
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 655ea81ee37d4..750eb952714f7 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -176,10 +176,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager SM(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
index 382aa5d6fe25e..574b64ee0f759 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
           clang::SourceRange R = BI->second.getSourceRange();
           if (R.isValid()) {
             TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
-                              &AST->getDiagnostics().getDiagnosticOptions());
+                              AST->getDiagnostics().getDiagnosticOptions());
             TD.emitDiagnostic(
                 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
                 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
index 5b77ee7b5738c..03502525417b2 100644
--- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
+++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -72,10 +72,10 @@ int main(int argc, const char **argv) {
 
   int ExitCode = Tool.run(Factory.get());
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
 
   auto &FileMgr = Tool.getFiles();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 733a53a0f5dcc..26f9afbc0880e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -97,15 +97,14 @@ class ErrorReporter {
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagOpts(new DiagnosticOptions()),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
-        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
+        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
               DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
-    DiagOpts->ShowColors = Context.getOptions().UseColor.value_or(
+    DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
         llvm::sys::Process::StandardOutHasColors());
     DiagPrinter->BeginSourceFile(LangOpts);
-    if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
+    if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
       llvm::sys::Process::UseANSIEscapeCodes(true);
     }
   }
@@ -308,7 +307,7 @@ class ErrorReporter {
 
   FileManager Files;
   LangOptions LangOpts; // FIXME: use langopts from each original file
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticConsumer *DiagPrinter;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
@@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options,
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(),
-                       llvm::makeIntrusiveRefCnt<DiagnosticOptions>(),
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
                        &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
   ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
-                       &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
+                       /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   Tool.setDiagnosticConsumer(&DiagConsumer);
 
   class ActionFactory : public FrontendActionFactory {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index b216970bfbd8c..a0253a5fd1a48 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -49,7 +49,7 @@ namespace {
 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
 public:
   ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
-                              DiagnosticOptions *DiagOpts,
+                              DiagnosticOptions &DiagOpts,
                               ClangTidyError &Error)
       : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
 
@@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
     forwardDiagnostic(Info);
   } else {
     ClangTidyDiagnosticRenderer Converter(
-        Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
+        Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
         Errors.back());
     SmallString<100> Message;
     Info.FormatDiagnostic(Message);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index d6cf6a2b2731e..bd7a1bf2c11c7 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -75,7 +75,9 @@ class ClangTidyContext {
   /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
   // FIXME: this is required initialization, and should be a constructor param.
   // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
+  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
+                            DiagnosticsEngine *DiagEngine) {
+    this->DiagOpts = std::move(DiagOpts);
     this->DiagEngine = DiagEngine;
   }
 
@@ -231,6 +233,7 @@ class ClangTidyContext {
   // Writes to Stats.
   friend class ClangTidyDiagnosticConsumer;
 
+  std::unique_ptr<DiagnosticOptions> DiagOpts = nullptr;
   DiagnosticsEngine *DiagEngine = nullptr;
   std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
 
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 03a3e8404e069..6a84704434c33 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
       InMemoryFs(new llvm::vfs::InMemoryFileSystem),
       Sources(Compiler.getSourceManager()),
       // Forward the new diagnostics to the original DiagnosticConsumer.
-      Diags(new DiagnosticIDs, new DiagnosticOptions,
+      Diags(new DiagnosticIDs, DiagOpts,
             new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
       LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
   // Add a FileSystem containing the extra files needed in place of modular
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
index a263681b3c633..c3478917ef498 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs;
 
   SourceManager &Sources;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   LangOptions LangOpts;
   HeaderSearchOptions HSOpts;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 9be0152afd2f7..8b3865c8a8e5c 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
   CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   CIOpts.CC1Args = CC1Args;
   CIOpts.RecoverOnError = true;
-  CIOpts.Diags = CompilerInstance::createDiagnostics(
-      *CIOpts.VFS, new DiagnosticOptions, &D, false);
+  DiagnosticOptions DiagOpts;
+  CIOpts.Diags =
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);
   CIOpts.ProbePrecompiled = false;
   std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
   if (!CI)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..bf77f43bd28bb 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   HSOpts.ValidateASTInputFilesContent = true;
 
   clang::clangd::IgnoreDiagnostics IgnoreDiags;
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
-                                          &IgnoreDiags,
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
                                           /*ShouldOwnClient=*/false);
 
   LangOptions LangOpts;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 3f63daaf400db..9e1f6bb977226 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
         *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
         tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
-    CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+    // The lifetime of DiagnosticOptions is managed by \c Clang.
+    CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index ba9a53db8a0dc..7b4d63ff197e7 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       });
   auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
-      CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(),
+      CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
                                           &PreambleDiagnostics,
                                           /*ShouldOwnClient=*/false);
   const Config &Cfg = Config::current();
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index 6417bf8765622..0b067e8b0b2b2 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -253,7 +253,8 @@ namespace {
 bool isValidTarget(llvm::StringRef Triple) {
   std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions);
   TargetOpts->Triple = Triple.str();
-  DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
                           new IgnoringDiagConsumer);
   llvm::IntrusiveRefCntPtr<TargetInfo> Target =
       TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index c3e484a1a79c4..75d0ff244038d 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
                                    "unreachable-code", "unused-variable",
                                    "typecheck_bool_condition",
                                    "unexpected_friend", "warn_alloca"));
-  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts,
                                       new clang::IgnoringDiagConsumer);
 
   using Diag = clang::Diagnostic;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
index 8bd40c1429012..e39b70224d97c 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
@@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) {
   for (const auto *Path : RelPaths)
     MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path));
   FileManager FM(FileSystemOptions(), MemFS);
-  DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts);
   SourceManager SM(DE, FM);
 
   for (const auto *Path : RelPaths) {
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index a10c0d5a54a95..91d2697712b6e 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) {
                  llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(),
                                                       /*BufferName=*/""));
 
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get());
+  DiagnosticOptions DiagOpts;
+  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts);
   auto Invocation = std::make_unique<CompilerInvocation>();
   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()},
                                                  *Diags, "clang"));
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index e45ea36f7938e..5223eb563e4cb 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -85,9 +85,9 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
   // For each difference, show the target point in context, like a diagnostic.
   std::string DiagBuf;
   llvm::raw_string_ostream DiagOS(DiagBuf);
-  auto *DiagOpts = new DiagnosticOptions();
-  DiagOpts->ShowLevel = 0;
-  DiagOpts->ShowNoteIncludeStack = 0;
+  DiagnosticOptions DiagOpts;
+  DiagOpts.ShowLevel = 0;
+  DiagOpts.ShowNoteIncludeStack = 0;
   TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
   auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) {
     Diag.emitDiagnostic(
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index 576e863c8a9d2..b04eb80a67717 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(...
[truncated]

@jansvoboda11 jansvoboda11 requested a review from benlangmuir May 13, 2025 16:57
@cor3ntin cor3ntin requested a review from AaronBallman May 14, 2025 09:40
Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

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

The clang parts look like a nice improvement, thanks!

Please wait for a few other people to review it though.

// as they are created in `createSourceManagerForFile` so that they can be
// deleted in the reverse order as they are created.
std::unique_ptr<FileManager> FileMgr;
std::unique_ptr<DiagnosticOptions> DiagOpts;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like that in some cases we have a unique_ptr and later (ATSUnit) we use a shared_ptr<>. It leaves an author unable to know given some arbitrary DiagnosticOptions* what the lifetime and/or ownership rules are.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think I understand. Now that DiagnosticOptions are not intrusively reference-counted, raw pointers have clearer semantics than before (typically nullable non-owning borrow), no? I'd also argue that using values, references, raw pointers, unique_ptr and shared_ptr depending on the context is the clearest way to communicate lifetimes and ownership. Regardless, there's only one raw pointer to DiagnosticOptions remaining after my patch in clang::tooling::ToolInvocation, and that has exactly the semantics you'd expect: optional borrow where the owner is someone else and you expect them to keep the object alive long enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jansvoboda11 the problem is that now an author does not know if a given DiagnosticOption is a unique_ptr or a shared_ptr. A given DiagnosticOption* may or may not be protectable, etc depending on the context and origin of the object.

Philosophically I prefer intrusive refcounts over shared_ptr because to me they make the lifetime much clearer as the lifetime rules are embedded in the type, but I don't think that's an issue in this PR.

My understanding is that the goal of this PR is to say "For API purposes, a given DiagnosticOption reference is only live as long as the API object that vends it. As an implementation detail there are some cases where it can outlast the vending object, but that's not generally part of the user visible API."

That's a perfectly reasonable change, but my concern is that by mixing and matching shared and unique_ptr an author loses the ability to reason about what a given object's lifetime is. It seems like the reason for shared_ptr is to deal with some slightly gross bits of the API, and I wonder if it's possible to fix those APIs so we can just use unique_ptr everywhere?

@llvm-ci
Copy link
Collaborator

llvm-ci commented May 23, 2025

LLVM Buildbot has detected a new failure on builder llvm-x86_64-debian-dylib running on gribozavr4 while building clang-tools-extra,clang,lldb at step 5 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/60/builds/28206

Here is the relevant piece of the build log for the reference
Step 5 (build-unified-tree) failure: build (failure)
...
134.306 [2947/96/4298] Building CXX object tools/clang/tools/extra/clang-tidy/utils/CMakeFiles/obj.clangTidyUtils.dir/Matchers.cpp.o
134.336 [2946/96/4299] Building CXX object tools/clang/tools/extra/clang-tidy/utils/CMakeFiles/obj.clangTidyUtils.dir/ExprSequence.cpp.o
134.477 [2945/96/4300] Building CXX object tools/clang/tools/extra/clang-tidy/utils/CMakeFiles/obj.clangTidyUtils.dir/IncludeSorter.cpp.o
135.822 [2944/96/4301] Building CXX object tools/clang/lib/Analysis/plugins/SampleAnalyzer/CMakeFiles/SampleAnalyzerPlugin.dir/MainCallChecker.cpp.o
135.922 [2943/96/4302] Building CXX object tools/clang/tools/clang-extdef-mapping/CMakeFiles/clang-extdef-mapping.dir/ClangExtDefMapGen.cpp.o
136.682 [2942/96/4303] Building CXX object tools/clang/tools/extra/clang-tidy/zircon/CMakeFiles/obj.clangTidyZirconModule.dir/ZirconTidyModule.cpp.o
136.904 [2941/96/4304] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGVTT.cpp.o
136.960 [2940/96/4305] Building CXX object tools/clang/lib/ASTMatchers/CMakeFiles/obj.clangASTMatchers.dir/ASTMatchFinder.cpp.o
137.015 [2939/96/4306] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGExprConstant.cpp.o
137.053 [2938/96/4307] Building CXX object tools/clang/tools/extra/clang-tidy/plugin/CMakeFiles/obj.clangTidyPlugin.dir/ClangTidyPlugin.cpp.o
FAILED: tools/clang/tools/extra/clang-tidy/plugin/CMakeFiles/obj.clangTidyPlugin.dir/ClangTidyPlugin.cpp.o 
CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines,time_macros /usr/bin/ccache /usr/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/1/llvm-x86_64-debian-dylib/build/tools/clang/tools/extra/clang-tidy/plugin -I/b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin -I/b/1/llvm-x86_64-debian-dylib/build/tools/clang/tools/extra/clang-tidy -I/b/1/llvm-x86_64-debian-dylib/llvm-project/clang/include -I/b/1/llvm-x86_64-debian-dylib/build/tools/clang/include -I/b/1/llvm-x86_64-debian-dylib/build/include -I/b/1/llvm-x86_64-debian-dylib/llvm-project/llvm/include -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -std=c++17 -MD -MT tools/clang/tools/extra/clang-tidy/plugin/CMakeFiles/obj.clangTidyPlugin.dir/ClangTidyPlugin.cpp.o -MF tools/clang/tools/extra/clang-tidy/plugin/CMakeFiles/obj.clangTidyPlugin.dir/ClangTidyPlugin.cpp.o.d -o tools/clang/tools/extra/clang-tidy/plugin/CMakeFiles/obj.clangTidyPlugin.dir/ClangTidyPlugin.cpp.o -c /b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp:45:51: error: too few arguments to function call, expected 2, have 1
    Context->setDiagnosticsEngine(DiagEngine.get());
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                 ^
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/../ClangTidyDiagnosticConsumer.h:78:8: note: 'setDiagnosticsEngine' declared here
  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
       ^
In file included from /b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp:9:
In file included from /b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/../ClangTidy.h:12:
In file included from /b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/../ClangTidyDiagnosticConsumer.h:12:
In file included from /b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/../ClangTidyOptions.h:12:
In file included from /b/1/llvm-x86_64-debian-dylib/llvm-project/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h:66:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/memory:83:
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/unique_ptr.h:962:34: error: no matching constructor for initialization of 'clang::DiagnosticsEngine'
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                                 ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp:43:28: note: in instantiation of function template specialization 'std::make_unique<clang::DiagnosticsEngine, clang::DiagnosticIDs *, clang::DiagnosticOptions *, clang::tidy::ClangTidyDiagnosticConsumer *&>' requested here
    auto DiagEngine = std::make_unique<DiagnosticsEngine>(
                           ^
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang/include/clang/Basic/Diagnostic.h:568:12: note: candidate constructor not viable: no known conversion from 'clang::DiagnosticOptions *' to 'clang::DiagnosticOptions &' for 2nd argument; dereference the argument with *
  explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
           ^
/b/1/llvm-x86_64-debian-dylib/llvm-project/clang/include/clang/Basic/Diagnostic.h:572:3: note: candidate constructor not viable: requires 1 argument, but 3 were provided
  DiagnosticsEngine(const DiagnosticsEngine &) = delete;
  ^
2 errors generated.
137.157 [2938/95/4308] Building CXX object tools/clang/lib/AST/CMakeFiles/obj.clangAST.dir/ASTContext.cpp.o
137.359 [2938/94/4309] Building CXX object tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaDeclAttr.cpp.o
137.663 [2938/93/4310] Building CXX object tools/clang/tools/extra/clang-tidy/zircon/CMakeFiles/obj.clangTidyZirconModule.dir/TemporaryObjectsCheck.cpp.o
137.816 [2938/92/4311] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGException.cpp.o
137.905 [2938/91/4312] Building CXX object tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaChecking.cpp.o
138.004 [2938/90/4313] Building CXX object tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaLookup.cpp.o
138.072 [2938/89/4314] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGExprAgg.cpp.o
138.171 [2938/88/4315] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGExprComplex.cpp.o
138.278 [2938/87/4316] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGExprCXX.cpp.o
138.315 [2938/86/4317] Building CXX object tools/clang/tools/extra/clang-tidy/modernize/CMakeFiles/obj.clangTidyModernizeModule.dir/ConcatNestedNamespacesCheck.cpp.o
139.398 [2938/85/4318] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/ConstantInitBuilder.cpp.o
139.817 [2938/84/4319] Building CXX object tools/clang/tools/extra/clang-tidy/google/CMakeFiles/obj.clangTidyGoogleModule.dir/DefaultArgumentsCheck.cpp.o

@llvm-ci
Copy link
Collaborator

llvm-ci commented May 23, 2025

LLVM Buildbot has detected a new failure on builder clang-x86_64-debian-fast running on gribozavr4 while building clang-tools-extra,clang,lldb at step 5 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/56/builds/26567

Here is the relevant piece of the build log for the reference
Step 5 (build-unified-tree) failure: build (failure)
...
             ^~~~~~~~~~~~~~~~
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Serialization/ASTReader.h:1829:14: note: did you mean 'NewLoadedModuleFile'?
  /// \param LoadedModuleFile The optional out-parameter refers to the new
             ^~~~~~~~~~~~~~~~
             NewLoadedModuleFile
53 warnings generated.
174.514 [915/96/5272] Building CXX object tools/clang/lib/Format/CMakeFiles/obj.clangFormat.dir/Format.cpp.o
174.589 [914/96/5273] Linking CXX static library lib/libclangFormat.a
175.033 [913/96/5274] Linking CXX executable bin/clang-format
175.215 [912/96/5275] Building CXX object tools/clang/tools/clang-fuzzer/handle-cxx/CMakeFiles/obj.clangHandleCXX.dir/handle_cxx.cpp.o
FAILED: tools/clang/tools/clang-fuzzer/handle-cxx/CMakeFiles/obj.clangHandleCXX.dir/handle_cxx.cpp.o 
CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines,time_macros /usr/bin/ccache /usr/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/1/clang-x86_64-debian-fast/llvm.obj/tools/clang/tools/clang-fuzzer/handle-cxx -I/b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx -I/b/1/clang-x86_64-debian-fast/llvm.src/clang/include -I/b/1/clang-x86_64-debian-fast/llvm.obj/tools/clang/include -I/b/1/clang-x86_64-debian-fast/llvm.obj/include -I/b/1/clang-x86_64-debian-fast/llvm.src/llvm/include -I/b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx/. -std=c++11 -Wdocumentation -Wno-documentation-deprecated-sync -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -std=c++17 -MD -MT tools/clang/tools/clang-fuzzer/handle-cxx/CMakeFiles/obj.clangHandleCXX.dir/handle_cxx.cpp.o -MF tools/clang/tools/clang-fuzzer/handle-cxx/CMakeFiles/obj.clangHandleCXX.dir/handle_cxx.cpp.o.d -o tools/clang/tools/clang-fuzzer/handle-cxx/CMakeFiles/obj.clangHandleCXX.dir/handle_cxx.cpp.o -c /b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp:15:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/CodeGen/CodeGenAction.h:12:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Frontend/FrontendAction.h:23:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Frontend/ASTUnit.h:17:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ASTContext.h:21:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/Decl.h:17:
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/APValue.h:391:14: warning: parameter 'UninitArray' not found in the function declaration [-Wdocumentation]
  /// \param UninitArray Marker. Pass an empty UninitArray.
             ^~~~~~~~~~~
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/APValue.h:400:14: warning: parameter 'UninitStruct' not found in the function declaration [-Wdocumentation]
  /// \param UninitStruct Marker. Pass an empty UninitStruct.
             ^~~~~~~~~~~~
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp:15:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/CodeGen/CodeGenAction.h:12:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Frontend/FrontendAction.h:23:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Frontend/ASTUnit.h:17:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ASTContext.h:21:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/Decl.h:22:
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ExternalASTSource.h:165:39: warning: empty paragraph passed to '\param' command [-Wdocumentation]
  /// specializations for the \param D.
                              ~~~~~~~~^
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ExternalASTSource.h:165:38: warning: parameter 'D.' not found in the function declaration [-Wdocumentation]
  /// specializations for the \param D.
                                     ^~
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ExternalASTSource.h:171:44: warning: empty paragraph passed to '\param' command [-Wdocumentation]
  /// args specified by \param TemplateArgs.
                        ~~~~~~~~~~~~~~~~~~~^
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ExternalASTSource.h:171:32: warning: parameter 'TemplateArgs.' not found in the function declaration [-Wdocumentation]
  /// args specified by \param TemplateArgs.
                               ^~~~~~~~~~~~~
/b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/AST/ExternalASTSource.h:171:32: note: did you mean 'TemplateArgs'?
  /// args specified by \param TemplateArgs.
                               ^~~~~~~~~~~~~
                               TemplateArgs
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp:15:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/CodeGen/CodeGenAction.h:12:
In file included from /b/1/clang-x86_64-debian-fast/llvm.src/clang/include/clang/Frontend/FrontendAction.h:23:

searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request May 24, 2025
comgr and driver.cpp changes due to
13e1a2c Reapply "[clang] Remove intrusive reference count from `DiagnosticOptions` (llvm#139584)"
@jyknight
Copy link
Member

I'm trying to update some non-in-tree code after this change, and I don't think I understand the newly-expected lifetime rules after this change. I see all the comments that say this makes lifetime clearer...so I expect I'm just misunderstanding things.

Previously, DiagnosticsEngine kept a DiagnosticOptions member via IntrusiveRefCntPtr, which meant the DiagnosticsOptions lifetime would be at least as long as the DiagnosticsEngine.

Now, it stores a reference. Which means, I think, that the creator of a DiagnosticsEngine needs to somehow ensure by themselves that the DiagnosticsOptions value has a sufficiently long lifetime.

But this seems very hard to figure out what lifetimes should be now, because DiagnosticsEngine is, itself, refcounted. How does it make sense to have a borrowed reference to DiagnosticsOption in the refcounted DiagnosticsEngine type? ISTM the caller who creates a DiagnosticsEngine cannot now easily know what the lifetime of the DiagnosticsEngine is going to be, and thus, has no way to ensure the DiagnosticsOptions lifetime is correct?

@jansvoboda11
Copy link
Contributor Author

@jyknight If the lifetime of the DiagnosticsEngine in your code is not clearly bounded (and therefore there's no good place to create a DiagnosticOptions value such that it's guaranteed to outlive the engine), I'd suggest to wrap the options in std::shared_ptr and pass it around with the engine. (e.g. as std::pair<llvm::IntrusiveRefCntPtr<DiagnosticsEngine>, std::shared_ptr<DiagnosticOptions>>)

@jyknight
Copy link
Member

The problem is, it's hard to tell if it's clearly bounded or not. The code is passing a DiagnosticsEngine to various Clang APIs in CompilerInvocation/CompilerInstance areas, and how do I know whether those are expecting to keep the DiagnosticsEngine or not -- since it is, after all, an intrusive refcounted object!

Only after a bunch of code delving and exploration, is it possible to figure out.

Let's take this one example, and some of my thought process around it:

  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnostic_options(
      new clang::DiagnosticOptions());
  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
      clang::CompilerInstance::createDiagnostics(*file_system,
          diagnostic_options.get(),
          new clang::TextDiagnosticPrinter(llvm::errs(),
                                           diagnostic_options.get()));
  clang::CreateInvocationOptions ci_opts;
  ci_opts.Diags = diagnostics_engine;
  [...]
  std::shared_ptr<clang::CompilerInvocation> invocation = clang::createInvocation(..., ci_opts);

  auto compiler_instance = std::make_unique<clang::CompilerInstance>(invocation);
  compiler_instance->setDiagnostics(diagnostics_engine.get());
  [...]
  return compiler_instance;

I look at this and want to figure out what change I need to make. I see in some other code in this PR, the DiagnosticOptions was just put on the stack. Can I do that here?

Well, let me try to figure it out. The code first passes the DiagnosticsEngine to createInvocation. CreateInvocationOptions has a llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> member. That makes it seem like it'll keep the DiagnosticsEngine...but after a bunch of code investigation, I can figure out that CompilerInvocation does not (seem to, at least) store the passed-in DiagnosticsEngine, the construction only takes one to report errors. So here DiagnosticOptions doesn't need to outlive this stack-frame. (hope I got that right)

Next thing is using the Invocation to create a CompilerInstance. We call setDiagnostics on it. That is definitely scary. Unless maybe setDiagnostics copies the DiagnosticOptions?...No, doesn't seem to. CompilerInstance has an IntrusiveRefCntPtr<DiagnosticsEngine> member, which previously handled ownership of the DiagnosticsEngine and through that, the DiagnosticOptions, and ensured the lifetimes were sufficient. But the setDiagnostics function only just assigns to that, which means it now only takes shared ownership of the DiagnosticsEngine, not its contained DiagnosticOptions. OK, this will definitely be a lifetime problem. So it wouldn't be safe here, to create DiagnosticOptions on the stack.

Fine. So, where should I keep my DiagnosticOptions now? It looks like CompilerInvocation actually has a std::shared_ptr<DiagnosticOptions> DiagnosticOpts member...maybe I should use that? But I needed the DiagnosticEngine before the CompilerInvocation is created. So I guess that's not the right thing to do either...

And here is where I am now. Though now I'm thinking in this case maybe I can just drop the DiagnosticsEngine code in this snippet entirely since the default seems already to be to print to the errs() stream.

But should this really be this hard to figure out?

@jansvoboda11
Copy link
Contributor Author

Thanks for the concrete example! I think the key thing to realize is that the DiagnosticsEngine and DiagnosticOptions used for command-line parsing are typically throwaway and separate from those used for actual compilation. I suggest looking at how cc1_main() orchestrates this and why. The intent is for the DiagnosticsEngine used during the compilation (owned by CompilerInstance) to refer to the fully-formed DiagnosticsOptions (owned by CompilerInvocation).

So concretely, I'd rewrite your example as:

  clang::DiagnosticOptions diagnostic_options;
  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
      clang::CompilerInstance::createDiagnostics(
          *file_system, diagnostic_options,
          new clang::TextDiagnosticPrinter(llvm::errs(), diagnostic_options));
  clang::CreateInvocationOptions ci_opts;
  ci_opts.Diags = diagnostics_engine;
  // ...
  std::shared_ptr<clang::CompilerInvocation> invocation =
      clang::createInvocation(args, ci_opts);

  auto compiler_instance =
      std::make_unique<clang::CompilerInstance>(invocation);
  compiler_instance->createDiagnostics(*file_system));
  // ...
  return compiler_instance;

I agree the lifetimes shouldn't be this complicated. FWIW I'd like to get rid of the reference count of DiagnosticsEngine too, and make the lifetimes stricter and more explicit, but that's a lower priority compared to the DiagnosticOptions refactor for me.

github-merge-queue bot pushed a commit to carbon-language/carbon-lang that referenced this pull request Jun 4, 2025
Some updates required for
llvm/llvm-project#139584.

Co-authored-by: Josh L <[email protected]>
bricknerb pushed a commit to bricknerb/carbon-lang that referenced this pull request Jun 11, 2025
Some updates required for
llvm/llvm-project#139584.

Co-authored-by: Josh L <[email protected]>
@jyknight
Copy link
Member

Thanks for the concrete example! [..]

I just wanted to thank you (a bit late) for the explanation above, it was really helpful!

FWIW I'd like to get rid of the reference count of DiagnosticsEngine too, and make the lifetimes stricter and more explicit, but that's a lower priority compared to the DiagnosticOptions refactor for me.

I do hope that will happen someday, because that does seem to be a key part of the confusion here. But I totally understand about the priority.

yonghong-song pushed a commit to iovisor/bcc that referenced this pull request Jul 15, 2025
The build error message:
  src/cc/frontends/clang/loader.cc:400:73: error: no matching function for
   call to ‘clang::TextDiagnosticPrinter::TextDiagnosticPrinter(
     llvm::raw_fd_ostream&, clang::DiagnosticOptions*)’
  400 |   auto diag_client = new TextDiagnosticPrinter(llvm::errs(), &*diag_opts);
      |                                                                         ^
The llvm commit
  llvm/llvm-project#139584
caused the build failure.

Adjust the code properly and the error is fixed.
yonghong-song added a commit to iovisor/bcc that referenced this pull request Jul 15, 2025
The build error message:
  src/cc/frontends/clang/loader.cc:400:73: error: no matching function for
   call to ‘clang::TextDiagnosticPrinter::TextDiagnosticPrinter(
     llvm::raw_fd_ostream&, clang::DiagnosticOptions*)’
  400 |   auto diag_client = new TextDiagnosticPrinter(llvm::errs(), &*diag_opts);
      |                                                                         ^
The llvm commit
  llvm/llvm-project#139584
caused the build failure.

Adjust the code properly and the error is fixed.
@Michael137
Copy link
Member

FYI, the LLDB ASAN bots are failing with a use-after-free: https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake-sanitized/2622/console:

08:15:39  =================================================================
08:15:39  ==61103==ERROR: AddressSanitizer: heap-use-after-free on address 0x60600012cf40 at pc 0x00012140d304 bp 0x00016eecc850 sp 0x00016eecc848
08:15:39  READ of size 8 at 0x60600012cf40 thread T0
08:15:39      #0 0x00012140d300 in llvm::formatted_raw_ostream::releaseStream() FormattedStream.h:205
08:15:39      #1 0x00012140d3a4 in llvm::formatted_raw_ostream::~formatted_raw_ostream() FormattedStream.h:145
08:15:39      #2 0x00012604abf8 in clang::TextDiagnostic::~TextDiagnostic() TextDiagnostic.cpp:721
08:15:39      #3 0x00012605dc80 in clang::TextDiagnosticPrinter::~TextDiagnosticPrinter() TextDiagnosticPrinter.cpp:30
08:15:39      #4 0x00012605dd5c in clang::TextDiagnosticPrinter::~TextDiagnosticPrinter() TextDiagnosticPrinter.cpp:27
08:15:39      #5 0x0001231fb210 in (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() ClangModulesDeclVendor.cpp:47
08:15:39      #6 0x0001231fb3bc in (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() ClangModulesDeclVendor.cpp:47
08:15:39      #7 0x000129aa9d70 in clang::DiagnosticsEngine::~DiagnosticsEngine() Diagnostic.cpp:91
08:15:39      #8 0x0001230436b8 in llvm::RefCountedBase<clang::DiagnosticsEngine>::Release() const IntrusiveRefCntPtr.h:103
08:15:39      #9 0x0001231fe6c8 in (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() ClangModulesDeclVendor.cpp:93
08:15:39      #10 0x0001231fe858 in (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() ClangModulesDeclVendor.cpp:93
08:15:39      #11 0x00012320bce0 in lldb_private::ClangPersistentVariables::~ClangPersistentVariables() ClangPersistentVariables.h:43
08:15:39      #12 0x00012320b618 in lldb_private::ClangPersistentVariables::~ClangPersistentVariables() ClangPersistentVariables.h:43
08:15:39      #13 0x0001212c84d4 in lldb_private::ScratchTypeSystemClang::~ScratchTypeSystemClang() TypeSystemClang.h:1262
08:15:39      #14 0x00012057a5cc in llvm::DenseMapBase<llvm::DenseMap<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>, unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>::clear() DenseMap.h:144
08:15:39      #15 0x000120579ed8 in lldb_private::TypeSystemMap::Clear() TypeSystem.cpp:237
08:15:39      #16 0x000120702944 in lldb_private::Target::Destroy() Target.cpp:376
08:15:39      #17 0x00011faedbf8 in lldb::SBDebugger::DeleteTarget(lldb::SBTarget&) SBDebugger.cpp:949
08:15:39      #18 0x00011fe09664 in _wrap_SBDebugger_DeleteTarget(_object*, _object*) LLDBWrapPython.cpp:26998
08:15:39      #19 0x0001028d0fcc in cfunction_call+0x70 (Python:arm64+0xbcfcc)
08:15:39      #20 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #21 0x00010299cdac in _PyEval_EvalFrameDefault+0x1ac8 (Python:arm64+0x188dac)
08:15:39      #22 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #23 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #24 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #25 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #26 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #27 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #28 0x00010299d4c8 in _PyEval_EvalFrameDefault+0x21e4 (Python:arm64+0x1894c8)
08:15:39      #29 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #30 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #31 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #32 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #33 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #34 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #35 0x00010299d4c8 in _PyEval_EvalFrameDefault+0x21e4 (Python:arm64+0x1894c8)
08:15:39      #36 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #37 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #38 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #39 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #40 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #41 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #42 0x00010299cdac in _PyEval_EvalFrameDefault+0x1ac8 (Python:arm64+0x188dac)
08:15:39      #43 0x00010299b064 in PyEval_EvalCode+0xc4 (Python:arm64+0x187064)
08:15:39      #44 0x000102a0b9f4 in run_eval_code_obj+0x64 (Python:arm64+0x1f79f4)
08:15:39      #45 0x000102a0b43c in run_mod+0xa4 (Python:arm64+0x1f743c)
08:15:39      #46 0x000102a09ae4 in pyrun_file+0xa0 (Python:arm64+0x1f5ae4)
08:15:39      #47 0x000102a08e20 in _PyRun_SimpleFileObject+0xfc (Python:arm64+0x1f4e20)
08:15:39      #48 0x000102a08a58 in _PyRun_AnyFileObject+0x4c (Python:arm64+0x1f4a58)
08:15:39      #49 0x000102a306f4 in pymain_run_file_obj+0xa0 (Python:arm64+0x21c6f4)
08:15:39      #50 0x000102a303a0 in pymain_run_file+0x48 (Python:arm64+0x21c3a0)
08:15:39      #51 0x000102a2f610 in Py_RunMain+0x3c4 (Python:arm64+0x21b610)
08:15:39      #52 0x000102a2fc0c in pymain_main+0x12c (Python:arm64+0x21bc0c)
08:15:39      #53 0x000102a2fcac in Py_BytesMain+0x24 (Python:arm64+0x21bcac)
08:15:39      #54 0x0001952aeb94 in start+0x17b8 (dyld:arm64e+0xfffffffffff3ab94)
08:15:39  
08:15:39  0x60600012cf40 is located 32 bytes inside of 56-byte region [0x60600012cf20,0x60600012cf58)
08:15:39  freed by thread T0 here:
08:15:39      #0 0x0001018abb88 in _ZdlPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4bb88)
08:15:39      #1 0x0001231fb1c0 in (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() ClangModulesDeclVendor.cpp:47
08:15:39      #2 0x0001231fb3bc in (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() ClangModulesDeclVendor.cpp:47
08:15:39      #3 0x000129aa9d70 in clang::DiagnosticsEngine::~DiagnosticsEngine() Diagnostic.cpp:91
08:15:39      #4 0x0001230436b8 in llvm::RefCountedBase<clang::DiagnosticsEngine>::Release() const IntrusiveRefCntPtr.h:103
08:15:39      #5 0x0001231fe6c8 in (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() ClangModulesDeclVendor.cpp:93
08:15:39      #6 0x0001231fe858 in (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() ClangModulesDeclVendor.cpp:93
08:15:39      #7 0x00012320bce0 in lldb_private::ClangPersistentVariables::~ClangPersistentVariables() ClangPersistentVariables.h:43
08:15:39      #8 0x00012320b618 in lldb_private::ClangPersistentVariables::~ClangPersistentVariables() ClangPersistentVariables.h:43
08:15:39      #9 0x0001212c84d4 in lldb_private::ScratchTypeSystemClang::~ScratchTypeSystemClang() TypeSystemClang.h:1262
08:15:39      #10 0x00012057a5cc in llvm::DenseMapBase<llvm::DenseMap<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>, unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>::clear() DenseMap.h:144
08:15:39      #11 0x000120579ed8 in lldb_private::TypeSystemMap::Clear() TypeSystem.cpp:237
08:15:39      #12 0x000120702944 in lldb_private::Target::Destroy() Target.cpp:376
08:15:39      #13 0x00011faedbf8 in lldb::SBDebugger::DeleteTarget(lldb::SBTarget&) SBDebugger.cpp:949
08:15:39      #14 0x00011fe09664 in _wrap_SBDebugger_DeleteTarget(_object*, _object*) LLDBWrapPython.cpp:26998
08:15:39      #15 0x0001028d0fcc in cfunction_call+0x70 (Python:arm64+0xbcfcc)
08:15:39      #16 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #17 0x00010299cdac in _PyEval_EvalFrameDefault+0x1ac8 (Python:arm64+0x188dac)
08:15:39      #18 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #19 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #20 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #21 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #22 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #23 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #24 0x00010299d4c8 in _PyEval_EvalFrameDefault+0x21e4 (Python:arm64+0x1894c8)
08:15:39      #25 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #26 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #27 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #28 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #29 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39  
08:15:39  previously allocated by thread T0 here:
08:15:39      #0 0x0001018ab760 in _Znwm+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4b760)
08:15:39      #1 0x0001231f8dec in lldb_private::ClangModulesDeclVendor::Create(lldb_private::Target&) ClangModulesDeclVendor.cpp:732
08:15:39      #2 0x00012320af58 in lldb_private::ClangPersistentVariables::GetClangModulesDeclVendor() ClangPersistentVariables.cpp:124
08:15:39      #3 0x0001232111f0 in lldb_private::ClangUserExpression::PrepareForParsing(lldb_private::DiagnosticManager&, lldb_private::ExecutionContext&, bool) ClangUserExpression.cpp:536
08:15:39      #4 0x000123213790 in lldb_private::ClangUserExpression::Parse(lldb_private::DiagnosticManager&, lldb_private::ExecutionContext&, lldb_private::ExecutionPolicy, bool, bool) ClangUserExpression.cpp:647
08:15:39      #5 0x00012032b258 in lldb_private::UserExpression::Evaluate(lldb_private::ExecutionContext&, lldb_private::EvaluateExpressionOptions const&, llvm::StringRef, llvm::StringRef, std::__1::shared_ptr<lldb_private::ValueObject>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, lldb_private::ValueObject*) UserExpression.cpp:280
08:15:39      #6 0x000120724010 in lldb_private::Target::EvaluateExpression(llvm::StringRef, lldb_private::ExecutionContextScope*, std::__1::shared_ptr<lldb_private::ValueObject>&, lldb_private::EvaluateExpressionOptions const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, lldb_private::ValueObject*) Target.cpp:2905
08:15:39      #7 0x00011fc7bde0 in lldb::SBTarget::EvaluateExpression(char const*, lldb::SBExpressionOptions const&) SBTarget.cpp:2305
08:15:39      #8 0x00011fc7b66c in lldb::SBTarget::EvaluateExpression(char const*) SBTarget.cpp:2276
08:15:39      #9 0x00011ff14cfc in _wrap_SBTarget_EvaluateExpression(_object*, _object*) LLDBWrapPython.cpp:74282
08:15:39      #10 0x0001028d0fcc in cfunction_call+0x70 (Python:arm64+0xbcfcc)
08:15:39      #11 0x0001028744d8 in _PyObject_Call+0x7c (Python:arm64+0x604d8)
08:15:39      #12 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #13 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #14 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #15 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #16 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #17 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #18 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #19 0x00010299d4c8 in _PyEval_EvalFrameDefault+0x21e4 (Python:arm64+0x1894c8)
08:15:39      #20 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #21 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #22 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39      #23 0x000102874bd4 in _PyObject_Call_Prepend+0x84 (Python:arm64+0x60bd4)
08:15:39      #24 0x0001029055e8 in slot_tp_call+0x7c (Python:arm64+0xf15e8)
08:15:39      #25 0x0001028737f8 in _PyObject_MakeTpCall+0x74 (Python:arm64+0x5f7f8)
08:15:39      #26 0x00010299d4c8 in _PyEval_EvalFrameDefault+0x21e4 (Python:arm64+0x1894c8)
08:15:39      #27 0x000102876d14 in method_vectorcall+0xb8 (Python:arm64+0x62d14)
08:15:39      #28 0x0001029a0980 in _PyEval_EvalFrameDefault+0x569c (Python:arm64+0x18c980)
08:15:39      #29 0x000102873604 in _PyObject_VectorcallDictTstate+0x58 (Python:arm64+0x5f604)
08:15:39  
08:15:39  SUMMARY: AddressSanitizer: heap-use-after-free FormattedStream.h:205 in llvm::formatted_raw_ostream::releaseStream()
08:15:39  Shadow bytes around the buggy address:
08:15:39    0x60600012cc80: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd
08:15:39    0x60600012cd00: fd fd fd fd fa fa fa fa fd fd fd fd fd fd fd fa
08:15:39    0x60600012cd80: fa fa fa fa fd fd fd fd fd fd fd fa fa fa fa fa
08:15:39    0x60600012ce00: fd fd fd fd fd fd fd fa fa fa fa fa 00 00 00 00
08:15:39    0x60600012ce80: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fd
08:15:39  =>0x60600012cf00: fa fa fa fa fd fd fd fd[fd]fd fd fa fa fa fa fa
08:15:39    0x60600012cf80: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
08:15:39    0x60600012d000: 00 00 00 00 fa fa fa fa fa fa fa fa fa fa fa fa
08:15:39    0x60600012d080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
08:15:39    0x60600012d100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
08:15:39    0x60600012d180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
08:15:39  Shadow byte legend (one shadow byte represents 8 application bytes):
08:15:39    Addressable:           00
08:15:39    Partially addressable: 01 02 03 04 05 06 07 
08:15:39    Heap left redzone:       fa
08:15:39    Freed heap region:       fd
08:15:39    Stack left redzone:      f1
08:15:39    Stack mid redzone:       f2
08:15:39    Stack right redzone:     f3
08:15:39    Stack after return:      f5
08:15:39    Stack use after scope:   f8
08:15:39    Global redzone:          f9
08:15:39    Global init order:       f6
08:15:39    Poisoned by user:        f7
08:15:39    Container overflow:      fc
08:15:39    Array cookie:            ac
08:15:39    Intra object redzone:    bb
08:15:39    ASan internal:           fe
08:15:39    Left alloca redzone:     ca
08:15:39    Right alloca redzone:    cb
08:15:39  ==61103==ABORTING
08:15:39  PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
08:15:39  Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
08:15:39  0  liblldb.22.0.99git.dylib           0x00000001215d65c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 260
08:15:39  1  liblldb.22.0.99git.dylib           0x00000001215d0e14 llvm::sys::RunSignalHandlers() + 140
08:15:39  2  liblldb.22.0.99git.dylib           0x00000001215d87bc SignalHandler(int, __siginfo*, void*) + 1276
08:15:39  3  libsystem_platform.dylib           0x0000000195688624 _sigtramp + 56
08:15:39  4  libsystem_pthread.dylib            0x000000019564e88c pthread_kill + 296
08:15:39  5  libsystem_c.dylib                  0x0000000195557c60 abort + 124
08:15:39  6  libclang_rt.asan_osx_dynamic.dylib 0x00000001018c1b50 __sanitizer::Atexit(void (*)()) + 0
08:15:39  7  libclang_rt.asan_osx_dynamic.dylib 0x00000001018c1270 __sanitizer::Die() + 108
08:15:39  8  libclang_rt.asan_osx_dynamic.dylib 0x00000001018a51e8 __asan::ErrorDescription::Print() + 0
08:15:39  9  libclang_rt.asan_osx_dynamic.dylib 0x00000001018a4444 __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) + 1968
08:15:39  10 libclang_rt.asan_osx_dynamic.dylib 0x00000001018a5b84 __asan_report_load8 + 64
08:15:39  11 liblldb.22.0.99git.dylib           0x000000012140d304 llvm::formatted_raw_ostream::releaseStream() + 584
08:15:39  12 liblldb.22.0.99git.dylib           0x000000012140d3a8 llvm::formatted_raw_ostream::~formatted_raw_ostream() + 128
08:15:39  13 liblldb.22.0.99git.dylib           0x000000012604abfc clang::TextDiagnostic::~TextDiagnostic() + 76
08:15:39  14 liblldb.22.0.99git.dylib           0x000000012605dc84 clang::TextDiagnosticPrinter::~TextDiagnosticPrinter() + 316
08:15:39  15 liblldb.22.0.99git.dylib           0x000000012605dd60 clang::TextDiagnosticPrinter::~TextDiagnosticPrinter() + 24
08:15:39  16 liblldb.22.0.99git.dylib           0x00000001231fb214 (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() + 516
08:15:39  17 liblldb.22.0.99git.dylib           0x00000001231fb3c0 (anonymous namespace)::StoringDiagnosticConsumer::~StoringDiagnosticConsumer() + 24
08:15:39  18 liblldb.22.0.99git.dylib           0x0000000129aa9d74 clang::DiagnosticsEngine::~DiagnosticsEngine() + 268
08:15:39  19 liblldb.22.0.99git.dylib           0x00000001230436bc llvm::RefCountedBase<clang::DiagnosticsEngine>::Release() const + 120
08:15:39  20 liblldb.22.0.99git.dylib           0x00000001231fe6cc (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() + 628
08:15:39  21 liblldb.22.0.99git.dylib           0x00000001231fe85c (anonymous namespace)::ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() + 24
08:15:39  22 liblldb.22.0.99git.dylib           0x000000012320bce4 lldb_private::ClangPersistentVariables::~ClangPersistentVariables() + 424
08:15:39  23 liblldb.22.0.99git.dylib           0x000000012320b61c lldb_private::ClangPersistentVariables::~ClangPersistentVariables() + 24
08:15:39  24 liblldb.22.0.99git.dylib           0x00000001212c84d8 lldb_private::ScratchTypeSystemClang::~ScratchTypeSystemClang() + 336
08:15:39  25 liblldb.22.0.99git.dylib           0x000000012057a5d0 llvm::DenseMapBase<llvm::DenseMap<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>, unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>, llvm::DenseMapInfo<unsigned short, void>, llvm::detail::DenseMapPair<unsigned short, std::__1::shared_ptr<lldb_private::TypeSystem>>>::clear() + 512
08:15:39  26 liblldb.22.0.99git.dylib           0x0000000120579edc lldb_private::TypeSystemMap::Clear() + 952
08:15:39  27 liblldb.22.0.99git.dylib           0x0000000120702948 lldb_private::Target::Destroy() + 480
08:15:39  28 liblldb.22.0.99git.dylib           0x000000011faedbfc lldb::SBDebugger::DeleteTarget(lldb::SBTarget&) + 428
08:15:39  29 liblldb.22.0.99git.dylib           0x000000011fe09668 _wrap_SBDebugger_DeleteTarget(_object*, _object*) + 396
08:15:39  30 Python                             0x00000001028d0fd0 cfunction_call + 116
08:15:39  31 Python                             0x00000001028737fc _PyObject_MakeTpCall + 120
08:15:39  32 Python                             0x000000010299cdb0 _PyEval_EvalFrameDefault + 6860
08:15:39  33 Python                             0x0000000102876d18 method_vectorcall + 188
08:15:39  34 Python                             0x00000001029a0984 _PyEval_EvalFrameDefault + 22176
08:15:39  35 Python                             0x0000000102873608 _PyObject_VectorcallDictTstate + 92
08:15:39  36 Python                             0x0000000102874bd8 _PyObject_Call_Prepend + 136
08:15:39  37 Python                             0x00000001029055ec slot_tp_call + 128
08:15:39  38 Python                             0x00000001028737fc _PyObject_MakeTpCall + 120
08:15:39  39 Python                             0x000000010299d4cc _PyEval_EvalFrameDefault + 8680
08:15:39  40 Python                             0x0000000102876d18 method_vectorcall + 188
08:15:39  41 Python                             0x00000001029a0984 _PyEval_EvalFrameDefault + 22176
08:15:39  42 Python                             0x0000000102873608 _PyObject_VectorcallDictTstate + 92
08:15:39  43 Python                             0x0000000102874bd8 _PyObject_Call_Prepend + 136
08:15:39  44 Python                             0x00000001029055ec slot_tp_call + 128
08:15:39  45 Python                             0x00000001028737fc _PyObject_MakeTpCall + 120
08:15:39  46 Python                             0x000000010299d4cc _PyEval_EvalFrameDefault + 8680
08:15:39  47 Python                             0x0000000102876d18 method_vectorcall + 188
08:15:39  48 Python                             0x00000001029a0984 _PyEval_EvalFrameDefault + 22176
08:15:39  49 Python                             0x0000000102873608 _PyObject_VectorcallDictTstate + 92
08:15:39  50 Python                             0x0000000102874bd8 _PyObject_Call_Prepend + 136
08:15:39  51 Python                             0x00000001029055ec slot_tp_call + 128
08:15:39  52 Python                             0x00000001028737fc _PyObject_MakeTpCall + 120
08:15:39  53 Python                             0x000000010299cdb0 _PyEval_EvalFrameDefault + 6860
08:15:39  54 Python                             0x000000010299b068 PyEval_EvalCode + 200
08:15:39  55 Python                             0x0000000102a0b9f8 run_eval_code_obj + 104
08:15:39  56 Python                             0x0000000102a0b440 run_mod + 168
08:15:39  57 Python                             0x0000000102a09ae8 pyrun_file + 164
08:15:39  58 Python                             0x0000000102a08e24 _PyRun_SimpleFileObject + 256
08:15:39  59 Python                             0x0000000102a08a5c _PyRun_AnyFileObject + 80
08:15:39  60 Python                             0x0000000102a306f8 pymain_run_file_obj + 164
08:15:39  61 Python                             0x0000000102a303a4 pymain_run_file + 76
08:15:39  62 Python                             0x0000000102a2f614 Py_RunMain + 968
08:15:39  63 Python                             0x0000000102a2fc10 pymain_main + 304
08:15:39  64 Python                             0x0000000102a2fcb0 Py_BytesMain + 40
08:15:39  65 dyld                               0x00000001952aeb98 start + 6076

Currently investigating..

@jansvoboda11
Copy link
Contributor Author

@ Michael137 Thanks for the heads-up, I'll try to take a look as well.

drodriguez added a commit to drodriguez/swift that referenced this pull request Nov 11, 2025
…r rebranch

Upstream LLVM in llvm/llvm-project#139584 changed `DiagnosticOptions`
from being a referenced counted object to just be a reference, not owned
by the `clang::DiagnosticEngine`.

In 0981b71 (part of swiftlang#82243), the usages
of the Swift repository were adapted to the new memory model, but it
introduced at least one use-after-free and a potential one around the
usage of Clang in the Clang Importer.

This commit tries to fix the use-after-free in both cases, by returning
a `unique_ptr` to the `clang::DiagnosticOptions`, which makes the
lifetime of the `DiagnosticOptions` match the lifetime of the variable
that uses it (normally a `CompilerInvocation`).

Other cases in 0981b71 should be safe
because the lifetime of the `DiagnosticOptions` do not seem to propagate beyond
the scope of the functions where they live (but I am not fully sure
about the one in `IDETool/CompilerInvocation.cpp` completely).

This was causing compiler crashes during the test
`Interop/Cxx/stdlib/unsupported-stdlib.swift` which eventually uses
`createClangDriver` and tries to emit a diagnostic, which in some cases
was reading the memory from `DiagnosticOptions` when it was already out
of scope.
drodriguez added a commit to swiftlang/swift that referenced this pull request Nov 12, 2025
…r rebranch (#85445)

Upstream LLVM in llvm/llvm-project#139584 changed `DiagnosticOptions`
from being a referenced counted object to just be a reference, not owned
by the `clang::DiagnosticEngine`.

In 0981b71 (part of #82243), the usages
of the Swift repository were adapted to the new memory model, but it
introduced at least one use-after-free and a potential one around the
usage of Clang in the Clang Importer.

This commit tries to fix the use-after-free in both cases, by returning
a `unique_ptr` to the `clang::DiagnosticOptions`, which makes the
lifetime of the `DiagnosticOptions` match the lifetime of the variable
that uses it (normally a `CompilerInvocation`).

Other cases in 0981b71 should be safe
because the lifetime of the `DiagnosticOptions` do not seem to propagate
beyond the scope of the functions where they live (but I am not fully
sure about the one in `IDETool/CompilerInvocation.cpp` completely).

This was causing compiler crashes during the test
`Interop/Cxx/stdlib/unsupported-stdlib.swift` which eventually uses
`createClangDriver` and tries to emit a diagnostic, which in some cases
was reading the memory from `DiagnosticOptions` when it was already out
of scope.
@Michael137
Copy link
Member

Apologies, the use-after-free was actually due to: 09262656f32ab3f2e1d82e5342ba37eecac52522

Just happened to touch similar parts of LLDB

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:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category clang-format clang-tidy clang-tools-extra clangd HLSL HLSL Language Support lldb

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants