[clang] [CodeGen][CIR] Split out Backend Diags to utils, impl CIR error-attr (PR #225966)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 29 13:57:43 PDT 2026


================
@@ -0,0 +1,660 @@
+//===--- BackendDiagnosticHandler.cpp - Shared Backend Diagnostics ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/BackendDiagnosticHandler.h"
+#include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+/// Forwards llvm::DiagnosticHandler callbacks into a BackendDiagnosticConsumer.
+class BackendDiagnosticHandlerImpl final : public DiagnosticHandler {
+public:
+  BackendDiagnosticHandlerImpl(const CodeGenOptions &CGOpts,
+                               BackendDiagnosticConsumer *Consumer)
+      : CodeGenOpts(CGOpts), Consumer(Consumer) {}
+
+  bool handleDiagnostics(const DiagnosticInfo &DI) override {
+    Consumer->handleDiagnostics(DI);
+    return true;
+  }
+
+  bool isAnalysisRemarkEnabled(StringRef PassName) const override {
+    return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(PassName);
+  }
+  bool isMissedOptRemarkEnabled(StringRef PassName) const override {
+    return CodeGenOpts.OptimizationRemarkMissed.patternMatches(PassName);
+  }
+  bool isPassedOptRemarkEnabled(StringRef PassName) const override {
+    return CodeGenOpts.OptimizationRemark.patternMatches(PassName);
+  }
+
+  bool isAnyRemarkEnabled() const override {
+    return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
+           CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
+           CodeGenOpts.OptimizationRemark.hasValidPattern();
+  }
+
+private:
+  const CodeGenOptions &CodeGenOpts;
+  BackendDiagnosticConsumer *Consumer;
+};
+
+/// Convert a location in a temporary llvm::SourceMgr buffer to be a valid
+/// FullSourceLoc.
+FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
+                                     SourceManager &CSM) {
+  // Get both the clang and llvm source managers. The location is relative to
+  // a memory buffer that the LLVM Source Manager is handling, we need to add
+  // a copy to the Clang source manager.
+  const llvm::SourceMgr &LSM = *D.getSourceMgr();
+
+  // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr
+  // already owns its one and clang::SourceManager wants to own its one.
+  const MemoryBuffer *LBuf =
+      LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+
+  // Create the copy and transfer ownership to clang::SourceManager.
+  // TODO: Avoid copying files into memory.
+  std::unique_ptr<llvm::MemoryBuffer> CBuf =
+      llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
+                                           LBuf->getBufferIdentifier());
+  // FIXME: Keep a file ID map instead of creating new IDs for each location.
+  FileID FID = CSM.createFileID(std::move(CBuf));
+
+  // Translate the offset into the file.
+  unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+  SourceLocation NewLoc =
+      CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset);
+  return FullSourceLoc(NewLoc, CSM);
+}
+
+} // namespace
+
+#define ComputeDiagID(Severity, GroupName, DiagID)                             \
+  do {                                                                         \
+    switch (Severity) {                                                        \
+    case llvm::DS_Error:                                                       \
+      DiagID = diag::err_fe_##GroupName;                                       \
+      break;                                                                   \
+    case llvm::DS_Warning:                                                     \
+      DiagID = diag::warn_fe_##GroupName;                                      \
+      break;                                                                   \
+    case llvm::DS_Remark:                                                      \
+      llvm_unreachable("'remark' severity not expected");                      \
+      break;                                                                   \
+    case llvm::DS_Note:                                                        \
+      DiagID = diag::note_fe_##GroupName;                                      \
+      break;                                                                   \
+    }                                                                          \
+  } while (false)
+
+#define ComputeDiagRemarkID(Severity, GroupName, DiagID)                       \
+  do {                                                                         \
+    switch (Severity) {                                                        \
+    case llvm::DS_Error:                                                       \
+      DiagID = diag::err_fe_##GroupName;                                       \
+      break;                                                                   \
+    case llvm::DS_Warning:                                                     \
+      DiagID = diag::warn_fe_##GroupName;                                      \
+      break;                                                                   \
+    case llvm::DS_Remark:                                                      \
+      DiagID = diag::remark_fe_##GroupName;                                    \
+      break;                                                                   \
+    case llvm::DS_Note:                                                        \
+      DiagID = diag::note_fe_##GroupName;                                      \
+      break;                                                                   \
+    }                                                                          \
+  } while (false)
+
+std::unique_ptr<llvm::DiagnosticHandler>
+BackendDiagnosticConsumer::createDiagnosticHandler() {
+  return std::make_unique<BackendDiagnosticHandlerImpl>(CodeGenOpts, this);
+}
+
+void BackendDiagnosticConsumer::addFunctionSourceLocation(StringRef MangledName,
+                                                          FullSourceLoc Loc) {
+  // TODO: use a fast content hash when available.
+  auto NameHash = llvm::hash_value(MangledName);
+  ManglingFullSourceLocs.push_back(std::make_pair(NameHash, Loc));
+}
+
+std::optional<FullSourceLoc>
+BackendDiagnosticConsumer::getFunctionSourceLocation(const Function &F) const {
+  auto Hash = llvm::hash_value(F.getName());
+  for (const auto &Pair : ManglingFullSourceLocs) {
+    if (Pair.first == Hash)
+      return Pair.second;
+  }
+  return std::nullopt;
+}
+
+FullSourceLoc BackendDiagnosticConsumer::getBestLocationFromDebugLoc(
----------------
erichkeane wrote:

Typically non-ref returns don't get const because its a little silly (since it is just going to copy).  BUT I'll put that in to match the previous version.

https://github.com/llvm/llvm-project/pull/225966


More information about the cfe-commits mailing list