MLIR 22.0.0git
DiagnosedSilenceableFailure.h
Go to the documentation of this file.
1//===- DiagnosedSilenceableFailure.h - Tri-state result ----------- C++ -*-===//
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//
9// This file declares the DiagnosedSilenceableFailure class allowing to store
10// a tri-state result (definite failure, recoverable failure, success) with an
11// optional associated list of diagnostics.
12//
13//===----------------------------------------------------------------------===//
14
15#include "mlir/IR/Diagnostics.h"
16#include "mlir/IR/Operation.h"
17#include <optional>
18
19#ifndef MLIR_DIALECT_TRANSFORM_UTILS_DIAGNOSEDSILENCEABLEFAILURE_H
20#define MLIR_DIALECT_TRANSFORM_UTILS_DIAGNOSEDSILENCEABLEFAILURE_H
21
22namespace mlir {
23/// The result of a transform IR operation application. This can have one of the
24/// three states:
25/// - success;
26/// - silenceable (recoverable) failure with yet-unreported diagnostic;
27/// - definite failure.
28/// Silenceable failure is intended to communicate information about
29/// transformations that did not apply but in a way that supports recovery,
30/// for example, they did not modify the payload IR or modified it in some
31/// predictable way. They are associated with a Diagnostic that provides more
32/// details on the failure. Silenceable failure can be discarded, turning the
33/// result into success, or "reported", emitting the diagnostic and turning the
34/// result into definite failure.
35/// Transform IR operations containing other operations are allowed to do either
36/// with the results of the nested transformations, but must propagate definite
37/// failures as their diagnostics have been already reported to the user.
38class [[nodiscard]] DiagnosedSilenceableFailure {
39public:
46
47 /// Constructs a DiagnosedSilenceableFailure in the success state.
49 return DiagnosedSilenceableFailure(::mlir::success());
50 }
51
52 /// Constructs a DiagnosedSilenceableFailure in the failure state. Typically,
53 /// a diagnostic has been emitted before this.
55 return DiagnosedSilenceableFailure(::mlir::failure());
56 }
57
58 /// Constructs a DiagnosedSilenceableFailure in the silenceable failure state,
59 /// ready to emit the given diagnostic. This is considered a failure
60 /// regardless of the diagnostic severity.
62 return DiagnosedSilenceableFailure(std::forward<Diagnostic>(diag));
63 }
69
70 /// Converts all kinds of failure into a LogicalResult failure, emitting the
71 /// diagnostic if necessary. Must not be called more than once.
72 LogicalResult checkAndReport();
73
74 /// Returns `true` if this is a success.
75 bool succeeded() const {
76 return ::mlir::succeeded(result) && diagnostics.empty();
77 }
78
79 /// Returns `true` if this is a definite failure.
80 bool isDefiniteFailure() const {
81 return ::mlir::failed(result) && diagnostics.empty();
82 }
83
84 /// Returns `true` if this is a silenceable failure.
85 bool isSilenceableFailure() const { return !diagnostics.empty(); }
86
87 /// Returns the diagnostic message without emitting it. Expects this object
88 /// to be a silenceable failure.
89 std::string getMessage() const {
90 std::string res;
91 for (auto &diagnostic : diagnostics) {
92 res.append(diagnostic.str());
93 res.append("\n");
94 }
95 return res;
96 }
97
98 /// Returns a string representation of the failure mode (for error reporting).
99 std::string getStatusString() const {
100 if (succeeded())
101 return "success";
103 return "silenceable failure";
104 return "definite failure";
105 }
106
107 /// Converts silenceable failure into LogicalResult success without reporting
108 /// the diagnostic, preserves the other states.
109 LogicalResult silence() {
110 if (!diagnostics.empty()) {
111 diagnostics.clear();
112 result = ::mlir::success();
113 }
114 return result;
115 }
116
117 /// Take the diagnostics and silence.
119 assert(!diagnostics.empty() && "expected a diagnostic to be present");
120 diags.append(std::make_move_iterator(diagnostics.begin()),
121 std::make_move_iterator(diagnostics.end()));
122 }
123
124 /// Streams the given values into the last diagnostic.
125 /// Expects this object to be a silenceable failure.
126 template <typename T>
128 assert(isSilenceableFailure() &&
129 "can only append output in silenceable failure state");
130 diagnostics.back() << std::forward<T>(value);
131 return *this;
132 }
133 template <typename T>
135 return std::move(this->operator<<(std::forward<T>(value)));
136 }
137
138 /// Attaches a note to the last diagnostic.
139 /// Expects this object to be a silenceable failure.
140 Diagnostic &attachNote(std::optional<Location> loc = std::nullopt) {
141 assert(isSilenceableFailure() &&
142 "can only attach notes to silenceable failures");
143 return diagnostics.back().attachNote(loc);
144 }
145
146private:
147 explicit DiagnosedSilenceableFailure(LogicalResult result) : result(result) {}
148 explicit DiagnosedSilenceableFailure(Diagnostic &&diagnostic)
149 : result(failure()) {
150 diagnostics.emplace_back(std::move(diagnostic));
151 }
152 explicit DiagnosedSilenceableFailure(SmallVector<Diagnostic> &&diagnostics)
153 : diagnostics(std::move(diagnostics)), result(failure()) {}
154
155 /// The diagnostics associated with this object. If non-empty, the object is
156 /// considered to be in the silenceable failure state regardless of the
157 /// `result` field.
158 SmallVector<Diagnostic, 1> diagnostics;
159
160 /// The "definite" logical state, either success or failure.
161 /// Ignored if the diagnostics message is present.
162 LogicalResult result;
163
164#if LLVM_ENABLE_ABI_BREAKING_CHECKS
165 /// Whether the associated diagnostics have been reported.
166 /// Diagnostics reporting consumes the diagnostics, so we need a mechanism to
167 /// differentiate reported diagnostics from a state where it was never
168 /// created.
169 bool reported = false;
170#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
171};
172
174
176 const Twine &message = {});
177
178/// A compatibility class connecting `InFlightDiagnostic` to
179/// `DiagnosedSilenceableFailure` while providing an interface similar to the
180/// former. Implicitly convertible to `DiagnosticSilenceableFailure` in definite
181/// failure state and to `LogicalResult` failure. Reports the error on
182/// conversion or on destruction. Instances of this class can be created by
183/// `emitDefiniteFailure()`.
186 const Twine &message);
187
188public:
189 /// Only move-constructible because it carries an in-flight diagnostic.
191
192 /// Forward the message to the diagnostic.
193 template <typename T>
195 diag << std::forward<T>(value);
196 return *this;
197 }
198 template <typename T>
200 return std::move(this->operator<<(std::forward<T>(value)));
201 }
202
203 /// Attaches a note to the error.
204 Diagnostic &attachNote(std::optional<Location> loc = std::nullopt) {
205 return diag.attachNote(loc);
206 }
207
208 /// Implicit conversion to DiagnosedSilenceableFailure in the definite failure
209 /// state. Reports the error.
211 diag.report();
213 }
214
215 /// Implicit conversion to LogicalResult in the failure state. Reports the
216 /// error.
217 operator LogicalResult() {
218 diag.report();
219 return failure();
220 }
221
222private:
223 /// Constructs a definite failure at the given location with the given
224 /// message.
225 explicit DiagnosedDefiniteFailure(Location loc, const Twine &message)
226 : diag(emitError(loc, message)) {}
227
228 /// Copy-construction and any assignment is disallowed to prevent repeated
229 /// error reporting.
232 operator=(const DiagnosedDefiniteFailure &) = delete;
234
235 /// The error message.
236 InFlightDiagnostic diag;
237};
238
239/// Emits a definite failure with the given message. The returned object allows
240/// for last-minute modification to the error message, such as attaching notes
241/// and completing the message. It will be reported when the object is
242/// destructed or converted.
244 const Twine &message) {
245 return DiagnosedDefiniteFailure(loc, message);
246}
248 const Twine &message = {}) {
249 return emitDefiniteFailure(op->getLoc(), message);
250}
251
252/// Emits a silenceable failure with the given message. A silenceable failure
253/// must be either suppressed or converted into a definite failure and reported
254/// to the user.
256emitSilenceableFailure(Location loc, const Twine &message = {}) {
257 Diagnostic diag(loc, DiagnosticSeverity::Error);
258 diag << message;
260}
262emitSilenceableFailure(Operation *op, const Twine &message = {}) {
263 return emitSilenceableFailure(op->getLoc(), message);
264}
265} // namespace mlir
266
267#endif // MLIR_DIALECT_TRANSFORM_UTILS_DIAGNOSEDSILENCEABLEFAILURE_H
static std::string diag(const llvm::Value &value)
A compatibility class connecting InFlightDiagnostic to DiagnosedSilenceableFailure while providing an...
DiagnosedDefiniteFailure & operator<<(T &&value) &
Forward the message to the diagnostic.
friend DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message)
Emits a definite failure with the given message.
DiagnosedDefiniteFailure && operator<<(T &&value) &&
DiagnosedDefiniteFailure(DiagnosedDefiniteFailure &&)=default
Only move-constructible because it carries an in-flight diagnostic.
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the error.
The result of a transform IR operation application.
LogicalResult silence()
Converts silenceable failure into LogicalResult success without reporting the diagnostic,...
DiagnosedSilenceableFailure & operator=(DiagnosedSilenceableFailure &&)=default
static DiagnosedSilenceableFailure success()
Constructs a DiagnosedSilenceableFailure in the success state.
std::string getStatusString() const
Returns a string representation of the failure mode (for error reporting).
std::string getMessage() const
Returns the diagnostic message without emitting it.
DiagnosedSilenceableFailure(DiagnosedSilenceableFailure &&)=default
bool isDefiniteFailure() const
Returns true if this is a definite failure.
static DiagnosedSilenceableFailure silenceableFailure(SmallVector< Diagnostic > &&diag)
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the last diagnostic.
DiagnosedSilenceableFailure(const DiagnosedSilenceableFailure &)=delete
static DiagnosedSilenceableFailure silenceableFailure(Diagnostic &&diag)
Constructs a DiagnosedSilenceableFailure in the silenceable failure state, ready to emit the given di...
void takeDiagnostics(SmallVectorImpl< Diagnostic > &diags)
Take the diagnostics and silence.
DiagnosedSilenceableFailure & operator=(const DiagnosedSilenceableFailure &)=delete
bool succeeded() const
Returns true if this is a success.
static DiagnosedSilenceableFailure definiteFailure()
Constructs a DiagnosedSilenceableFailure in the failure state.
DiagnosedSilenceableFailure && operator<<(T &&value) &&
DiagnosedSilenceableFailure & operator<<(T &&value) &
Streams the given values into the last diagnostic.
bool isSilenceableFailure() const
Returns true if this is a silenceable failure.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:223
Include the generated interface declarations.
DiagnosedSilenceableFailure emitSilenceableFailure(Location loc, const Twine &message={})
Emits a silenceable failure with the given message.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message={})
Emits a definite failure with the given message.