FileCheck: Improve FileCheck variable terminology

Summary:
Terminology introduced by [[#]] blocks is confusing and does not
integrate well with existing terminology.

First, variables referred by [[]] blocks are called "pattern variables"
while the text a CHECK directive needs to match is called a "CHECK
pattern". This is inconsistent with variables in [[#]] blocks since
[[#]] blocks are also found in CHECK pattern yet those variables are
called "numeric variable".

Second, the replacing of both [[]] and [[#]] blocks by the value of the
variable or expression they contain is represented by a
FileCheckPatternSubstitution class. The naming refers to being a
substitution in a CHECK pattern but could be wrongly understood as being
a substitution of a pattern variable.

Third and lastly, comments use "numeric expression" to refer both to the
[[#]] blocks as well as to the numeric expressions these blocks contain
which get evaluated at match time.

This patch solves these confusions by
- calling variables in [[]] and [[#]] blocks as string and numeric
  variables respectively;
- referring to [[]] and [[#]] as substitution *blocks*, with the former
  being a string substitution block and the latter a numeric
  substitution block;
- calling [[]] and [[#]] blocks to be replaced by the value of a
  variable or expression they contain a substitution (as opposed to
  definition when these blocks are used to defined a variable), with the
  former being a string substitution and the latter a numeric
  substitution;
- renaming the FileCheckPatternSubstitution as a FileCheckSubstitution
  class with FileCheckStringSubstitution and
  FileCheckNumericSubstitution subclasses;
- restricting the use of "numeric expression" to refer to the expression
  that is evaluated in a numeric substitution.

While numeric substitution blocks only support numeric substitutions of
numeric expressions at the moment there are plans to augment numeric
substitution blocks to support numeric definitions as well as both a
numeric definition and numeric substitution in the same numeric
substitution block.

Reviewers: jhenderson, jdenny, probinson, arichardson

Subscribers: hiraditya, arichardson, probinson, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D62146

llvm-svn: 361445
This commit is contained in:
Thomas Preud'homme 2019-05-23 00:10:14 +00:00
parent 33dbab8271
commit 1a944d27b2
9 changed files with 196 additions and 189 deletions

View File

@ -499,8 +499,8 @@ simply uniquely match a single line in the file being verified.
``CHECK-LABEL:`` directives cannot contain variable definitions or uses.
FileCheck Pattern Matching Syntax
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck Regex Matching Syntax
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All FileCheck directives take a pattern to match.
For most uses of FileCheck, fixed string matching is perfectly sufficient. For
@ -525,14 +525,15 @@ braces like you would in C. In the rare case that you want to match double
braces explicitly from the input, you can use something ugly like
``{{[{][{]}}`` as your pattern.
FileCheck Pattern Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck String Substitution Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is often useful to match a pattern and then verify that it occurs again
later in the file. For codegen tests, this can be useful to allow any register,
but verify that that register is used consistently later. To do this,
:program:`FileCheck` supports pattern expressions that allow pattern variables
to be defined and substituted into patterns. Here is a simple example:
later in the file. For codegen tests, this can be useful to allow any
register, but verify that that register is used consistently later. To do
this, :program:`FileCheck` supports string substitution blocks that allow
string variables to be defined and substituted into patterns. Here is a simple
example:
.. code-block:: llvm
@ -541,15 +542,16 @@ to be defined and substituted into patterns. Here is a simple example:
; CHECK: andw {{.*}}[[REGISTER]]
The first check line matches a regex ``%[a-z]+`` and captures it into the
variable ``REGISTER``. The second line verifies that whatever is in
``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`
variable references are always contained in ``[[ ]]`` pairs, and their names can
be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``. If a colon follows the name,
then it is a definition of the variable; otherwise, it is a use.
string variable ``REGISTER``. The second line verifies that whatever is in
``REGISTER`` occurs later in the file after an "``andw``". :program:`FileCheck`
string substitution blocks are always contained in ``[[ ]]`` pairs, and string
variable names can be formed with the regex ``[a-zA-Z_][a-zA-Z0-9_]*``. If a
colon follows the name, then it is a definition of the variable; otherwise, it
is a substitution.
:program:`FileCheck` variables can be defined multiple times, and uses always
get the latest value. Variables can also be used later on the same line they
were defined on. For example:
:program:`FileCheck` variables can be defined multiple times, and substitutions
always get the latest value. Variables can also be substituted later on the
same line they were defined on. For example:
.. code-block:: llvm
@ -565,16 +567,17 @@ 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FileCheck Numeric Substitution Blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: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.
:program:`FileCheck` also supports numeric substitution blocks that allow
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:
The syntax of a numeric substitution block is ``[[#<NUMVAR><op><offset>]]``
where:
* ``<NUMVAR>`` is the name of a numeric variable defined on the command line.
@ -585,6 +588,10 @@ The syntax to check a numeric expression constraint is
the numeric operation <op>. It must be present if ``<op>`` is present,
absent otherwise.
Spaces are accepted before, after and between any of these elements.
Unlike string substitution blocks, numeric substitution blocks only introduce
numeric substitutions which substitute a numeric expression for its value.
For example:
.. code-block:: llvm
@ -606,7 +613,7 @@ but would not match the line:
due to ``7`` being unequal to ``5 + 1``.
The ``--enable-var-scope`` option has the same effect on numeric variables as
on pattern variables.
on string variables.
FileCheck Pseudo Numeric Variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -632,9 +639,9 @@ relative line number references, for example:
// CHECK-NEXT: {{^ ;}}
int a
To support legacy uses of ``@LINE`` as a special pattern variable,
:program:`FileCheck` also accepts the following uses of ``@LINE`` with pattern
variable syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and
To support legacy uses of ``@LINE`` as a special string variable,
:program:`FileCheck` also accepts the following uses of ``@LINE`` with string
substitution block syntax: ``[[@LINE]]``, ``[[@LINE+<offset>]]`` and
``[[@LINE-<offset>]]`` without any spaces inside the brackets and where
``offset`` is an integer.

View File

@ -37,7 +37,7 @@ struct FileCheckRequest {
};
//===----------------------------------------------------------------------===//
// Numeric expression handling code.
// Numeric substitution handling code.
//===----------------------------------------------------------------------===//
/// Class representing a numeric variable with a given value in a numeric
@ -105,25 +105,28 @@ public:
class FileCheckPatternContext;
/// Class representing a substitution to perform in the string to match.
class FileCheckPatternSubstitution {
private:
/// Pointer to a class instance holding the table with the values of live
/// pattern variables at the start of any given CHECK line. Used for
/// substituting pattern variables (numeric variables have their value in the
/// FileCheckNumExpr class instance pointed to by NumExpr).
/// Class representing a substitution to perform in the RegExStr string.
class FileCheckSubstitution {
protected:
/// Pointer to a class instance holding, among other things, the table with
/// the values of live string variables at the start of any given CHECK line.
/// Used for substituting string variables with the text they were defined
/// as. Numeric expressions are linked to the numeric variables they use at
/// parse time and directly access the value of the numeric variable to
/// evaluate their value.
FileCheckPatternContext *Context;
/// Whether this represents a numeric expression substitution.
bool IsNumExpr;
bool IsNumSubst;
/// The string that needs to be substituted for something else. For a
/// pattern variable this is its name, otherwise this is the whole numeric
/// string variable this is its name, otherwise this is the whole numeric
/// expression.
StringRef FromStr;
/// If this is a numeric expression substitution, this is the pointer to the
/// class representing that numeric expression.
/// class representing the numeric expression whose value is to be
/// substituted.
FileCheckNumExpr *NumExpr = nullptr;
// Index in RegExStr of where to do the substitution.
@ -131,29 +134,29 @@ private:
public:
/// Constructor for a pattern variable substitution.
FileCheckPatternSubstitution(FileCheckPatternContext *Context,
StringRef VarName, size_t InsertIdx)
: Context(Context), IsNumExpr(false), FromStr(VarName),
FileCheckSubstitution(FileCheckPatternContext *Context,
StringRef VarName, size_t InsertIdx)
: Context(Context), IsNumSubst(false), FromStr(VarName),
InsertIdx(InsertIdx) {}
/// Constructor for a numeric expression substitution.
FileCheckPatternSubstitution(FileCheckPatternContext *Context, StringRef Expr,
FileCheckNumExpr *NumExpr, size_t InsertIdx)
: Context(Context), IsNumExpr(true), FromStr(Expr), NumExpr(NumExpr),
FileCheckSubstitution(FileCheckPatternContext *Context, StringRef Expr,
FileCheckNumExpr *NumExpr, size_t InsertIdx)
: Context(Context), IsNumSubst(true), FromStr(Expr), NumExpr(NumExpr),
InsertIdx(InsertIdx) {}
/// \returns whether this is a numeric expression substitution.
bool isNumExpr() const { return IsNumExpr; }
bool isNumSubst() const { return IsNumSubst; }
/// \returns the string to be substituted.
/// \returns the string to be substituted for something else.
StringRef getFromString() const { return FromStr; }
/// \returns the index where the substitution is to be performed.
/// \returns the index where the substitution is to be performed in RegExStr.
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
/// substituted by their values. String variables are simply replaced by the
/// text their definition matched.
llvm::Optional<std::string> getResult() const;
@ -216,14 +219,14 @@ class FileCheckPatternContext {
friend class FileCheckPattern;
private:
/// When matching a given pattern, this holds the value of all the FileCheck
/// pattern variables defined in previous patterns. In a pattern, only the
/// last definition for a given variable is recorded in this table.
/// When matching a given pattern, this holds the value of all the string
/// variables defined in previous patterns. In a pattern, only the last
/// definition for a given variable is recorded in this table.
/// 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
/// Map of all string variables defined so far. Used at parse time to detect
/// a name conflict between a numeric variable and a string variable when
/// the former is defined on a later line than the latter.
StringMap<bool> DefinedVariableTable;
@ -243,11 +246,11 @@ private:
std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
public:
/// \returns the value of pattern variable \p VarName or None if no such
/// \returns the value of string 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
/// Defines string 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.
@ -255,7 +258,9 @@ public:
SourceMgr &SM);
/// Undefines local variables (variables whose name does not start with a '$'
/// sign), i.e. removes them from GlobalVariableTable.
/// sign), i.e. removes them from GlobalVariableTable and from
/// GlobalNumericVariableTable and also clears the value of numeric
/// variables.
void clearLocalVars();
private:
@ -281,17 +286,15 @@ class FileCheckPattern {
/// a fixed string to match.
std::string RegExStr;
/// 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
/// Entries in this vector represent a substitution of a string variable or a
/// numeric expression in the RegExStr regex at match time. For example, in
/// the case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",
/// 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.
std::vector<FileCheckPatternSubstitution> Substitutions;
/// that tells us to insert the value of string variable "bar" at offset 3
/// and the value of numeric expression "N+1" at offset 6.
std::vector<FileCheckSubstitution> Substitutions;
/// Maps names of pattern variables defined in a pattern to the parenthesized
/// Maps names of string variables defined in a pattern to the parenthesized
/// capture numbers of their last definition.
///
/// E.g. for the pattern "foo[[bar:.*]]baz[[bar]]quux[[bar:.*]]",
@ -304,9 +307,9 @@ class FileCheckPattern {
/// Pointer to a class instance holding the global state shared by all
/// patterns:
/// - separate tables with the values of live pattern and numeric variables
/// - separate tables with the values of live string and numeric variables
/// respectively at the start of any given CHECK line;
/// - table holding whether a pattern variable has been defined at any given
/// - table holding whether a string variable has been defined at any given
/// point during the parsing phase.
FileCheckPatternContext *Context;
@ -335,14 +338,14 @@ 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)
/// Parses a numeric substitution 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,
const SourceMgr &SM) const;
/// expression being substituted or nullptr if parsing fails, in which case
/// errors are reported on \p SM.
FileCheckNumExpr *parseNumericSubstitution(StringRef Name, bool IsPseudo,
StringRef Trailer,
const SourceMgr &SM) const;
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
/// instance accordingly.
///
@ -361,11 +364,11 @@ public:
/// string.
///
/// The GlobalVariableTable StringMap in the FileCheckPatternContext class
/// instance provides the current values of FileCheck pattern variables and
/// instance provides the current values of FileCheck string variables and
/// is updated if this match defines new values.
size_t match(StringRef Buffer, size_t &MatchLen) const;
/// Prints the value of successful substitutions or the name of the undefined
/// pattern or numeric variable preventing such a successful substitution.
/// string or numeric variable preventing a successful substitution.
void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
SMRange MatchRange = None) const;
void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,

View File

@ -52,8 +52,8 @@ StringRef FileCheckNumExpr::getUndefVarName() const {
return StringRef();
}
llvm::Optional<std::string> FileCheckPatternSubstitution::getResult() const {
if (IsNumExpr) {
llvm::Optional<std::string> FileCheckSubstitution::getResult() const {
if (IsNumSubst) {
llvm::Optional<uint64_t> EvaluatedValue = NumExpr->eval();
if (!EvaluatedValue)
return llvm::None;
@ -67,8 +67,8 @@ llvm::Optional<std::string> FileCheckPatternSubstitution::getResult() const {
return Regex::escape(*VarVal);
}
StringRef FileCheckPatternSubstitution::getUndefVarName() const {
if (IsNumExpr)
StringRef FileCheckSubstitution::getUndefVarName() const {
if (IsNumSubst)
// 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();
@ -129,9 +129,9 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
}
FileCheckNumExpr *
FileCheckPattern::parseNumericExpression(StringRef Name, bool IsPseudo,
StringRef Trailer,
const SourceMgr &SM) const {
FileCheckPattern::parseNumericSubstitution(StringRef Name, bool IsPseudo,
StringRef Trailer,
const SourceMgr &SM) const {
if (IsPseudo && !Name.equals("@LINE")) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
"invalid pseudo numeric variable '" + Name + "'");
@ -288,12 +288,12 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
continue;
}
// Pattern and numeric expression matches. Pattern expressions come in two
// 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
// String and numeric substitution blocks. String substitution blocks come
// in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
// other regex) and assigns it to the string variable 'foo'. The latter
// substitutes foo's value. Numeric substitution blocks start with a
// '#' sign after the double brackets and only have the substitution form.
// Both string 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.
if (PatternStr.startswith("[[")) {
@ -302,23 +302,21 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
// offset relative to the beginning of the match string.
size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
StringRef MatchStr = UnparsedPatternStr.substr(0, End);
bool IsNumExpr = MatchStr.consume_front("#");
const char *RefTypeStr =
IsNumExpr ? "numeric expression" : "pattern variable";
bool IsNumBlock = MatchStr.consume_front("#");
if (End == StringRef::npos) {
SM.PrintMessage(
SMLoc::getFromPointer(PatternStr.data()), SourceMgr::DK_Error,
Twine("Invalid ") + RefTypeStr + " reference, no ]] found");
SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
SourceMgr::DK_Error,
"Invalid substitution block, no ]] found");
return true;
}
// Strip the subtitution we are parsing. End points to the start of the
// "]]" closing the expression so account for it in computing the index
// of the first unparsed character.
// Strip the substitution block we are parsing. End points to the start
// of the "]]" closing the expression so account for it in computing the
// index of the first unparsed character.
PatternStr = UnparsedPatternStr.substr(End + 2);
size_t VarEndIdx = MatchStr.find(":");
if (IsNumExpr)
if (IsNumBlock)
MatchStr = MatchStr.ltrim(SpaceChars);
else {
size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
@ -329,7 +327,7 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
}
}
// Get the regex name (e.g. "foo") and verify it is well formed.
// Get the variable name (e.g. "foo") and verify it is well formed.
bool IsPseudo;
unsigned TrailIdx;
if (parseVariable(MatchStr, IsPseudo, TrailIdx)) {
@ -349,11 +347,11 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
if (IsPseudo || !Trailer.consume_front(":")) {
SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
SourceMgr::DK_Error,
"invalid name in pattern variable definition");
"invalid name in string variable definition");
return true;
}
// Detect collisions between pattern and numeric variables when the
// Detect collisions between string and numeric variables when the
// former is created later than the latter.
if (Context->GlobalNumericVariableTable.find(Name) !=
Context->GlobalNumericVariableTable.end()) {
@ -364,18 +362,18 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
}
}
if (IsNumExpr || (!IsVarDef && IsPseudo)) {
NumExpr = parseNumericExpression(Name, IsPseudo, Trailer, SM);
if (IsNumBlock || (!IsVarDef && IsPseudo)) {
NumExpr = parseNumericSubstitution(Name, IsPseudo, Trailer, SM);
if (NumExpr == nullptr)
return true;
IsNumExpr = true;
IsNumBlock = true;
}
// Handle variable use: [[foo]] and [[#<foo expr>]].
// Handle substitutions: [[foo]] and [[#<foo expr>]].
if (!IsVarDef) {
// Handle use of pattern variables that were defined earlier on the
// same line by emitting a backreference.
if (!IsNumExpr && VariableDefs.find(Name) != VariableDefs.end()) {
// Handle substitution of string variables that were defined earlier on
// the same line by emitting a backreference.
if (!IsNumBlock && VariableDefs.find(Name) != VariableDefs.end()) {
unsigned CaptureParen = VariableDefs[Name];
if (CaptureParen < 1 || CaptureParen > 9) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
@ -385,19 +383,19 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
}
AddBackrefToRegEx(CaptureParen);
} else {
// Handle use of pattern variables ([[<var>]]) defined in previous
// CHECK pattern or use of a numeric expression.
FileCheckPatternSubstitution Substitution =
IsNumExpr ? FileCheckPatternSubstitution(Context, MatchStr,
NumExpr, SubstInsertIdx)
: FileCheckPatternSubstitution(Context, MatchStr,
SubstInsertIdx);
// Handle substitution of string variables ([[<var>]]) defined in
// previous CHECK patterns, and substitution of numeric expressions.
FileCheckSubstitution Substitution =
IsNumBlock ? FileCheckSubstitution(Context, MatchStr, NumExpr,
SubstInsertIdx)
: FileCheckSubstitution(Context, MatchStr,
SubstInsertIdx);
Substitutions.push_back(Substitution);
}
continue;
}
// Handle [[foo:.*]].
// Handle variable definitions: [[foo:.*]].
VariableDefs[Name] = CurParen;
RegExStr += '(';
++CurParen;
@ -460,7 +458,7 @@ size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
// Regex match.
// If there are variable uses, we need to create a temporary string with the
// If there are substitutions, we need to create a temporary string with the
// actual value.
StringRef RegExToMatch = RegExStr;
std::string TmpStr;
@ -468,8 +466,8 @@ size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
TmpStr = RegExStr;
size_t InsertOffset = 0;
// Substitute all pattern variables and numeric expressions whose value is
// known just now. Use of pattern variables defined on the same line are
// Substitute all string variables and numeric expressions whose values are
// only now known. Use of string variables defined on the same line are
// handled by back-references.
for (const auto &Substitution : Substitutions) {
// Substitute and check for failure (e.g. use of undefined variable).
@ -495,7 +493,7 @@ size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
assert(!MatchInfo.empty() && "Didn't get any match");
StringRef FullMatch = MatchInfo[0];
// If this defines any pattern variables, remember their values.
// If this defines any string variables, remember their values.
for (const auto &VariableDef : VariableDefs) {
assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
Context->GlobalVariableTable[VariableDef.first] =
@ -529,13 +527,12 @@ unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
SMRange MatchRange) const {
// Print what we know about substitutions. This covers both uses of pattern
// variables and numeric subsitutions.
// Print what we know about substitutions.
if (!Substitutions.empty()) {
for (const auto &Substitution : Substitutions) {
SmallString<256> Msg;
raw_svector_ostream OS(Msg);
bool IsNumExpr = Substitution.isNumExpr();
bool IsNumSubst = Substitution.isNumSubst();
llvm::Optional<std::string> MatchedValue = Substitution.getResult();
// Substitution failed or is not known at match time, print the undefined
@ -548,10 +545,10 @@ void FileCheckPattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
OS.write_escaped(UndefVarName) << "\"";
} else {
// Substitution succeeded. Print substituted value.
if (IsNumExpr)
if (IsNumSubst)
OS << "with numeric expression \"";
else
OS << "with variable \"";
OS << "with string variable \"";
OS.write_escaped(Substitution.getFromString()) << "\" equal to \"";
OS.write_escaped(*MatchedValue) << "\"";
}
@ -1585,13 +1582,13 @@ bool FileCheckPatternContext::defineCmdlineVariables(
continue;
}
// Detect collisions between pattern and numeric variables when the
// latter is created later than the former.
// Detect collisions between string 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");
"string variable with name '" + CmdlineName + "' already exists");
ErrorFound = true;
continue;
}
@ -1611,7 +1608,7 @@ bool FileCheckPatternContext::defineCmdlineVariables(
// Record this variable definition.
GlobalNumericVariableTable[CmdlineName] = DefinedNumericVariable;
} else {
// Pattern variable definition.
// String variable definition.
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
StringRef Name = CmdlineNameVal.first;
bool IsPseudo;
@ -1619,14 +1616,14 @@ bool FileCheckPatternContext::defineCmdlineVariables(
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 +
"invalid name in string variable definition '" + Name +
"'");
ErrorFound = true;
continue;
}
// Detect collisions between pattern and numeric variables when the
// former is created later than the latter.
// Detect collisions between string 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,
@ -1636,12 +1633,12 @@ bool FileCheckPatternContext::defineCmdlineVariables(
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().
// Mark the string variable as defined to detect collisions between
// string 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;
}
}
@ -1655,12 +1652,12 @@ 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.
// Numeric 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 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();

View File

@ -23,7 +23,7 @@
23 arst CHECK: [[@LINE]] {{a}}rst
24
25 BAD1: [[@LINE:cant-have-regex]]
26 ERR1: line-count.txt:[[#@LINE-1]]:12: error: invalid name in pattern variable definition
26 ERR1: line-count.txt:[[#@LINE-1]]:12: error: invalid name in string variable definition
27
28 BAD2: [[ @LINE]]
29 ERR2: line-count.txt:[[#@LINE-1]]:12: error: unexpected whitespace

View File

@ -71,7 +71,7 @@ INVAL-OP-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: unsupported numeric
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
; Name conflict between Numeric variable definition and string 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
@ -90,6 +90,6 @@ 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: Global defines:3:20: error: string variable with name 'PATVAR' already exists
CLI-CLI-NUM-CONFLICT-NEXT: Global define #3: #PATVAR=42
CLI-CLI-NUM-CONFLICT-NEXT: {{^ \^$}}

View File

@ -16,19 +16,19 @@ ERRCLIEQ2: {{F|f}}ile{{C|c}}heck{{[^:]*}}: for the -D option: requires a value!
RUN: not FileCheck -D=10 --input-file %s %s 2>&1 \
RUN: | FileCheck %s --check-prefix ERRCLIVAR1
ERRCLIVAR1: Missing pattern variable name in command-line definition '-D=10'
ERRCLIVAR1: Missing variable name in command-line definition '-D=10'
; Missing variable name.
RUN: not FileCheck -D= --input-file %s %s 2>&1 \
RUN: | FileCheck %s --check-prefix ERRCLIVAR2
ERRCLIVAR2: Missing pattern variable name in command-line definition '-D='
ERRCLIVAR2: Missing variable name in command-line definition '-D='
; Invalid variable name: starts with a digit.
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 in string 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 in string 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 in string variable definition 'VALUE + 2'
ERRCLITRAIL-NEXT: Global define #1: VALUE + 2=10
ERRCLITRAIL-NEXT: {{^ \^$}}

View File

@ -1,7 +1,7 @@
; Test functionality of -D option: pattern variables are defined to the right
; Test functionality of -D option: string variables are defined to the right
; value and CHECK directives using them match as expected given the value set.
; Pattern variable correctly defined to a non-empty string.
; String variable correctly defined to a non-empty string.
RUN: FileCheck -DVALUE=10 --input-file %s %s
RUN: not FileCheck -DVALUE=20 --input-file %s %s 2>&1 \
RUN: | FileCheck %s --check-prefix ERRMSG
@ -15,14 +15,14 @@ NOT-NOT: Value = [[VALUE]]
ERRMSG: defines.txt:[[@LINE-3]]:8: error: CHECK: expected string not found in input
ERRMSG: defines.txt:1:1: note: scanning from here
ERRMSG: defines.txt:1:1: note: with variable "VALUE" equal to "20"
ERRMSG: defines.txt:1:1: note: with string variable "VALUE" equal to "20"
ERRMSG: defines.txt:[[@LINE-7]]:1: note: possible intended match here
NOT-ERRMSG: defines.txt:[[@LINE-7]]:10: error: {{NOT}}-NOT: excluded string found in input
NOT-ERRMSG: defines.txt:[[@LINE-10]]:1: note: found here
NOT-ERRMSG: defines.txt:[[@LINE-11]]:1: note: with variable "VALUE" equal to "10"
NOT-ERRMSG: defines.txt:[[@LINE-11]]:1: note: with string variable "VALUE" equal to "10"
; Definition of pattern variable to an empty string.
; Definition of string variable to an empty string.
RUN: FileCheck -DVALUE= --check-prefix EMPTY --input-file %s %s 2>&1
Empty value = @@

View File

@ -171,7 +171,7 @@ public:
StringRef NameTrailerRef = bufferize(SM, NameTrailer);
StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
return P.parseNumericExpression(VarNameRef, IsPseudo, TrailerRef, SM) ==
return P.parseNumericSubstitution(VarNameRef, IsPseudo, TrailerRef, SM) ==
nullptr;
}
};
@ -228,10 +228,10 @@ TEST_F(FileCheckTest, Substitution) {
GlobalDefines.emplace_back(std::string("FOO=BAR"));
Context.defineCmdlineVariables(GlobalDefines, SM);
// Substitution of undefined pattern variable fails.
FileCheckPatternSubstitution PatternSubstitution =
FileCheckPatternSubstitution(&Context, "VAR404", 42);
EXPECT_FALSE(PatternSubstitution.getResult());
// Substitution of an undefined string variable fails.
FileCheckSubstitution Substitution =
FileCheckSubstitution(&Context, "VAR404", 42);
EXPECT_FALSE(Substitution.getResult());
// Substitutions of defined pseudo and non-pseudo numeric variables return
// the right value.
@ -239,10 +239,10 @@ TEST_F(FileCheckTest, Substitution) {
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);
FileCheckSubstitution SubstitutionLine =
FileCheckSubstitution(&Context, "@LINE", &NumExprLine, 12);
FileCheckSubstitution SubstitutionN =
FileCheckSubstitution(&Context, "N", &NumExprN, 30);
llvm::Optional<std::string> Value = SubstitutionLine.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("42", *Value);
@ -250,16 +250,16 @@ TEST_F(FileCheckTest, Substitution) {
EXPECT_TRUE(Value);
EXPECT_EQ("13", *Value);
// Substitution of undefined numeric variable fails.
// Substitution of an 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.
// Substitution of a defined string variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
PatternSubstitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
Value = PatternSubstitution.getResult();
Substitution = FileCheckSubstitution(&Context, "FOO", 42);
Value = Substitution.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("BAR", *Value);
}
@ -271,29 +271,29 @@ 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);
// getUndefVarName() on a string substitution with an undefined variable
// returns that variable.
FileCheckSubstitution Substitution =
FileCheckSubstitution(&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);
// getUndefVarName() on a string substitution with a defined variable returns
// an empty string.
Substitution = FileCheckSubstitution(&Context, "FOO", 42);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric expression substitution with a defined
// variable returns an empty string.
// getUndefVarName() on a numeric substitution with a defined variable
// returns an empty string.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
Substitution = FileCheckSubstitution(&Context, "@LINE", &NumExpr, 12);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric expression substitution with an undefined
// variable returns that variable.
// getUndefVarName() on a numeric substitution with an undefined variable
// returns that variable.
LineVar.clearValue();
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("@LINE", UndefVar);
@ -360,7 +360,7 @@ TEST_F(FileCheckTest, FileCheckContext) {
llvm::Optional<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt);
FileCheckNumExpr *NumExpr =
P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
llvm::Optional<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
llvm::Optional<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
EXPECT_TRUE(LocalVar);
@ -384,7 +384,7 @@ TEST_F(FileCheckTest, FileCheckContext) {
EXPECT_FALSE(NumExpr->eval());
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_FALSE(NumExpr);
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_FALSE(EmptyVar);
@ -401,7 +401,7 @@ TEST_F(FileCheckTest, FileCheckContext) {
EXPECT_EQ(*GlobalVar, "BAR");
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);
@ -413,7 +413,7 @@ TEST_F(FileCheckTest, FileCheckContext) {
EXPECT_TRUE(GlobalVar);
P = FileCheckPattern(Check::CheckPlain, &Cxt);
NumExpr =
P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
EXPECT_TRUE(NumExpr);
NumExprVal = NumExpr->eval();
EXPECT_TRUE(NumExprVal);

View File

@ -537,8 +537,8 @@ int main(int argc, char **argv) {
continue;
}
if (EqIdx == 0) {
errs() << "Missing pattern variable name in command-line definition '-D"
<< G << "'\n";
errs() << "Missing variable name in command-line definition '-D" << G
<< "'\n";
GlobalDefineError = true;
continue;
}