diff options
Diffstat (limited to 'llvm/lib/Support/FileCheck.cpp')
-rw-r--r-- | llvm/lib/Support/FileCheck.cpp | 309 |
1 files changed, 118 insertions, 191 deletions
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp index eab16ad6865..44e394f5b9d 100644 --- a/llvm/lib/Support/FileCheck.cpp +++ b/llvm/lib/Support/FileCheck.cpp @@ -24,38 +24,11 @@ using namespace llvm; -bool FileCheckNumericVariable::isValueKnownAtMatchTime() const { - if (Value) - return true; - - return ExpressionAST != nullptr; -} - -void FileCheckNumericVariable::setValue(uint64_t NewValue) { - if (ExpressionAST != nullptr) { - // Caller is expected to call setValue only if substitution was successful. - assert(NewValue == cantFail(ExpressionAST->eval(), - "Failed to evaluate associated expression when " - "sanity checking value") && - "Value being set to different from variable evaluation"); - } - Value = NewValue; - // Clear pointer to AST to ensure it is not used after the numeric - // substitution defining this variable is processed since it's the - // substitution that owns the pointer. - ExpressionAST = nullptr; -} - Expected<uint64_t> FileCheckNumericVariableUse::eval() const { Optional<uint64_t> Value = NumericVariable->getValue(); if (Value) return *Value; - - FileCheckExpressionAST *ExpressionAST = NumericVariable->getExpressionAST(); - if (!ExpressionAST) - return make_error<FileCheckUndefVarError>(Name); - - return ExpressionAST->eval(); + return make_error<FileCheckUndefVarError>(Name); } Expected<uint64_t> FileCheckASTBinop::eval() const { @@ -141,8 +114,7 @@ char FileCheckNotFoundError::ID = 0; Expected<FileCheckNumericVariable *> FileCheckPattern::parseNumericVariableDefinition( StringRef &Expr, FileCheckPatternContext *Context, - Optional<size_t> LineNumber, FileCheckExpressionAST *ExpressionAST, - const SourceMgr &SM) { + Optional<size_t> LineNumber, const SourceMgr &SM) { Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); if (!ParseVarResult) return ParseVarResult.takeError(); @@ -169,17 +141,14 @@ FileCheckPattern::parseNumericVariableDefinition( if (VarTableIter != Context->GlobalNumericVariableTable.end()) DefinedNumericVariable = VarTableIter->second; else - DefinedNumericVariable = - Context->makeNumericVariable(Name, LineNumber, ExpressionAST); + DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber); return DefinedNumericVariable; } Expected<std::unique_ptr<FileCheckNumericVariableUse>> FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo, - Optional<size_t> LineNumber, - FileCheckPatternContext *Context, - const SourceMgr &SM) { + const SourceMgr &SM) const { if (IsPseudo && !Name.equals("@LINE")) return FileCheckErrorDiagnostic::get( SM, Name, "invalid pseudo numeric variable '" + Name + "'"); @@ -202,29 +171,24 @@ FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo, } Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); - if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber && - !NumericVariable->isValueKnownAtMatchTime()) + if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) return FileCheckErrorDiagnostic::get( SM, Name, - "numeric variable '" + Name + - "' defined from input on the same line as used"); + "numeric variable '" + Name + "' defined on the same line as used"); return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable); } Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO, - Optional<size_t> LineNumber, - FileCheckPatternContext *Context, - const SourceMgr &SM) { + const SourceMgr &SM) const { if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { // Try to parse as a numeric variable use. 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. @@ -248,10 +212,10 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) { return LeftOp - RightOp; } -Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop( - StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> 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); @@ -282,7 +246,7 @@ Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop( AllowedOperand AO = IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any; Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult = - parseNumericOperand(Expr, AO, LineNumber, Context, SM); + parseNumericOperand(Expr, AO, SM); if (!RightOpResult) return RightOpResult; @@ -295,54 +259,50 @@ Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseNumericSubstitutionBlock( StringRef Expr, Optional<FileCheckNumericVariable *> &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional<size_t> LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr; - StringRef DefExpr = StringRef(); + 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<FileCheckExpressionAST>> 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 FileCheckErrorDiagnostic::get( - SM, Expr, - "unexpected characters at end of expression '" + Expr + "'"); - } - if (!ParseResult) - return ParseResult; - ExpressionAST = 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<FileCheckNumericVariable *> ParseResult = - parseNumericVariableDefinition(DefExpr, Context, LineNumber, - ExpressionAST.get(), SM); - + parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM); if (!ParseResult) return ParseResult.takeError(); DefinedNumericVariable = *ParseResult; + + return nullptr; } - return ExpressionAST; + // 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 FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, @@ -425,15 +385,14 @@ bool FileCheckPattern::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 @@ -454,7 +413,6 @@ bool FileCheckPattern::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; @@ -485,7 +443,6 @@ bool FileCheckPattern::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()), @@ -520,61 +477,22 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, if (IsNumBlock) { Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult = parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, - IsLegacyLineExpr, LineNumber, Context, - SM); + IsLegacyLineExpr, SM); if (!ParseResult) { logAllUnhandledErrors(ParseResult.takeError(), errs()); return true; } ExpressionAST = std::move(*ParseResult); - SubstNeeded = ExpressionAST != nullptr; 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) { - 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 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. @@ -597,7 +515,37 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, : 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. @@ -1797,32 +1745,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 @@ -1832,10 +1759,14 @@ 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), FileCheckErrorDiagnostic::get( @@ -1845,35 +1776,31 @@ Error FileCheckPatternContext::defineCmdlineVariables( // 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<FileCheckNumericVariable *> DefinedNumericVariable; - Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult = - FileCheckPattern::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<FileCheckExpressionAST> ExpressionAST = - 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 = ExpressionAST->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('='); @@ -1910,7 +1837,7 @@ Error FileCheckPatternContext::defineCmdlineVariables( } 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 |