diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/FileCheck/FileCheck.cpp | |
parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'llvm/lib/FileCheck/FileCheck.cpp')
-rw-r--r-- | llvm/lib/FileCheck/FileCheck.cpp | 437 |
1 files changed, 256 insertions, 181 deletions
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp index 3169afaed58c..04476d999336 100644 --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -45,8 +45,12 @@ StringRef ExpressionFormat::toString() const { } Expected<std::string> ExpressionFormat::getWildcardRegex() const { - auto CreatePrecisionRegex = [this](StringRef S) { - return (S + Twine('{') + Twine(Precision) + "}").str(); + StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); + + auto CreatePrecisionRegex = [&](StringRef S) { + return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) + + "}") + .str(); }; switch (Value) { @@ -61,11 +65,11 @@ Expected<std::string> ExpressionFormat::getWildcardRegex() const { case Kind::HexUpper: if (Precision) return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]"); - return std::string("[0-9A-F]+"); + return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str(); case Kind::HexLower: if (Precision) return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]"); - return std::string("[0-9a-f]+"); + return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str(); default: return createStringError(std::errc::invalid_argument, "trying to match value with invalid format"); @@ -107,34 +111,48 @@ ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { "trying to match value with invalid format"); } + StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); + if (Precision > AbsoluteValueStr.size()) { unsigned LeadingZeros = Precision - AbsoluteValueStr.size(); - return (Twine(SignPrefix) + std::string(LeadingZeros, '0') + - AbsoluteValueStr) + return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + + std::string(LeadingZeros, '0') + AbsoluteValueStr) .str(); } - return (Twine(SignPrefix) + AbsoluteValueStr).str(); + return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr) + .str(); } Expected<ExpressionValue> ExpressionFormat::valueFromStringRepr(StringRef StrVal, const SourceMgr &SM) const { bool ValueIsSigned = Value == Kind::Signed; - StringRef OverflowErrorStr = "unable to represent numeric value"; + // Both the FileCheck utility and library only call this method with a valid + // value in StrVal. This is guaranteed by the regex returned by + // getWildcardRegex() above. Only underflow and overflow errors can thus + // occur. However new uses of this method could be added in the future so + // the error message does not make assumptions about StrVal. + StringRef IntegerParseErrorStr = "unable to represent numeric value"; if (ValueIsSigned) { int64_t SignedValue; if (StrVal.getAsInteger(10, SignedValue)) - return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); + return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); return ExpressionValue(SignedValue); } bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; uint64_t UnsignedValue; + bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x"); if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue)) - return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr); + return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr); + + // Error out for a missing prefix only now that we know we have an otherwise + // valid integer. For example, "-0x18" is reported above instead. + if (MissingFormPrefix) + return ErrorDiagnostic::get(SM, StrVal, "missing alternate form prefix"); return ExpressionValue(UnsignedValue); } @@ -458,6 +476,7 @@ char OverflowError::ID = 0; char UndefVarError::ID = 0; char ErrorDiagnostic::ID = 0; char NotFoundError::ID = 0; +char ErrorReported::ID = 0; Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( StringRef &Expr, FileCheckPatternContext *Context, @@ -512,7 +531,7 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( // we get below is null, it means no such variable was defined before. When // that happens, we create a dummy variable so that parsing can continue. All // uses of undefined variables, whether string or numeric, are then diagnosed - // in printSubstitutions() after failing to match. + // in printNoMatch() after failing to match. auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); NumericVariable *NumericVariable; if (VarTableIter != Context->GlobalNumericVariableTable.end()) @@ -767,6 +786,10 @@ Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( SM, FormatExpr, "invalid matching format specification in expression"); + // Parse alternate form flag. + SMLoc AlternateFormFlagLoc = SMLoc::getFromPointer(FormatExpr.data()); + bool AlternateForm = FormatExpr.consume_front("#"); + // Parse precision. if (FormatExpr.consume_front(".")) { if (FormatExpr.consumeInteger(10, Precision)) @@ -788,12 +811,12 @@ Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( ExpressionFormat(ExpressionFormat::Kind::Signed, Precision); break; case 'x': - ExplicitFormat = - ExpressionFormat(ExpressionFormat::Kind::HexLower, Precision); + ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower, + Precision, AlternateForm); break; case 'X': - ExplicitFormat = - ExpressionFormat(ExpressionFormat::Kind::HexUpper, Precision); + ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper, + Precision, AlternateForm); break; default: return ErrorDiagnostic::get(SM, FmtLoc, @@ -801,6 +824,12 @@ Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock( } } + if (AlternateForm && ExplicitFormat != ExpressionFormat::Kind::HexLower && + ExplicitFormat != ExpressionFormat::Kind::HexUpper) + return ErrorDiagnostic::get( + SM, AlternateFormFlagLoc, + "alternate form only supported for hex values"); + FormatExpr = FormatExpr.ltrim(SpaceChars); if (!FormatExpr.empty()) return ErrorDiagnostic::get( @@ -1054,8 +1083,15 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, if (IsPseudo) { MatchStr = OrigMatchStr; IsLegacyLineExpr = IsNumBlock = true; - } else + } else { + if (!MatchStr.empty()) { + SM.PrintMessage(SMLoc::getFromPointer(Name.data()), + SourceMgr::DK_Error, + "invalid name in string variable use"); + return true; + } SubstStr = Name; + } } } @@ -1184,22 +1220,19 @@ void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { RegExStr += Backref; } -Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, - const SourceMgr &SM) const { +Pattern::MatchResult Pattern::match(StringRef Buffer, + const SourceMgr &SM) const { // If this is the EOF pattern, match it immediately. - if (CheckTy == Check::CheckEOF) { - MatchLen = 0; - return Buffer.size(); - } + if (CheckTy == Check::CheckEOF) + return MatchResult(Buffer.size(), 0, Error::success()); // If this is a fixed string pattern, just match it now. if (!FixedStr.empty()) { - MatchLen = FixedStr.size(); size_t Pos = - IgnoreCase ? Buffer.find_lower(FixedStr) : Buffer.find(FixedStr); + IgnoreCase ? Buffer.find_insensitive(FixedStr) : Buffer.find(FixedStr); if (Pos == StringRef::npos) return make_error<NotFoundError>(); - return Pos; + return MatchResult(Pos, /*MatchLen=*/FixedStr.size(), Error::success()); } // Regex match. @@ -1217,20 +1250,28 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, // Substitute all string variables and expressions whose values are only // now known. Use of string variables defined on the same line are handled // by back-references. + Error Errs = Error::success(); for (const auto &Substitution : Substitutions) { // Substitute and check for failure (e.g. use of undefined variable). Expected<std::string> Value = Substitution->getResult(); if (!Value) { // Convert to an ErrorDiagnostic to get location information. This is - // done here rather than PrintNoMatch since now we know which + // done here rather than printMatch/printNoMatch since now we know which // substitution block caused the overflow. - Error Err = - handleErrors(Value.takeError(), [&](const OverflowError &E) { - return ErrorDiagnostic::get(SM, Substitution->getFromString(), - "unable to substitute variable or " - "numeric expression: overflow error"); - }); - return std::move(Err); + Errs = joinErrors(std::move(Errs), + handleErrors( + Value.takeError(), + [&](const OverflowError &E) { + return ErrorDiagnostic::get( + SM, Substitution->getFromString(), + "unable to substitute variable or " + "numeric expression: overflow error"); + }, + [&SM](const UndefVarError &E) { + return ErrorDiagnostic::get(SM, E.getVarName(), + E.message()); + })); + continue; } // Plop it into the regex at the adjusted offset. @@ -1238,6 +1279,8 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, Value->begin(), Value->end()); InsertOffset += Value->size(); } + if (Errs) + return std::move(Errs); // Match the newly constructed regex. RegExToMatch = TmpStr; @@ -1261,6 +1304,14 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, MatchInfo[VariableDef.second]; } + // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after + // the required preceding newline, which is consumed by the pattern in the + // case of CHECK-EMPTY but not CHECK-NEXT. + size_t MatchStartSkip = CheckTy == Check::CheckEmpty; + Match TheMatch; + TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip; + TheMatch.Len = FullMatch.size() - MatchStartSkip; + // If this defines any numeric variables, remember their values. for (const auto &NumericVariableDef : NumericVariableDefs) { const NumericVariableMatch &NumericVariableMatch = @@ -1275,16 +1326,11 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, Expected<ExpressionValue> Value = Format.valueFromStringRepr(MatchedValue, SM); if (!Value) - return Value.takeError(); + return MatchResult(TheMatch, Value.takeError()); DefinedNumericVariable->setValue(*Value, MatchedValue); } - // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after - // the required preceding newline, which is consumed by the pattern in the - // case of CHECK-EMPTY but not CHECK-NEXT. - size_t MatchStartSkip = CheckTy == Check::CheckEmpty; - MatchLen = FullMatch.size() - MatchStartSkip; - return FullMatch.data() - Buffer.data() + MatchStartSkip; + return MatchResult(TheMatch, Error::success()); } unsigned Pattern::computeMatchDistance(StringRef Buffer) const { @@ -1313,33 +1359,18 @@ void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, for (const auto &Substitution : Substitutions) { SmallString<256> Msg; raw_svector_ostream OS(Msg); - Expected<std::string> MatchedValue = Substitution->getResult(); - // Substitution failed or is not known at match time, print the undefined - // variables it uses. + Expected<std::string> MatchedValue = Substitution->getResult(); + // Substitution failures are handled in printNoMatch(). if (!MatchedValue) { - bool UndefSeen = false; - handleAllErrors( - MatchedValue.takeError(), [](const NotFoundError &E) {}, - // Handled in PrintNoMatch(). - [](const ErrorDiagnostic &E) {}, - // Handled in match(). - [](const OverflowError &E) {}, - [&](const UndefVarError &E) { - if (!UndefSeen) { - OS << "uses undefined variable(s):"; - UndefSeen = true; - } - OS << " "; - E.log(OS); - }); - } else { - // Substitution succeeded. Print substituted value. - OS << "with \""; - OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; - OS.write_escaped(*MatchedValue) << "\""; + consumeError(MatchedValue.takeError()); + continue; } + OS << "with \""; + OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; + OS.write_escaped(*MatchedValue) << "\""; + // We report only the start of the match/search range to suggest we are // reporting the substitutions as set at the start of the match/search. // Indicating a non-zero-length range might instead seem to imply that the @@ -1376,11 +1407,12 @@ void Pattern::printVariableDefs(const SourceMgr &SM, for (const auto &VariableDef : NumericVariableDefs) { VarCapture VC; VC.Name = VariableDef.getKey(); - StringRef StrValue = VariableDef.getValue() - .DefinedNumericVariable->getStringValue() - .getValue(); - SMLoc Start = SMLoc::getFromPointer(StrValue.data()); - SMLoc End = SMLoc::getFromPointer(StrValue.data() + StrValue.size()); + Optional<StringRef> StrValue = + VariableDef.getValue().DefinedNumericVariable->getStringValue(); + if (!StrValue) + continue; + SMLoc Start = SMLoc::getFromPointer(StrValue->data()); + SMLoc End = SMLoc::getFromPointer(StrValue->data() + StrValue->size()); VC.Range = SMRange(Start, End); VarCaptures.push_back(VC); } @@ -2008,126 +2040,173 @@ bool FileCheck::readCheckFile( return false; } -static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, - StringRef Prefix, SMLoc Loc, const Pattern &Pat, - int MatchedCount, StringRef Buffer, size_t MatchPos, - size_t MatchLen, const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) { +/// Returns either (1) \c ErrorSuccess if there was no error or (2) +/// \c ErrorReported if an error was reported, such as an unexpected match. +static Error printMatch(bool ExpectedMatch, const SourceMgr &SM, + StringRef Prefix, SMLoc Loc, const Pattern &Pat, + int MatchedCount, StringRef Buffer, + Pattern::MatchResult MatchResult, + const FileCheckRequest &Req, + std::vector<FileCheckDiag> *Diags) { + // Suppress some verbosity if there's no error. + bool HasError = !ExpectedMatch || MatchResult.TheError; bool PrintDiag = true; - if (ExpectedMatch) { + if (!HasError) { if (!Req.Verbose) - return; + return ErrorReported::reportedOrSuccess(HasError); if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF) - return; + return ErrorReported::reportedOrSuccess(HasError); // Due to their verbosity, we don't print verbose diagnostics here if we're - // gathering them for a different rendering, but we always print other - // diagnostics. + // gathering them for Diags to be rendered elsewhere, but we always print + // other diagnostics. PrintDiag = !Diags; } + + // Add "found" diagnostic, substitutions, and variable definitions to Diags. FileCheckDiag::MatchType MatchTy = ExpectedMatch ? FileCheckDiag::MatchFoundAndExpected : FileCheckDiag::MatchFoundButExcluded; SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), - Buffer, MatchPos, MatchLen, Diags); + Buffer, MatchResult.TheMatch->Pos, + MatchResult.TheMatch->Len, Diags); if (Diags) { Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags); Pat.printVariableDefs(SM, MatchTy, Diags); } - if (!PrintDiag) - return; + if (!PrintDiag) { + assert(!HasError && "expected to report more diagnostics for error"); + return ErrorReported::reportedOrSuccess(HasError); + } + // Print the match. std::string Message = formatv("{0}: {1} string found in input", Pat.getCheckTy().getDescription(Prefix), (ExpectedMatch ? "expected" : "excluded")) .str(); if (Pat.getCount() > 1) Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); - SM.PrintMessage( Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", {MatchRange}); + + // Print additional information, which can be useful even if there are errors. Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr); Pat.printVariableDefs(SM, MatchTy, nullptr); -} -static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, - const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, size_t MatchPos, size_t MatchLen, - FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) { - PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, - MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags); -} - -static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, - StringRef Prefix, SMLoc Loc, const Pattern &Pat, - int MatchedCount, StringRef Buffer, - bool VerboseVerbose, std::vector<FileCheckDiag> *Diags, - Error MatchErrors) { - assert(MatchErrors && "Called on successful match"); + // Print errors and add them to Diags. We report these errors after the match + // itself because we found them after the match. If we had found them before + // the match, we'd be in printNoMatch. + handleAllErrors(std::move(MatchResult.TheError), + [&](const ErrorDiagnostic &E) { + E.log(errs()); + if (Diags) { + Diags->emplace_back(SM, Pat.getCheckTy(), Loc, + FileCheckDiag::MatchFoundErrorNote, + E.getRange(), E.getMessage().str()); + } + }); + return ErrorReported::reportedOrSuccess(HasError); +} + +/// Returns either (1) \c ErrorSuccess if there was no error, or (2) +/// \c ErrorReported if an error was reported, such as an expected match not +/// found. +static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM, + StringRef Prefix, SMLoc Loc, const Pattern &Pat, + int MatchedCount, StringRef Buffer, Error MatchError, + bool VerboseVerbose, + std::vector<FileCheckDiag> *Diags) { + // Print any pattern errors, and record them to be added to Diags later. + bool HasError = ExpectedMatch; + bool HasPatternError = false; + FileCheckDiag::MatchType MatchTy = ExpectedMatch + ? FileCheckDiag::MatchNoneButExpected + : FileCheckDiag::MatchNoneAndExcluded; + SmallVector<std::string, 4> ErrorMsgs; + handleAllErrors( + std::move(MatchError), + [&](const ErrorDiagnostic &E) { + HasError = HasPatternError = true; + MatchTy = FileCheckDiag::MatchNoneForInvalidPattern; + E.log(errs()); + if (Diags) + ErrorMsgs.push_back(E.getMessage().str()); + }, + // NotFoundError is why printNoMatch was invoked. + [](const NotFoundError &E) {}); + + // Suppress some verbosity if there's no error. bool PrintDiag = true; - if (!ExpectedMatch) { - if (!VerboseVerbose) { - consumeError(std::move(MatchErrors)); - return; - } + if (!HasError) { + if (!VerboseVerbose) + return ErrorReported::reportedOrSuccess(HasError); // Due to their verbosity, we don't print verbose diagnostics here if we're - // gathering them for a different rendering, but we always print other - // diagnostics. + // gathering them for Diags to be rendered elsewhere, but we always print + // other diagnostics. PrintDiag = !Diags; } - // If the current position is at the end of a line, advance to the start of - // the next line. - Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r")); - FileCheckDiag::MatchType MatchTy = ExpectedMatch - ? FileCheckDiag::MatchNoneButExpected - : FileCheckDiag::MatchNoneAndExcluded; + // Add "not found" diagnostic, substitutions, and pattern errors to Diags. + // + // We handle Diags a little differently than the errors we print directly: + // we add the "not found" diagnostic to Diags even if there are pattern + // errors. The reason is that we need to attach pattern errors as notes + // somewhere in the input, and the input search range from the "not found" + // diagnostic is all we have to anchor them. SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags); - if (Diags) + if (Diags) { + SMRange NoteRange = SMRange(SearchRange.Start, SearchRange.Start); + for (StringRef ErrorMsg : ErrorMsgs) + Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange, + ErrorMsg); Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags); - if (!PrintDiag) { - consumeError(std::move(MatchErrors)); - return; } - - MatchErrors = handleErrors(std::move(MatchErrors), - [](const ErrorDiagnostic &E) { E.log(errs()); }); - - // No problem matching the string per se. - if (!MatchErrors) - return; - consumeError(std::move(MatchErrors)); - - // Print "not found" diagnostic. - std::string Message = formatv("{0}: {1} string not found in input", - Pat.getCheckTy().getDescription(Prefix), - (ExpectedMatch ? "expected" : "excluded")) - .str(); - if (Pat.getCount() > 1) - Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); - SM.PrintMessage( - Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message); - - // Print the "scanning from here" line. - SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here"); - - // Allow the pattern to print additional information if desired. + if (!PrintDiag) { + assert(!HasError && "expected to report more diagnostics for error"); + return ErrorReported::reportedOrSuccess(HasError); + } + + // Print "not found" diagnostic, except that's implied if we already printed a + // pattern error. + if (!HasPatternError) { + std::string Message = formatv("{0}: {1} string not found in input", + Pat.getCheckTy().getDescription(Prefix), + (ExpectedMatch ? "expected" : "excluded")) + .str(); + if (Pat.getCount() > 1) + Message += + formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str(); + SM.PrintMessage(Loc, + ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, + Message); + SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, + "scanning from here"); + } + + // Print additional information, which can be useful even after a pattern + // error. Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr); - if (ExpectedMatch) Pat.printFuzzyMatch(SM, Buffer, Diags); + return ErrorReported::reportedOrSuccess(HasError); } -static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, - const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, bool VerboseVerbose, - std::vector<FileCheckDiag> *Diags, Error MatchErrors) { - PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, - MatchedCount, Buffer, VerboseVerbose, Diags, - std::move(MatchErrors)); +/// Returns either (1) \c ErrorSuccess if there was no error, or (2) +/// \c ErrorReported if an error was reported. +static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM, + StringRef Prefix, SMLoc Loc, const Pattern &Pat, + int MatchedCount, StringRef Buffer, + Pattern::MatchResult MatchResult, + const FileCheckRequest &Req, + std::vector<FileCheckDiag> *Diags) { + if (MatchResult.TheMatch) + return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, + std::move(MatchResult), Req, Diags); + return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer, + std::move(MatchResult.TheError), Req.VerboseVerbose, + Diags); } /// Counts the number of newlines in the specified range. @@ -2179,24 +2258,23 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, assert(Pat.getCount() != 0 && "pattern count can not be zero"); for (int i = 1; i <= Pat.getCount(); i++) { StringRef MatchBuffer = Buffer.substr(LastMatchEnd); - size_t CurrentMatchLen; // get a match at current start point - Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM); + Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); // report - if (!MatchResult) { - PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags, - MatchResult.takeError()); + if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, Loc, + Pat, i, MatchBuffer, + std::move(MatchResult), Req, Diags)) { + cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); return StringRef::npos; } - size_t MatchPos = *MatchResult; - PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req, - Diags); + + size_t MatchPos = MatchResult.TheMatch->Pos; if (i == 1) FirstMatchPos = LastPos + MatchPos; // move start point after the match - LastMatchEnd += MatchPos + CurrentMatchLen; + LastMatchEnd += MatchPos + MatchResult.TheMatch->Len; } // Full match len counts from first match pos. MatchLen = LastMatchEnd - FirstMatchPos; @@ -2303,22 +2381,15 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, bool DirectiveFail = false; for (const Pattern *Pat : NotStrings) { assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); - - size_t MatchLen = 0; - Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM); - - if (!MatchResult) { - PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, - Req.VerboseVerbose, Diags, MatchResult.takeError()); + Pattern::MatchResult MatchResult = Pat->match(Buffer, SM); + if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix, + Pat->getLoc(), *Pat, 1, Buffer, + std::move(MatchResult), Req, Diags)) { + cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {})); + DirectiveFail = true; continue; } - size_t Pos = *MatchResult; - - PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen, - Req, Diags); - DirectiveFail = true; } - return DirectiveFail; } @@ -2364,20 +2435,22 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // CHECK-DAG group. for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { StringRef MatchBuffer = Buffer.substr(MatchPos); - Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM); + Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM); // With a group of CHECK-DAGs, a single mismatching means the match on // that group of CHECK-DAGs fails immediately. - if (!MatchResult) { - PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer, - Req.VerboseVerbose, Diags, MatchResult.takeError()); - return StringRef::npos; + if (MatchResult.TheError || Req.VerboseVerbose) { + if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, + Pat.getLoc(), Pat, 1, MatchBuffer, + std::move(MatchResult), Req, Diags)) { + cantFail( + handleErrors(std::move(Err), [&](const ErrorReported &E) {})); + return StringRef::npos; + } } - size_t MatchPosBuf = *MatchResult; - // Re-calc it as the offset relative to the start of the original string. - MatchPos += MatchPosBuf; - if (Req.VerboseVerbose) - PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, - MatchLen, Req, Diags); + MatchLen = MatchResult.TheMatch->Len; + // Re-calc it as the offset relative to the start of the original + // string. + MatchPos += MatchResult.TheMatch->Pos; MatchRange M{MatchPos, MatchPos + MatchLen}; if (Req.AllowDeprecatedDagOverlap) { // We don't need to track all matches in this mode, so we just maintain @@ -2428,8 +2501,10 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, MatchPos = MI->End; } if (!Req.VerboseVerbose) - PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos, - MatchLen, Req, Diags); + cantFail(printMatch( + /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, + Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req, + Diags)); // Handle the end of a CHECK-DAG group. if (std::next(PatItr) == PatEnd || |