mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-30 07:00:57 +00:00
FileCheck [8/12]: Define numeric var from expr
Summary: This patch is part of a patch series to add support for FileCheck numeric expressions. This specific patch lift the restriction for a numeric expression to either be a variable definition or a numeric expression to try to match. This commit allows a numeric variable to be set to the result of the evaluation of a numeric expression after it has been matched successfully. When it happens, the variable is allowed to be used on the same line since its value is known at match time. It also makes use of this possibility to reuse the parsing code to parse a command-line definition by crafting a mirror string of the -D option with the equal sign replaced by a colon sign, e.g. for option '-D#NUMVAL=10' it creates the string '-D#NUMVAL=10 (parsed as [[#NUMVAL:10]])' where the numeric expression is parsed to define NUMVAL. This result in a few tests needing updating for the location diagnostics on top of the tests for the new feature. It also enables empty numeric expression which match any number without defining a variable. This is done here rather than in commit #5 of the patch series because it requires to dissociate automatic regex insertion in RegExStr from variable definition which would make commit #5 even bigger than it already is. Copyright: - Linaro (changes up to diff 183612 of revision D55940) - GraphCore (changes in later versions of revision D55940 and in new revision created off D55940) Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield Tags: #llvm Differential Revision: https://reviews.llvm.org/D60388 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366860 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f79e8f94d2
commit
247241e07e
@ -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#<NUMVAR>=<VALUE EXPRESSION>
|
||||
.. option:: -D#<NUMVAR>=<NUMERIC EXPRESSION>
|
||||
|
||||
Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
|
||||
``<VALUE EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
|
||||
``FileCheck Numeric Variables and Expressions`` for details on the format
|
||||
and meaning of ``<VALUE EXPRESSION>``.
|
||||
``<NUMERIC EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
|
||||
``FileCheck Numeric Variables and Expressions`` for details on supported
|
||||
numeric expressions.
|
||||
|
||||
.. option:: -version
|
||||
|
||||
@ -625,11 +625,27 @@ 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 ``[[#<NUMVAR>: <expr>]]`` 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 defined on the same line.
|
||||
numeric variable with a non-empty expression defined on the same line.
|
||||
|
||||
FileCheck Pseudo Numeric Variables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -94,6 +94,11 @@ 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<uint64_t> Value;
|
||||
|
||||
@ -104,10 +109,14 @@ private:
|
||||
|
||||
public:
|
||||
/// Constructor for a variable \p Name defined at line \p DefLineNumber or
|
||||
/// defined before input is parsed if DefLineNumber is None.
|
||||
/// 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.
|
||||
FileCheckNumericVariable(StringRef Name,
|
||||
Optional<size_t> DefLineNumber = None)
|
||||
: Name(Name), DefLineNumber(DefLineNumber) {}
|
||||
Optional<size_t> DefLineNumber = None,
|
||||
FileCheckExpressionAST *ExpressionAST = nullptr)
|
||||
: Name(Name), ExpressionAST(ExpressionAST), DefLineNumber(DefLineNumber) {
|
||||
}
|
||||
|
||||
/// \returns name of this numeric variable.
|
||||
StringRef getName() const { return Name; }
|
||||
@ -115,12 +124,25 @@ public:
|
||||
/// \returns this variable's value.
|
||||
Optional<uint64_t> getValue() const { return Value; }
|
||||
|
||||
/// Sets value of this numeric variable to \p NewValue.
|
||||
void setValue(uint64_t NewValue) { Value = NewValue; }
|
||||
/// \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);
|
||||
|
||||
/// Clears value of this numeric variable, regardless of whether it is
|
||||
/// currently defined or not.
|
||||
void clearValue() { Value = None; }
|
||||
void clearValue() {
|
||||
Value = None;
|
||||
ExpressionAST = nullptr;
|
||||
}
|
||||
|
||||
/// \returns the line number where this variable is defined, if any, or None
|
||||
/// if defined before input is parsed.
|
||||
@ -507,27 +529,22 @@ public:
|
||||
/// \p Str from the variable name.
|
||||
static Expected<VariableProperties> parseVariable(StringRef &Str,
|
||||
const 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<FileCheckNumericVariable *> parseNumericVariableDefinition(
|
||||
StringRef &Expr, FileCheckPatternContext *Context,
|
||||
Optional<size_t> LineNumber, const SourceMgr &SM);
|
||||
/// Parses \p Expr for a numeric substitution block. Parameter
|
||||
/// Parses \p Expr for a numeric substitution block at line \p LineNumber,
|
||||
/// or before input is parsed if \p LineNumber is None. Parameter
|
||||
/// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
|
||||
/// 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
|
||||
/// 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
|
||||
/// substitution block, or None if this block does not define any variable.
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>>
|
||||
static Expected<std::unique_ptr<FileCheckExpressionAST>>
|
||||
parseNumericSubstitutionBlock(
|
||||
StringRef Expr,
|
||||
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
|
||||
bool IsLegacyLineExpr, const SourceMgr &SM) const;
|
||||
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context, const SourceMgr &SM);
|
||||
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
|
||||
/// instance accordingly.
|
||||
///
|
||||
@ -581,28 +598,49 @@ private:
|
||||
/// was not found.
|
||||
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
|
||||
|
||||
/// 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<std::unique_ptr<FileCheckNumericVariableUse>>
|
||||
parseNumericVariableUse(StringRef Name, bool IsPseudo,
|
||||
const SourceMgr &SM) const;
|
||||
enum class AllowedOperand { LineVar, Literal, Any };
|
||||
/// 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<std::unique_ptr<FileCheckExpressionAST>>
|
||||
parseNumericOperand(StringRef &Expr, AllowedOperand AO,
|
||||
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. \returns the class representing
|
||||
/// the binary operation in the AST of the expression, or an error holding a
|
||||
/// 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<FileCheckNumericVariable *> parseNumericVariableDefinition(
|
||||
StringRef &Expr, FileCheckPatternContext *Context,
|
||||
Optional<size_t> 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.
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>>
|
||||
static Expected<std::unique_ptr<FileCheckNumericVariableUse>>
|
||||
parseNumericVariableUse(StringRef Name, bool IsPseudo,
|
||||
Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context,
|
||||
const SourceMgr &SM);
|
||||
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<std::unique_ptr<FileCheckExpressionAST>>
|
||||
parseNumericOperand(StringRef &Expr, AllowedOperand AO,
|
||||
Optional<size_t> 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
|
||||
/// 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<std::unique_ptr<FileCheckExpressionAST>>
|
||||
parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
|
||||
bool IsLegacyLineExpr, const SourceMgr &SM) const;
|
||||
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context, const SourceMgr &SM);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -24,11 +24,38 @@
|
||||
|
||||
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;
|
||||
return make_error<FileCheckUndefVarError>(Name);
|
||||
|
||||
FileCheckExpressionAST *ExpressionAST = NumericVariable->getExpressionAST();
|
||||
if (!ExpressionAST)
|
||||
return make_error<FileCheckUndefVarError>(Name);
|
||||
|
||||
return ExpressionAST->eval();
|
||||
}
|
||||
|
||||
Expected<uint64_t> FileCheckASTBinop::eval() const {
|
||||
@ -114,7 +141,8 @@ char FileCheckNotFoundError::ID = 0;
|
||||
Expected<FileCheckNumericVariable *>
|
||||
FileCheckPattern::parseNumericVariableDefinition(
|
||||
StringRef &Expr, FileCheckPatternContext *Context,
|
||||
Optional<size_t> LineNumber, const SourceMgr &SM) {
|
||||
Optional<size_t> LineNumber, FileCheckExpressionAST *ExpressionAST,
|
||||
const SourceMgr &SM) {
|
||||
Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
|
||||
if (!ParseVarResult)
|
||||
return ParseVarResult.takeError();
|
||||
@ -141,14 +169,17 @@ FileCheckPattern::parseNumericVariableDefinition(
|
||||
if (VarTableIter != Context->GlobalNumericVariableTable.end())
|
||||
DefinedNumericVariable = VarTableIter->second;
|
||||
else
|
||||
DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);
|
||||
DefinedNumericVariable =
|
||||
Context->makeNumericVariable(Name, LineNumber, ExpressionAST);
|
||||
|
||||
return DefinedNumericVariable;
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<FileCheckNumericVariableUse>>
|
||||
FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
|
||||
const SourceMgr &SM) const {
|
||||
Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context,
|
||||
const SourceMgr &SM) {
|
||||
if (IsPseudo && !Name.equals("@LINE"))
|
||||
return FileCheckErrorDiagnostic::get(
|
||||
SM, Name, "invalid pseudo numeric variable '" + Name + "'");
|
||||
@ -171,24 +202,29 @@ FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
|
||||
}
|
||||
|
||||
Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();
|
||||
if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
|
||||
if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber &&
|
||||
!NumericVariable->isValueKnownAtMatchTime())
|
||||
return FileCheckErrorDiagnostic::get(
|
||||
SM, Name,
|
||||
"numeric variable '" + Name + "' defined on the same line as used");
|
||||
"numeric variable '" + Name +
|
||||
"' defined from input on the same line as used");
|
||||
|
||||
return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>>
|
||||
FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
|
||||
const SourceMgr &SM) const {
|
||||
Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context,
|
||||
const SourceMgr &SM) {
|
||||
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, SM);
|
||||
ParseVarResult->IsPseudo, LineNumber,
|
||||
Context, SM);
|
||||
if (AO == AllowedOperand::LineVar)
|
||||
return ParseVarResult.takeError();
|
||||
// Ignore the error and retry parsing as a literal.
|
||||
@ -212,10 +248,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, const SourceMgr &SM) const {
|
||||
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) {
|
||||
Expr = Expr.ltrim(SpaceChars);
|
||||
if (Expr.empty())
|
||||
return std::move(LeftOp);
|
||||
@ -246,7 +282,7 @@ FileCheckPattern::parseBinop(StringRef &Expr,
|
||||
AllowedOperand AO =
|
||||
IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
|
||||
parseNumericOperand(Expr, AO, SM);
|
||||
parseNumericOperand(Expr, AO, LineNumber, Context, SM);
|
||||
if (!RightOpResult)
|
||||
return RightOpResult;
|
||||
|
||||
@ -259,50 +295,54 @@ Expected<std::unique_ptr<FileCheckExpressionAST>>
|
||||
FileCheckPattern::parseNumericSubstitutionBlock(
|
||||
StringRef Expr,
|
||||
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
|
||||
bool IsLegacyLineExpr, const SourceMgr &SM) const {
|
||||
// Parse the numeric variable definition.
|
||||
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
|
||||
FileCheckPatternContext *Context, const SourceMgr &SM) {
|
||||
std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;
|
||||
StringRef DefExpr = StringRef();
|
||||
DefinedNumericVariable = None;
|
||||
// Save variable definition expression if any.
|
||||
size_t DefEnd = Expr.find(':');
|
||||
if (DefEnd != StringRef::npos) {
|
||||
StringRef DefExpr = Expr.substr(0, DefEnd);
|
||||
StringRef UseExpr = Expr.substr(DefEnd + 1);
|
||||
|
||||
UseExpr = UseExpr.ltrim(SpaceChars);
|
||||
if (!UseExpr.empty())
|
||||
return FileCheckErrorDiagnostic::get(
|
||||
SM, UseExpr,
|
||||
"unexpected string after variable definition: '" + UseExpr + "'");
|
||||
|
||||
DefExpr = DefExpr.ltrim(SpaceChars);
|
||||
Expected<FileCheckNumericVariable *> ParseResult =
|
||||
parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
|
||||
if (!ParseResult)
|
||||
return ParseResult.takeError();
|
||||
DefinedNumericVariable = *ParseResult;
|
||||
|
||||
return nullptr;
|
||||
DefExpr = Expr.substr(0, DefEnd);
|
||||
Expr = Expr.substr(DefEnd + 1);
|
||||
}
|
||||
|
||||
// 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 (!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);
|
||||
}
|
||||
if (!ParseResult)
|
||||
return ParseResult;
|
||||
return std::move(*ParseResult);
|
||||
|
||||
// Parse the numeric variable definition.
|
||||
if (DefEnd != StringRef::npos) {
|
||||
DefExpr = DefExpr.ltrim(SpaceChars);
|
||||
Expected<FileCheckNumericVariable *> ParseResult =
|
||||
parseNumericVariableDefinition(DefExpr, Context, LineNumber,
|
||||
ExpressionAST.get(), SM);
|
||||
|
||||
if (!ParseResult)
|
||||
return ParseResult.takeError();
|
||||
DefinedNumericVariable = *ParseResult;
|
||||
}
|
||||
|
||||
return ExpressionAST;
|
||||
}
|
||||
|
||||
bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
|
||||
@ -385,14 +425,15 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
|
||||
continue;
|
||||
}
|
||||
|
||||
// String and numeric substitution blocks. String substitution blocks come
|
||||
// String and numeric substitution blocks. Pattern 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 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.
|
||||
// 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.
|
||||
if (PatternStr.startswith("[[")) {
|
||||
StringRef UnparsedPatternStr = PatternStr.substr(2);
|
||||
// Find the closing bracket pair ending the match. End is going to be an
|
||||
@ -413,6 +454,7 @@ 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;
|
||||
@ -443,6 +485,7 @@ 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()),
|
||||
@ -477,22 +520,61 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
|
||||
if (IsNumBlock) {
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
|
||||
parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
|
||||
IsLegacyLineExpr, SM);
|
||||
IsLegacyLineExpr, LineNumber, Context,
|
||||
SM);
|
||||
if (!ParseResult) {
|
||||
logAllUnhandledErrors(ParseResult.takeError(), errs());
|
||||
return true;
|
||||
}
|
||||
ExpressionAST = std::move(*ParseResult);
|
||||
SubstNeeded = ExpressionAST != nullptr;
|
||||
if (DefinedNumericVariable) {
|
||||
IsDefinition = true;
|
||||
DefName = (*DefinedNumericVariable)->getName();
|
||||
MatchRegexp = StringRef("[0-9]+");
|
||||
} else
|
||||
}
|
||||
if (SubstNeeded)
|
||||
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 (!IsDefinition) {
|
||||
if (SubstNeeded) {
|
||||
// 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.
|
||||
@ -515,37 +597,7 @@ 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.
|
||||
@ -1745,11 +1797,32 @@ Error FileCheckPatternContext::defineCmdlineVariables(
|
||||
unsigned I = 0;
|
||||
Error Errs = Error::success();
|
||||
std::string CmdlineDefsDiag;
|
||||
StringRef Prefix1 = "Global define #";
|
||||
StringRef Prefix2 = ": ";
|
||||
for (StringRef CmdlineDef : CmdlineDefines)
|
||||
CmdlineDefsDiag +=
|
||||
(Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a buffer with fake command line content in order to display
|
||||
// parsing diagnostic with location information and point to the
|
||||
@ -1759,14 +1832,10 @@ Error FileCheckPatternContext::defineCmdlineVariables(
|
||||
StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
|
||||
SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
|
||||
|
||||
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) {
|
||||
for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
|
||||
StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
|
||||
CmdlineDefIndices.second);
|
||||
if (CmdlineDef.empty()) {
|
||||
Errs = joinErrors(
|
||||
std::move(Errs),
|
||||
FileCheckErrorDiagnostic::get(
|
||||
@ -1776,31 +1845,35 @@ Error FileCheckPatternContext::defineCmdlineVariables(
|
||||
|
||||
// Numeric variable definition.
|
||||
if (CmdlineDef[0] == '#') {
|
||||
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());
|
||||
// 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());
|
||||
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());
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;
|
||||
DefinedNumericVariable->setValue(Val);
|
||||
assert(DefinedNumericVariable && "No variable defined");
|
||||
(*DefinedNumericVariable)->setValue(*Value);
|
||||
|
||||
// Record this variable definition.
|
||||
GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
|
||||
DefinedNumericVariable;
|
||||
GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
|
||||
*DefinedNumericVariable;
|
||||
} else {
|
||||
// String variable definition.
|
||||
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
|
||||
@ -1837,7 +1910,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
|
||||
|
@ -4,30 +4,22 @@
|
||||
RUN: not FileCheck -D#10VALUE=10 --input-file %s %s 2>&1 \
|
||||
RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIFMT
|
||||
|
||||
NUMERRCLIFMT: Global defines:1:20: error: invalid variable name
|
||||
NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10
|
||||
NUMERRCLIFMT-NEXT: {{^ \^$}}
|
||||
NUMERRCLIFMT: Global defines:1:46: error: invalid variable name
|
||||
NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10 (parsed as: {{\[\[#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:20: error: definition of pseudo numeric variable unsupported
|
||||
NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10
|
||||
NUMERRCLIPSEUDO-NEXT: {{^ \^$}}
|
||||
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: {{^ \^$}}
|
||||
|
||||
; 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: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: {{^ \^$}}
|
||||
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: {{^ \^$}}
|
||||
|
@ -1,22 +1,38 @@
|
||||
; 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#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
|
||||
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
|
||||
|
||||
Numeric value = 12
|
||||
CHECKNUM: Numeric value = [[#NUMVAL]]
|
||||
NUMNOT-NOT: Numeric value = [[#NUMVAL]]
|
||||
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]]
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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"
|
||||
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"
|
||||
|
@ -82,6 +82,20 @@ 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
|
||||
@ -145,9 +159,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:20: error: string variable with name 'STRVAR' already exists
|
||||
CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42
|
||||
CLI-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: {{^ \^$}}
|
||||
|
||||
; Numeric variable definition with too big value.
|
||||
RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \
|
||||
@ -160,3 +174,18 @@ 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: {{^ \^$}}
|
||||
|
@ -49,15 +49,21 @@ expectUndefErrors(std::unordered_set<std::string> 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: getValue and eval fail, error returned by eval holds
|
||||
// the name of the undefined variable.
|
||||
// Undefined variable: isValueKnownAtMatchTime returns false, 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());
|
||||
@ -67,7 +73,9 @@ TEST_F(FileCheckTest, NumericVariable) {
|
||||
|
||||
FooVar.setValue(42);
|
||||
|
||||
// Defined variable: getValue and eval return value set.
|
||||
// Defined variable: isValueKnownAtMatchTime returns true, getValue and eval
|
||||
// return value set.
|
||||
EXPECT_TRUE(FooVar.isValueKnownAtMatchTime());
|
||||
Optional<uint64_t> Value = FooVar.getValue();
|
||||
EXPECT_TRUE(bool(Value));
|
||||
EXPECT_EQ(42U, *Value);
|
||||
@ -75,24 +83,51 @@ 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<FileCheckNumericVariableUse> FooVarUsePtr =
|
||||
llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
|
||||
std::unique_ptr<FileCheckExpressionLiteral> One =
|
||||
llvm::make_unique<FileCheckExpressionLiteral>(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();
|
||||
Value = FooVar.getValue();
|
||||
EXPECT_FALSE(Value);
|
||||
FoobarExprVar.clearValue();
|
||||
EXPECT_FALSE(FoobarExprVar.getExpressionAST());
|
||||
EXPECT_FALSE(FooVar.getValue());
|
||||
EXPECT_FALSE(FoobarExprVar.getValue());
|
||||
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");
|
||||
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 1);
|
||||
FooVar.setValue(42);
|
||||
std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =
|
||||
llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
|
||||
FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR");
|
||||
FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 2);
|
||||
BarVar.setValue(18);
|
||||
std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =
|
||||
llvm::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);
|
||||
@ -237,19 +272,13 @@ 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<FileCheckNumericVariable *> DefinedNumericVariable;
|
||||
return errorToBool(P.parseNumericSubstitutionBlock(
|
||||
ExprBufferRef, DefinedNumericVariable, false, SM)
|
||||
.takeError());
|
||||
return errorToBool(
|
||||
P.parseNumericSubstitutionBlock(ExprBufferRef, DefinedNumericVariable,
|
||||
false, LineNumber - 1, &Context, SM)
|
||||
.takeError());
|
||||
}
|
||||
|
||||
bool parsePatternExpect(StringRef Pattern) {
|
||||
@ -264,19 +293,6 @@ 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;
|
||||
|
||||
@ -287,17 +303,18 @@ 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.
|
||||
|
||||
@ -310,9 +327,21 @@ TEST_F(FileCheckTest, ParseExpr) {
|
||||
EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
|
||||
EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
|
||||
|
||||
// Use variable defined on same line.
|
||||
EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));
|
||||
EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));
|
||||
// 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"));
|
||||
|
||||
// Unsupported operator.
|
||||
EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
|
||||
@ -323,6 +352,7 @@ 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]]"));
|
||||
@ -354,7 +384,6 @@ 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]]"));
|
||||
@ -365,9 +394,16 @@ 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
|
||||
@ -381,16 +417,16 @@ TEST_F(FileCheckTest, Match) {
|
||||
// the correct value for @LINE.
|
||||
Tester.initNextPattern();
|
||||
EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
|
||||
// Ok, @LINE is 4 now.
|
||||
EXPECT_FALSE(Tester.matchExpect("4"));
|
||||
// Ok, @LINE is 5 now.
|
||||
EXPECT_FALSE(Tester.matchExpect("5"));
|
||||
Tester.initNextPattern();
|
||||
// @LINE is now 5, match with substitution failure.
|
||||
// @LINE is now 6, match with substitution failure.
|
||||
EXPECT_FALSE(Tester.parsePatternExpect("[[#UNKNOWN]]"));
|
||||
EXPECT_TRUE(Tester.matchExpect("FOO"));
|
||||
Tester.initNextPattern();
|
||||
// Check that @LINE is 6 as expected.
|
||||
// Check that @LINE is 7 as expected.
|
||||
EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE]]"));
|
||||
EXPECT_FALSE(Tester.matchExpect("6"));
|
||||
EXPECT_FALSE(Tester.matchExpect("7"));
|
||||
}
|
||||
|
||||
TEST_F(FileCheckTest, Substitution) {
|
||||
@ -410,9 +446,9 @@ TEST_F(FileCheckTest, Substitution) {
|
||||
|
||||
// Substitutions of defined pseudo and non-pseudo numeric variables return
|
||||
// the right value.
|
||||
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE");
|
||||
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 1);
|
||||
FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 1);
|
||||
LineVar.setValue(42);
|
||||
FileCheckNumericVariable NVar = FileCheckNumericVariable("N");
|
||||
NVar.setValue(10);
|
||||
auto LineVarUse =
|
||||
llvm::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);
|
||||
@ -494,22 +530,29 @@ 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("#LocalNumVar=18"));
|
||||
GlobalDefines.emplace_back(std::string("#LocalNumVar1=18"));
|
||||
GlobalDefines.emplace_back(std::string("#LocalNumVar2=LocalNumVar1+2"));
|
||||
EXPECT_FALSE(errorToBool(Cxt.defineCmdlineVariables(GlobalDefines, SM)));
|
||||
|
||||
// Check defined variables are present and undefined is absent.
|
||||
StringRef LocalVarStr = "LocalVar";
|
||||
StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
|
||||
StringRef LocalNumVar1Ref = bufferize(SM, "LocalNumVar1");
|
||||
StringRef LocalNumVar2Ref = bufferize(SM, "LocalNumVar2");
|
||||
StringRef EmptyVarStr = "EmptyVar";
|
||||
StringRef UnknownVarStr = "UnknownVar";
|
||||
Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
|
||||
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
|
||||
Optional<FileCheckNumericVariable *> DefinedNumericVariable;
|
||||
Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =
|
||||
P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable,
|
||||
/*IsLegacyLineExpr=*/false, SM);
|
||||
P.parseNumericSubstitutionBlock(LocalNumVar1Ref, DefinedNumericVariable,
|
||||
/*IsLegacyLineExpr=*/false,
|
||||
/*LineNumber=*/1, &Cxt, SM);
|
||||
EXPECT_TRUE(bool(LocalVar));
|
||||
EXPECT_EQ(*LocalVar, "FOO");
|
||||
Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
|
||||
@ -518,6 +561,14 @@ TEST_F(FileCheckTest, FileCheckContext) {
|
||||
Expected<uint64_t> 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()));
|
||||
@ -533,7 +584,14 @@ TEST_F(FileCheckTest, FileCheckContext) {
|
||||
EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
|
||||
P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
|
||||
ExpressionAST = P.parseNumericSubstitutionBlock(
|
||||
LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
|
||||
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);
|
||||
EXPECT_TRUE(bool(ExpressionAST));
|
||||
ExpressionVal = (*ExpressionAST)->eval();
|
||||
EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
|
||||
@ -554,7 +612,8 @@ TEST_F(FileCheckTest, FileCheckContext) {
|
||||
EXPECT_EQ(*GlobalVar, "BAR");
|
||||
P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
|
||||
ExpressionAST = P.parseNumericSubstitutionBlock(
|
||||
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
|
||||
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
||||
/*LineNumber=*/3, &Cxt, SM);
|
||||
EXPECT_TRUE(bool(ExpressionAST));
|
||||
ExpressionVal = (*ExpressionAST)->eval();
|
||||
EXPECT_TRUE(bool(ExpressionVal));
|
||||
@ -565,7 +624,8 @@ TEST_F(FileCheckTest, FileCheckContext) {
|
||||
EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
|
||||
P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
|
||||
ExpressionAST = P.parseNumericSubstitutionBlock(
|
||||
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
|
||||
GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false,
|
||||
/*LineNumber=*/4, &Cxt, SM);
|
||||
EXPECT_TRUE(bool(ExpressionAST));
|
||||
ExpressionVal = (*ExpressionAST)->eval();
|
||||
EXPECT_TRUE(bool(ExpressionVal));
|
||||
|
Loading…
Reference in New Issue
Block a user