diff --git a/include/swift/AST/DiagnosticConsumer.h b/include/swift/AST/DiagnosticConsumer.h index 2ee9e90936a..bf0e07bb8fc 100644 --- a/include/swift/AST/DiagnosticConsumer.h +++ b/include/swift/AST/DiagnosticConsumer.h @@ -101,8 +101,6 @@ public: /// \returns true if an error occurred while finishing-up. virtual bool finishProcessing() { return false; } - - virtual bool hadOnlySuppressedFatalErrors() const { return false; } }; /// \brief DiagnosticConsumer that discards all diagnostics. @@ -142,10 +140,17 @@ private: /// All consumers owned by this FileSpecificDiagnosticConsumer. const SmallVector SubConsumers; - /// The DiagnosticConsumer may be empty if those diagnostics are not to be - /// emitted. - using ConsumersOrderedByRangeEntry = - std::pair; + struct ConsumerSpecificInformation { + const CharSourceRange range; + /// The DiagnosticConsumer may be empty if those diagnostics are not to be + /// emitted. + DiagnosticConsumer *const consumer; + bool hasAnErrorBeenEmitted = false; + + ConsumerSpecificInformation(const CharSourceRange range, + DiagnosticConsumer *const consumer) + : range(range), consumer(consumer) {} + }; /// The consumers owned by this FileSpecificDiagnosticConsumer, sorted by /// the end locations of each file so that a lookup by position can be done @@ -156,7 +161,7 @@ private: /// as long as they don't have source locations. /// /// \see #consumerForLocation - SmallVector ConsumersOrderedByRange; + SmallVector ConsumersOrderedByRange; /// Indicates which consumer to send Note diagnostics too. /// @@ -167,8 +172,7 @@ private: /// If null, diagnostics are suppressed. Optional ConsumerForSubsequentNotes = None; - bool WasAFatalDiagnosticSuppressed = false; - bool WasAFatalDiagnosticEmitted = false; + bool WasAnErrorSuppressed = false; public: /// Takes ownership of the DiagnosticConsumers specified in \p consumers. @@ -186,9 +190,8 @@ public: bool finishProcessing() override; - bool hadOnlySuppressedFatalErrors() const override; - private: + void addNonSpecificErrors(); void computeConsumersOrderedByRange(SourceManager &SM); /// Returns nullptr if diagnostic is to be suppressed, diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index f16bcc79074..21fecc92cc9 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -768,8 +768,6 @@ namespace swift { ArrayRef FormatArgs, DiagnosticFormatOptions FormatOpts = DiagnosticFormatOptions()); - bool hadOnlySuppressedFatalErrors() const; - private: /// \brief Flush the active diagnostic. void flushActiveDiagnostic(); diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 8eed536e263..d83ce321f17 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -235,7 +235,7 @@ WARNING(cannot_assign_value_to_conditional_compilation_flag,none, ERROR(error_optimization_remark_pattern, none, "%0 in '%1'", (StringRef, StringRef)) -ERROR(error_compilation_failed,none, "compilation failed", ()) +ERROR(error_some_error_occured_in_a_file_that_was_used_in_this_one,none, "some error occured in a file that was used by this one", ()) #ifndef DIAG_NO_UNDEF # if defined(DIAG) diff --git a/lib/AST/DiagnosticConsumer.cpp b/lib/AST/DiagnosticConsumer.cpp index 1f9b42da98e..7347944ff82 100644 --- a/lib/AST/DiagnosticConsumer.cpp +++ b/lib/AST/DiagnosticConsumer.cpp @@ -17,6 +17,7 @@ #define DEBUG_TYPE "swift-ast" #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" @@ -71,7 +72,8 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange( Optional bufferID = SM.getIDForBufferIdentifier(pair.first); assert(bufferID.hasValue() && "consumer registered for unknown file"); CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue()); - ConsumersOrderedByRange.emplace_back(range, pair.second.get()); + ConsumersOrderedByRange.emplace_back( + ConsumerSpecificInformation(range, pair.second.get())); } // Sort the "map" by buffer /end/ location, for use with std::lower_bound @@ -79,23 +81,23 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange( // ranges must not be overlapping, but since we need to check end locations // later it's consistent to sort by that here.) std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), - [](const ConsumersOrderedByRangeEntry &left, - const ConsumersOrderedByRangeEntry &right) -> bool { - auto compare = std::less(); - return compare(getRawLoc(left.first.getEnd()).getPointer(), - getRawLoc(right.first.getEnd()).getPointer()); - }); + [](const ConsumerSpecificInformation &left, + const ConsumerSpecificInformation &right) -> bool { + auto compare = std::less(); + return compare(getRawLoc(left.range.getEnd()).getPointer(), + getRawLoc(right.range.getEnd()).getPointer()); + }); // Check that the ranges are non-overlapping. If the files really are all // distinct, this should be trivially true, but if it's ever not we might end // up mis-filing diagnostics. assert(ConsumersOrderedByRange.end() == - std::adjacent_find(ConsumersOrderedByRange.begin(), - ConsumersOrderedByRange.end(), - [](const ConsumersOrderedByRangeEntry &left, - const ConsumersOrderedByRangeEntry &right) { - return left.first.overlaps(right.first); - }) && + std::adjacent_find(ConsumersOrderedByRange.begin(), + ConsumersOrderedByRange.end(), + [](const ConsumerSpecificInformation &left, + const ConsumerSpecificInformation &right) { + return left.range.overlaps(right.range); + }) && "overlapping ranges despite having distinct files"); } @@ -139,20 +141,17 @@ FileSpecificDiagnosticConsumer::consumerForLocation(SourceManager &SM, // that /might/ contain 'loc'. Specifically, since the ranges are sorted // by end location, it's looking for the first range where the end location // is greater than or equal to 'loc'. - auto possiblyContainingRangeIter = - std::lower_bound(ConsumersOrderedByRange.begin(), - ConsumersOrderedByRange.end(), - loc, - [](const ConsumersOrderedByRangeEntry &entry, - SourceLoc loc) -> bool { - auto compare = std::less(); - return compare(getRawLoc(entry.first.getEnd()).getPointer(), - getRawLoc(loc).getPointer()); - }); + auto possiblyContainingRangeIter = std::lower_bound( + ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc, + [](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool { + auto compare = std::less(); + return compare(getRawLoc(entry.range.getEnd()).getPointer(), + getRawLoc(loc).getPointer()); + }); if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() && - possiblyContainingRangeIter->first.contains(loc)) { - return possiblyContainingRangeIter->second; + possiblyContainingRangeIter->range.contains(loc)) { + return possiblyContainingRangeIter->consumer; } return None; @@ -176,36 +175,57 @@ void FileSpecificDiagnosticConsumer::handleDiagnostic( break; } - const bool isErrorFatal = Kind == DiagnosticKind::Error; if (!specificConsumer.hasValue()) { for (auto &subConsumer : SubConsumers) { if (subConsumer.second) { subConsumer.second->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info); - WasAFatalDiagnosticEmitted |= isErrorFatal; } } - } else if (DiagnosticConsumer *c = specificConsumer.getValue()) { + } else if (DiagnosticConsumer *c = specificConsumer.getValue()) c->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info); - WasAFatalDiagnosticEmitted |= isErrorFatal; - } else { // Suppress non-primary diagnostic in batch mode. - WasAFatalDiagnosticSuppressed |= isErrorFatal; - } -} - -bool FileSpecificDiagnosticConsumer::hadOnlySuppressedFatalErrors() const { - return WasAFatalDiagnosticSuppressed && !WasAFatalDiagnosticEmitted; + else + WasAnErrorSuppressed = + true; // Suppress non-primary diagnostic in batch mode. } bool FileSpecificDiagnosticConsumer::finishProcessing() { // Deliberately don't use std::any_of here because we don't want early-exit // behavior. + + addNonSpecificErrors(); + bool hadError = false; for (auto &subConsumer : SubConsumers) hadError |= subConsumer.second && subConsumer.second->finishProcessing(); return hadError; } +void FileSpecificDiagnosticConsumer::addNonSpecificErrors() { + if (!WasAnErrorSuppressed) + return; + + SourceManager s; + + Diagnostic diagnostic( + diag::error_some_error_occured_in_a_file_that_was_used_in_this_one); + + // Stolen from DiagnosticEngine::emitDiagnostic + DiagnosticInfo Info; + Info.ID = diagnostic.getID(); + Info.Ranges = diagnostic.getRanges(); + Info.FixIts = diagnostic.getFixIts(); + + for (auto &info : ConsumersOrderedByRange) { + if (!info.hasAnErrorBeenEmitted && info.consumer) { + info.consumer->handleDiagnostic(s, SourceLoc(), DiagnosticKind::Error, + diagnosticStrings[(unsigned)Info.ID], + diagnostic.getArgs(), Info); + info.hasAnErrorBeenEmitted = true; + } + } +} + void NullDiagnosticConsumer::handleDiagnostic( SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind, StringRef FormatString, ArrayRef FormatArgs, diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 011529f3217..d0456a7d7bc 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -259,14 +259,6 @@ bool DiagnosticEngine::finishProcessing() { return hadError; } -bool DiagnosticEngine::hadOnlySuppressedFatalErrors() const { - for (auto &Consumer : Consumers) { - if (Consumer->hadOnlySuppressedFatalErrors()) - return true; - } - return false; -} - /// \brief Skip forward to one of the given delimiters. /// /// \param Text The text to search through, which will be updated to point diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 38eb9604210..8e6e820c5e5 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1651,9 +1651,6 @@ int swift::performFrontend(ArrayRef Args, auto finishDiagProcessing = [&](int retValue) -> int { FinishDiagProcessingCheckRAII.CalledFinishDiagProcessing = true; - if (Instance->getDiags().hadOnlySuppressedFatalErrors()) - Instance->getDiags().diagnose(SourceLoc(), - diag::error_compilation_failed); bool err = Instance->getDiags().finishProcessing(); return retValue ? retValue : err; };