From: Thomas Preud'homme Date: Wed, 24 Jul 2019 07:32:34 +0000 (+0000) Subject: Revert "FileCheck [8/12]: Define numeric var from expr" X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da0bd4db2c56fdeae07c6c75daacdc707ef2127b;p=llvm Revert "FileCheck [8/12]: Define numeric var from expr" This reverts commit 1b05977538d9487aa845ee2f3bec8b89c63c4f29. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366872 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/CommandGuide/FileCheck.rst b/docs/CommandGuide/FileCheck.rst index c5521e4e9bd..0aa2d89fbcf 100644 --- a/docs/CommandGuide/FileCheck.rst +++ b/docs/CommandGuide/FileCheck.rst @@ -107,12 +107,12 @@ and from the command line. Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be used in ``CHECK:`` lines. -.. option:: -D#= +.. option:: -D#= Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating - ```` that can be used in ``CHECK:`` lines. See section - ``FileCheck Numeric Variables and Expressions`` for details on supported - numeric expressions. + ```` that can be used in ``CHECK:`` lines. See section + ``FileCheck Numeric Variables and Expressions`` for details on the format + and meaning of ````. .. option:: -version @@ -625,27 +625,11 @@ but would not match the text: due to ``7`` being unequal to ``5 + 1``. -The syntax also supports an empty expression, equivalent to writing {{[0-9]+}}, -for cases where the input must contain a numeric value but the value itself -does not matter: - -.. code-block:: gas - - ; CHECK-NOT: mov r0, r[[#]] - -to check that a value is synthesized rather than moved around. - -A numeric variable can also be defined to the result of a numeric expression, -in which case the numeric expression is checked and if verified the variable is -assigned to the value. The unified syntax for both defining numeric variables -and checking a numeric expression is thus ``[[#: ]]`` with each -element as described previously. - The ``--enable-var-scope`` option has the same effect on numeric variables as on string variables. Important note: In its current implementation, an expression cannot use a -numeric variable with a non-empty expression defined on the same line. +numeric variable defined on the same line. FileCheck Pseudo Numeric Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/llvm/Support/FileCheck.h b/include/llvm/Support/FileCheck.h index dfe7513ac98..69345266f2e 100644 --- a/include/llvm/Support/FileCheck.h +++ b/include/llvm/Support/FileCheck.h @@ -94,11 +94,6 @@ private: /// Name of the numeric variable. StringRef Name; - /// Pointer to expression defining this numeric variable. Null for pseudo - /// variable whose value is known at parse time (e.g. @LINE pseudo variable) - /// or cleared local variable. - FileCheckExpressionAST *ExpressionAST; - /// Value of numeric variable, if defined, or None otherwise. Optional Value; @@ -109,14 +104,10 @@ private: public: /// Constructor for a variable \p Name defined at line \p DefLineNumber or - /// defined before input is parsed if \p DefLineNumber is None. If not null, - /// the value set with setValue must match the result of evaluating - /// \p ExpressionAST. + /// defined before input is parsed if DefLineNumber is None. FileCheckNumericVariable(StringRef Name, - Optional DefLineNumber = None, - FileCheckExpressionAST *ExpressionAST = nullptr) - : Name(Name), ExpressionAST(ExpressionAST), DefLineNumber(DefLineNumber) { - } + Optional DefLineNumber = None) + : Name(Name), DefLineNumber(DefLineNumber) {} /// \returns name of this numeric variable. StringRef getName() const { return Name; } @@ -124,25 +115,12 @@ public: /// \returns this variable's value. Optional getValue() const { return Value; } - /// \returns the pointer to the expression defining this numeric variable, if - /// any, or null otherwise. - FileCheckExpressionAST *getExpressionAST() const { return ExpressionAST; } - - /// \returns whether this variable's value is known when performing the - /// substitutions of the line where it is defined. - bool isValueKnownAtMatchTime() const; - - /// Sets value of this numeric variable to \p NewValue. Triggers an assertion - /// failure if the variable is defined by an expression and the expression - /// cannot be evaluated to be equal to \p NewValue. - void setValue(uint64_t NewValue); + /// Sets value of this numeric variable to \p NewValue. + void setValue(uint64_t NewValue) { Value = NewValue; } /// Clears value of this numeric variable, regardless of whether it is /// currently defined or not. - void clearValue() { - Value = None; - ExpressionAST = nullptr; - } + void clearValue() { Value = None; } /// \returns the line number where this variable is defined, if any, or None /// if defined before input is parsed. @@ -529,22 +507,27 @@ public: /// \p Str from the variable name. static Expected parseVariable(StringRef &Str, const SourceMgr &SM); - /// Parses \p Expr for a numeric substitution block at line \p LineNumber, - /// or before input is parsed if \p LineNumber is None. Parameter + /// Parses \p Expr for the name of a numeric variable to be defined at line + /// \p LineNumber or before input is parsed if \p LineNumber is None. + /// \returns a pointer to the class instance representing that variable, + /// creating it if needed, or an error holding a diagnostic against \p SM + /// should defining such a variable be invalid. + static Expected parseNumericVariableDefinition( + StringRef &Expr, FileCheckPatternContext *Context, + Optional LineNumber, const SourceMgr &SM); + /// Parses \p Expr for a numeric substitution block. Parameter /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE - /// expression and \p Context points to the class instance holding the live - /// string and numeric variables. \returns a pointer to the class instance - /// representing the AST of the expression whose value must be substitued, or - /// an error holding a diagnostic against \p SM if parsing fails. If - /// substitution was successful, sets \p DefinedNumericVariable to point to - /// the class representing the numeric variable defined in this numeric + /// expression. \returns a pointer to the class instance representing the AST + /// of the expression whose value must be substituted, or an error holding a + /// diagnostic against \p SM if parsing fails. If substitution was + /// successful, sets \p DefinedNumericVariable to point to the class + /// representing the numeric variable being defined in this numeric /// substitution block, or None if this block does not define any variable. - static Expected> + Expected> parseNumericSubstitutionBlock( StringRef Expr, Optional &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); + bool IsLegacyLineExpr, const SourceMgr &SM) const; /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern /// instance accordingly. /// @@ -598,49 +581,28 @@ private: /// was not found. size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM); - /// Parses \p Expr for the name of a numeric variable to be defined at line - /// \p LineNumber, or before input is parsed if \p LineNumber is None. - /// \returns a pointer to the class instance representing that variable, - /// creating it if needed, or an error holding a diagnostic against \p SM - /// should defining such a variable be invalid. - static Expected parseNumericVariableDefinition( - StringRef &Expr, FileCheckPatternContext *Context, - Optional LineNumber, FileCheckExpressionAST *ExpressionAST, - const SourceMgr &SM); - /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use - /// at line \p LineNumber, or before input is parsed if \p LineNumber is - /// None. Parameter \p Context points to the class instance holding the live - /// string and numeric variables. \returns the pointer to the class instance - /// representing that variable if successful, or an error holding a - /// diagnostic against \p SM otherwise. - static Expected> + /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use. + /// \returns the pointer to the class instance representing that variable if + /// successful, or an error holding a diagnostic against \p SM otherwise. + Expected> parseNumericVariableUse(StringRef Name, bool IsPseudo, - Optional LineNumber, - FileCheckPatternContext *Context, - const SourceMgr &SM); + const SourceMgr &SM) const; enum class AllowedOperand { LineVar, Literal, Any }; - /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or - /// before input is parsed if \p LineNumber is None. Accepts both literal - /// values and numeric variables, depending on the value of \p AO. Parameter - /// \p Context points to the class instance holding the live string and - /// numeric variables. \returns the class representing that operand in the - /// AST of the expression or an error holding a diagnostic against \p SM - /// otherwise. - static Expected> + /// Parses \p Expr for use of a numeric operand. Accepts both literal values + /// and numeric variables, depending on the value of \p AO. \returns the + /// class representing that operand in the AST of the expression or an error + /// holding a diagnostic against \p SM otherwise. + Expected> parseNumericOperand(StringRef &Expr, AllowedOperand AO, - Optional LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); - /// Parses \p Expr for a binary operation at line \p LineNumber, or before - /// input is parsed if \p LineNumber is None. The left operand of this binary + const SourceMgr &SM) const; + /// Parses \p Expr for a binary operation. The left operand of this binary /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether - /// we are parsing a legacy @LINE expression. Parameter \p Context points to - /// the class instance holding the live string and numeric variables. - /// \returns the class representing the binary operation in the AST of the - /// expression, or an error holding a diagnostic against \p SM otherwise. - static Expected> + /// we are parsing a legacy @LINE expression. \returns the class representing + /// the binary operation in the AST of the expression, or an error holding a + /// diagnostic against \p SM otherwise. + Expected> parseBinop(StringRef &Expr, std::unique_ptr LeftOp, - bool IsLegacyLineExpr, Optional LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM); + bool IsLegacyLineExpr, const SourceMgr &SM) const; }; //===----------------------------------------------------------------------===// diff --git a/lib/Support/FileCheck.cpp b/lib/Support/FileCheck.cpp index eab16ad6865..44e394f5b9d 100644 --- a/lib/Support/FileCheck.cpp +++ b/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 FileCheckNumericVariableUse::eval() const { Optional Value = NumericVariable->getValue(); if (Value) return *Value; - - FileCheckExpressionAST *ExpressionAST = NumericVariable->getExpressionAST(); - if (!ExpressionAST) - return make_error(Name); - - return ExpressionAST->eval(); + return make_error(Name); } Expected FileCheckASTBinop::eval() const { @@ -141,8 +114,7 @@ char FileCheckNotFoundError::ID = 0; Expected FileCheckPattern::parseNumericVariableDefinition( StringRef &Expr, FileCheckPatternContext *Context, - Optional LineNumber, FileCheckExpressionAST *ExpressionAST, - const SourceMgr &SM) { + Optional LineNumber, const SourceMgr &SM) { Expected 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> FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo, - Optional 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 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(Name, NumericVariable); } Expected> FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO, - Optional 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 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> FileCheckPattern::parseBinop( - StringRef &Expr, std::unique_ptr LeftOp, - bool IsLegacyLineExpr, Optional LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { +Expected> +FileCheckPattern::parseBinop(StringRef &Expr, + std::unique_ptr LeftOp, + bool IsLegacyLineExpr, const SourceMgr &SM) const { Expr = Expr.ltrim(SpaceChars); if (Expr.empty()) return std::move(LeftOp); @@ -282,7 +246,7 @@ Expected> FileCheckPattern::parseBinop( AllowedOperand AO = IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any; Expected> RightOpResult = - parseNumericOperand(Expr, AO, LineNumber, Context, SM); + parseNumericOperand(Expr, AO, SM); if (!RightOpResult) return RightOpResult; @@ -295,54 +259,50 @@ Expected> FileCheckPattern::parseNumericSubstitutionBlock( StringRef Expr, Optional &DefinedNumericVariable, - bool IsLegacyLineExpr, Optional LineNumber, - FileCheckPatternContext *Context, const SourceMgr &SM) { - std::unique_ptr 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> 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 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> 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> 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: [[:(...)]] and [[#(...):(...)]]. - 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 [[#]]. - 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: [[:(...)]] and + // [[#(...):(...)]]. + 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, 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 CmdlineDefIndices : CmdlineDefsIndices) { - StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first, - CmdlineDefIndices.second); - if (CmdlineDef.empty()) { + SmallVector 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 DefinedNumericVariable; - Expected> 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 ParseResult = + FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this, + None, SM); + if (!ParseResult) { + Errs = joinErrors(std::move(Errs), ParseResult.takeError()); continue; } - std::unique_ptr 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 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 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 diff --git a/test/FileCheck/numeric-defines-diagnostics.txt b/test/FileCheck/numeric-defines-diagnostics.txt index 2d320a2c7ee..bee0b402699 100644 --- a/test/FileCheck/numeric-defines-diagnostics.txt +++ b/test/FileCheck/numeric-defines-diagnostics.txt @@ -4,22 +4,30 @@ RUN: not FileCheck -D#10VALUE=10 --input-file %s %s 2>&1 \ RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIFMT -NUMERRCLIFMT: Global defines:1:46: error: invalid variable name -NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#10VALUE:10\]\]}}) -NUMERRCLIFMT-NEXT: {{^ \^$}} +NUMERRCLIFMT: Global defines:1:20: error: invalid variable name +NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 +NUMERRCLIFMT-NEXT: {{^ \^$}} ; Invalid definition of pseudo variable. RUN: not FileCheck -D#@VALUE=10 --input-file %s %s 2>&1 \ RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIPSEUDO -NUMERRCLIPSEUDO: Global defines:1:45: error: definition of pseudo numeric variable unsupported -NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10 (parsed as: {{\[\[#@VALUE:10\]\]}}) -NUMERRCLIPSEUDO-NEXT: {{^ \^$}} +NUMERRCLIPSEUDO: Global defines:1:20: error: definition of pseudo numeric variable unsupported +NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10 +NUMERRCLIPSEUDO-NEXT: {{^ \^$}} ; Invalid definition of an expression. RUN: not FileCheck -D#VALUE+2=10 --input-file %s %s 2>&1 \ RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLITRAIL -NUMERRCLITRAIL: Global defines:1:51: error: unexpected characters after numeric variable name -NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10 (parsed as: {{\[\[#VALUE\+2:10\]\]}}) -NUMERRCLITRAIL-NEXT: {{^ \^$}} +NUMERRCLITRAIL: Global defines:1:25: error: unexpected characters after numeric variable name +NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10 +NUMERRCLITRAIL-NEXT: {{^ \^$}} + +; Invalid value: numeric expression instead of literal. +RUN: not FileCheck -D#VALUE1=3 -D#VALUE2='VALUE1 + 2' --input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIEXPR + +NUMERRCLIEXPR: Global defines:2:27: error: invalid value in numeric variable definition 'VALUE1 + 2' +NUMERRCLIEXPR-NEXT: Global define #2: #VALUE2=VALUE1 + 2 +NUMERRCLIEXPR-NEXT: {{^ \^$}} diff --git a/test/FileCheck/numeric-defines.txt b/test/FileCheck/numeric-defines.txt index 2ace5bad3f2..bbdd8e8c69e 100644 --- a/test/FileCheck/numeric-defines.txt +++ b/test/FileCheck/numeric-defines.txt @@ -1,38 +1,22 @@ ; Test functionality of -D# option: numeric variables are defined to the right ; value and CHECK directives using them match as expected given the value set. -RUN: FileCheck -D#NUMVAL1=8 -D#NUMVAL2='NUMVAL1 + 4' -check-prefixes CHECKNUM1,CHECKNUM2 -input-file %s %s -RUN: not FileCheck -D#NUMVAL1=7 -D#NUMVAL2=12 -check-prefix CHECKNUM1 -input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG1 -RUN: not FileCheck -D#NUMVAL1=8 -D#NUMVAL2=8 -check-prefix CHECKNUM2 -input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace -check-prefix NUMERRMSG2 -RUN: not FileCheck -D#NUMVAL1=8 -D#NUMVAL2=8 -check-prefix NUMNOT -input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace -check-prefixes NOT-NUMERRMSG1 -RUN: not FileCheck -D#NUMVAL1=7 -D#NUMVAL2=12 -check-prefix NUMNOT -input-file %s %s 2>&1 \ -RUN: | FileCheck %s --strict-whitespace -check-prefixes NOT-NUMERRMSG2 -RUN: FileCheck -D#NUMVAL1=7 -D#NUMVAL2=8 -check-prefixes NUMNOT -input-file %s %s +RUN: FileCheck -D#NUMVAL=12 --check-prefix CHECKNUM --input-file %s %s +RUN: not FileCheck -D#NUMVAL=8 --check-prefix CHECKNUM --input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRMSG +RUN: not FileCheck -D#NUMVAL=12 --check-prefix NUMNOT --input-file %s %s 2>&1 \ +RUN: | FileCheck %s --strict-whitespace --check-prefix NOT-NUMERRMSG +RUN: FileCheck -D#NUMVAL=8 --check-prefixes NUMNOT --input-file %s %s -Numeric value #1 = 8 -Numeric value #2 = 12 -CHECKNUM1: Numeric value #1 = [[#NUMVAL1]] -CHECKNUM2: Numeric value #2 = [[#NUMVAL2]] -NUMNOT-NOT: Numeric value #1 = [[#NUMVAL1]] -NUMNOT-NOT: Numeric value #2 = [[#NUMVAL2]] +Numeric value = 12 +CHECKNUM: Numeric value = [[#NUMVAL]] +NUMNOT-NOT: Numeric value = [[#NUMVAL]] -NUMERRMSG1: defines.txt:[[#@LINE-5]]:12: error: CHECKNUM1: expected string not found in input -NUMERRMSG1: defines.txt:1:1: note: scanning from here -NUMERRMSG1: defines.txt:1:1: note: with "NUMVAL1" equal to "7" -NUMERRMSG1: defines.txt:[[#@LINE-10]]:1: note: possible intended match here +NUMERRMSG: defines.txt:[[#@LINE-3]]:11: error: CHECKNUM: expected string not found in input +NUMERRMSG: defines.txt:1:1: note: scanning from here +NUMERRMSG: defines.txt:1:1: note: with "NUMVAL" equal to "8" +NUMERRMSG: defines.txt:[[#@LINE-7]]:1: note: possible intended match here -NUMERRMSG2: defines.txt:[[#@LINE-9]]:12: error: CHECKNUM2: expected string not found in input -NUMERRMSG2: defines.txt:1:1: note: scanning from here -NUMERRMSG2: defines.txt:1:1: note: with "NUMVAL2" equal to "8" -NUMERRMSG2: defines.txt:[[#@LINE-14]]:1: note: possible intended match here - -NOT-NUMERRMSG1: defines.txt:[[#@LINE-13]]:13: error: {{NUMNOT}}-NOT: excluded string found in input -NOT-NUMERRMSG1: defines.txt:[[#@LINE-18]]:1: note: found here -NOT-NUMERRMSG1: defines.txt:[[#@LINE-19]]:1: note: with "NUMVAL1" equal to "8" - -NOT-NUMERRMSG2: defines.txt:[[#@LINE-16]]:13: error: {{NUMNOT}}-NOT: excluded string found in input -NOT-NUMERRMSG2: defines.txt:[[#@LINE-21]]:1: note: found here -NOT-NUMERRMSG2: defines.txt:[[#@LINE-22]]:1: note: with "NUMVAL2" equal to "12" +NOT-NUMERRMSG: defines.txt:[[#@LINE-7]]:13: error: {{NUMNOT}}-NOT: excluded string found in input +NOT-NUMERRMSG: defines.txt:[[#@LINE-10]]:1: note: found here +NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with "NUMVAL" equal to "12" diff --git a/test/FileCheck/numeric-expression.txt b/test/FileCheck/numeric-expression.txt index 3245adc85c3..29abc385650 100644 --- a/test/FileCheck/numeric-expression.txt +++ b/test/FileCheck/numeric-expression.txt @@ -82,20 +82,6 @@ CHECK-LABEL: USE MULTI VAR CHECK-NEXT: [[#VAR2:]] CHECK-NEXT: [[#VAR1+VAR2]] -; Numeric expression using a variable defined from a numeric expression. -DEF EXPR GOOD MATCH -42 -41 43 -; CHECK-LABEL: DEF EXPR GOOD MATCH -; CHECK-NEXT: [[# VAR42:VAR1+31]] -; CHECK-NEXT: [[# VAR41: VAR42-1]] [[# VAR41 + 2]] - -; Empty numeric expression. -EMPTY NUM EXPR -foo 104 bar -; CHECK-LABEL: EMPTY NUM EXPR -; CHECK-NEXT: foo [[#]] bar - ; Numeric expression using undefined variables. RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \ RUN: | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s @@ -159,9 +145,9 @@ CLI-STR-CONFLICT-NEXT: {{^ \^$}} INPUT-NUM-CONFLICT: numeric-expression.txt:[[#@LINE-7]]:22: error: string variable with name 'STRVAR' already exists INPUT-NUM-CONFLICT-NEXT: CONFLICT4: redef2 {{\[\[#STRVAR:\]\]}} INPUT-NUM-CONFLICT-NEXT: {{^ \^$}} -CLI-NUM-CONFLICT: Global defines:2:45: error: string variable with name 'STRVAR' already exists -CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42 (parsed as: {{\[\[#STRVAR:42\]\]}}) -CLI-NUM-CONFLICT-NEXT: {{^ \^$}} +CLI-NUM-CONFLICT: Global defines:2:20: error: string variable with name 'STRVAR' already exists +CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42 +CLI-NUM-CONFLICT-NEXT: {{^ \^$}} ; Numeric variable definition with too big value. RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \ @@ -174,18 +160,3 @@ BIGVAL-NEXT: NUMVAR: [[#NUMVAR:]] BIGVAL-MSG: numeric-expression.txt:[[#@LINE-3]]:9: error: Unable to represent numeric value BIGVAL-MSG-NEXT: {{N}}UMVAR: 10000000000000000000000 BIGVAL-MSG-NEXT: {{^ \^$}} - -; Verify that when a variable is set to an expression the expression is still -; checked. -RUN: not FileCheck --check-prefix DEF-EXPR-FAIL --input-file %s %s 2>&1 \ -RUN: | FileCheck --strict-whitespace --check-prefix DEF-EXPR-FAIL-MSG %s - -DEF EXPR WRONG MATCH -20 -43 -DEF-EXPR-FAIL-LABEL: DEF EXPR WRONG MATCH -DEF-EXPR-FAIL-NEXT: [[# VAR20:]] -DEF-EXPR-FAIL-NEXT: [[# VAR42: VAR20+22]] -DEF-EXPR-FAIL-MSG: numeric-expression.txt:[[#@LINE-1]]:21: error: {{D}}EF-EXPR-FAIL-NEXT: is not on the line after the previous match -DEF-EXPR-FAIL-MSG-NEXT: {{D}}EF-EXPR-FAIL-NEXT: {{\[\[# VAR42: VAR20\+22\]\]}} -DEF-EXPR-FAIL-MSG-NEXT: {{^ \^$}} diff --git a/unittests/Support/FileCheckTest.cpp b/unittests/Support/FileCheckTest.cpp index 147ed68e223..2b7b2707be8 100644 --- a/unittests/Support/FileCheckTest.cpp +++ b/unittests/Support/FileCheckTest.cpp @@ -49,21 +49,15 @@ expectUndefErrors(std::unordered_set ExpectedUndefVarNames, EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames); } -// Return whether Err contains any FileCheckUndefVarError whose associated name -// is not ExpectedUndefVarName. static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) { expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err)); } -uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; } - TEST_F(FileCheckTest, NumericVariable) { - // Undefined variable: isValueKnownAtMatchTime returns false, getValue and - // eval fail, error returned by eval holds the name of the undefined - // variable. + // Undefined variable: getValue and eval fail, error returned by eval holds + // the name of the undefined variable. FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1); EXPECT_EQ("FOO", FooVar.getName()); - EXPECT_FALSE(FooVar.isValueKnownAtMatchTime()); FileCheckNumericVariableUse FooVarUse = FileCheckNumericVariableUse("FOO", &FooVar); EXPECT_FALSE(FooVar.getValue()); @@ -73,9 +67,7 @@ TEST_F(FileCheckTest, NumericVariable) { FooVar.setValue(42); - // Defined variable: isValueKnownAtMatchTime returns true, getValue and eval - // return value set. - EXPECT_TRUE(FooVar.isValueKnownAtMatchTime()); + // Defined variable: getValue and eval return value set. Optional Value = FooVar.getValue(); EXPECT_TRUE(bool(Value)); EXPECT_EQ(42U, *Value); @@ -83,51 +75,24 @@ TEST_F(FileCheckTest, NumericVariable) { EXPECT_TRUE(bool(EvalResult)); EXPECT_EQ(42U, *EvalResult); - // Variable defined by numeric expression: isValueKnownAtMatchTime - // returns true, getValue and eval return value of expression, setValue - // clears expression. - std::unique_ptr FooVarUsePtr = - llvm::make_unique("FOO", &FooVar); - std::unique_ptr One = - llvm::make_unique(1); - FileCheckASTBinop Binop = - FileCheckASTBinop(doAdd, std::move(FooVarUsePtr), std::move(One)); - FileCheckNumericVariable FoobarExprVar = - FileCheckNumericVariable("FOOBAR", 2, &Binop); - EXPECT_TRUE(FoobarExprVar.isValueKnownAtMatchTime()); - EXPECT_FALSE(FoobarExprVar.getValue()); - FileCheckNumericVariableUse FoobarExprVarUse = - FileCheckNumericVariableUse("FOOBAR", &FoobarExprVar); - EvalResult = FoobarExprVarUse.eval(); - EXPECT_TRUE(bool(EvalResult)); - EXPECT_EQ(43U, *EvalResult); - EXPECT_TRUE(FoobarExprVar.getExpressionAST()); - FoobarExprVar.setValue(43); - EXPECT_FALSE(FoobarExprVar.getExpressionAST()); - FoobarExprVar = FileCheckNumericVariable("FOOBAR", 2, &Binop); - EXPECT_TRUE(FoobarExprVar.getExpressionAST()); - // Clearing variable: getValue and eval fail. Error returned by eval holds // the name of the cleared variable. FooVar.clearValue(); - FoobarExprVar.clearValue(); - EXPECT_FALSE(FoobarExprVar.getExpressionAST()); - EXPECT_FALSE(FooVar.getValue()); - EXPECT_FALSE(FoobarExprVar.getValue()); + Value = FooVar.getValue(); + EXPECT_FALSE(Value); EvalResult = FooVarUse.eval(); EXPECT_FALSE(EvalResult); expectUndefError("FOO", EvalResult.takeError()); - EvalResult = FoobarExprVarUse.eval(); - EXPECT_FALSE(EvalResult); - expectUndefError("FOOBAR", EvalResult.takeError()); } +uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; } + TEST_F(FileCheckTest, Binop) { - FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1); + FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO"); FooVar.setValue(42); std::unique_ptr FooVarUse = llvm::make_unique("FOO", &FooVar); - FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 2); + FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR"); BarVar.setValue(18); std::unique_ptr BarVarUse = llvm::make_unique("BAR", &BarVar); @@ -272,13 +237,19 @@ public: P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++); } + bool parseNumVarDefExpect(StringRef Expr) { + StringRef ExprBufferRef = bufferize(SM, Expr); + return errorToBool(FileCheckPattern::parseNumericVariableDefinition( + ExprBufferRef, &Context, LineNumber, SM) + .takeError()); + } + bool parseSubstExpect(StringRef Expr) { StringRef ExprBufferRef = bufferize(SM, Expr); Optional DefinedNumericVariable; - return errorToBool( - P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable, - false, LineNumber - 1, &Context, SM) - .takeError()); + return errorToBool(P.parseNumericSubstitutionBlock( + ExprBufferRef, DefinedNumericVariable, false, SM) + .takeError()); } bool parsePatternExpect(StringRef Pattern) { @@ -293,6 +264,19 @@ public: } }; +TEST_F(FileCheckTest, ParseNumericVariableDefinition) { + PatternTester Tester; + + // Invalid definition of pseudo. + EXPECT_TRUE(Tester.parseNumVarDefExpect("@LINE")); + + // Conflict with pattern variable. + EXPECT_TRUE(Tester.parseNumVarDefExpect("BAR")); + + // Defined variable. + EXPECT_FALSE(Tester.parseNumVarDefExpect("FOO")); +} + TEST_F(FileCheckTest, ParseExpr) { PatternTester Tester; @@ -303,18 +287,17 @@ TEST_F(FileCheckTest, ParseExpr) { EXPECT_TRUE(Tester.parseSubstExpect("@FOO:")); EXPECT_TRUE(Tester.parseSubstExpect("@LINE:")); - // Conflict with pattern variable. - EXPECT_TRUE(Tester.parseSubstExpect("BAR:")); - // Garbage after name of variable being defined. EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:")); + // Variable defined to numeric expression. + EXPECT_TRUE(Tester.parseSubstExpect("VAR1: FOO")); + // Acceptable variable definition. EXPECT_FALSE(Tester.parseSubstExpect("VAR1:")); EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:")); EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :")); EXPECT_FALSE(Tester.parseSubstExpect("VAR3: ")); - EXPECT_FALSE(Tester.parsePatternExpect("[[#FOOBAR: FOO+1]]")); // Numeric expression. @@ -327,21 +310,9 @@ TEST_F(FileCheckTest, ParseExpr) { EXPECT_FALSE(Tester.parseSubstExpect("FOO")); EXPECT_FALSE(Tester.parseSubstExpect("UNDEF")); - // Valid empty expression. - EXPECT_FALSE(Tester.parseSubstExpect("")); - - // Valid use of variable defined on the same line from expression. Note that - // the same pattern object is used for the parsePatternExpect and - // parseSubstExpect since no initNextPattern is called, thus appearing as - // being on the same line from the pattern's point of view. - EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:FOO+1]]")); - EXPECT_FALSE(Tester.parseSubstExpect("LINE1VAR")); - - // Invalid use of variable defined on same line from input. As above, the - // absence of a call to initNextPattern makes it appear to be on the same - // line from the pattern's point of view. - EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE2VAR:]]")); - EXPECT_TRUE(Tester.parseSubstExpect("LINE2VAR")); + // Use variable defined on same line. + EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]")); + EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR")); // Unsupported operator. EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2")); @@ -352,7 +323,6 @@ TEST_F(FileCheckTest, ParseExpr) { // Valid expression. EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5")); EXPECT_FALSE(Tester.parseSubstExpect("FOO+4")); - EXPECT_FALSE(Tester.parseSubstExpect("FOOBAR")); Tester.initNextPattern(); EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]")); EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]")); @@ -384,6 +354,7 @@ TEST_F(FileCheckTest, ParsePattern) { EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]")); EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]")); EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]")); + EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]")); // Valid numeric expressions and numeric variable definition. EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]")); @@ -394,16 +365,9 @@ TEST_F(FileCheckTest, ParsePattern) { TEST_F(FileCheckTest, Match) { PatternTester Tester; - // Check matching an empty expression only matches a number. - Tester.parsePatternExpect("[[#]]"); - EXPECT_TRUE(Tester.matchExpect("FAIL")); - EXPECT_FALSE(Tester.matchExpect("18")); - // Check matching a definition only matches a number. - Tester.initNextPattern(); Tester.parsePatternExpect("[[#NUMVAR:]]"); EXPECT_TRUE(Tester.matchExpect("FAIL")); - EXPECT_TRUE(Tester.matchExpect("")); EXPECT_FALSE(Tester.matchExpect("18")); // Check matching the variable defined matches the correct number only @@ -417,16 +381,16 @@ TEST_F(FileCheckTest, Match) { // the correct value for @LINE. Tester.initNextPattern(); EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]")); - // Ok, @LINE is 5 now. - EXPECT_FALSE(Tester.matchExpect("5")); + // Ok, @LINE is 4 now. + EXPECT_FALSE(Tester.matchExpect("4")); Tester.initNextPattern(); - // @LINE is now 6, match with substitution failure. + // @LINE is now 5, match with substitution failure. EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]")); EXPECT_TRUE(Tester.matchExpect("FOO")); Tester.initNextPattern(); - // Check that @LINE is 7 as expected. + // Check that @LINE is 6 as expected. EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]")); - EXPECT_FALSE(Tester.matchExpect("7")); + EXPECT_FALSE(Tester.matchExpect("6")); } TEST_F(FileCheckTest, Substitution) { @@ -446,9 +410,9 @@ TEST_F(FileCheckTest, Substitution) { // Substitutions of defined pseudo and non-pseudo numeric variables return // the right value. - FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 1); - FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 1); + FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE"); LineVar.setValue(42); + FileCheckNumericVariable NVar = FileCheckNumericVariable("N"); NVar.setValue(10); auto LineVarUse = llvm::make_unique("@LINE", &LineVar); @@ -530,29 +494,22 @@ TEST_F(FileCheckTest, FileCheckContext) { // Define local variables from command-line. GlobalDefines.clear(); - // Clear local variables to remove dummy numeric variable x that - // parseNumericSubstitutionBlock would have created and stored in - // GlobalNumericVariableTable. - Cxt.clearLocalVars(); GlobalDefines.emplace_back(std::string("LocalVar=FOO")); GlobalDefines.emplace_back(std::string("EmptyVar=")); - GlobalDefines.emplace_back(std::string("#LocalNumVar1=18")); - GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2")); + GlobalDefines.emplace_back(std::string("#LocalNumVar=18")); EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM))); // Check defined variables are present and undefined is absent. StringRef LocalVarStr = "LocalVar"; - StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1"); - StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2"); + StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar"); StringRef EmptyVarStr = "EmptyVar"; StringRef UnknownVarStr = "UnknownVar"; Expected LocalVar = Cxt.getPatternVarValue(LocalVarStr); FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1); Optional DefinedNumericVariable; Expected> ExpressionAST = - P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable, - /*IsLegacyLineExpr=*/false, - /*LineNumber=*/1, &Cxt, SM); + P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable, + /*IsLegacyLineExpr=*/false, SM); EXPECT_TRUE(bool(LocalVar)); EXPECT_EQ(*LocalVar, "FOO"); Expected EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); @@ -561,14 +518,6 @@ TEST_F(FileCheckTest, FileCheckContext) { Expected ExpressionVal = (*ExpressionAST)->eval(); EXPECT_TRUE(bool(ExpressionVal)); EXPECT_EQ(*ExpressionVal, 18U); - ExpressionAST = - P.parseNumericSubstitutionBlock(LocalNumVar2Ref, DefinedNumericVariable, - /*IsLegacyLineExpr=*/false, - /*LineNumber=*/1, &Cxt, SM); - EXPECT_TRUE(bool(ExpressionAST)); - ExpressionVal = (*ExpressionAST)->eval(); - EXPECT_TRUE(bool(ExpressionVal)); - EXPECT_EQ(*ExpressionVal, 20U); EXPECT_TRUE(bool(EmptyVar)); EXPECT_EQ(*EmptyVar, ""); EXPECT_TRUE(errorToBool(UnknownVar.takeError())); @@ -584,14 +533,7 @@ TEST_F(FileCheckTest, FileCheckContext) { EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError())); P = FileCheckPattern(Check::CheckPlain, &Cxt, 2); ExpressionAST = P.parseNumericSubstitutionBlock( - LocalNumVar1Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, - /*LineNumber=*/2, &Cxt, SM); - EXPECT_TRUE(bool(ExpressionAST)); - ExpressionVal = (*ExpressionAST)->eval(); - EXPECT_TRUE(errorToBool(ExpressionVal.takeError())); - ExpressionAST = P.parseNumericSubstitutionBlock( - LocalNumVar2Ref, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, - /*LineNumber=*/2, &Cxt, SM); + LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM); EXPECT_TRUE(bool(ExpressionAST)); ExpressionVal = (*ExpressionAST)->eval(); EXPECT_TRUE(errorToBool(ExpressionVal.takeError())); @@ -612,8 +554,7 @@ TEST_F(FileCheckTest, FileCheckContext) { EXPECT_EQ(*GlobalVar, "BAR"); P = FileCheckPattern(Check::CheckPlain, &Cxt, 3); ExpressionAST = P.parseNumericSubstitutionBlock( - GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, - /*LineNumber=*/3, &Cxt, SM); + GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM); EXPECT_TRUE(bool(ExpressionAST)); ExpressionVal = (*ExpressionAST)->eval(); EXPECT_TRUE(bool(ExpressionVal)); @@ -624,8 +565,7 @@ TEST_F(FileCheckTest, FileCheckContext) { EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError())); P = FileCheckPattern(Check::CheckPlain, &Cxt, 4); ExpressionAST = P.parseNumericSubstitutionBlock( - GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, - /*LineNumber=*/4, &Cxt, SM); + GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM); EXPECT_TRUE(bool(ExpressionAST)); ExpressionVal = (*ExpressionAST)->eval(); EXPECT_TRUE(bool(ExpressionVal));