From 9e306ad4600c4d3392c194a8be88919ee758425c Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 22 May 2025 12:33:52 -0700 Subject: [clang] Remove intrusive reference count from `DiagnosticOptions` (#139584) 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: ```c++ void shareOwnership(CompilerInvocation &CI) { llvm::IntrusiveRefCntPtr 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. --- clang/lib/Frontend/CompilerInstance.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'clang/lib/Frontend/CompilerInstance.cpp') diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 503d364..cc39049 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -280,20 +280,20 @@ static void collectVFSEntries(CompilerInstance &CI, } // Diagnostics -static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, +static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts, const CodeGenOptions *CodeGenOpts, DiagnosticsEngine &Diags) { std::error_code EC; std::unique_ptr StreamOwner; raw_ostream *OS = &llvm::errs(); - if (DiagOpts->DiagnosticLogFile != "-") { + if (DiagOpts.DiagnosticLogFile != "-") { // Create the output stream. auto FileOS = std::make_unique( - DiagOpts->DiagnosticLogFile, EC, + DiagOpts.DiagnosticLogFile, EC, llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF); if (EC) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) - << DiagOpts->DiagnosticLogFile << EC.message(); + << DiagOpts.DiagnosticLogFile << EC.message(); } else { FileOS->SetUnbuffered(); OS = FileOS.get(); @@ -315,7 +315,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, } } -static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, +static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts, DiagnosticsEngine &Diags, StringRef OutputFile) { auto SerializedConsumer = @@ -333,12 +333,12 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, void CompilerInstance::createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticConsumer *Client, bool ShouldOwnClient) { - Diagnostics = createDiagnostics(VFS, &getDiagnosticOpts(), Client, + Diagnostics = createDiagnostics(VFS, getDiagnosticOpts(), Client, ShouldOwnClient, &getCodeGenOpts()); } IntrusiveRefCntPtr CompilerInstance::createDiagnostics( - llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts, + llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts, DiagnosticConsumer *Client, bool ShouldOwnClient, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); @@ -349,25 +349,24 @@ IntrusiveRefCntPtr CompilerInstance::createDiagnostics( // implementing -verify. if (Client) { Diags->setClient(Client, ShouldOwnClient); - } else if (Opts->getFormat() == DiagnosticOptions::SARIF) { + } else if (Opts.getFormat() == DiagnosticOptions::SARIF) { Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts)); } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. - if (Opts->VerifyDiagnostics) + if (Opts.VerifyDiagnostics) Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. - if (!Opts->DiagnosticLogFile.empty()) + if (!Opts.DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - if (!Opts->DiagnosticSerializationFile.empty()) - SetupSerializedDiagnostics(Opts, *Diags, - Opts->DiagnosticSerializationFile); + if (!Opts.DiagnosticSerializationFile.empty()) + SetupSerializedDiagnostics(Opts, *Diags, Opts.DiagnosticSerializationFile); // Configure our handling of diagnostics. - ProcessWarningOptions(*Diags, *Opts, VFS); + ProcessWarningOptions(*Diags, Opts, VFS); return Diags; } -- cgit v1.1