diff options
author | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
commit | ce9904c6ea8fd669978a8eefb854b330eb9828ff (patch) | |
tree | 2418ee2e96ea220977c8fb74959192036ab5b133 /utils/FileCheck | |
parent | c27b10b198c1d9e9b51f2303994313ec2778edd7 (diff) | |
parent | dbb832b83351cec97b025b61c26536ef50c3181c (diff) | |
download | external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.zip external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.gz external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.bz2 |
Merge remote-tracking branch 'upstream/release_34' into merge-20140211
Conflicts:
lib/Linker/LinkModules.cpp
lib/Support/Unix/Signals.inc
Change-Id: Ia54f291fa5dc828052d2412736e8495c1282aa64
Diffstat (limited to 'utils/FileCheck')
-rw-r--r-- | utils/FileCheck/CMakeLists.txt | 2 | ||||
-rw-r--r-- | utils/FileCheck/FileCheck.cpp | 433 |
2 files changed, 318 insertions, 117 deletions
diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt index fa56f92..d691ceb 100644 --- a/utils/FileCheck/CMakeLists.txt +++ b/utils/FileCheck/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_utility(FileCheck target_link_libraries(FileCheck LLVMSupport) if( MINGW ) - target_link_libraries(FileCheck imagehlp psapi) + target_link_libraries(FileCheck imagehlp psapi shell32) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD ) target_link_libraries(FileCheck pthread) diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 8d5af58..f2510d7 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" @@ -29,6 +30,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> +#include <cctype> #include <map> #include <string> #include <vector> @@ -41,30 +43,39 @@ static cl::opt<std::string> InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), cl::init("-"), cl::value_desc("filename")); -static cl::opt<std::string> -CheckPrefix("check-prefix", cl::init("CHECK"), - cl::desc("Prefix to use from check file (defaults to 'CHECK')")); +static cl::list<std::string> +CheckPrefixes("check-prefix", + cl::desc("Prefix to use from check file (defaults to 'CHECK')")); static cl::opt<bool> NoCanonicalizeWhiteSpace("strict-whitespace", cl::desc("Do not treat all horizontal whitespace as equivalent")); +typedef cl::list<std::string>::const_iterator prefix_iterator; + //===----------------------------------------------------------------------===// // Pattern Handling Code. //===----------------------------------------------------------------------===// +namespace Check { + enum CheckType { + CheckNone = 0, + CheckPlain, + CheckNext, + CheckNot, + CheckDAG, + CheckLabel, + + /// MatchEOF - When set, this pattern only matches the end of file. This is + /// used for trailing CHECK-NOTs. + CheckEOF + }; +} + class Pattern { SMLoc PatternLoc; - /// MatchEOF - When set, this pattern only matches the end of file. This is - /// used for trailing CHECK-NOTs. - bool MatchEOF; - - /// MatchNot - bool MatchNot; - - /// MatchDag - bool MatchDag; + Check::CheckType CheckTy; /// FixedStr - If non-empty, this pattern is a fixed string match with the /// specified fixed string. @@ -89,17 +100,21 @@ class Pattern { public: - Pattern(bool matchEOF = false) - : MatchEOF(matchEOF), MatchNot(false), MatchDag(false) { } + Pattern(Check::CheckType Ty) + : CheckTy(Ty) { } /// getLoc - Return the location in source code. SMLoc getLoc() const { return PatternLoc; } - /// ParsePattern - Parse the given string into the Pattern. SM provides the - /// SourceMgr used for error reports, and LineNumber is the line number in - /// the input file from which the pattern string was read. - /// Returns true in case of an error, false otherwise. - bool ParsePattern(StringRef PatternStr, SourceMgr &SM, unsigned LineNumber); + /// ParsePattern - Parse the given string into the Pattern. Prefix provides + /// which prefix is being matched, SM provides the SourceMgr used for error + /// reports, and LineNumber is the line number in the input file from which + /// the pattern string was read. Returns true in case of an error, false + /// otherwise. + bool ParsePattern(StringRef PatternStr, + StringRef Prefix, + SourceMgr &SM, + unsigned LineNumber); /// Match - Match the pattern string against the input buffer Buffer. This /// returns the position that is matched or npos if there is no match. If @@ -118,11 +133,7 @@ public: bool hasVariable() const { return !(VariableUses.empty() && VariableDefs.empty()); } - void setMatchNot(bool Not) { MatchNot = Not; } - bool getMatchNot() const { return MatchNot; } - - void setMatchDag(bool Dag) { MatchDag = Dag; } - bool getMatchDag() const { return MatchDag; } + Check::CheckType getCheckTy() const { return CheckTy; } private: static void AddFixedStringToRegEx(StringRef FixedStr, std::string &TheStr); @@ -148,7 +159,9 @@ private: }; -bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, +bool Pattern::ParsePattern(StringRef PatternStr, + StringRef Prefix, + SourceMgr &SM, unsigned LineNumber) { this->LineNumber = LineNumber; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); @@ -162,7 +175,7 @@ bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM, if (PatternStr.empty()) { SM.PrintMessage(PatternLoc, SourceMgr::DK_Error, "found empty check string with prefix '" + - CheckPrefix+":'"); + Prefix + ":'"); return true; } @@ -381,7 +394,7 @@ bool Pattern::EvaluateExpression(StringRef Expr, std::string &Value) const { size_t Pattern::Match(StringRef Buffer, size_t &MatchLen, StringMap<StringRef> &VariableTable) const { // If this is the EOF pattern, match it immediately. - if (MatchEOF) { + if (CheckTy == Check::CheckEOF) { MatchLen = 0; return Buffer.size(); } @@ -590,27 +603,30 @@ struct CheckString { /// Pat - The pattern to match. Pattern Pat; + /// Prefix - Which prefix name this check matched. + StringRef Prefix; + /// Loc - The location in the match file that the check string was specified. SMLoc Loc; - /// IsCheckNext - This is true if this is a CHECK-NEXT: directive (as opposed - /// to a CHECK: directive. - bool IsCheckNext; - - /// IsCheckLabel - This is true if this is a CHECK-LABEL: directive (as - /// opposed to a CHECK: directive. - bool IsCheckLabel; + /// CheckTy - Specify what kind of check this is. e.g. CHECK-NEXT: directive, + /// as opposed to a CHECK: directive. + Check::CheckType CheckTy; /// DagNotStrings - These are all of the strings that are disallowed from /// occurring between this match string and the previous one (or start of /// file). std::vector<Pattern> DagNotStrings; - CheckString(const Pattern &P, SMLoc L, bool isCheckNext, bool isCheckLabel) - : Pat(P), Loc(L), IsCheckNext(isCheckNext), IsCheckLabel(isCheckLabel) {} + + CheckString(const Pattern &P, + StringRef S, + SMLoc L, + Check::CheckType Ty) + : Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {} /// Check - Match check string and its "not strings" and/or "dag strings". - size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel, + size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t &MatchLen, StringMap<StringRef> &VariableTable) const; /// CheckNext - Verify there is a single line in the given buffer. @@ -666,6 +682,161 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB, return MB2; } +static bool IsPartOfWord(char c) { + return (isalnum(c) || c == '-' || c == '_'); +} + +// Get the size of the prefix extension. +static size_t CheckTypeSize(Check::CheckType Ty) { + switch (Ty) { + case Check::CheckNone: + return 0; + + case Check::CheckPlain: + return sizeof(":") - 1; + + case Check::CheckNext: + return sizeof("-NEXT:") - 1; + + case Check::CheckNot: + return sizeof("-NOT:") - 1; + + case Check::CheckDAG: + return sizeof("-DAG:") - 1; + + case Check::CheckLabel: + return sizeof("-LABEL:") - 1; + + case Check::CheckEOF: + llvm_unreachable("Should not be using EOF size"); + } + + llvm_unreachable("Bad check type"); +} + +static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { + char NextChar = Buffer[Prefix.size()]; + + // Verify that the : is present after the prefix. + if (NextChar == ':') + return Check::CheckPlain; + + if (NextChar != '-') + return Check::CheckNone; + + StringRef Rest = Buffer.drop_front(Prefix.size() + 1); + if (Rest.startswith("NEXT:")) + return Check::CheckNext; + + if (Rest.startswith("NOT:")) + return Check::CheckNot; + + if (Rest.startswith("DAG:")) + return Check::CheckDAG; + + if (Rest.startswith("LABEL:")) + return Check::CheckLabel; + + return Check::CheckNone; +} + +// From the given position, find the next character after the word. +static size_t SkipWord(StringRef Str, size_t Loc) { + while (Loc < Str.size() && IsPartOfWord(Str[Loc])) + ++Loc; + return Loc; +} + +// Try to find the first match in buffer for any prefix. If a valid match is +// found, return that prefix and set its type and location. If there are almost +// matches (e.g. the actual prefix string is found, but is not an actual check +// string), but no valid match, return an empty string and set the position to +// resume searching from. If no partial matches are found, return an empty +// string and the location will be StringRef::npos. If one prefix is a substring +// of another, the maximal match should be found. e.g. if "A" and "AA" are +// prefixes then AA-CHECK: should match the second one. +static StringRef FindFirstCandidateMatch(StringRef &Buffer, + Check::CheckType &CheckTy, + size_t &CheckLoc) { + StringRef FirstPrefix; + size_t FirstLoc = StringRef::npos; + size_t SearchLoc = StringRef::npos; + Check::CheckType FirstTy = Check::CheckNone; + + CheckTy = Check::CheckNone; + CheckLoc = StringRef::npos; + + for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end(); + I != E; ++I) { + StringRef Prefix(*I); + size_t PrefixLoc = Buffer.find(Prefix); + + if (PrefixLoc == StringRef::npos) + continue; + + // Track where we are searching for invalid prefixes that look almost right. + // We need to only advance to the first partial match on the next attempt + // since a partial match could be a substring of a later, valid prefix. + // Need to skip to the end of the word, otherwise we could end up + // matching a prefix in a substring later. + if (PrefixLoc < SearchLoc) + SearchLoc = SkipWord(Buffer, PrefixLoc); + + // We only want to find the first match to avoid skipping some. + if (PrefixLoc > FirstLoc) + continue; + // If one matching check-prefix is a prefix of another, choose the + // longer one. + if (PrefixLoc == FirstLoc && Prefix.size() < FirstPrefix.size()) + continue; + + StringRef Rest = Buffer.drop_front(PrefixLoc); + // Make sure we have actually found the prefix, and not a word containing + // it. This should also prevent matching the wrong prefix when one is a + // substring of another. + if (PrefixLoc != 0 && IsPartOfWord(Buffer[PrefixLoc - 1])) + continue; + + FirstLoc = PrefixLoc; + FirstTy = FindCheckType(Rest, Prefix); + FirstPrefix = Prefix; + } + + // If the first prefix is invalid, we should continue the search after it. + if (FirstTy == Check::CheckNone) { + CheckLoc = SearchLoc; + return ""; + } + + CheckTy = FirstTy; + CheckLoc = FirstLoc; + return FirstPrefix; +} + +static StringRef FindFirstMatchingPrefix(StringRef &Buffer, + unsigned &LineNumber, + Check::CheckType &CheckTy, + size_t &CheckLoc) { + while (!Buffer.empty()) { + StringRef Prefix = FindFirstCandidateMatch(Buffer, CheckTy, CheckLoc); + // If we found a real match, we are done. + if (!Prefix.empty()) { + LineNumber += Buffer.substr(0, CheckLoc).count('\n'); + return Prefix; + } + + // We didn't find any almost matches either, we are also done. + if (CheckLoc == StringRef::npos) + return StringRef(); + + LineNumber += Buffer.substr(0, CheckLoc + 1).count('\n'); + + // Advance to the last possible match we found and try again. + Buffer = Buffer.drop_front(CheckLoc + 1); + } + + return StringRef(); +} /// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. @@ -696,49 +867,27 @@ static bool ReadCheckFile(SourceMgr &SM, unsigned LineNumber = 1; while (1) { - // See if Prefix occurs in the memory buffer. - size_t PrefixLoc = Buffer.find(CheckPrefix); - // If we didn't find a match, we're done. - if (PrefixLoc == StringRef::npos) + Check::CheckType CheckTy; + size_t PrefixLoc; + + // See if a prefix occurs in the memory buffer. + StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, + LineNumber, + CheckTy, + PrefixLoc); + if (UsedPrefix.empty()) break; - LineNumber += Buffer.substr(0, PrefixLoc).count('\n'); - - Buffer = Buffer.substr(PrefixLoc); - - const char *CheckPrefixStart = Buffer.data(); - - // When we find a check prefix, keep track of whether we find CHECK: or - // CHECK-NEXT: - bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false, - IsCheckLabel = false; - - // Verify that the : is present after the prefix. - if (Buffer[CheckPrefix.size()] == ':') { - Buffer = Buffer.substr(CheckPrefix.size()+1); - } else if (Buffer.size() > CheckPrefix.size()+6 && - memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+6); - IsCheckNext = true; - } else if (Buffer.size() > CheckPrefix.size()+5 && - memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+5); - IsCheckNot = true; - } else if (Buffer.size() > CheckPrefix.size()+5 && - memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+5); - IsCheckDag = true; - } else if (Buffer.size() > CheckPrefix.size()+7 && - memcmp(Buffer.data()+CheckPrefix.size(), "-LABEL:", 7) == 0) { - Buffer = Buffer.substr(CheckPrefix.size()+7); - IsCheckLabel = true; - } else { - Buffer = Buffer.substr(1); - continue; - } + Buffer = Buffer.drop_front(PrefixLoc); + + // Location to use for error messages. + const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); - // Okay, we found the prefix, yay. Remember the rest of the line, but - // ignore leading and trailing whitespace. + // PrefixLoc is to the start of the prefix. Skip to the end. + Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); + + // Okay, we found the prefix, yay. Remember the rest of the line, but ignore + // leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. @@ -748,59 +897,65 @@ static bool ReadCheckFile(SourceMgr &SM, SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. - Pattern P; - if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber)) + Pattern P(CheckTy); + if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables - if (IsCheckLabel && P.hasVariable()) { - SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), + if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { + SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '"+CheckPrefix+"-LABEL:' with variable definition" - " or use'"); + "found '" + UsedPrefix + "-LABEL:'" + " with variable definition or use"); return true; } - P.setMatchNot(IsCheckNot); - P.setMatchDag(IsCheckDag); - Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if (IsCheckNext && CheckStrings.empty()) { - SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), + if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { + SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '"+CheckPrefix+"-NEXT:' without previous '"+ - CheckPrefix+ ": line"); + "found '" + UsedPrefix + "-NEXT:' without previous '" + + UsedPrefix + ": line"); return true; } // Handle CHECK-DAG/-NOT. - if (IsCheckDag || IsCheckNot) { + if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { DagNotMatches.push_back(P); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, + UsedPrefix, PatternLoc, - IsCheckNext, - IsCheckLabel)); + CheckTy)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } - // Add an EOF pattern for any trailing CHECK-DAG/-NOTs. + // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first + // prefix as a filler for the error message. if (!DagNotMatches.empty()) { - CheckStrings.push_back(CheckString(Pattern(true), + CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), + CheckPrefixes[0], SMLoc::getFromPointer(Buffer.data()), - false, - false)); + Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } if (CheckStrings.empty()) { - errs() << "error: no check strings found with prefix '" << CheckPrefix - << ":'\n"; + errs() << "error: no check strings found with prefix" + << (CheckPrefixes.size() > 1 ? "es " : " "); + for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) { + StringRef Prefix(CheckPrefixes[I]); + errs() << '\'' << Prefix << ":'"; + if (I != N - 1) + errs() << ", "; + } + + errs() << '\n'; return true; } @@ -852,12 +1007,16 @@ static unsigned CountNumNewlinesBetween(StringRef Range) { } size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, - bool IsLabel, size_t &MatchLen, + bool IsLabelScanMode, size_t &MatchLen, StringMap<StringRef> &VariableTable) const { size_t LastPos = 0; std::vector<const Pattern *> NotStrings; - if (!IsLabel) { + // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL + // bounds; we have not processed variable definitions within the bounded block + // yet so cannot handle any final CHECK-DAG yet; this is handled when going + // over the block again (including the last CHECK-LABEL) in normal mode. + if (!IsLabelScanMode) { // Match "dag strings" (with mixed "not strings" if any). LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable); if (LastPos == StringRef::npos) @@ -873,7 +1032,9 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, } MatchPos += LastPos; - if (!IsLabel) { + // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT + // or CHECK-NOT + if (!IsLabelScanMode) { StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); // If this check is a "CHECK-NEXT", verify that the previous match was on @@ -891,7 +1052,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, } bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { - if (!IsCheckNext) + if (CheckTy != Check::CheckNext) return false; // Count the number of newlines between the previous match and this one. @@ -904,7 +1065,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { unsigned NumNewLines = CountNumNewlinesBetween(Buffer); if (NumNewLines == 0) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ + SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix + "-NEXT: is on the same line as previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, "'next' match was here"); @@ -914,7 +1075,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { } if (NumNewLines != 1) { - SM.PrintMessage(Loc, SourceMgr::DK_Error, CheckPrefix+ + SM.PrintMessage(Loc, SourceMgr::DK_Error, Prefix + "-NEXT: is not on the line after the previous match"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, "'next' match was here"); @@ -932,7 +1093,7 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, for (unsigned ChunkNo = 0, e = NotStrings.size(); ChunkNo != e; ++ChunkNo) { const Pattern *Pat = NotStrings[ChunkNo]; - assert(Pat->getMatchNot() && "Expect CHECK-NOT!"); + assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); size_t MatchLen = 0; size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); @@ -941,9 +1102,9 @@ bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos), SourceMgr::DK_Error, - CheckPrefix+"-NOT: string occurred!"); + Prefix + "-NOT: string occurred!"); SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-NOT: pattern specified here"); + Prefix + "-NOT: pattern specified here"); return true; } @@ -963,15 +1124,16 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, ChunkNo != e; ++ChunkNo) { const Pattern &Pat = DagNotStrings[ChunkNo]; - assert((Pat.getMatchDag() ^ Pat.getMatchNot()) && + assert((Pat.getCheckTy() == Check::CheckDAG || + Pat.getCheckTy() == Check::CheckNot) && "Invalid CHECK-DAG or CHECK-NOT!"); - if (Pat.getMatchNot()) { + if (Pat.getCheckTy() == Check::CheckNot) { NotStrings.push_back(&Pat); continue; } - assert(Pat.getMatchDag() && "Expect CHECK-DAG!"); + assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); size_t MatchLen = 0, MatchPos; @@ -992,17 +1154,17 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // Reordered? SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos), SourceMgr::DK_Error, - CheckPrefix+"-DAG: found a match of CHECK-DAG" + Prefix + "-DAG: found a match of CHECK-DAG" " reordering across a CHECK-NOT"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos), SourceMgr::DK_Note, - CheckPrefix+"-DAG: the farthest match of CHECK-DAG" + Prefix + "-DAG: the farthest match of CHECK-DAG" " is found here"); SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-NOT: the crossed pattern specified" + Prefix + "-NOT: the crossed pattern specified" " here"); SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note, - CheckPrefix+"-DAG: the reordered pattern specified" + Prefix + "-DAG: the reordered pattern specified" " here"); return StringRef::npos; } @@ -1026,11 +1188,50 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, return LastPos; } +// A check prefix must contain only alphanumeric, hyphens and underscores. +static bool ValidateCheckPrefix(StringRef CheckPrefix) { + Regex Validator("^[a-zA-Z0-9_-]*$"); + return Validator.match(CheckPrefix); +} + +static bool ValidateCheckPrefixes() { + StringSet<> PrefixSet; + + for (prefix_iterator I = CheckPrefixes.begin(), E = CheckPrefixes.end(); + I != E; ++I) { + StringRef Prefix(*I); + + if (!PrefixSet.insert(Prefix)) + return false; + + if (!ValidateCheckPrefix(Prefix)) + return false; + } + + return true; +} + +// I don't think there's a way to specify an initial value for cl::list, +// so if nothing was specified, add the default +static void AddCheckPrefixIfNeeded() { + if (CheckPrefixes.empty()) + CheckPrefixes.push_back("CHECK"); +} + int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); + if (!ValidateCheckPrefixes()) { + errs() << "Supplied check-prefix is invalid! Prefixes must be unique and " + "start with a letter and contain only alphanumeric characters, " + "hyphens and underscores\n"; + return 2; + } + + AddCheckPrefixIfNeeded(); + SourceMgr SM; // Read the expected strings from the check file. @@ -1076,7 +1277,7 @@ int main(int argc, char **argv) { CheckRegion = Buffer; } else { const CheckString &CheckLabelStr = CheckStrings[j]; - if (!CheckLabelStr.IsCheckLabel) { + if (CheckLabelStr.CheckTy != Check::CheckLabel) { ++j; continue; } |