clang 24.0.0git
CIRDiagnosticHandler.cpp
Go to the documentation of this file.
1//===--- CIRDiagnosticHandler.cpp - Route MLIR diags to clang ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "mlir/IR/BuiltinAttributes.h"
12#include "mlir/IR/Diagnostics.h"
13#include "mlir/IR/Location.h"
14#include "mlir/IR/MLIRContext.h"
15
21
22#include "llvm/ADT/Twine.h"
23#include "llvm/Support/ErrorHandling.h"
24
25#include <cassert>
26#include <optional>
27#include <string>
28
29namespace cir {
30
34 clang::FileManager &fileMgr)
35 : mlir::ScopedDiagnosticHandler(ctx), Diags(diags), SrcMgr(srcMgr),
36 FileMgr(fileMgr) {
37 setHandler([this](mlir::Diagnostic &D) { return handle(D); });
38}
39
40clang::SourceLocation CIRDiagnosticHandler::translateLoc(mlir::Location loc) {
41 // Walk common location wrappers to reach a usable file/line/column triple.
42 // Anything we can't translate becomes an invalid SourceLocation, which the
43 // diagnostics engine renders without a source line.
44 if (auto file = mlir::dyn_cast<mlir::FileLineColLoc>(loc)) {
45 // SourceManager::translateFileLineCol requires 1-based line/column.
46 // Module-level locations carry (0, 0); fall through unattached.
47 if (file.getLine() == 0 || file.getColumn() == 0)
48 return clang::SourceLocation();
49 auto fileRef = FileMgr.getOptionalFileRef(file.getFilename().getValue());
50 if (!fileRef)
51 return clang::SourceLocation();
52 return SrcMgr.translateFileLineCol(&fileRef->getFileEntry(), file.getLine(),
53 file.getColumn());
54 }
55 if (auto fused = mlir::dyn_cast<mlir::FusedLoc>(loc)) {
56 for (mlir::Location child : fused.getLocations()) {
57 clang::SourceLocation translated = translateLoc(child);
58 if (translated.isValid())
59 return translated;
60 }
61 return clang::SourceLocation();
62 }
63 if (auto callsite = mlir::dyn_cast<mlir::CallSiteLoc>(loc))
64 return translateLoc(callsite.getCallee());
65 if (auto named = mlir::dyn_cast<mlir::NameLoc>(loc))
66 return translateLoc(named.getChildLoc());
67 // OpaqueLoc / UnknownLoc and anything else fall through unattached.
68 return clang::SourceLocation();
69}
70
71// Returns the first file/line/column location with a known line nested in
72// \p loc, walking the same wrappers as translateLoc.
73static std::optional<mlir::FileLineColLoc>
74findFileLineColLoc(mlir::Location loc) {
75 if (auto file = mlir::dyn_cast<mlir::FileLineColLoc>(loc)) {
76 if (file.getLine() == 0 || file.getColumn() == 0)
77 return std::nullopt;
78 return file;
79 }
80 if (auto fused = mlir::dyn_cast<mlir::FusedLoc>(loc)) {
81 for (mlir::Location child : fused.getLocations())
82 if (std::optional<mlir::FileLineColLoc> file = findFileLineColLoc(child))
83 return file;
84 return std::nullopt;
85 }
86 if (auto callsite = mlir::dyn_cast<mlir::CallSiteLoc>(loc))
87 return findFileLineColLoc(callsite.getCallee());
88 if (auto named = mlir::dyn_cast<mlir::NameLoc>(loc))
89 return findFileLineColLoc(named.getChildLoc());
90 return std::nullopt;
91}
92
93void CIRDiagnosticHandler::emit(mlir::Diagnostic &diag, bool isNote) {
94 unsigned diagID;
95 if (isNote) {
96 assert(diag.getSeverity() == mlir::DiagnosticSeverity::Note &&
97 "a note attached to a diagnostic must have Note severity");
98 diagID = clang::diag::note_cir_mlir_diagnostic;
99 } else {
100 switch (diag.getSeverity()) {
101 case mlir::DiagnosticSeverity::Error:
102 diagID = clang::diag::err_cir_mlir_diagnostic;
103 break;
104 case mlir::DiagnosticSeverity::Warning:
105 diagID = clang::diag::warn_cir_mlir_diagnostic;
106 break;
107 case mlir::DiagnosticSeverity::Remark:
108 diagID = clang::diag::remark_cir_mlir_diagnostic;
109 break;
110 case mlir::DiagnosticSeverity::Note:
111 llvm_unreachable("a top-level MLIR diagnostic should not have Note "
112 "severity; notes arrive via getNotes()");
113 }
114 }
115 clang::SourceLocation loc = translateLoc(diag.getLocation());
116 std::string message = diag.str();
117 // A location in a file that is not loaded in the SourceManager, such as the
118 // original source of parsed ClangIR input, cannot be attached to the
119 // diagnostic. Keep it as text so the user can still find the code.
120 if (loc.isInvalid())
121 if (std::optional<mlir::FileLineColLoc> file =
122 findFileLineColLoc(diag.getLocation()))
123 message = (llvm::Twine(file->getFilename().getValue()) + ":" +
124 llvm::Twine(file->getLine()) + ":" +
125 llvm::Twine(file->getColumn()) + ": " + message)
126 .str();
127 Diags.Report(loc, diagID) << message;
128}
129
130mlir::LogicalResult CIRDiagnosticHandler::handle(mlir::Diagnostic &diag) {
131 emit(diag, /*isNote=*/false);
132 for (mlir::Diagnostic &note : diag.getNotes())
133 emit(note, /*isNote=*/true);
134 return mlir::success();
135}
136
137} // namespace cir
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
CIRDiagnosticHandler(mlir::MLIRContext *ctx, clang::DiagnosticsEngine &diags, clang::SourceManager &srcMgr, clang::FileManager &fileMgr)
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:241
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:57
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Get a FileEntryRef if it exists, without doing anything on error.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
SourceLocation translateFileLineCol(const FileEntry *SourceFile, unsigned Line, unsigned Col) const
Get the source location for the given file:line:col triplet.
static std::optional< mlir::FileLineColLoc > findFileLineColLoc(mlir::Location loc)