MLIR  19.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 
22 namespace 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.
38 class [[nodiscard]] DiagnosedSilenceableFailure {
39 public:
46 
47  /// Constructs a DiagnosedSilenceableFailure in the success state.
50  }
51 
52  /// Constructs a DiagnosedSilenceableFailure in the failure state. Typically,
53  /// a diagnostic has been emitted before this.
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  }
67  std::forward<SmallVector<Diagnostic>>(diag));
68  }
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";
102  if (isSilenceableFailure())
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.
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 
146 private:
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 
173 class DiagnosedDefiniteFailure;
174 
175 DiagnosedDefiniteFailure emitDefiniteFailure(Location loc,
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 
188 public:
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 
222 private:
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;
233  DiagnosedDefiniteFailure &operator=(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.
255 inline DiagnosedSilenceableFailure
256 emitSilenceableFailure(Location loc, const Twine &message = {}) {
257  Diagnostic diag(loc, DiagnosticSeverity::Error);
258  diag << message;
260 }
261 inline DiagnosedSilenceableFailure
262 emitSilenceableFailure(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...
friend DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message)
Emits a definite failure with the given message.
DiagnosedDefiniteFailure & operator<<(T &&value) &
Forward the message to the diagnostic.
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the error.
DiagnosedDefiniteFailure && operator<<(T &&value) &&
DiagnosedDefiniteFailure(DiagnosedDefiniteFailure &&)=default
Only move-constructible because it carries an in-flight diagnostic.
The result of a transform IR operation application.
LogicalResult silence()
Converts silenceable failure into LogicalResult success without reporting the diagnostic,...
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).
Diagnostic & attachNote(std::optional< Location > loc=std::nullopt)
Attaches a note to the last diagnostic.
DiagnosedSilenceableFailure & operator=(DiagnosedSilenceableFailure &&)=default
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)
DiagnosedSilenceableFailure && operator<<(T &&value) &&
DiagnosedSilenceableFailure(const DiagnosedSilenceableFailure &)=delete
static DiagnosedSilenceableFailure silenceableFailure(Diagnostic &&diag)
Constructs a DiagnosedSilenceableFailure in the silenceable failure state, ready to emit the given di...
DiagnosedSilenceableFailure & operator<<(T &&value) &
Streams the given values into the last diagnostic.
void takeDiagnostics(SmallVectorImpl< Diagnostic > &diags)
Take the diagnostics and silence.
bool succeeded() const
Returns true if this is a success.
static DiagnosedSilenceableFailure definiteFailure()
Constructs a DiagnosedSilenceableFailure in the failure state.
DiagnosedSilenceableFailure & operator=(const DiagnosedSilenceableFailure &)=delete
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.
Definition: Diagnostics.h:156
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:346
void report()
Reports the diagnostic to the engine.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
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.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
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.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message={})
Emits a definite failure with the given message.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26