15 #include "llvm/ADT/MapVector.h" 16 #include "llvm/ADT/SmallString.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/TypeSwitch.h" 19 #include "llvm/Support/Mutex.h" 20 #include "llvm/Support/PrettyStackTrace.h" 21 #include "llvm/Support/Regex.h" 22 #include "llvm/Support/Signals.h" 23 #include "llvm/Support/SourceMgr.h" 24 #include "llvm/Support/raw_ostream.h" 36 opaqueVal(reinterpret_cast<intptr_t>(attr.getAsOpaquePointer())) {}
41 opaqueVal(reinterpret_cast<intptr_t>(val.getAsOpaquePointer())) {}
47 reinterpret_cast<const void *>(
opaqueVal));
87 std::vector<std::unique_ptr<
char[]>> &strings) {
90 auto strRef = val.toStringRef(data);
94 strings.push_back(std::unique_ptr<
char[]>(
new char[
strRef.size()]));
95 memcpy(&strings.back()[0],
strRef.data(),
strRef.size());
97 return StringRef(&strings.back()[0],
strRef.size());
141 llvm::raw_string_ostream os(str);
143 return *
this << os.str();
149 llvm::raw_string_ostream os(str);
151 return *
this << os.str();
156 for (
auto &arg : getArguments())
163 llvm::raw_string_ostream os(str);
174 "cannot attach a note to a note");
183 return *notes.back();
204 owner->emit(std::move(*
impl));
234 DiagnosticEngine::HandlerID uniqueHandlerId = 1;
242 llvm::sys::SmartScopedLock<true> lock(mutex);
247 for (
auto &handlerIt : llvm::reverse(handlers))
255 auto &os = llvm::errs();
256 if (!
diag.getLocation().isa<UnknownLoc>())
257 os <<
diag.getLocation() <<
": ";
276 llvm::sys::SmartScopedLock<true> lock(
impl->mutex);
277 auto uniqueID =
impl->uniqueHandlerId++;
278 impl->handlers.insert({uniqueID, std::move(handler)});
284 llvm::sys::SmartScopedLock<true> lock(
impl->mutex);
285 impl->handlers.erase(handlerID);
292 "notes should not be emitted directly");
303 auto diag = diagEngine.emit(location, severity);
304 if (!message.isTriviallyEmpty())
311 llvm::raw_string_ostream stream(bt);
312 llvm::sys::PrintStackTrace(stream);
315 diag.attachNote() <<
"diagnostic emitted with trace:\n" << bt;
349 ctx->getDiagEngine().eraseHandler(handlerID);
361 StringRef filename) {
363 auto bufferIt = filenameToBufId.find(filename);
364 if (bufferIt != filenameToBufId.end())
365 return bufferIt->second;
368 for (
unsigned i = 1, e = mgr.getNumBuffers() + 1; i != e; ++i) {
369 auto *buf = mgr.getMemoryBuffer(i);
370 if (buf->getBufferIdentifier() == filename)
371 return filenameToBufId[filename] = i;
377 mgr.AddIncludeFile(std::string(filename), SMLoc(), ignored);
378 filenameToBufId[filename] = id;
390 Optional<FileLineColLoc> firstFileLoc;
392 if (FileLineColLoc fileLoc = loc.
dyn_cast<FileLineColLoc>()) {
393 firstFileLoc = fileLoc;
394 return WalkResult::interrupt();
403 if (
auto nameLoc = loc.
dyn_cast<NameLoc>())
405 if (
auto callLoc = loc.
dyn_cast<CallSiteLoc>())
407 if (
auto fusedLoc = loc.
dyn_cast<FusedLoc>()) {
408 for (
auto subLoc : loc.
cast<FusedLoc>().getLocations()) {
422 return llvm::SourceMgr::DK_Note;
424 return llvm::SourceMgr::DK_Warning;
426 return llvm::SourceMgr::DK_Error;
428 return llvm::SourceMgr::DK_Remark;
430 llvm_unreachable(
"Unknown DiagnosticSeverity");
434 llvm::SourceMgr &mgr,
MLIRContext *ctx, raw_ostream &os,
437 shouldShowLocFn(std::move(shouldShowLocFn)),
451 bool displaySourceLine) {
458 llvm::raw_string_ostream strOS(str);
459 if (!loc.
isa<UnknownLoc>())
460 strOS << loc <<
": ";
467 if (displaySourceLine) {
468 auto smloc = convertLocToSMLoc(*fileLoc);
477 llvm::raw_string_ostream locOS(locStr);
478 locOS << fileLoc->getFilename().getValue() <<
":" << fileLoc->getLine() <<
":" 479 << fileLoc->getColumn();
480 llvm::SMDiagnostic
diag(locOS.str(),
getDiagKind(kind), message.str());
487 auto addLocToStack = [&](
Location loc, StringRef locContext) {
489 locationStack.emplace_back(*showableLoc, locContext);
494 addLocToStack(loc, {});
500 loc = callLoc->getCaller();
501 for (
unsigned curDepth = 0; curDepth < callStackLimit; ++curDepth) {
502 addLocToStack(loc,
"called from");
504 loc = callLoc->getCaller();
511 if (locationStack.empty()) {
517 for (
auto &it : llvm::drop_begin(locationStack))
523 for (
auto ¬e : diag.
getNotes()) {
524 emitDiagnostic(note.getLocation(), note.str(), note.getSeverity(),
525 loc != note.getLocation());
526 loc = note.getLocation();
531 const llvm::MemoryBuffer *
533 if (
unsigned id =
impl->getSourceMgrBufferIDForFile(
mgr, filename))
534 return mgr.getMemoryBuffer(
id);
549 return findLocToShow(callLoc.getCallee());
555 for (
Location childLoc : fusedLoc.getLocations())
561 return findLocToShow(nameLoc.getChildLoc());
565 return findLocToShow(opaqueLoc.getFallbackLocation());
575 SMLoc SourceMgrDiagnosticHandler::convertLocToSMLoc(FileLineColLoc loc) {
578 if (loc.getLine() == 0 || loc.getColumn() == 0)
581 unsigned bufferId =
impl->getSourceMgrBufferIDForFile(
mgr, loc.getFilename());
584 return mgr.FindLocForLineAndColumn(bufferId, loc.getLine(), loc.getColumn());
611 computeExpectedDiags(
const llvm::MemoryBuffer *buf);
620 llvm::Regex expected = llvm::Regex(
"expected-(error|note|remark|warning) " 621 "*(@([+-][0-9]+|above|below))? *{{(.*)}}");
638 llvm_unreachable(
"Unknown DiagnosticSeverity");
642 Optional<MutableArrayRef<ExpectedDiag>>
643 SourceMgrDiagnosticVerifierHandlerImpl::getExpectedDiags(StringRef bufName) {
644 auto expectedDiags = expectedDiagsPerFile.find(bufName);
645 if (expectedDiags != expectedDiagsPerFile.end())
652 SourceMgrDiagnosticVerifierHandlerImpl::computeExpectedDiags(
653 const llvm::MemoryBuffer *buf) {
657 auto &expectedDiags = expectedDiagsPerFile[buf->getBufferIdentifier()];
660 unsigned lastNonDesignatorLine = 0;
667 buf->getBuffer().split(lines,
'\n');
668 for (
unsigned lineNo = 0, e = lines.size(); lineNo < e; ++lineNo) {
670 if (!expected.match(lines[lineNo], &matches)) {
672 if (!designatorsForNextLine.empty()) {
673 for (
unsigned diagIndex : designatorsForNextLine)
674 expectedDiags[diagIndex].lineNo = lineNo + 1;
675 designatorsForNextLine.clear();
677 lastNonDesignatorLine = lineNo;
682 auto expectedStart = SMLoc::getFromPointer(matches[0].data());
685 if (matches[1] ==
"error")
687 else if (matches[1] ==
"warning")
689 else if (matches[1] ==
"remark")
692 assert(matches[1] ==
"note");
696 ExpectedDiag record{kind, lineNo + 1, matches[4], expectedStart,
false};
697 auto offsetMatch = matches[2];
698 if (!offsetMatch.empty()) {
699 offsetMatch = offsetMatch.drop_front(1);
702 if (offsetMatch[0] ==
'+' || offsetMatch[0] ==
'-') {
704 offsetMatch.drop_front().getAsInteger(0, offset);
706 if (offsetMatch.front() ==
'+')
707 record.lineNo += offset;
709 record.lineNo -= offset;
710 }
else if (offsetMatch.consume_front(
"above")) {
713 record.lineNo = lastNonDesignatorLine + 1;
717 assert(offsetMatch.consume_front(
"below"));
718 designatorsForNextLine.push_back(expectedDiags.size());
725 expectedDiags.push_back(record);
727 return expectedDiags;
731 llvm::SourceMgr &srcMgr,
MLIRContext *ctx, raw_ostream &out)
736 for (
unsigned i = 0, e =
mgr.getNumBuffers(); i != e; ++i)
737 (
void)
impl->computeExpectedDiags(
mgr.getMemoryBuffer(i + 1));
764 for (
auto &expectedDiagsPair :
impl->expectedDiagsPerFile) {
765 for (
auto &err : expectedDiagsPair.second) {
768 SMRange range(err.fileLoc,
769 SMLoc::getFromPointer(err.fileLoc.getPointer() +
770 err.substring.size()));
771 mgr.PrintMessage(
os, err.fileLoc, llvm::SourceMgr::DK_Error,
773 err.substring +
"\" was not produced",
778 impl->expectedDiagsPerFile.clear();
783 void SourceMgrDiagnosticVerifierHandler::process(
Diagnostic &
diag) {
788 return process(*fileLoc, diag.
str(), kind);
797 void SourceMgrDiagnosticVerifierHandler::process(FileLineColLoc loc,
801 auto diags =
impl->getExpectedDiags(loc.getFilename());
810 unsigned line = loc.getLine();
811 for (
auto &e : *diags) {
812 if (line == e.lineNo && msg.contains(e.substring)) {
813 if (e.kind == kind) {
826 mgr.PrintMessage(
os, nearMiss->
fileLoc, llvm::SourceMgr::DK_Error,
828 "' diagnostic emitted when expecting a '" +
845 : id(id), diag(std::move(diag)) {}
859 uint64_t tid = llvm::get_threadid();
860 llvm::sys::SmartScopedLock<true> lock(mutex);
864 if (!threadToOrderID.count(tid))
868 diagnostics.emplace_back(threadToOrderID[tid], std::move(diag));
875 context->getDiagEngine().eraseHandler(handlerID);
878 if (diagnostics.empty())
883 return context->getDiagEngine().emit(std::move(diag));
892 std::stable_sort(diagnostics.begin(), diagnostics.end());
901 uint64_t tid = llvm::get_threadid();
902 llvm::sys::SmartScopedLock<true> lock(mutex);
903 threadToOrderID[tid] = orderID;
908 uint64_t tid = llvm::get_threadid();
909 llvm::sys::SmartScopedLock<true> lock(mutex);
910 threadToOrderID.erase(tid);
916 if (diagnostics.empty())
919 os <<
"In-Flight Diagnostics:\n";
969 impl->setOrderIDForThread(orderID);
975 impl->eraseOrderIDForThread();
Include the generated interface declarations.
static std::string diag(llvm::Value &v)
llvm::sys::SmartMutex< true > mutex
A smart mutex to lock access to the internal state.
MLIRContext * context
The context to emit the diagnostics to.
void eraseHandler(HandlerID id)
Erase the registered diagnostic handler with the given identifier.
static Optional< CallSiteLoc > getCallSiteLoc(Location loc)
Return a processable CallSiteLoc from the given location.
Explicitly register a set of "builtin" types.
Operation is a basic unit of execution within MLIR.
DenseMap< uint64_t, size_t > threadToOrderID
A mapping between the thread id and the current order id.
void setHandler(FuncTy &&handler)
Set the handler to manage via RAII.
This class represents a diagnostic that is inflight and set to be reported.
const llvm::MemoryBuffer * getBufferForFile(StringRef filename)
Get a memory buffer for the given file, or nullptr if no file is available.
void setOrderIDForThread(size_t orderID)
Set the order id for the current thread.
Diagnostic & attachNote(Optional< Location > noteLoc=llvm::None)
Attaches a note to this diagnostic.
llvm::unique_function< bool(Location)> ShouldShowLocFn
This type represents a functor used to filter out locations when printing a diagnostic.
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
void print(raw_ostream &os) const override
Dump the current diagnostics that were inflight.
~ParallelDiagnosticHandler()
~SourceMgrDiagnosticVerifierHandler()
uint64_t getAsUnsigned() const
Returns this argument as an unsigned integer.
Location getLocation() const
Returns the source location for this diagnostic.
void emitDiagnostics(llvm::function_ref< void(Diagnostic &)> emitFn) const
Utility method to emit any held diagnostics.
int64_t getAsInteger() const
Returns this argument as a signed integer.
void emitDiagnostic(Location loc, Twine message, DiagnosticSeverity kind, bool displaySourceLine=true)
Emit the given diagnostic information with the held source manager.
void print(raw_ostream &os) const
Outputs this argument to a stream.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
DiagnosticSeverity getSeverity() const
Returns the severity of this diagnostic.
DiagnosticSeverity
Defines the different supported severity of a diagnostic.
Attribute getAsAttribute() const
Returns this argument as an Attribute.
~ParallelDiagnosticHandlerImpl() override
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
SourceMgrDiagnosticVerifierHandlerImpl()
Type getAsType() const
Returns this argument as a Type.
std::vector< ThreadDiagnostic > diagnostics
An unordered list of diagnostics that were emitted.
unsigned getSourceMgrBufferIDForFile(llvm::SourceMgr &mgr, StringRef filename)
Return the SrcManager buffer id for the specified file, or zero if none can be found.
size_t id
The id for this diagnostic, this is used for ordering.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Diagnostic diag
The diagnostic.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine...
This class represents an efficient way to signal success or failure.
void print(raw_ostream &os)
bool shouldPrintStackTraceOnDiagnostic()
Return true if we should attach the current stacktrace to diagnostics when emitted.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
OpPrintingFlags & printGenericOpForm()
Always print operations in the generic form.
void eraseOrderIDForThread()
Remove the order id for the current thread.
std::enable_if< !std::is_convertible< Arg, StringRef >::value &&std::is_constructible< DiagnosticArgument, Arg >::value, Diagnostic & >::type operator<<(Arg &&val)
Stream operator for inserting new diagnostic arguments.
MLIRContext * getContext() const
Return the context this attribute belongs to.
llvm::unique_function< LogicalResult(Diagnostic &)> HandlerTy
The handler type for MLIR diagnostics.
bool isa() const
Type casting utilities on the underlying location.
uint64_t HandlerID
A handle to a specific registered handler object.
StringRef getAsString() const
Returns this argument as a string.
raw_ostream & os
The output stream to use when printing diagnostics.
void print(raw_ostream &os) const
Outputs this diagnostic to a stream.
Attributes are known-constant values of operations.
void setOrderIDForThread(size_t orderID)
Set the order id for the current thread.
~ScopedDiagnosticHandler()
static Optional< FileLineColLoc > getFileLineColLoc(Location loc)
Return a processable FileLineColLoc from the given location.
static Type getFromOpaquePointer(const void *pointer)
static WalkResult advance()
DiagnosticArgumentKind
Enum that represents the different kinds of diagnostic arguments supported.
~SourceMgrDiagnosticHandler()
static StringRef twineToStrRef(const Twine &val, std::vector< std::unique_ptr< char[]>> &strings)
Convert a Twine to a StringRef.
void eraseOrderIDForThread()
Remove the order id for the current thread.
void abandon()
Abandons this diagnostic so that it will no longer be reported.
DiagnosticArgumentKind getKind() const
Returns the kind of this argument.
bool operator<(const ThreadDiagnostic &rhs) const
void print(raw_ostream &os, const OpPrintingFlags &flags=llvm::None)
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class is a utility diagnostic handler for use with llvm::SourceMgr.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
HandlerID registerHandler(HandlerTy handler)
Register a new handler for diagnostics to the engine.
llvm::StringMap< unsigned > filenameToBufId
Mapping between file name and buffer ID's.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx, raw_ostream &os, ShouldShowLocFn &&shouldShowLocFn={})
This class is a utility diagnostic handler for use with llvm::SourceMgr that verifies that emitted di...
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
InFlightDiagnostic emit(Location loc, DiagnosticSeverity severity)
Create a new inflight diagnostic with the given location and severity.
Set of flags used to control the behavior of the various IR print methods (e.g.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
iterator_range< note_iterator > getNotes()
Returns the notes held by this diagnostic.
static StringRef getDiagKindStr(DiagnosticSeverity kind)
Given a diagnostic kind, return a human readable string for it.
ShouldShowLocFn shouldShowLocFn
A functor used when determining if a location for a diagnostic should be shown.
llvm::SourceMgr & mgr
The source manager that we are wrapping.
static InFlightDiagnostic emitDiag(Location location, DiagnosticSeverity severity, const Twine &message)
Helper function used to emit a diagnostic with an optionally empty twine message. ...
static llvm::SourceMgr::DiagKind getDiagKind(DiagnosticSeverity kind)
Given a diagnostic kind, returns the LLVM DiagKind.
MLIRContext is the top-level object for a collection of MLIR operations.
ParallelDiagnosticHandler(MLIRContext *ctx)
DiagnosticArgument(Attribute attr)
Note: The constructors below are only exposed due to problems accessing constructors from type traits...
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
void report()
Reports the diagnostic to the engine.
ParallelDiagnosticHandlerImpl(MLIRContext *ctx)
LogicalResult status
The current status of the verifier.
SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx, raw_ostream &out)
llvm::SmallMapVector< DiagnosticEngine::HandlerID, DiagnosticEngine::HandlerTy, 2 > handlers
These are the handlers used to report diagnostics.
static OpPrintingFlags adjustPrintingFlags(OpPrintingFlags flags, DiagnosticSeverity severity)
Adjusts operation printing flags used in diagnostics for the given severity level.
WalkResult walk(function_ref< WalkResult(Location)> walkFn)
Walk all of the locations nested under, and including, the current.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Diagnostic & appendOp(Operation &val, const OpPrintingFlags &flags)
Append an operation with the given printing flags.
double getAsDouble() const
Returns this argument as a double.
LogicalResult verify()
Returns the status of the handler and verifies that all expected diagnostics were emitted...
std::string str() const
Converts the diagnostic to a string.
llvm::sys::SmartMutex< true > mutex
A mutex to ensure that diagnostics emission is thread-safe.
ThreadDiagnostic(size_t id, Diagnostic diag)
llvm::StringMap< SmallVector< ExpectedDiag, 2 > > expectedDiagsPerFile
A list of expected diagnostics for each buffer of the source manager.