MLIR  20.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.
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  }
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.
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 
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:155
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:351
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.
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.