1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

Revert "FileCheck [5/12]: Introduce regular numeric variables"

This reverts r360578 (git e47362c1ec1ea31b626336cc05822035601c3e57) to
solve the sphinx build failure on
http://lab.llvm.org:8011/builders/llvm-sphinx-docs buildbot.

llvm-svn: 360653
This commit is contained in:
Thomas Preud'homme 2019-05-14 08:43:11 +00:00
parent 34de1a1455
commit 7206726a7e
11 changed files with 151 additions and 802 deletions

View File

@ -105,11 +105,6 @@ 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>
Sets a filecheck numeric variable ``NUMVAR`` to ``<VALUE>`` that can be used
in ``CHECK:`` lines.
.. option:: -version
Show the version number of this program.
@ -565,51 +560,8 @@ CHECK-LABEL block. Global variables are not affected by CHECK-LABEL.
This makes it easier to ensure that individual tests are not affected
by variables set in preceding tests.
FileCheck Numeric Variables and Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:program:`FileCheck` also allows checking for numeric values that satisfy a
numeric expression constraint based on numeric variables. This allows
``CHECK:`` directives to verify a numeric relation between two numbers, such as
the need for consecutive registers to be used.
The syntax to check a numeric expression constraint is
``[[#<NUMVAR><op><offset>]]`` where:
*``<NUMVAR>`` is the name of a numeric variable defined on the command line.
*``<op>`` is an optional numeric operation to perform on the value of
``<NUMVAR>``. Currently supported numeric operations are ``+`` and ``-``.
*``<offset>`` is the immediate value that constitutes the second operand of
the numeric operation <op>. It must be present if ``<op>`` is present,
absent otherwise.
For example:
.. code-block:: llvm
; CHECK: add r[[#REG]], r[[#REG]], r[[#REG+1]]
The above example would match the line:
.. code-block:: llvm
add r5, r5, r6
but would not match the line:
.. code-block:: llvm
add r5, r5, r7
due to ``7`` being unequal to ``5 + 1``.
The ``--enable-var-scope`` option has the same effect on numeric variables as
on pattern variables.
FileCheck Pseudo Numeric Variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck Numeric Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes there's a need to verify output that contains line numbers of the
match file, e.g. when testing compiler diagnostics. This introduces a certain
@ -617,9 +569,11 @@ fragility of the match file structure, as "``CHECK:``" lines contain absolute
line numbers in the same file, which have to be updated whenever line numbers
change due to text addition or deletion.
To support this case, FileCheck understands the ``@LINE`` pseudo numeric
variable which evaluates to the line number of the CHECK pattern where it is
found.
To support this case, FileCheck allows using ``[[#@LINE]]``,
``[[#@LINE+<offset>]]`` and ``[[#@LINE-<offset>]]`` numeric expressions in
patterns, with an arbitrary number of spaces between each element of the
expression. These expressions expand to the number of the line where a pattern
is located (with an optional integer offset).
This way match patterns can be put near the relevant test lines and include
relative line number references, for example:

View File

@ -40,67 +40,20 @@ struct FileCheckRequest {
// Numeric expression handling code.
//===----------------------------------------------------------------------===//
/// Class representing a numeric variable with a given value in a numeric
/// expression.
class FileCheckNumericVariable {
private:
/// Name of the numeric variable.
StringRef Name;
/// Value of numeric variable, if defined, or None otherwise.
llvm::Optional<uint64_t> Value;
public:
/// Constructor for numeric variable \p Name with a known \p Value at parse
/// time (e.g. the @LINE numeric variable).
FileCheckNumericVariable(StringRef Name, uint64_t Value)
: Name(Name), Value(Value) {}
/// \returns name of that numeric variable.
StringRef getName() const { return Name; }
/// \returns value of this numeric variable.
llvm::Optional<uint64_t> getValue() const { return Value; }
/// Sets value of this numeric variable if not defined. \returns whether the
/// variable was already defined.
bool setValue(uint64_t Value);
/// Clears value of this numeric variable. \returns whether the variable was
/// already undefined.
bool clearValue();
};
/// Type of functions evaluating a given binary operation.
using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
/// Class representing a numeric expression consisting of either a single
/// numeric variable or a binary operation between a numeric variable and an
/// immediate.
/// Class representing a numeric expression.
class FileCheckNumExpr {
private:
/// Left operand.
FileCheckNumericVariable *LeftOp;
/// Right operand.
uint64_t RightOp;
/// Pointer to function that can evaluate this binary operation.
binop_eval_t EvalBinop;
/// Value of the numeric expression.
uint64_t Value;
public:
FileCheckNumExpr(binop_eval_t EvalBinop,
FileCheckNumericVariable *OperandLeft, uint64_t OperandRight)
: LeftOp(OperandLeft), RightOp(OperandRight), EvalBinop(EvalBinop) {}
/// Constructor for a numeric expression with a known value at parse time,
/// e.g. the implicit numeric expression defining the @LINE numeric pseudo
/// variable.
explicit FileCheckNumExpr(uint64_t Value) : Value(Value) {}
/// Evaluates the value of this numeric expression, using EvalBinop to
/// perform the binary operation it consists of. \returns None if the numeric
/// variable used is undefined, or the expression value otherwise.
llvm::Optional<uint64_t> eval() const;
/// \returns the name of the undefined variable used in this expression if
/// any or an empty string otherwise.
StringRef getUndefVarName() const;
/// \returns the value being matched against.
uint64_t getValue() const { return Value; }
};
class FileCheckPatternContext;
@ -152,9 +105,9 @@ public:
size_t getIndex() const { return InsertIdx; }
/// \returns the result of the substitution represented by this class
/// instance or None if substitution failed. Numeric expressions are
/// substituted by their values. Pattern variables are simply replaced by the
/// text their definition matched.
/// instance or None if substitution failed. For a numeric expression we
/// substitute it by its value. For a pattern variable we simply replace it
/// by the text its definition matched.
llvm::Optional<std::string> getResult() const;
/// \returns the name of the undefined variable used in this substitution, if
@ -222,35 +175,19 @@ private:
/// Back-references are used for uses after any the other definition.
StringMap<StringRef> GlobalVariableTable;
/// Map of all pattern variables defined so far. Used at parse time to detect
/// a name conflict between a numeric variable and a pattern variable when
/// the former is defined on a later line than the latter.
StringMap<bool> DefinedVariableTable;
/// When matching a given pattern, this holds the pointers to the classes
/// representing the last definitions of numeric variables defined in
/// previous patterns. Earlier definition of the variables, if any, have
/// their own class instance not referenced by this table.
StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;
/// Vector holding pointers to all parsed numeric expressions. Used to
/// automatically free the numeric expressions once they are guaranteed to no
/// longer be used.
std::vector<std::unique_ptr<FileCheckNumExpr>> NumExprs;
/// Vector holding pointers to all parsed numeric variables. Used to
/// automatically free them once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
public:
/// \returns the value of pattern variable \p VarName or None if no such
/// variable has been defined.
llvm::Optional<StringRef> getPatternVarValue(StringRef VarName);
/// Defines pattern and numeric variables from definitions given on the
/// command line, passed as a vector of [#]VAR=VAL strings in
/// \p CmdlineDefines. Reports any error to \p SM and \returns whether an
/// error occured.
/// Defines pattern variables from definitions given on the command line,
/// passed as a vector of VAR=VAL strings in \p CmdlineDefines. Reports any
/// error to \p SM and \returns whether an error occured.
bool defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
SourceMgr &SM);
@ -261,13 +198,7 @@ public:
private:
/// Makes a new numeric expression instance and registers it for destruction
/// when the context is destroyed.
FileCheckNumExpr *makeNumExpr(binop_eval_t EvalBinop,
FileCheckNumericVariable *OperandLeft,
uint64_t OperandRight);
/// Makes a new numeric variable and registers it for destruction when the
/// context is destroyed.
FileCheckNumericVariable *makeNumericVariable(StringRef Name, uint64_t Value);
template <class... Types> FileCheckNumExpr *makeNumExpr(Types... Args);
};
class FileCheckPattern {
@ -283,12 +214,12 @@ class FileCheckPattern {
/// Entries in this vector represent uses of a pattern variable or a numeric
/// expression in the pattern that need to be substituted in the regexp
/// pattern at match time, e.g. "foo[[bar]]baz[[#N+1]]". In this case, the
/// RegExStr will contain "foobaz" and we'll get two entries in this vector
/// that tells us to insert the value of pattern variable "bar" at offset 3
/// and the value of numeric expression "N+1" at offset 6. Uses are
/// represented by a FileCheckPatternSubstitution class to abstract whether
/// it is a pattern variable or a numeric expression.
/// pattern at match time, e.g. "foo[[bar]]baz[[#@LINE+1]]". In this case,
/// the RegExStr will contain "foobaz" and we'll get two entries in this
/// vector that tells us to insert the value of pattern variable "bar" at
/// offset 3 and the value of numeric expression "@LINE+1" at offset 6. Uses
/// are represented by a FileCheckPatternSubstitution class to abstract
/// whether it is a pattern variable or a numeric expression.
std::vector<FileCheckPatternSubstitution> Substitutions;
/// Maps names of pattern variables defined in a pattern to the parenthesized
@ -302,12 +233,8 @@ class FileCheckPattern {
/// iterating over values.
std::map<StringRef, unsigned> VariableDefs;
/// Pointer to a class instance holding the global state shared by all
/// patterns:
/// - separate tables with the values of live pattern and numeric variables
/// respectively at the start of any given CHECK line;
/// - table holding whether a pattern variable has been defined at any given
/// point during the parsing phase.
/// Pointer to the class instance shared by all patterns holding a table with
/// the values of live variables at the start of any given CHECK line.
FileCheckPatternContext *Context;
Check::FileCheckType CheckTy;
@ -335,13 +262,11 @@ public:
/// character that is part of the variable name. Otherwise, only
/// \returns true.
static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
/// Parses a numeric expression involving (pseudo if \p IsPseudo is true)
/// variable \p Name with the string corresponding to the operation being
/// performed in \p Trailer. \returns the class representing the numeric
/// expression or nullptr if parsing fails in which case errors are reported
/// on \p SM.
FileCheckNumExpr *parseNumericExpression(StringRef Name, bool IsPseudo,
StringRef Trailer,
/// Parses a numeric expression involving pseudo variable \p Name with the
/// string corresponding to the operation being performed in \p Trailer.
/// \returns the class representing the numeric expression or nullptr if
/// parsing fails in which case errors are reported on \p SM.
FileCheckNumExpr *parseNumericExpression(StringRef Name, StringRef Trailer,
const SourceMgr &SM) const;
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
/// instance accordingly.

View File

@ -24,54 +24,24 @@
using namespace llvm;
bool FileCheckNumericVariable::setValue(uint64_t NewValue) {
if (Value)
return true;
Value = NewValue;
return false;
}
bool FileCheckNumericVariable::clearValue() {
if (!Value)
return true;
Value = llvm::None;
return false;
}
llvm::Optional<uint64_t> FileCheckNumExpr::eval() const {
llvm::Optional<uint64_t> LeftOp = this->LeftOp->getValue();
// Variable is undefined.
if (!LeftOp)
return llvm::None;
return EvalBinop(*LeftOp, RightOp);
}
StringRef FileCheckNumExpr::getUndefVarName() const {
if (!LeftOp->getValue())
return LeftOp->getName();
return StringRef();
}
llvm::Optional<std::string> FileCheckPatternSubstitution::getResult() const {
if (IsNumExpr) {
llvm::Optional<uint64_t> EvaluatedValue = NumExpr->eval();
if (!EvaluatedValue)
return utostr(NumExpr->getValue());
} else {
// Look up the value and escape it so that we can put it into the
// regex.
llvm::Optional<StringRef> VarVal = Context->getPatternVarValue(FromStr);
if (!VarVal)
return llvm::None;
return utostr(*EvaluatedValue);
return Regex::escape(*VarVal);
}
// Look up the value and escape it so that we can put it into the regex.
llvm::Optional<StringRef> VarVal = Context->getPatternVarValue(FromStr);
if (!VarVal)
return llvm::None;
return Regex::escape(*VarVal);
}
StringRef FileCheckPatternSubstitution::getUndefVarName() const {
// Parsing guarantees only @LINE is ever referenced and it is not undefined
// by ClearLocalVars.
if (IsNumExpr)
// Although a use of an undefined numeric variable is detected at parse
// time, a numeric variable can be undefined later by ClearLocalVariables.
return NumExpr->getUndefVarName();
return StringRef();
if (!Context->getPatternVarValue(FromStr))
return FromStr;
@ -121,70 +91,31 @@ static char popFront(StringRef &S) {
return C;
}
static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
return LeftOp + RightOp;
}
static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
return LeftOp - RightOp;
}
FileCheckNumExpr *
FileCheckPattern::parseNumericExpression(StringRef Name, bool IsPseudo,
StringRef Trailer,
FileCheckPattern::parseNumericExpression(StringRef Name, StringRef Trailer,
const SourceMgr &SM) const {
if (IsPseudo && !Name.equals("@LINE")) {
if (!Name.equals("@LINE")) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"invalid pseudo numeric variable '" + Name + "'");
return nullptr;
}
// This method is indirectly called from ParsePattern for all numeric
// variable definitions and uses in the order in which they appear in the
// CHECK pattern. For each definition, the pointer to the class instance of
// the corresponding numeric variable definition is stored in
// GlobalNumericVariableTable. Therefore, the pointer we get below is for the
// class instance corresponding to the last definition of this variable use.
auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
if (VarTableIter == Context->GlobalNumericVariableTable.end()) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"using undefined numeric variable '" + Name + "'");
return nullptr;
}
FileCheckNumericVariable *LeftOp = VarTableIter->second;
// Check if this is a supported operation and select a function to perform
// it.
// Check if this is a supported operation and select function to perform it.
Trailer = Trailer.ltrim(SpaceChars);
if (Trailer.empty()) {
return Context->makeNumExpr(add, LeftOp, 0);
}
if (Trailer.empty())
return Context->makeNumExpr(LineNumber);
SMLoc OpLoc = SMLoc::getFromPointer(Trailer.data());
char Operator = popFront(Trailer);
binop_eval_t EvalBinop;
switch (Operator) {
case '+':
EvalBinop = add;
break;
case '-':
EvalBinop = sub;
break;
default:
SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
Twine("unsupported numeric operation '") + Twine(Operator) +
"'");
return nullptr;
}
// Parse right operand.
Trailer = Trailer.ltrim(SpaceChars);
if (Trailer.empty()) {
SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
"missing operand in numeric expression");
"missing operand in numeric expression '" + Trailer + "'");
return nullptr;
}
uint64_t RightOp;
if (Trailer.consumeInteger(10, RightOp)) {
uint64_t Offset;
if (Trailer.consumeInteger(10, Offset)) {
SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
"invalid offset in numeric expression '" + Trailer + "'");
return nullptr;
@ -197,24 +128,31 @@ FileCheckPattern::parseNumericExpression(StringRef Name, bool IsPseudo,
return nullptr;
}
return Context->makeNumExpr(EvalBinop, LeftOp, RightOp);
uint64_t Value;
switch (Operator) {
case '+':
Value = LineNumber + Offset;
break;
case '-':
Value = LineNumber - Offset;
break;
default:
SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
Twine("unsupported numeric operation '") + Twine(Operator) +
"'");
return nullptr;
}
return Context->makeNumExpr(Value);
}
bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
SourceMgr &SM, unsigned LineNumber,
const FileCheckRequest &Req) {
SourceMgr &SM, unsigned LineNumber,
const FileCheckRequest &Req) {
bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
this->LineNumber = LineNumber;
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
// Create fake @LINE pseudo variable definition.
StringRef LinePseudo = "@LINE";
uint64_t LineNumber64 = LineNumber;
FileCheckNumericVariable *LinePseudoVar =
Context->makeNumericVariable(LinePseudo, LineNumber64);
Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar;
if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
// Ignore trailing whitespace.
while (!PatternStr.empty() &&
@ -292,10 +230,10 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
// forms: [[foo:.*]] and [[foo]]. The former matches .* (or some other
// regex) and assigns it to the FileCheck variable 'foo'. The latter
// substitutes foo's value. Numeric expressions start with a '#' sign after
// the double brackets and only have the substitution form. Both pattern
// and numeric variables must satisfy the regular expression
// "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch some common
// errors.
// the double brackets and only have the substitution form. Pattern
// variables must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*"
// to be valid, as this helps catch some common errors. Numeric expressions
// only support the @LINE pseudo numeric variable.
if (PatternStr.startswith("[[")) {
StringRef UnparsedPatternStr = PatternStr.substr(2);
// Find the closing bracket pair ending the match. End is going to be an
@ -345,33 +283,21 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
StringRef Trailer = MatchStr.substr(TrailIdx);
bool IsVarDef = (VarEndIdx != StringRef::npos);
if (IsVarDef) {
if (IsPseudo || !Trailer.consume_front(":")) {
SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
SourceMgr::DK_Error,
"invalid name in pattern variable definition");
return true;
}
// Detect collisions between pattern and numeric variables when the
// former is created later than the latter.
if (Context->GlobalNumericVariableTable.find(Name) !=
Context->GlobalNumericVariableTable.end()) {
SM.PrintMessage(
SMLoc::getFromPointer(MatchStr.data()), SourceMgr::DK_Error,
"numeric variable with name '" + Name + "' already exists");
return true;
}
if (IsVarDef && (IsPseudo || !Trailer.consume_front(":"))) {
SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
SourceMgr::DK_Error,
"invalid name in pattern variable definition");
return true;
}
if (IsNumExpr || (!IsVarDef && IsPseudo)) {
NumExpr = parseNumericExpression(Name, IsPseudo, Trailer, SM);
if (!IsVarDef && IsPseudo) {
NumExpr = parseNumericExpression(Name, Trailer, SM);
if (NumExpr == nullptr)
return true;
IsNumExpr = true;
}
// Handle variable use: [[foo]] and [[#<foo expr>]].
// Handle [[foo]].
if (!IsVarDef) {
// Handle use of pattern variables that were defined earlier on the
// same line by emitting a backreference.
@ -640,22 +566,12 @@ FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
return VarIter->second;
}
FileCheckNumExpr *
FileCheckPatternContext::makeNumExpr(binop_eval_t EvalBinop,
FileCheckNumericVariable *OperandLeft,
uint64_t OperandRight) {
NumExprs.push_back(llvm::make_unique<FileCheckNumExpr>(EvalBinop, OperandLeft,
OperandRight));
template <class... Types>
FileCheckNumExpr *FileCheckPatternContext::makeNumExpr(Types... Args) {
NumExprs.emplace_back(new FileCheckNumExpr(Args...));
return NumExprs.back().get();
}
FileCheckNumericVariable *
FileCheckPatternContext::makeNumericVariable(StringRef Name, uint64_t Value) {
NumericVariables.push_back(
llvm::make_unique<FileCheckNumericVariable>(Name, Value));
return NumericVariables.back().get();
}
size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
// Offset keeps track of the current offset within the input Str
size_t Offset = 0;
@ -1529,7 +1445,7 @@ Regex llvm::FileCheck::buildCheckPrefixRegex() {
bool FileCheckPatternContext::defineCmdlineVariables(
std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {
assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
assert(GlobalVariableTable.empty() &&
"Overriding defined variable with command-line variable definitions");
if (CmdlineDefines.empty())
@ -1547,9 +1463,6 @@ bool FileCheckPatternContext::defineCmdlineVariables(
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
// global definition with invalid syntax.
std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =
MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");
StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
@ -1559,91 +1472,27 @@ bool FileCheckPatternContext::defineCmdlineVariables(
CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,
false /*KeepEmpty*/);
for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
if (CmdlineDef.find('=') == StringRef::npos) {
SM.PrintMessage(SMLoc::getFromPointer(CmdlineDef.data()),
unsigned NameStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
if (CmdlineDefDiag.substr(NameStart).find('=') == StringRef::npos) {
SM.PrintMessage(SMLoc::getFromPointer(CmdlineDefDiag.data()),
SourceMgr::DK_Error,
"Missing equal sign in global definition");
ErrorFound = true;
continue;
}
// Numeric variable definition.
if (CmdlineDef[0] == '#') {
bool IsPseudo;
unsigned TrailIdx;
size_t EqIdx = CmdlineDef.find('=');
StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
if (FileCheckPattern::parseVariable(CmdlineName, IsPseudo, TrailIdx) ||
IsPseudo || TrailIdx != CmdlineName.size() || CmdlineName.empty()) {
SM.PrintMessage(SMLoc::getFromPointer(CmdlineName.data()),
SourceMgr::DK_Error,
"invalid name in numeric variable definition '" +
CmdlineName + "'");
ErrorFound = true;
continue;
}
// Detect collisions between pattern and numeric variables when the
// latter is created later than the former.
if (DefinedVariableTable.find(CmdlineName) !=
DefinedVariableTable.end()) {
SM.PrintMessage(
SMLoc::getFromPointer(CmdlineName.data()), SourceMgr::DK_Error,
"pattern variable with name '" + CmdlineName + "' already exists");
ErrorFound = true;
continue;
}
StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
uint64_t Val;
if (CmdlineVal.getAsInteger(10, Val)) {
SM.PrintMessage(SMLoc::getFromPointer(CmdlineVal.data()),
SourceMgr::DK_Error,
"invalid value in numeric variable definition '" +
CmdlineVal + "'");
ErrorFound = true;
continue;
}
auto DefinedNumericVariable = makeNumericVariable(CmdlineName, Val);
// Record this variable definition.
GlobalNumericVariableTable[CmdlineName] = DefinedNumericVariable;
} else {
// Pattern variable definition.
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
StringRef Name = CmdlineNameVal.first;
bool IsPseudo;
unsigned TrailIdx;
if (FileCheckPattern::parseVariable(Name, IsPseudo, TrailIdx) ||
IsPseudo || TrailIdx != Name.size() || Name.empty()) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"invalid name in pattern variable definition '" + Name +
"'");
ErrorFound = true;
continue;
}
// Detect collisions between pattern and numeric variables when the
// former is created later than the latter.
if (GlobalNumericVariableTable.find(Name) !=
GlobalNumericVariableTable.end()) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"numeric variable with name '" + Name +
"' already exists");
ErrorFound = true;
continue;
}
GlobalVariableTable.insert(CmdlineNameVal);
// Mark the pattern variable as defined to detect collisions between
// pattern and numeric variables in DefineCmdlineVariables when the
// latter is created later than the former. We cannot reuse
// GlobalVariableTable for that by populating it with an empty string
// since we would then lose the ability to detect the use of an undefined
// variable in Match().
DefinedVariableTable[Name] = true;
std::pair<StringRef, StringRef> CmdlineNameVal =
CmdlineDefDiag.substr(NameStart).split('=');
StringRef Name = CmdlineNameVal.first;
bool IsPseudo;
unsigned TrailIdx;
if (FileCheckPattern::parseVariable(Name, IsPseudo, TrailIdx) || IsPseudo ||
TrailIdx != Name.size() || Name.empty()) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"invalid name for variable definition '" + Name + "'");
ErrorFound = true;
continue;
}
GlobalVariableTable.insert(CmdlineNameVal);
}
return ErrorFound;
@ -1655,22 +1504,8 @@ void FileCheckPatternContext::clearLocalVars() {
if (Var.first()[0] != '$')
LocalPatternVars.push_back(Var.first());
// Numeric expression substitution reads the value of a variable directly,
// not via GlobalNumericVariableTable. Therefore, we clear local variables by
// clearing their value which will lead to a numeric expression substitution
// failure. We also mark the variable for removal from
// GlobalNumericVariableTable since this is what defineCmdlineVariables
// checks to decide that no global variable has been defined.
for (const auto &Var : GlobalNumericVariableTable)
if (Var.first()[0] != '$') {
Var.getValue()->clearValue();
LocalNumericVars.push_back(Var.first());
}
for (const auto &Var : LocalPatternVars)
GlobalVariableTable.erase(Var);
for (const auto &Var : LocalNumericVars)
GlobalNumericVariableTable.erase(Var);
}
bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
@ -1703,10 +1538,7 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
++j;
}
// Do not clear the first region as it's the one before the first
// CHECK-LABEL and it would clear variables defined on the command-line
// before they get used.
if (i != 0 && Req.EnableVarScope)
if (Req.EnableVarScope)
PatternContext.clearLocalVars();
for (; i != j; ++i) {

View File

@ -1,33 +0,0 @@
; Test incorrect syntax for -D# option is correctly diagnosed.
; Invalid variable name: starts with a digit.
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 name in numeric variable definition '10VALUE'
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:20: error: invalid name in numeric variable definition '@VALUE'
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:20: error: invalid name in numeric variable definition 'VALUE+2'
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: {{^ \^$}}

View File

@ -1,22 +0,0 @@
; 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
Numeric value = 12
CHECKNUM: Numeric value = [[#NUMVAL]]
NUMNOT-NOT: Numeric value = [[#NUMVAL]]
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 numeric expression "NUMVAL" equal to "8"
NUMERRMSG: defines.txt:[[#@LINE-7]]: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 numeric expression "NUMVAL" equal to "12"

View File

@ -1,95 +0,0 @@
RUN: FileCheck -D#VAR1=11 --input-file %s %s
; We use CHECK-NEXT directives to force a match on all lines with digits.
; Numeric expressions using variables defined on the command-line without
; spaces
USE NO SPC
11
12
10
CHECK-LABEL: USE NO SPC
CHECK-NEXT: [[#VAR1]]
CHECK-NEXT: [[#VAR1+1]]
CHECK-NEXT: [[#VAR1-1]]
; Numeric expressions using variables defined on the command-line in alternate
; spacing
USE ALT SPC
11
11
12
12
12
12
10
10
10
10
CHECK-LABEL: USE ALT SPC
CHECK-NEXT: [[# VAR1]]
CHECK-NEXT: [[# VAR1 ]]
CHECK-NEXT: [[# VAR1+1]]
CHECK-NEXT: [[# VAR1 +1]]
CHECK-NEXT: [[# VAR1 + 1]]
CHECK-NEXT: [[# VAR1 + 1 ]]
CHECK-NEXT: [[# VAR1-1]]
CHECK-NEXT: [[# VAR1 -1]]
CHECK-NEXT: [[# VAR1 - 1]]
CHECK-NEXT: [[# VAR1 - 1 ]]
; Numeric expressions using variables defined on the command-line and an
; immediate interpreted as an unsigned value
; Note: 9223372036854775819 = 0x8000000000000000 + 11
; 9223372036854775808 = 0x8000000000000000
USE UNSIGNED IMM
9223372036854775819
CHECK-LABEL: USE UNSIGNED IMM
CHECK-NEXT: [[#VAR1+9223372036854775808]]
; Numeric expression using undefined variable
RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s
UNDEF VAR USE
UNDEFVAR: 11
UNDEF-USE-LABEL: UNDEF VAR USE
UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR]]
UNDEF-USE-MSG: numeric-expression.txt:[[#@LINE-1]]:30: error: using undefined numeric variable 'UNDEFVAR'
UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}}
UNDEF-USE-MSG-NEXT: {{^ \^$}}
; Numeric expression with unsupported operator
RUN: not FileCheck -D#VAR1=11 --check-prefixes CHECK,INVAL-OP --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix INVAL-OP-MSG %s
INVALID OPERATOR
VAR1*2: 22
INVAL-OP-LABEL: INVALID OPERATOR
INVAL-OP-NEXT: VAR1*2: [[#VAR1*2]]
INVAL-OP-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: unsupported numeric operation '*'
INVAL-OP-MSG-NEXT: {{I}}NVAL-OP-NEXT: VAR1*2: {{\[\[#VAR1\*2\]\]}}
INVAL-OP-MSG-NEXT: {{^ \^$}}
; Name conflict between Numeric variable definition and pattern variable
; definition
RUN: not FileCheck -D#VAR1=11 -D#NUMVAR=42 --check-prefixes CONFLICT,CONFLICT1 --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix CLI-INPUT-PAT-CONFLICT %s
RUN: not FileCheck -D#VAR1=11 -D#NUMVAR=42 -DNUMVAR=foobar --check-prefix CONFLICT --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix CLI-CLI-PAT-CONFLICT %s
RUN: not FileCheck -D#VAR1=11 -DPATVAR=foobar -D#PATVAR=42 --check-prefix CONFLICT --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix CLI-CLI-NUM-CONFLICT %s
PATVAR NUMVAR CONFLICT
foobar
CONFLICT-LABEL: PATVAR NUMVAR CONFLICT
CONFLICT1-NEXT: [[NUMVAR:foo.*]]
CLI-INPUT-PAT-CONFLICT: numeric-expression.txt:[[#@LINE-1]]:19: error: numeric variable with name 'NUMVAR' already exists
CLI-INPUT-PAT-CONFLICT-NEXT: {{C}}ONFLICT1-NEXT: {{\[\[NUMVAR:foo\.\*\]\]}}
CLI-INPUT-PAT-CONFLICT-NEXT: {{^ \^$}}
CLI-CLI-PAT-CONFLICT: Global defines:3:19: error: numeric variable with name 'NUMVAR' already exists
CLI-CLI-PAT-CONFLICT-NEXT: Global define #3: NUMVAR=foobar
CLI-CLI-PAT-CONFLICT-NEXT: {{^ \^$}}
CLI-CLI-NUM-CONFLICT: Global defines:3:20: error: pattern variable with name 'PATVAR' already exists
CLI-CLI-NUM-CONFLICT-NEXT: Global define #3: #PATVAR=42
CLI-CLI-NUM-CONFLICT-NEXT: {{^ \^$}}

View File

@ -28,7 +28,7 @@ ERRCLIVAR2: Missing pattern variable name in command-line definition '-D='
RUN: not FileCheck -D10VALUE=10 --input-file %s %s 2>&1 \
RUN: | FileCheck %s --strict-whitespace --check-prefix ERRCLIFMT
ERRCLIFMT: Global defines:1:19: error: invalid name in pattern variable definition '10VALUE'
ERRCLIFMT: Global defines:1:19: error: invalid name for variable definition '10VALUE'
ERRCLIFMT-NEXT: Global define #1: 10VALUE=10
ERRCLIFMT-NEXT: {{^ \^$}}
@ -36,7 +36,7 @@ ERRCLIFMT-NEXT: {{^ \^$}}
RUN: not FileCheck -D@VALUE=10 --input-file %s %s 2>&1 \
RUN: | FileCheck %s --strict-whitespace --check-prefix ERRCLIPSEUDO
ERRCLIPSEUDO: Global defines:1:19: error: invalid name in pattern variable definition '@VALUE'
ERRCLIPSEUDO: Global defines:1:19: error: invalid name for variable definition '@VALUE'
ERRCLIPSEUDO-NEXT: Global define #1: @VALUE=10
ERRCLIPSEUDO-NEXT: {{^ \^$}}
@ -44,6 +44,6 @@ ERRCLIPSEUDO-NEXT: {{^ \^$}}
RUN: not FileCheck -D'VALUE + 2=10' --input-file %s %s 2>&1 \
RUN: | FileCheck %s --strict-whitespace --check-prefix ERRCLITRAIL
ERRCLITRAIL: Global defines:1:19: error: invalid name in pattern variable definition 'VALUE + 2'
ERRCLITRAIL: Global defines:1:19: error: invalid name for variable definition 'VALUE + 2'
ERRCLITRAIL-NEXT: Global define #1: VALUE + 2=10
ERRCLITRAIL-NEXT: {{^ \^$}}

View File

@ -0,0 +1,23 @@
// RUN: FileCheck -input-file %s %s
// RUN: FileCheck -check-prefixes CHECK,GLOBAL -input-file %s %s
// RUN: FileCheck -check-prefixes CHECK,LOCAL -input-file %s %s
// RUN: FileCheck -check-prefixes CHECK,GLOBAL --enable-var-scope -input-file %s %s
// RUN: not FileCheck -check-prefixes CHECK,LOCAL --enable-var-scope -input-file %s %s
local
global
; CHECK: [[LOCAL:loc.*]]
; CHECK: [[$GLOBAL:glo.*]]
local2
global2
; CHECK: [[LOCAL]]2
; CHECK: [[$GLOBAL]]2
barrier:
; CHECK-LABEL: barrier
local3
global3
; LOCAL: [[LOCAL]]3
; GLOBAL: [[$GLOBAL]]3

View File

@ -1,35 +0,0 @@
; Test that variables not starting with dollar sign get undefined after a
; CHECK-LABEL directive iff --enable-var-scope is used.
RUN: FileCheck -D#LOCNUM=1 -D'#$GLOBNUM=1' --check-prefixes CHECK,LOCAL3,GLOBAL --input-file %s %s
RUN: FileCheck -D#LOCNUM=1 -D'#$GLOBNUM=1' --check-prefixes CHECK,GLOBAL --enable-var-scope --input-file %s %s
RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL1 --enable-var-scope --input-file %s %s 2>&1 \
RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCAL %s
RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL2 --enable-var-scope --input-file %s %s 2>&1 \
RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCNUM %s
RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL3 --enable-var-scope --input-file %s %s 2>&1 \
RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCAL,ERRUNDEFLOCNUM %s
local1
global1
CHECK: [[LOCAL:loc[^[:digit:]]*]][[#LOCNUM]]
CHECK: [[$GLOBAL:glo[^[:digit:]]*]][[#$GLOBNUM]]
local2
global2
CHECK: [[LOCAL]][[#LOCNUM+1]]
CHECK: [[$GLOBAL]][[#$GLOBNUM+1]]
barrier:
CHECK-LABEL: barrier
local3
global3
LOCAL1: [[LOCAL]]3
LOCAL2: local[[#LOCNUM+2]]
LOCAL3: [[LOCAL]][[#LOCNUM+2]]
GLOBAL: [[$GLOBAL]][[#$GLOBNUM+2]]
ERRUNDEF: expected string not found in input
ERRUNDEFLOCAL: uses undefined variable "LOCAL"
ERRUNDEFLOCNUM: uses undefined variable "LOCNUM"

View File

@ -1,6 +1,6 @@
; RUN: FileCheck -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck -check-prefix QUIET --allow-empty %s
; RUN: FileCheck -v -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix V %s
; RUN: FileCheck -vv -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefixes V,VV %s
; RUN: FileCheck -input-file %s %s 2>&1 | FileCheck -check-prefix QUIET --allow-empty %s
; RUN: FileCheck -v -input-file %s %s 2>&1 | FileCheck -check-prefix V %s
; RUN: FileCheck -vv -input-file %s %s 2>&1 | FileCheck -check-prefixes V,VV %s
foo
bar
@ -29,39 +29,6 @@ VV-NEXT: verbose.txt:[[@LINE-22]]:1: note: scanning from here
VV-NEXT: {{^}}bar{{$}}
VV-NEXT: {{^}}^{{$}}
NUMVAR:42
NUMVAR - 1:41
CHECK: NUMVAR:[[#NUMVAR]]
CHECK-NOT: [[#NUMVAR + 1]]
CHECK-NEXT: NUMVAR - 1:[[#NUMVAR - 1]]
V: verbose.txt:[[#@LINE-4]]:8: remark: {{C}}HECK: expected string found in input
V-NEXT: {{C}}HECK: {{NUMVAR:[[][[]#NUMVAR[]][]]$}}
V-NEXT: {{^ \^$}}
V-NEXT: verbose.txt:[[#@LINE-9]]:1: note: found here
V-NEXT: {{^}}NUMVAR:42{{$}}
V-NEXT: {{^}}^~~~~~~~~{{$}}
V-NEXT: verbose.txt:[[#@LINE-12]]:1: note: with numeric expression "NUMVAR" equal to "42"
V-NEXT: {{^}}NUMVAR:42{{$}}
V-NEXT: {{^}}^~~~~~~~~{{$}}
V-NEXT: verbose.txt:[[#@LINE-12]]:13: remark: {{C}}HECK-NEXT: expected string found in input
V-NEXT: {{C}}HECK-NEXT: {{NUMVAR - 1:[[][[]#NUMVAR - 1[]][]]$}}
V-NEXT: {{^ \^$}}
V-NEXT: verbose.txt:[[#@LINE-18]]:1: note: found here
V-NEXT: {{^}}NUMVAR - 1:41{{$}}
V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
V-NEXT: verbose.txt:[[#@LINE-21]]:1: note: with numeric expression "NUMVAR - 1" equal to "41"
V-NEXT: {{^}}NUMVAR - 1:41{{$}}
V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
VV-NEXT: verbose.txt:[[#@LINE-23]]:12: remark: {{C}}HECK-NOT: excluded string not found in input
VV-NEXT: {{C}}HECK-NOT: {{[[][[]#NUMVAR [+] 1[]][]]$}}
VV-NEXT: {{^ \^$}}
VV-NEXT: verbose.txt:[[#@LINE-28]]:1: note: scanning from here
VV-NEXT: {{^}}NUMVAR - 1:41{{$}}
VV-NEXT: {{^}}^{{$}}
before empty
after empty
@ -132,7 +99,7 @@ V-NEXT: {{^}}^~~{{$}}
VV-NEXT: verbose.txt:[[@LINE-9]]:19: remark: implicit EOF: expected string found in input
VV-NEXT: {{C}}HECK-NOT: {{[{][{]z[}][}]yx$}}
VV-NEXT: {{^ \^$}}
VV-NEXT: {{^ \^$}}
VV-NEXT: verbose.txt:[[@LINE+13]]:1: note: found here
VV-NOT: {{.}}
VV: {{^\^$}}

View File

@ -14,57 +14,6 @@ namespace {
class FileCheckTest : public ::testing::Test {};
TEST_F(FileCheckTest, NumericVariable) {
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
EXPECT_EQ("FOO", FooVar.getName());
// Defined variable: getValue returns a value, setValue fails and value
// remains unchanged.
llvm::Optional<uint64_t> Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(42U, *Value);
EXPECT_TRUE(FooVar.setValue(43));
Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(42U, *Value);
// Clearing variable: getValue fails, clearValue again fails.
EXPECT_FALSE(FooVar.clearValue());
Value = FooVar.getValue();
EXPECT_FALSE(Value);
EXPECT_TRUE(FooVar.clearValue());
// Undefined variable: setValue works, getValue returns value set.
EXPECT_FALSE(FooVar.setValue(43));
Value = FooVar.getValue();
EXPECT_TRUE(Value);
EXPECT_EQ(43U, *Value);
}
uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
TEST_F(FileCheckTest, NumExpr) {
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &FooVar, 18);
// Defined variable: eval returns right value, no undefined variable
// returned.
llvm::Optional<uint64_t> Value = NumExpr.eval();
EXPECT_TRUE(Value);
EXPECT_EQ(60U, *Value);
StringRef UndefVar = NumExpr.getUndefVarName();
EXPECT_EQ("", UndefVar);
// Undefined variable: eval fails, undefined variable returned. We call
// getUndefVarName first to check that it can be called without calling
// eval() first.
FooVar.clearValue();
UndefVar = NumExpr.getUndefVarName();
EXPECT_EQ("FOO", UndefVar);
Value = NumExpr.eval();
EXPECT_FALSE(Value);
}
TEST_F(FileCheckTest, ValidVarNameStart) {
EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
@ -141,38 +90,22 @@ TEST_F(FileCheckTest, ParseVar) {
EXPECT_EQ(TrailIdx, VarName.size() - 1);
}
static StringRef bufferize(SourceMgr &SM, StringRef Str) {
std::unique_ptr<MemoryBuffer> Buffer =
MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
StringRef StrBufferRef = Buffer->getBuffer();
SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
return StrBufferRef;
}
class ExprTester {
private:
SourceMgr SM;
FileCheckRequest Req;
FileCheckPatternContext Context;
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
public:
ExprTester() {
std::vector<std::string> GlobalDefines;
GlobalDefines.emplace_back(std::string("#FOO=42"));
Context.defineCmdlineVariables(GlobalDefines, SM);
// Call ParsePattern to have @LINE defined.
P.ParsePattern("N/A", "CHECK", SM, 1, Req);
}
bool parseExpect(std::string &VarName, std::string &Trailer) {
bool IsPseudo = VarName[0] == '@';
std::string NameTrailer = VarName + Trailer;
StringRef NameTrailerRef = bufferize(SM, NameTrailer);
std::unique_ptr<MemoryBuffer> Buffer =
MemoryBuffer::getMemBufferCopy(NameTrailer, "TestBuffer");
StringRef NameTrailerRef = Buffer->getBuffer();
SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
return P.parseNumericExpression(VarNameRef, IsPseudo, TrailerRef, SM) ==
nullptr;
return P.parseNumericExpression(VarNameRef, TrailerRef, SM) == nullptr;
}
};
@ -188,14 +121,6 @@ TEST_F(FileCheckTest, ParseExpr) {
Trailer = "";
EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
// Defined variable.
VarName = "FOO";
EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
// Undefined variable.
VarName = "UNDEF";
EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
// Wrong Pseudovar.
VarName = "@FOO";
EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
@ -228,38 +153,19 @@ TEST_F(FileCheckTest, Substitution) {
GlobalDefines.emplace_back(std::string("FOO=BAR"));
Context.defineCmdlineVariables(GlobalDefines, SM);
// Substitution of undefined pattern variable fails.
FileCheckPatternSubstitution PatternSubstitution =
FileCheckPatternSubstitution Substitution =
FileCheckPatternSubstitution(&Context, "VAR404", 42);
EXPECT_FALSE(PatternSubstitution.getResult());
EXPECT_FALSE(Substitution.getResult());
// Substitutions of defined pseudo and non-pseudo numeric variables return
// the right value.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumericVariable NVar = FileCheckNumericVariable("@N", 10);
FileCheckNumExpr NumExprLine = FileCheckNumExpr(doAdd, &LineVar, 0);
FileCheckNumExpr NumExprN = FileCheckNumExpr(doAdd, &NVar, 3);
FileCheckPatternSubstitution SubstitutionLine =
FileCheckPatternSubstitution(&Context, "@LINE", &NumExprLine, 12);
FileCheckPatternSubstitution SubstitutionN =
FileCheckPatternSubstitution(&Context, "N", &NumExprN, 30);
llvm::Optional<std::string> Value = SubstitutionLine.getResult();
FileCheckNumExpr NumExpr = FileCheckNumExpr(42);
Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
llvm::Optional<std::string> Value = Substitution.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("42", *Value);
Value = SubstitutionN.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("13", *Value);
// Substitution of undefined numeric variable fails.
LineVar.clearValue();
EXPECT_FALSE(SubstitutionLine.getResult());
NVar.clearValue();
EXPECT_FALSE(SubstitutionN.getResult());
// Substitution of defined pattern variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
PatternSubstitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
Value = PatternSubstitution.getResult();
Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
Value = Substitution.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("BAR", *Value);
}
@ -271,32 +177,19 @@ TEST_F(FileCheckTest, UndefVars) {
GlobalDefines.emplace_back(std::string("FOO=BAR"));
Context.defineCmdlineVariables(GlobalDefines, SM);
// getUndefVarName() on a pattern variable substitution with an undefined
// variable returns that variable.
FileCheckPatternSubstitution Substitution =
FileCheckPatternSubstitution(&Context, "VAR404", 42);
StringRef UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("VAR404", UndefVar);
// getUndefVarName() on a pattern variable substitution with a defined
// variable returns an empty string.
Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric expression substitution with a defined
// variable returns an empty string.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
FileCheckNumExpr NumExpr = FileCheckNumExpr(42);
Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric expression substitution with an undefined
// variable returns that variable.
LineVar.clearValue();
Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("@LINE", UndefVar);
EXPECT_EQ("", UndefVar);
}
TEST_F(FileCheckTest, FileCheckContext) {
@ -304,71 +197,36 @@ TEST_F(FileCheckTest, FileCheckContext) {
std::vector<std::string> GlobalDefines;
SourceMgr SM;
// Missing equal sign.
// Missing equal sign
GlobalDefines.emplace_back(std::string("LocalVar"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Empty variable name.
// Empty variable
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Invalid variable name.
// Invalid variable
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("18LocalVar=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Name conflict between pattern and numeric variable.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("LocalVar=18"));
GlobalDefines.emplace_back(std::string("#LocalVar=36"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
Cxt = FileCheckPatternContext();
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
Cxt = FileCheckPatternContext();
// Invalid numeric value for numeric variable.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Define local variables from command-line.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
GlobalDefines.emplace_back(std::string("EmptyVar="));
GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
bool GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
// Check defined variables are present and undefined is absent.
StringRef LocalVarStr = "LocalVar";
StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
StringRef EmptyVarStr = "EmptyVar";
StringRef UnknownVarStr = "UnknownVar";
llvm::Optional<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt);
FileCheckNumExpr *NumExpr =
P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
llvm::Optional<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
llvm::Optional<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
EXPECT_TRUE(LocalVar);
EXPECT_EQ(*LocalVar, "FOO");
EXPECT_TRUE(NumExpr);
llvm::Optional<uint64_t> NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 18U);
EXPECT_TRUE(EmptyVar);
EXPECT_EQ(*EmptyVar, "");
EXPECT_FALSE(UnknownVar);
@ -377,46 +235,21 @@ TEST_F(FileCheckTest, FileCheckContext) {
Cxt.clearLocalVars();
LocalVar = Cxt.getPatternVarValue(LocalVarStr);
EXPECT_FALSE(LocalVar);
// Check a numeric expression's evaluation fails if called after clearing of
// local variables, if it was created before. This is important because local
// variable clearing due to --enable-var-scope happens after numeric
// expressions are linked to the numeric variables they use.
EXPECT_FALSE(NumExpr->eval());
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_FALSE(NumExpr);
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_FALSE(EmptyVar);
// Redefine global variables and check variables are defined again.
GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
StringRef GlobalVarStr = "$GlobalVar";
StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
llvm::Optional<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
EXPECT_EQ(*GlobalVar, "BAR");
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 36U);
// Clear local variables and check global variables remain defined.
Cxt.clearLocalVars();
GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
EXPECT_EQ(*NumExprVal, 36U);
}
} // namespace