1//===- Diagnostics.h - MLIR Diagnostics -------------------------*- 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 defines utilities for emitting diagnostics.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_IR_DIAGNOSTICS_H
14#define MLIR_IR_DIAGNOSTICS_H
15
16#include "mlir/IR/Location.h"
17#include <functional>
18#include <optional>
19
20namespace llvm {
21class MemoryBuffer;
22class SMLoc;
23class SourceMgr;
24} // namespace llvm
25
26namespace mlir {
27class DiagnosticEngine;
28struct LogicalResult;
29class MLIRContext;
30class Operation;
31class OperationName;
32class OpPrintingFlags;
33class Type;
34class Value;
35
36namespace detail {
37struct DiagnosticEngineImpl;
38} // namespace detail
39
40/// Defines the different supported severity of a diagnostic.
41enum class DiagnosticSeverity {
42 Note,
43 Warning,
44 Error,
45 Remark,
46};
47
48//===----------------------------------------------------------------------===//
49// DiagnosticArgument
50//===----------------------------------------------------------------------===//
51
52/// A variant type that holds a single argument for a diagnostic.
53class DiagnosticArgument {
54public:
55 /// Note: The constructors below are only exposed due to problems accessing
56 /// constructors from type traits, they should not be used directly by users.
57 // Construct from an Attribute.
58 explicit DiagnosticArgument(Attribute attr);
59 // Construct from a floating point number.
60 explicit DiagnosticArgument(double val)
61 : kind(DiagnosticArgumentKind::Double), doubleVal(val) {}
62 explicit DiagnosticArgument(float val) : DiagnosticArgument(double(val)) {}
63 // Construct from a signed integer.
64 template <typename T>
65 explicit DiagnosticArgument(
66 T val, std::enable_if_t<std::is_signed<T>::value &&
67 std::numeric_limits<T>::is_integer &&
68 sizeof(T) <= sizeof(int64_t)> * = nullptr)
69 : kind(DiagnosticArgumentKind::Integer), opaqueVal(int64_t(val)) {}
70 // Construct from an unsigned integer.
71 template <typename T>
72 explicit DiagnosticArgument(
73 T val, std::enable_if_t<std::is_unsigned<T>::value &&
74 std::numeric_limits<T>::is_integer &&
75 sizeof(T) <= sizeof(uint64_t)> * = nullptr)
76 : kind(DiagnosticArgumentKind::Unsigned), opaqueVal(uint64_t(val)) {}
77 // Construct from a string reference.
78 explicit DiagnosticArgument(StringRef val)
79 : kind(DiagnosticArgumentKind::String), stringVal(val) {}
80 // Construct from a Type.
81 explicit DiagnosticArgument(Type val);
82
83 /// Enum that represents the different kinds of diagnostic arguments
84 /// supported.
85 enum class DiagnosticArgumentKind {
86 Attribute,
87 Double,
88 Integer,
89 String,
90 Type,
91 Unsigned,
92 };
93
94 /// Outputs this argument to a stream.
95 void print(raw_ostream &os) const;
96
97 /// Returns the kind of this argument.
98 DiagnosticArgumentKind getKind() const { return kind; }
99
100 /// Returns this argument as an Attribute.
101 Attribute getAsAttribute() const;
102
103 /// Returns this argument as a double.
104 double getAsDouble() const {
105 assert(getKind() == DiagnosticArgumentKind::Double);
106 return doubleVal;
107 }
108
109 /// Returns this argument as a signed integer.
110 int64_t getAsInteger() const {
111 assert(getKind() == DiagnosticArgumentKind::Integer);
112 return static_cast<int64_t>(opaqueVal);
113 }
114
115 /// Returns this argument as a string.
116 StringRef getAsString() const {
117 assert(getKind() == DiagnosticArgumentKind::String);
118 return stringVal;
119 }
120
121 /// Returns this argument as a Type.
122 Type getAsType() const;
123
124 /// Returns this argument as an unsigned integer.
125 uint64_t getAsUnsigned() const {
126 assert(getKind() == DiagnosticArgumentKind::Unsigned);
127 return static_cast<uint64_t>(opaqueVal);
128 }
129
130private:
131 friend class Diagnostic;
132
133 /// The kind of this argument.
134 DiagnosticArgumentKind kind;
135
136 /// The value of this argument.
137 union {
138 double doubleVal;
139 intptr_t opaqueVal;
140 StringRef stringVal;
141 };
142};
143
144inline raw_ostream &operator<<(raw_ostream &os, const DiagnosticArgument &arg) {
145 arg.print(os);
146 return os;
147}
148
149//===----------------------------------------------------------------------===//
150// Diagnostic
151//===----------------------------------------------------------------------===//
152
153/// This class contains all of the information necessary to report a diagnostic
154/// to the DiagnosticEngine. It should generally not be constructed directly,
155/// and instead used transitively via InFlightDiagnostic.
156class Diagnostic {
157 using NoteVector = std::vector<std::unique_ptr<Diagnostic>>;
158
159public:
160 Diagnostic(Location loc, DiagnosticSeverity severity)
161 : loc(loc), severity(severity) {}
162 Diagnostic(Diagnostic &&) = default;
163 Diagnostic &operator=(Diagnostic &&) = default;
164
165 /// Returns the severity of this diagnostic.
166 DiagnosticSeverity getSeverity() const { return severity; }
167
168 /// Returns the source location for this diagnostic.
169 Location getLocation() const { return loc; }
170
171 /// Returns the current list of diagnostic arguments.
172 MutableArrayRef<DiagnosticArgument> getArguments() { return arguments; }
173 ArrayRef<DiagnosticArgument> getArguments() const { return arguments; }
174
175 /// Stream operator for inserting new diagnostic arguments.
176 template <typename Arg>
177 std::enable_if_t<!std::is_convertible<Arg, StringRef>::value &&
178 std::is_constructible<DiagnosticArgument, Arg>::value,
179 Diagnostic &>
180 operator<<(Arg &&val) {
181 arguments.push_back(Elt: DiagnosticArgument(std::forward<Arg>(val)));
182 return *this;
183 }
184 Diagnostic &operator<<(StringAttr val);
185
186 /// Stream in a string literal.
187 Diagnostic &operator<<(const char *val) {
188 arguments.push_back(Elt: DiagnosticArgument(val));
189 return *this;
190 }
191
192 /// Stream in a Twine argument.
193 Diagnostic &operator<<(char val);
194 Diagnostic &operator<<(const Twine &val);
195 Diagnostic &operator<<(Twine &&val);
196
197 /// Stream in an OperationName.
198 Diagnostic &operator<<(OperationName val);
199
200 /// Stream in an Operation.
201 Diagnostic &operator<<(Operation &op);
202 Diagnostic &operator<<(Operation *op) { return *this << *op; }
203 /// Append an operation with the given printing flags.
204 Diagnostic &appendOp(Operation &op, const OpPrintingFlags &flags);
205
206 /// Stream in a Value.
207 Diagnostic &operator<<(Value val);
208
209 /// Stream in a range.
210 template <typename T, typename ValueT = llvm::detail::ValueOfRange<T>>
211 std::enable_if_t<!std::is_constructible<DiagnosticArgument, T>::value,
212 Diagnostic &>
213 operator<<(T &&range) {
214 return appendRange(range);
215 }
216
217 /// Append a range to the diagnostic. The default delimiter between elements
218 /// is ','.
219 template <typename T>
220 Diagnostic &appendRange(const T &c, const char *delim = ", ") {
221 llvm::interleave(
222 c, [this](const auto &a) { *this << a; }, [&]() { *this << delim; });
223 return *this;
224 }
225
226 /// Append arguments to the diagnostic.
227 template <typename Arg1, typename Arg2, typename... Args>
228 Diagnostic &append(Arg1 &&arg1, Arg2 &&arg2, Args &&...args) {
229 append(std::forward<Arg1>(arg1));
230 return append(std::forward<Arg2>(arg2), std::forward<Args>(args)...);
231 }
232 /// Append one argument to the diagnostic.
233 template <typename Arg>
234 Diagnostic &append(Arg &&arg) {
235 *this << std::forward<Arg>(arg);
236 return *this;
237 }
238
239 /// Outputs this diagnostic to a stream.
240 void print(raw_ostream &os) const;
241
242 /// Converts the diagnostic to a string.
243 std::string str() const;
244
245 /// Attaches a note to this diagnostic. A new location may be optionally
246 /// provided, if not, then the location defaults to the one specified for this
247 /// diagnostic. Notes may not be attached to other notes.
248 Diagnostic &attachNote(std::optional<Location> noteLoc = std::nullopt);
249
250 using note_iterator = llvm::pointee_iterator<NoteVector::iterator>;
251 using const_note_iterator =
252 llvm::pointee_iterator<NoteVector::const_iterator>;
253
254 /// Returns the notes held by this diagnostic.
255 iterator_range<note_iterator> getNotes() {
256 return llvm::make_pointee_range(Range&: notes);
257 }
258 iterator_range<const_note_iterator> getNotes() const {
259 return llvm::make_pointee_range(Range: notes);
260 }
261
262 /// Allow a diagnostic to be converted to 'failure'.
263 operator LogicalResult() const;
264
265 /// Allow a diagnostic to be converted to 'failure'.
266 operator ParseResult() const { return ParseResult(LogicalResult(*this)); }
267
268 /// Allow a diagnostic to be converted to FailureOr<T>. Always results in
269 /// 'failure' because this cast cannot possibly return an object of 'T'.
270 template <typename T>
271 operator FailureOr<T>() const {
272 return failure();
273 }
274
275private:
276 Diagnostic(const Diagnostic &rhs) = delete;
277 Diagnostic &operator=(const Diagnostic &rhs) = delete;
278
279 /// The source location.
280 Location loc;
281
282 /// The severity of this diagnostic.
283 DiagnosticSeverity severity;
284
285 /// The current list of arguments.
286 SmallVector<DiagnosticArgument, 4> arguments;
287
288 /// A list of string values used as arguments. This is used to guarantee the
289 /// liveness of non-constant strings used in diagnostics.
290 std::vector<std::unique_ptr<char[]>> strings;
291
292 /// A list of attached notes.
293 NoteVector notes;
294};
295
296inline raw_ostream &operator<<(raw_ostream &os, const Diagnostic &diag) {
297 diag.print(os);
298 return os;
299}
300
301//===----------------------------------------------------------------------===//
302// InFlightDiagnostic
303//===----------------------------------------------------------------------===//
304
305/// This class represents a diagnostic that is inflight and set to be reported.
306/// This allows for last minute modifications of the diagnostic before it is
307/// emitted by a DiagnosticEngine.
308class InFlightDiagnostic {
309public:
310 InFlightDiagnostic() = default;
311 InFlightDiagnostic(InFlightDiagnostic &&rhs)
312 : owner(rhs.owner), impl(std::move(rhs.impl)) {
313 // Reset the rhs diagnostic.
314 rhs.impl.reset();
315 rhs.abandon();
316 }
317 ~InFlightDiagnostic() {
318 if (isInFlight())
319 report();
320 }
321
322 /// Stream operator for new diagnostic arguments.
323 template <typename Arg>
324 InFlightDiagnostic &operator<<(Arg &&arg) & {
325 return append(std::forward<Arg>(arg));
326 }
327 template <typename Arg>
328 InFlightDiagnostic &&operator<<(Arg &&arg) && {
329 return std::move(append(std::forward<Arg>(arg)));
330 }
331
332 /// Append arguments to the diagnostic.
333 template <typename... Args>
334 InFlightDiagnostic &append(Args &&...args) & {
335 assert(isActive() && "diagnostic not active");
336 if (isInFlight())
337 impl->append(std::forward<Args>(args)...);
338 return *this;
339 }
340 template <typename... Args>
341 InFlightDiagnostic &&append(Args &&...args) && {
342 return std::move(append(std::forward<Args>(args)...));
343 }
344
345 /// Attaches a note to this diagnostic.
346 Diagnostic &attachNote(std::optional<Location> noteLoc = std::nullopt) {
347 assert(isActive() && "diagnostic not active");
348 return impl->attachNote(noteLoc);
349 }
350
351 /// Returns the underlying diagnostic or nullptr if this diagnostic isn't
352 /// active.
353 Diagnostic *getUnderlyingDiagnostic() { return impl ? &*impl : nullptr; }
354
355 /// Reports the diagnostic to the engine.
356 void report();
357
358 /// Abandons this diagnostic so that it will no longer be reported.
359 void abandon();
360
361 /// Allow an inflight diagnostic to be converted to 'failure', otherwise
362 /// 'success' if this is an empty diagnostic.
363 operator LogicalResult() const;
364
365 /// Allow an inflight diagnostic to be converted to 'failure', otherwise
366 /// 'success' if this is an empty diagnostic.
367 operator ParseResult() const { return ParseResult(LogicalResult(*this)); }
368
369 /// Allow an inflight diagnostic to be converted to FailureOr<T>. Always
370 /// results in 'failure' because this cast cannot possibly return an object of
371 /// 'T'.
372 template <typename T>
373 operator FailureOr<T>() const {
374 return failure();
375 }
376
377private:
378 InFlightDiagnostic &operator=(const InFlightDiagnostic &) = delete;
379 InFlightDiagnostic &operator=(InFlightDiagnostic &&) = delete;
380 InFlightDiagnostic(DiagnosticEngine *owner, Diagnostic &&rhs)
381 : owner(owner), impl(std::move(rhs)) {}
382
383 /// Returns true if the diagnostic is still active, i.e. it has a live
384 /// diagnostic.
385 bool isActive() const { return impl.has_value(); }
386
387 /// Returns true if the diagnostic is still in flight to be reported.
388 bool isInFlight() const { return owner; }
389
390 // Allow access to the constructor.
391 friend DiagnosticEngine;
392
393 /// The engine that this diagnostic is to report to.
394 DiagnosticEngine *owner = nullptr;
395
396 /// The raw diagnostic that is inflight to be reported.
397 std::optional<Diagnostic> impl;
398};
399
400//===----------------------------------------------------------------------===//
401// DiagnosticEngine
402//===----------------------------------------------------------------------===//
403
404/// This class is the main interface for diagnostics. The DiagnosticEngine
405/// manages the registration of diagnostic handlers as well as the core API for
406/// diagnostic emission. This class should not be constructed directly, but
407/// instead interfaced with via an MLIRContext instance.
408class DiagnosticEngine {
409public:
410 ~DiagnosticEngine();
411
412 // Diagnostic handler registration and use. MLIR supports the ability for the
413 // IR to carry arbitrary metadata about operation location information. If a
414 // problem is detected by the compiler, it can invoke the emitError /
415 // emitWarning / emitRemark method on an Operation and have it get reported
416 // through this interface.
417 //
418 // Tools using MLIR are encouraged to register error handlers and define a
419 // schema for their location information. If they don't, then warnings and
420 // notes will be dropped and errors will be emitted to errs.
421
422 /// The handler type for MLIR diagnostics. This function takes a diagnostic as
423 /// input, and returns success if the handler has fully processed this
424 /// diagnostic. Returns failure otherwise.
425 using HandlerTy = llvm::unique_function<LogicalResult(Diagnostic &)>;
426
427 /// A handle to a specific registered handler object.
428 using HandlerID = uint64_t;
429
430 /// Register a new handler for diagnostics to the engine. Diagnostics are
431 /// process by handlers in stack-like order, meaning that the last added
432 /// handlers will process diagnostics first. This function returns a unique
433 /// identifier for the registered handler, which can be used to unregister
434 /// this handler at a later time.
435 HandlerID registerHandler(HandlerTy handler);
436
437 /// Set the diagnostic handler with a function that returns void. This is a
438 /// convenient wrapper for handlers that always completely process the given
439 /// diagnostic.
440 template <typename FuncTy, typename RetT = decltype(std::declval<FuncTy>()(
441 std::declval<Diagnostic &>()))>
442 std::enable_if_t<std::is_same<RetT, void>::value, HandlerID>
443 registerHandler(FuncTy &&handler) {
444 return registerHandler([=](Diagnostic &diag) {
445 handler(diag);
446 return success();
447 });
448 }
449
450 /// Erase the registered diagnostic handler with the given identifier.
451 void eraseHandler(HandlerID id);
452
453 /// Create a new inflight diagnostic with the given location and severity.
454 InFlightDiagnostic emit(Location loc, DiagnosticSeverity severity) {
455 assert(severity != DiagnosticSeverity::Note &&
456 "notes should not be emitted directly");
457 return InFlightDiagnostic(this, Diagnostic(loc, severity));
458 }
459
460 /// Emit a diagnostic using the registered issue handler if present, or with
461 /// the default behavior if not. The diagnostic instance is consumed in the
462 /// process.
463 void emit(Diagnostic &&diag);
464
465private:
466 friend class MLIRContextImpl;
467 DiagnosticEngine();
468
469 /// The internal implementation of the DiagnosticEngine.
470 std::unique_ptr<detail::DiagnosticEngineImpl> impl;
471};
472
473/// Utility method to emit an error message using this location.
474InFlightDiagnostic emitError(Location loc);
475InFlightDiagnostic emitError(Location loc, const Twine &message);
476
477/// Utility method to emit a warning message using this location.
478InFlightDiagnostic emitWarning(Location loc);
479InFlightDiagnostic emitWarning(Location loc, const Twine &message);
480
481/// Utility method to emit a remark message using this location.
482InFlightDiagnostic emitRemark(Location loc);
483InFlightDiagnostic emitRemark(Location loc, const Twine &message);
484
485/// Overloads of the above emission functions that take an optionally null
486/// location. If the location is null, no diagnostic is emitted and a failure is
487/// returned. Given that the provided location may be null, these methods take
488/// the diagnostic arguments directly instead of relying on the returned
489/// InFlightDiagnostic.
490template <typename... Args>
491LogicalResult emitOptionalError(std::optional<Location> loc, Args &&...args) {
492 if (loc)
493 return emitError(loc: *loc).append(std::forward<Args>(args)...);
494 return failure();
495}
496template <typename... Args>
497LogicalResult emitOptionalWarning(std::optional<Location> loc, Args &&...args) {
498 if (loc)
499 return emitWarning(loc: *loc).append(std::forward<Args>(args)...);
500 return failure();
501}
502template <typename... Args>
503LogicalResult emitOptionalRemark(std::optional<Location> loc, Args &&...args) {
504 if (loc)
505 return emitRemark(loc: *loc).append(std::forward<Args>(args)...);
506 return failure();
507}
508
509//===----------------------------------------------------------------------===//
510// ScopedDiagnosticHandler
511//===----------------------------------------------------------------------===//
512
513/// This diagnostic handler is a simple RAII class that registers and erases a
514/// diagnostic handler on a given context. This class can be either be used
515/// directly, or in conjunction with a derived diagnostic handler.
516class ScopedDiagnosticHandler {
517public:
518 explicit ScopedDiagnosticHandler(MLIRContext *ctx) : handlerID(0), ctx(ctx) {}
519 template <typename FuncTy>
520 ScopedDiagnosticHandler(MLIRContext *ctx, FuncTy &&handler)
521 : handlerID(0), ctx(ctx) {
522 setHandler(std::forward<FuncTy>(handler));
523 }
524 ~ScopedDiagnosticHandler();
525
526protected:
527 /// Set the handler to manage via RAII.
528 template <typename FuncTy>
529 void setHandler(FuncTy &&handler) {
530 auto &diagEngine = ctx->getDiagEngine();
531 if (handlerID)
532 diagEngine.eraseHandler(id: handlerID);
533 handlerID = diagEngine.registerHandler(std::forward<FuncTy>(handler));
534 }
535
536private:
537 /// The unique id for the scoped handler.
538 DiagnosticEngine::HandlerID handlerID;
539
540 /// The context to erase the handler from.
541 MLIRContext *ctx;
542};
543
544//===----------------------------------------------------------------------===//
545// SourceMgrDiagnosticHandler
546//===----------------------------------------------------------------------===//
547
548namespace detail {
549struct SourceMgrDiagnosticHandlerImpl;
550} // namespace detail
551
552/// This class is a utility diagnostic handler for use with llvm::SourceMgr.
553class SourceMgrDiagnosticHandler : public ScopedDiagnosticHandler {
554public:
555 /// This type represents a functor used to filter out locations when printing
556 /// a diagnostic. It should return true if the provided location is okay to
557 /// display, false otherwise. If all locations in a diagnostic are filtered
558 /// out, the first location is used as the sole location. When deciding
559 /// whether or not to filter a location, this function should not recurse into
560 /// any nested location. This recursion is handled automatically by the
561 /// caller.
562 using ShouldShowLocFn = llvm::unique_function<bool(Location)>;
563
564 SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx,
565 raw_ostream &os,
566 ShouldShowLocFn &&shouldShowLocFn = {});
567 SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx,
568 ShouldShowLocFn &&shouldShowLocFn = {});
569 ~SourceMgrDiagnosticHandler();
570
571 /// Emit the given diagnostic information with the held source manager.
572 void emitDiagnostic(Location loc, Twine message, DiagnosticSeverity kind,
573 bool displaySourceLine = true);
574
575protected:
576 /// Emit the given diagnostic with the held source manager.
577 void emitDiagnostic(Diagnostic &diag);
578
579 /// Get a memory buffer for the given file, or nullptr if no file is
580 /// available.
581 const llvm::MemoryBuffer *getBufferForFile(StringRef filename);
582
583 /// The source manager that we are wrapping.
584 llvm::SourceMgr &mgr;
585
586 /// The output stream to use when printing diagnostics.
587 raw_ostream &os;
588
589 /// A functor used when determining if a location for a diagnostic should be
590 /// shown. If null, all locations should be shown.
591 ShouldShowLocFn shouldShowLocFn;
592
593private:
594 /// Convert a location into the given memory buffer into an SMLoc.
595 SMLoc convertLocToSMLoc(FileLineColLoc loc);
596
597 /// Given a location, returns the first nested location (including 'loc') that
598 /// can be shown to the user.
599 std::optional<Location> findLocToShow(Location loc);
600
601 /// The maximum depth that a call stack will be printed.
602 /// TODO: This should be a tunable flag.
603 unsigned callStackLimit = 10;
604
605 std::unique_ptr<detail::SourceMgrDiagnosticHandlerImpl> impl;
606};
607
608//===----------------------------------------------------------------------===//
609// SourceMgrDiagnosticVerifierHandler
610//===----------------------------------------------------------------------===//
611
612namespace detail {
613struct SourceMgrDiagnosticVerifierHandlerImpl;
614} // namespace detail
615
616/// This class is a utility diagnostic handler for use with llvm::SourceMgr that
617/// verifies that emitted diagnostics match 'expected-*' lines on the
618/// corresponding line of the source file.
619class SourceMgrDiagnosticVerifierHandler : public SourceMgrDiagnosticHandler {
620public:
621 SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx,
622 raw_ostream &out);
623 SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx);
624 ~SourceMgrDiagnosticVerifierHandler();
625
626 /// Returns the status of the handler and verifies that all expected
627 /// diagnostics were emitted. This return success if all diagnostics were
628 /// verified correctly, failure otherwise.
629 LogicalResult verify();
630
631private:
632 /// Process a single diagnostic.
633 void process(Diagnostic &diag);
634
635 /// Process a FileLineColLoc diagnostic.
636 void process(FileLineColLoc loc, StringRef msg, DiagnosticSeverity kind);
637
638 std::unique_ptr<detail::SourceMgrDiagnosticVerifierHandlerImpl> impl;
639};
640
641//===----------------------------------------------------------------------===//
642// ParallelDiagnosticHandler
643//===----------------------------------------------------------------------===//
644
645namespace detail {
646struct ParallelDiagnosticHandlerImpl;
647} // namespace detail
648
649/// This class is a utility diagnostic handler for use when multi-threading some
650/// part of the compiler where diagnostics may be emitted. This handler ensures
651/// a deterministic ordering to the emitted diagnostics that mirrors that of a
652/// single-threaded compilation.
653class ParallelDiagnosticHandler {
654public:
655 ParallelDiagnosticHandler(MLIRContext *ctx);
656 ~ParallelDiagnosticHandler();
657
658 /// Set the order id for the current thread. This is required to be set by
659 /// each thread that will be emitting diagnostics to this handler. The orderID
660 /// corresponds to the order in which diagnostics would be emitted when
661 /// executing synchronously. For example, if we were processing a list
662 /// of operations [a, b, c] on a single-thread. Diagnostics emitted while
663 /// processing operation 'a' would be emitted before those for 'b' or 'c'.
664 /// This corresponds 1-1 with the 'orderID'. The thread that is processing 'a'
665 /// should set the orderID to '0'; the thread processing 'b' should set it to
666 /// '1'; and so on and so forth. This provides a way for the handler to
667 /// deterministically order the diagnostics that it receives given the thread
668 /// that it is receiving on.
669 void setOrderIDForThread(size_t orderID);
670
671 /// Remove the order id for the current thread. This removes the thread from
672 /// diagnostics tracking.
673 void eraseOrderIDForThread();
674
675private:
676 std::unique_ptr<detail::ParallelDiagnosticHandlerImpl> impl;
677};
678} // namespace mlir
679
680#endif
681

source code of mlir/include/mlir/IR/Diagnostics.h