diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support/FileCheck.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Support/FileCheck.cpp | 562 |
1 files changed, 269 insertions, 293 deletions
diff --git a/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp b/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp index 2261ecc236c2..e0f17787bdf8 100644 --- a/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp +++ b/contrib/llvm-project/llvm/lib/Support/FileCheck.cpp @@ -14,26 +14,35 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/FileCheck.h" -#include "FileCheckImpl.h" #include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/FormatVariadic.h" #include <cstdint> #include <list> +#include <map> #include <tuple> #include <utility> using namespace llvm; -Expected<uint64_t> NumericVariableUse::eval() const { - Optional<uint64_t> Value = Variable->getValue(); +void FileCheckNumericVariable::setValue(uint64_t NewValue) { + assert(!Value && "Overwriting numeric variable's value is not allowed"); + Value = NewValue; +} + +void FileCheckNumericVariable::clearValue() { + if (!Value) + return; + Value = None; +} + +Expected<uint64_t> FileCheckNumericVariableUse::eval() const { + Optional<uint64_t> Value = NumericVariable->getValue(); if (Value) return *Value; - - return make_error<UndefVarError>(Name); + return make_error<FileCheckUndefVarError>(Name); } -Expected<uint64_t> BinaryOperation::eval() const { +Expected<uint64_t> FileCheckASTBinop::eval() const { Expected<uint64_t> LeftOp = LeftOperand->eval(); Expected<uint64_t> RightOp = RightOperand->eval(); @@ -51,14 +60,14 @@ Expected<uint64_t> BinaryOperation::eval() const { return EvalBinop(*LeftOp, *RightOp); } -Expected<std::string> NumericSubstitution::getResult() const { - Expected<uint64_t> EvaluatedValue = ExpressionASTPointer->eval(); +Expected<std::string> FileCheckNumericSubstitution::getResult() const { + Expected<uint64_t> EvaluatedValue = ExpressionAST->eval(); if (!EvaluatedValue) return EvaluatedValue.takeError(); return utostr(*EvaluatedValue); } -Expected<std::string> StringSubstitution::getResult() const { +Expected<std::string> FileCheckStringSubstitution::getResult() const { // Look up the value and escape it so that we can put it into the regex. Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr); if (!VarVal) @@ -66,12 +75,14 @@ Expected<std::string> StringSubstitution::getResult() const { return Regex::escape(*VarVal); } -bool Pattern::isValidVarNameStart(char C) { return C == '_' || isalpha(C); } +bool FileCheckPattern::isValidVarNameStart(char C) { + return C == '_' || isalpha(C); +} -Expected<Pattern::VariableProperties> -Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { +Expected<FileCheckPattern::VariableProperties> +FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) { if (Str.empty()) - return ErrorDiagnostic::get(SM, Str, "empty variable name"); + return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name"); bool ParsedOneChar = false; unsigned I = 0; @@ -83,7 +94,7 @@ Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { for (unsigned E = Str.size(); I != E; ++I) { if (!ParsedOneChar && !isValidVarNameStart(Str[I])) - return ErrorDiagnostic::get(SM, Str, "invalid variable name"); + return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name"); // Variable names are composed of alphanumeric characters and underscores. if (Str[I] != '_' && !isalnum(Str[I])) @@ -98,7 +109,7 @@ Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) { // StringRef holding all characters considered as horizontal whitespaces by // FileCheck input canonicalization. -constexpr StringLiteral SpaceChars = " \t"; +StringRef SpaceChars = " \t"; // Parsing helper function that strips the first character in S and returns it. static char popFront(StringRef &S) { @@ -107,11 +118,12 @@ static char popFront(StringRef &S) { return C; } -char UndefVarError::ID = 0; -char ErrorDiagnostic::ID = 0; -char NotFoundError::ID = 0; +char FileCheckUndefVarError::ID = 0; +char FileCheckErrorDiagnostic::ID = 0; +char FileCheckNotFoundError::ID = 0; -Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( +Expected<FileCheckNumericVariable *> +FileCheckPattern::parseNumericVariableDefinition( StringRef &Expr, FileCheckPatternContext *Context, Optional<size_t> LineNumber, const SourceMgr &SM) { Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); @@ -120,22 +132,22 @@ Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( StringRef Name = ParseVarResult->Name; if (ParseVarResult->IsPseudo) - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, Name, "definition of pseudo numeric variable unsupported"); // Detect collisions between string and numeric variables when the latter // is created later than the former. if (Context->DefinedVariableTable.find(Name) != Context->DefinedVariableTable.end()) - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, Name, "string variable with name '" + Name + "' already exists"); Expr = Expr.ltrim(SpaceChars); if (!Expr.empty()) - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, Expr, "unexpected characters after numeric variable name"); - NumericVariable *DefinedNumericVariable; + FileCheckNumericVariable *DefinedNumericVariable; auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); if (VarTableIter != Context->GlobalNumericVariableTable.end()) DefinedNumericVariable = VarTableIter->second; @@ -145,11 +157,11 @@ Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( return DefinedNumericVariable; } -Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( - StringRef Name, bool IsPseudo, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { +Expected<std::unique_ptr<FileCheckNumericVariableUse>> +FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo, + const SourceMgr &SM) const { if (IsPseudo && !Name.equals("@LINE")) - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, Name, "invalid pseudo numeric variable '" + Name + "'"); // Numeric variable definitions and uses are parsed in the order in which @@ -161,7 +173,7 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( // uses of undefined variables, whether string or numeric, are then diagnosed // in printSubstitutions() after failing to match. auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); - NumericVariable *NumericVariable; + FileCheckNumericVariable *NumericVariable; if (VarTableIter != Context->GlobalNumericVariableTable.end()) NumericVariable = VarTableIter->second; else { @@ -171,25 +183,23 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse( Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, Name, - "numeric variable '" + Name + - "' defined earlier in the same CHECK directive"); + "numeric variable '" + Name + "' defined on the same line as used"); - return std::make_unique<NumericVariableUse>(Name, NumericVariable); + return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable); } -Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( - StringRef &Expr, AllowedOperand AO, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO, + const SourceMgr &SM) const { if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { // Try to parse as a numeric variable use. - Expected<Pattern::VariableProperties> ParseVarResult = + Expected<FileCheckPattern::VariableProperties> ParseVarResult = parseVariable(Expr, SM); if (ParseVarResult) return parseNumericVariableUse(ParseVarResult->Name, - ParseVarResult->IsPseudo, LineNumber, - Context, SM); + ParseVarResult->IsPseudo, SM); if (AO == AllowedOperand::LineVar) return ParseVarResult.takeError(); // Ignore the error and retry parsing as a literal. @@ -199,10 +209,10 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand( // Otherwise, parse it as a literal. uint64_t LiteralValue; if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue)) - return std::make_unique<ExpressionLiteral>(LiteralValue); + return llvm::make_unique<FileCheckExpressionLiteral>(LiteralValue); - return ErrorDiagnostic::get(SM, Expr, - "invalid operand format '" + Expr + "'"); + return FileCheckErrorDiagnostic::get(SM, Expr, + "invalid operand format '" + Expr + "'"); } static uint64_t add(uint64_t LeftOp, uint64_t RightOp) { @@ -213,10 +223,10 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) { return LeftOp - RightOp; } -Expected<std::unique_ptr<ExpressionAST>> -Pattern::parseBinop(StringRef &Expr, std::unique_ptr<ExpressionAST> LeftOp, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseBinop(StringRef &Expr, + std::unique_ptr<FileCheckExpressionAST> LeftOp, + bool IsLegacyLineExpr, const SourceMgr &SM) const { Expr = Expr.ltrim(SpaceChars); if (Expr.empty()) return std::move(LeftOp); @@ -234,82 +244,82 @@ Pattern::parseBinop(StringRef &Expr, std::unique_ptr<ExpressionAST> LeftOp, EvalBinop = sub; break; default: - return ErrorDiagnostic::get( + return FileCheckErrorDiagnostic::get( SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); } // Parse right operand. Expr = Expr.ltrim(SpaceChars); if (Expr.empty()) - return ErrorDiagnostic::get(SM, Expr, "missing operand in expression"); + return FileCheckErrorDiagnostic::get(SM, Expr, + "missing operand in expression"); // The second operand in a legacy @LINE expression is always a literal. AllowedOperand AO = IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any; - Expected<std::unique_ptr<ExpressionAST>> RightOpResult = - parseNumericOperand(Expr, AO, LineNumber, Context, SM); + Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult = + parseNumericOperand(Expr, AO, SM); if (!RightOpResult) return RightOpResult; Expr = Expr.ltrim(SpaceChars); - return std::make_unique<BinaryOperation>(EvalBinop, std::move(LeftOp), - std::move(*RightOpResult)); + return llvm::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp), + std::move(*RightOpResult)); } -Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericSubstitutionBlock( - StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr; - StringRef DefExpr = StringRef(); +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseNumericSubstitutionBlock( + StringRef Expr, + Optional<FileCheckNumericVariable *> &DefinedNumericVariable, + bool IsLegacyLineExpr, const SourceMgr &SM) const { + // Parse the numeric variable definition. DefinedNumericVariable = None; - // Save variable definition expression if any. size_t DefEnd = Expr.find(':'); if (DefEnd != StringRef::npos) { - DefExpr = Expr.substr(0, DefEnd); - Expr = Expr.substr(DefEnd + 1); - } + StringRef DefExpr = Expr.substr(0, DefEnd); + StringRef UseExpr = Expr.substr(DefEnd + 1); - // Parse the expression itself. - Expr = Expr.ltrim(SpaceChars); - if (!Expr.empty()) { - // The first operand in a legacy @LINE expression is always the @LINE - // pseudo variable. - AllowedOperand AO = - IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; - Expected<std::unique_ptr<ExpressionAST>> ParseResult = - parseNumericOperand(Expr, AO, LineNumber, Context, SM); - while (ParseResult && !Expr.empty()) { - ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, - LineNumber, Context, SM); - // Legacy @LINE expressions only allow 2 operands. - if (ParseResult && IsLegacyLineExpr && !Expr.empty()) - return ErrorDiagnostic::get( - SM, Expr, - "unexpected characters at end of expression '" + Expr + "'"); - } - if (!ParseResult) - return ParseResult; - ExpressionASTPointer = std::move(*ParseResult); - } + UseExpr = UseExpr.ltrim(SpaceChars); + if (!UseExpr.empty()) + return FileCheckErrorDiagnostic::get( + SM, UseExpr, + "unexpected string after variable definition: '" + UseExpr + "'"); - // Parse the numeric variable definition. - if (DefEnd != StringRef::npos) { DefExpr = DefExpr.ltrim(SpaceChars); - Expected<NumericVariable *> ParseResult = + Expected<FileCheckNumericVariable *> ParseResult = parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM); - if (!ParseResult) return ParseResult.takeError(); DefinedNumericVariable = *ParseResult; + + return nullptr; } - return std::move(ExpressionASTPointer); + // Parse the expression itself. + Expr = Expr.ltrim(SpaceChars); + // The first operand in a legacy @LINE expression is always the @LINE pseudo + // variable. + AllowedOperand AO = + IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any; + Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult = + parseNumericOperand(Expr, AO, SM); + while (ParseResult && !Expr.empty()) { + ParseResult = + parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM); + // Legacy @LINE expressions only allow 2 operands. + if (ParseResult && IsLegacyLineExpr && !Expr.empty()) + return FileCheckErrorDiagnostic::get( + SM, Expr, + "unexpected characters at end of expression '" + Expr + "'"); + } + if (!ParseResult) + return ParseResult; + return std::move(*ParseResult); } -bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, - SourceMgr &SM, const FileCheckRequest &Req) { +bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, + SourceMgr &SM, + const FileCheckRequest &Req) { bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; - IgnoreCase = Req.IgnoreCase; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); @@ -386,15 +396,14 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, continue; } - // String and numeric substitution blocks. Pattern substitution blocks come + // String and numeric substitution blocks. String substitution blocks come // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some // other regex) and assigns it to the string variable 'foo'. The latter - // substitutes foo's value. Numeric substitution blocks recognize the same - // form as string ones, but start with a '#' sign after the double - // brackets. They also accept a combined form which sets a numeric variable - // to the evaluation of an expression. Both string and numeric variable - // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be - // valid, as this helps catch some common errors. + // substitutes foo's value. Numeric substitution blocks work the same way + // as string ones, but start with a '#' sign after the double brackets. + // Both string and numeric variable names must satisfy the regular + // expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch + // some common errors. if (PatternStr.startswith("[[")) { StringRef UnparsedPatternStr = PatternStr.substr(2); // Find the closing bracket pair ending the match. End is going to be an @@ -415,7 +424,6 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, PatternStr = UnparsedPatternStr.substr(End + 2); bool IsDefinition = false; - bool SubstNeeded = false; // Whether the substitution block is a legacy use of @LINE with string // substitution block syntax. bool IsLegacyLineExpr = false; @@ -436,7 +444,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, // Get the name (e.g. "foo") and verify it is well formed. StringRef OrigMatchStr = MatchStr; - Expected<Pattern::VariableProperties> ParseVarResult = + Expected<FileCheckPattern::VariableProperties> ParseVarResult = parseVariable(MatchStr, SM); if (!ParseVarResult) { logAllUnhandledErrors(ParseVarResult.takeError(), errs()); @@ -446,7 +454,6 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, bool IsPseudo = ParseVarResult->IsPseudo; IsDefinition = (VarEndIdx != StringRef::npos); - SubstNeeded = !IsDefinition; if (IsDefinition) { if ((IsPseudo || !MatchStr.consume_front(":"))) { SM.PrintMessage(SMLoc::getFromPointer(Name.data()), @@ -476,66 +483,27 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, } // Parse numeric substitution block. - std::unique_ptr<ExpressionAST> ExpressionASTPointer; - Optional<NumericVariable *> DefinedNumericVariable; + std::unique_ptr<FileCheckExpressionAST> ExpressionAST; + Optional<FileCheckNumericVariable *> DefinedNumericVariable; if (IsNumBlock) { - Expected<std::unique_ptr<ExpressionAST>> ParseResult = + Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult = parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, - IsLegacyLineExpr, LineNumber, Context, - SM); + IsLegacyLineExpr, SM); if (!ParseResult) { logAllUnhandledErrors(ParseResult.takeError(), errs()); return true; } - ExpressionASTPointer = std::move(*ParseResult); - SubstNeeded = ExpressionASTPointer != nullptr; + ExpressionAST = std::move(*ParseResult); if (DefinedNumericVariable) { IsDefinition = true; DefName = (*DefinedNumericVariable)->getName(); - } - if (SubstNeeded) + MatchRegexp = StringRef("[0-9]+"); + } else SubstStr = MatchStr; - else - MatchRegexp = "[0-9]+"; - } - - // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]]. - if (IsDefinition) { - RegExStr += '('; - ++SubstInsertIdx; - - if (IsNumBlock) { - NumericVariableMatch NumericVariableDefinition = { - *DefinedNumericVariable, CurParen}; - NumericVariableDefs[DefName] = NumericVariableDefinition; - // This store is done here rather than in match() to allow - // parseNumericVariableUse() to get the pointer to the class instance - // of the right variable definition corresponding to a given numeric - // variable use. - Context->GlobalNumericVariableTable[DefName] = - *DefinedNumericVariable; - } else { - VariableDefs[DefName] = CurParen; - // Mark string variable as defined to detect collisions between - // string and numeric variables in parseNumericVariableUse() and - // defineCmdlineVariables() when the latter is created later than the - // former. We cannot reuse GlobalVariableTable for this by populating - // it with an empty string since we would then lose the ability to - // detect the use of an undefined variable in match(). - Context->DefinedVariableTable[DefName] = true; - } - - ++CurParen; } - if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM)) - return true; - - if (IsDefinition) - RegExStr += ')'; - // Handle substitutions: [[foo]] and [[#<foo expr>]]. - if (SubstNeeded) { + if (!IsDefinition) { // Handle substitution of string variables that were defined earlier on // the same line by emitting a backreference. Expressions do not // support substituting a numeric variable defined on the same line. @@ -551,15 +519,44 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, } else { // Handle substitution of string variables ([[<var>]]) defined in // previous CHECK patterns, and substitution of expressions. - Substitution *Substitution = + FileCheckSubstitution *Substitution = IsNumBlock ? Context->makeNumericSubstitution( - SubstStr, std::move(ExpressionASTPointer), - SubstInsertIdx) + SubstStr, std::move(ExpressionAST), SubstInsertIdx) : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); Substitutions.push_back(Substitution); } + continue; } + + // Handle variable definitions: [[<def>:(...)]] and + // [[#(...)<def>:(...)]]. + if (IsNumBlock) { + FileCheckNumericVariableMatch NumericVariableDefinition = { + *DefinedNumericVariable, CurParen}; + NumericVariableDefs[DefName] = NumericVariableDefinition; + // This store is done here rather than in match() to allow + // parseNumericVariableUse() to get the pointer to the class instance + // of the right variable definition corresponding to a given numeric + // variable use. + Context->GlobalNumericVariableTable[DefName] = *DefinedNumericVariable; + } else { + VariableDefs[DefName] = CurParen; + // Mark the string variable as defined to detect collisions between + // string and numeric variables in parseNumericVariableUse() and + // DefineCmdlineVariables() when the latter is created later than the + // former. We cannot reuse GlobalVariableTable for this by populating + // it with an empty string since we would then lose the ability to + // detect the use of an undefined variable in match(). + Context->DefinedVariableTable[DefName] = true; + } + RegExStr += '('; + ++CurParen; + + if (AddRegExToRegEx(MatchRegexp, CurParen, SM)) + return true; + + RegExStr += ')'; } // Handle fixed string matches. @@ -579,7 +576,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, return false; } -bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { +bool FileCheckPattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { Regex R(RS); std::string Error; if (!R.isValid(Error)) { @@ -593,14 +590,14 @@ bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) { return false; } -void Pattern::AddBackrefToRegEx(unsigned BackrefNum) { +void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) { assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number"); std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum); RegExStr += Backref; } -Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, - const SourceMgr &SM) const { +Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen, + const SourceMgr &SM) const { // If this is the EOF pattern, match it immediately. if (CheckTy == Check::CheckEOF) { MatchLen = 0; @@ -610,10 +607,9 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, // 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); + size_t Pos = Buffer.find(FixedStr); if (Pos == StringRef::npos) - return make_error<NotFoundError>(); + return make_error<FileCheckNotFoundError>(); return Pos; } @@ -635,8 +631,10 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, for (const auto &Substitution : Substitutions) { // Substitute and check for failure (e.g. use of undefined variable). Expected<std::string> Value = Substitution->getResult(); - if (!Value) + if (!Value) { + Context->LineVariable->clearValue(); return Value.takeError(); + } // Plop it into the regex at the adjusted offset. TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, @@ -646,14 +644,12 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, // Match the newly constructed regex. RegExToMatch = TmpStr; + Context->LineVariable->clearValue(); } SmallVector<StringRef, 4> MatchInfo; - unsigned int Flags = Regex::Newline; - if (IgnoreCase) - Flags |= Regex::IgnoreCase; - if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) - return make_error<NotFoundError>(); + if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo)) + return make_error<FileCheckNotFoundError>(); // Successful regex match. assert(!MatchInfo.empty() && "Didn't get any match"); @@ -668,18 +664,18 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, // If this defines any numeric variables, remember their values. for (const auto &NumericVariableDef : NumericVariableDefs) { - const NumericVariableMatch &NumericVariableMatch = + const FileCheckNumericVariableMatch &NumericVariableMatch = NumericVariableDef.getValue(); unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); - NumericVariable *DefinedNumericVariable = + FileCheckNumericVariable *DefinedNumericVariable = NumericVariableMatch.DefinedNumericVariable; StringRef MatchedValue = MatchInfo[CaptureParenGroup]; uint64_t Val; if (MatchedValue.getAsInteger(10, Val)) - return ErrorDiagnostic::get(SM, MatchedValue, - "Unable to represent numeric value"); + return FileCheckErrorDiagnostic::get(SM, MatchedValue, + "Unable to represent numeric value"); DefinedNumericVariable->setValue(Val); } @@ -691,7 +687,7 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen, return FullMatch.data() - Buffer.data() + MatchStartSkip; } -unsigned Pattern::computeMatchDistance(StringRef Buffer) const { +unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const { // Just compute the number of matching characters. For regular expressions, we // just compare against the regex itself and hope for the best. // @@ -708,8 +704,8 @@ unsigned Pattern::computeMatchDistance(StringRef Buffer) const { return BufferPrefix.edit_distance(ExampleString); } -void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, - SMRange MatchRange) const { +void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, + SMRange MatchRange) const { // Print what we know about substitutions. if (!Substitutions.empty()) { for (const auto &Substitution : Substitutions) { @@ -721,10 +717,11 @@ void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer, // variables it uses. if (!MatchedValue) { bool UndefSeen = false; - handleAllErrors(MatchedValue.takeError(), [](const NotFoundError &E) {}, + handleAllErrors(MatchedValue.takeError(), + [](const FileCheckNotFoundError &E) {}, // Handled in PrintNoMatch(). - [](const ErrorDiagnostic &E) {}, - [&](const UndefVarError &E) { + [](const FileCheckErrorDiagnostic &E) {}, + [&](const FileCheckUndefVarError &E) { if (!UndefSeen) { OS << "uses undefined variable(s):"; UndefSeen = true; @@ -767,8 +764,9 @@ static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, return Range; } -void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, - std::vector<FileCheckDiag> *Diags) const { +void FileCheckPattern::printFuzzyMatch( + const SourceMgr &SM, StringRef Buffer, + std::vector<FileCheckDiag> *Diags) 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 @@ -817,34 +815,36 @@ Expected<StringRef> FileCheckPatternContext::getPatternVarValue(StringRef VarName) { auto VarIter = GlobalVariableTable.find(VarName); if (VarIter == GlobalVariableTable.end()) - return make_error<UndefVarError>(VarName); + return make_error<FileCheckUndefVarError>(VarName); return VarIter->second; } template <class... Types> -NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) { - NumericVariables.push_back(std::make_unique<NumericVariable>(args...)); +FileCheckNumericVariable * +FileCheckPatternContext::makeNumericVariable(Types... args) { + NumericVariables.push_back( + llvm::make_unique<FileCheckNumericVariable>(args...)); return NumericVariables.back().get(); } -Substitution * +FileCheckSubstitution * FileCheckPatternContext::makeStringSubstitution(StringRef VarName, size_t InsertIdx) { Substitutions.push_back( - std::make_unique<StringSubstitution>(this, VarName, InsertIdx)); + llvm::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx)); return Substitutions.back().get(); } -Substitution *FileCheckPatternContext::makeNumericSubstitution( +FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution( StringRef ExpressionStr, - std::unique_ptr<ExpressionAST> ExpressionASTPointer, size_t InsertIdx) { - Substitutions.push_back(std::make_unique<NumericSubstitution>( - this, ExpressionStr, std::move(ExpressionASTPointer), InsertIdx)); + std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) { + Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>( + this, ExpressionStr, std::move(ExpressionAST), InsertIdx)); return Substitutions.back().get(); } -size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { +size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { // Offset keeps track of the current offset within the input Str size_t Offset = 0; // [...] Nesting depth @@ -1108,24 +1108,18 @@ void FileCheckPatternContext::createLineVariable() { GlobalNumericVariableTable[LineName] = LineVariable; } -FileCheck::FileCheck(FileCheckRequest Req) - : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()), - CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {} - -FileCheck::~FileCheck() = default; - -bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, - Regex &PrefixRE) { +bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, + std::vector<FileCheckString> &CheckStrings) { Error DefineError = - PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM); + PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM); if (DefineError) { logAllUnhandledErrors(std::move(DefineError), errs()); return true; } - PatternContext->createLineVariable(); + PatternContext.createLineVariable(); - std::vector<Pattern> ImplicitNegativeChecks; + std::vector<FileCheckPattern> ImplicitNegativeChecks; for (const auto &PatternString : Req.ImplicitCheckNot) { // Create a buffer with fake command line content in order to display the // command line option responsible for the specific implicit CHECK-NOT. @@ -1139,12 +1133,12 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); ImplicitNegativeChecks.push_back( - Pattern(Check::CheckNot, PatternContext.get())); + FileCheckPattern(Check::CheckNot, &PatternContext)); ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, "IMPLICIT-CHECK", SM, Req); } - std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; + std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks; // LineNumber keeps track of the line on which CheckPrefix instances are // found. @@ -1202,7 +1196,7 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. - Pattern P(CheckTy, PatternContext.get(), LineNumber); + FileCheckPattern P(CheckTy, &PatternContext, LineNumber); if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req)) return true; @@ -1220,7 +1214,7 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, // 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()) { + CheckStrings.empty()) { StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME"; @@ -1238,21 +1232,21 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, } // Okay, add the string we captured to the output vector and move on. - CheckStrings->emplace_back(P, UsedPrefix, PatternLoc); - std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); + CheckStrings.emplace_back(P, UsedPrefix, PatternLoc); + std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); DagNotMatches = ImplicitNegativeChecks; } // 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->emplace_back( - Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1), + CheckStrings.emplace_back( + FileCheckPattern(Check::CheckEOF, &PatternContext, LineNumber + 1), *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); - std::swap(DagNotMatches, CheckStrings->back().DagNotStrings); + std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } - if (CheckStrings->empty()) { + if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix" << (Req.CheckPrefixes.size() > 1 ? "es " : " "); auto I = Req.CheckPrefixes.begin(); @@ -1272,7 +1266,7 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer, } static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, - StringRef Prefix, SMLoc Loc, const Pattern &Pat, + StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat, int MatchedCount, StringRef Buffer, size_t MatchPos, size_t MatchLen, const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) { @@ -1318,10 +1312,10 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, } 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) { + StringRef Prefix, SMLoc Loc, + const FileCheckPattern &Pat, int MatchedCount, + StringRef Buffer, bool VerboseVerbose, + std::vector<FileCheckDiag> *Diags, Error MatchErrors) { assert(MatchErrors && "Called on successful match"); bool PrintDiag = true; if (!ExpectedMatch) { @@ -1347,8 +1341,9 @@ static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, return; } - MatchErrors = handleErrors(std::move(MatchErrors), - [](const ErrorDiagnostic &E) { E.log(errs()); }); + MatchErrors = + handleErrors(std::move(MatchErrors), + [](const FileCheckErrorDiagnostic &E) { E.log(errs()); }); // No problem matching the string per se. if (!MatchErrors) @@ -1412,7 +1407,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const { size_t LastPos = 0; - std::vector<const Pattern *> NotStrings; + std::vector<const FileCheckPattern *> NotStrings; // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL // bounds; we have not processed variable definitions within the bounded block @@ -1550,11 +1545,11 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { return false; } -bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, - const std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { - for (const Pattern *Pat : NotStrings) { +bool FileCheckString::CheckNot( + const SourceMgr &SM, StringRef Buffer, + const std::vector<const FileCheckPattern *> &NotStrings, + const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const { + for (const FileCheckPattern *Pat : NotStrings) { assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); size_t MatchLen = 0; @@ -1576,10 +1571,11 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, return false; } -size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, - std::vector<const Pattern *> &NotStrings, - const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { +size_t +FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, + std::vector<const FileCheckPattern *> &NotStrings, + const FileCheckRequest &Req, + std::vector<FileCheckDiag> *Diags) const { if (DagNotStrings.empty()) return 0; @@ -1599,7 +1595,7 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // 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; + const FileCheckPattern &Pat = *PatItr; assert((Pat.getCheckTy() == Check::CheckDAG || Pat.getCheckTy() == Check::CheckNot) && "Invalid CHECK-DAG or CHECK-NOT!"); @@ -1708,7 +1704,7 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // A check prefix must contain only alphanumeric, hyphens and underscores. static bool ValidateCheckPrefix(StringRef CheckPrefix) { - static const Regex Validator("^[a-zA-Z0-9_-]*$"); + Regex Validator("^[a-zA-Z0-9_-]*$"); return Validator.match(CheckPrefix); } @@ -1763,32 +1759,11 @@ Error FileCheckPatternContext::defineCmdlineVariables( unsigned I = 0; Error Errs = Error::success(); std::string CmdlineDefsDiag; - SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices; - for (StringRef CmdlineDef : CmdlineDefines) { - std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str(); - size_t EqIdx = CmdlineDef.find('='); - if (EqIdx == StringRef::npos) { - CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0)); - continue; - } - // Numeric variable definition. - if (CmdlineDef[0] == '#') { - // Append a copy of the command-line definition adapted to use the same - // format as in the input file to be able to reuse - // parseNumericSubstitutionBlock. - CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str(); - std::string SubstitutionStr = CmdlineDef; - SubstitutionStr[EqIdx] = ':'; - CmdlineDefsIndices.push_back( - std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size())); - CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str(); - } else { - CmdlineDefsDiag += DefPrefix; - CmdlineDefsIndices.push_back( - std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size())); - CmdlineDefsDiag += (CmdlineDef + "\n").str(); - } - } + StringRef Prefix1 = "Global define #"; + StringRef Prefix2 = ": "; + for (StringRef CmdlineDef : CmdlineDefines) + CmdlineDefsDiag += + (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str(); // Create a buffer with fake command line content in order to display // parsing diagnostic with location information and point to the @@ -1798,55 +1773,55 @@ Error FileCheckPatternContext::defineCmdlineVariables( StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer(); SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc()); - for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) { - StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, - CmdlineDefIndices.second); - if (CmdlineDef.empty()) { + SmallVector<StringRef, 4> CmdlineDefsDiagVec; + CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/, + false /*KeepEmpty*/); + for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) { + unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size(); + StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart); + size_t EqIdx = CmdlineDef.find('='); + if (EqIdx == StringRef::npos) { Errs = joinErrors( std::move(Errs), - ErrorDiagnostic::get(SM, CmdlineDef, - "missing equal sign in global definition")); + FileCheckErrorDiagnostic::get( + SM, CmdlineDef, "missing equal sign in global definition")); continue; } // Numeric variable definition. if (CmdlineDef[0] == '#') { - // Now parse the definition both to check that the syntax is correct and - // to create the necessary class instance. - StringRef CmdlineDefExpr = CmdlineDef.substr(1); - Optional<NumericVariable *> DefinedNumericVariable; - Expected<std::unique_ptr<ExpressionAST>> ExpressionASTResult = - Pattern::parseNumericSubstitutionBlock( - CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM); - if (!ExpressionASTResult) { - Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError()); + StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1); + Expected<FileCheckNumericVariable *> ParseResult = + FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this, + None, SM); + if (!ParseResult) { + Errs = joinErrors(std::move(Errs), ParseResult.takeError()); continue; } - std::unique_ptr<ExpressionAST> ExpressionASTPointer = - std::move(*ExpressionASTResult); - // Now evaluate the expression whose value this variable should be set - // to, since the expression of a command-line variable definition should - // only use variables defined earlier on the command-line. If not, this - // is an error and we report it. - Expected<uint64_t> Value = ExpressionASTPointer->eval(); - if (!Value) { - Errs = joinErrors(std::move(Errs), Value.takeError()); + + StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1); + uint64_t Val; + if (CmdlineVal.getAsInteger(10, Val)) { + Errs = joinErrors(std::move(Errs), + FileCheckErrorDiagnostic::get( + SM, CmdlineVal, + "invalid value in numeric variable definition '" + + CmdlineVal + "'")); continue; } - - assert(DefinedNumericVariable && "No variable defined"); - (*DefinedNumericVariable)->setValue(*Value); + FileCheckNumericVariable *DefinedNumericVariable = *ParseResult; + DefinedNumericVariable->setValue(Val); // Record this variable definition. - GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] = - *DefinedNumericVariable; + GlobalNumericVariableTable[DefinedNumericVariable->getName()] = + DefinedNumericVariable; } else { // String variable definition. std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('='); StringRef CmdlineName = CmdlineNameVal.first; StringRef OrigCmdlineName = CmdlineName; - Expected<Pattern::VariableProperties> ParseVarResult = - Pattern::parseVariable(CmdlineName, SM); + Expected<FileCheckPattern::VariableProperties> ParseVarResult = + FileCheckPattern::parseVariable(CmdlineName, SM); if (!ParseVarResult) { Errs = joinErrors(std::move(Errs), ParseVarResult.takeError()); continue; @@ -1856,7 +1831,7 @@ Error FileCheckPatternContext::defineCmdlineVariables( // "FOO+2" in a "FOO+2=10" definition. if (ParseVarResult->IsPseudo || !CmdlineName.empty()) { Errs = joinErrors(std::move(Errs), - ErrorDiagnostic::get( + FileCheckErrorDiagnostic::get( SM, OrigCmdlineName, "invalid name in string variable definition '" + OrigCmdlineName + "'")); @@ -1868,15 +1843,15 @@ Error FileCheckPatternContext::defineCmdlineVariables( // is created later than the latter. if (GlobalNumericVariableTable.find(Name) != GlobalNumericVariableTable.end()) { - Errs = joinErrors(std::move(Errs), - ErrorDiagnostic::get(SM, Name, + Errs = joinErrors(std::move(Errs), FileCheckErrorDiagnostic::get( + SM, Name, "numeric variable with name '" + Name + "' already exists")); continue; } GlobalVariableTable.insert(CmdlineNameVal); // Mark the string variable as defined to detect collisions between - // string and numeric variables in defineCmdlineVariables when the latter + // string and numeric variables in DefineCmdlineVariables when the latter // is created later than the former. We cannot reuse GlobalVariableTable // for this by populating it with an empty string since we would then // lose the ability to detect the use of an undefined variable in @@ -1912,17 +1887,18 @@ void FileCheckPatternContext::clearLocalVars() { GlobalNumericVariableTable.erase(Var); } -bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, +bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, + ArrayRef<FileCheckString> CheckStrings, std::vector<FileCheckDiag> *Diags) { bool ChecksFailed = false; - unsigned i = 0, j = 0, e = CheckStrings->size(); + unsigned i = 0, j = 0, e = CheckStrings.size(); while (true) { StringRef CheckRegion; if (j == e) { CheckRegion = Buffer; } else { - const FileCheckString &CheckLabelStr = (*CheckStrings)[j]; + const FileCheckString &CheckLabelStr = CheckStrings[j]; if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) { ++j; continue; @@ -1945,10 +1921,10 @@ bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer, // CHECK-LABEL and it would clear variables defined on the command-line // before they get used. if (i != 0 && Req.EnableVarScope) - PatternContext->clearLocalVars(); + PatternContext.clearLocalVars(); for (; i != j; ++i) { - const FileCheckString &CheckStr = (*CheckStrings)[i]; + const FileCheckString &CheckStr = CheckStrings[i]; // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) |
