Jiri Slaby 2018-10-29 16:28:45 +00:00 committed by Git OBS Bridge
parent 13fb9cc2f2
commit 220a78369b
4 changed files with 291 additions and 91 deletions

View File

@ -21,14 +21,14 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cctype>
#include <list>
#include <map>
#include <string>
#include <system_error>
@ -83,6 +83,28 @@ static cl::opt<bool> EnableVarScope(
"do not start with '$' will be reset at the beginning of\n"
"each CHECK-LABEL block."));
static cl::opt<bool> AllowDeprecatedDagOverlap(
"allow-deprecated-dag-overlap", cl::init(false),
cl::desc("Enable overlapping among matches in a group of consecutive\n"
"CHECK-DAG directives. This option is deprecated and is only\n"
"provided for convenience as old tests are migrated to the new\n"
"non-overlapping CHECK-DAG implementation.\n"));
static cl::opt<bool> Verbose("v", cl::init(false),
cl::desc("Print directive pattern matches.\n"));
static cl::opt<bool> VerboseVerbose(
"vv", cl::init(false),
cl::desc("Print information helpful in diagnosing internal FileCheck\n"
"issues. Implies -v.\n"));
static const char * DumpInputEnv = "FILECHECK_DUMP_INPUT_ON_FAILURE";
static cl::opt<bool> DumpInputOnFailure(
"dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
cl::desc("Dump original input to stderr before failing.\n"
"The value can be also controlled using\n"
"FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"));
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===//
@ -98,6 +120,7 @@ enum CheckType {
CheckNot,
CheckDAG,
CheckLabel,
CheckEmpty,
/// Indicates the pattern only matches the end of file. This is used for
/// trailing CHECK-NOTs.
@ -146,8 +169,11 @@ public:
unsigned LineNumber);
size_t Match(StringRef Buffer, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const;
void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const;
void PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable,
SMRange MatchRange = None) const;
void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const;
bool hasVariable() const {
return !(VariableUses.empty() && VariableDefs.empty());
@ -185,12 +211,25 @@ bool Pattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
// Check that there is something on the line.
if (PatternStr.empty()) {
if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
"found empty check string with prefix '" + Prefix + ":'");
return true;
}
if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
SM.PrintMessage(
PatternLoc, SourceMgr::DK_Error,
"found non-empty check string for empty check with prefix '" + Prefix +
":'");
return true;
}
if (CheckTy == Check::CheckEmpty) {
RegExStr = "(\n$)";
return false;
}
// Check to see if this is a fixed string, or if it has regex pieces.
if (!MatchFullLinesHere &&
(PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
@ -463,8 +502,12 @@ size_t Pattern::Match(StringRef Buffer, size_t &MatchLen,
VariableTable[VariableDef.first] = MatchInfo[VariableDef.second];
}
MatchLen = FullMatch.size();
return FullMatch.data() - Buffer.data();
// 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;
}
@ -490,11 +533,9 @@ Pattern::ComputeMatchDistance(StringRef Buffer,
return BufferPrefix.edit_distance(ExampleString);
}
/// Prints additional information about a failure to match involving this
/// pattern.
void Pattern::PrintFailureInfo(
const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const {
void Pattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable,
SMRange MatchRange) const {
// If this was a regular expression using variables, print the current
// variable values.
if (!VariableUses.empty()) {
@ -526,11 +567,19 @@ void Pattern::PrintFailureInfo(
}
}
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
OS.str());
if (MatchRange.isValid())
SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, OS.str(),
{MatchRange});
else
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
SourceMgr::DK_Note, OS.str());
}
}
}
void Pattern::PrintFuzzyMatch(
const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const {
// Attempt to find the closest/best fuzzy match. Usually an error happens
// because some string in the output didn't exactly match. In these cases, we
// would like to show the user a best guess at what "should have" matched, to
@ -710,6 +759,9 @@ static size_t CheckTypeSize(Check::CheckType Ty) {
case Check::CheckLabel:
return sizeof("-LABEL:") - 1;
case Check::CheckEmpty:
return sizeof("-EMPTY:") - 1;
case Check::CheckEOF:
llvm_unreachable("Should not be using EOF size");
}
@ -717,7 +769,37 @@ static size_t CheckTypeSize(Check::CheckType Ty) {
llvm_unreachable("Bad check type");
}
// Get a description of the type.
static std::string CheckTypeName(StringRef Prefix, Check::CheckType Ty) {
switch (Ty) {
case Check::CheckNone:
return "invalid";
case Check::CheckPlain:
return Prefix;
case Check::CheckNext:
return Prefix.str() + "-NEXT";
case Check::CheckSame:
return Prefix.str() + "-SAME";
case Check::CheckNot:
return Prefix.str() + "-NOT";
case Check::CheckDAG:
return Prefix.str() + "-DAG";
case Check::CheckLabel:
return Prefix.str() + "-LABEL";
case Check::CheckEmpty:
return Prefix.str() + "-EMPTY";
case Check::CheckEOF:
return "implicit EOF";
case Check::CheckBadNot:
return "bad NOT";
}
llvm_unreachable("unknown CheckType");
}
static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Buffer.size() <= Prefix.size())
return Check::CheckNone;
char NextChar = Buffer[Prefix.size()];
// Verify that the : is present after the prefix.
@ -743,10 +825,14 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Rest.startswith("LABEL:"))
return Check::CheckLabel;
if (Rest.startswith("EMPTY:"))
return Check::CheckEmpty;
// You can't combine -NOT with another suffix.
if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:"))
Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
return Check::CheckBadNot;
return Check::CheckNone;
@ -906,10 +992,13 @@ static bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) &&
// Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
CheckTy == Check::CheckEmpty) &&
CheckStrings.empty()) {
StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME";
StringRef Type = CheckTy == Check::CheckNext
? "NEXT"
: CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error,
"found '" + UsedPrefix + "-" + Type +
@ -956,12 +1045,49 @@ static bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
return false;
}
static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat,
StringRef Buffer,
StringMap<StringRef> &VariableTable) {
static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
StringRef Prefix, SMLoc Loc, const Pattern &Pat,
StringRef Buffer, StringMap<StringRef> &VariableTable,
size_t MatchPos, size_t MatchLen) {
if (ExpectedMatch) {
if (!Verbose)
return;
if (!VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
return;
}
SMLoc MatchStart = SMLoc::getFromPointer(Buffer.data() + MatchPos);
SMLoc MatchEnd = SMLoc::getFromPointer(Buffer.data() + MatchPos + MatchLen);
SMRange MatchRange(MatchStart, MatchEnd);
SM.PrintMessage(
Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error,
CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
(ExpectedMatch ? "expected" : "excluded") +
" string found in input");
SM.PrintMessage(MatchStart, SourceMgr::DK_Note, "found here", {MatchRange});
Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
}
static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
const CheckString &CheckStr, StringRef Buffer,
StringMap<StringRef> &VariableTable, size_t MatchPos,
size_t MatchLen) {
PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Buffer, VariableTable, MatchPos, MatchLen);
}
static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
StringRef Prefix, SMLoc Loc, const Pattern &Pat,
StringRef Buffer,
StringMap<StringRef> &VariableTable) {
if (!ExpectedMatch && !VerboseVerbose)
return;
// Otherwise, we have an error, emit an error message.
SM.PrintMessage(Loc, SourceMgr::DK_Error,
"expected string not found in input");
SM.PrintMessage(Loc,
ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark,
CheckTypeName(Prefix, Pat.getCheckTy()) + ": " +
(ExpectedMatch ? "expected" : "excluded") +
" string not found in input");
// Print the "scanning from here" line. If the current position is at the
// end of a line, advance to the start of the next line.
@ -971,13 +1097,16 @@ static void PrintCheckFailed(const SourceMgr &SM, SMLoc Loc, const Pattern &Pat,
"scanning from here");
// Allow the pattern to print additional information if desired.
Pat.PrintFailureInfo(SM, Buffer, VariableTable);
Pat.PrintVariableUses(SM, Buffer, VariableTable);
if (ExpectedMatch)
Pat.PrintFuzzyMatch(SM, Buffer, VariableTable);
}
static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr,
StringRef Buffer,
StringMap<StringRef> &VariableTable) {
PrintCheckFailed(SM, CheckStr.Loc, CheckStr.Pat, Buffer, VariableTable);
static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
const CheckString &CheckStr, StringRef Buffer,
StringMap<StringRef> &VariableTable) {
PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
Buffer, VariableTable);
}
/// Count the number of newlines in the specified range.
@ -1025,9 +1154,10 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
StringRef MatchBuffer = Buffer.substr(LastPos);
size_t MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
if (MatchPos == StringRef::npos) {
PrintCheckFailed(SM, *this, MatchBuffer, VariableTable);
PrintNoMatch(true, SM, *this, MatchBuffer, VariableTable);
return StringRef::npos;
}
PrintMatch(true, SM, *this, MatchBuffer, VariableTable, MatchPos, MatchLen);
// Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
// or CHECK-NOT
@ -1055,22 +1185,27 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
/// Verify there is a single line in the given buffer.
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
if (Pat.getCheckTy() != Check::CheckNext)
if (Pat.getCheckTy() != Check::CheckNext &&
Pat.getCheckTy() != Check::CheckEmpty)
return false;
Twine CheckName =
Prefix +
Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
// Count the number of newlines between the previous match and this one.
assert(Buffer.data() !=
SM.getMemoryBuffer(SM.FindBufferContainingLoc(
SMLoc::getFromPointer(Buffer.data())))
->getBufferStart() &&
"CHECK-NEXT can't be the first check in a file");
"CHECK-NEXT and CHECK-EMPTY can't be the first check in a file");
const char *FirstNewLine = nullptr;
unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
if (NumNewLines == 0) {
SM.PrintMessage(Loc, SourceMgr::DK_Error,
Prefix + "-NEXT: is on the same line as previous match");
CheckName + ": is on the same line as previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
"'next' match was here");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
@ -1080,8 +1215,8 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
if (NumNewLines != 1) {
SM.PrintMessage(Loc, SourceMgr::DK_Error,
Prefix +
"-NEXT: is not on the line after the previous match");
CheckName +
": is not on the line after the previous match");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
"'next' match was here");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
@ -1133,13 +1268,15 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
size_t MatchLen = 0;
size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
if (Pos == StringRef::npos)
if (Pos == StringRef::npos) {
PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer,
VariableTable);
continue;
}
PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, Buffer, VariableTable,
Pos, MatchLen);
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Pos),
SourceMgr::DK_Error, Prefix + "-NOT: string occurred!");
SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
Prefix + "-NOT: pattern specified here");
return true;
}
@ -1153,10 +1290,23 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
if (DagNotStrings.empty())
return 0;
size_t LastPos = 0;
size_t StartPos = LastPos;
// The start of the search range.
size_t StartPos = 0;
for (const Pattern &Pat : DagNotStrings) {
struct MatchRange {
size_t Pos;
size_t End;
};
// A sorted list of ranges for non-overlapping CHECK-DAG matches. Match
// ranges are erased from this list once they are no longer in the search
// range.
std::list<MatchRange> MatchRanges;
// We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
// group, so we don't use a range-based for loop here.
for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
PatItr != PatEnd; ++PatItr) {
const Pattern &Pat = *PatItr;
assert((Pat.getCheckTy() == Check::CheckDAG ||
Pat.getCheckTy() == Check::CheckNot) &&
"Invalid CHECK-DAG or CHECK-NOT!");
@ -1168,57 +1318,92 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
size_t MatchLen = 0, MatchPos;
// CHECK-DAG always matches from the start.
StringRef MatchBuffer = Buffer.substr(StartPos);
MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
if (MatchPos == StringRef::npos) {
PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable);
return StringRef::npos;
}
// Re-calc it as the offset relative to the start of the original string.
MatchPos += StartPos;
size_t MatchLen = 0, MatchPos = StartPos;
if (!NotStrings.empty()) {
if (MatchPos < LastPos) {
// Reordered?
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
SourceMgr::DK_Error,
Prefix + "-DAG: found a match of CHECK-DAG"
" reordering across a CHECK-NOT");
SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
SourceMgr::DK_Note,
Prefix + "-DAG: the farthest match of CHECK-DAG"
" is found here");
SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
Prefix + "-NOT: the crossed pattern specified"
" here");
SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
Prefix + "-DAG: the reordered pattern specified"
" here");
// Search for a match that doesn't overlap a previous match in this
// CHECK-DAG group.
for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
StringRef MatchBuffer = Buffer.substr(MatchPos);
size_t MatchPosBuf = Pat.Match(MatchBuffer, MatchLen, VariableTable);
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
if (MatchPosBuf == StringRef::npos) {
PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, MatchBuffer,
VariableTable);
return StringRef::npos;
}
// All subsequent CHECK-DAGs should be matched from the farthest
// position of all precedent CHECK-DAGs (including this one.)
StartPos = LastPos;
// If there's CHECK-NOTs between two CHECK-DAGs or from CHECK to
// CHECK-DAG, verify that there's no 'not' strings occurred in that
// region.
StringRef SkippedRegion = Buffer.slice(LastPos, MatchPos);
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();
// Re-calc it as the offset relative to the start of the original string.
MatchPos += MatchPosBuf;
if (VerboseVerbose)
PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
MatchPos, MatchLen);
MatchRange M{MatchPos, MatchPos + MatchLen};
if (AllowDeprecatedDagOverlap) {
// We don't need to track all matches in this mode, so we just maintain
// one match range that encompasses the current CHECK-DAG group's
// matches.
if (MatchRanges.empty())
MatchRanges.insert(MatchRanges.end(), M);
else {
auto Block = MatchRanges.begin();
Block->Pos = std::min(Block->Pos, M.Pos);
Block->End = std::max(Block->End, M.End);
}
break;
}
// Iterate previous matches until overlapping match or insertion point.
bool Overlap = false;
for (; MI != ME; ++MI) {
if (M.Pos < MI->End) {
// !Overlap => New match has no overlap and is before this old match.
// Overlap => New match overlaps this old match.
Overlap = MI->Pos < M.End;
break;
}
}
if (!Overlap) {
// Insert non-overlapping match into list.
MatchRanges.insert(MI, M);
break;
}
if (VerboseVerbose) {
SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
SMRange OldRange(OldStart, OldEnd);
SM.PrintMessage(OldStart, SourceMgr::DK_Note,
"match discarded, overlaps earlier DAG match here",
{OldRange});
}
MatchPos = MI->End;
}
if (!VerboseVerbose)
PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, Buffer, VariableTable,
MatchPos, MatchLen);
// Update the last position with CHECK-DAG matches.
LastPos = std::max(MatchPos + MatchLen, LastPos);
// Handle the end of a CHECK-DAG group.
if (std::next(PatItr) == PatEnd ||
std::next(PatItr)->getCheckTy() == Check::CheckNot) {
if (!NotStrings.empty()) {
// If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
// CHECK-DAG, verify that there are no 'not' strings occurred in that
// region.
StringRef SkippedRegion =
Buffer.slice(StartPos, MatchRanges.begin()->Pos);
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();
}
// All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
// end of this CHECK-DAG group's match range.
StartPos = MatchRanges.rbegin()->End;
// Don't waste time checking for (impossible) overlaps before that.
MatchRanges.clear();
}
}
return LastPos;
return StartPos;
}
// A check prefix must contain only alphanumeric, hyphens and underscores.
@ -1357,8 +1542,7 @@ bool CheckInput(SourceMgr &SM, StringRef Buffer,
}
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
if (!ValidateCheckPrefixes()) {
@ -1379,6 +1563,9 @@ int main(int argc, char **argv) {
return 2;
}
if (VerboseVerbose)
Verbose = true;
SourceMgr SM;
// Read the expected strings from the check file.
@ -1425,5 +1612,9 @@ int main(int argc, char **argv) {
InputFileText, InputFile.getBufferIdentifier()),
SMLoc());
return CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;
int ExitCode = CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;
if (ExitCode == 1 && DumpInputOnFailure)
errs() << "Full input was:\n<<<<<<\n" << InputFileText << "\n>>>>>>\n";
return ExitCode;
}

View File

@ -1,3 +1,8 @@
-------------------------------------------------------------------
Mon Oct 29 16:28:27 UTC 2018 - Jiri Slaby <jslaby@suse.com>
- switch to LLVM 7
-------------------------------------------------------------------
Sat Oct 27 07:24:23 UTC 2018 - opensuse-packaging@opensuse.org

View File

@ -12,11 +12,11 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%define llvm_version_major 6
%define llvm_version_major 7
%define llvm_version_minor 0
%define llvm_version %{llvm_version_major}

View File

@ -38,8 +38,12 @@ int main(int argc, const char **argv) {
return 1;
}
std::vector<StringRef> Argv;
Argv.reserve(argc);
for (int i = 0; i < argc; ++i)
Argv.push_back(argv[i]);
std::string ErrMsg;
int Result = sys::ExecuteAndWait(*Program, argv, nullptr, {}, 0, 0, &ErrMsg);
int Result = sys::ExecuteAndWait(*Program, Argv, None, {}, 0, 0, &ErrMsg);
#ifdef _WIN32
// Handle abort() in msvcrt -- It has exit code as 3. abort(), aka
// unreachable, should be recognized as a crash. However, some binaries use